diff --git a/resources/[ERS]/SmartFiresLite/.fxap b/resources/[ERS]/SmartFiresLite/.fxap index 0099fe9f0..bd5b9a68e 100644 Binary files a/resources/[ERS]/SmartFiresLite/.fxap and b/resources/[ERS]/SmartFiresLite/.fxap differ diff --git a/resources/[ERS]/SmartFiresLite/cl_smartfires.lua b/resources/[ERS]/SmartFiresLite/cl_smartfires.lua index 7ab530c01..a4c6e88a3 100644 Binary files a/resources/[ERS]/SmartFiresLite/cl_smartfires.lua and b/resources/[ERS]/SmartFiresLite/cl_smartfires.lua differ diff --git a/resources/[ERS]/SmartFiresLite/sv_smartfires.lua b/resources/[ERS]/SmartFiresLite/sv_smartfires.lua index 32f82356e..628b96de7 100644 Binary files a/resources/[ERS]/SmartFiresLite/sv_smartfires.lua and b/resources/[ERS]/SmartFiresLite/sv_smartfires.lua differ diff --git a/resources/[ERS]/SmartHoseLite/.fxap b/resources/[ERS]/SmartHoseLite/.fxap index 8e056a434..affe7d6db 100644 Binary files a/resources/[ERS]/SmartHoseLite/.fxap and b/resources/[ERS]/SmartHoseLite/.fxap differ diff --git a/resources/[ERS]/SmartHoseLite/cl_hose.lua b/resources/[ERS]/SmartHoseLite/cl_hose.lua index 974a4887f..77300d92e 100644 Binary files a/resources/[ERS]/SmartHoseLite/cl_hose.lua and b/resources/[ERS]/SmartHoseLite/cl_hose.lua differ diff --git a/resources/[ERS]/SmartHoseLite/sv_exports.lua b/resources/[ERS]/SmartHoseLite/sv_exports.lua index 13271aff7..741f8947d 100644 Binary files a/resources/[ERS]/SmartHoseLite/sv_exports.lua and b/resources/[ERS]/SmartHoseLite/sv_exports.lua differ diff --git a/resources/[ERS]/SmartHoseLite/sv_hose.lua b/resources/[ERS]/SmartHoseLite/sv_hose.lua index 5f041fdb6..37c475191 100644 Binary files a/resources/[ERS]/SmartHoseLite/sv_hose.lua and b/resources/[ERS]/SmartHoseLite/sv_hose.lua differ diff --git a/resources/[ERS]/ebu_flatbeds_ers/.fxap b/resources/[ERS]/ebu_flatbeds_ers/.fxap index 120c11e6f..c3dce4805 100644 Binary files a/resources/[ERS]/ebu_flatbeds_ers/.fxap and b/resources/[ERS]/ebu_flatbeds_ers/.fxap differ diff --git a/resources/[ERS]/ebu_flatbeds_ers/client/client.lua b/resources/[ERS]/ebu_flatbeds_ers/client/client.lua index e82b25be4..f4b4e5fc0 100644 Binary files a/resources/[ERS]/ebu_flatbeds_ers/client/client.lua and b/resources/[ERS]/ebu_flatbeds_ers/client/client.lua differ diff --git a/resources/[ERS]/ebu_flatbeds_ers/config.lua b/resources/[ERS]/ebu_flatbeds_ers/config.lua index 1280acaf5..ef0701638 100644 --- a/resources/[ERS]/ebu_flatbeds_ers/config.lua +++ b/resources/[ERS]/ebu_flatbeds_ers/config.lua @@ -81,10 +81,6 @@ Config.flatbed = "flatbed" -- Base game flatbed Config.flatbedm2 = "flatbedm2" -- https://www.gta5-mods.com/vehicles/freightliner-m2-crew-cab-flatbed-add-on-script-beta Config.lgc19flatbed = "lgc19flatbed" -- https://forum.cfx.re/t/2019-peterbilt-flatbed/4783413 Config.biftowmfd2 = "biftowmfd2" -- https://mfd.tebex.io/package/6281210 -Config.Gtow = "Gtow" -- https://www.gta5-mods.com/vehicles/peterbilt-337-tuning-by-mfd-fivem -Config.flatbedm2 = "flatbedm2" -- https://www.gta5-mods.com/vehicles/freightliner-m2-crew-cab-flatbed-add-on-script-beta -Config.lgc19flatbed = "lgc19flatbed" -- https://forum.cfx.re/t/2019-peterbilt-flatbed/4783413 -Config.biftowmfd2 = "biftowmfd2" -- https://mfd.tebex.io/package/6281210 Config.Gtow = "Gtow" Config.towy = "towy" Config.rollback1 = "rollback1" @@ -105,6 +101,11 @@ Config.gtrailer = "gtrailer" Config.dotgooseneck = "dotgooseneck" Config.firef350 = "firef350" Config.Terrain20tahoe = "Terrain20tahoe" + + + + + -- List any vehicle models here you do not want to be able to be towed Config.BlacklistedVehs = { diff --git a/resources/[ERS]/ebu_flatbeds_ers/server/server.lua b/resources/[ERS]/ebu_flatbeds_ers/server/server.lua index 9c3557834..eeec6d14c 100644 Binary files a/resources/[ERS]/ebu_flatbeds_ers/server/server.lua and b/resources/[ERS]/ebu_flatbeds_ers/server/server.lua differ diff --git a/resources/[ERS]/night_ers/.fxap b/resources/[ERS]/night_ers/.fxap index ba4447520..67747aac4 100644 Binary files a/resources/[ERS]/night_ers/.fxap and b/resources/[ERS]/night_ers/.fxap differ diff --git a/resources/[ERS]/night_ers/NUI/main.js b/resources/[ERS]/night_ers/NUI/main.js index ad40cddc2..38438cfd6 100644 --- a/resources/[ERS]/night_ers/NUI/main.js +++ b/resources/[ERS]/night_ers/NUI/main.js @@ -1,2812 +1,49 @@ -// Global values -let resourceName = null; -let language = null; -let commands = null; -let firstnames = {}; -let lastnames = {}; - -let isDisplayingPreCalloutInterface = false; -let isDisplayingCalloutInterface = false; - -// Drag functionality variables -let isDragMode = false; -let isDragging = false; -let dragElement = null; -let dragOffset = { x: 0, y: 0 }; - -// UI Layout Mode variables -let isLayoutMode = false; -let layoutElements = {}; -let visibleLayoutElements = new Set(); - -// Enhanced layout system variables -let originalStyles = new Map(); // Store original styles before layout mode -let layoutBoundaries = { left: 20, top: 20, right: 20, bottom: 20 }; // Screen boundaries -let snapGrid = { enabled: true, size: 10 }; // Grid snapping -let collisionDetection = { enabled: true }; // Element collision detection -let dimensionValidation = { enabled: true }; // Validate element dimensions for real vs placeholder content - -window.addEventListener('message', (event) => { - const data = event.data; - - if (data.transactionType == "playSound") { - PlayNUISound(data.transactionFolder, data.transactionFile, data.transactionVolume) - } - - if (data.type == "init") { - if (typeof $ !== 'undefined') { - resourceName = data.resourcename - language = data.language - commands = data.commands - firstnames = data.firstnames - lastnames = data.lastnames - - $.post(`https://${resourceName}/initComplete`, JSON.stringify({ - complete: true - })); - } else { - console.log("Script is still loading...") - }; - } - - if (data.type == "togglecalloutinfo") { - toggleCalloutInfo(); - } - - if (data.type == "toggleUILayoutMode") { - console.log("Received toggleUILayoutMode message from Lua"); - toggleUILayoutMode(); - } - - if (data.type == "emergencyUICleanup") { - console.log("Received emergencyUICleanup message from Lua"); - clearModuleData(); - emergencyUICleanup(); - } - - if (data.type == "clearInformationModulesOnShiftEnd") { - clearModuleData(); - } - - if (data.type == "ersselectionmenu") { - var display = data.display - var permissions = data.permissions - ToggleERSSelectionMenu(display, permissions) - } - - if (data.type == "radialmenu") { - var display = data.display - ToggleRadialMenu(display) - } - - if (data.type == "pursuitradialmenu") { - var display = data.display - TogglePursuitRadialMenu(display) - } - - if (data.type == "pursuitmode") { - var display = data.display - var displayhotkeyhint = data.displayhotkeyhint - var zoomhotkey = data.zoomhotkey - var backuphotkey = data.backuphotkey - TogglePursuitModeUI(display, displayhotkeyhint, zoomhotkey, backuphotkey) - } - - if (data.type == "dualsteeringmode") { - var display = data.display - ToggleDualSteeringMode(display) - } - - if (data.type == "hotkeyhintprompt") { - var display = data.display - var hotkeys = data.hotkeys - var time = data.time - ToggleHotKeyHintPrompt(display, hotkeys, language, time) - } - - if (data.type == "dispatchmessage") { - var display = data.display - var hotkeys = data.hotkeys - var messagetype = data.messagetype - var calloutdata = data.calloutdata - var message = data.message - var time = data.time - var toggle = data.toggle - AddMessageToDispatchQueue(display, hotkeys, messagetype, calloutdata, time, message, toggle) - } - - if (data.type == "calloutprompt") { - var display = data.display - var calloutdata = data.calloutdata - var hotkeys = data.hotkeys - var time = data.time - var serviceType = data.serviceType - ToggleCalloutDisplayPrompt(display, hotkeys, language, time, calloutdata, serviceType) - } - - if (data.type == "calloutpreinterface") { - var display = data.display - var hotkeys = data.hotkeys - var calloutdata = data.calloutdata - TogglePreCalloutInterface(display, hotkeys, calloutdata) - } - - if (data.type == "calloutinterface") { - var display = data.display - var hotkeys = data.hotkeys - var pedCount = data.pedCount - var vehicleCount = data.vehicleCount - var objectCount = data.objectCount - var propCount = data.propCount - var fireCount = data.fireCount - var smokeCount = data.smokeCount - - var calloutdata = data.calloutdata - - var pedOriginalCount = data.pedOriginalCount - var vehOriginalCount = data.vehOriginalCount - var objOriginalCount = data.objOriginalCount - var propOriginalCount = data.propOriginalCount - var fireOriginalCount = data.fireOriginalCount - var smokeOriginalCount = data.smokeOriginalCount - - ToggleCalloutInterface(display, hotkeys,pedCount, vehicleCount, objectCount, propCount, fireCount, smokeCount, calloutdata, pedOriginalCount, vehOriginalCount, objOriginalCount, propOriginalCount, fireOriginalCount, smokeOriginalCount) - } - - if (data.type == "unifiedprompt") { - var display = data.display - var promptType = data.promptType - var hotkey = data.hotkey - var message = data.message - var time = data.time - DisplayUnifiedPrompt(display, promptType, hotkey, message, time) - } - - if (data.type == "interactionmodule") { - var display = data.display - var isDead = data.ispeddeadordying - var service = data.service - DisplayPedInteractionModule(display, isDead, service) - } - - if (data.type == "idcardprompt") { - var display = data.display - var personaldata = data.pedpersonaldata - var showdatabasecheck = data.showdatabasecheck - DisplayPedIdCard(display, personaldata, showdatabasecheck) - } - - if (data.type == "inventoryprompt") { - var display = data.display - var itemList = data.itemlist - DisplayPedInventory(display, itemList) - } - - if(data.type == "vehicleinfoprompt") { - var display = data.display - var vehicleData = data.vehicleData - var DisableTaxAndMOT = data.DisableTaxAndMOT - DisplayVehicleInfo(display, vehicleData, DisableTaxAndMOT) - } - - if (data.type == "redisplaylastmodule") { - redisplayLastModule() - } - - if (data.type == "togglequestionsmodule") { - var display = data.display - var questions = data.questions - ToggleQuestionsModule(display, questions) - } - - if (data.type == "updateanswers") { - var display = data.display - var answers = data.answers - UpdateAnswers(display, answers) - } - - if (data.type == "addorremovewaypoint") { - var addOrRemove = data.addwaypoint - AddWaypoint(addOrRemove); - } - - if (data.type == "updatewaypoint") { - var scaleX = data.scaleX - var scaleY = data.scaleY - var distanceText = data.distanceText - UpdateWaypointPosition(scaleX, scaleY, distanceText); - } - - if (data.type == "areyousure") { - var display = data.display - DisplayAreYouSurePopup(display) - } - - if (data.type == "gearmenu") { - var display = data.display - var locationData = data.locationdata - DisplayGearMenu(display, locationData) - } - - if (data.type == "updatezonechange") { - var lastZone = data.lastZone - var currentZone = data.currentZone - UpdateZoneChangeUI(lastZone, currentZone) - } - - if (data.type === 'updatewaypoints') { - updateWaypoints(data); - } -}); - -// FUNCTIONS - -var zoneChangeTimeout = null; -let zoneChangeQueue = []; -let isAnimating = false; - -function UpdateZoneChangeUI(oldZone, newZone) { - zoneChangeQueue.push({ oldZone, newZone }); - if (!isAnimating) { - processNextZoneChange(); - } -} - -function processNextZoneChange() { - if (zoneChangeQueue.length === 0) { - isAnimating = false; - return; - } - - isAnimating = true; - const { oldZone, newZone } = zoneChangeQueue.shift(); - - const zoneChangeUI = document.getElementById('zone-change-ui'); - if (!zoneChangeUI) { - processNextZoneChange(); - return; - } - - const oldZoneElement = zoneChangeUI.querySelector('.old-zone'); - const newZoneElement = zoneChangeUI.querySelector('.new-zone'); - - if (!oldZoneElement || !newZoneElement) { - processNextZoneChange(); - return; - } - - // Clear any existing timeout - if (zoneChangeTimeout) { - clearTimeout(zoneChangeTimeout); - } - - // Reset the animation state - zoneChangeUI.classList.remove('show'); - newZoneElement.classList.remove('show'); - - // Set the new zone values - oldZoneElement.textContent = oldZone ? oldZone : "N/A"; - newZoneElement.textContent = newZone ? newZone : "N/A"; - - // Trigger reflow to ensure the animation restarts - void zoneChangeUI.offsetWidth; - - // Start the new animation - zoneChangeUI.classList.add('show'); - newZoneElement.classList.add('show'); - - // Set a new timeout - zoneChangeTimeout = setTimeout(() => { - zoneChangeUI.classList.remove('show'); - newZoneElement.classList.remove('show'); - - // Process the next zone change after the animation is complete - setTimeout(processNextZoneChange, 500); // Add a small delay between animations - }, 4000); -} - -let escapeEventListenerAdded = false; - -function DisplayAreYouSurePopup(display) { - if (display) { - // Remove any previous modals - $('#are-you-sure-modal').remove(); - - // HTML - const modal = ` - - `; - - $('body').append(modal); - - // Initialize the modal with static backdrop and disabled keyboard interaction - $('#are-you-sure-modal').modal({ - backdrop: 'static', - keyboard: false - }); - - // Show the modal explicitly - $('#are-you-sure-modal').modal('show'); - - // Handle Escape key press only when the modal is open - $('#are-you-sure-modal').on('shown.bs.modal', function() { - if (!escapeEventListenerAdded) { - $(document).on('keydown', function(event) { - if (event.key === "Escape") { - // Close the modal - $('#are-you-sure-modal').modal('hide'); - // Trigger the same action as the "No" button click - handleNoClick(); - // Ensure the event doesn't propagate further - event.stopPropagation(); - } - }); - escapeEventListenerAdded = true; - } - }).on('hidden.bs.modal', function() { - // Remove the Escape key press event listener when the modal is closed - $(document).off('keydown'); - escapeEventListenerAdded = false; - }); - - } else { - $('#are-you-sure-modal').remove(); - } -} - - -// Function to handle 'No' button click -function handleNoClick() { - $.post(`https://${resourceName}/AreYouSure`, JSON.stringify({ - areyousure: false - })); - $('#are-you-sure-modal').modal('hide'); -} - -// Function to handle 'Yes' button click -function handleYesClick() { - $.post(`https://${resourceName}/AreYouSure`, JSON.stringify({ - areyousure: true - })); - $('#are-you-sure-modal').modal('hide'); -} - -function DisplayPedInteractionModule(display, isDead, service) { // service can be: police, fire, ambulance or tow. - if (display) { - DisplayUnifiedPrompt(false) - if (isDead) { - $("#ped-interaction-module").empty(); - $("#ped-interaction-module").show(); - - //HTML - $("#ped-interaction-module").append(` -

${language.InteractionOptions}

-
-
- -
- ${[ - { id: 'identify', label: language.IdentifyDeadPed, explanation: language.IdentifyDeadPedExplanation }, - { id: 'drag', label: language.DragPed, explanation: language.DragPedExplanation }, - { id: 'massivebleeding', label: language.CheckMassiveBleeding, explanation: language.CheckMassiveExplanation }, - { id: 'airway', label: language.CheckAirway, explanation: language.CheckAirwayExplanation }, - { id: 'breathing', label: language.CheckBreathing, explanation: language.CheckBreathingExplanation }, - { id: 'circulation', label: language.CheckCirculation, explanation: language.CheckCirculationExplanation }, - { id: 'hypothermia', label: language.CheckHypothermia, explanation: language.CheckHypothermiaExplanation }, - { id: 'cpr', label: language.PerformCPR, explanation: language.PerformCPRExplanation }, - { id: 'putonstretcher', label: language.PutOnStretcher, explanation: language.PutOnStretcherExplanation }, - { id: 'takeoffstretcher', label: language.TakeOffStretcher, explanation: language.TakeOffStretcherExplanation }, - { id: 'bodybag', label: language.PutInBodyBag, explanation: language.PutInBodyBagExplanation } - ].map(item => ` -
-
- -
-
- ${item.explanation} -
-
- `).join('')} -
-
- -
- -
-
- -
-
-
- `); - - // Apply sound effects to all buttons - const buttonIds = [ - 'identify', 'drag', 'massivebleeding', 'airway', 'breathing', 'circulation', 'hypothermia', 'cpr', 'putonstretcher', 'takeoffstretcher', 'bodybag', - 'exit' - ]; - buttonIds.forEach(id => addSoundOnHoverEventListener(`p-btn-${id}`)); - - } else { - $("#ped-interaction-module").empty(); - $("#ped-interaction-module").show(); - - // Per service we need to show different buttons. - var buttonsPerService = { - police: [ - { id: 'greet', label: language.Greet, explanation: language.GreetExplanation }, - { id: 'id', label: language.AskForId, explanation: language.AskForIdExplanation }, - { id: 'questioning', label: language.Question, explanation: language.QuestionExplanation }, - { id: 'breathalyze', label: language.Breathalyze, explanation: language.BreathalyzeExplanation }, - { id: 'drugtest', label: language.DrugTest, explanation: language.DrugTestExplanation }, - { id: 'warn', label: language.Warn, explanation: language.WarnExplanation }, - { id: 'fine', label: language.Fine, explanation: language.FineExplanation }, - { id: 'grab', label: language.Grab, explanation: language.GrabExplanation }, - { id: 'getout', label: language.GetOut, explanation: language.GetOutExplanation }, - { id: 'follow', label: language.AskToFollow, explanation: language.AskToFollowExplanation }, - { id: 'wait', label: language.AskToWait, explanation: language.AskToWaitExplanation }, - { id: 'handsup', label: language.HandsUp, explanation: language.HandsUpExplanation }, - { id: 'search', label: language.Search, explanation: language.SearchExplanation }, - { id: 'cuff', label: language.Cuff, explanation: language.CuffExplanation }, - { id: 'putinvehicle', label: language.PutInVehicle, explanation: language.PutInVehicleExplanation } - ], - ambulance: [ - { id: 'greet', label: language.Greet, explanation: language.GreetExplanation }, - { id: 'questioning', label: language.Question, explanation: language.QuestionExplanation }, - { id: 'breathalyze', label: language.Breathalyze, explanation: language.BreathalyzeExplanation }, - { id: 'drugtest', label: language.DrugTest, explanation: language.DrugTestExplanation }, - { id: 'getout', label: language.GetOut, explanation: language.GetOutExplanation }, - { id: 'follow', label: language.AskToFollow, explanation: language.AskToFollowExplanation }, - { id: 'wait', label: language.AskToWait, explanation: language.AskToWaitExplanation }, - { id: 'putinvehicle', label: language.PutInVehicle, explanation: language.PutInVehicleExplanation } - ], - fire: [ - { id: 'greet', label: language.Greet, explanation: language.GreetExplanation }, - { id: 'questioning', label: language.Question, explanation: language.QuestionExplanation }, - { id: 'breathalyze', label: language.Breathalyze, explanation: language.BreathalyzeExplanation }, - { id: 'drugtest', label: language.DrugTest, explanation: language.DrugTestExplanation }, - { id: 'getout', label: language.GetOut, explanation: language.GetOutExplanation }, - { id: 'follow', label: language.AskToFollow, explanation: language.AskToFollowExplanation }, - { id: 'wait', label: language.AskToWait, explanation: language.AskToWaitExplanation }, - { id: 'putinvehicle', label: language.PutInVehicle, explanation: language.PutInVehicleExplanation } - ], - tow: [ - { id: 'greet', label: language.Greet, explanation: language.GreetExplanation }, - { id: 'questioning', label: language.Question, explanation: language.QuestionExplanation }, - { id: 'getout', label: language.GetOut, explanation: language.GetOutExplanation }, - { id: 'follow', label: language.AskToFollow, explanation: language.AskToFollowExplanation }, - { id: 'wait', label: language.AskToWait, explanation: language.AskToWaitExplanation }, - { id: 'putinvehicle', label: language.PutInVehicle, explanation: language.PutInVehicleExplanation } - ] - } - - // HTML - $("#ped-interaction-module").append(` -

${language.InteractionOptions}

-
-
- -
- ${(buttonsPerService[service] || buttonsPerService.police).map(item => ` -
-
- -
-
- ${item.explanation} -
-
- `).join('')} -
-
- -
- -
-
- - - ${service === 'police' ? `` : ''} -
-
-
- `); - - // Apply sound on hover to all buttons - const serviceButtons = buttonsPerService[service] || buttonsPerService.police; - const buttonIds = [ - ...serviceButtons.map(item => item.id), - 'end', 'exit', - ...(service === 'police' ? ['custody'] : []) - ]; - buttonIds.forEach(id => addSoundOnHoverEventListener(`p-btn-${id}`)); - } - } else { - $("#ped-interaction-module").hide(); - } -} - -function PedInteraction(intType) { - $.post(`https://${resourceName}/pedInteraction`, JSON.stringify({ - interactionType: intType - })) -} - -function addSoundOnHoverEventListener(buttonId) { - var button = document.getElementById(buttonId); - button.addEventListener('mouseenter', function() { - PlayNUISound('generic-sounds', "rollover", 0.5); - }); -} - -var unifiedPromptTimeout; - -function DisplayUnifiedPrompt(display, promptType, hotkey, message, time) { - if (display) { - $("#unified-prompt").show(); - - clearTimeout(unifiedPromptTimeout); - - // Define prompt configurations - const promptConfigs = { - 'pedinteraction': { - icon: '๐Ÿ’ฌ', - color: 'text-warning', - text: language.ToInteract, - timeout: 1500 - }, - 'injuredped': { - icon: '๐Ÿฉบ', - color: 'text-danger', - text: language.ToPerformCPR, - timeout: 1500 - }, - 'impound': { - icon: '๐Ÿš—', - color: 'text-danger', - text: language.ToInteractImpound, - timeout: 1500 - }, - 'gear': { - icon: '๐Ÿš—', - color: 'text-danger', - text: language.ToInteractGear, - timeout: 1500 - }, - 'stretcher': { - icon: '๐Ÿฅ', - color: 'text-info', - text: language.ToUseStretcherVeh, - timeout: 1500 - }, - 'objectcleanup': { - icon: '๐Ÿงน', - color: 'text-success', - text: language.ToCleanupObject, - timeout: 1500 - }, - 'spikesvehicle': { - icon: '๐Ÿ’ข', - color: 'text-warning', - text: message || '', - timeout: time || 1500 - } - }; - - const config = promptConfigs[promptType] || promptConfigs['pedinteraction']; - - $("#unified-prompt").html(` -
${config.icon} ${language.Press} ${hotkey} ${config.text}
- `); - - unifiedPromptTimeout = setTimeout(function() { - $("#unified-prompt").hide(); - }, config.timeout); - - } else { - $("#unified-prompt").hide(); - } -} - -// Track last displayed module for TAB key re-display -var lastDisplayedModule = null; // 'idcard', 'vehicle', or 'inventory' -var lastIdCardData = null; -var lastVehicleData = null; -var lastInventoryData = null; - -// Track database check completion states for each module -var idCardDbCheckCompleted = false; -var vehicleDbCheckCompleted = false; - -var idCardTimeout; -var vehicleInfoTimeout; -var dbCheckTimeout; -var vehicleDbCheckTimeout; -var moduleClearTimeout; // Timeout to clear module data if hidden for > 1 minute -var moduleProgressInterval; // Interval to update progress bar -var moduleClearStartTime; // Timestamp when module clear timer started - -function DisplayPedIdCard(display, personaldata, showdatabasecheck, skipDbCheckAnimation) { - if (display) { - // Hide vehicle info. - $("#vehicle-info").hide(); - // Hide inventory - $("#ped-interaction-inventory").hide(); - - clearTimeout(idCardTimeout); - - // Only clear dbCheckTimeout if we're not preserving state - if (!skipDbCheckAnimation) { - clearTimeout(dbCheckTimeout); - idCardDbCheckCompleted = false; - } - - $("#ped-interaction-id-card").empty(); - - var profilePicture = personaldata.ProfilePicture || 'N/A'; - var firstName = personaldata.FirstName || 'N/A'; - var lastName = personaldata.LastName || 'N/A'; - var dob = personaldata.DOB || 'N/A'; - var gender = personaldata.Gender || 'N/A'; - var email = personaldata.Email || 'N/A'; - var phone = personaldata.PhoneNumber || 'N/A'; - var country = personaldata.Country || 'N/A'; - var state = personaldata.State || 'N/A'; - var city = personaldata.City || 'N/A'; - var postalcode = personaldata.PostalCode || 'N/A'; - var address = personaldata.Address || 'N/A'; - var addressType = personaldata.AddressType || 'N/A'; - var nationality = personaldata.Nationality || 'N/A'; - var flagsOrMarkers = personaldata.FlagsOrMarkers // This is a list of keys which are true or false, I want each one to be displayed.... - var driversLicense = personaldata.License_Car || 'N/A'; - var driversLicenseColour = personaldata.License_Car_Colour || 'text-light'; - var driversLicenseIcon = personaldata.License_Car_Icon || 'fas fa-car'; - var bikeLicense = personaldata.License_Bike || 'N/A'; - var bikeLicenseColour = personaldata.License_Bike_Colour || 'text-light'; - var bikeLicenseIcon = personaldata.License_Bike_Icon || 'fas fa-bicycle'; - var boatLicense = personaldata.License_Boat || 'N/A'; - var boatLicenseColour = personaldata.License_Boat_Colour || 'text-light'; - var boatLicenseIcon = personaldata.License_Boat_Icon || 'fas fa-ship'; - var truckLicense = personaldata.License_Truck || 'N/A'; - var truckLicenseColour = personaldata.License_Truck_Colour || 'text-light'; - var truckLicenseIcon = personaldata.License_Truck_Icon || 'fas fa-truck'; - var pilotLicense = personaldata.License_Pilot || 'N/A'; - var pilotLicenseColour = personaldata.License_Pilot_Colour || 'text-light'; - var pilotLicenseIcon = personaldata.License_Pilot_Icon || 'fas fa-plane'; - - // Store data for TAB key re-display - lastDisplayedModule = 'idcard'; - lastIdCardData = { - personaldata: personaldata, - showdatabasecheck: showdatabasecheck - }; - - // Modern Bootstrap 5.2.3 Card Design - // DON'T use isolation: isolate - it causes text blurriness - $("#ped-interaction-id-card").append(` -
-
-
- -
${language.PersonalDetails}
-
-
-
-
- ${language.FullName} - ${firstName} ${lastName} -
-
- ${language.DOB} - ${dob} -
-
-
- `); - - $("#ped-interaction-id-card").show(); - - if (showdatabasecheck) { - // Always create the database-check container first - // DON'T use isolation: isolate on the card itself - it causes text blurriness - $("#ped-interaction-id-card").append(` -
-
- `); - - // Check if database check was already completed - if (idCardDbCheckCompleted && skipDbCheckAnimation) { - // Show completed results immediately - renderIdCardDatabaseResults(personaldata, firstName, lastName, dob, profilePicture, nationality, gender, address, city, state, postalcode, country, email, phone, driversLicense, driversLicenseColour, bikeLicense, bikeLicenseColour, boatLicense, boatLicenseColour, truckLicense, truckLicenseColour, pilotLicense, pilotLicenseColour, flagsOrMarkers); - } else { - // Show loading spinner - $("#database-check").html(` -
-
- -
${language.DatabaseCheck}
-
-
-
-
- -
-

${language.RunningDatabaseCheck}

-
-
-
-
- `); - - // Delay before results & Display results - dbCheckTimeout = setTimeout(function() { - idCardDbCheckCompleted = true; - $("#initial-check").remove(); - renderIdCardDatabaseResults(personaldata, firstName, lastName, dob, profilePicture, nationality, gender, address, city, state, postalcode, country, email, phone, driversLicense, driversLicenseColour, bikeLicense, bikeLicenseColour, boatLicense, boatLicenseColour, truckLicense, truckLicenseColour, pilotLicense, pilotLicenseColour, flagsOrMarkers); - }, 3000); - } - } - - // Hide the ID card after a certain period - idCardTimeout = setTimeout(function() { - $("#ped-interaction-id-card").hide(); - updateModuleIndicator(); - scheduleModuleClearIfHidden(); - }, 15000); - - updateModuleIndicator(); - - } else { - $("#ped-interaction-id-card").hide(); - updateModuleIndicator(); - } -} - -// Separate function to render ID card database results -function renderIdCardDatabaseResults(personaldata, firstName, lastName, dob, profilePicture, nationality, gender, address, city, state, postalcode, country, email, phone, driversLicense, driversLicenseColour, bikeLicense, bikeLicenseColour, boatLicense, boatLicenseColour, truckLicense, truckLicenseColour, pilotLicense, pilotLicenseColour, flagsOrMarkers) { - // Completely clear and replace content to reset rendering context - var dbCheckElement = document.getElementById('database-check'); - if (dbCheckElement) { - // Remove all content including loading indicator - dbCheckElement.innerHTML = ''; - // Force a reflow to clear any rendering contexts - void dbCheckElement.offsetHeight; - } - - $("#database-check").html(` -
-
- -
${language.DatabaseCheckResults}
-
-
-
-
-
-
-
${firstName} ${lastName}
- ${dob} -
- Photo -
-
-
-
-
- ${language.Nationality} - ${nationality} -
-
-
-
- ${language.Gender} - ${gender} -
-
-
-
- ${language.Address} - ${address}, ${city}
${state} ${postalcode}, ${country}
-
-
-
-
- ${language.Email} - ${email} -
-
- ${language.PhoneNumber} - ${phone} -
-
-
-
-
- -
-
${language.Licenses}
-
- - ${driversLicense} - - - ${bikeLicense} - - - ${boatLicense} - - - ${truckLicense} - - - ${pilotLicense} - -
-
- - ${flagsOrMarkers && Object.keys(flagsOrMarkers).some(key => flagsOrMarkers[key]) ? ` -
-
${language.FlagsOrMarkers}
-
- ${flagsOrMarkers.armed_and_dangerous ? `
${language.armed_and_dangerous}
` : ''} - ${flagsOrMarkers.assault ? `
${language.assault}
` : ''} - ${flagsOrMarkers.burglary ? `
${language.burglary}
` : ''} - ${flagsOrMarkers.drug_related ? `
${language.drug_related}
` : ''} - ${flagsOrMarkers.gang_affiliation ? `
${language.gang_affiliation}
` : ''} - ${flagsOrMarkers.homicide ? `
${language.homicide}
` : ''} - ${flagsOrMarkers.kidnapping ? `
${language.kidnapping}
` : ''} - ${flagsOrMarkers.mental_health_issues ? `
${language.mental_health_issues}
` : ''} - ${flagsOrMarkers.sex_offense ? `
${language.sex_offense}
` : ''} - ${flagsOrMarkers.terrorism ? `
${language.terrorism}
` : ''} - ${flagsOrMarkers.theft ? `
${language.theft}
` : ''} - ${flagsOrMarkers.traffic_violation ? `
${language.traffic_violation}
` : ''} - ${flagsOrMarkers.wanted_person ? `
${language.wanted_person}
` : ''} - ${flagsOrMarkers.other ? `
${language.other}
` : ''} - ${flagsOrMarkers.active_warrant ? `
${language.active_warrant}
` : ''} -
-
- ` : ''} -
- `); - - // Force browser reflow and repaint to ensure text renders crisply - var databaseCheck = document.getElementById('database-check'); - if (databaseCheck) { - // Force reflow - void databaseCheck.offsetHeight; - // Reset any transform that might affect rendering - databaseCheck.style.isolation = 'auto'; - // Force repaint by toggling a property - var originalTransform = databaseCheck.style.transform; - databaseCheck.style.transform = 'translateZ(0)'; - // Use requestAnimationFrame to ensure browser has processed the change - requestAnimationFrame(function() { - databaseCheck.style.transform = originalTransform || 'translateZ(0)'; - }); - } -} - -function DisplayVehicleInfo(display, vehicleData, DisableTaxAndMOT, skipDbCheckAnimation) { - if (display) { - // Hide ID card - $("#ped-interaction-id-card").hide(); - // Hide inventory - $("#ped-interaction-inventory").hide(); - - clearTimeout(vehicleInfoTimeout); - - // Only clear vehicleDbCheckTimeout if we're not preserving state - if (!skipDbCheckAnimation) { - clearTimeout(vehicleDbCheckTimeout); - vehicleDbCheckCompleted = false; - } - - $("#vehicle-info").empty(); - - // Vehicle Data - var data = { - vehNetId: vehicleData.vehNetId, - license_plate: vehicleData.license_plate, - model: vehicleData.model, - model_hash: vehicleData.model_hash, - vehicle_class: vehicleData.vehicle_class, - vehicle_class_from_name: vehicleData.vehicle_class_from_name, - color: vehicleData.color, - color_secondary: vehicleData.color_secondary, - build_year: vehicleData.build_year, - tax: vehicleData.tax, - mot: vehicleData.mot, - insurance: vehicleData.insurance, - stolen: vehicleData.stolen, - bolo: vehicleData.bolo, - bolo_description: vehicleData.bolo_description, - owner_name: vehicleData.owner_name, - } - - // Store data for TAB key re-display - lastDisplayedModule = 'vehicle'; - lastVehicleData = { - vehicleData: vehicleData, - DisableTaxAndMOT: DisableTaxAndMOT - }; - - // Modern Bootstrap 5.2.3 Vehicle Info Card - // DON'T use isolation: isolate - it causes text blurriness - $("#vehicle-info").append(` -
-
-
- -
${language.VehicleDetails}
-
-
-
-
- ${language.VehiclePlate} - ${data.license_plate} -
-
- ${language.VehicleModel} - ${data.model} -
-
-
- `); - - // Always create the database-check container first - // DON'T use isolation: isolate on the card itself - it causes text blurriness - $("#vehicle-info").append(` -
-
- `); - - $("#vehicle-info").show(); - - // Check if database check was already completed - if (vehicleDbCheckCompleted && skipDbCheckAnimation) { - // Show completed results immediately - renderVehicleDatabaseResults(data, DisableTaxAndMOT); - } else { - // Show loading spinner - $("#vehicle-info-database-check").html(` -
-
- -
${language.DatabaseCheck}
-
-
-
-
- -
-

${language.RunningDatabaseCheck}

-
-
-
-
- `); - - vehicleDbCheckTimeout = setTimeout(function() { - vehicleDbCheckCompleted = true; - renderVehicleDatabaseResults(data, DisableTaxAndMOT); - }, 5000); - } - - // Hide the vehicle info after a certain period - vehicleInfoTimeout = setTimeout(function() { - $("#vehicle-info").hide(); - updateModuleIndicator(); - scheduleModuleClearIfHidden(); - }, 15000); - - updateModuleIndicator(); - - } else { - $("#vehicle-info").hide(); - updateModuleIndicator(); - } -} - -// Separate function to render vehicle database results -function renderVehicleDatabaseResults(data, DisableTaxAndMOT) { - // Completely clear and replace content to reset rendering context - var vehicleDbCheckElement = document.getElementById('vehicle-info-database-check'); - if (vehicleDbCheckElement) { - // Remove all content including loading indicator - vehicleDbCheckElement.innerHTML = ''; - // Force a reflow to clear any rendering contexts - void vehicleDbCheckElement.offsetHeight; - } - - $("#vehicle-info-database-check").html(` -
-
- -
${language.DatabaseCheckResults}
-
-
-
-
-
-
- ${language.VehicleOwner} - ${data.owner_name} -
-
-
-
- ${language.VehicleBuildYear} - ${data.build_year} -
-
-
-
- ${language.VehicleColor} - ${data.color} -
-
-
-
- ${language.VehicleColorSecondary} - ${data.color_secondary} -
-
- - ${DisableTaxAndMOT ? "" : ` -
-
- ${language.VehicleTax} - - ${data.tax ? language.Paid : language.NotPaid} - -
-
-
-
- ${language.VehicleMOT} - - ${data.mot ? language.Passed : language.Failed} - -
-
- `} -
-
- ${language.VehicleInsurance} - - ${data.insurance ? language.Valid : language.Invalid} - -
-
-
-
- ${language.VehicleStolen} - - ${data.stolen ? language.Yes : language.No} - -
-
-
-
- ${language.VehicleBolo} - - ${data.bolo ? language.Yes : language.No} - -
-
- ${!data.bolo ? "" : ` -
-
-
${language.VehicleBoloDescription}
-

${wrapText(data.bolo_description ? data.bolo_description : "-", 50)}

-
-
- `} -
-
- `); - - // Force browser reflow and repaint to ensure text renders crisply - var vehicleDbCheck = document.getElementById('vehicle-info-database-check'); - if (vehicleDbCheck) { - // Force reflow - void vehicleDbCheck.offsetHeight; - // Reset any transform that might affect rendering - vehicleDbCheck.style.isolation = 'auto'; - // Force repaint by toggling a property - var originalTransform = vehicleDbCheck.style.transform; - vehicleDbCheck.style.transform = 'translateZ(0)'; - // Use requestAnimationFrame to ensure browser has processed the change - requestAnimationFrame(function() { - vehicleDbCheck.style.transform = originalTransform || 'translateZ(0)'; - }); - } -} - -var inventoryTimeout; -function DisplayPedInventory(display, itemList) { - if (display) { - // Hide ID card - $("#ped-interaction-id-card").hide(); - // Hide vehicle info - $("#vehicle-info").hide(); - - clearTimeout(inventoryTimeout); - - $("#ped-interaction-inventory").empty(); - - // Store data for TAB key re-display - lastDisplayedModule = 'inventory'; - lastInventoryData = { - itemList: itemList - }; - - // Modern Bootstrap 5.2.3 Inventory Card - $("#ped-interaction-inventory").append(` -
-
-
-
- -
${language.Inventory}
-
- ${itemList.length} ${itemList.length === 1 ? 'item' : 'items'} -
-
-
-
-
-
-
- `); - - if (itemList.length === 0) { - $("#inventory-list-body").append(` -
- -

No items found

-
- `); - } else { - $.each(itemList, function (key, v) { - var isIllegal = v.illegal; - var itemClass = isIllegal ? 'border-danger border-opacity-50' : 'border-secondary border-opacity-25'; - var textClass = isIllegal ? 'text-danger' : 'text-light'; - var iconClass = isIllegal ? 'fas fa-exclamation-triangle text-danger' : 'fas fa-cube text-info'; - - var listItem = ` -
-
- - ${v.name} - ${isIllegal ? 'Illegal' : ''} -
-
- `; - $("#inventory-list-body").append(listItem); - }); - } - - $("#ped-interaction-inventory").show(); - - inventoryTimeout = setTimeout(function() { - $("#ped-interaction-inventory").hide(); - updateModuleIndicator(); - scheduleModuleClearIfHidden(); - }, 15000); - - updateModuleIndicator(); - - } else { - $("#ped-interaction-inventory").hide(); - updateModuleIndicator(); - } -} - -// Function to clear module data when shift ends -function clearModuleData() { - // Clear stored module data - lastDisplayedModule = null; - lastIdCardData = null; - lastVehicleData = null; - lastInventoryData = null; - - // Reset database check completion states - idCardDbCheckCompleted = false; - vehicleDbCheckCompleted = false; - - // Clear any active timeouts - clearTimeout(idCardTimeout); - clearTimeout(vehicleInfoTimeout); - clearTimeout(inventoryTimeout); - clearTimeout(dbCheckTimeout); - clearTimeout(vehicleDbCheckTimeout); - clearTimeout(moduleClearTimeout); - stopModuleProgressBar(); - - // Hide any visible modules - $("#ped-interaction-id-card").hide(); - $("#vehicle-info").hide(); - $("#ped-interaction-inventory").hide(); - - // Hide the module indicator - $("#module-indicator").fadeOut(200); -} - -// Function to schedule clearing module data if hidden for > 1 minute -function scheduleModuleClearIfHidden() { - // Clear any existing timeout and interval - clearTimeout(moduleClearTimeout); - clearInterval(moduleProgressInterval); - - // Record start time for progress bar - moduleClearStartTime = Date.now(); - - // Start progress bar animation - startModuleProgressBar(); - - // Set new timeout to clear after 60 seconds - moduleClearTimeout = setTimeout(function() { - // Only clear if module is still hidden - if (lastDisplayedModule) { - var isCurrentlyVisible = false; - - if (lastDisplayedModule === 'idcard' && $("#ped-interaction-id-card").is(":visible")) { - isCurrentlyVisible = true; - } else if (lastDisplayedModule === 'vehicle' && $("#vehicle-info").is(":visible")) { - isCurrentlyVisible = true; - } else if (lastDisplayedModule === 'inventory' && $("#ped-interaction-inventory").is(":visible")) { - isCurrentlyVisible = true; - } - - // Clear module data if still hidden after 60 seconds - if (!isCurrentlyVisible) { - clearModuleData(); - } - } - }, 30000); // 30 seconds -} - -// Function to start/update progress bar animation -function startModuleProgressBar() { - // Clear any existing interval - clearInterval(moduleProgressInterval); - - // Update progress bar every 100ms for smooth animation - moduleProgressInterval = setInterval(function() { - if (!moduleClearStartTime || !lastDisplayedModule) { - clearInterval(moduleProgressInterval); - return; - } - - var elapsed = Date.now() - moduleClearStartTime; - var remaining = Math.max(0, 30000 - elapsed); - var progress = (remaining / 30000) * 100; // Percentage remaining (100% to 0%) - - // Update progress bar (shows remaining time, fills from left to right) - var progressBar = $("#module-indicator-progress"); - if (progressBar.length > 0) { - progressBar.css('width', progress + '%'); - } - - // Stop interval if timer is complete - if (progress <= 0) { - clearInterval(moduleProgressInterval); - } - }, 100); // Update every 100ms -} - -// Function to stop progress bar animation -function stopModuleProgressBar() { - clearInterval(moduleProgressInterval); - moduleClearStartTime = null; - var progressBar = $("#module-indicator-progress"); - if (progressBar.length > 0) { - progressBar.css('width', '100%'); - } -} - -// Function to update module indicator icon -function updateModuleIndicator() { - var indicator = $("#module-indicator"); - - // Check if there's a last displayed module and if it's currently hidden - if (lastDisplayedModule) { - var isCurrentlyVisible = false; - var moduleIcon = ''; - - if (lastDisplayedModule === 'idcard') { - isCurrentlyVisible = $("#ped-interaction-id-card").is(":visible"); - moduleIcon = 'fas fa-id-card'; - } else if (lastDisplayedModule === 'vehicle') { - isCurrentlyVisible = $("#vehicle-info").is(":visible"); - moduleIcon = 'fas fa-car'; - } else if (lastDisplayedModule === 'inventory') { - isCurrentlyVisible = $("#ped-interaction-inventory").is(":visible"); - moduleIcon = 'fas fa-box'; - } - - // Show indicator only if module is hidden - if (!isCurrentlyVisible) { - if (indicator.length === 0) { - // Create indicator if it doesn't exist - $('body').append(` -
-
- - ${language.Press} TAB -
-
-
-
-
- `); - // Show the indicator after creation - $("#module-indicator").fadeIn(200); - } else { - // Update existing indicator - indicator.find('i').attr('class', moduleIcon + ' me-2'); - indicator.find('span').html(`${language.Press} TAB`); - // Ensure progress bar container exists - if (indicator.find('.module-indicator-progress-container').length === 0) { - indicator.append(` -
-
-
- `); - } - indicator.fadeIn(200); - } - } else { - // Hide indicator if module is visible - indicator.fadeOut(200); - stopModuleProgressBar(); - } - } else { - // Hide indicator if no last displayed module - indicator.fadeOut(200); - } -} - -// Function to re-display last shown module (called from Lua client) -function redisplayLastModule() { - // Toggle visibility: hide if visible, show if hidden - if (lastDisplayedModule) { - var isCurrentlyVisible = false; - - if (lastDisplayedModule === 'idcard' && $("#ped-interaction-id-card").is(":visible")) { - isCurrentlyVisible = true; - } else if (lastDisplayedModule === 'vehicle' && $("#vehicle-info").is(":visible")) { - isCurrentlyVisible = true; - } else if (lastDisplayedModule === 'inventory' && $("#ped-interaction-inventory").is(":visible")) { - isCurrentlyVisible = true; - } - - if (isCurrentlyVisible) { - // Hide the module and clear timeout - if (lastDisplayedModule === 'idcard') { - clearTimeout(idCardTimeout); - $("#ped-interaction-id-card").hide(); - } else if (lastDisplayedModule === 'vehicle') { - clearTimeout(vehicleInfoTimeout); - $("#vehicle-info").hide(); - } else if (lastDisplayedModule === 'inventory') { - clearTimeout(inventoryTimeout); - $("#ped-interaction-inventory").hide(); - } - updateModuleIndicator(); - scheduleModuleClearIfHidden(); - } else { - // Show the module if currently hidden - // Clear the module clear timeout since we're showing it - clearTimeout(moduleClearTimeout); - stopModuleProgressBar(); - if (lastDisplayedModule === 'idcard' && lastIdCardData) { - DisplayPedIdCard(true, lastIdCardData.personaldata, lastIdCardData.showdatabasecheck, idCardDbCheckCompleted); - } else if (lastDisplayedModule === 'vehicle' && lastVehicleData) { - DisplayVehicleInfo(true, lastVehicleData.vehicleData, lastVehicleData.DisableTaxAndMOT, vehicleDbCheckCompleted); - } else if (lastDisplayedModule === 'inventory' && lastInventoryData) { - DisplayPedInventory(true, lastInventoryData.itemList); - } - updateModuleIndicator(); - } - } -} - -// NPC Backup Request Radial Menu -var listener = false; -function setupButton(buttonId, iconClass, instructionText) { - const button = document.getElementById(buttonId); - $(`#${buttonId}`).html(``); - - button.addEventListener('mouseenter', () => PlayNUISound('generic-sounds', "rollover", 0.5)); - button.addEventListener('mouseover', () => { - document.getElementById('instruction-text').style.display = 'block'; - $("#instruction-text").html(`

${instructionText}

`); - }); - button.addEventListener('mouseout', () => document.getElementById('instruction-text').style.display = 'none'); -} - -function setupRadialMenu() { - if (!listener) { - listener = true; - - /* - TO ADD NEW BACKUP, SIMPLY ADD YOUR BACKUP TYPE TO THE BUTTONS ARRAY BELOW AND CHANGE THE VALUES! - MAKE SURE TO CREATE THE REQUIRED FUNCTION AND ADD THE CSS CODE IN STYLES.CSS! - */ - - // INSTRUCTION - // const instructionText = document.getElementById('instruction-text'); - const buttons = [ - // THIS ALWAYS NEEDS TO BE THE FIRST ITEM IN THIS ARRAY! - { id: 'middle-x', iconClass: '', instruction: language.ExitRadialMenuInstruction, hoverColour: '', function: 'ToggleRadialMenu(false)' }, - // - { id: 'police-transport', iconClass: language.RequestPoliceTransportIcon, instruction: language.RequestPoliceTransportInstruction, hoverColour: '#0057b9', function: 'RequestOrCancelPoliceTransport()' }, - { id: 'ambulance-request', iconClass: language.RequestAmbulanceIcon, instruction: language.RequestAmbulanceInstruction, hoverColour: '#ff0000', function: 'RequestOrCancelAmbulance()' }, - { id: 'tow-request', iconClass: language.RequestTowIcon, instruction: language.RequestTowInstruction, hoverColour: '#782323', function: 'RequestOrCancelTow()' }, - { id: 'taxi-request', iconClass: language.RequestTaxiIcon, instruction: language.RequestTaxiInstruction, hoverColour: '#FF9A18', function: 'RequestOrCancelTaxi()' }, - { id: 'road-service-request', iconClass: language.RequestRoadServiceIcon, instruction: language.RequestRoadServiceInstruction, hoverColour: '#ffbf00', function: 'RequestOrCancelRoadService()' }, - { id: 'coroner-request', iconClass: language.RequestCoronerIcon, instruction: language.RequestCoronerInstruction, hoverColour: '#3D3D3D', function: 'RequestOrCancelCoroner()' }, - { id: 'animal-rescue-request', iconClass: language.RequestAnimalRescueIcon, instruction: language.RequestAnimalRescueInstruction, hoverColour: '#9bde00', function: 'RequestOrCancelAnimalRescue()' }, - { id: 'mechanic-request', iconClass: language.RequestMechanicIcon, instruction: language.RequestMechanicInstruction, hoverColour: '#3D3D3D', function: 'RequestOrCancelMechanic()' }, - { id: 'fire-request', iconClass: language.RequestFireIcon, instruction: language.RequestFireInstruction, hoverColour: '#3D3D3D', function: 'RequestOrCancelFire()' } - ]; - - $('#circle-menu').html(` -
+let resourceName=null,language=null,commands=null,firstnames={},lastnames={},isDisplayingPreCalloutInterface=!1,isDisplayingCalloutInterface=!1,isDragMode=!1,isDragging=!1,dragElement=null,dragOffset={x:0,y:0},isLayoutMode=!1,layoutElements={},visibleLayoutElements=new Set,originalStyles=new Map,layoutBoundaries={left:20,top:20,right:20,bottom:20},snapGrid={enabled:!0,size:10},collisionDetection={enabled:!0},dimensionValidation={enabled:!0};window.addEventListener("message",e=>{let t=e.data;if("playSound"==t.transactionType&&PlayNUISound(t.transactionFolder,t.transactionFile,t.transactionVolume),"init"==t.type&&("undefined"!=typeof $?(resourceName=t.resourcename,language=t.language,commands=t.commands,firstnames=t.firstnames,lastnames=t.lastnames,$.post(`https://${resourceName}/initComplete`,JSON.stringify({complete:!0}))):console.log("Script is still loading...")),"togglecalloutinfo"==t.type&&toggleCalloutInfo(),"toggleUILayoutMode"==t.type&&(console.log("Received toggleUILayoutMode message from Lua"),toggleUILayoutMode()),"emergencyUICleanup"==t.type&&(console.log("Received emergencyUICleanup message from Lua"),emergencyUICleanup()),"ersselectionmenu"==t.type){var a,n,i,o=t.display;ToggleERSSelectionMenu(o,t.permissions)}if("radialmenu"==t.type){var o=t.display;ToggleRadialMenu(o)}if("pursuitradialmenu"==t.type){var o=t.display;TogglePursuitRadialMenu(o)}if("pursuitmode"==t.type){var s,l,o=t.display,r=t.displayhotkeyhint;TogglePursuitModeUI(o,r,t.zoomhotkey,t.backuphotkey)}if("dualsteeringmode"==t.type){var o=t.display;ToggleDualSteeringMode(o)}if("hotkeyhintprompt"==t.type){var o=t.display,c=t.hotkeys,d=t.time;ToggleHotKeyHintPrompt(o,c,language,d)}if("dispatchmessage"==t.type){var u,o=t.display,c=t.hotkeys,g=t.messagetype,p=t.calloutdata,b=t.message,d=t.time;AddMessageToDispatchQueue(o,c,g,p,d,b,t.toggle)}if("calloutprompt"==t.type){var m,o=t.display,p=t.calloutdata,c=t.hotkeys,d=t.time;ToggleCalloutDisplayPrompt(o,c,language,d,p,t.serviceType)}if("calloutpreinterface"==t.type){var o=t.display,c=t.hotkeys,p=t.calloutdata;TogglePreCalloutInterface(o,c,p)}if("calloutinterface"==t.type){var h,y,o=t.display,c=t.hotkeys,f=t.pedCount,v=t.vehicleCount,x=t.objectCount,w=t.propCount,k=t.fireCount,C=t.smokeCount,p=t.calloutdata,I=t.pedOriginalCount,T=t.vehOriginalCount,S=t.objOriginalCount,P=t.propOriginalCount;ToggleCalloutInterface(o,c,f,v,x,w,k,C,p,I,T,S,P,t.fireOriginalCount,t.smokeOriginalCount)}if("unifiedprompt"==t.type){var o=t.display,E=t.promptType,R=t.hotkey,b=t.message,d=t.time;DisplayUnifiedPrompt(o,E,R,b,d)}if("interactionmodule"==t.type){var N,A,o=t.display;DisplayPedInteractionModule(o,t.ispeddeadordying,t.service)}if("idcardprompt"==t.type){var M,_,o=t.display;DisplayPedIdCard(o,t.pedpersonaldata,t.showdatabasecheck)}if("inventoryprompt"==t.type){var q,o=t.display;DisplayPedInventory(o,t.itemlist)}if("vehicleinfoprompt"==t.type){var D,O,o=t.display;DisplayVehicleInfo(o,t.vehicleData,t.DisableTaxAndMOT)}if("togglequestionsmodule"==t.type){var L,o=t.display;ToggleQuestionsModule(o,t.questions)}if("updateanswers"==t.type){var B,o=t.display;UpdateAnswers(o,t.answers)}if("addorremovewaypoint"==t.type&&AddWaypoint(t.addwaypoint),"updatewaypoint"==t.type){var U,j,F,G=t.scaleX;UpdateWaypointPosition(G,t.scaleY,t.distanceText)}if("areyousure"==t.type){var o=t.display;DisplayAreYouSurePopup(o)}if("gearmenu"==t.type){var W,o=t.display;DisplayGearMenu(o,t.locationdata)}if("updatezonechange"==t.type){UpdateZoneChangeUI(t.lastZone,t.currentZone)}"updatewaypoints"===t.type&&updateWaypoints(t)});var unifiedPromptTimeout,idCardTimeout,dbCheckTimeout,vehicleInfoTimeout,vehicleDbCheckTimeout,inventoryTimeout,zoneChangeTimeout=null;let zoneChangeQueue=[],isAnimating=!1;function UpdateZoneChangeUI(e,t){zoneChangeQueue.push({oldZone:e,newZone:t}),isAnimating||processNextZoneChange()}function processNextZoneChange(){if(0===zoneChangeQueue.length){isAnimating=!1;return}isAnimating=!0;let{oldZone:e,newZone:t}=zoneChangeQueue.shift(),a=document.getElementById("zone-change-ui");if(!a){processNextZoneChange();return}let n=a.querySelector(".old-zone"),i=a.querySelector(".new-zone");if(!n||!i){processNextZoneChange();return}zoneChangeTimeout&&clearTimeout(zoneChangeTimeout),a.classList.remove("show"),i.classList.remove("show"),n.textContent=e||"N/A",i.textContent=t||"N/A",a.offsetWidth,a.classList.add("show"),i.classList.add("show"),zoneChangeTimeout=setTimeout(()=>{a.classList.remove("show"),i.classList.remove("show"),setTimeout(processNextZoneChange,500)},4e3)}let escapeEventListenerAdded=!1;function DisplayAreYouSurePopup(e){if(e){$("#are-you-sure-modal").remove();let t=` `;$("body").append(t),$("#are-you-sure-modal").modal({backdrop:"static",keyboard:!1}),$("#are-you-sure-modal").modal("show"),$("#are-you-sure-modal").on("shown.bs.modal",function(){escapeEventListenerAdded||($(document).on("keydown",function(e){"Escape"===e.key&&($("#are-you-sure-modal").modal("hide"),handleNoClick(),e.stopPropagation())}),escapeEventListenerAdded=!0)}).on("hidden.bs.modal",function(){$(document).off("keydown"),escapeEventListenerAdded=!1})}else $("#are-you-sure-modal").remove()}function handleNoClick(){$.post(`https://${resourceName}/AreYouSure`,JSON.stringify({areyousure:!1})),$("#are-you-sure-modal").modal("hide")}function handleYesClick(){$.post(`https://${resourceName}/AreYouSure`,JSON.stringify({areyousure:!0})),$("#are-you-sure-modal").modal("hide")}function DisplayPedInteractionModule(e,t,a){if(e){if(DisplayUnifiedPrompt(!1),t)$("#ped-interaction-module").empty(),$("#ped-interaction-module").show(),$("#ped-interaction-module").append(`

${language.InteractionOptions}

${[{id:"identify",label:language.IdentifyDeadPed,explanation:language.IdentifyDeadPedExplanation},{id:"drag",label:language.DragPed,explanation:language.DragPedExplanation},{id:"massivebleeding",label:language.CheckMassiveBleeding,explanation:language.CheckMassiveExplanation},{id:"airway",label:language.CheckAirway,explanation:language.CheckAirwayExplanation},{id:"breathing",label:language.CheckBreathing,explanation:language.CheckBreathingExplanation},{id:"circulation",label:language.CheckCirculation,explanation:language.CheckCirculationExplanation},{id:"hypothermia",label:language.CheckHypothermia,explanation:language.CheckHypothermiaExplanation},{id:"cpr",label:language.PerformCPR,explanation:language.PerformCPRExplanation},{id:"putonstretcher",label:language.PutOnStretcher,explanation:language.PutOnStretcherExplanation},{id:"takeoffstretcher",label:language.TakeOffStretcher,explanation:language.TakeOffStretcherExplanation},{id:"bodybag",label:language.PutInBodyBag,explanation:language.PutInBodyBagExplanation}].map(e=>`
${e.explanation}
`).join("")}

`),applySavedPosition("ped-interaction-module"),["identify","drag","massivebleeding","airway","breathing","circulation","hypothermia","cpr","putonstretcher","takeoffstretcher","bodybag","exit"].forEach(e=>addSoundOnHoverEventListener(`p-btn-${e}`));else{$("#ped-interaction-module").empty(),$("#ped-interaction-module").show();var n={police:[{id:"greet",label:language.Greet,explanation:language.GreetExplanation},{id:"id",label:language.AskForId,explanation:language.AskForIdExplanation},{id:"questioning",label:language.Question,explanation:language.QuestionExplanation},{id:"breathalyze",label:language.Breathalyze,explanation:language.BreathalyzeExplanation},{id:"drugtest",label:language.DrugTest,explanation:language.DrugTestExplanation},{id:"warn",label:language.Warn,explanation:language.WarnExplanation},{id:"fine",label:language.Fine,explanation:language.FineExplanation},{id:"grab",label:language.Grab,explanation:language.GrabExplanation},{id:"getout",label:language.GetOut,explanation:language.GetOutExplanation},{id:"follow",label:language.AskToFollow,explanation:language.AskToFollowExplanation},{id:"wait",label:language.AskToWait,explanation:language.AskToWaitExplanation},{id:"handsup",label:language.HandsUp,explanation:language.HandsUpExplanation},{id:"search",label:language.Search,explanation:language.SearchExplanation},{id:"cuff",label:language.Cuff,explanation:language.CuffExplanation},{id:"putinvehicle",label:language.PutInVehicle,explanation:language.PutInVehicleExplanation}],ambulance:[{id:"greet",label:language.Greet,explanation:language.GreetExplanation},{id:"questioning",label:language.Question,explanation:language.QuestionExplanation},{id:"breathalyze",label:language.Breathalyze,explanation:language.BreathalyzeExplanation},{id:"drugtest",label:language.DrugTest,explanation:language.DrugTestExplanation},{id:"getout",label:language.GetOut,explanation:language.GetOutExplanation},{id:"follow",label:language.AskToFollow,explanation:language.AskToFollowExplanation},{id:"wait",label:language.AskToWait,explanation:language.AskToWaitExplanation},{id:"putinvehicle",label:language.PutInVehicle,explanation:language.PutInVehicleExplanation}],fire:[{id:"greet",label:language.Greet,explanation:language.GreetExplanation},{id:"questioning",label:language.Question,explanation:language.QuestionExplanation},{id:"breathalyze",label:language.Breathalyze,explanation:language.BreathalyzeExplanation},{id:"drugtest",label:language.DrugTest,explanation:language.DrugTestExplanation},{id:"getout",label:language.GetOut,explanation:language.GetOutExplanation},{id:"follow",label:language.AskToFollow,explanation:language.AskToFollowExplanation},{id:"wait",label:language.AskToWait,explanation:language.AskToWaitExplanation},{id:"putinvehicle",label:language.PutInVehicle,explanation:language.PutInVehicleExplanation}],tow:[{id:"greet",label:language.Greet,explanation:language.GreetExplanation},{id:"questioning",label:language.Question,explanation:language.QuestionExplanation},{id:"getout",label:language.GetOut,explanation:language.GetOutExplanation},{id:"follow",label:language.AskToFollow,explanation:language.AskToFollowExplanation},{id:"wait",label:language.AskToWait,explanation:language.AskToWaitExplanation},{id:"putinvehicle",label:language.PutInVehicle,explanation:language.PutInVehicleExplanation}]};$("#ped-interaction-module").append(`

${language.InteractionOptions}

${(n[a]||n.police).map(e=>`
${e.explanation}
`).join("")}

${"police"===a?``:""}
`);let i=n[a]||n.police,o=[...i.map(e=>e.id),"end","exit",..."police"===a?["custody"]:[]];o.forEach(e=>addSoundOnHoverEventListener(`p-btn-${e}`)),applySavedPosition("ped-interaction-module")}}else $("#ped-interaction-module").hide()}function PedInteraction(e){$.post(`https://${resourceName}/pedInteraction`,JSON.stringify({interactionType:e}))}function addSoundOnHoverEventListener(e){document.getElementById(e).addEventListener("mouseenter",function(){PlayNUISound("generic-sounds","rollover",.5)})}function DisplayUnifiedPrompt(e,t,a,n,i){if(e){$("#unified-prompt").show(),applySavedPosition("unified-prompt"),clearTimeout(unifiedPromptTimeout);let o={pedinteraction:{icon:"\uD83D\uDCAC",color:"text-warning",text:language.ToInteract,timeout:1500},injuredped:{icon:"\uD83E\uDE7A",color:"text-danger",text:language.ToPerformCPR,timeout:1500},impound:{icon:"\uD83D\uDE97",color:"text-danger",text:language.ToInteractImpound,timeout:1500},gear:{icon:"\uD83D\uDE97",color:"text-danger",text:language.ToInteractGear,timeout:1500},stretcher:{icon:"\uD83C\uDFE5",color:"text-info",text:language.ToUseStretcherVeh,timeout:1500},objectcleanup:{icon:"\uD83E\uDDF9",color:"text-success",text:language.ToCleanupObject,timeout:1500},spikesvehicle:{icon:"\uD83D\uDCA2",color:"text-warning",text:n||"",timeout:i||1500}},s=o[t]||o.pedinteraction;$("#unified-prompt").html(` +
${s.icon} ${language.Press} ${a} ${s.text}
+ `),unifiedPromptTimeout=setTimeout(function(){$("#unified-prompt").hide()},s.timeout)}else $("#unified-prompt").hide()}function DisplayPedIdCard(e,t,a){if(e){$("#vehicle-info").hide(),$("#ped-interaction-inventory").hide(),clearTimeout(idCardTimeout),clearTimeout(dbCheckTimeout),$("#ped-interaction-id-card").empty();var n=t.ProfilePicture||"N/A",i=t.FirstName||"N/A",o=t.LastName||"N/A",s=t.DOB||"N/A",l=t.Gender||"N/A",r=t.Email||"N/A",c=t.PhoneNumber||"N/A",d=t.Country||"N/A",u=t.State||"N/A",g=t.City||"N/A",p=t.PostalCode||"N/A",b=t.Address||"N/A";t.AddressType;var m=t.Nationality||"N/A",h=t.FlagsOrMarkers,y=t.License_Car||"N/A",f=t.License_Car_Colour||"text-light",v=t.License_Car_Icon||"fas fa-car",x=t.License_Bike||"N/A",w=t.License_Bike_Colour||"text-light",k=t.License_Bike_Icon||"fas fa-bicycle",C=t.License_Boat||"N/A",I=t.License_Boat_Colour||"text-light",T=t.License_Boat_Icon||"fas fa-ship",S=t.License_Truck||"N/A",P=t.License_Truck_Colour||"text-light",E=t.License_Truck_Icon||"fas fa-truck",R=t.License_Pilot||"N/A",N=t.License_Pilot_Colour||"text-light",A=t.License_Pilot_Icon||"fas fa-plane";$("#ped-interaction-id-card").append(`
${language.PersonalDetails}
`),$("#ped-interaction-id-card").show(),applySavedPosition("ped-interaction-id-card"),a&&($("#ped-interaction-id-card").append(`
${language.DatabaseCheck}
Loading...

${language.RunningDatabaseCheck}

`),dbCheckTimeout=setTimeout(function(){$("#initial-check").remove(),$("#database-check").html(`
${language.DatabaseCheckResults}
${i} ${o}
Photo
(${s})
  • ${language.Nationality} ${m}
  • ${language.Gender} ${l}
  • ${language.Address} ${b}, ${g}, ${u} ${p} (${d})
  • ${language.Email} ${r} | ${language.PhoneNumber} ${c}
${language.Licenses}
${y} ${x} ${C} ${S} ${R}
${h&&Object.keys(h).some(e=>h[e])?`
${language.FlagsOrMarkers}

${h.armed_and_dangerous?` ${language.armed_and_dangerous}
`:""} ${h.assault?` ${language.assault}
`:""} ${h.burglary?` ${language.burglary}
`:""} ${h.drug_related?` ${language.drug_related}
`:""} ${h.gang_affiliation?` ${language.gang_affiliation}
`:""} ${h.homicide?` ${language.homicide}
`:""} ${h.kidnapping?` ${language.kidnapping}
`:""} ${h.mental_health_issues?` ${language.mental_health_issues}
`:""} ${h.sex_offense?` ${language.sex_offense}
`:""} ${h.terrorism?` ${language.terrorism}
`:""} ${h.theft?` ${language.theft}
`:""} ${h.traffic_violation?` ${language.traffic_violation}
`:""} ${h.wanted_person?` ${language.wanted_person}
`:""} ${h.other?` ${language.other}
`:""} ${h.active_warrant?` ${language.active_warrant}
`:""}

`:""}
`)},3e3)),idCardTimeout=setTimeout(function(){$("#ped-interaction-id-card").hide()},15e3)}else $("#ped-interaction-id-card").hide()}function DisplayVehicleInfo(e,t,a){if(e){$("#ped-interaction-id-card").hide(),$("#ped-interaction-inventory").hide(),clearTimeout(vehicleInfoTimeout),clearTimeout(vehicleDbCheckTimeout),$("#vehicle-info").empty();var n={vehNetId:t.vehNetId,license_plate:t.license_plate,model:t.model,model_hash:t.model_hash,vehicle_class:t.vehicle_class,vehicle_class_from_name:t.vehicle_class_from_name,color:t.color,color_secondary:t.color_secondary,build_year:t.build_year,tax:t.tax,mot:t.mot,insurance:t.insurance,stolen:t.stolen,bolo:t.bolo,bolo_description:t.bolo_description,owner_name:t.owner_name};$("#vehicle-info").append(`
${language.VehicleDetails}
`),$("#vehicle-info").append(`
${language.DatabaseCheck}
Loading...

${language.RunningDatabaseCheck}

`),$("#vehicle-info").show(),applySavedPosition("vehicle-info"),vehicleDbCheckTimeout=setTimeout(function(){$("#vehicle-info-database-check").html(`
${language.DatabaseCheckResults}
`)},5e3),vehicleInfoTimeout=setTimeout(function(){$("#vehicle-info").hide()},15e3)}else $("#vehicle-info").hide()}function DisplayPedInventory(e,t){e?($("#ped-interaction-id-card").hide(),$("#vehicle-info").hide(),clearTimeout(inventoryTimeout),$("#ped-interaction-inventory").empty(),$("#ped-interaction-inventory").append(`

${language.Inventory}

`),$.each(t,function(e,t){var a,n=` ${t.name} `;$("#inventory-table-body").append(n)}),$("#ped-interaction-inventory").show(),applySavedPosition("ped-interaction-inventory"),inventoryTimeout=setTimeout(function(){$("#ped-interaction-inventory").hide()},15e3)):$("#ped-interaction-inventory").hide()}var listener=!1;function setupButton(e,t,a){let n=document.getElementById(e);$(`#${e}`).html(``),n.addEventListener("mouseenter",()=>PlayNUISound("generic-sounds","rollover",.5)),n.addEventListener("mouseover",()=>{document.getElementById("instruction-text").style.display="block",$("#instruction-text").html(`

${a}

`)}),n.addEventListener("mouseout",()=>document.getElementById("instruction-text").style.display="none")}function setupRadialMenu(){if(!listener){listener=!0;let e=[{id:"middle-x",iconClass:"",instruction:language.ExitRadialMenuInstruction,hoverColour:"",function:"ToggleRadialMenu(false)"},{id:"police-transport",iconClass:language.RequestPoliceTransportIcon,instruction:language.RequestPoliceTransportInstruction,hoverColour:"#0057b9",function:"RequestOrCancelPoliceTransport()"},{id:"ambulance-request",iconClass:language.RequestAmbulanceIcon,instruction:language.RequestAmbulanceInstruction,hoverColour:"#ff0000",function:"RequestOrCancelAmbulance()"},{id:"tow-request",iconClass:language.RequestTowIcon,instruction:language.RequestTowInstruction,hoverColour:"#782323",function:"RequestOrCancelTow()"},{id:"taxi-request",iconClass:language.RequestTaxiIcon,instruction:language.RequestTaxiInstruction,hoverColour:"#FF9A18",function:"RequestOrCancelTaxi()"},{id:"road-service-request",iconClass:language.RequestRoadServiceIcon,instruction:language.RequestRoadServiceInstruction,hoverColour:"#ffbf00",function:"RequestOrCancelRoadService()"},{id:"coroner-request",iconClass:language.RequestCoronerIcon,instruction:language.RequestCoronerInstruction,hoverColour:"#3D3D3D",function:"RequestOrCancelCoroner()"},{id:"animal-rescue-request",iconClass:language.RequestAnimalRescueIcon,instruction:language.RequestAnimalRescueInstruction,hoverColour:"#9bde00",function:"RequestOrCancelAnimalRescue()"},{id:"mechanic-request",iconClass:language.RequestMechanicIcon,instruction:language.RequestMechanicInstruction,hoverColour:"#3D3D3D",function:"RequestOrCancelMechanic()"},{id:"fire-request",iconClass:language.RequestFireIcon,instruction:language.RequestFireInstruction,hoverColour:"#3D3D3D",function:"RequestOrCancelFire()"}];$("#circle-menu").html(` +
- `) - - buttons.forEach(({ id, iconClass, instruction }) => setupButton(id, iconClass, instruction)); - } -} - -function ToggleRadialMenu(display) { - setupRadialMenu(); - - if (display) { - // Add escape key event listener - document.addEventListener('keyup', handleRadialMenuEscape); - - const instructionTitle = document.getElementById('instruction-title'); - instructionTitle.style.display = 'block'; - $("#instruction-title").html(`

${language.RadialMenuInstructionTitle}

`); - $("#circle-menu").show(); - - // Apply the blur overlay - $("body").append("
"); - - } else { - // Remove escape key event listener - document.removeEventListener('keyup', handleRadialMenuEscape); - - PlayNUISound('generic-sounds', "radialclose", 0.5); - - // Hide all instruction elements - const instructionTitle = document.getElementById('instruction-title'); - const instructionText = document.getElementById('instruction-text'); - - if (instructionTitle) { - instructionTitle.style.display = 'none'; - } - if (instructionText) { - instructionText.style.display = 'none'; - } - - $("#circle-menu").hide(); - $.post(`https://${resourceName}/closeRadialMenu`, JSON.stringify({})); - - // Remove the blur overlay - $(".blur-overlay").remove(); - } -} - -function handleRadialMenuEscape(event) { - if (event.key === 'Escape') { - ToggleRadialMenu(false); - } -} - -function RequestOrCancelPoliceTransport() { - ToggleRadialMenu(false) - $.post(`https://${resourceName}/requestOrCancelPoliceTransport`, JSON.stringify({})) -} - -function RequestOrCancelAmbulance() { - ToggleRadialMenu(false) - $.post(`https://${resourceName}/requestOrCancelAmbulance`, JSON.stringify({})) -} - -function RequestOrCancelTow() { - ToggleRadialMenu(false) - $.post(`https://${resourceName}/requestOrCancelTow`, JSON.stringify({})) -} - -function RequestOrCancelTaxi() { - ToggleRadialMenu(false) - $.post(`https://${resourceName}/requestOrCancelTaxi`, JSON.stringify({})) -} - -function RequestOrCancelRoadService() { - ToggleRadialMenu(false) - $.post(`https://${resourceName}/requestOrCancelRoadService`, JSON.stringify({})) -} - -function RequestOrCancelCoroner() { - ToggleRadialMenu(false) - $.post(`https://${resourceName}/requestOrCancelCoroner`, JSON.stringify({})) -} - -function RequestOrCancelAnimalRescue() { - ToggleRadialMenu(false) - $.post(`https://${resourceName}/requestOrCancelAnimalRescue`, JSON.stringify({})) -} - -function RequestOrCancelMechanic() { - ToggleRadialMenu(false) - $.post(`https://${resourceName}/requestOrCancelMechanic`, JSON.stringify({})) -} - -function RequestOrCancelFire() { - ToggleRadialMenu(false) - $.post(`https://${resourceName}/requestOrCancelFire`, JSON.stringify({})) -} - -// Pursuit Mode UI - -function TogglePursuitModeUI(display, displayhotkeyhint, zoomhotkey, backuphotkey) { - $("#pursuit-mode-ui").toggle(display); - if (display) { - - // MINIFY - $("#pursuit-mode-ui").html(`
${language.ActivePursuit}
${displayhotkeyhint ? `
${zoomhotkey} (${language.PursuitHotkeyFocus}) | ${backuphotkey} (${language.PursuitHotkeyBackup})
` : ''}
`); - - // HTML - // $("#pursuit-mode-ui").html(` - //
- //
- //
- //
- // ${language.ActivePursuit} - //
- //
- //
- // ${displayhotkeyhint ? ` - //
- // ${zoomhotkey} (${language.PursuitHotkeyFocus}) | ${backuphotkey} (${language.PursuitHotkeyBackup}) - //
- // ` : ''} - //
- //
- //
- // `); - - } else { - $("#pursuit-mode-ui").hide(); - } -} - -//Pursuit Radial Menu -var pursuitRadialMenuListener = false; -function setupPursuitRadialMenuButton(buttonId, iconClass, instructionText) { - const button = document.getElementById(buttonId); - $(`#${buttonId}`).html(``); - - // Use mouseenter instead of mouseover to prevent event bubbling - button.addEventListener('mouseenter', () => { - PlayNUISound('generic-sounds', "rollover", 0.5); - document.getElementById('pursuit-instruction-text').style.display = 'block'; - $("#pursuit-instruction-text").html(`

${instructionText}

`); - }); - - // Use mouseleave instead of mouseout to prevent event bubbling - button.addEventListener('mouseleave', () => { - document.getElementById('pursuit-instruction-text').style.display = 'none'; - }); -} - -function setupPursuitRadialMenu() { - if (!pursuitRadialMenuListener) { - pursuitRadialMenuListener = true; - - // INSTRUCTION - // const instructionText = document.getElementById('pursuit-instruction-text'); - const buttons = [ - // THIS ALWAYS NEEDS TO BE THE FIRST ITEM IN THIS ARRAY! - { id: 'pursuit-middle-x', iconClass: '', instruction: language.ExitRadialMenuInstruction, hoverColour: '', function: 'TogglePursuitRadialMenu(false)' }, - // - { id: 'pursuit-backup-light', iconClass: language.RequestLightBackupIcon, instruction: language.RequestLightBackupInstruction, hoverColour: '#0080f8', function: "RequestPursuitBackup('light')" }, - { id: 'pursuit-backup-medium', iconClass: language.RequestMediumBackupIcon, instruction: language.RequestMediumBackupInstruction, hoverColour: '#014b8f', function: "RequestPursuitBackup('medium')" }, - { id: 'pursuit-backup-heavy', iconClass: language.RequestHeavyBackupIcon, instruction: language.RequestHeavyBackupInstruction, hoverColour: '#001e39', function: "RequestPursuitBackup('heavy')" }, - { id: 'pursuit-backup-air', iconClass: language.RequestAirBackupIcon, instruction: language.RequestAirBackupInstruction, hoverColour: '#00a2dd', function: "RequestPursuitBackup('air')" }, - { id: 'pursuit-backup-army', iconClass: language.RequestArmyBackupIcon, instruction: language.RequestArmyBackupInstruction, hoverColour: '#647b32', function: "RequestPursuitBackup('army')" }, - ]; - - $('#pursuit-radial-menu').html(` -
+ `),e.forEach(({id:e,iconClass:t,instruction:a})=>setupButton(e,t,a))}}function ToggleRadialMenu(e){if(setupRadialMenu(),e){document.addEventListener("keyup",handleRadialMenuEscape);let t=document.getElementById("instruction-title");t.style.display="block",$("#instruction-title").html(`

${language.RadialMenuInstructionTitle}

`),$("#circle-menu").show(),$("body").append("
")}else{document.removeEventListener("keyup",handleRadialMenuEscape),PlayNUISound("generic-sounds","radialclose",.5);let a=document.getElementById("instruction-title"),n=document.getElementById("instruction-text");a&&(a.style.display="none"),n&&(n.style.display="none"),$("#circle-menu").hide(),$.post(`https://${resourceName}/closeRadialMenu`,JSON.stringify({})),$(".blur-overlay").remove()}}function handleRadialMenuEscape(e){"Escape"===e.key&&ToggleRadialMenu(!1)}function RequestOrCancelPoliceTransport(){ToggleRadialMenu(!1),$.post(`https://${resourceName}/requestOrCancelPoliceTransport`,JSON.stringify({}))}function RequestOrCancelAmbulance(){ToggleRadialMenu(!1),$.post(`https://${resourceName}/requestOrCancelAmbulance`,JSON.stringify({}))}function RequestOrCancelTow(){ToggleRadialMenu(!1),$.post(`https://${resourceName}/requestOrCancelTow`,JSON.stringify({}))}function RequestOrCancelTaxi(){ToggleRadialMenu(!1),$.post(`https://${resourceName}/requestOrCancelTaxi`,JSON.stringify({}))}function RequestOrCancelRoadService(){ToggleRadialMenu(!1),$.post(`https://${resourceName}/requestOrCancelRoadService`,JSON.stringify({}))}function RequestOrCancelCoroner(){ToggleRadialMenu(!1),$.post(`https://${resourceName}/requestOrCancelCoroner`,JSON.stringify({}))}function RequestOrCancelAnimalRescue(){ToggleRadialMenu(!1),$.post(`https://${resourceName}/requestOrCancelAnimalRescue`,JSON.stringify({}))}function RequestOrCancelMechanic(){ToggleRadialMenu(!1),$.post(`https://${resourceName}/requestOrCancelMechanic`,JSON.stringify({}))}function RequestOrCancelFire(){ToggleRadialMenu(!1),$.post(`https://${resourceName}/requestOrCancelFire`,JSON.stringify({}))}function TogglePursuitModeUI(e,t,a,n){$("#pursuit-mode-ui").toggle(e),e?$("#pursuit-mode-ui").html(`
${language.ActivePursuit}
${t?`
${a} (${language.PursuitHotkeyFocus}) | ${n} (${language.PursuitHotkeyBackup})
`:""}
`):$("#pursuit-mode-ui").hide()}var pursuitRadialMenuListener=!1;function setupPursuitRadialMenuButton(e,t,a){let n=document.getElementById(e);$(`#${e}`).html(``),n.addEventListener("mouseenter",()=>{PlayNUISound("generic-sounds","rollover",.5),document.getElementById("pursuit-instruction-text").style.display="block",$("#pursuit-instruction-text").html(`

${a}

`)}),n.addEventListener("mouseleave",()=>{document.getElementById("pursuit-instruction-text").style.display="none"})}function setupPursuitRadialMenu(){if(!pursuitRadialMenuListener){pursuitRadialMenuListener=!0;let e=[{id:"pursuit-middle-x",iconClass:"",instruction:language.ExitRadialMenuInstruction,hoverColour:"",function:"TogglePursuitRadialMenu(false)"},{id:"pursuit-backup-light",iconClass:language.RequestLightBackupIcon,instruction:language.RequestLightBackupInstruction,hoverColour:"#0080f8",function:"RequestPursuitBackup('light')"},{id:"pursuit-backup-medium",iconClass:language.RequestMediumBackupIcon,instruction:language.RequestMediumBackupInstruction,hoverColour:"#014b8f",function:"RequestPursuitBackup('medium')"},{id:"pursuit-backup-heavy",iconClass:language.RequestHeavyBackupIcon,instruction:language.RequestHeavyBackupInstruction,hoverColour:"#001e39",function:"RequestPursuitBackup('heavy')"},{id:"pursuit-backup-air",iconClass:language.RequestAirBackupIcon,instruction:language.RequestAirBackupInstruction,hoverColour:"#00a2dd",function:"RequestPursuitBackup('air')"},{id:"pursuit-backup-army",iconClass:language.RequestArmyBackupIcon,instruction:language.RequestArmyBackupInstruction,hoverColour:"#647b32",function:"RequestPursuitBackup('army')"},];$("#pursuit-radial-menu").html(` +
- `) - - buttons.forEach(({ id, iconClass, instruction }) => setupPursuitRadialMenuButton(id, iconClass, instruction)); - } -} - -function TogglePursuitRadialMenu(display) { - setupPursuitRadialMenu(); - - if (display) { - // Add escape key event listener - document.addEventListener('keyup', handlePursuitRadialMenuEscape); - - const instructionTitle = document.getElementById('pursuit-instruction-title'); - instructionTitle.style.display = 'block'; - $("#pursuit-instruction-title").html(`

${language.PursuitRadialMenuInstructionTitle}

`); - $("#pursuit-radial-menu").show(); - - // Apply the blur overlay - $("body").append("
"); - - } else { - // Remove escape key event listener - document.removeEventListener('keyup', handlePursuitRadialMenuEscape); - - PlayNUISound('generic-sounds', "radialclose", 0.5); - const instructionTitle = document.getElementById('pursuit-instruction-title'); - if (instructionTitle) { - instructionTitle.style.display = 'none'; - } - const instructionText = document.getElementById('pursuit-instruction-text'); - if (instructionText) { - instructionText.style.display = 'none'; - } - - $("#pursuit-radial-menu").hide(); - $.post(`https://${resourceName}/closePursuitRadialMenu`, JSON.stringify({})); - - // Remove the blur overlay - $(".blur-overlay").remove(); - } -} - -function handlePursuitRadialMenuEscape(event) { - if (event.key === 'Escape') { - TogglePursuitRadialMenu(false); - } -} - -function RequestPursuitBackup(unitType) { - TogglePursuitRadialMenu(false) - $.post(`https://${resourceName}/requestPursuitBackup`, JSON.stringify({unitType: unitType})); -} - -// DISPATCH - -var isDispatchQueueProcessing = false; -var dispatchMessages = []; - -function AddMessageToDispatchQueue(display, hotkeys, messagetype, calloutdata, timeInMS, message, toggle) { - dispatchMessages.push({ display: display, hotkeys: hotkeys, messagetype: messagetype, calloutdata: calloutdata, timeInMS: timeInMS, message: message, toggle: toggle }); - if (!isDispatchQueueProcessing) { - ProcessDispatchQueue(); - } -} - -function ProcessDispatchQueue() { - if (dispatchMessages.length > 0) { - isDispatchQueueProcessing = true; - - var message = dispatchMessages[0]; // Get the first message from the queue without removing it - - DisplayDispatchMessage(message.display, message.hotkeys, message.messagetype, message.calloutdata, message.message, message.toggle); - - // Determine the timeout duration based on the message.toggle property - var timeoutDuration = message.toggle ? message.timeInMS : 3000; // Use 3000ms if toggle is false - - // Set the countdown timer for the message - StartCountdownTimer(timeoutDuration); - - setTimeout(function() { - dispatchMessages.shift(); // Remove the first message from the queue - ProcessDispatchQueue(); - }, timeoutDuration); - } else { - isDispatchQueueProcessing = false; - $("#dispatch-message-prompt-container").hide(); // Hide the message prompt container if there are no more messages - } -} - -function getDispatchIcon(messagetype) { - switch(messagetype) { - case "response": - return ''; - case "arrival": - return ''; - case "detach": - return ''; - case "shift": - return ''; - case "ambulance": - return ''; - case "police": - return ''; - case "fire": - return ''; - case "tow": - return ''; - case "taxi": - return ''; - default: - return ''; - } -} - -function DisplayDispatchMessage(display, hotkeys, messagetype, calloutdata, message, toggle) { - - if (!toggle) { - $("#dispatch-message-prompt-container").empty().show().append(` + `),e.forEach(({id:e,iconClass:t,instruction:a})=>setupPursuitRadialMenuButton(e,t,a))}}function TogglePursuitRadialMenu(e){if(setupPursuitRadialMenu(),e){document.addEventListener("keyup",handlePursuitRadialMenuEscape);let t=document.getElementById("pursuit-instruction-title");t.style.display="block",$("#pursuit-instruction-title").html(`

${language.PursuitRadialMenuInstructionTitle}

`),$("#pursuit-radial-menu").show(),$("body").append("
")}else{document.removeEventListener("keyup",handlePursuitRadialMenuEscape),PlayNUISound("generic-sounds","radialclose",.5);let a=document.getElementById("pursuit-instruction-title");a&&(a.style.display="none");let n=document.getElementById("pursuit-instruction-text");n&&(n.style.display="none"),$("#pursuit-radial-menu").hide(),$.post(`https://${resourceName}/closePursuitRadialMenu`,JSON.stringify({})),$(".blur-overlay").remove()}}function handlePursuitRadialMenuEscape(e){"Escape"===e.key&&TogglePursuitRadialMenu(!1)}function RequestPursuitBackup(e){TogglePursuitRadialMenu(!1),$.post(`https://${resourceName}/requestPursuitBackup`,JSON.stringify({unitType:e}))}var isDispatchQueueProcessing=!1,dispatchMessages=[];function AddMessageToDispatchQueue(e,t,a,n,i,o,s){dispatchMessages.push({display:e,hotkeys:t,messagetype:a,calloutdata:n,timeInMS:i,message:o,toggle:s}),isDispatchQueueProcessing||ProcessDispatchQueue()}function ProcessDispatchQueue(){if(dispatchMessages.length>0){isDispatchQueueProcessing=!0;var e=dispatchMessages[0];DisplayDispatchMessage(e.display,e.hotkeys,e.messagetype,e.calloutdata,e.message,e.toggle);var t=e.toggle?e.timeInMS:3e3;StartCountdownTimer(t),setTimeout(function(){dispatchMessages.shift(),ProcessDispatchQueue()},t)}else isDispatchQueueProcessing=!1,$("#dispatch-message-prompt-container").hide()}function DisplayDispatchMessage(e,t,a,n,i,o){if(!o){$("#dispatch-message-prompt-container").empty().show().append(`
${language.DispatchMessage}
- `); - return; - } - - - if (messagetype == "response" || messagetype == "arrival") { - - if (messagetype == "response") { - $.post(`https://${resourceName}/offerToTrackPlayer`, JSON.stringify({calloutdata: calloutdata})); - } - - // HTML - $("#dispatch-message-prompt-container").empty().show().append(` -
-
- ${language.DispatchMessage} - - ${getDispatchIcon(messagetype)} - -
-
- ${calloutdata.CalloutName ? ` -
- ${calloutdata.CalloutName} -
- ` : ''} -
- ${message}
- ${calloutdata.Description ? ` - ${calloutdata.Description} - ` : ''} -
-
- ${language.Caller} - ${calloutdata.FirstName} ${calloutdata.LastName} -
-
- ${language.Location} - ${calloutdata.StreetName ?? 'N/A'} -
-
- ${language.Postal} - ${calloutdata.Postal ?? 'N/A'} -
-
- -
- `); - - if (messagetype == "response") { - - // HTML - $("#dispatch-message-prompt-container").append(` -
- - ${language.TrackUnitProposal} - - -
- `) - - } - - } else { // if (messagetype == "detach" || messagetype == "shift" || messagetype == "ambulance" || messagetype == "police" || messagetype == "taxi" || messagetype == "tow" etc...) - - // HTML - $("#dispatch-message-prompt-container").empty().show().append(` -
-
- ${language.DispatchMessage} - - ${getDispatchIcon(messagetype)} - -
-
-
- ${message} -
-
- -
- `); - } -} - -function StartCountdownTimer(timeInMS) { - var remainingTime = timeInMS / 1000; // Convert milliseconds to seconds - const countdownMessage = `${language.NextDispatchMessage} ${remainingTime} ${language.Seconds}...`; - - $("#countdown-timer").html(`${wrapText(countdownMessage, 70)}`); // Wrap text with max 30 characters per line - - var timerInterval = setInterval(function() { - remainingTime--; - - if (remainingTime >= 0) { - $("#countdown-timer").html(`${wrapText(`${language.NextDispatchMessage} ${remainingTime} ${language.Seconds}...`, 70)}`); // Wrap text with max 30 characters per line - } else { - clearInterval(timerInterval); - $("#countdown-timer").html(`${wrapText("Time's up!", 70)}`); // Wrap "Time's up!" with max 30 characters per line - } - }, 1000); -} - -// HINTS - -function ToggleHotKeyHintPrompt(display, hotkeys, language, time) { - if (display) { - $("#hint-prompt-container").empty(); // clear previous data - $("#hint-prompt-container").show(); - - // HTML - $("#hint-prompt-container").append(` -
-
- ${language.Hint} -
-
-
- ${language.Aim} + ${hotkeys.OrderOnKneesOrStandUp} - ${language.OrderOnKneesOrStandUpExplanation} -
-
- ${hotkeys.PullOver} - ${language.PullOver} -
-
- ${hotkeys.AcceptCallout} - ${language.AcceptCallout} -
-
- ${hotkeys.CompleteCallout} - ${language.CompleteCallout} -
-
- ${hotkeys.RadialMenu} - ${language.RadialMenuExplanation} -
-
- /${commands.StopTrackingUnit} - ${language.StopTrackingUnitExplanation} -
-
- -
- `); - - // Auto-hide after elapsed time - setTimeout(function() { - $("#hint-prompt-container").hide(); - $.post(`https://${resourceName}/reallowPromptMessages`, JSON.stringify({})); - }, time); // 10 seconds in milliseconds - } else { - $("#hint-prompt-container").empty(); - $("#hint-prompt-container").hide(); - } -} - -// CALLOUTS (DISPATCH) - -function ToggleCalloutDisplayPrompt(display, hotkeys, language, time, calloutdata, serviceType) { - var calloutDisplayPromptTime = (time / 1000); // in s - - if (display) { - $("#callout-prompt-container").empty(); // clear previous data - $("#callout-prompt-container").show(); - - // HTML - $("#callout-prompt-container").append(` -
-
- ${language.EmergencyCall} - ${calloutdata.CalloutName} -
-
-
- ${language.Caller} - ${calloutdata.FirstName} ${calloutdata.LastName} -
-
- ${language.Location} - ${calloutdata.StreetName ?? 'N/A'} -
-
- ${language.Postal} - ${calloutdata.Postal ?? 'N/A'} -
-
- ${calloutdata.Description ?? 'N/A'} -
-
- -
- `); - - // Clear any existing countdown interval - clearInterval(window.countdownInterval); - - // Initial countdown display - const countdownMessage = `${calloutDisplayPromptTime} ${language.Seconds}...`; - $("#callout-countdown-timer").html(countdownMessage); - - calloutDisplayPromptTime--; - - window.countdownInterval = setInterval(function() { - if (calloutDisplayPromptTime > 0) { - // Update countdown display - const countdownMessage = `${calloutDisplayPromptTime} ${language.Seconds}...`; - $("#callout-countdown-timer").html(countdownMessage); - - calloutDisplayPromptTime--; - } else { - clearInterval(window.countdownInterval); - $("#callout-prompt-container").hide(); - $.post(`https://${resourceName}/calloutTimeout`, JSON.stringify({})); - } - }, 1000); // update every second - - } else { - $("#callout-prompt-container").empty(); // clear previous data - $("#callout-prompt-container").hide(); - } -} - -function ToggleCalloutInterface(display, hotkeys, pedCount, vehicleCount, objectCount, propCount, fireCount, smokeCount, calloutdata, pedOriginalCount, vehOriginalCount, objOriginalCount, propOriginalCount, fireOriginalCount, smokeOriginalCount) { - isDisplayingCalloutInterface = display; - if (display) { - $("#callout-interface-container").empty().removeClass('slideOutToLeft').addClass('slideInFromLeft'); // clear previous data - $("#callout-interface-container").show(); - - // HTML - $("#callout-interface-container").append(` -
แฏฝ ${calloutdata.CalloutName}
- - - ${pedCount > 0 ? ` - - - - ` : ''} - ${vehicleCount > 0 ? ` - - - - ` : ''} - ${objectCount > 0 ? ` - - - - ` : ''} - ${propCount > 0 ? ` - - - - ` : ''} - ${fireCount > 0 ? ` - - - - ` : ''} - ${smokeCount > 0 ? ` - - - - ` : ''} - -
โŸก ${language.InvolvedPedsRemaining}${pedCount}/${pedOriginalCount}
โŸก ${language.InvolvedVehsRemaining}${vehicleCount}/${vehOriginalCount}
โŸก ${language.InvolvedObjsRemaining}${objectCount}/${objOriginalCount}
โŸก ${language.InvolvedPropsRemaining}${propCount}/${propOriginalCount}
โŸก ${language.ExtinguishAllFires}${fireCount}/${fireOriginalCount}
โŸก ${language.ClearAreaOfSmoke}${smokeCount}/${smokeOriginalCount}
-
-
${language.Press} ${hotkeys.ToggleCalloutInfo} ${language.ToHideOrShow}
- `); - - } else { - $("#callout-interface-container").empty(); // clear previous data - $("#callout-interface-container").hide(); - $('#minimized-indicator').fadeOut(200); // Hide indicator when interface is completely closed - } -} - - -function TogglePreCalloutInterface(display, hotkeys, calloutdata) { - isDisplayingPreCalloutInterface = display; - if (display) { - $("#callout-pre-interface-container").empty().removeClass('slideOutToLeft').addClass('slideInFromLeft'); // clear previous data - $("#callout-pre-interface-container").show(); - - // HTML - $("#callout-pre-interface-container").append(` -
- แฏฝ - ${wrapText(`${language.EmergencyCall} (${calloutdata?.CalloutName ?? 'N/A'})`, 40)} -
- - - - - - - - - - - - - - - - - - - - - - -
- โŸก - ${language.Caller}
- ${wrapText(`${calloutdata?.FirstName ?? 'N/A'} ${calloutdata?.LastName ?? 'N/A'}`, 70)} -
- โŸก - ${language.CallDescription}
- ${wrapText(calloutdata?.Description ?? 'N/A', 70)} -
- โŸก - ${language.Location}
- ${wrapText(calloutdata?.StreetName ?? 'N/A', 70)} -
- โŸก - ${language.Postal}
- ${wrapText(calloutdata?.Postal ?? 'N/A', 70)} -
- โŸก - ${language.CalloutUnitsRequired}
- ${wrapText(calloutdata?.CalloutUnitsRequired?.description ?? 'N/A', 70)} -
- โŸก - ${language.DispatchNote}
- ${wrapText(language.DispatchNoteResponseText, 70)} -
-
-
${language.Press} ${hotkeys.ToggleCalloutInfo} ${language.ToHideOrShow}
- `); - - } else { - $("#callout-pre-interface-container").empty(); // clear previous data - $("#callout-pre-interface-container").hide(); - $('#minimized-indicator').fadeOut(200); // Hide indicator when interface is completely closed - } -} - -// WAYPOINTS - -let Waypoints = [] - -// Cache DOM elements and values for better performance -let waypointCache = { - container: null, - distanceElement: null, - lastDistanceText: '', - lastScaleX: -999, - lastScaleY: -999, - width: 0, - height: 0, - offsetWidth: 0, - offsetHeight: 0, - needsSizeRecalc: true -}; - -// Update window dimensions on resize -window.addEventListener('resize', function() { - waypointCache.width = window.innerWidth; - waypointCache.height = window.innerHeight; - waypointCache.needsSizeRecalc = true; -}); - -function UpdateWaypointPosition(scaleX, scaleY, distanceText) { - let waypoint = Waypoints[0]; - if (waypoint == null) { - $("#waypoint-container").hide(); - return; - } - - // Initialize cache if needed - if (!waypointCache.container) { - waypointCache.container = document.getElementById('waypoint-container'); - waypointCache.distanceElement = document.getElementById('waypoint-distance'); - waypointCache.width = window.innerWidth; - waypointCache.height = window.innerHeight; - } - - // Show container if hidden - if (waypointCache.container.style.display === 'none') { - $("#waypoint-container").show(); - waypointCache.needsSizeRecalc = true; - } - - // Only update distance text if it changed - if (distanceText !== waypointCache.lastDistanceText) { - waypointCache.distanceElement.innerHTML = `แฏฝ ${distanceText}`; - waypointCache.lastDistanceText = distanceText; - waypointCache.needsSizeRecalc = true; - } - - // Recalculate size only when needed (text changed or first time) - if (waypointCache.needsSizeRecalc) { - let positionInfo = waypointCache.container.getBoundingClientRect(); - waypointCache.offsetWidth = positionInfo.width; - waypointCache.offsetHeight = positionInfo.height; - waypointCache.needsSizeRecalc = false; - } - - // Only update position if it changed significantly (reduce jitter) - const threshold = 0.001; // ~1 pixel change threshold - if (Math.abs(scaleX - waypointCache.lastScaleX) > threshold || - Math.abs(scaleY - waypointCache.lastScaleY) > threshold) { - waypointCache.container.style.left = ((waypointCache.width - waypointCache.offsetWidth) * scaleX) + "px"; - waypointCache.container.style.top = ((waypointCache.height - waypointCache.offsetHeight) * scaleY) + "px"; - waypointCache.lastScaleX = scaleX; - waypointCache.lastScaleY = scaleY; - } -} - -function AddWaypoint(addOrRemove) { - let element = document.getElementById('waypoint-container'); - if (addOrRemove) { - Waypoints.push({ element: element }); - // Reset cache - waypointCache.needsSizeRecalc = true; - waypointCache.lastDistanceText = ''; - } else { - $("#waypoint-container").hide(); - Waypoints = []; - // Clear cache - waypointCache.lastDistanceText = ''; - waypointCache.lastScaleX = -999; - waypointCache.lastScaleY = -999; - } -} - -// ERS SELECTION MENU - -let escapeEventListenerAddedERSSelectionMenu = false; -let menuSoundInstance = null; -function ToggleERSSelectionMenu(display, permissions) { - if (display) { - const hasPoliceAccess = permissions.isPolice; - const hasAmbulanceAccess = permissions.isAmbulance; - const hasFireAccess = permissions.isFire; - const hasTowAccess = permissions.isTow; - - fadeOutMenuMusic(menuSoundInstance) - menuSoundInstance = PlayNUISound('generic-sounds', 'selectionmenu', 0.5); - - // HTML - const modal = ` - - `; - - // Add the modal to the page - $('body').append(modal); - - // Initialize the modal with static backdrop and disabled keyboard interaction - $('#ers-selection-modal').modal({ - backdrop: 'static', - keyboard: false - }); - - // Show the modal - $('#ers-selection-modal').modal('show'); - - for (var i = 1; i <= 6; i++) { - addSoundOnHoverEventListener('s-btn-' + i); - } - - // Handle Escape key press only when the modal is open - $('#ers-selection-modal').on('shown.bs.modal', function() { - if (!escapeEventListenerAddedERSSelectionMenu) { - $(document).on('keydown', function(event) { - if (event.key === "Escape") { - // Close the modal - fadeOutMenuMusic(menuSoundInstance) - $('#ers-selection-modal').modal('hide'); - // Trigger the same action as the "No" button click - CancelServiceSelection(); - // Ensure the event doesn't propagate further - event.stopPropagation(); - } - }); - escapeEventListenerAddedERSSelectionMenu = true; - } - }).on('hidden.bs.modal', function() { - // Remove the Escape key press event listener when the modal is closed - $(document).off('keydown'); - escapeEventListenerAddedERSSelectionMenu = false; - }); - - } else { - // Hide and remove the modal if display is false - $('#ers-selection-modal').modal('hide').on('hidden.bs.modal', function () { - fadeOutMenuMusic(menuSoundInstance) - $(this).remove(); - }); - } -} - -function CancelServiceSelection() { - $.post(`https://${resourceName}/cancelServiceSelection`, JSON.stringify({})); - $('#ers-selection-modal').modal('hide').on('hidden.bs.modal', function () { - fadeOutMenuMusic(menuSoundInstance) - $(this).data('bs.modal', null); // Remove data object - $(this).remove(); // Remove the modal element from DOM - }); -} - -function SelectService(serviceType) { - $.post(`https://${resourceName}/selectedService`, JSON.stringify({ - service: serviceType - })); - $('#ers-selection-modal').modal('hide').on('hidden.bs.modal', function () { - fadeOutMenuMusic(menuSoundInstance) - $(this).data('bs.modal', null); // Remove data object - $(this).remove(); // Remove the modal element from DOM - }); -} - -function fadeOutMenuMusic(soundInstance) { - if (soundInstance !== null) { - soundInstance.fade(soundInstance.volume(), 0, 5000); - setTimeout(function() { - soundInstance.stop(); - }, 5000); - } -} - -let escapeEventListenerAddedERSGearnMenu = false; - -function DisplayGearMenu(display, locationData) { - if (display) { - - fadeOutMenuMusic(menuSoundInstance); - menuSoundInstance = PlayNUISound('generic-sounds', 'selectionmenu', 0.5); - - //HTML - const modal = ` - - `; - - // Add the modal to the page - $('body').append(modal); - - var clothingOptions = locationData.ClothingData; - - function getBackgroundColour(serviceType) { - switch (serviceType) { - case 'police': return 'primary'; - case 'fire': return 'danger'; - case 'ambulance': return 'warning'; - case 'tow': return 'info'; - default: return 'secondary'; - } - } - - let backgroundColour = getBackgroundColour(locationData.ServiceType); - - // Generate the HTML for each clothing option - $.each(clothingOptions, function (key, v) { - let locationDataJson = encodeURIComponent(JSON.stringify(locationData)); - - // Minify - $("#gear-options").append(`
${v.Name}

${v.Description}

`); - - // HTML - // $("#gear-options").append(` - //
- //
- //
- //
${v.Name}
- //
- //
- //

- // ${v.Description} - //

- //
- // - //
- //
- // `); - }); - - // Initialize the modal with static backdrop and disabled keyboard interaction - $('#ers-gear-modal').modal({ - backdrop: 'static', - keyboard: false - }); - - // Show the modal - $('#ers-gear-modal').modal('show'); - - for (var i = 0; i < clothingOptions.length; i++) { - addSoundOnHoverEventListener('g-btn-' + i); - } - - // Handle Escape key press only when the modal is open - $('#ers-gear-modal').on('shown.bs.modal', function() { - if (!escapeEventListenerAddedERSGearnMenu) { - $(document).on('keydown', function(event) { - if (event.key === "Escape") { - // Close the modal - fadeOutMenuMusic(menuSoundInstance); - $('#ers-gear-modal').modal('hide'); - // Trigger the same action as the "No" button click - CancelGearSelection(); - // Ensure the event doesn't propagate further - event.stopPropagation(); - } - }); - escapeEventListenerAddedERSGearnMenu = true; - } - }).on('hidden.bs.modal', function() { - // Remove the Escape key press event listener when the modal is closed - $(document).off('keydown'); - escapeEventListenerAddedERSGearnMenu = false; - }); - - } else { - // Hide and remove the modal if display is false - $('#ers-gear-modal').modal('hide').on('hidden.bs.modal', function () { - fadeOutMenuMusic(menuSoundInstance); - $(this).remove(); - }); - } -} - -function handleClick(button) { - let key = button.getAttribute('data-key'); - let locationDataJson = button.getAttribute('data-location-data'); - let locationData = JSON.parse(decodeURIComponent(locationDataJson)); - SelectedGear(key, locationData); -} - -function SelectedGear(key, locationData) { - $.post(`https://${resourceName}/selectedGear`, JSON.stringify({ - clothingIndex: key, - locationData: locationData - })); - $('#ers-gear-modal').modal('hide').on('hidden.bs.modal', function () { - fadeOutMenuMusic(menuSoundInstance); - $(this).data('bs.modal', null); // Remove data object - $(this).remove(); // Remove the modal element from DOM - }); -} - -function CancelGearSelection() { - $.post(`https://${resourceName}/cancelGearSelection`, JSON.stringify({})); - $('#ers-gear-modal').modal('hide').on('hidden.bs.modal', function () { - fadeOutMenuMusic(menuSoundInstance) - $(this).data('bs.modal', null); // Remove data object - $(this).remove(); // Remove the modal element from DOM - }); -} - -///////////////////// UNIFIED PROMPT SYSTEM ///////////////////// - -///////////////////// USER INTERFACE TOGGLE ///////////////////// - -const containerIDs = { - preCallout: "#callout-pre-interface-container", - callout: "#callout-interface-container", -}; - -function slideOut(element) { - $(element).removeClass('slideInFromLeft').addClass('slideOutToLeft'); - setTimeout(() => { - $(element).hide(); - updateMinimizedIndicator(); - }, 300); // Match duration with animation -} - -// Function to show the element with slide-in animation -function slideIn(element) { - $(element).show().removeClass('slideOutToLeft').addClass('slideInFromLeft'); - updateMinimizedIndicator(); -} - -function updateMinimizedIndicator() { - const preCalloutHidden = isDisplayingPreCalloutInterface && !$(containerIDs.preCallout).is(':visible'); - const calloutHidden = isDisplayingCalloutInterface && !$(containerIDs.callout).is(':visible'); - - // Show indicator if any interface is hidden - if (preCalloutHidden || calloutHidden) { - $('#minimized-indicator').fadeIn(200); - } else { - $('#minimized-indicator').fadeOut(200); - } -} - -function toggleCalloutInfo() { - // Toggle pre-callout interface based on its initial state - if (isDisplayingPreCalloutInterface) { - const preCalloutElement = containerIDs.preCallout; - if ($(preCalloutElement).is(':visible')) { - slideOut(preCalloutElement); - } else { - slideIn(preCalloutElement); - } - } - - // Toggle callout interface based on its initial state - if (isDisplayingCalloutInterface) { - const calloutElement = containerIDs.callout; - if ($(calloutElement).is(':visible')) { - slideOut(calloutElement); - } else { - slideIn(calloutElement); - } - } -} - -// Click handler for minimized indicator -document.addEventListener('DOMContentLoaded', function() { - const minimizedIndicator = document.getElementById('minimized-indicator'); - if (minimizedIndicator) { - minimizedIndicator.addEventListener('click', function() { - toggleCalloutInfo(); - }); - } -}); - -///////////////////// CALLOUT UNIT WAYPOINTS ///////////////////// - -function updateWaypoints(data) { - const waypointData = data.data; - const existingWaypoints = trackExistingUnitWaypoints(); - for (const [key, value] of Object.entries(waypointData)) { - if (value !== null) { - if (value.distanceText > 0) { - processUnitWaypoint(key, value, existingWaypoints); - } - } - } - removeUnusedUnitWaypoints(existingWaypoints); -} - -function trackExistingUnitWaypoints() { - const existingWaypoints = new Set(); - document.querySelectorAll('.unit-waypoint-container').forEach(container => { - existingWaypoints.add(container.id); - }); - return existingWaypoints; -} - -function processUnitWaypoint(key, value, existingWaypoints) { - const waypointId = `unit-waypoint-container-${key}`; - let waypointContainer = document.getElementById(waypointId); - - if (!waypointContainer) { - waypointContainer = createUnitWaypointContainer(waypointId); - } - - updateUnitWaypointPosition(waypointContainer, value); - updateUnitWaypointContent(waypointContainer, value); - - existingWaypoints.delete(waypointId); -} - -function createUnitWaypointContainer(waypointId) { - const waypointContainer = document.createElement('div'); - waypointContainer.classList.add('unit-waypoint-container', 'smooth-transition'); - waypointContainer.id = waypointId; - document.body.appendChild(waypointContainer); - return waypointContainer; -} - -function updateUnitWaypointPosition(container, value) { - const width = window.innerWidth; - const height = window.innerHeight; - const positionInfo = container.getBoundingClientRect(); - const offsetWidth = positionInfo.width; - const offsetHeight = positionInfo.height; - - if (value.scaleX >= 0 && value.scaleX <= 1 && value.scaleY >= 0 && value.scaleY <= 1) { - container.style.left = ((width - offsetWidth) * value.scaleX) + "px"; - container.style.top = ((height - offsetHeight) * value.scaleY) + "px"; - } -} - -function updateUnitWaypointContent(container, value) { - container.innerHTML = ` - แฏฝ ${value.distanceText}${value.metrics} - `; -} - -function removeUnusedUnitWaypoints(existingWaypoints) { - existingWaypoints.forEach(id => { - const container = document.getElementById(id); - if (container) { - container.remove(); - } - }); -} - -///////////////////// QUESTIONING ///////////////////// - -function ToggleQuestionsModule(display, questions) { - if (display) { - $("#question-options-list").empty(); - $("#ped-interaction-questioning").show(); - - if (questions.length > 0) { - - // Render the questions in a column with spacing - let html = ` + `),applySavedPosition("dispatch-message-prompt-container");return}"response"==a||"arrival"==a?("response"==a&&$.post(`https://${resourceName}/offerToTrackPlayer`,JSON.stringify({calloutdata:n})),$("#dispatch-message-prompt-container").empty().show().append(`
${language.DispatchMessage}
${wrapText(i,50)}
${language.Caller} ${wrapText(`${n.FirstName} ${n.LastName}`,50)}
${language.CallDescription} ${wrapText(n.Description??"N/A",50)}
${language.Location} ${wrapText(n.StreetName??"N/A",50)}
${language.Postal} ${wrapText(n.Postal??"N/A",50)}
${language.CalloutUnitsRequired} ${wrapText(n.CalloutUnitsRequired?.description??"N/A",50)}
${language.DispatchNote} ${wrapText(language.DispatchNoteResponseText??"N/A",50)}
`),applySavedPosition("dispatch-message-prompt-container"),"response"==a&&$("#dispatch-message-prompt-container").append(` `)):($("#dispatch-message-prompt-container").empty().show().append(`
${language.DispatchMessage}
${i}
`),applySavedPosition("dispatch-message-prompt-container"))}function StartCountdownTimer(e){var t=e/1e3;let a=`${language.NextDispatchMessage} ${t} ${language.Seconds}...`;$("#countdown-timer").html(`
${wrapText(a,70)}
`);var n=setInterval(function(){--t>=0?$("#countdown-timer").html(`
${wrapText(`${language.NextDispatchMessage} ${t} ${language.Seconds}...`,70)}
`):(clearInterval(n),$("#countdown-timer").html(`
${wrapText("Time's up!",70)}
`))},1e3)}function ToggleHotKeyHintPrompt(e,t,a,n){e?($("#hint-prompt-container").empty(),$("#hint-prompt-container").show(),applySavedPosition("hint-prompt-container"),$("#hint-prompt-container").append(`
${a.Hint}
${a.HotKeys}
${a.Explanation}
`),setTimeout(function(){$("#hint-prompt-container").hide(),$.post(`https://${resourceName}/reallowPromptMessages`,JSON.stringify({}))},n)):($("#hint-prompt-container").empty(),$("#hint-prompt-container").hide())}function SelectBackGroundColourByServiceType(e){var t="bg-primary",a="border-primary",n="btn-outline-primary",i="text-light";return"police"==e?(t="bg-primary",a="border-primary",n="btn-outline-primary",i="text-light"):"ambulance"==e?(t="bg-success",a="border-success",n="btn-outline-success",i="text-light"):"fire"==e?(t="bg-danger",a="border-danger",n="btn-outline-danger",i="text-light"):"tow"==e&&(t="bg-warning",a="border-warning",n="btn-outline-warning",i="text-light"),{backgroundColor:t,borderColor:a,textColor:i,buttonOutlineColor:n}}function ToggleCalloutDisplayPrompt(e,t,a,n,i,o){var s=n/1e3,{backgroundColor:l,borderColor:r,textColor:c,buttonOutlineColor:d}=SelectBackGroundColourByServiceType(o);e?($("#callout-prompt-container").empty(),$("#callout-prompt-container").show(),$("#callout-prompt-container").append(`
${wrapText(`${a.EmergencyCall} (${i.CalloutName})`,50)}
${a.Caller} ${wrapText(`${i.FirstName} ${i.LastName}`,50)}
${a.CallDescription} ${wrapText(i.Description??"N/A",50)}
${a.Location} ${wrapText(i.StreetName??"N/A",50)}
${a.Postal} ${wrapText(i.Postal??"N/A",50)}
${a.CalloutUnitsRequired} ${wrapText(i.CalloutUnitsRequired?.description??"N/A",50)}
${a.DispatchNote} ${wrapText(a.DispatchNoteResponseText??"N/A",50)}
`),applySavedPosition("callout-prompt-container"),clearInterval(window.countdownInterval),s--,window.countdownInterval=setInterval(function(){s>0?($("#callout-prompt-container").find("#countdown-text").html(` ${a.TimeRemainingToAcceptCallout} ${s} ${a.Seconds}... `),s--):(clearInterval(window.countdownInterval),$("#callout-prompt-container").hide(),$.post(`https://${resourceName}/calloutTimeout`,JSON.stringify({})))},1e3)):($("#callout-prompt-container").empty(),$("#callout-prompt-container").hide())}function ToggleCalloutInterface(e,t,a,n,i,o,s,l,r,c,d,u,g,p,b){isDisplayingCalloutInterface=e,e?($("#callout-interface-container").empty().addClass("slideInFromLeft"),$("#callout-interface-container").show(),$("#callout-interface-container").append(`
แฏฝ ${r.CalloutName}
${a>0?` `:""} ${n>0?` `:""} ${i>0?` `:""} ${o>0?` `:""} ${s>0?` `:""} ${l>0?` `:""}
โŸก ${language.InvolvedPedsRemaining} ${a}/${c}
โŸก ${language.InvolvedVehsRemaining} ${n}/${d}
โŸก ${language.InvolvedObjsRemaining} ${i}/${u}
โŸก ${language.InvolvedPropsRemaining} ${o}/${g}
โŸก ${language.ExtinguishAllFires} ${s}/${p}
โŸก ${language.ClearAreaOfSmoke} ${l}/${b}

${language.Press} ${t.ToggleCalloutInfo} ${language.ToHideOrShow}
`),applySavedPosition("callout-interface-container")):($("#callout-interface-container").empty(),$("#callout-interface-container").hide())}function TogglePreCalloutInterface(e,t,a){isDisplayingPreCalloutInterface=e,e?($("#callout-pre-interface-container").empty().addClass("slideInFromLeft"),$("#callout-pre-interface-container").show(),$("#callout-pre-interface-container").append(`
แฏฝ ${wrapText(`${language.EmergencyCall} (${a?.CalloutName??"N/A"})`,40)}
โŸก ${language.Caller}
${wrapText(`${a?.FirstName??"N/A"} ${a?.LastName??"N/A"}`,70)}
โŸก ${language.CallDescription}
${wrapText(a?.Description??"N/A",70)}
โŸก ${language.Location}
${wrapText(a?.StreetName??"N/A",70)}
โŸก ${language.Postal}
${wrapText(a?.Postal??"N/A",70)}
โŸก ${language.CalloutUnitsRequired}
${wrapText(a?.CalloutUnitsRequired?.description??"N/A",70)}
โŸก ${language.DispatchNote}
${wrapText(language.DispatchNoteResponseText,70)}

${language.Press} ${t.ToggleCalloutInfo} ${language.ToHideOrShow}
`),applySavedPosition("callout-pre-interface-container")):($("#callout-pre-interface-container").empty(),$("#callout-pre-interface-container").hide())}let Waypoints=[];function UpdateWaypointPosition(e,t,a){if(null==Waypoints[0]){$("#waypoint-container").hide();return}let n=document.getElementById("waypoint-container");$("#waypoint-distance").empty(),$("#waypoint-container").show(),$("#waypoint-distance").append(` + แฏฝ ${a} + `);let i=window.innerWidth,o=window.innerHeight,s=n.getBoundingClientRect(),l=s.width,r=s.height;n.style.left=(i-l)*e+"px",n.style.top=(o-r)*t+"px"}function AddWaypoint(e){let t=document.getElementById("waypoint-container");e?Waypoints.push({element:t}):($("#waypoint-container").hide(),Waypoints=[])}let escapeEventListenerAddedERSSelectionMenu=!1,menuSoundInstance=null;function ToggleERSSelectionMenu(e,t){if(e){let a=t.isPolice,n=t.isAmbulance,i=t.isFire,o=t.isTow;fadeOutMenuMusic(menuSoundInstance),menuSoundInstance=PlayNUISound("generic-sounds","selectionmenu",.5);let s=` `;$("body").append(s),$("#ers-selection-modal").modal({backdrop:"static",keyboard:!1}),$("#ers-selection-modal").modal("show");for(var l=1;l<=6;l++)addSoundOnHoverEventListener("s-btn-"+l);$("#ers-selection-modal").on("shown.bs.modal",function(){escapeEventListenerAddedERSSelectionMenu||($(document).on("keydown",function(e){"Escape"===e.key&&(fadeOutMenuMusic(menuSoundInstance),$("#ers-selection-modal").modal("hide"),CancelServiceSelection(),e.stopPropagation())}),escapeEventListenerAddedERSSelectionMenu=!0)}).on("hidden.bs.modal",function(){$(document).off("keydown"),escapeEventListenerAddedERSSelectionMenu=!1})}else $("#ers-selection-modal").modal("hide").on("hidden.bs.modal",function(){fadeOutMenuMusic(menuSoundInstance),$(this).remove()})}function CancelServiceSelection(){$.post(`https://${resourceName}/cancelServiceSelection`,JSON.stringify({})),$("#ers-selection-modal").modal("hide").on("hidden.bs.modal",function(){fadeOutMenuMusic(menuSoundInstance),$(this).data("bs.modal",null),$(this).remove()})}function SelectService(e){$.post(`https://${resourceName}/selectedService`,JSON.stringify({service:e})),$("#ers-selection-modal").modal("hide").on("hidden.bs.modal",function(){fadeOutMenuMusic(menuSoundInstance),$(this).data("bs.modal",null),$(this).remove()})}function fadeOutMenuMusic(e){null!==e&&(e.fade(e.volume(),0,5e3),setTimeout(function(){e.stop()},5e3))}let escapeEventListenerAddedERSGearnMenu=!1;function DisplayGearMenu(e,t){if(e){fadeOutMenuMusic(menuSoundInstance),menuSoundInstance=PlayNUISound("generic-sounds","selectionmenu",.5);let a=` `;$("body").append(a);var n=t.ClothingData;let i=function e(t){switch(t){case"police":return"primary";case"fire":return"danger";case"ambulance":return"warning";case"tow":return"info";default:return"secondary"}}(t.ServiceType);$.each(n,function(e,a){let n=encodeURIComponent(JSON.stringify(t));$("#gear-options").append(`
${a.Name}

${a.Description}

`)}),$("#ers-gear-modal").modal({backdrop:"static",keyboard:!1}),$("#ers-gear-modal").modal("show");for(var o=0;o$(e).hide(),250)}function slideIn(e){$(e).show().removeClass("slideOutToLeft").addClass("slideInFromLeft")}function toggleCalloutInfo(){if(isDisplayingPreCalloutInterface){let e=containerIDs.preCallout;$(e).is(":visible")?slideOut(e):slideIn(e)}if(isDisplayingCalloutInterface){let t=containerIDs.callout;$(t).is(":visible")?slideOut(t):slideIn(t)}}function updateWaypoints(e){let t=e.data,a=trackExistingUnitWaypoints();for(let[n,i]of Object.entries(t))null!==i&&i.distanceText>0&&processUnitWaypoint(n,i,a);removeUnusedUnitWaypoints(a)}function trackExistingUnitWaypoints(){let e=new Set;return document.querySelectorAll(".unit-waypoint-container").forEach(t=>{e.add(t.id)}),e}function processUnitWaypoint(e,t,a){let n=`unit-waypoint-container-${e}`,i=document.getElementById(n);i||(i=createUnitWaypointContainer(n)),updateUnitWaypointPosition(i,t),updateUnitWaypointContent(i,t),a.delete(n)}function createUnitWaypointContainer(e){let t=document.createElement("div");return t.classList.add("unit-waypoint-container","smooth-transition"),t.id=e,document.body.appendChild(t),t}function updateUnitWaypointPosition(e,t){let a=window.innerWidth,n=window.innerHeight,i=e.getBoundingClientRect(),o=i.width,s=i.height;t.scaleX>=0&&t.scaleX<=1&&t.scaleY>=0&&t.scaleY<=1&&(e.style.left=(a-o)*t.scaleX+"px",e.style.top=(n-s)*t.scaleY+"px")}function updateUnitWaypointContent(e,t){e.innerHTML=` + แฏฝ ${t.distanceText}${t.metrics} + `}function removeUnusedUnitWaypoints(e){e.forEach(e=>{let t=document.getElementById(e);t&&t.remove()})}function ToggleQuestionsModule(e,t){if(e){if($("#question-options-list").empty(),$("#ped-interaction-questioning").show(),t.length>0){let a=`
- ${questions.map((q, index) => ` + ${t.map((e,t)=>` - `).join('')} + `).join("")}
- `; - $("#question-options-list").append(html); - - // Add sound effects to the question buttons - questions.forEach((_, index) => { - const buttonId = `s-btn-${index + 1}`; - if (document.getElementById(buttonId)) { - addSoundOnHoverEventListener(buttonId); - } - }); - - // Add click handlers - $("#question-options-list button").off("click").on("click", function() { - let target = $(this).data("target"); - let questionText = $(this).data("question-text"); - let soundFile = $(this).data("sound-file"); - let soundVolume = $(this).data("sound-volume"); - if (target) { - // Find the full question data for this button - const selectedQuestion = { - id: target, - text: questionText, - soundFile: soundFile, - soundVolume: soundVolume - }; - - PlayNUISound('generic-sounds', "q_select", 1.0); - - $.post(`https://${resourceName}/questionSelected`, JSON.stringify({ - questionData: selectedQuestion - })); - } - }); - } - - // Leave button - let leaveBtn = ` + `;$("#question-options-list").append(a),applySavedPosition("ped-interaction-questioning"),t.forEach((e,t)=>{let a=`s-btn-${t+1}`;document.getElementById(a)&&addSoundOnHoverEventListener(a)}),$("#question-options-list button").off("click").on("click",function(){let e=$(this).data("target"),t=$(this).data("question-text"),a=$(this).data("sound-file"),n=$(this).data("sound-volume");e&&(PlayNUISound("generic-sounds","q_select",1),$.post(`https://${resourceName}/questionSelected`,JSON.stringify({questionData:{id:e,text:t,soundFile:a,soundVolume:n}})))})}let n=` - `; - $("#question-leave-btn").html(leaveBtn); - - // Add sound effect to leave button - if (document.getElementById("leave-questioning-btn")) { - addSoundOnHoverEventListener("leave-questioning-btn"); - } - - // Add click handler for leave button - $("#leave-questioning-btn").off("click").on("click", function() { - PlayNUISound('generic-sounds', "radialclose", 0.5); - $.post(`https://${resourceName}/leaveQuestioning`, JSON.stringify({})); - }); - - } else { - $("#ped-interaction-questioning").hide(); - $("#question-options-list").empty(); - $("#question-leave-btn").empty(); - } -} - -function UpdateAnswers(display, answers) { - if (display) { - // Get the answers container and clear it - let answersContainer = $("#question-answers-list"); - - // Clear the answers container - answersContainer.empty(); - - // Add a title above the answers - answersContainer.html(` + `;$("#question-leave-btn").html(n),document.getElementById("leave-questioning-btn")&&addSoundOnHoverEventListener("leave-questioning-btn"),$("#leave-questioning-btn").off("click").on("click",function(){PlayNUISound("generic-sounds","radialclose",.5),$.post(`https://${resourceName}/leaveQuestioning`,JSON.stringify({}))})}else $("#ped-interaction-questioning").hide(),$("#question-options-list").empty(),$("#question-leave-btn").empty()}function UpdateAnswers(e,t){if(e){let a=$("#question-answers-list");a.empty(),a.html(`
@@ -2816,42 +53,30 @@ function UpdateAnswers(display, answers) {
- ${Array.isArray(answers) && answers.length > 0 ? answers.map((value, index) => ` + ${Array.isArray(t)&&t.length>0?t.map((e,t)=>`
- User Profile + User Profile
- ${value.question || ''} + ${e.question||""} ${new Date().toLocaleTimeString()}
-

${value.answer || ''}

+

${e.answer||""}

- `).join('') : '
...
'} + `).join(""):'
...
'}
- `); - } else { - $("#question-answers-list").empty(); - } -} - -///////////////////// DUAL STEERING MODE ///////////////////// - -function ToggleDualSteeringMode(display) { - const container = $("#dual-steering-mode"); - container.toggle(display); - if (display) { - container.html(` + `)}else $("#question-answers-list").empty()}function ToggleDualSteeringMode(e){let t=$("#dual-steering-mode");t.toggle(e),e?(t.html(`
${language.DualSteeringMode}
โ†‘${language.ReelInWinch}
@@ -2859,45 +84,4 @@ function ToggleDualSteeringMode(display) {
โ†’${language.SteerRight}
โ†${language.SteerLeft}
โŒซ${language.DisconnectWinch}
- `); - } else { - container.empty(); - } -} - -///////////////////// OTHER FUNCTIONS ///////////////////// - -function hideAllPrompts() { - $("#unified-prompt").empty().hide(); -} - -function PlayNUISound(soundFolderPrefix, filename, filevol) { - var audioPlayer = null; - if (audioPlayer != null) { - audioPlayer.pause(); - } - audioPlayer = new Howl({ src: [`nui://${resourceName}/NUI/sounds/${soundFolderPrefix}/${filename}.ogg`] }); - audioPlayer.volume(filevol); - audioPlayer.play(); - - return audioPlayer; -} - -function wrapText(text, maxCharsPerLine) { - const lines = []; - let currentLine = ''; - - for (const word of text.toString().split(/\s+/)) { - if ((currentLine.length + word.length + (currentLine.length > 0 ? 1 : 0)) > maxCharsPerLine) { - lines.push(currentLine.trim() + '-'); // Add a dash to the end of the line - currentLine = ''; - } - currentLine += (currentLine.length > 0 ? ' ' : '') + word; - } - - if (currentLine.length > 0) { - lines.push(currentLine.trim()); - } - - return lines.join('
'); // Join lines with
-} \ No newline at end of file + `),applySavedPosition("dual-steering-mode")):t.empty()}function hideAllPrompts(){$("#unified-prompt").empty().hide()}function PlayNUISound(e,t,a){var n=null;return null!=n&&n.pause(),(n=new Howl({src:[`nui://${resourceName}/NUI/sounds/${e}/${t}.ogg`]})).volume(a),n.play(),n}function wrapText(e,t){let a=[],n="";for(let i of e.toString().split(/\s+/))n.length+i.length+(n.length>0?1:0)>t&&(a.push(n.trim()+"-"),n=""),n+=(n.length>0?" ":"")+i;return n.length>0&&a.push(n.trim()),a.join("
")}function applySavedPosition(e){} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_ambulance_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_ambulance_f.mp3 new file mode 100644 index 000000000..42139be58 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_ambulance_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_animalrescue_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_animalrescue_f.mp3 new file mode 100644 index 000000000..19a8f5386 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_animalrescue_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_coroner_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_coroner_f.mp3 new file mode 100644 index 000000000..7af589a6c Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_coroner_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_fire_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_fire_f.mp3 new file mode 100644 index 000000000..8e25a50b5 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_fire_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_mechanic_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_mechanic_f.mp3 new file mode 100644 index 000000000..fd5d17105 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_mechanic_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_police_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_police_f.mp3 new file mode 100644 index 000000000..8abc1357c Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_police_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_roadservice_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_roadservice_f.mp3 new file mode 100644 index 000000000..ed1adf779 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_roadservice_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_taxi_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_taxi_f.mp3 new file mode 100644 index 000000000..ac24cb5dd Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_taxi_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_tow_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_tow_f.mp3 new file mode 100644 index 000000000..6dacb742b Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_backup_tow_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_breathalyze_1_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_breathalyze_1_f.mp3 new file mode 100644 index 000000000..d469c9337 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_breathalyze_1_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_breathalyze_2_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_breathalyze_2_f.mp3 new file mode 100644 index 000000000..c2d908107 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_breathalyze_2_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_breathalyze_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_breathalyze_f.mp3 new file mode 100644 index 000000000..1d39882e1 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_breathalyze_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_cuffs_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_cuffs_f.mp3 new file mode 100644 index 000000000..f4f7319da Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_cuffs_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_drugtest_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_drugtest_f.mp3 new file mode 100644 index 000000000..60bf1dbff Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_drugtest_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_end_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_end_f.mp3 new file mode 100644 index 000000000..d5e67676e Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_end_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_fine_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_fine_f.mp3 new file mode 100644 index 000000000..3f6c72593 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_fine_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_follow_1_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_follow_1_f.mp3 new file mode 100644 index 000000000..27a49ffc4 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_follow_1_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_follow_2_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_follow_2_f.mp3 new file mode 100644 index 000000000..1ff726ed9 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_follow_2_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_follow_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_follow_f.mp3 new file mode 100644 index 000000000..0fb15aa4f Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_follow_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_getout_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_getout_f.mp3 new file mode 100644 index 000000000..0fa634331 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_getout_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_handsup_1_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_handsup_1_f.mp3 new file mode 100644 index 000000000..d93d93aa8 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_handsup_1_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_handsup_2_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_handsup_2_f.mp3 new file mode 100644 index 000000000..4486c3719 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_handsup_2_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_handsup_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_handsup_f.mp3 new file mode 100644 index 000000000..f5ad6e059 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_handsup_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_hello_1_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_hello_1_f.mp3 new file mode 100644 index 000000000..73b331d5f Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_hello_1_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_hello_2_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_hello_2_f.mp3 new file mode 100644 index 000000000..1f3f19ac6 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_hello_2_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_hello_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_hello_f.mp3 new file mode 100644 index 000000000..a6780d367 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_hello_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_id_1_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_id_1_f.mp3 new file mode 100644 index 000000000..bbab14a00 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_id_1_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_id_2_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_id_2_f.mp3 new file mode 100644 index 000000000..013639dd0 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_id_2_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_id_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_id_f.mp3 new file mode 100644 index 000000000..f00760e1e Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_id_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_impound_class_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_impound_class_f.mp3 new file mode 100644 index 000000000..090b7e255 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_impound_class_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_impound_done_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_impound_done_f.mp3 new file mode 100644 index 000000000..c347fa464 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_impound_done_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_impound_task_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_impound_task_f.mp3 new file mode 100644 index 000000000..644f2f6ec Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_impound_task_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_pursuit_backup_air_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_pursuit_backup_air_f.mp3 new file mode 100644 index 000000000..84acbb627 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_pursuit_backup_air_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_pursuit_backup_army_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_pursuit_backup_army_f.mp3 new file mode 100644 index 000000000..4321fab31 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_pursuit_backup_army_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_pursuit_backup_heavy_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_pursuit_backup_heavy_f.mp3 new file mode 100644 index 000000000..809f6637b Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_pursuit_backup_heavy_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_pursuit_backup_light_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_pursuit_backup_light_f.mp3 new file mode 100644 index 000000000..7e753b381 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_pursuit_backup_light_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_pursuit_backup_medium_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_pursuit_backup_medium_f.mp3 new file mode 100644 index 000000000..0c599a45d Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_pursuit_backup_medium_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_putinvehicle_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_putinvehicle_f.mp3 new file mode 100644 index 000000000..6e230822d Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_putinvehicle_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_search_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_search_f.mp3 new file mode 100644 index 000000000..871d7be90 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_search_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_wait_1_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_wait_1_f.mp3 new file mode 100644 index 000000000..a53f97f39 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_wait_1_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_wait_2_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_wait_2_f.mp3 new file mode 100644 index 000000000..f5dbc0d37 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_wait_2_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_wait_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_wait_f.mp3 new file mode 100644 index 000000000..7517e1845 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_wait_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/de/de_warn_f.mp3 b/resources/[ERS]/night_ers/NUI/sounds/de/de_warn_f.mp3 new file mode 100644 index 000000000..e0b872a45 Binary files /dev/null and b/resources/[ERS]/night_ers/NUI/sounds/de/de_warn_f.mp3 differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/en/en_arrest_rights.ogg b/resources/[ERS]/night_ers/NUI/sounds/en/en_arrest_rights.ogg deleted file mode 100644 index 37e4a807f..000000000 Binary files a/resources/[ERS]/night_ers/NUI/sounds/en/en_arrest_rights.ogg and /dev/null differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/en/en_arrest_rights_f.ogg b/resources/[ERS]/night_ers/NUI/sounds/en/en_arrest_rights_f.ogg deleted file mode 100644 index 13819b016..000000000 Binary files a/resources/[ERS]/night_ers/NUI/sounds/en/en_arrest_rights_f.ogg and /dev/null differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/us/us_arrest_rights.ogg b/resources/[ERS]/night_ers/NUI/sounds/us/us_arrest_rights.ogg deleted file mode 100644 index 3068de553..000000000 Binary files a/resources/[ERS]/night_ers/NUI/sounds/us/us_arrest_rights.ogg and /dev/null differ diff --git a/resources/[ERS]/night_ers/NUI/sounds/us/us_arrest_rights_f.ogg b/resources/[ERS]/night_ers/NUI/sounds/us/us_arrest_rights_f.ogg deleted file mode 100644 index e36534038..000000000 Binary files a/resources/[ERS]/night_ers/NUI/sounds/us/us_arrest_rights_f.ogg and /dev/null differ diff --git a/resources/[ERS]/night_ers/NUI/styles.css b/resources/[ERS]/night_ers/NUI/styles.css index 3e4e5245b..f2f40d955 100644 --- a/resources/[ERS]/night_ers/NUI/styles.css +++ b/resources/[ERS]/night_ers/NUI/styles.css @@ -27,11 +27,6 @@ body { } */ /* A default font */ -html, body { - background: transparent !important; - background-color: transparent !important; -} - body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; font-size: 13px; @@ -201,30 +196,6 @@ body { transition: opacity 0.25s ease-out; } -#callout-interface-container h4, -#callout-pre-interface-container h4 { - font-size: 1.5rem; - font-weight: 500; - margin-bottom: 0.5rem; - margin-top: 0; -} - -#callout-interface-container h5, -#callout-pre-interface-container h5 { - font-size: 1.25rem; - font-weight: 500; - margin-bottom: 0.5rem; - margin-top: 0; -} - -#callout-interface-container h6, -#callout-pre-interface-container h6 { - font-size: 1rem; - font-weight: 500; - margin-bottom: 0.5rem; - margin-top: 0; -} - .hint { position: absolute; margin: 5px; @@ -272,7 +243,6 @@ body { top: var(--module-default-y, 50%); transform: translate(-50%, -50%); z-index: 1; - min-width: 550px; opacity: 0; animation: fadeIn 0.25s ease forwards; background-color: var(--interaction-bg-color); @@ -289,506 +259,6 @@ body { z-index: 1; opacity: 0; animation: fadeIn 0.25s ease forwards; - max-width: 400px; - max-height: 80vh; - overflow-y: auto; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -/* Simple loading indicator */ -.loading-indicator { - display: flex; - align-items: center; - justify-content: center; -} - -.loading-indicator i { - animation: loading-pulse 1.5s ease-in-out infinite; -} - -@keyframes loading-pulse { - 0%, 100% { - opacity: 0.5; - } - 50% { - opacity: 1; - } -} - -/* Compact ID Card Styles */ -#ped-interaction-id-card .card { - margin: 8px !important; - font-size: 12px; -} - -#ped-interaction-id-card .card-header { - padding: 8px 12px; - font-size: 13px; -} - -#ped-interaction-id-card .card-body { - padding: 8px 12px; -} - -#ped-interaction-id-card .list-group-item { - padding: 6px 8px; - font-size: 11px; -} - -#ped-interaction-id-card .profile-picture { - max-height: 120px !important; - object-fit: cover; -} - -#ped-interaction-id-card .license-badge { - font-size: 10px; - padding: 2px 6px; - margin: 1px; -} - -#ped-interaction-id-card .fs-5 { - font-size: 14px !important; -} - -#ped-interaction-id-card .col-md-4, -#ped-interaction-id-card .col-md-8 { - padding: 0 4px; -} - -#ped-interaction-id-card .row { - margin: 0; -} - -#ped-interaction-id-card .mb-3 { - margin-bottom: 8px !important; -} - -#ped-interaction-id-card .mb-2 { - margin-bottom: 4px !important; -} - -/* Compact License Display */ -.license-compact { - display: flex; - flex-wrap: wrap; - gap: 4px; - margin-top: 4px; -} - -.license-compact-item { - display: inline-flex; - align-items: center; - gap: 4px; - padding: 3px 8px; - background: rgba(0, 0, 0, 0.4); - border-radius: 4px; - border: 1px solid rgba(255, 255, 255, 0.3); - font-size: 11px; - font-weight: 500; - white-space: nowrap; - color: #fff !important; -} - -.license-compact-item i { - font-size: 12px; -} - -/* Icon colors only - text stays white */ -.license-compact-item.text-success i { - color: #28a745; -} - -.license-compact-item.text-danger i { - color: #dc3545; -} - -.license-compact-item.text-warning i { - color: #ffc107; -} - -.license-compact-item.text-secondary i { - color: #6c757d; -} - -/* Minimalistic Hint Styles */ -.hint-minimal { - background: rgba(0, 0, 0, 0.8); - border: 1px solid rgba(255, 193, 7, 0.6); - border-radius: 8px; - padding: 12px; - max-width: 350px; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; -} - -.hint-header { - margin-bottom: 8px; - padding-bottom: 6px; - border-bottom: 1px solid rgba(255, 193, 7, 0.3); -} - -.hint-title { - color: #ffc107; - font-size: 13px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.5px; -} - -.hint-content { - display: flex; - flex-direction: column; - gap: 4px; -} - -.hint-item { - display: flex; - justify-content: space-between; - align-items: center; - padding: 3px 0; -} - -.hint-key { - color: #fff; - font-size: 11px; - font-weight: 600; - background: rgba(255, 193, 7, 0.2); - padding: 2px 6px; - border-radius: 3px; - border: 1px solid rgba(255, 193, 7, 0.4); - font-family: 'Courier New', monospace; -} - -.hint-desc { - color: rgba(255, 255, 255, 0.8); - font-size: 10px; - text-align: right; - max-width: 60%; - line-height: 1.3; -} - -.hint-footer { - margin-top: 8px; - padding-top: 6px; - border-top: 1px solid rgba(255, 193, 7, 0.3); - text-align: center; -} - -.hint-toggle { - color: rgba(255, 193, 7, 0.7); - font-size: 9px; - font-style: italic; -} - -/* Minimalistic Callout Styles */ -.callout-minimal { - background: rgba(0, 0, 0, 0.6); - border-radius: 8px; - padding: 12px; - max-width: 400px; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - border: 1px solid rgba(255, 255, 255, 0.2); - backdrop-filter: blur(5px); -} - -/* Service-specific subtle accents */ -.callout-minimal.callout-police { - border-left: 3px solid rgba(0, 87, 185, 0.75); -} - -.callout-minimal.callout-ambulance { - border-left: 3px solid rgba(40, 167, 69, 0.75); -} - -.callout-minimal.callout-fire { - border-left: 3px solid rgba(255, 69, 0, 0.75); -} - -.callout-minimal.callout-tow { - border-left: 3px solid rgba(120, 35, 35, 0.75); -} - -.callout-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 10px; - padding-bottom: 6px; - border-bottom: 1px solid rgba(255, 255, 255, 0.1); -} - -.callout-title { - color: rgba(255, 255, 255, 0.9); - font-size: 14px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.5px; -} - -.callout-type { - color: rgba(255, 255, 255, 0.8); - font-size: 11px; - font-weight: 500; - background: rgba(255, 255, 255, 0.1); - padding: 2px 6px; - border-radius: 3px; - border: 1px solid rgba(255, 255, 255, 0.2); -} - -.callout-content { - display: flex; - flex-direction: column; - gap: 6px; - margin-bottom: 10px; -} - -.callout-info { - display: flex; - justify-content: space-between; - align-items: center; - padding: 2px 0; -} - -.callout-label { - color: rgba(255, 255, 255, 0.8); - font-size: 11px; - font-weight: 600; - min-width: 60px; -} - -.callout-value { - color: #fff; - font-size: 11px; - font-weight: 500; - text-align: right; - max-width: 60%; -} - -.callout-description { - margin-top: 4px; - padding: 6px; - background: rgba(255, 255, 255, 0.05); - border-radius: 4px; - border-left: 2px solid rgba(255, 255, 255, 0.3); -} - -.callout-desc { - color: rgba(255, 255, 255, 0.9); - font-size: 11px; - line-height: 1.4; - font-style: italic; -} - -.callout-footer { - display: flex; - justify-content: space-between; - align-items: center; - padding-top: 8px; - border-top: 1px solid rgba(255, 255, 255, 0.1); -} - -.callout-countdown { - color: rgba(255, 255, 255, 0.8); - font-size: 11px; - font-weight: 500; -} - -.callout-countdown .text-warning { - color: #ffc107; - font-weight: 700; -} - -.callout-actions { - display: flex; - align-items: center; - gap: 4px; -} - -.callout-btn { - color: #ffc107; - font-size: 11px; - font-weight: 700; - background: rgba(255, 193, 7, 0.2); - padding: 4px 8px; - border-radius: 4px; - border: 1px solid #ffc107; - font-family: 'Courier New', monospace; - cursor: pointer; - transition: all 0.2s ease; - text-transform: uppercase; - letter-spacing: 0.5px; -} - -.callout-btn:hover { - background: rgba(0, 0, 0, 0.9); - border-color: #ffd43b; - color: #ffd43b; - transform: scale(1.05); -} - -.callout-separator { - color: rgba(255, 255, 255, 0.5); - font-size: 10px; - margin: 0 2px; -} - -/* Minimalistic Dispatch Message Styles */ -.dispatch-minimal { - background: rgba(0, 0, 0, 0.8); - background-color: rgba(0, 0, 0, 0.8); - border-radius: 8px; - padding: 12px; - max-width: 400px; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - border: 1px solid rgba(255, 255, 255, 0.2); - border-left: 3px solid rgba(0, 123, 255, 0.6); -} - -#dispatch-message-prompt-card { - background: rgba(0, 0, 0, 0.8); - background-color: rgba(0, 0, 0, 0.8); -} - -/* If you want backdrop blur and it works in your setup, you can enable it here */ -.dispatch-minimal.with-blur { - backdrop-filter: blur(5px); - -webkit-backdrop-filter: blur(5px); -} - -.dispatch-header { - display: flex; - justify-content: space-between; - align-items: center; - gap: 12px; - margin-bottom: 10px; - padding-bottom: 6px; - border-bottom: 1px solid rgba(255, 255, 255, 0.1); -} - -.dispatch-title { - color: rgba(255, 255, 255, 0.9); - font-size: 14px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.5px; -} - -.dispatch-type { - color: rgba(255, 255, 255, 0.8); - font-size: 11px; - font-weight: 500; - background: rgba(255, 255, 255, 0.1); - padding: 2px 6px; - border-radius: 3px; - border: 1px solid rgba(255, 255, 255, 0.2); -} - -.dispatch-content { - display: flex; - flex-direction: column; - gap: 6px; - margin-bottom: 10px; -} - -.dispatch-callout-badge-container { - margin-bottom: 8px; -} - -.dispatch-callout-badge { - display: inline-block; - color: rgba(255, 255, 255, 0.9); - font-size: 11px; - font-weight: 600; - background: rgba(255, 193, 7, 0.2); - padding: 4px 10px; - border-radius: 4px; - border: 1px solid rgba(255, 193, 7, 0.5); - text-transform: uppercase; - letter-spacing: 0.5px; -} - -.dispatch-message { - margin-bottom: 4px; - padding: 6px; - background: rgba(255, 255, 255, 0.05); - border-radius: 4px; - border-left: 2px solid rgba(255, 255, 255, 0.3); -} - -.dispatch-desc { - color: rgba(255, 255, 255, 0.9); - font-size: 11px; - line-height: 1.4; - font-style: italic; -} - -.dispatch-info { - display: flex; - justify-content: space-between; - align-items: center; - padding: 2px 0; -} - -.dispatch-label { - color: rgba(255, 255, 255, 0.8); - font-size: 11px; - font-weight: 600; - min-width: 60px; -} - -.dispatch-value { - color: rgba(255, 255, 255, 0.9); - font-size: 11px; - font-weight: 500; - text-align: right; - max-width: 60%; -} - -.dispatch-footer { - padding-top: 8px; - border-top: 1px solid rgba(255, 255, 255, 0.1); - font-size: 11px; - color: rgba(255, 255, 255, 0.8); -} - -.dispatch-track { - display: flex; - justify-content: space-between; - align-items: center; - padding: 8px; - background: linear-gradient(to right, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0.6)); - border-radius: 4px; - border-top: 1px solid rgba(255, 255, 255, 0.1); - margin-top: 8px; -} - -.dispatch-track-text { - color: rgba(255, 255, 255, 0.9); - font-size: 11px; - font-weight: 500; -} - -.dispatch-track-btn { - color: #ffc107; - font-size: 11px; - font-weight: 700; - background: rgba(255, 193, 7, 0.2); - padding: 4px 8px; - border-radius: 4px; - border: 1px solid #ffc107; - font-family: 'Courier New', monospace; - cursor: pointer; - transition: all 0.2s ease; - text-transform: uppercase; - letter-spacing: 0.5px; -} - -.dispatch-track-btn:hover { - background: rgba(255, 193, 7, 0.3); - border-color: #ffd43b; - color: #ffd43b; - transform: scale(1.05); } .spinner-wrapper { @@ -1762,143 +1232,4 @@ body { opacity: 0; transform: translate(-50%, -50%) scale(0.8); } -} - -/* Slide animations for callout interfaces */ -@keyframes slideInFromLeft { - from { - opacity: 0; - transform: translateY(-50%) translateX(-100%); - } - to { - opacity: 1; - transform: translateY(-50%) translateX(0); - } -} - -@keyframes slideOutToLeft { - from { - opacity: 1; - transform: translateY(-50%) translateX(0); - } - to { - opacity: 0; - transform: translateY(-50%) translateX(-100%); - } -} - -.slideInFromLeft { - animation: slideInFromLeft 0.3s ease-out forwards; -} - -.slideOutToLeft { - animation: slideOutToLeft 0.3s ease-out forwards; -} - -/* Minimized Interface Indicator */ -#minimized-indicator { - position: fixed; - left: 20px; - top: 50%; - transform: translateY(-50%); - z-index: 1000; - display: none; - background: rgba(0, 0, 0, 0.7); - border: 2px solid rgba(255, 193, 7, 0.6); - border-left: 4px solid rgba(255, 193, 7, 0.9); - border-radius: 8px; - padding: 10px 12px; - cursor: pointer; - transition: all 0.3s ease; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4); -} - -#minimized-indicator:hover { - background: rgba(0, 0, 0, 0.85); - border-color: rgba(255, 193, 7, 0.9); - transform: translateY(-50%) scale(1.05); - box-shadow: 0 6px 16px rgba(255, 193, 7, 0.3); -} - -#minimized-indicator i { - font-size: 20px; - color: #ffc107; - display: block; - animation: pulse 2s infinite; -} - -#minimized-indicator .indicator-text { - color: rgba(255, 255, 255, 0.9); - font-size: 10px; - text-align: center; - margin-top: 4px; - text-transform: uppercase; - letter-spacing: 0.5px; - font-weight: 600; -} - -@keyframes pulse { - 0%, 100% { - opacity: 1; - transform: scale(1); - } - 50% { - opacity: 0.7; - transform: scale(0.95); - } -} - -/* Module indicator for TAB key reminder */ -.module-indicator { - position: fixed; - top: 20px; - left: 20px; - z-index: 10000; - background: rgba(0, 0, 0, 0.85); - border: 1px solid rgba(255, 193, 7, 0.4); - border-radius: 8px; - padding: 12px 16px; - padding-bottom: 8px; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5); - display: none; - animation: fadeIn 0.3s ease; - min-width: 100px; - overflow: hidden; -} - -.module-indicator i { - color: #ffc107; - font-size: 1.1rem; -} - -.module-indicator span { - color: rgba(255, 255, 255, 0.9); - font-size: 0.875rem; -} - -.module-indicator kbd { - padding: 2px 6px; - border-radius: 4px; - font-size: 0.8rem; - font-weight: 600; - font-family: monospace; -} - -/* Progress bar container - integrated into bottom border */ -.module-indicator-progress-container { - position: absolute; - bottom: 0; - left: 0; - width: 100%; - height: 3px; - background: rgba(255, 255, 255, 0.1); - overflow: hidden; -} - -/* Progress bar fill - fills from left to right */ -.module-indicator-progress { - height: 100%; - width: 0%; - background: linear-gradient(90deg, rgba(255, 193, 7, 0.6) 0%, rgba(255, 193, 7, 1) 100%); - transition: width 0.1s linear; } \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_boat_migrants.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_boat_migrants.lua deleted file mode 100644 index cd6955603..000000000 --- a/resources/[ERS]/night_ers/callouts/plugins/callout_boat_migrants.lua +++ /dev/null @@ -1,115 +0,0 @@ -Config.Callouts["boat_migrants"] = { - - Enabled = true, - CalloutName = "Reports of migrants arriving on a boat", - CalloutDescriptions = { - "Investigate reports of migrants arriving on a boat; secure the area and ensure their safety.", - "Alert: dispatch units to respond to reports of migrants arriving on a boat; provide immediate assistance.", - "Units required: respond to reports of a boat carrying migrants and take necessary actions to assist them.", - "Notice: check reports of migrants arriving on a boat; implement measures to ensure their wellbeing.", - "Alert: respond promptly to reports of migrants arriving on a boat; prioritize their safety and care.", - "Incident reported: look into reports of migrants arriving on a boat to provide necessary aid and support.", - "Investigate reports of a boat carrying migrants; coordinate with relevant authorities to address the situation.", - "Situation alert: address reports of migrants arriving on a boat; ensure the area is secured and help is provided.", - "Alert: handle reports of migrants arriving on a boat and follow protocols to ensure their safety and support.", - "Response needed: investigate reports of migrants arriving on a boat and take appropriate actions to assist and protect them.", - }, - CalloutUnitsRequired = { - description = "Police", - policeRequired = true, - ambulanceRequired = false, - fireRequired = false, - towRequired = false, - }, - CalloutLocations = { - [1] = vector3(-1417.2120, -1615.8606, 0.1448), - [2] = vector3(-1809.3936, -973.8002, 1.9747), - [3] = vector3(-2076.4451, -611.0533, 1.3401), - [4] = vector3(-3030.3972, -0.8509, 1.7006), - [5] = vector3(-3169.9976, 289.5727, 2.1437), - [6] = vector3(-3265.2388, 895.5994, -0.4368), - [7] = vector3(-3125.7136, 1656.5962, 0.4893), - [8] = vector3(-2685.5750, 2533.6912, 0.7223), - [9] = vector3(-2393.0715, 2630.3701, -0.0339), - [10] = vector3(-1868.3955, 2566.3022, 0.1976), - [11] = vector3(-1549.2698, 2626.0557, 1.5337), - [12] = vector3(-2553.6880, 3923.9187, 1.6076), - [13] = vector3(-2093.0620, 4599.1460, 1.1754), - [14] = vector3(-1394.5308, 5285.9351, 0.8501), - [15] = vector3(-885.7209, 5840.6069, 0.8044), - [16] = vector3(6.6508, 7059.5547, -0.6106), - [17] = vector3(3395.8420, 5637.5762, 0.9500), - [18] = vector3(2977.9421, 1821.2184, 1.2231), - [19] = vector3(2940.1265, 311.0411, 0.7346), - [20] = vector3(1601.8865, -2747.1536, 0.9043), - }, - PedChanceToFleeFromPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. - PedChanceToAttackPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. - PedChanceToSurrender = 0, -- Value between 0 and 100 -> Lower is less chance. - PedChanceToObtainWeapons = 0, -- Value between 0 and 100 -> Lower is less chance. - PedActionMinimumTimeoutInMs = 0, -- Milliseconds for the minimum timeout time to start the secondary action listed above. - PedActionMaximumTimeoutInMs = 1000, -- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! - PedActionOnNoActionFound = "none", -- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" - PedWeaponData = { -- The ped will be given one randomly selected weapon (in hand) from these weapons if PedChanceToObtainWeapons passed. - "weapon_unarmed", - }, - - client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) - - for index, pedNetId in pairs(pedList) do - local ped = NetToPed(pedNetId) - if DoesEntityExist(ped) then - ERS_RequestNetControlForEntity(ped) - if not IsPedInAnyBoat(ped) then - ERS_SetMovementAnimClipSetToPed(ped, "move_m@injured") - TaskWanderStandard(ped, 10.0, 10) - else - TaskReactAndFleePed(ped, plyPed) - end - end - end - - ERS_CreateTemporaryBlipForEntities(pedList, 30000) - - ERS_PerformTimedActionOnPed(calloutDataClient, pedList) - - end, - server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) - - - local diameter = 20 - - -- Build vehicle - local vehModel = "dinghy" - local vehType = "boat" - local vehCoords = vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z) - local vehHeading = math.random(360) - local vehNetId = ERS_CreateVehicle(vehModel, vehType, vehCoords, vehHeading) - local vehicle = NetworkGetEntityFromNetworkId(vehNetId) - table.insert(vehicleList, vehNetId) - - -- Build boat captain - local seatIndex = -1 - local pedModel = ERS_GetRandomModel(Config.randomPeds) - local pedCoords = vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z+3.0) - local pedHeading = math.random(360) - local pedNetId = ERS_CreatePed(pedModel, pedCoords, pedHeading) - local ped = NetworkGetEntityFromNetworkId(pedNetId) - SetPedIntoVehicle(ped, vehicle, seatIndex) - table.insert(pedList, pedNetId) - - -- Build migrant peds - local randomAmountOfPeds = math.random(2,10) - for i = 0, randomAmountOfPeds do - local coords = ERS_GetRandomCoordinateWithinRangeOfCoordinate(calloutData.Coordinates, diameter) - local pedModel = ERS_GetRandomModel(Config.randomPeds) - local pedCoords = vector3(coords.x, coords.y, coords.z + 1.0) - local pedHeading = math.random(360) - local pedNetId = ERS_CreatePed(pedModel, pedCoords, pedHeading) - local ped = NetworkGetEntityFromNetworkId(pedNetId) - table.insert(pedList, pedNetId) - end - - return true - end -} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_aggresive_boars.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_aggresive_boars.lua new file mode 100644 index 000000000..754587522 --- /dev/null +++ b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_aggresive_boars.lua @@ -0,0 +1,92 @@ +Config.Callouts["roxwood_aggresive_boars"] = { + + Enabled = true, + CalloutName = "Aggressive Boars", + CalloutDescriptions = { + "Respond to a report of aggressive boars attacking a farmer; ensure public safety and coordinate with animal control.", + "Alert: wild boars spotted attacking a farmer; deploy units to contain the animals and protect civilians.", + "Units needed: emergency call for aggressive boars; focus on securing the area and preventing any harm.", + "Notice: boars reported attacking a farmer; act promptly to control the situation and provide assistance.", + "Alert: report of aggressive boars; intervention needed to secure the scene and ensure safety.", + "Incident reported: boars sighted attacking a farmer; take action to deliver urgent response and support.", + "Respond to a situation involving aggressive boars; prioritize public safety and coordinate with wildlife experts.", + "Situation alert: boars on the loose; provide immediate assistance and ensure the area is secure.", + "Alert: report of boars attacking a farmer; respond swiftly to address the emergency and offer necessary support.", + "Response needed: aggressive boars; ensure public safety, provide aid, and secure the area.", + }, + CalloutUnitsRequired = { + description = "Police", + policeRequired = true, + ambulanceRequired = false, + fireRequired = false, + towRequired = false, + }, + CalloutLocations = { + [1] = vector3(-1823.0022, 6998.0410, 34.9726), + [2] = vector3(-2387.3379, 7242.6768, 29.0290), + [3] = vector3(-2461.5059, 7537.0752, 29.0388), + [4] = vector3(-2497.2771, 7169.6704, 29.0752), + [5] = vector3(-2538.9504, 7436.2910, 28.8805), + }, + PedChanceToFleeFromPlayer = 0, -- Boars won't flee from the player. + PedChanceToAttackPlayer = 100, -- Low chance to attack the player. + PedChanceToSurrender = 0, -- Boars won't surrender. + PedChanceToObtainWeapons = 0, -- Boars don't use weapons. + PedActionMinimumTimeoutInMs = 10000, -- Milliseconds for the minimum timeout time to start the secondary action listed above. + PedActionMaximumTimeoutInMs = 15000, -- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! + PedActionOnNoActionFound = "flee",-- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" + PedWeaponData = { -- The ped will be given one randomly selected weapon (in hand) from these weapons if PedChanceToObtainWeapons passed. + "weapon_musket", + }, + + client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) + local farmer + local boarPedList = {} + + for index, pedNetId in pairs(pedList) do + local ped = NetToPed(pedNetId) + if DoesEntityExist(ped) then + ERS_RequestNetControlForEntity(ped) + if index == 1 then + farmer = ped + ERS_PedEquipWeapon(ped, "weapon_musket", 100) + Wait(100) + TaskCombatPed(ped, NetToPed(pedList[2]), 0, 16) + else + TaskCombatPed(ped, farmer, 0, 16) + table.insert(boarPedList, pedNetId) + end + end + end + + ERS_CreateTemporaryBlipForEntities(boarPedList, 30000) + + ERS_PerformTimedActionOnPed(calloutDataClient, boarPedList) + end, + + server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) + local diameter = 15 + + -- Build farmer + local farmerModel = "a_m_m_farmer_01" + local farmerCoords = vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z+1.0) + local farmerHeading = math.random(360) + local farmerNetId = ERS_CreatePed(farmerModel, farmerCoords, farmerHeading) + local farmer = NetworkGetEntityFromNetworkId(farmerNetId) + table.insert(pedList, farmerNetId) + + -- Build boars + local boarModel = "a_c_boar" + local randomAmountOfBoars = math.random(3, 5) -- Randomize number of boars + for i = 1, randomAmountOfBoars do + local coords = ERS_GetRandomCoordinateWithinRangeOfCoordinate(calloutData.Coordinates, diameter) + local boarCoords = vector3(coords.x, coords.y, coords.z+1.0) + local boarHeading = math.random(360) + local boarNetId = ERS_CreatePed(boarModel, boarCoords, boarHeading) + local boar = NetworkGetEntityFromNetworkId(boarNetId) + table.insert(pedList, boarNetId) + end + + return true + end +} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_animal_on_road.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_animal_on_road.lua new file mode 100644 index 000000000..661201833 --- /dev/null +++ b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_animal_on_road.lua @@ -0,0 +1,84 @@ +Config.Callouts["roxwood_animal_on_road"] = { + + Enabled = true, + CalloutName = "Animal on the Road in Roxwood", + CalloutDescriptions = { + "An unexpected type of animal has appeared on the road, causing a disruption in traffic flow.", + "Emergency services have been called to intervene in a situation where an animal is impeding traffic on the road.", + "Reports indicate a disturbance on the roadway, with an unidentified creature causing a commotion.", + "A peculiar incident has unfolded on the road, requiring immediate attention to ensure public safety.", + "Emergency services have been dispatched to address an obstruction on the road, involving an animal.", + "A surprising encounter has occurred on the road, with an unknown creature causing a hindrance to traffic.", + "Witnesses report an unusual occurrence on the road, with an unidentified animal creating a hazard for motorists.", + "An incident has occurred on the road, with an animal posing a potential threat to drivers.", + "Emergency services have been alerted to a situation where an unidentified creature is obstructing the roadway.", + "Reports suggest an unexpected type of animal on the road, involving an animal that requires immediate assistance.", + }, + CalloutUnitsRequired = { + description = "Police, animal rescue.", + policeRequired = true, + ambulanceRequired = false, + fireRequired = false, + towRequired = false, + }, + CalloutLocations = { + [1] = vector3(-2917.2009, 6687.8828, 24.9933), + [2] = vector3(-2385.1338, 6949.2163, 35.3990), + [3] = vector3(-1927.2576, 7528.9648, 75.0004), + [4] = vector3(-673.5764, 7669.7896, 28.7780), + [5] = vector3(-670.4109, 6713.2271, 21.3245), + [6] = vector3(-397.3026, 7055.0483, 20.4035), + [7] = vector3(-2483.4431, 7576.3521, 28.6643), + [8] = vector3(-2060.8218, 8574.8389, 36.1939), + [9] = vector3(-2706.7444, 6928.1416, 28.8962), + [10] = vector3(-2615.2388, 6572.5176, 24.5263), + }, + PedChanceToFleeFromPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToAttackPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToSurrender = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToObtainWeapons = 0, -- Value between 0 and 100 -> Lower is less chance. + PedActionMinimumTimeoutInMs = 0, -- Milliseconds for the minimum timeout time to start the secondary action listed above. + PedActionMaximumTimeoutInMs = 1000, -- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! + PedActionOnNoActionFound = "none", -- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" + PedWeaponData = { -- The ped will be given one randomly selected weapon (in hand) from these weapons if PedChanceToObtainWeapons passed. + "weapon_unarmed", + }, + + client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) + + for index, pedNetId in pairs(pedList) do + local ped = NetToPed(pedNetId) + if DoesEntityExist(ped) then + ERS_RequestNetControlForEntity(ped) + ClearPedTasks(ped) + + if Config.Debug then + print("Found animal entity: "..ped) + end + + TaskWanderStandard(ped, 10.0, 10) + end + end + + ERS_CreateTemporaryBlipForEntities(pedList, 15000) + --ERS_PerformTimedActionOnPed(calloutDataClient, pedList) + + end, + server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) + + local diameter = 20 + + local randomAmountOfAnimals = math.random(1, 8) + local randomAnimalPedModel = ERS_GetRandomModel(Config.calloutAnimals) + for i = 1, randomAmountOfAnimals do + -- Build animals of the same type. + local coords = ERS_GetRandomCoordinateWithinRangeOfCoordinate(calloutData.Coordinates, diameter) + local animalPedCoords = vector3(coords.x, coords.y, coords.z) + local animalPedHeading = math.random(360) + local animalPedNetId = ERS_CreatePed(randomAnimalPedModel, animalPedCoords, animalPedHeading) + local animalPed = NetworkGetEntityFromNetworkId(animalPedNetId) + table.insert(pedList, animalPedNetId) + end + return true + end +} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_arson.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_arson.lua new file mode 100644 index 000000000..a54fdcc13 --- /dev/null +++ b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_arson.lua @@ -0,0 +1,102 @@ +Config.Callouts["roxwood_arson"] = { + + Enabled = true, + CalloutName = "Reports of Arson in Roxwood", + CalloutDescriptions = { + "Suspected arson incidents have been reported, requiring immediate response from law enforcement and fire services.", + "Urgent assistance needed to address suspected arson, ensuring community safety and property protection.", + "Multiple suspected arson cases reported, demanding swift action to prevent further damage and risk.", + "Identified arson cases prompt the need for additional resources to investigate and control the situation.", + "Emergency services alerted to suspected arson, necessitating coordinated efforts to apprehend those responsible.", + "Authorities seek assistance in addressing suspected arson, emphasizing public vigilance and cooperation.", + "Additional units required to support law enforcement and fire teams in responding to suspected arson incidents.", + "Emergency backup needed to help manage and contain suspected arson, ensuring public safety.", + "Responders call for assistance in dealing with suspected arson, highlighting the urgency of the situation.", + "Immediate intervention crucial to manage and address suspected arson, safeguarding lives and property.", + }, + CalloutUnitsRequired = { + description = "Police, Fire", + policeRequired = true, + ambulanceRequired = false, + fireRequired = true, + towRequired = false, + }, + CalloutLocations = { + [1] = vector3(-3082.4443, 7910.6416, 54.4692), + [2] = vector3(-3083.5991, 7936.8086, 54.1143), + [3] = vector3(-3044.8267, 7937.8999, 58.7173), + [4] = vector3(-3013.9849, 7916.1396, 58.6186), + [5] = vector3(-2541.5210, 7480.6040, 28.7263), + [6] = vector3(-2304.5576, 7760.9302, 44.3912), + [7] = vector3(-2281.4097, 8151.0815, 34.1373), + [8] = vector3(-1140.2708, 8119.0449, 23.1818), + [9] = vector3(-416.6748, 7650.4414, 6.3326), + [10] = vector3(-341.3544, 7396.8135, 6.4100), + }, + PedChanceToFleeFromPlayer = 50, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToAttackPlayer = 50, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToSurrender = 10, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToObtainWeapons = 60, -- Value between 0 and 100 -> Lower is less chance. + PedActionMinimumTimeoutInMs = 5000, -- Milliseconds for the minimum timeout time to start the secondary action listed above. + PedActionMaximumTimeoutInMs = 10000, -- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! + PedActionOnNoActionFound = "flee", -- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" + PedWeaponData = { -- The ped will be given one randomly selected weapon (in hand) from these weapons if PedChanceToObtainWeapons passed. + "weapon_knife", + "weapon_hammer", + "weapon_crowbar", + "weapon_bottle", + }, + + client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) + + for index, pedNetId in pairs(pedList) do + local ped = NetToPed(pedNetId) + if DoesEntityExist(ped) then + ERS_RequestNetControlForEntity(ped) + TaskSetBlockingOfNonTemporaryEvents(ped, true) + Wait(100) + ERS_SetPedToFleeFromPlayer(ped) + end + end + + ERS_CreateTemporaryBlipForEntities(pedList, 15000) + + ERS_PerformTimedActionOnPed(calloutDataClient, pedList) + + end, + server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) + + local diameter = 2 + + if UsingSmartFires then + -- Full version + local fireSize = Config.RandomSmallFireOrSmokeSize[math.random(#Config.RandomSmallFireOrSmokeSize)] + local fireType = Config.NormalFireTypes[math.random(#Config.NormalFireTypes)] + local fireId = exports['SmartFires']:CreateFire(vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z-0.5), fireSize, fireType) + DebugPrint("Created fire with ID: "..fireId) + table.insert(fireList, fireId) + else + -- Lite version + local fireSize = Config.RandomSmallFireOrSmokeSize[math.random(#Config.RandomSmallFireOrSmokeSize)] + local fireType = "normal" + local fireId = exports['SmartFiresLite']:CreateFire(vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z-0.5), fireSize, fireType) + DebugPrint("Created fire with SmartFiresLite with ID: "..fireId) + table.insert(fireList, fireId) + end + + -- Build suspect peds + local randomAmountOfSuspects = math.random(3) + for i = 1, randomAmountOfSuspects do + local coords = ERS_GetRandomCoordinateWithinRangeOfCoordinate(calloutData.Coordinates, diameter) + + local suspectPedModel = ERS_GetRandomModel(Config.randomPeds) + local suspectPedCoords = vector3(coords.x, coords.y, coords.z) + local suspectPedHeading = math.random(360) + local suspectPedNetId = ERS_CreatePed(suspectPedModel, suspectPedCoords, suspectPedHeading) + local suspectPed = NetworkGetEntityFromNetworkId(suspectPedNetId) + table.insert(pedList, suspectPedNetId) + end + + return true + end +} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_bouncer_in_trouble.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_bouncer_in_trouble.lua new file mode 100644 index 000000000..927288021 --- /dev/null +++ b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_bouncer_in_trouble.lua @@ -0,0 +1,154 @@ +Config.Callouts["roxwood_bouncer_in_trouble"] = { + + Enabled = true, + CalloutName = "Bouncer in Trouble", + CalloutDescriptions = { + "A bouncer is struggling to control a rowdy crowd at a nightclub, with tensions escalating quickly.", + "Security personnel have called for backup as a confrontation with patrons turns violent.", + "Reports indicate a bouncer is overwhelmed by a group of unruly individuals at a local bar.", + "A nightclub bouncer is facing resistance from aggressive patrons, requiring immediate assistance.", + "A disturbance at a bar has led to a bouncer being outnumbered, with the situation deteriorating.", + "A bouncer is attempting to defuse a volatile situation at a club, with the potential for violence.", + "Witnesses report a bouncer being attacked by patrons, with the need for urgent intervention.", + "Security at a venue is under threat as a bouncer deals with a hostile crowd, needing backup.", + "A bouncer is in distress as a confrontation with patrons escalates, requiring swift response.", + "Emergency services are needed to assist a bouncer in trouble, with the potential for further conflict.", + }, + CalloutUnitsRequired = { + description = "Police.", + policeRequired = true, + ambulanceRequired = false, + fireRequired = false, + towRequired = false, + }, + CalloutLocations = { + [1] = vector3(-605.2895, 7008.7100, 24.2095), + [2] = vector3(-626.9119, 6922.6372, 24.3170), + [3] = vector3(-330.2892, 7173.5366, 6.4107), + }, + PedChanceToFleeFromPlayer = 20, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToAttackPlayer = 50, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToSurrender = 20, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToObtainWeapons = 25, -- Value between 0 and 100 -> Lower is less chance. + PedActionMinimumTimeoutInMs = 10000,-- Milliseconds for the minimum timeout time to start the secondary action listed above. + PedActionMaximumTimeoutInMs = 15000,-- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! + PedActionOnNoActionFound = "flee", -- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" + PedWeaponData = { -- The ped will be given one randomly selected weapon (in hand) from these weapons if PedChanceToObtainWeapons passed. + "weapon_knife", + "weapon_bat", + "weapon_hammer", + "weapon_wrench", + "weapon_pistol", + }, + + client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) + local teamBouncers = {} + local teamOthers = {} + + for index, pedNetId in pairs(pedList) do + local ped = NetToPed(pedNetId) + if DoesEntityExist(ped) then + ERS_RequestNetControlForEntity(ped) + local model = GetEntityModel(ped) + + -- Check if the ped is a bouncer + if model == GetHashKey("s_m_m_bouncer_01") or model == GetHashKey("s_m_m_highsec_01") or model == GetHashKey("s_m_m_highsec_02") then + table.insert(teamBouncers, ped) + else + table.insert(teamOthers, ped) + end + + TaskSetBlockingOfNonTemporaryEvents(ped, true) + Wait(100) + ERS_SpawnConfiguredWeaponForPed(ped, calloutDataClient) + end + end + + -- Function to make peds flee + local function makePedsFlee(peds) + for _, ped in pairs(peds) do + if DoesEntityExist(ped) and not IsPedDeadOrDying(ped, true) then + TaskSmartFleePed(ped, plyPed, 100.0, -1, false, false) + end + end + end + + -- Monitor and update ped behavior + Citizen.CreateThread(function() + while true do + Citizen.Wait(1000) -- Check every second + + -- Remove dead peds from teams + for i = #teamBouncers, 1, -1 do + if IsPedDeadOrDying(teamBouncers[i], true) then + table.remove(teamBouncers, i) + end + end + + for i = #teamOthers, 1, -1 do + if IsPedDeadOrDying(teamOthers[i], true) then + table.remove(teamOthers, i) + end + end + + -- If the others team or the bouncers team is too small, make them flee (and let bouncers stay) + if #teamOthers < 3 or #teamBouncers < 2 then + makePedsFlee(teamOthers) + break + end + end + end) + + -- Initial combat setup + if #teamBouncers > 0 and #teamOthers > 0 then + for _, bouncer in pairs(teamBouncers) do + local randomTarget = teamOthers[math.random(#teamOthers)] + TaskCombatPed(bouncer, randomTarget, 0, 16) + if Config.Debug then + print("Bouncer "..bouncer.." is attacking ped "..randomTarget) + end + end + + for _, other in pairs(teamOthers) do + local randomTarget = teamBouncers[math.random(#teamBouncers)] + TaskCombatPed(other, randomTarget, 0, 16) + if Config.Debug then + print("Other ped "..other.." is attacking bouncer "..randomTarget) + end + end + end + + ERS_CreateTemporaryBlipForEntities(pedList, 15000) + ERS_PerformTimedActionOnPed(calloutDataClient, pedList) + end, + server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) + local bouncerPedModels = { + "s_m_m_bouncer_01", + "s_m_m_highsec_01", + "s_m_m_highsec_02", + } + local randomBouncers = math.random(1, 3) + for i = 1, randomBouncers do + -- Build peds + local pedModel = bouncerPedModels[math.random(#bouncerPedModels)] + local pedCoords = vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z) + local pedHeading = math.random(360) + local pedNetId = ERS_CreatePed(pedModel, pedCoords, pedHeading) + local ped = NetworkGetEntityFromNetworkId(pedNetId) + table.insert(pedList, pedNetId) + end + + local randomBrawlers = math.random(2, 8) + for i = 1, randomBrawlers do + -- Build peds + local pedModel = ERS_GetRandomModel(Config.randomPeds) + local pedCoords = vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z) + local pedHeading = math.random(360) + local pedNetId = ERS_CreatePed(pedModel, pedCoords, pedHeading) + local ped = NetworkGetEntityFromNetworkId(pedNetId) + table.insert(pedList, pedNetId) + end + + return true + end +} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_bridge_blockade.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_bridge_blockade.lua new file mode 100644 index 000000000..727890b05 --- /dev/null +++ b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_bridge_blockade.lua @@ -0,0 +1,72 @@ +Config.Callouts["roxwood_bridge_blockade"] = { + + Enabled = true, + CalloutName = "Bridge blockade", + CalloutDescriptions = { + "Emergency: respond to reports of a bridge blockade; ensure the area is cleared to prevent accidents.", + "Urgent alert: dispatch units to address a bridge blockade; remove debris to ensure safe passage for vehicles.", + "Critical response required: attend to reports of a bridge blockade; secure the area and prevent further incidents.", + "Notice: check reports of a bridge blockade; take immediate action to clear debris and restore road safety.", + "Alert: respond promptly to reports of a bridge blockade; prioritize the safety of motorists and clear the obstruction.", + "Incident reported: investigate reports of a bridge blockade; coordinate with local authorities to manage the situation.", + "Immediate action: address reports of a bridge blockade; use appropriate methods to clear the area and ensure safety.", + "Situation alert: assist with clearing a bridge blockade; ensure the area is safe for traffic and pedestrians.", + "Emergency response: handle reports of a bridge blockade and follow protocols to remove debris and ensure road safety.", + "Response needed: investigate reports of a bridge blockade urgently; take appropriate actions to prevent accidents and ensure clear passage.", + }, + CalloutUnitsRequired = { + description = "Police.", + policeRequired = true, + ambulanceRequired = false, + fireRequired = false, + towRequired = false, + }, + CalloutLocations = { + [1] = vector3(-2015.0530, 7387.4570, 53.4759), + [2] = vector3(-1930.3730, 7569.9995, 81.9424), + [3] = vector3(-2857.5974, 8359.9668, 43.2680), + [4] = vector3(-652.4728, 6653.6875, 20.9940), + [5] = vector3(-1568.6243, 6724.4087, 17.7642), + }, + PedChanceToFleeFromPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToAttackPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToSurrender = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToObtainWeapons = 0, -- Value between 0 and 100 -> Lower is less chance. + PedActionMinimumTimeoutInMs = 0, -- Milliseconds for the minimum timeout time to start the secondary action listed above. + PedActionMaximumTimeoutInMs = 1000, -- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! + PedActionOnNoActionFound = "none", -- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" + PedWeaponData = { -- The ped will be given one randomly selected weapon (in hand) from these weapons if PedChanceToObtainWeapons passed. + "weapon_unarmed", + }, + + client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) + for index, objNetId in pairs(objectList) do + local obj = NetToObj(objNetId) + if DoesEntityExist(obj) then + ERS_RequestNetControlForEntity(obj) + PlaceObjectOnGroundProperly(obj) + end + end + ERS_CreateTemporaryBlipForEntities(objectList, 30000) + end, + server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) + local diameter = 10 + -- Build objects + local bridgeBlockObjects = {"prop_rub_scrap_06", "prop_tree_fallen_02", "prop_rub_pile_02", "prop_rub_pile_01", "prop_pile_dirt_04", "prop_pile_dirt_02", "prop_pipe_single_01"} + local randomAmountOfObjects = math.random(5) + for i = 1, randomAmountOfObjects do + local coords = ERS_GetRandomCoordinateWithinRangeOfCoordinate(calloutData.Coordinates, diameter) + local objModel = ERS_GetRandomModel(bridgeBlockObjects) + local objCoords = vector3(coords.x, coords.y, coords.z) + local objHeading = math.random(360) + local objNetId = ERS_CreateObject(objModel, objCoords, objHeading) + if objNetId then + local obj = NetworkGetEntityFromNetworkId(objNetId) + table.insert(objectList, objNetId) + else + DebugPrint("^1ERROR ^7Could not create object: "..objModel) + end + end + return true + end +} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_crop_fire.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_crop_fire.lua new file mode 100644 index 000000000..853b85c57 --- /dev/null +++ b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_crop_fire.lua @@ -0,0 +1,95 @@ +Config.Callouts["roxwood_crop_fire"] = { + Enabled = true, + CalloutName = "Roxwood Crop Fire", + CalloutDescriptions = { + "Reports of a combine harvester malfunction causing a rapidly spreading wheat field fire.", + "Lightning strike has ignited multiple dry crop fields, threatening nearby farm structures.", + "Agricultural equipment sparked a fire in drought-affected corn fields, requiring immediate response.", + "Burning embers from a controlled burn have spread to adjacent crop fields.", + "Chemical fertilizer storage caught fire near valuable crop fields, situation escalating.", + "Electrical fault in irrigation system has triggered a fire in the surrounding crop fields.", + "Severe drought conditions have led to spontaneous combustion in hay storage, threatening nearby crops.", + "Farm workers report uncontrolled fire spreading through mature wheat fields during harvest.", + "Mechanical failure in grain silo ventilation system caused fire to spread to surrounding crops.", + "Emergency response needed for crop fire threatening multiple agricultural structures and equipment.", + }, + CalloutUnitsRequired = { + description = "Police, Fire.", + policeRequired = true, + ambulanceRequired = false, + fireRequired = true, + towRequired = false, + }, + CalloutLocations = { + [1] = vector3(-2399.7097, 7358.4756, 29.0479), + [2] = vector3(-2487.0852, 7449.9502, 29.0479), + [3] = vector3(-2494.1135, 7374.3760, 29.0479), + [4] = vector3(-2517.3569, 7199.2168, 29.0479), + [5] = vector3(-2652.8608, 7139.6714, 29.0479), + [6] = vector3(-2579.2705, 7414.2432, 29.0479), + [7] = vector3(-2398.9187, 7448.2280, 29.0479), + [8] = vector3(-2344.8552, 7197.0410, 29.0479), + [9] = vector3(-2189.1917, 7144.0063, 29.0479), + [10] = vector3(-2502.3936, 7176.9692, 29.0479), + }, + PedChanceToFleeFromPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToAttackPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToSurrender = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToObtainWeapons = 0, -- Value between 0 and 100 -> Lower is less chance. + PedActionMinimumTimeoutInMs = 0, -- Milliseconds for the minimum timeout time to start the secondary action listed above. + PedActionMaximumTimeoutInMs = 1000, -- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! + PedActionOnNoActionFound = "none", -- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" + PedWeaponData = { -- The ped will be given one randomly selected weapon (in hand) from these weapons if PedChanceToObtainWeapons passed. + "weapon_unarmed", + }, + client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) + + for index, objNetId in pairs(objectList) do + local obj = NetToObj(objNetId) + if DoesEntityExist(obj) then + ERS_RequestNetControlForEntity(obj) + PlaceObjectOnGroundProperly(obj) + end + end + + end, + server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) + + local diameter = 30 + + -- Build Fires & smoke + local randomAmountOfFires = math.random(10) + for i = 1, randomAmountOfFires do + local coords = ERS_GetRandomCoordinateWithinRangeOfCoordinate(calloutData.Coordinates, diameter) + if UsingSmartFires then + -- Full version + local fireSize = Config.RandomLargeFireOrSmokeSize[math.random(#Config.RandomLargeFireOrSmokeSize)] + local fireType = Config.NormalFireTypes[math.random(#Config.NormalFireTypes)] + local fireId = exports['SmartFires']:CreateFire(vector3(coords.x, coords.y, coords.z+0.6), fireSize, fireType) + DebugPrint("Created fire with ID: "..fireId) + table.insert(fireList, fireId) + + local smokeSize = Config.RandomMediumFireOrSmokeSize[math.random(#Config.RandomMediumFireOrSmokeSize)] + local smokeType = Config.AllSmokeTypes[math.random(#Config.AllSmokeTypes)] + local smokeId = exports['SmartFires']:CreateSmoke(vector3(coords.x, coords.y, coords.z-0.5), smokeSize, smokeType) + DebugPrint("Created smoke particle with ID: "..smokeId) + table.insert(smokeList, smokeId) + else + -- Lite version + local fireSize = Config.RandomLargeFireOrSmokeSize[math.random(#Config.RandomLargeFireOrSmokeSize)] + local fireType = "normal" + local fireId = exports['SmartFiresLite']:CreateFire(vector3(coords.x, coords.y, coords.z+0.6), fireSize, fireType) + DebugPrint("Created fire with SmartFiresLite with ID: "..fireId) + table.insert(fireList, fireId) + + local smokeSize = Config.RandomMediumFireOrSmokeSize[math.random(#Config.RandomMediumFireOrSmokeSize)] + local smokeType = "normal" + local smokeId = exports['SmartFiresLite']:CreateSmoke(vector3(coords.x, coords.y, coords.z-0.5), smokeSize, smokeType) + DebugPrint("Created smoke particle with ID: "..smokeId) + table.insert(smokeList, smokeId) + end + end + + return true + end +} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_drug_lab_incident.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_drug_lab_incident.lua new file mode 100644 index 000000000..04e61544a --- /dev/null +++ b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_drug_lab_incident.lua @@ -0,0 +1,113 @@ +Config.Callouts["roxwood_drug_lab_incident"] = { + + Enabled = true, + CalloutName = "Drug Lab Incident", + CalloutDescriptions = { + "Emergency response needed at the drug lab; individual requiring immediate medical attention.", + "Alert: medical emergency reported at drug lab facilities; units requested for immediate response.", + "Units needed: incident reported at drug lab involving an injured person.", + "Emergency situation at drug lab; medical assistance required for lab visitor.", + "Alert: drug lab incident in progress; medical response team needed on scene.", + "First responders requested at drug lab location; medical emergency reported.", + "Respond to drug lab emergency; coordinate with on-site staff for immediate assistance.", + "Situation alert: medical incident at drug lab facilities requiring urgent response.", + "Emergency services needed at drug lab; injured person requiring immediate attention.", + "Response needed: drug lab incident involving injured visitor; medical assistance required.", + }, + CalloutUnitsRequired = { + description = "Police, Ambulance, Fire.", + policeRequired = true, + ambulanceRequired = true, + fireRequired = true, + towRequired = false, + }, + CalloutLocations = { + [1] = vector3(-2281.0774, 8149.1436, 31.2439), + [2] = vector3(-2280.4634, 8029.7676, 34.1530), + [3] = vector3(-3075.2825, 7893.6514, 56.5999), + }, + PedChanceToFleeFromPlayer = 30, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToAttackPlayer = 30, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToSurrender = 30, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToObtainWeapons = 30, -- Value between 0 and 100 -> Lower is less chance. + PedActionMinimumTimeoutInMs = 0, -- Milliseconds for the minimum timeout time to start the secondary action listed above. + PedActionMaximumTimeoutInMs = 1000, -- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! + PedActionOnNoActionFound = "none", -- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" + PedWeaponData = { -- The ped will be given one randomly selected weapon (in hand) from these weapons if PedChanceToObtainWeapons passed. + "weapon_pistol", + }, + + client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) + + for index, pedNetId in pairs(pedList) do + local ped = NetToPed(pedNetId) + if DoesEntityExist(ped) then + ERS_RequestNetControlForEntity(ped) + ERS_SetPedAsDrunkPed(ped) + ERS_ApplyBloodToPed(ped) + ERS_SetPedToFleeFromPlayer(ped) + end + end + + ERS_CreateTemporaryBlipForEntities(pedList, 15000) + ERS_PerformTimedActionOnPed(calloutDataClient, pedList) + + end, + server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) + + -- Build peds + local diameter = 1.5 + local randomAmountOfWorkers = math.random(1, 3) + local drugLabWorkerPedModels = {"mp_f_cocaine_01", "mp_f_meth_01", "mp_m_meth_01", "mp_m_cocaine_01"} + for i = 1, randomAmountOfWorkers do + local coords = ERS_GetRandomCoordinateWithinRangeOfCoordinate(calloutData.Coordinates, diameter) + local pedModel = drugLabWorkerPedModels[math.random(1, #drugLabWorkerPedModels)] + local pedCoords = vector3(coords.x, coords.y, coords.z+1.0) + local pedHeading = math.random(360) + local pedNetId = ERS_CreatePed(pedModel, pedCoords, pedHeading) + local ped = NetworkGetEntityFromNetworkId(pedNetId) + table.insert(pedList, pedNetId) + end + + -- Build a small sized fire + if UsingSmartFires then + -- Full version + local fireSize = Config.RandomSmallFireOrSmokeSize[math.random(#Config.RandomSmallFireOrSmokeSize)] + local fireType = Config.NormalFireTypes[math.random(#Config.NormalFireTypes)] + local fireId = exports['SmartFires']:CreateFire(vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z-0.5), fireSize, fireType) + DebugPrint("Created fire with ID: "..fireId) + table.insert(fireList, fireId) + + -- Build smoke + local chanceOnASmoke = 50 + if math.random(1, 100) <= chanceOnASmoke then + local smokeSize = Config.RandomSmallFireOrSmokeSize[math.random(#Config.RandomSmallFireOrSmokeSize)] + local smokeType = Config.AllSmokeTypes[math.random(#Config.AllSmokeTypes)] + local smokeId = exports['SmartFires']:CreateSmoke(vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z-0.5), smokeSize, smokeType) + + DebugPrint("Created smoke with ID: "..smokeId) + table.insert(smokeList, smokeId) + end + else + -- Lite version + local fireSize = Config.RandomSmallFireOrSmokeSize[math.random(#Config.RandomSmallFireOrSmokeSize)] + local fireType = "normal" + local fireId = exports['SmartFiresLite']:CreateFire(vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z-0.5), fireSize, fireType) + DebugPrint("Created fire with SmartFiresLite with ID: "..fireId) + table.insert(fireList, fireId) + + -- Build smoke + local chanceOnASmoke = 50 + if math.random(1, 100) <= chanceOnASmoke then + local smokeSize = Config.RandomSmallFireOrSmokeSize[math.random(#Config.RandomSmallFireOrSmokeSize)] + local smokeType = "normal" + local smokeId = exports['SmartFiresLite']:CreateSmoke(vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z-0.5), smokeSize, smokeType) + + DebugPrint("Created smoke with ID: "..smokeId) + table.insert(smokeList, smokeId) + end + end + + return true + end +} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_gas_station_robbery.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_gas_station_robbery.lua new file mode 100644 index 000000000..a09a5963b --- /dev/null +++ b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_gas_station_robbery.lua @@ -0,0 +1,112 @@ +Config.Callouts["roxwood_gas_station_robbery"] = { + + Enabled = true, + CalloutName = "Roxwood Gas Station Robbery", + CalloutDescriptions = { + "Respond to a report of an armed robbery at a gas station; secure the area and apprehend the suspects.", + "Alert: armed robbery in progress at a gas station; deploy units to the location and ensure public safety.", + "Units needed: report of a robbery involving multiple armed suspects; focus on securing the scene and detaining the suspects.", + "Notice: armed robbery reported at a gas station; act promptly to control the situation and prevent harm.", + "Alert: report of an armed robbery; intervention needed to apprehend the suspects and ensure safety.", + "Incident reported: armed robbery at a gas station; take action to secure the premises and protect bystanders.", + "Respond to a situation involving an armed robbery; prioritize public safety and coordinate with law enforcement.", + "Situation alert: armed robbery in progress; secure the area and detain the suspects.", + "Alert: report of a robbery with weapons; respond swiftly to address the situation and ensure safety.", + "Response needed: armed robbery; secure the area, apprehend the suspects, and restore order.", + }, + CalloutUnitsRequired = { + description = "Police, Ambulance.", + policeRequired = true, + ambulanceRequired = true, + fireRequired = false, + towRequired = false, + }, + CalloutLocations = { + [1] = vector3(-1228.4095, 6927.7363, 20.4751), + [2] = vector3(-522.2498, 7560.3276, 6.5205), + }, + PedChanceToFleeFromPlayer = 50, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToAttackPlayer = 50, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToSurrender = 20, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToObtainWeapons = 100, -- Value between 0 and 100 -> Lower is less chance. + PedActionMinimumTimeoutInMs = 10000, -- Milliseconds for the minimum timeout time to start the secondary action listed above. + PedActionMaximumTimeoutInMs = 15000, -- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! + PedActionOnNoActionFound = "attack", -- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" + PedWeaponData = { -- The ped will be given one randomly selected weapon (in hand) from these weapons if PedChanceToObtainWeapons passed. + "weapon_pistol", + }, + + client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) + + local plyGroupHash = GetPedRelationshipGroupHash(plyPed) + local retval, suspectGroupHash = AddRelationshipGroup("SUSPECT_GROUP_HASH") + local victim + local suspectPedList = {} + + for index, pedNetId in pairs(pedList) do + local ped = NetToPed(pedNetId) + if DoesEntityExist(ped) then + ERS_RequestNetControlForEntity(ped) + if index == 1 then + victim = ped + ERS_ClearPedTasksAndBlockEvents(ped) + Wait(100) + TaskHandsUp(ped, -1, 0, -1, true) + else + SetPedRelationshipGroupHash(ped, suspectGroupHash) + SetEntityCanBeDamagedByRelationshipGroup(ped, false, suspectGroupHash) + SetRelationshipBetweenGroups(5, suspectGroupHash, plyGroupHash) + SetRelationshipBetweenGroups(5, plyGroupHash, suspectGroupHash) + + ERS_ClearPedTasksAndBlockEvents(ped) + ERS_SpawnConfiguredWeaponForPed(ped, calloutDataClient) + Wait(100) + TaskAimGunAtEntity(ped, victim, -1, false) + table.insert(suspectPedList, pedNetId) + + Citizen.CreateThread(function() + local randomTime = math.random(5000, 9000) + Citizen.Wait(randomTime) + local chanceToShoot = math.random(1, 100) + if chanceToShoot <= 50 then + TaskShootAtEntity(ped, victim, -1, false) + else + TaskSmartFleePed(ped, plyPed, 10000, -1, false) + end + end) + end + end + end + + ERS_CreateTemporaryBlipForEntities(suspectPedList, 15000) + + ERS_PerformTimedActionOnPed(calloutDataClient, suspectPedList) + + end, + server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) + + local diameter = 15 + + -- Build victim + local pedModel = ERS_GetRandomModel(Config.randomPeds) + local pedCoords = vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z+1.0) + local pedHeading = math.random(360) + local pedNetId = ERS_CreatePed(pedModel, pedCoords, pedHeading) + local ped = NetworkGetEntityFromNetworkId(pedNetId) + table.insert(pedList, pedNetId) + + -- Build suspects + local randomAmountOfSuspects = math.random(2, 4) -- Randomize number of suspects + for i = 1, randomAmountOfSuspects do + local coords = ERS_GetRandomCoordinateWithinRangeOfCoordinate(calloutData.Coordinates, diameter) + local pedModel = ERS_GetRandomModel(Config.randomPeds) + local pedCoords = vector3(coords.x, coords.y, coords.z+1.0) + local pedHeading = math.random(360) + local pedNetId = ERS_CreatePed(pedModel, pedCoords, pedHeading) + local ped = NetworkGetEntityFromNetworkId(pedNetId) + table.insert(pedList, pedNetId) + end + + return true + end +} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_illegal_camping.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_illegal_camping.lua new file mode 100644 index 000000000..5695e0aee --- /dev/null +++ b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_illegal_camping.lua @@ -0,0 +1,117 @@ +Config.Callouts["roxwood_illegal_camping"] = { + + Enabled = true, + CalloutName = "Illegal Camping", + CalloutDescriptions = { + "Investigate reports of illegal camping in a restricted area; ensure compliance with local regulations.", + "Alert: dispatch units to handle reports of unauthorized camping; assess environmental impact.", + "Units required: respond to reports of illegal camping and evaluate potential safety hazards.", + "Notice: check reports of campers setting up in prohibited zones; enforce park rules.", + "Alert: respond promptly to reports of unauthorized camping; prioritize public safety and environmental protection.", + "Incident reported: look into reports of illegal camping activities to understand the situation.", + "Investigate reports of campers in restricted areas; coordinate with park authorities and secure the site.", + "Situation alert: address reports of illegal camping; work with local enforcement to resolve the issue.", + "Alert: handle reports of unauthorized camping and adhere to protocols for potential environmental hazards.", + "Response needed: investigate reports of illegal camping and take steps to ensure compliance with regulations.", + }, + CalloutUnitsRequired = { + description = "Police", + policeRequired = true, + ambulanceRequired = false, + fireRequired = false, + towRequired = false, + }, + CalloutLocations = { + [1] = vector3(-2968.4868, 8348.0039, 43.2270), + [2] = vector3(-2376.2881, 7808.8652, 33.1581), + [3] = vector3(-2710.9854, 7801.0586, 46.5524), + [4] = vector3(-3067.7266, 7109.3135, 42.5468), + [5] = vector3(-3676.9055, 6168.9692, 24.5723), + [6] = vector3(-3588.0854, 7165.6846, 46.3299), + [7] = vector3(-3312.8560, 8835.7363, 36.2966), + [8] = vector3(-1284.6665, 8242.3164, 12.2473), + [9] = vector3(-1490.4974, -262.6434, 50.2380), + [10] = vector3(-2220.6472, 7570.6499, 56.8878), + }, + PedChanceToFleeFromPlayer = 10, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToAttackPlayer = 10, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToSurrender = 50, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToObtainWeapons = 10, -- Value between 0 and 100 -> Lower is less chance. + PedActionMinimumTimeoutInMs = 10000, -- Milliseconds for the minimum timeout time to start the secondary action listed above. + PedActionMaximumTimeoutInMs = 15000, -- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! + PedActionOnNoActionFound = "none", -- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" + PedWeaponData = { -- The ped will be given one randomly selected weapon (in hand) from these weapons if PedChanceToObtainWeapons passed. + "weapon_knife", + }, + + client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) + + local vehicle + local driver + + for index, vehNetId in pairs(vehicleList) do + local veh = NetToVeh(vehNetId) + if DoesEntityExist(veh) then + vehicle = veh + ERS_RequestNetControlForEntity(vehicle) + + end + end + + for index, pedNetId in pairs(pedList) do + local ped = NetToPed(pedNetId) + if DoesEntityExist(ped) then + if index == 1 then + driver = ped + ERS_RequestNetControlForEntity(driver) + TaskSetBlockingOfNonTemporaryEvents(driver, true) + ERS_SetPedAsDrunkPed(driver) + else + -- Play a smoking weed animation on them + ERS_SetPedAsDrunkPed(ped) + local scenario = ERS_SelectRandomSmokeScenario() + TaskStartScenarioInPlace(ped, scenario, 0, true) + end + end + end + + ERS_CreateTemporaryBlipForEntities(vehicleList, 15000) + ERS_CreateTemporaryBlipForEntities(pedList, 15000) + + end, + server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) + + -- Build vehicle + local campingVehicles = {"camper", "journey", "paradise"} + local vehModel = ERS_GetRandomModel(campingVehicles) + local vehType = "automobile" + local vehCoords = vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z) + local vehHeading = math.random(360) + local vehNetId = ERS_CreateVehicle(vehModel, vehType, vehCoords, vehHeading) + local vehicle = NetworkGetEntityFromNetworkId(vehNetId) + table.insert(vehicleList, vehNetId) + + -- Build ped + local pedModel = ERS_GetRandomModel(Config.randomPeds) + local pedCoords = vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z+3.0) + local pedHeading = math.random(360) + local pedNetId = ERS_CreatePed(pedModel, pedCoords, pedHeading) + local ped = NetworkGetEntityFromNetworkId(pedNetId) + SetPedIntoVehicle(ped, vehicle, -1) + table.insert(pedList, pedNetId) + + -- Build camping friends + local amountOfCampingFriends = math.random(1, 5) + for i = 1, amountOfCampingFriends do + local diameter = 20.0 + local coords = ERS_GetRandomCoordinateWithinRangeOfCoordinate(calloutData.Coordinates, diameter) + local companionModel = ERS_GetRandomModel(Config.randomPeds) + local companionCoords = vector3(coords.x, coords.y, coords.z+3.0) + local companionHeading = math.random(360) + local companionNetId = ERS_CreatePed(companionModel, companionCoords, companionHeading) + table.insert(pedList, companionNetId) + end + + return true + end +} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_miner_panicalarm.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_miner_panicalarm.lua new file mode 100644 index 000000000..334814b70 --- /dev/null +++ b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_miner_panicalarm.lua @@ -0,0 +1,91 @@ +Config.Callouts["roxwood_miner_panic_alarm"] = { + + Enabled = true, + CalloutName = "Panic alarm at the mine", + CalloutDescriptions = { + "Emergency responders are required to investigate the source of the panic alarm at the mine.", + "Authorities report panic alarm at the mine, demanding immediate investigation to ensure safety.", + "Panic alarm has been reported at the mine, necessitating urgent action to identify and address the cause.", + "Critical situation with panic alarm at the mine; additional units are needed for support.", + "Immediate response needed to address panic alarm at the mine posing potential danger.", + "Panic alarm has been detected at the mine, posing a possible threat; reinforcements are necessary to investigate and contain any hazards.", + "Emergency crews are requesting backup to assist in investigating and managing panic alarm at the mine.", + "An urgent call for help has been issued to handle panic alarm at the mine and ensure safety.", + "Responders are on the scene of panic alarm at the mine and need extra support to stabilize the situation.", + "A serious emergency involving panic alarm at the mine demands swift action to prevent a potential catastrophic outcome.", + }, + CalloutUnitsRequired = { + description = "Police, Fire.", + policeRequired = true, + ambulanceRequired = false, + fireRequired = true, + towRequired = false, + }, + CalloutLocations = { + [1] = vector3(-1474.1163, 7612.5264, 90.0090), + [2] = vector3(-1498.0601, 7648.6548, 89.9406), + [3] = vector3(-1561.5817, 7478.5679, 95.6648), + [4] = vector3(-1400.6205, 7501.4053, 80.8366), + }, + PedChanceToFleeFromPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToAttackPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToSurrender = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToObtainWeapons = 0, -- Value between 0 and 100 -> Lower is less chance. + PedActionMinimumTimeoutInMs = 0, -- Milliseconds for the minimum timeout time to start the secondary action listed above. + PedActionMaximumTimeoutInMs = 1000, -- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! + PedActionOnNoActionFound = "none", -- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" + PedWeaponData = { -- The ped will be given one randomly selected weapon (in hand) from these weapons if PedChanceToObtainWeapons passed. + "weapon_unarmed", + }, + + client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) + + -- No other actions required clientside. + for index, pedNetId in pairs(pedList) do + local ped = NetToPed(pedNetId) + if DoesEntityExist(ped) then + ERS_RequestNetControlForEntity(ped) + TaskSetBlockingOfNonTemporaryEvents(ped, true) + ERS_ApplyBloodToPed(ped) + local scenario = ERS_SelectRandomWoundedPersonScenario() + TaskStartScenarioInPlace(ped, scenario, 0, true) + end + end + + ERS_CreateTemporaryBlipForEntities(pedList, 120000) + ERS_PerformTimedActionOnPed(calloutDataClient, pedList) + end, + server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) + + -- Build smoke + if UsingSmartFires then + -- Full version + local smokeSize = Config.RandomMediumFireOrSmokeSize[math.random(#Config.RandomMediumFireOrSmokeSize)] + local smokeType = Config.FoggySmoke + local smokeId = exports['SmartFires']:CreateSmoke(vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z-0.5), smokeSize, smokeType) + DebugPrint("Created smoke particle with ID: "..smokeId) + table.insert(smokeList, smokeId) + else + -- Lite version + local smokeSize = Config.RandomMediumFireOrSmokeSize[math.random(#Config.RandomMediumFireOrSmokeSize)] + local smokeType = "normal" + local smokeId = exports['SmartFiresLite']:CreateSmoke(vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z-0.5), smokeSize, smokeType) + DebugPrint("Created smoke particle with ID: "..smokeId) + table.insert(smokeList, smokeId) + end + + -- Build wounded miner + local amountOfPeds = math.random(1, 4) + local minerPedModels = {"s_m_y_construct_01", "s_m_y_construct_02"} + for i = 1, amountOfPeds do + local pedModel = ERS_GetRandomModel(minerPedModels) + local pedCoords = vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z) + local pedHeading = math.random(360) + local pedNetId = ERS_CreatePed(pedModel, pedCoords, pedHeading) + local ped = NetworkGetEntityFromNetworkId(pedNetId) + table.insert(pedList, pedNetId) + end + + return true + end +} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_mysterious_egg.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_mysterious_egg.lua new file mode 100644 index 000000000..375653531 --- /dev/null +++ b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_mysterious_egg.lua @@ -0,0 +1,516 @@ +Config.Callouts["roxwood_mysterious_egg"] = { + + Enabled = true, + CalloutName = "Mysterious egg(s) reported", + CalloutDescriptions = { + "Emergency: respond to reports of a mysterious egg; assess potential hazards.", + "Urgent alert: unidentified egg-like object reported requiring immediate investigation.", + "Critical response required: investigate reports of an unusual egg of unknown origin.", + "Notice: mysterious egg discovered in the area; assessment needed.", + "Alert: respond to reports of a suspicious egg-shaped object; evaluate potential risks.", + "Incident reported: mysterious egg found requiring immediate attention.", + "Immediate action: address reports of an unidentified egg; assess situation.", + "Situation alert: investigation needed for mysterious egg discovery.", + "Emergency response: handle reports of an unusual egg; ensure public safety.", + "Response needed: investigate reports of a mysterious egg; assess and secure the area.", + }, + CalloutUnitsRequired = { + description = "Police, fire.", + policeRequired = true, + ambulanceRequired = false, + fireRequired = true, + towRequired = false, + }, + CalloutLocations = { + [1] = vector3(-176.0005, 7555.7231, 2.0013), + [2] = vector3(-229.1338, 7345.6353, 4.2200), + [3] = vector3(-3411.0190, 6075.2427, 2.6527), + [4] = vector3(-783.9731, 6659.8804, 2.3201), + [5] = vector3(-328.8283, 6974.1064, 2.4945), + }, + PedChanceToFleeFromPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToAttackPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToSurrender = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToObtainWeapons = 0, -- Value between 0 and 100 -> Lower is less chance. + PedActionMinimumTimeoutInMs = 0, -- Milliseconds for the minimum timeout time to start the secondary action listed above. + PedActionMaximumTimeoutInMs = 1000, -- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! + PedActionOnNoActionFound = "none", -- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" + PedWeaponData = { -- The ped will be given one randomly selected weapon (in hand) from these weapons if PedChanceToObtainWeapons passed. + "weapon_unarmed", + }, + + client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) + local eggObjects = {} + for index, objNetId in pairs(objectList) do + local obj = NetToObj(objNetId) + if DoesEntityExist(obj) then + ERS_RequestNetControlForEntity(obj) + PlaceObjectOnGroundProperly(obj) + table.insert(eggObjects, obj) + + -- Make weird shit happen, like drawing lights fading in and out in green colour + local coords = GetEntityCoords(obj) + local radius = 10.0 + local intensity = 0.0 + local fadeSpeed = 0.005 -- Lower = slower fade + local increasing = true + + Citizen.CreateThread(function() + while DoesEntityExist(obj) do + -- Draw the light with current intensity + DrawLightWithRangeAndShadow( + coords.x, + coords.y, + coords.z, + 0, -- Red + math.floor(intensity * 100), -- Green (0-100 range) + 0, -- Blue + 10.0, + 0.5, -- Light intensity + 1.0 + ) + + -- Update intensity + if increasing then + intensity = intensity + fadeSpeed + if intensity >= 1.0 then + intensity = 1.0 + increasing = false + end + else + intensity = intensity - fadeSpeed + if intensity <= 0.0 then + intensity = 0.0 + increasing = true + end + end + + Wait(0) + end + end) + end + end + + -- Make UFO fly in from high altitude, then start the abduction sequence + local ufoEntityId = nil + local ufoNetId = nil + Citizen.SetTimeout(10000, function() + local ufoModel = 'imp_prop_ship_01a' + RequestModel(ufoModel) + while not HasModelLoaded(ufoModel) do + Wait(100) + end + + -- Start position high in the sky + local startCoords = vector3(calloutDataClient.Coordinates.x + 50.0, calloutDataClient.Coordinates.y + 50.0, calloutDataClient.Coordinates.z + 150.0) + local finalCoords = vector3(calloutDataClient.Coordinates.x, calloutDataClient.Coordinates.y, calloutDataClient.Coordinates.z + 30.0) + local ufoHeading = math.random(360) + + -- Create UFO at start position + ufoEntityId = CreateObject(ufoModel, startCoords.x, startCoords.y, startCoords.z, true, true, true) + while not DoesEntityExist(ufoEntityId) do + Wait(100) + end + ufoNetId = NetworkGetNetworkIdFromEntity(ufoEntityId) + + -- Play UFO approach sound + PlaySoundFrontend(-1, "Object_Dropped_Remote", "GTAO_FM_Events_Soundset", true) + + -- UFO arrival animation + Citizen.CreateThread(function() + local arrivalDuration = 5000 -- 5 seconds for arrival + local startTime = GetGameTimer() + + -- Add a slight hovering effect + local hoverOffset = 0.0 + local hoverRate = 0.003 -- Reduced from 0.01 for slower hovering + + -- Play arrival sequence + while DoesEntityExist(ufoEntityId) do + local currentTime = GetGameTimer() + local timeElapsed = currentTime - startTime + local t = math.min(timeElapsed / arrivalDuration, 1.0) + + -- Use cubic easing for natural movement + local tSquared = t * t + local tCubed = tSquared * t + local easedT = 1.0 - math.pow(1.0 - t, 3) + + -- Calculate new position + local newX = lerp(startCoords.x, finalCoords.x, easedT) + local newY = lerp(startCoords.y, finalCoords.y, easedT) + local newZ = lerp(startCoords.z, finalCoords.z, easedT) + + -- Add hovering effect + hoverOffset = math.sin(currentTime * hoverRate) * 0.5 + + -- Set UFO position + SetEntityCoords(ufoEntityId, newX, newY, newZ + hoverOffset, false, false, false, false) + + -- Rotate the UFO slightly as it comes in + local currentHeading = GetEntityHeading(ufoEntityId) + SetEntityHeading(ufoEntityId, currentHeading + 0.2) + + -- If UFO reached final position, break the loop + if t >= 1.0 then + -- Play hovering sound when UFO is in position + --PlaySoundFrontend(-1, "Altitude_Warning", "EXILE_1", true) + PlaySoundFrontend(-1, "Object_Dropped_Remote", "GTAO_FM_Events_Soundset", true) + break + end + + Wait(0) + end + + -- After arrival, continue with the spotlights and abduction + local ufoCoords = GetEntityCoords(ufoEntityId) + local isCalloutActive = true + local isUFODeparting = false -- New flag to control hover effect + + -- Create a thread to monitor callout status + Citizen.CreateThread(function() + while true do + -- Check if callout is still active + if not isAttachedToCallout then + isCalloutActive = false + + -- Clean up UFO if it exists + if DoesEntityExist(ufoEntityId) then + DeleteEntity(ufoEntityId) + end + + -- Break the monitoring loop + break + end + Wait(1000) -- Check every second + end + end) + + Citizen.CreateThread(function() + -- Light pulsing variables + local lightIntensity = 1.0 + local pulseRate = 0.005 + local minIntensity = 0.7 + local maxIntensity = 1.3 + + -- Play spotlight activation sound + PlaySoundFrontend(-1, "Beep_Red", "DLC_HEIST_HACKING_SNAKE_SOUNDS", true) + Wait(800) + PlaySoundFrontend(-1, "CHECKPOINT_PERFECT", "HUD_MINI_GAME_SOUNDSET", true) + + while DoesEntityExist(ufoEntityId) and isCalloutActive do + local gameTime = GetGameTimer() + + -- Only apply hover if not departing + if not isUFODeparting then + -- Update hover effect with slower rate + hoverOffset = math.sin(gameTime * hoverRate) * 0.5 + SetEntityCoords(ufoEntityId, ufoCoords.x, ufoCoords.y, ufoCoords.z + hoverOffset, false, false, false, false) + end + + -- Calculate pulsing light intensity + lightIntensity = lerp(minIntensity, maxIntensity, (math.sin(gameTime * pulseRate) + 1) * 0.5) + + -- Draw spotlights only if not departing + if not isUFODeparting then + -- Draw the main red spotlight with pulsing intensity + DrawSpotLightWithShadow( + ufoCoords.x, ufoCoords.y, ufoCoords.z-3.0, + 0.0, 0.0, -1.0, + 255, 0, 0, + 100.0, lightIntensity, 0.0, 100.0, 1.0 + ) + + -- White spotlight remains consistent + DrawSpotLightWithShadow( + ufoCoords.x, ufoCoords.y, ufoCoords.z-3.0, + 0.0, 0.0, -1.0, + 255, 255, 255, + 100.0, 1.0, 0.0, 20.0, 1.0 + ) + end + Wait(0) + end + end) + + -- Create a forceful push away from eggs when player gets too close + Citizen.CreateThread(function() + while true do + local playerPed = PlayerPedId() + local playerCoords = GetEntityCoords(playerPed) + + for _, eggObject in ipairs(eggObjects) do + if DoesEntityExist(eggObject) then + local eggCoords = GetEntityCoords(eggObject) + local distance = #(playerCoords - eggCoords) + + -- Strong repulsion when very close to eggs + if distance < 8.0 then -- Reduced range for more dramatic effect + -- Calculate direction AWAY from egg + local force = (playerCoords - eggCoords) + local magnitude = #force + + if magnitude > 0 then + -- Strong push at any time + local pushStrength = 10.0 + + -- Ragdoll the player for dramatic effect + SetPedGravity(playerPed, false) + SetPedToRagdoll(playerPed, 1000, 1000, 0, 0, 0, 0) + + -- Apply strong push force away from egg + SetEntityVelocity(playerPed, + force.x/magnitude * pushStrength, + force.y/magnitude * pushStrength, + pushStrength * 0.5) -- Upward component for dramatic effect + + -- Small delay to prevent sound spam + Wait(500) + SetPedGravity(playerPed, true) + end + end + end + end + Wait(0) + end + end) + + -- Make the objects fly up into the UFO and make the UFO fly away + Citizen.CreateThread(function() + local objectsRemaining = #objectList + local lastObject = nil + local shouldFlyAway = false -- New flag to control UFO departure + + -- Handle each object in the list + for _, eggObject in ipairs(eggObjects) do + if DoesEntityExist(eggObject) and isCalloutActive then + local startCoords = GetEntityCoords(eggObject) + local endCoords = GetEntityCoords(ufoEntityId) + local duration = 5000 -- 5 seconds for each object + local startTime = GetGameTimer() + + -- Animate each object + while DoesEntityExist(ufoEntityId) and DoesEntityExist(eggObject) and isCalloutActive do + local currentTime = GetGameTimer() + local timeElapsed = currentTime - startTime + + -- Calculate easing + local t = math.min(timeElapsed / duration, 1.0) + local tSquared = t * t + local tCubed = tSquared * t + local easedT = 3 * tSquared - 2 * tCubed + + -- Calculate new position + local newX = lerp(startCoords.x, endCoords.x, easedT) + local newY = lerp(startCoords.y, endCoords.y, easedT) + local newZ = lerp(startCoords.z, endCoords.z + 1.0, easedT) + + -- Add some wobble to the movement + local wobble = math.sin(timeElapsed * 0.01) * (1.0 - easedT) * 0.3 + + -- Set new position + SetEntityCoords(eggObject, newX + wobble, newY + wobble, newZ, false, false, false, false) + + -- Add rotation + local currentRotation = GetEntityRotation(eggObject, 2) + SetEntityRotation(eggObject, + currentRotation.x + 2.0, + currentRotation.y + 2.0, + currentRotation.z + 2.0, + 2, true) + + -- Draw laser beam from UFO to object + local ufoPos = GetEntityCoords(ufoEntityId) + local objPos = GetEntityCoords(eggObject) + + -- Main laser beam + DrawLine( + ufoPos.x, ufoPos.y, ufoPos.z - 2.0, -- From bottom of UFO + objPos.x, objPos.y, objPos.z, -- To object + 0, 255, 0, -- Green color + 255 -- Alpha + ) + + -- Add some additional lines for thickness effect + DrawLine( + ufoPos.x + 0.05, ufoPos.y, ufoPos.z - 2.0, + objPos.x + 0.05, objPos.y, objPos.z, + 0, 255, 0, 180 + ) + + DrawLine( + ufoPos.x - 0.05, ufoPos.y, ufoPos.z - 2.0, + objPos.x - 0.05, objPos.y, objPos.z, + 0, 255, 0, 180 + ) + + DrawLine( + ufoPos.x, ufoPos.y + 0.05, ufoPos.z - 2.0, + objPos.x, objPos.y + 0.05, objPos.z, + 0, 255, 0, 180 + ) + + DrawLine( + ufoPos.x, ufoPos.y - 0.05, ufoPos.z - 2.0, + objPos.x, objPos.y - 0.05, objPos.z, + 0, 255, 0, 180 + ) + + -- Add pulsing effect + local pulseIntensity = math.sin(timeElapsed * 0.02) * 0.5 + 0.5 + DrawLine( + ufoPos.x, ufoPos.y, ufoPos.z - 2.0, + objPos.x, objPos.y, objPos.z, + 0, 255 * pulseIntensity, 0, + 200 + ) + + -- If object reached UFO + if t >= 1.0 then + -- Play object capture sound + PlaySoundFrontend(-1, "CHECKPOINT_UNDER_THE_BRIDGE", "HUD_MINI_GAME_SOUNDSET", true) + --print("Object reached UFO, remaining: " .. objectsRemaining) -- Debug print + + objectsRemaining = objectsRemaining - 1 + + if DoesEntityExist(eggObject) then + if objectsRemaining == 0 then + --print("Last object captured, preparing UFO departure") -- Debug print + lastObject = eggObject + SetEntityVisible(eggObject, false, false) + shouldFlyAway = true -- Set flag for UFO to fly away + else + ERS_DeleteEntityFromCallout(eggObject) + end + end + break + end + + Wait(0) + end + + -- Small delay between objects + if isCalloutActive and objectsRemaining > 0 then + Wait(500) + end + end + end + + -- In the UFO departure sequence, set isUFODeparting = true before starting: + if shouldFlyAway then + --print("Starting UFO departure sequence") -- Debug print + + -- Add a delay before departure + Wait(2000) + + -- Set departing flag to true + isUFODeparting = true + + -- Create new thread specifically for UFO departure + Citizen.CreateThread(function() + if DoesEntityExist(ufoEntityId) and isCalloutActive then + --print("UFO exists and callout is active, beginning departure") -- Debug print + + -- Play UFO departure sounds + PlaySoundFrontend(-1, "Object_Dropped_Remote", "GTAO_FM_Events_Soundset", true) + + local ufoStartCoords = GetEntityCoords(ufoEntityId) + local ufoEndCoords = vector3(ufoStartCoords.x, ufoStartCoords.y, ufoStartCoords.z + 30.0) + local ufoDuration = 8000 + local ufoStartTime = GetGameTimer() + + while DoesEntityExist(ufoEntityId) and isCalloutActive do + local currentTime = GetGameTimer() + local timeElapsed = currentTime - ufoStartTime + local t = math.min(timeElapsed / ufoDuration, 1.0) + + -- Exponential easing for UFO departure + local easedT = t * t + + -- Move UFO up + local newZ = lerp(ufoStartCoords.z, ufoEndCoords.z, easedT) + --print("Moving UFO - Height: " .. newZ) -- Debug print + + SetEntityCoords(ufoEntityId, + ufoStartCoords.x, + ufoStartCoords.y, + newZ, + false, false, false, false) + + if t >= 1.0 then + --print("UFO reached max height, cleaning up") -- Debug print + TriggerServerEvent("ns_easter_egg:DeleteUFO", ufoNetId) + + -- Small delay before ending callout + Wait(1000) + + if lastObject and DoesEntityExist(lastObject) then + ERS_DeleteEntityFromCallout(lastObject) + end + break + end + + Wait(0) + end + end + end) + else + --print("shouldFlyAway flag not set, UFO departure sequence skipped") -- Debug print + end + end) + end) + end) + + ERS_CreateTemporaryBlipForEntities(objectList, 30000) + end, + server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) + local diameter = 10 + -- Build objects + local alienEggObjects = {"prop_alien_egg_01"} + local randomAmountOfObjects = math.random(1, 12) + for i = 1, randomAmountOfObjects do + local coords = ERS_GetRandomCoordinateWithinRangeOfCoordinate(calloutData.Coordinates, diameter) + local objModel = ERS_GetRandomModel(alienEggObjects) + local objCoords = vector3(coords.x, coords.y, coords.z+2.0) + local objHeading = math.random(360) + local objNetId = ERS_CreateObject(objModel, objCoords, objHeading) + if objNetId then + local obj = NetworkGetEntityFromNetworkId(objNetId) + table.insert(objectList, objNetId) + else + DebugPrint("^1ERROR ^7Could not create object: "..objModel) + end + end + + -- Create smoke (Optionally) + -- -- Build a small sized fire + -- if UsingSmartFires then + -- -- Full version + -- -- Build smoke + -- local smokeSize = Config.RandomMediumFireOrSmokeSize[math.random(#Config.RandomMediumFireOrSmokeSize)] + -- local smokeType = "foggy" + -- local smokeId = exports['SmartFires']:CreateSmoke(vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z-0.5), smokeSize, smokeType) + -- DebugPrint("Created smoke with ID: "..smokeId) + -- table.insert(smokeList, smokeId) + -- else + -- -- Lite version + -- -- Build smoke + -- local smokeSize = Config.RandomMediumFireOrSmokeSize[math.random(#Config.RandomMediumFireOrSmokeSize)] + -- local smokeType = "normal" + -- local smokeId = exports['SmartFiresLite']:CreateSmoke(vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z-0.5), smokeSize, smokeType) + -- DebugPrint("Created smoke with ID: "..smokeId) + -- table.insert(smokeList, smokeId) + -- end + + + RegisterServerEvent("ns_easter_egg:DeleteUFO") + AddEventHandler("ns_easter_egg:DeleteUFO", function(objNetId) + local obj = NetworkGetEntityFromNetworkId(objNetId) + if DoesEntityExist(obj) then + DeleteEntity(obj) + end + end) + + return true + end +} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_race_crash.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_race_crash.lua new file mode 100644 index 000000000..4600743da --- /dev/null +++ b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_race_crash.lua @@ -0,0 +1,272 @@ + +Config.Callouts["roxwood_race_crash"] = { + Enabled = false, + CalloutName = "Roxwood GP Race Crash", + CalloutDescriptions = { + "Reported road traffic collision, further details needed", + "Collision involving vehicles, assess scene for safety", + "Incident on road reported, extent of damage unclear", + "Traffic incident with unknown injuries, approach carefully", + "Vehicle collision reported, assistance required", + "Accident scene identified, evaluate for emergency response", + "Collision on roadway, prioritize safety and assistance", + "Traffic incident reported, coordinate response accordingly", + "Roadway blocked due to collision, assess for hazards", + "Vehicle collision with unspecified injuries, response needed", + -- Add more if you like. + }, + CalloutUnitsRequired = { + description = "Police, ambulance, fire, tow.", + policeRequired = true, + ambulanceRequired = true, + fireRequired = true, + towRequired = true, + }, + CalloutLocations = { + [1] = vector3(-2878.8276, 8350.8096, 37.0427), + [2] = vector3(-3003.3206, 8421.5879, 37.0592), + [3] = vector3(-3262.5945, 8667.0674, 37.1207), + [4] = vector3(-3020.7278, 8711.4346, 46.1127), + [5] = vector3(-2703.4087, 8518.3428, 44.1534), + [6] = vector3(-2239.3889, 8563.3916, 47.5178), + [7] = vector3(-2343.6777, 8891.8887, 51.0247), + [8] = vector3(-2524.2251, 8750.5879, 45.5379), + [9] = vector3(-2624.4514, 8621.4854, 47.0158), + [10] = vector3(-2576.6099, 8060.3647, 46.6511), + [11] = vector3(-3196.3193, 8153.2676, 47.0967), + }, + PedChanceToFleeFromPlayer = 0, -- Value between 0 and 100 -> 0 is no chance. The lower the less chance. + PedChanceToAttackPlayer = 0, -- Value between 0 and 100 -> 0 is no chance. The lower the less chance. + PedChanceToSurrender = 0, -- Value between 0 and 100 -> 0 is no chance. The lower the less chance. + PedChanceToObtainWeapons = 0, -- Value between 0 and 100 -> 0 is no chance. The lower the less chance. + PedActionMinimumTimeoutInMs = 0, -- Milliseconds for the minimum timeout time to start the secondary action listed above. + PedActionMaximumTimeoutInMs = 1000, -- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! + PedActionOnNoActionFound = "none", -- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" + PedWeaponData = { -- The ped will be given one randomly selected weapon (in hand) from these weapons if PedChanceToObtainWeapons passed. + "weapon_unarmed", -- Basically none. + }, + client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) + for index, vehNetId in pairs(vehicleList) do + local veh = NetToVeh(vehNetId) + if DoesEntityExist(veh) then + ERS_RequestNetControlForEntity(veh) + ERS_SetRandomDamageToVehicle(veh) + end + end + + for index, pedNetId in pairs(pedList) do + local ped = NetToPed(pedNetId) + if DoesEntityExist(ped) then + + ERS_RequestNetControlForEntity(ped) + + local pedCoords = GetEntityCoords(ped) + local chanceToSurvive = math.random(0, 1) + + ERS_SetMovementAnimClipSetToPed(ped, "move_m@injured") + + if chanceToSurvive < 1 then + -- Dead + SetEntityHealth(ped, 0) + TaskSetBlockingOfNonTemporaryEvents(ped, true) + ERS_ApplyBloodToPed(ped) + SetPedKeepTask(ped, true) + else + -- Alive + TaskSetBlockingOfNonTemporaryEvents(ped, true) + ERS_SpawnConfiguredWeaponForPed(ped, calloutDataClient) + if IsPedInAnyVehicle(ped, false) then + TaskLeaveAnyVehicle(ped) + Wait(500) + end + TaskSetBlockingOfNonTemporaryEvents(ped, true) + SetPedKeepTask(ped, true) + + ERS_ApplyBloodToPed(ped) + + pedCoords = GetEntityCoords(ped) + local bool, safeCoords = GetSafeCoordForPed(pedCoords.x, pedCoords.y, pedCoords.z, true, 16) + if bool then + if Config.Debug then + print("Found safe coord for ped: "..safeCoords) + end + local xOffset= math.random(-2, 2) + local yOffset= math.random(-2, 2) + + if Config.Debug then + print("Could not find safe coord for ped: "..safeCoords) + end + end + + Citizen.SetTimeout(10000, function() + if DoesEntityExist(ped) then + if not IsPedDeadOrDying(ped, true) then + ERS_RequestNetControlForEntity(ped) + + TaskSetBlockingOfNonTemporaryEvents(ped, true) + + local scenario = ERS_SelectRandomWoundedPersonScenario() + TaskStartScenarioInPlace(ped, scenario, 0, true) + + ERS_PerformTimedActionOnPed(calloutDataClient, pedList) + + if Config.Debug then + print("Blocking off non-temp events for ped at safe coords for ped: "..ped) + end + end + end + end) + end + end + end + + for index, objNetId in pairs(objectList) do + local obj = NetToObj(objNetId) + if DoesEntityExist(obj) then + ERS_RequestNetControlForEntity(obj) + PlaceObjectOnGroundProperly(obj) + end + end + + ERS_CreateTemporaryBlipForEntities(vehicleList, 15000) + ERS_CreateTemporaryBlipForEntities(pedList, 15000) + end, + server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) + local randomAmountOfVehicles = math.random(2,5) + local randomAmountOfObjects = math.random(1,5) + local randomAmountOfFires = math.random(1,3) + local racePedModels = { + "ig_trafficwarden", "player_zero", "ig_agatha", + "hc_driver", "hc_gunman", "hc_hacker", "ig_abigail", "ig_agent", + "ig_amandatownley", "ig_andreas", "ig_ashley", "ig_avon", "ig_ballasog", + "ig_bankman", "ig_barry", "ig_benny", "ig_bestmen", "ig_beverly", + "ig_brad", "ig_bride", "ig_car3guy1", "ig_car3guy2", "ig_casey", + "ig_chef", "ig_chef2", "ig_chengsr", "ig_chrisformage", "ig_clay", + "ig_claypain", "ig_cletus", "ig_dale", "ig_davenorton", "ig_denise", + "ig_devin", "ig_dix", "ig_djblamadon", "ig_djblamrupert", "ig_djblamryans", + "ig_djdixmanager", "ig_djgeneric_01", "ig_djsolfotios", "ig_djsoljakob", + "ig_djsolmanager", "ig_djsolmike", "ig_djsolrobt", "ig_djtalaurelia", + "ig_djtalignazio", "ig_dom", "ig_dreyfuss", "ig_drfriedlander", + "ig_englishdave", "ig_fabien", "ig_fbisuit_01", "ig_floyd", "ig_g", + "ig_groom", "ig_hao", "ig_hunter", "ig_janet", "ig_jay_norris", + "ig_jewelass", "ig_jimmyboston", "ig_jimmyboston_02", "ig_jimmydisanto", + "ig_joeminuteman", "ig_johnnyklebitz", "ig_josef", "ig_josh", + "ig_karen_daniels", "ig_kerrymcintosh", "ig_kerrymcintosh_02", + "ig_lacey_jones_02", "ig_lamardavis", "ig_lazlow", "ig_lazlow_2", + "ig_lestercrest", "ig_lestercrest_2", "ig_lifeinvad_01", "ig_lifeinvad_02", + "ig_magenta", "ig_malc", "ig_manuel", "ig_marnie", "ig_maryann", + "ig_maude", "ig_michelle", "ig_milton", "ig_molly", "ig_money", + "ig_mp_agent14", "ig_mrk", "ig_mrs_thornhill", "ig_mrsphillips", + "ig_natalia", "ig_nervousron", "ig_nigel", "ig_old_man1a", "ig_old_man2", + "ig_omega", "ig_oneil", "ig_orleans", "ig_ortega", "ig_paige", "ig_paper", + "ig_patricia", "ig_popov", "ig_priest", "ig_prolsec_02", "ig_ramp_gang", + "ig_ramp_hic", "ig_ramp_hipster", "ig_ramp_mex", "ig_rashcosvki", + "ig_roccopelosi", "ig_russiandrunk", "ig_sacha", "ig_screen_writer", + "ig_siemonyetarian", "ig_sol", "ig_solomon", "ig_stevehains", "ig_stretch", + "ig_talcc", "ig_talina", "ig_talmm", "ig_tanisha", "ig_taocheng", + "ig_taostranslator", "ig_tenniscoach", "ig_terry", "ig_tomepsilon", + "ig_tonya", "ig_tonyprince", "ig_tracydisanto", "ig_trafficwarden", + "ig_tylerdix", "ig_tylerdix_02", "ig_vagspeak", "ig_wade", "ig_zimbor", + "player_one", "player_two", "player_zero", "ig_agatha", "ig_avery", + "ig_brucie2", "ig_thornton", "ig_tomcasino", "ig_vincent" + } + local vehRaceModels = {"formula", "formula2", "openwheel1", "openwheel2"} + local carPartObjects = {"prop_car_battery_01", "prop_car_exhaust_01", "prop_rub_carpart_04", "prop_rub_carpart_05", "prop_car_engine_01"} + local diameter = 20 + + -- Car race or motorbike race chance + local carRaceChance = math.random(0, 1) + local vehType = "automobile" + if carRaceChance == 0 then + -- motorbike race + vehRaceModels = {"bati2"} + vehType = "bike" + end + + -- Build entities + for i = 1, randomAmountOfVehicles do + local coords = ERS_GetRandomCoordinateWithinRangeOfCoordinate(calloutData.Coordinates, diameter) + + -- Build vehicle + local vehModel = ERS_GetRandomModel(vehRaceModels) + local vehCoords = vector3(coords.x, coords.y, coords.z) + local vehHeading = math.random(360) + local vehNetId = ERS_CreateVehicle(vehModel, vehType, vehCoords, vehHeading) + local vehicle = NetworkGetEntityFromNetworkId(vehNetId) + table.insert(vehicleList, vehNetId) + + -- Build ped + coords = ERS_GetRandomCoordinateWithinRangeOfCoordinate(calloutData.Coordinates, diameter) + + local pedModel = ERS_GetRandomModel(racePedModels) + local pedCoords = vector3(coords.x, coords.y, coords.z) + local pedHeading = math.random(360) + local pedNetId = ERS_CreatePed(pedModel, pedCoords, pedHeading) + local ped = NetworkGetEntityFromNetworkId(pedNetId) + SetPedIntoVehicle(ped, vehicle, -1) + table.insert(pedList, pedNetId) + + -- Break vehicle + SetVehicleBodyHealth(vehicle, (math.random(1000) + 0.0)) + for i = 0, 5 do + local broken = math.random(0, 1) + if broken == 1 then + SetVehicleDoorBroken(vehicle, i, false) + end + SetVehicleDirtLevel(vehicle, math.random(15) + 0.0) + end + end + + -- Build objects + for i = 1, randomAmountOfObjects do + local coords = ERS_GetRandomCoordinateWithinRangeOfCoordinate(calloutData.Coordinates, diameter) + + local objModel = ERS_GetRandomModel(carPartObjects) + local objCoords = vector3(coords.x, coords.y, coords.z) + local objHeading = math.random(360) + local objNetId = ERS_CreateObject(objModel, objCoords, objHeading) + if objNetId then + local obj = NetworkGetEntityFromNetworkId(objNetId) + table.insert(objectList, objNetId) + else + DebugPrint("^1ERROR ^7Could not create object: "..objModel) + end + end + + for i = 1, randomAmountOfFires do + local coords = ERS_GetRandomCoordinateWithinRangeOfCoordinate(calloutData.Coordinates, diameter) + if UsingSmartFires then + -- Full version + local fireSize = Config.RandomLargeFireOrSmokeSize[math.random(#Config.RandomLargeFireOrSmokeSize)] + local fireType = Config.NormalFireTypes[math.random(#Config.NormalFireTypes)] + local fireId = exports['SmartFires']:CreateFire(vector3(coords.x, coords.y, coords.z+0.6), fireSize, fireType) + DebugPrint("Created fire with ID: "..fireId) + table.insert(fireList, fireId) + + local smokeSize = Config.RandomMediumFireOrSmokeSize[math.random(#Config.RandomMediumFireOrSmokeSize)] + local smokeType = Config.AllSmokeTypes[math.random(#Config.AllSmokeTypes)] + local smokeId = exports['SmartFires']:CreateSmoke(vector3(coords.x, coords.y, coords.z-0.5), smokeSize, smokeType) + DebugPrint("Created smoke particle with ID: "..smokeId) + table.insert(smokeList, smokeId) + else + local chanceToCreateSmoke = math.random(0, 1) -- 50% chance to create smoke + if chanceToCreateSmoke == 1 then + -- Lite version + local fireSize = Config.RandomLargeFireOrSmokeSize[math.random(#Config.RandomLargeFireOrSmokeSize)] + local fireType = "normal" + local fireId = exports['SmartFiresLite']:CreateFire(vector3(coords.x, coords.y, coords.z+0.6), fireSize, fireType) + DebugPrint("Created fire with SmartFiresLite with ID: "..fireId) + table.insert(fireList, fireId) + + local smokeSize = Config.RandomMediumFireOrSmokeSize[math.random(#Config.RandomMediumFireOrSmokeSize)] + local smokeType = "normal" + local smokeId = exports['SmartFiresLite']:CreateSmoke(vector3(coords.x, coords.y, coords.z-0.5), smokeSize, smokeType) + DebugPrint("Created smoke particle with ID: "..smokeId) + table.insert(smokeList, smokeId) + end + end + end + + return true + end +} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_racecar_theft.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_racecar_theft.lua new file mode 100644 index 000000000..ea46f7324 --- /dev/null +++ b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_racecar_theft.lua @@ -0,0 +1,98 @@ +Config.Callouts["roxwood_racecar_theft"] = { + Enabled = false, + CalloutName = "Theft of a Racecar", + CalloutDescriptions = { + "High-performance racecar reported stolen from local track, immediate response required", + "Professional racing vehicle theft in progress, suspect may be armed and dangerous", + "Modified racing vehicle stolen during event preparations, high-value target", + "Competition racecar reported missing from secured garage area", + "Emergency: High-speed capable vehicle theft from racing complex", + "Urgent: Racing team reports theft of competition vehicle, suspect fleeing area", + "Track security reports unauthorized removal of professional racing vehicle", + "High-priority: Racing prototype stolen, vehicle extremely valuable", + "Alert: Competition vehicle theft from pit area, immediate response needed", + "Racing team reports forced entry and theft of performance vehicle", + }, + CalloutUnitsRequired = { + description = "Police.", + policeRequired = true, + ambulanceRequired = false, + fireRequired = false, + towRequired = false, + }, + CalloutLocations = { + [1] = vector3(-2901.6108, 8056.7153, 44.8517), + [2] = vector3(-2737.1699, 8028.4966, 49.4163), + [3] = vector3(-2969.1304, 7983.6553, 44.8298), + }, + PedChanceToFleeFromPlayer = 90, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToAttackPlayer = 10, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToSurrender = 10, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToObtainWeapons = 25, -- Value between 0 and 100 -> Lower is less chance. + PedActionMinimumTimeoutInMs = 0, -- Milliseconds for the minimum timeout time to start the secondary action listed above. + PedActionMaximumTimeoutInMs = 2000, -- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! + PedActionOnNoActionFound = "flee", -- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" + PedWeaponData = { -- The ped will be given one randomly selected weapon (in hand) from these weapons if PedChanceToObtainWeapons passed. + "weapon_knife", + "weapon_pistol", + }, + client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) + local vehicle = nil + local driver = nil + + for index, vehNetId in pairs(vehicleList) do + local veh = NetToVeh(vehNetId) + if DoesEntityExist(veh) then + vehicle = veh + ERS_RequestNetControlForEntity(vehicle) + end + end + + for index, pedNetId in pairs(pedList) do + local ped = NetToPed(pedNetId) + if DoesEntityExist(ped) then + driver = ped + ERS_RequestNetControlForEntity(driver) + if not IsPedOnAnyBike(driver) then + SmashVehicleWindow(vehicle, 0) -- break driver window + end + if not IsPedInAnyVehicle(driver, true) then + TaskEnterVehicle(driver, vehicle, 5000, -1, 2.0, 1, 0) + Wait(5000) + ERS_SetPedToFleeFromPlayer(driver) + else + ERS_SetPedToFleeFromPlayer(driver) + end + end + end + + ERS_CreateTemporaryBlipForEntities(vehicleList, 15000) + ERS_CreateTemporaryBlipForEntities(pedList, 15000) + + ERS_PerformTimedActionOnPed(calloutDataClient, pedList) + end, + server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) + -- Build vehicle + local vehRaceModels = {"formula", "formula2", "openwheel1", "openwheel2"} + local vehModel = ERS_GetRandomModel(vehRaceModels) + local vehType = "automobile" + local vehCoords = vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z) + local vehHeading = math.random(360) + local vehNetId = ERS_CreateVehicle(vehModel, vehType, vehCoords, vehHeading) + local vehicle = NetworkGetEntityFromNetworkId(vehNetId) + table.insert(vehicleList, vehNetId) + + -- Build ped + local pedModel = ERS_GetRandomModel(Config.randomPeds) + local pedCoords = vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z +1.0) + local pedHeading = math.random(360) + local pedNetId = ERS_CreatePed(pedModel, pedCoords, pedHeading) + local ped = NetworkGetEntityFromNetworkId(pedNetId) + SetPedIntoVehicle(ped, vehicle, -1) + table.insert(pedList, pedNetId) + + calloutBuilt = true + + return true + end +} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_reports_of_a_fire.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_reports_of_a_fire.lua new file mode 100644 index 000000000..e38f8f59a --- /dev/null +++ b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_reports_of_a_fire.lua @@ -0,0 +1,135 @@ +Config.Callouts["roxwood_reports_of_a_fire"] = { + + Enabled = true, + CalloutName = "Reports of a Fire", + CalloutDescriptions = { + "A fire has been reported, requiring immediate attention from fire services.", + "Emergency services are needed to extinguish a reported fire.", + "Reports indicate a fire has broken out, necessitating urgent firefighting intervention.", + "A fire has been identified, and additional fire personnel are needed for containment and extinguishment.", + "Emergency services have been requested to respond to a fire.", + "A request for assistance has been made by authorities dealing with a fire.", + "Additional units are required to support fire personnel managing a fire.", + "Emergency backup is required to assist fire authorities in handling a fire.", + "A call for assistance has been issued by responders dealing with a fire.", + "Reports suggest a situation where immediate firefighting intervention is crucial to manage and address a fire.", + }, + CalloutUnitsRequired = { + description = "Fire", + policeRequired = false, + ambulanceRequired = false, + fireRequired = true, + towRequired = false, + }, + CalloutLocations = { + [1] = vector3(-2542.1089, 7467.2939, 40.1682), + [2] = vector3(-2070.9167, 7103.6870, 28.5290), + [3] = vector3(-2680.5420, 6456.3721, 28.7906), + [4] = vector3(-2660.3013, 6341.2979, 20.9317), + [5] = vector3(-2920.7075, 6240.0674, 12.7980), + [6] = vector3(-2785.6145, 6105.6709, 7.2804), + [7] = vector3(-2989.0220, 6141.8804, 4.8758), + [8] = vector3(-3029.2122, 6094.7715, 16.5621), + [9] = vector3(-3289.9795, 6187.9121, 13.7178), + [10] = vector3(-3068.1689, 7862.0122, 59.1986), + [11] = vector3(-2314.8447, 7807.0688, 38.4255), + [12] = vector3(-2306.9417, 7822.5352, 44.2124), + [13] = vector3(-2163.0261, 7998.2568, 44.3750), + [14] = vector3(-2207.9578, 8031.9858, 44.2027), + [15] = vector3(-2274.9910, 8146.1890, 34.1373), + [16] = vector3(-1290.7288, 8218.0352, 12.9399), + [17] = vector3(-606.0902, 7564.0142, 11.6405), + [18] = vector3(-833.0021, 7150.1865, 104.5681), + [19] = vector3(-380.6089, 7202.0557, 18.2214), + [20] = vector3(-455.5331, 7737.0986, 6.2801), + [21] = vector3(193.0212, 7768.1797, 6.4081), + }, + PedChanceToFleeFromPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToAttackPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToSurrender = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToObtainWeapons = 0, -- Value between 0 and 100 -> Lower is less chance. + PedActionMinimumTimeoutInMs = 0, -- Milliseconds for the minimum timeout time to start the secondary action listed above. + PedActionMaximumTimeoutInMs = 1000, -- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! + PedActionOnNoActionFound = "none", -- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" + PedWeaponData = { -- The ped will be given one randomly selected weapon (in hand) from these weapons if PedChanceToObtainWeapons passed. + "weapon_unarmed", + }, + + client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) + + for index, pedNetId in pairs(pedList) do + local ped = NetToPed(pedNetId) + if DoesEntityExist(ped) then + ERS_RequestNetControlForEntity(ped) + TaskSetBlockingOfNonTemporaryEvents(ped, true) + PlayPain(ped, 8, 200) + ERS_ApplyBloodToPed(ped) + Wait(2500) + SetEntityHealth(ped, 0) + + end + end + + ERS_CreateTemporaryBlipForEntities(pedList, 15000) + + ERS_PerformTimedActionOnPed(calloutDataClient, pedList) + + end, + server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) + + local diameter = 2 + local coords = ERS_GetRandomCoordinateWithinRangeOfCoordinate(calloutData.Coordinates, diameter) + + -- Build a small sized fire + if UsingSmartFires then + -- Full version + local fireSize = Config.RandomMediumFireOrSmokeSize[math.random(#Config.RandomMediumFireOrSmokeSize)] + local fireType = Config.NormalFireTypes[math.random(#Config.NormalFireTypes)] + local fireId = exports['SmartFires']:CreateFire(vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z-0.5), fireSize, fireType) + DebugPrint("Created fire with ID: "..fireId) + table.insert(fireList, fireId) + + -- Build smoke + local chanceOnASmoke = 50 + if math.random(1, 100) <= chanceOnASmoke then + local smokeSize = Config.RandomMediumFireOrSmokeSize[math.random(#Config.RandomMediumFireOrSmokeSize)] + local smokeType = Config.AllSmokeTypes[math.random(#Config.AllSmokeTypes)] + local smokeId = exports['SmartFires']:CreateSmoke(vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z-0.5), smokeSize, smokeType) + + DebugPrint("Created smoke with ID: "..smokeId) + table.insert(smokeList, smokeId) + end + else + -- Lite version + local fireSize = Config.RandomSmallFireOrSmokeSize[math.random(#Config.RandomSmallFireOrSmokeSize)] + local fireType = "normal" + local fireId = exports['SmartFiresLite']:CreateFire(vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z-0.5), fireSize, fireType) + DebugPrint("Created fire with SmartFiresLite with ID: "..fireId) + table.insert(fireList, fireId) + + -- Build smoke + local chanceOnASmoke = 50 + if math.random(1, 100) <= chanceOnASmoke then + local smokeSize = Config.RandomMediumFireOrSmokeSize[math.random(#Config.RandomMediumFireOrSmokeSize)] + local smokeType = "normal" + local smokeId = exports['SmartFiresLite']:CreateSmoke(vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z-0.5), smokeSize, smokeType) + + DebugPrint("Created smoke with ID: "..smokeId) + table.insert(smokeList, smokeId) + end + end + + local chanceOnAVictim = 50 + if math.random(1, 100) <= chanceOnAVictim then + -- Build victim + local pedModel = ERS_GetRandomModel(Config.randomPeds) + local pedCoords = vector3(coords.x, coords.y, coords.z) + local pedHeading = math.random(360) + local pedNetId = ERS_CreatePed(pedModel, pedCoords, pedHeading) + local ped = NetworkGetEntityFromNetworkId(pedNetId) + table.insert(pedList, pedNetId) + end + + return true + end +} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_reports_of_theft.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_reports_of_theft.lua new file mode 100644 index 000000000..9065688d7 --- /dev/null +++ b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_reports_of_theft.lua @@ -0,0 +1,110 @@ +Config.Callouts["roxwood_reports_of_theft"] = { + Enabled = false, + CalloutName = "Reports of Theft", + CalloutDescriptions = { + "Reports of theft, details pending", + "Suspected theft reported, further information needed", + "Incident involving stolen vehicle, assess situation for safety", + "Theft reported, prioritize response for recovery", + "Reported theft of motor vehicle, investigate promptly", + "Vehicle reported missing, coordinate search and recovery efforts", + "Stolen reported, assess potential risks", + "Suspected theft of vehicle, approach investigation with caution", + "Reports of theft, prioritize response for recovery", + "Theft incident reported, coordinate with authorities", + }, + CalloutUnitsRequired = { + description = "Police.", + policeRequired = true, + ambulanceRequired = false, + fireRequired = false, + towRequired = false, + }, + CalloutLocations = { + [1] = vector3(-906.1519, 6810.3047, 21.3176), + [2] = vector3(-641.7461, 6866.0830, 24.2095), + [3] = vector3(-629.4213, 6988.1577, 24.3153), + [4] = vector3(-540.8360, 6718.5483, 21.2485), + [5] = vector3(-263.4102, 7058.8438, 12.0184), + [6] = vector3(-302.9133, 7167.9888, 6.3294), + [7] = vector3(-289.1859, 7225.0986, 6.3294), + [8] = vector3(-216.6804, 7675.9102, 6.3277), + [9] = vector3(-1288.2164, 8249.0859, 12.0572), + [10] = vector3(-2238.5459, 8170.4370, 33.1580), + [11] = vector3(-2554.0913, 7474.7725, 28.6994), + [12] = vector3(-3058.3174, 7338.7568, 44.0336), + [13] = vector3(-3067.8191, 6315.9731, 8.8898), + [14] = vector3(-2989.0806, 6175.4121, 8.4440), + [15] = vector3(-3684.9780, 6187.1943, 24.5932), + [16] = vector3(-3096.2888, 6538.0146, 23.5485), + }, + PedChanceToFleeFromPlayer = 90, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToAttackPlayer = 10, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToSurrender = 10, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToObtainWeapons = 25, -- Value between 0 and 100 -> Lower is less chance. + PedActionMinimumTimeoutInMs = 0, -- Milliseconds for the minimum timeout time to start the secondary action listed above. + PedActionMaximumTimeoutInMs = 2000, -- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! + PedActionOnNoActionFound = "flee", -- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" + PedWeaponData = { -- The ped will be given one randomly selected weapon (in hand) from these weapons if PedChanceToObtainWeapons passed. + "weapon_knife", + "weapon_pistol", + }, + client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) + local vehicle = nil + local driver = nil + + for index, vehNetId in pairs(vehicleList) do + local veh = NetToVeh(vehNetId) + if DoesEntityExist(veh) then + vehicle = veh + ERS_RequestNetControlForEntity(vehicle) + end + end + + for index, pedNetId in pairs(pedList) do + local ped = NetToPed(pedNetId) + if DoesEntityExist(ped) then + driver = ped + ERS_RequestNetControlForEntity(driver) + if not IsPedOnAnyBike(driver) then + SmashVehicleWindow(vehicle, 0) -- break driver window + end + if not IsPedInAnyVehicle(driver, true) then + TaskEnterVehicle(driver, vehicle, 5000, -1, 2.0, 1, 0) + Wait(5000) + ERS_SetPedToFleeFromPlayer(driver) + else + ERS_SetPedToFleeFromPlayer(driver) + end + end + end + + ERS_CreateTemporaryBlipForEntities(vehicleList, 15000) + ERS_CreateTemporaryBlipForEntities(pedList, 15000) + + ERS_PerformTimedActionOnPed(calloutDataClient, pedList) + end, + server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) + -- Build vehicle + local vehModel = ERS_GetRandomModel(Config.randomVehicles) + local vehType = "automobile" + local vehCoords = vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z) + local vehHeading = math.random(360) + local vehNetId = ERS_CreateVehicle(vehModel, vehType, vehCoords, vehHeading) + local vehicle = NetworkGetEntityFromNetworkId(vehNetId) + table.insert(vehicleList, vehNetId) + + -- Build ped + local pedModel = ERS_GetRandomModel(Config.randomPeds) + local pedCoords = vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z +1.0) + local pedHeading = math.random(360) + local pedNetId = ERS_CreatePed(pedModel, pedCoords, pedHeading) + local ped = NetworkGetEntityFromNetworkId(pedNetId) + SetPedIntoVehicle(ped, vehicle, -1) + table.insert(pedList, pedNetId) + + calloutBuilt = true + + return true + end +} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_rubbish_washed_up_from_sea.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_rubbish_washed_up_from_sea.lua new file mode 100644 index 000000000..46f8911a4 --- /dev/null +++ b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_rubbish_washed_up_from_sea.lua @@ -0,0 +1,72 @@ +Config.Callouts["roxwood_rubbish_washed_up_from_sea"] = { + + Enabled = true, + CalloutName = "Rubbish washed up from the sea", + CalloutDescriptions = { + "Emergency: respond to reports of debris washed up on the shoreline; assess environmental hazards.", + "Urgent alert: marine debris reported on the beach requiring immediate cleanup response.", + "Critical response required: investigate reports of sea waste washing up on the coast.", + "Notice: significant amount of marine debris has washed ashore; environmental assessment needed.", + "Alert: respond to reports of ocean waste on the beach; evaluate potential hazards.", + "Incident reported: sea debris has washed up on the shoreline requiring immediate attention.", + "Immediate action: address reports of marine waste on the beach; assess environmental impact.", + "Situation alert: coastal cleanup needed for debris washed up from the ocean.", + "Emergency response: handle reports of sea waste on the shoreline; ensure public safety.", + "Response needed: investigate reports of marine debris washed ashore; assess and coordinate cleanup.", + }, + CalloutUnitsRequired = { + description = "Police, fire.", + policeRequired = true, + ambulanceRequired = false, + fireRequired = true, + towRequired = false, + }, + CalloutLocations = { + [1] = vector3(-176.0005, 7555.7231, 2.0013), + [2] = vector3(-229.1338, 7345.6353, 4.2200), + [3] = vector3(-3411.0190, 6075.2427, 2.6527), + [4] = vector3(-783.9731, 6659.8804, 2.3201), + [5] = vector3(-328.8283, 6974.1064, 2.4945), + }, + PedChanceToFleeFromPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToAttackPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToSurrender = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToObtainWeapons = 0, -- Value between 0 and 100 -> Lower is less chance. + PedActionMinimumTimeoutInMs = 0, -- Milliseconds for the minimum timeout time to start the secondary action listed above. + PedActionMaximumTimeoutInMs = 1000, -- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! + PedActionOnNoActionFound = "none", -- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" + PedWeaponData = { -- The ped will be given one randomly selected weapon (in hand) from these weapons if PedChanceToObtainWeapons passed. + "weapon_unarmed", + }, + + client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) + for index, objNetId in pairs(objectList) do + local obj = NetToObj(objNetId) + if DoesEntityExist(obj) then + ERS_RequestNetControlForEntity(obj) + PlaceObjectOnGroundProperly(obj) + end + end + ERS_CreateTemporaryBlipForEntities(objectList, 30000) + end, + server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) + local diameter = 10 + -- Build objects + local rubbishObjects = {"prop_rub_buswreck_01", "prop_rub_carwreck_10", "prop_rub_carwreck_13", "prop_rub_pile_01", "prop_pile_dirt_04", "prop_pile_dirt_02", "prop_rub_buswreck_03", "prop_wrecked_buzzard"} + local randomAmountOfObjects = math.random(1, 6) + for i = 1, randomAmountOfObjects do + local coords = ERS_GetRandomCoordinateWithinRangeOfCoordinate(calloutData.Coordinates, diameter) + local objModel = ERS_GetRandomModel(rubbishObjects) + local objCoords = vector3(coords.x, coords.y, coords.z+2.0) + local objHeading = math.random(360) + local objNetId = ERS_CreateObject(objModel, objCoords, objHeading) + if objNetId then + local obj = NetworkGetEntityFromNetworkId(objNetId) + table.insert(objectList, objNetId) + else + DebugPrint("^1ERROR ^7Could not create object: "..objModel) + end + end + return true + end +} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_shootout.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_shootout.lua new file mode 100644 index 000000000..c6ae1476a --- /dev/null +++ b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_shootout.lua @@ -0,0 +1,146 @@ +Config.Callouts["roxwood_shootout"] = { + Enabled = true, + CalloutName = "Roxwood Shootout", + CalloutDescriptions = { + "A violent shootout has erupted between two rival groups in Roxwood.", + "Reports of gunfire exchanged between two factions, immediate response required.", + "A shootout is underway in Roxwood, with multiple armed individuals involved.", + "Two rival gangs are engaged in a firefight, posing a threat to public safety.", + "Gunfire reported in Roxwood as two groups clash violently.", + "Emergency services needed to contain a shootout between two armed groups.", + "A dangerous shootout is occurring, requiring swift intervention from authorities.", + "Two factions are exchanging gunfire, escalating tensions in the area.", + "A shootout has broken out, with both sides heavily armed.", + "Immediate action required to control a shootout between rival groups.", + }, + CalloutUnitsRequired = { + description = "Police.", + policeRequired = true, + ambulanceRequired = false, + fireRequired = false, + towRequired = false, + }, + CalloutLocations = { + [1] = vector3(-829.9780, 7158.2388, 99.7499), + [2] = vector3(-455.7968, 7240.3081, 17.5236), + [3] = vector3(-357.8293, 7197.4155, 6.3290), + [4] = vector3(-362.7209, 7389.6875, 6.4129), + [5] = vector3(-537.7283, 7538.1699, 6.7560), + }, + PedChanceToFleeFromPlayer = 0, -- Lower chance to flee during a shootout. + PedChanceToAttackPlayer = 100, -- High chance to attack during a shootout. + PedChanceToSurrender = 0, -- No surrender during a shootout. + PedChanceToObtainWeapons = 100, -- Ensure all peds are armed. + PedActionMinimumTimeoutInMs = 0, -- Milliseconds for the minimum timeout time to start the secondary action listed above. + PedActionMaximumTimeoutInMs = 1000, -- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! + PedActionOnNoActionFound = "attack", -- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" + PedWeaponData = { -- Weapons for the shootout. + "weapon_pistol", + "weapon_smg", + "weapon_assaultrifle", + }, + + client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) + local team1 = {} + local team2 = {} + + for index, pedNetId in pairs(pedList) do + local ped = NetToPed(pedNetId) + if DoesEntityExist(ped) then + ERS_RequestNetControlForEntity(ped) + local model = GetEntityModel(ped) + + -- Randomly assign peds to one of the two teams + if #team1 < 8 and (math.random(2) == 1 or #team2 >= 8) then + table.insert(team1, ped) + else + table.insert(team2, ped) + end + + TaskSetBlockingOfNonTemporaryEvents(ped, true) + Wait(100) + ERS_SpawnConfiguredWeaponForPed(ped, calloutDataClient) + end + end + + -- Function to make peds flee for this case + local function makePedsFlee(peds) + for _, ped in pairs(peds) do + if DoesEntityExist(ped) and not IsPedDeadOrDying(ped, true) then + TaskSmartFleePed(ped, plyPed, 100.0, -1, false, false) + end + end + end + + -- Monitor and update ped behavior + Citizen.CreateThread(function() + while true do + Citizen.Wait(1000) -- Check every second + + -- Remove dead peds from teams + for i = #team1, 1, -1 do + if IsPedDeadOrDying(team1[i], true) then + table.remove(team1, i) + end + end + + for i = #team2, 1, -1 do + if IsPedDeadOrDying(team2[i], true) then + table.remove(team2, i) + end + end + + -- If a team is too small, make them flee + if #team1 < 3 then + makePedsFlee(team1) + break + end + + if #team2 < 3 then + makePedsFlee(team2) + break + end + end + end) + + -- Initial combat setup + if #team1 > 0 and #team2 > 0 then + for _, ped in pairs(team1) do + local randomTarget = team2[math.random(#team2)] + TaskCombatPed(ped, randomTarget, 0, 16) + if Config.Debug then + print("Team 1 Ped "..ped.." is attacking ped "..randomTarget) + end + end + + for _, ped in pairs(team2) do + local randomTarget = team1[math.random(#team1)] + TaskCombatPed(ped, randomTarget, 0, 16) + if Config.Debug then + print("Team 2 Ped "..ped.." is attacking ped "..randomTarget) + end + end + end + + ERS_CreateTemporaryBlipForEntities(pedList, 15000) + ERS_PerformTimedActionOnPed(calloutDataClient, pedList) + end, + + server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) + local randomPeds = Config.randomGangPeds + local totalPeds = math.random(10, 16) -- Total peds for both teams + + for i = 1, totalPeds do + -- Build peds + local diameter = 20 + local pedModel = ERS_GetRandomModel(randomPeds) + local pedCoords = ERS_GetRandomCoordinateWithinRangeOfCoordinate(calloutData.Coordinates, diameter) + local pedHeading = math.random(360) + local pedNetId = ERS_CreatePed(pedModel, pedCoords, pedHeading) + local ped = NetworkGetEntityFromNetworkId(pedNetId) + table.insert(pedList, pedNetId) + end + + return true + end +} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_silo_fire.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_silo_fire.lua new file mode 100644 index 000000000..3f54ac0e0 --- /dev/null +++ b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_silo_fire.lua @@ -0,0 +1,165 @@ +Config.Callouts["roxwood_silo_fire"] = { + + Enabled = true, + CalloutName = "Silo Fire", + CalloutDescriptions = { + "A fire has been reported in an agricultural silo, requiring immediate emergency response.", + "Emergency services are needed to address a fire situation at a grain storage silo.", + "Reports indicate a fire has broken out in a farm silo, necessitating urgent firefighting intervention.", + "A silo fire has been identified, posing potential risks to stored agricultural products and nearby structures.", + "Emergency services have been requested to respond to a fire at a storage silo facility.", + "A request for assistance has been made by farm personnel dealing with a silo fire.", + "Additional units are required to support fire personnel managing a dangerous silo fire.", + "Emergency backup is needed to contain a fire that has broken out in an agricultural silo.", + "First responders report an active fire situation at a grain storage silo.", + "Reports indicate a critical fire situation at a farm silo requiring specialized firefighting equipment.", + }, + CalloutUnitsRequired = { + description = "Fire", + policeRequired = false, + ambulanceRequired = false, + fireRequired = true, + towRequired = false, + }, + CalloutLocations = { + [1] = vector3(-1650.7075, 6579.6846, 30.4142), + [2] = vector3(-1757.1521, 6566.3809, 79.2261), + [3] = vector3(-1666.2078, 6543.0640, 79.2194), + [4] = vector3(-1660.5845, 6602.8188, 32.9437), + [5] = vector3(-1680.0370, 6607.5435, 34.4462), + [6] = vector3(-1707.4130, 6616.6157, 31.7320), + [7] = vector3(-1724.4045, 6619.4497, 34.8395), + [8] = vector3(-1737.7704, 6623.3125, 33.3164), + [9] = vector3(175.7780, 7849.1553, 17.2202), + [10] = vector3(175.9884, 7765.7866, 16.3057), + [11] = vector3(21.9351, 7808.2656, 31.6843), + [12] = vector3(-708.7509, 6809.5586, 35.5453), + [13] = vector3(-713.1135, 6787.7432, 38.4738), + [14] = vector3(-2898.8865, 8279.4307, 48.0824), + }, + PedChanceToFleeFromPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToAttackPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToSurrender = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToObtainWeapons = 0, -- Value between 0 and 100 -> Lower is less chance. + PedActionMinimumTimeoutInMs = 0, -- Milliseconds for the minimum timeout time to start the secondary action listed above. + PedActionMaximumTimeoutInMs = 1000, -- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! + PedActionOnNoActionFound = "none", -- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" + PedWeaponData = { -- The ped will be given one randomly selected weapon (in hand) from these weapons if PedChanceToObtainWeapons passed. + "weapon_unarmed", + }, + + client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) + + for index, pedNetId in pairs(pedList) do + local ped = NetToPed(pedNetId) + if DoesEntityExist(ped) then + ERS_RequestNetControlForEntity(ped) + TaskSetBlockingOfNonTemporaryEvents(ped, true) + PlayPain(ped, 8, 200) + ERS_ApplyBloodToPed(ped) + Wait(2500) + SetEntityHealth(ped, 0) + + end + end + + local chanceOfAnExplosion = 100 + if math.random(1, 100) <= chanceOfAnExplosion then + Citizen.SetTimeout(math.random(5000, 10000), function() + local explosionCoords = vector3(calloutDataClient.Coordinates.x, calloutDataClient.Coordinates.y, calloutDataClient.Coordinates.z) + local explosionRadius = 10.0 + local explosionForce = 10.0 + local explosionValues = { + 0, -- GRENADE + 1, -- GRENADELAUNCHER + 2, -- STICKYBOMB + 3, -- MOLOTOV + 4, -- ROCKET + 5, -- TANKSHELL + 6, -- HI_OCTANE + 7, -- CAR + 8, -- PLANE + 9, -- PETROL_PUMP + 10, -- BIKE + 11, -- DIR_STEAM + 12, -- DIR_FLAME + 13, -- DIR_WATER_HYDRANT + 14, -- DIR_GAS_CANISTER + 15, -- BOAT + 16, -- SHIP_DESTROY + 17, -- TRUCK + 18, -- BULLET + 19, -- SMOKE_GRENADE_LAUNCHER + 20, -- SMOKE_GRENADE + 21, -- BZGAS + 22, -- FLARE + 23, -- GAS_CANISTER + 24, -- EXTINGUISHER + 25, -- PROGRAMMABLEAR + 26, -- TRAIN + 27, -- BARREL + 28, -- PROPANE + 29, -- BLIMP + 30, -- DIR_FLAME_EXPLODE + 31, -- TANKER + 74, -- BOMB water + 75, -- BOMB water secondary + -- Only including explosion types that make sense for a silo fire + } + local explosionType = explosionValues[math.random(#explosionValues)] + AddExplosion(explosionCoords.x, explosionCoords.y, explosionCoords.z-2.0, explosionType, explosionRadius, explosionForce, true, false, 1.0) + end) + end + + ERS_CreateTemporaryBlipForEntities(pedList, 15000) + + ERS_PerformTimedActionOnPed(calloutDataClient, pedList) + + end, + server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) + + local diameter = 2 + local coords = ERS_GetRandomCoordinateWithinRangeOfCoordinate(calloutData.Coordinates, diameter) + + -- Build a medium sized fire + if UsingSmartFires then + -- Full version + local fireSize = Config.RandomMediumFireOrSmokeSize[math.random(#Config.RandomMediumFireOrSmokeSize)] + local fireType = Config.NormalFireTypes[math.random(#Config.NormalFireTypes)] + local fireId = exports['SmartFires']:CreateFire(vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z-0.5), fireSize, fireType) + DebugPrint("Created fire with ID: "..fireId) + table.insert(fireList, fireId) + + -- Build smoke + local chanceOnASmoke = 50 + if math.random(1, 100) <= chanceOnASmoke then + local smokeSize = Config.RandomMediumFireOrSmokeSize[math.random(#Config.RandomMediumFireOrSmokeSize)] + local smokeType = Config.AllSmokeTypes[math.random(#Config.AllSmokeTypes)] + local smokeId = exports['SmartFires']:CreateSmoke(vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z-0.5), smokeSize, smokeType) + + DebugPrint("Created smoke with ID: "..smokeId) + table.insert(smokeList, smokeId) + end + else + -- Lite version + local fireSize = Config.RandomSmallFireOrSmokeSize[math.random(#Config.RandomSmallFireOrSmokeSize)] + local fireType = "normal" + local fireId = exports['SmartFiresLite']:CreateFire(vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z-0.5), fireSize, fireType) + DebugPrint("Created fire with SmartFiresLite with ID: "..fireId) + table.insert(fireList, fireId) + + -- Build smoke + local chanceOnASmoke = 50 + if math.random(1, 100) <= chanceOnASmoke then + local smokeSize = Config.RandomMediumFireOrSmokeSize[math.random(#Config.RandomMediumFireOrSmokeSize)] + local smokeType = "normal" + local smokeId = exports['SmartFiresLite']:CreateSmoke(vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z-0.5), smokeSize, smokeType) + + DebugPrint("Created smoke with ID: "..smokeId) + table.insert(smokeList, smokeId) + end + end + + return true + end +} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_waterpark_incident.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_waterpark_incident.lua new file mode 100644 index 000000000..4afbd756b --- /dev/null +++ b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_waterpark_incident.lua @@ -0,0 +1,75 @@ +Config.Callouts["roxwood_waterpark_incident"] = { + + Enabled = true, + CalloutName = "Waterpark Incident", + CalloutDescriptions = { + "Emergency response needed at the waterpark; individual requiring immediate medical attention.", + "Alert: medical emergency reported at waterpark facilities; units requested for immediate response.", + "Units needed: incident reported at waterpark involving an injured person.", + "Emergency situation at waterpark; medical assistance required for park visitor.", + "Alert: waterpark incident in progress; medical response team needed on scene.", + "First responders requested at waterpark location; medical emergency reported.", + "Respond to waterpark emergency; coordinate with on-site staff for immediate assistance.", + "Situation alert: medical incident at waterpark facilities requiring urgent response.", + "Emergency services needed at waterpark; injured person requiring immediate attention.", + "Response needed: waterpark incident involving injured visitor; medical assistance required.", + }, + CalloutUnitsRequired = { + description = "Ambulance.", + policeRequired = false, + ambulanceRequired = true, + fireRequired = false, + towRequired = false, + }, + CalloutLocations = { + [1] = vector3(-283.4168, 7742.1196, 4.7899), + [2] = vector3(-355.4387, 7813.5391, 4.4505), + [3] = vector3(-285.5687, 7806.6489, 6.3981), + [4] = vector3(-294.5287, 7814.0903, 6.4198), + [5] = vector3(-253.2503, 7772.4219, 6.4892), + [6] = vector3(-207.7762, 7791.9185, 11.1117), + [7] = vector3(-314.7422, 7720.8774, 6.3765), + [8] = vector3(-372.0792, 7815.6128, 6.3837), + [9] = vector3(-314.7273, 7838.0542, 27.3287), + [10] = vector3(-260.1914, 7839.4521, 14.3411), + + }, + PedChanceToFleeFromPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToAttackPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToSurrender = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToObtainWeapons = 0, -- Value between 0 and 100 -> Lower is less chance. + PedActionMinimumTimeoutInMs = 0, -- Milliseconds for the minimum timeout time to start the secondary action listed above. + PedActionMaximumTimeoutInMs = 1000, -- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! + PedActionOnNoActionFound = "none", -- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" + PedWeaponData = { -- The ped will be given one randomly selected weapon (in hand) from these weapons if PedChanceToObtainWeapons passed. + "weapon_unarmed", + }, + + client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) + + for index, pedNetId in pairs(pedList) do + local ped = NetToPed(pedNetId) + if DoesEntityExist(ped) then + ERS_RequestNetControlForEntity(ped) + SetEntityHealth(ped, 0) + end + end + + ERS_CreateTemporaryBlipForEntities(pedList, 15000) + ERS_PerformTimedActionOnPed(calloutDataClient, pedList) + + end, + server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) + + -- Build ped` + local bathingPedModels = {"a_f_m_beach_01", "a_f_m_bodybuild_01", "a_f_m_fatcult_01", "a_f_y_beach_01", "a_m_m_tranvest_01", "a_m_y_acult_02", "a_m_y_jetski_01", "a_m_y_musclbeac_01", "a_m_y_stwhi_01"} + local pedModel = bathingPedModels[math.random(1, #bathingPedModels)] + local pedCoords = vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z+1.0) + local pedHeading = math.random(360) + local pedNetId = ERS_CreatePed(pedModel, pedCoords, pedHeading) + local ped = NetworkGetEntityFromNetworkId(pedNetId) + table.insert(pedList, pedNetId) + + return true + end +} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_wounded_adventurer.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_wounded_adventurer.lua new file mode 100644 index 000000000..0bd6bc1c3 --- /dev/null +++ b/resources/[ERS]/night_ers/callouts/plugins/callout_roxwood_wounded_adventurer.lua @@ -0,0 +1,72 @@ +Config.Callouts["roxwood_wounded_adventurer"] = { + + Enabled = true, + CalloutName = "Wounded adventurer", + CalloutDescriptions = { + "Emergency responders have located a wounded adventurer and are providing assistance.", + "Authorities report that a wounded adventurer has been found, requiring immediate medical attention.", + "A wounded adventurer has been located, necessitating urgent action to ensure their safety.", + "Critical situation with a wounded adventurer located; medical personnel are needed for support.", + "Immediate response needed to provide medical assistance to the wounded adventurer.", + "A wounded adventurer has been found, posing a severe threat to their health; medical reinforcements are necessary.", + "Emergency crews are requesting medical backup to assist in providing care to the wounded adventurer.", + "An urgent call for help has been issued to handle a wounded adventurer and ensure their well-being.", + "Responders are on the scene with a wounded adventurer and need extra support to provide necessary care.", + "A serious emergency involving a wounded adventurer demands swift action to provide medical attention and ensure their recovery.", + }, + CalloutUnitsRequired = { + description = "Police, Ambulance, Fire.", + policeRequired = true, + ambulanceRequired = true, + fireRequired = true, + towRequired = false, + }, + CalloutLocations = { + [1] = vector3(-2018.5511, 7298.9761, 33.5327), + [2] = vector3(-1760.0613, 7586.3652, 144.0277), + [3] = vector3(-1436.0414, 7666.9263, 322.1493), + [4] = vector3(-1310.2694, 7819.0005, 112.6630), + [5] = vector3(-1512.3247, 8080.1509, 42.6374), + [6] = vector3(-1986.1616, 8326.9473, 53.5735), + [7] = vector3(-2109.8350, 8310.7412, 39.0122), + [8] = vector3(-2905.3364, 7596.4253, 14.0765), + [9] = vector3(-3712.5322, 7523.3833, 30.1363), + [10] = vector3(-3044.6580, 7873.9575, 57.8766), + }, + PedChanceToFleeFromPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToAttackPlayer = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToSurrender = 0, -- Value between 0 and 100 -> Lower is less chance. + PedChanceToObtainWeapons = 0, -- Value between 0 and 100 -> Lower is less chance. + PedActionMinimumTimeoutInMs = 0, -- Milliseconds for the minimum timeout time to start the secondary action listed above. + PedActionMaximumTimeoutInMs = 1000, -- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! + PedActionOnNoActionFound = "none", -- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" + PedWeaponData = { -- The ped will be given one randomly selected weapon (in hand) from these weapons if PedChanceToObtainWeapons passed. + "weapon_unarmed", + }, + client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) + for index, pedNetId in pairs(pedList) do + local ped = NetToPed(pedNetId) + if DoesEntityExist(ped) then + ERS_RequestNetControlForEntity(ped) + TaskSetBlockingOfNonTemporaryEvents(ped, true) + ERS_ApplyBloodToPed(ped) + local scenario = ERS_SelectRandomWoundedPersonScenario() + TaskStartScenarioInPlace(ped, scenario, 0, true) + end + end + + ERS_CreateTemporaryBlipForEntities(pedList, 5000) -- short, to make it harder to find. :) + ERS_PerformTimedActionOnPed(calloutDataClient, pedList) + end, + server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) + -- Build ped + local pedModel = ERS_GetRandomModel(Config.randomPeds) + local pedCoords = vector3(calloutData.Coordinates.x, calloutData.Coordinates.y, calloutData.Coordinates.z) + local pedHeading = math.random(360) + local pedNetId = ERS_CreatePed(pedModel, pedCoords, pedHeading) + local ped = NetworkGetEntityFromNetworkId(pedNetId) + table.insert(pedList, pedNetId) + + return true + end +} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/callouts/plugins/callout_smoking_weed.lua b/resources/[ERS]/night_ers/callouts/plugins/callout_smoking_weed.lua deleted file mode 100644 index fa7aca48c..000000000 --- a/resources/[ERS]/night_ers/callouts/plugins/callout_smoking_weed.lua +++ /dev/null @@ -1,125 +0,0 @@ -Config.Callouts["smoking_weed"] = { - - Enabled = true, - CalloutName = "Reports of a person smoking weed", - CalloutDescriptions = { - "Investigate reports of a person smoking weed; locate the individual and assess the situation.", - "Alert: dispatch units to check on reports of marijuana use in a public area; ensure compliance with laws.", - "Units required: respond to reports of someone smoking weed and evaluate the circumstances.", - "Notice: check reports of a person using marijuana; take necessary actions to maintain public order.", - "Alert: respond promptly to reports of marijuana use; prioritize community safety and proper assessment.", - "Incident reported: look into reports of a person smoking weed to understand the context and legality.", - "Investigate reports of marijuana use; coordinate with local authorities to address the situation.", - "Situation alert: address reports of a person smoking weed; work with relevant authorities if needed.", - "Alert: handle reports of marijuana use and adhere to protocols for ensuring public safety and compliance.", - "Response needed: investigate reports of a person smoking weed and take steps to ensure community standards are upheld.", - }, - CalloutUnitsRequired = { - description = "Police", - policeRequired = true, - ambulanceRequired = false, - fireRequired = false, - towRequired = false, - }, - CalloutLocations = { - [1] = vector3(558.51, -2590.25, 6.19), - [2] = vector3(314.44, -997.08, 29.18), - [3] = vector3(195.41, -948.04, 30.09), - [4] = vector3(171.31, -1077.74, 29.19), - [5] = vector3(34.17, -1025.83, 29.47), - [6] = vector3(-137.15, -1180.85, 25.25), - [7] = vector3(-306.71, -1167.35, 23.26), - [8] = vector3(-318.98, -1334.59, 31.34), - [9] = vector3(-356.58, -1483.50, 30.16), - [10] = vector3(-342.61, -1566.72, 25.22), - [11] = vector3(-429.75, -1721.61, 19.05), - [12] = vector3(-575.62, -1793.78, 22.73), - [13] = vector3(-249.28, -1939.75, 29.95), - [14] = vector3(-331.26, -2171.95, 10.32), - [15] = vector3(-809.27, -2328.58, 14.57), - [16] = vector3(-1148.01, -1984.79, 13.16), - [17] = vector3(-1247.68, -1711.14, 4.47), - [18] = vector3(-1216.14, -1525.44, 4.26), - [19] = vector3(-1285.50, -1408.50, 4.45), - [20] = vector3(-1493.06, -1369.73, 2.15), - [21] = vector3(-1817.37, -1240.33, 13.02), - [22] = vector3(-1654.58, -362.49, 49.48), - [23] = vector3(-1318.32, -152.82, 46.39), - [24] = vector3(-516.12, -446.37, 34.19), - [25] = vector3(-302.33, -262.08, 32.42), - [26] = vector3(-188.07, -88.38, 52.18), - [27] = vector3(-43.71, -12.89, 69.87), - [28] = vector3(83.45, 33.97, 73.51), - [29] = vector3(243.14, 117.53, 102.62), - [30] = vector3(323.57, 174.77, 103.61), - [31] = vector3(193.88, 296.12, 105.62), - [32] = vector3(173.28, 387.58, 109.38), - [33] = vector3(206.88, 777.59, 205.56), - [34] = vector3(1221.91, 2722.65, 38.00), - [35] = vector3(1771.69, 3306.27, 41.17), - [36] = vector3(1633.14, 3559.25, 35.15), - [37] = vector3(1646.57, 3725.12, 34.34), - [38] = vector3(1767.44, 3754.12, 33.83), - [39] = vector3(1978.10, 3759.90, 32.18), - [40] = vector3(2461.98, 4063.67, 38.06), - [41] = vector3(2108.17, 4767.26, 41.17), - [42] = vector3(1695.52, 4784.01, 42.01), - [43] = vector3(1669.93, 4768.75, 41.85), - [44] = vector3(1429.15, 4384.90, 44.18), - [45] = vector3(1684.00, 6422.10, 32.27), - [46] = vector3(131.79, 6636.05, 31.81), - [47] = vector3(76.80, 6347.70, 31.37), - [48] = vector3(-18.15, 6392.06, 31.44), - [49] = vector3(-104.94, 6256.18, 31.35), - [50] = vector3(-252.48, 6213.64, 31.49), - [51] = vector3(-329.01, 6222.01, 31.48), - }, - PedChanceToFleeFromPlayer = 25, -- Value between 0 and 100 -> Lower is less chance. - PedChanceToAttackPlayer = 25, -- Value between 0 and 100 -> Lower is less chance. - PedChanceToSurrender = 10, -- Value between 0 and 100 -> Lower is less chance. - PedChanceToObtainWeapons = 10, -- Value between 0 and 100 -> Lower is less chance. - PedActionMinimumTimeoutInMs = 10000, -- Milliseconds for the minimum timeout time to start the secondary action listed above. - PedActionMaximumTimeoutInMs = 15000, -- Milliseconds for the maximum timeout time to start the secondary action. Must be a higher number than the minimum! - PedActionOnNoActionFound = "flee", -- When no action of the above options is found. It'll perform this action after the set timeout. Options: "none", "attack", "flee", "surrender" - PedWeaponData = { -- The ped will be given one randomly selected weapon (in hand) from these weapons if PedChanceToObtainWeapons passed. - "weapon_bat", - "weapon_hammer", - "weapon_wrench", - "weapon_pistol", - }, - - client = function(plyPed, pedList, vehicleList, playersList, objectList, propList, fireList, smokeList, calloutDataClient) - - for index, pedNetId in pairs(pedList) do - local ped = NetToPed(pedNetId) - if DoesEntityExist(ped) then - ERS_RequestNetControlForEntity(ped) - local scenario = ERS_SelectRandomSmokeScenario() - TaskStartScenarioInPlace(ped, scenario, 0, true) - end - end - - ERS_CreateTemporaryBlipForEntities(pedList, 15000) - - ERS_PerformTimedActionOnPed(calloutDataClient, pedList) - - end, - server = function(request, src, calloutData, pedList, vehicleList, objectList, propList, playersList, fireList, smokeList) - - local diameter = 10 - - -- Build suspects - local suspects = math.random(1, 3) - for i = 1, suspects do - local coords = ERS_GetRandomCoordinateWithinRangeOfCoordinate(calloutData.Coordinates, diameter) - local pedModel = ERS_GetRandomModel(Config.randomGangPeds) - local pedCoords = vector3(coords.x, coords.y, coords.z+1.0) - local pedHeading = math.random(360) - local pedNetId = ERS_CreatePed(pedModel, pedCoords, pedHeading) - local ped = NetworkGetEntityFromNetworkId(pedNetId) - table.insert(pedList, pedNetId) - end - - return true - end -} \ No newline at end of file diff --git a/resources/[ERS]/night_ers/client/c_functions.lua b/resources/[ERS]/night_ers/client/c_functions.lua index c948b5287..397c78bf2 100644 --- a/resources/[ERS]/night_ers/client/c_functions.lua +++ b/resources/[ERS]/night_ers/client/c_functions.lua @@ -190,8 +190,6 @@ function OnNPCGivesGear(data) end end -exports("OnNPCGivesGear", OnNPCGivesGear) - -- ============================================ -- FUNCTIONS -- ============================================ diff --git a/resources/[ERS]/night_ers/client/client.lua b/resources/[ERS]/night_ers/client/client.lua index c1585b844..b45e603de 100644 Binary files a/resources/[ERS]/night_ers/client/client.lua and b/resources/[ERS]/night_ers/client/client.lua differ diff --git a/resources/[ERS]/night_ers/client/ers_functions.lua b/resources/[ERS]/night_ers/client/ers_functions.lua index 0898900f2..94e518ccd 100644 Binary files a/resources/[ERS]/night_ers/client/ers_functions.lua and b/resources/[ERS]/night_ers/client/ers_functions.lua differ diff --git a/resources/[ERS]/night_ers/client/exports_client.lua b/resources/[ERS]/night_ers/client/exports_client.lua index 051c7960a..e32ec7dcd 100644 --- a/resources/[ERS]/night_ers/client/exports_client.lua +++ b/resources/[ERS]/night_ers/client/exports_client.lua @@ -21,11 +21,6 @@ exports('getIsPlayerAttachedToCallout', function() return isAttachedToCallout end) -exports('getIsPlayerOfferedACallout', function() - -- Returns: true or false - return isOfferedCallout -end) - exports('getIsPlayerTrackingUnit', function() -- Returns: true or false return isTrackingUnit.isTracking @@ -87,10 +82,6 @@ exports('ERS_ConnectClosestVehicle', function() ERS_ConnectClosestVehicle() end) -exports('getIsImperialEnabled', function() - return Config.UseImperial -end) - --====================== TEST COMMANDS ======================-- -- RegisterCommand('testclientexports', function() diff --git a/resources/[ERS]/night_ers/client/gear_client.lua b/resources/[ERS]/night_ers/client/gear_client.lua index 555be2386..5f9b6880f 100644 Binary files a/resources/[ERS]/night_ers/client/gear_client.lua and b/resources/[ERS]/night_ers/client/gear_client.lua differ diff --git a/resources/[ERS]/night_ers/client/impound_client.lua b/resources/[ERS]/night_ers/client/impound_client.lua index 518f2db14..5565c2e70 100644 Binary files a/resources/[ERS]/night_ers/client/impound_client.lua and b/resources/[ERS]/night_ers/client/impound_client.lua differ diff --git a/resources/[ERS]/night_ers/client/npcbackup_client.lua b/resources/[ERS]/night_ers/client/npcbackup_client.lua index e69586ab4..2f079f810 100644 Binary files a/resources/[ERS]/night_ers/client/npcbackup_client.lua and b/resources/[ERS]/night_ers/client/npcbackup_client.lua differ diff --git a/resources/[ERS]/night_ers/client/pedinteractions_client.lua b/resources/[ERS]/night_ers/client/pedinteractions_client.lua index 5f7de0f33..48a2a175c 100644 Binary files a/resources/[ERS]/night_ers/client/pedinteractions_client.lua and b/resources/[ERS]/night_ers/client/pedinteractions_client.lua differ diff --git a/resources/[ERS]/night_ers/client/pullover_client.lua b/resources/[ERS]/night_ers/client/pullover_client.lua index aa6b447c4..b2739083e 100644 Binary files a/resources/[ERS]/night_ers/client/pullover_client.lua and b/resources/[ERS]/night_ers/client/pullover_client.lua differ diff --git a/resources/[ERS]/night_ers/client/pursuit_client.lua b/resources/[ERS]/night_ers/client/pursuit_client.lua index b8fe20ed9..496ae3669 100644 Binary files a/resources/[ERS]/night_ers/client/pursuit_client.lua and b/resources/[ERS]/night_ers/client/pursuit_client.lua differ diff --git a/resources/[ERS]/night_ers/client/questioning_client.lua b/resources/[ERS]/night_ers/client/questioning_client.lua index 5f5071f13..40f950773 100644 Binary files a/resources/[ERS]/night_ers/client/questioning_client.lua and b/resources/[ERS]/night_ers/client/questioning_client.lua differ diff --git a/resources/[ERS]/night_ers/client/spikestrip_client.lua b/resources/[ERS]/night_ers/client/spikestrip_client.lua index 45a572ffa..362522679 100644 Binary files a/resources/[ERS]/night_ers/client/spikestrip_client.lua and b/resources/[ERS]/night_ers/client/spikestrip_client.lua differ diff --git a/resources/[ERS]/night_ers/client/stretcher_client.lua b/resources/[ERS]/night_ers/client/stretcher_client.lua index f481a1442..f60af685d 100644 Binary files a/resources/[ERS]/night_ers/client/stretcher_client.lua and b/resources/[ERS]/night_ers/client/stretcher_client.lua differ diff --git a/resources/[ERS]/night_ers/client/target.lua b/resources/[ERS]/night_ers/client/target.lua index cc1e377e6..462667da9 100644 Binary files a/resources/[ERS]/night_ers/client/target.lua and b/resources/[ERS]/night_ers/client/target.lua differ diff --git a/resources/[ERS]/night_ers/client/towtools_client.lua b/resources/[ERS]/night_ers/client/towtools_client.lua index 47e6aac56..b402885a0 100644 Binary files a/resources/[ERS]/night_ers/client/towtools_client.lua and b/resources/[ERS]/night_ers/client/towtools_client.lua differ diff --git a/resources/[ERS]/night_ers/client/vehinteractions_client.lua b/resources/[ERS]/night_ers/client/vehinteractions_client.lua index 6c6d29076..5e3849fc2 100644 Binary files a/resources/[ERS]/night_ers/client/vehinteractions_client.lua and b/resources/[ERS]/night_ers/client/vehinteractions_client.lua differ diff --git a/resources/[ERS]/night_ers/config/config.lua b/resources/[ERS]/night_ers/config/config.lua index 005be1532..799bf435c 100644 --- a/resources/[ERS]/night_ers/config/config.lua +++ b/resources/[ERS]/night_ers/config/config.lua @@ -2,15 +2,15 @@ Config = Config or {} Config = { - ConfigVersion = "1.8.3", + ConfigVersion = "1.8.1", Debug = false, -- Enable or disable Debug, recommended to set to false for improved gameplay (resmon is very high in debug mode). EventPrefix = "night_ers", -- Leave this be. - Language = "US", -- Available languages: en | us | nl | de | fr | he | cs | pt-br | sv | (Ajust text in config/translations.lua) - SoundLanguage = "US", -- Available languages: en | us | fr | de | (Ajust text in config/sound-config.lua) - DOBFormat = "US", -- Options: en | us + Language = "us", -- Available languages: en | us | nl | de | fr | he | cs | pt-br | sv | (Ajust text in config/translations.lua) + SoundLanguage = "us", -- Available languages: en | us | fr | de | (Ajust text in config/sound-config.lua) + DOBFormat = "us", -- Options: en | us UseImperial = false, -- Options: true = feet (mi) | false = meters (km) (Determines whether to display distances in feet (true) or meters (false)) - Timezone = "America/Los_Angeles", -- Set the timezone which the script uses. https://en.wikipedia.org/wiki/List_of_tz_database_time_zones + Timezone = "Europe/London", -- Set the timezone which the script uses. https://en.wikipedia.org/wiki/List_of_tz_database_time_zones --[[ IMPORTANT: https://docs.fivem.net/natives/?_0xA0F2201F [OPTIONS FOR ServerLockDownMode (below)] @@ -270,9 +270,6 @@ Config = { -- Tow Tools ConnectClosestVehicle = "", -- Button to connect the closest vehicle to the towing vehicle. (None by default) - - -- Redisplay Last Module - RedisplayLastModule = "TAB", -- Button to redisplay the last shown module (ID card, vehicle info, or inventory). }, Commands = { @@ -331,9 +328,6 @@ Config = { -- Tow Tools ConnectClosestVehicle = "ccv", - -- Redisplay Last Module - RedisplayLastModule = "redisplaylastmodule", - -- Hints ToggleHints = "togglehints", }, @@ -393,9 +387,6 @@ Config = { -- Tow Tools ConnectClosestVehicle = "Command used to connect the closest vehicle to the towing vehicle.", - -- Redisplay Last Module - RedisplayLastModule = "Command used to redisplay the last shown module (ID card, vehicle info, or inventory).", - -- Hints ToggleHints = "Command used to toggle hints at certain events.", }, diff --git a/resources/[ERS]/night_ers/config/sound-config.lua b/resources/[ERS]/night_ers/config/sound-config.lua index 758aa7aa5..58a5cb013 100644 --- a/resources/[ERS]/night_ers/config/sound-config.lua +++ b/resources/[ERS]/night_ers/config/sound-config.lua @@ -219,12 +219,12 @@ Config.PedInteractionSoundFiles = { -- Only adjust FileName, SoundVolume and/or }, ['cuff'] = { Male = { - [1] = {FileName = SoundFileLanguagePrefix .. "_arrest_rights", SoundVolume = 0.3, TTS = '"**Reading Rights**"'}, + [1] = {FileName = SoundFileLanguagePrefix .. "_cuffs", SoundVolume = 0.3, TTS = '"Turn around so I can work on these cuffs."'}, -- [2] = {FileName = SoundFileLanguagePrefix .. "_cuff_1", SoundVolume = 0.3, TTS = '"Make your audio file and write the subtitle here."'}, -- [3] = {FileName = SoundFileLanguagePrefix .. "_cuff_2", SoundVolume = 0.3, TTS = '"Make your audio file and write the subtitle here."'}, }, Female = { - [1] = {FileName = SoundFileLanguagePrefix .. "_arrest_rights_f", SoundVolume = 0.3, TTS = '"**Reading Rights**"'}, + [1] = {FileName = SoundFileLanguagePrefix .. "_cuffs_f", SoundVolume = 0.3, TTS = '"Turn around so I can work on these cuffs."'}, -- [2] = {FileName = SoundFileLanguagePrefix .. "_cuff_1", SoundVolume = 0.3, TTS = '"Make your audio file and write the subtitle here."'}, -- [3] = {FileName = SoundFileLanguagePrefix .. "_cuff_2", SoundVolume = 0.3, TTS = '"Make your audio file and write the subtitle here."'}, }, diff --git a/resources/[ERS]/night_ers/config/spikestrip-config.lua b/resources/[ERS]/night_ers/config/spikestrip-config.lua index 96bb7cf04..e45df1b78 100644 --- a/resources/[ERS]/night_ers/config/spikestrip-config.lua +++ b/resources/[ERS]/night_ers/config/spikestrip-config.lua @@ -1225,8 +1225,10 @@ Config.Spikestrips = { "schp16piust", "schp16piu", "maxchasrt", - "safe33g", - "tskodae", + "safe33g", + + + diff --git a/resources/[ERS]/night_ers/config/stretcher-config.lua b/resources/[ERS]/night_ers/config/stretcher-config.lua index 03bffeba4..f6e7b9470 100644 --- a/resources/[ERS]/night_ers/config/stretcher-config.lua +++ b/resources/[ERS]/night_ers/config/stretcher-config.lua @@ -15,6 +15,7 @@ Config.VehiclesWithStretchers = { {hash = "ambumercbox", behindVehicle = -6.0, sideways = 0.0, depth = -1.4, height = 0.28}, {hash = "ukambu1", behindVehicle = -6.0, sideways = 0.0, depth = -1.5, height = 0.28}, {hash = "ukambu2", behindVehicle = -6.0, sideways = 0.0, depth = -1.5, height = 0.28}, + -- {hash = "your_ambulance", behindVehicle = -6.0, sideways = 0.0, depth = -1.5, height = 0.28}, {hash = "lafdrambulance", behindVehicle = -6.0, sideways = 0.0, depth = -1.5, height = 0.28}, {hash = "rambulance", behindVehicle = -6.0, sideways = 0.0, depth = -1.5, height = 0.28}, {hash = "24ramambo", behindVehicle = -6.0, sideways = 0.0, depth = -1.5, height = 0.28}, @@ -26,9 +27,7 @@ Config.VehiclesWithStretchers = { {hash = "fdgator", behindVehicle = -6.0, sideways = 0.0, depth = -1.5, height = 0.28}, {hash = "medic22", behindVehicle = -6.0, sideways = 0.0, depth = -1.5, height = 0.28}, - - -- {hash = "your_ambulance", behindVehicle = -6.0, sideways = 0.0, depth = -1.5, height = 0.28}, - -- Add more here. + } Config.ShowSavedScreen = true -- Shows victim saved in GTA style, when dropping off a victim. diff --git a/resources/[ERS]/night_ers/config/towtools-config.lua b/resources/[ERS]/night_ers/config/towtools-config.lua index 483a01bed..0d2a1fd7c 100644 --- a/resources/[ERS]/night_ers/config/towtools-config.lua +++ b/resources/[ERS]/night_ers/config/towtools-config.lua @@ -19,13 +19,13 @@ Config.TowableVehicleClasses = { [10] = true, -- Industrial [11] = true, -- Utility [12] = true, -- Vans - [13] = false,-- Cycles + [13] = true,-- Cycles [14] = false,-- Boats [15] = false,-- Helicopters [16] = false,-- Planes [17] = true, -- Service [18] = true, -- Emergency - [19] = true, -- Military + [19] = false, -- Military [20] = true, -- Commercial [21] = false,-- Trains [22] = true, -- Open Wheel @@ -35,18 +35,6 @@ Config.TowableVehicleClasses = { -- TO ADD MORE VEHICLES, COPY THE FORMAT AND FILL IN THE VARIABLES Config.TowVehicles = { - [`flatbed`] = { - enginePowerMultiplier = 28.0, -- Required for some tow trucks to have more power to pull heavy vehicles. - winchAnchorOverride = { - enabled = true, -- If false, the script will use the default tow anchor position. (Which is using the suspension or wheel bones) - left = { - { bone = "suspension_lr", leftRight = 0.0, forwardBack = 0.0, upDown = 0.0 }, - }, - right = { - { bone = "suspension_rr", leftRight = 0.0, forwardBack = 0.0, upDown = 0.0 }, - } - } - }, [`flatbed`] = { enginePowerMultiplier = 28.0, -- Required for some tow trucks to have more power to pull heavy vehicles. winchAnchorOverride = { @@ -552,5 +540,8 @@ Config.TowVehicles = { } } }, - + + + + } \ No newline at end of file diff --git a/resources/[ERS]/night_ers/fxmanifest.lua b/resources/[ERS]/night_ers/fxmanifest.lua index de8d4fb8d..b35ed3085 100644 --- a/resources/[ERS]/night_ers/fxmanifest.lua +++ b/resources/[ERS]/night_ers/fxmanifest.lua @@ -4,7 +4,7 @@ games { 'gta5' } author 'Nights Software' description 'Emergency Response Simulator' -version '1.8.3' +version '1.8.2' lua54 'yes' shared_scripts { @@ -46,7 +46,7 @@ files { 'stream/*.ytyp' } -data_file 'DLC_ITYP_REQUEST' 'stream/neko_night_barrier_assets.ytyp' +data_file 'DLC_ITYP_REQUEST' 'stream/neko_night_barrier_assets' data_file 'DLC_ITYP_REQUEST' 'stream/cages/v_storage_2.ytyp' data_file 'DLC_ITYP_REQUEST' 'stream/prop_alcotest.ytyp' diff --git a/resources/[ERS]/night_ers/index.html b/resources/[ERS]/night_ers/index.html index 38781c6bc..ebadec919 100644 --- a/resources/[ERS]/night_ers/index.html +++ b/resources/[ERS]/night_ers/index.html @@ -19,10 +19,6 @@ - diff --git a/resources/[ERS]/night_ers/server/connection_server.lua b/resources/[ERS]/night_ers/server/connection_server.lua index 1eb1eaf3c..6116c3b3c 100644 Binary files a/resources/[ERS]/night_ers/server/connection_server.lua and b/resources/[ERS]/night_ers/server/connection_server.lua differ diff --git a/resources/[ERS]/night_ers/server/exports_server.lua b/resources/[ERS]/night_ers/server/exports_server.lua index 3a1019150..7a9e46714 100644 --- a/resources/[ERS]/night_ers/server/exports_server.lua +++ b/resources/[ERS]/night_ers/server/exports_server.lua @@ -1,38 +1,22 @@ --====================== SERVERSIDE EXPORTS ======================-- --- local isOnShift = exports['night_ers']:getIsPlayerOnShift(src) -exports('getIsPlayerOnShift', function(src) - return getIsPlayerOnShift(src) -end) - --- local getPlayerActiveServiceType = exports['night_ers']:getPlayerActiveServiceType(src) -exports('getPlayerActiveServiceType', function(src) - -- Returns: "police", "ambulance", "fire", "tow" or nil - return getPlayerActiveServiceType(src) -end) - --- exports['night_ers']:toggleShift(source, shiftType) exports('toggleShift', function(source, shiftType) ToggleShift(source, shiftType) -- shiftType can be "police", "ambulance", "fire" or "tow" end) --- exports['night_ers']:trackPlayerCallout(source, targetSource) exports('trackPlayerCallout', function(source, targetSource) TrackUnit(source, targetSource) end) --- exports['night_ers']:setPlayerCalloutOffersEnabled(source, enabled) exports('setPlayerCalloutOffersEnabled', function(source, enabled) SetPlayerCalloutOffersEnabled(source, enabled) end) --- exports['night_ers']:getCallouts() exports('getCallouts', function() local jsonReadyTable = cloneWithoutFunctions(Config.Callouts) return jsonReadyTable end) --- exports['night_ers']:createCallout(callout) exports('createCallout', function(callout) local newCalloutID = callout.id .. '-' .. os.time() Config.Callouts[newCalloutID] = Config.Callouts[callout.id] @@ -48,4 +32,9 @@ exports('createCallout', function(callout) calloutId = newCalloutID, } return returnData -end) \ No newline at end of file +end) + +-- exports['night_ers']:toggleShift(source, shiftType) +-- exports['night_ers']:trackPlayerCallout(source, targetSource) +-- exports['night_ers']:setPlayerCalloutOffersEnabled(source, enabled) +-- exports['night_ers']:createCallout(callout) \ No newline at end of file diff --git a/resources/[ERS]/night_ers/server/gear_server.lua b/resources/[ERS]/night_ers/server/gear_server.lua index 2a8aaf7b8..da4e393c4 100644 Binary files a/resources/[ERS]/night_ers/server/gear_server.lua and b/resources/[ERS]/night_ers/server/gear_server.lua differ diff --git a/resources/[ERS]/night_ers/server/impound_server.lua b/resources/[ERS]/night_ers/server/impound_server.lua index c0db83c8f..9b659495f 100644 Binary files a/resources/[ERS]/night_ers/server/impound_server.lua and b/resources/[ERS]/night_ers/server/impound_server.lua differ diff --git a/resources/[ERS]/night_ers/server/leaderboard_server.lua b/resources/[ERS]/night_ers/server/leaderboard_server.lua index fa4714f08..fd265d343 100644 Binary files a/resources/[ERS]/night_ers/server/leaderboard_server.lua and b/resources/[ERS]/night_ers/server/leaderboard_server.lua differ diff --git a/resources/[ERS]/night_ers/server/npcbackup_server.lua b/resources/[ERS]/night_ers/server/npcbackup_server.lua index 418d47b42..20c073fe6 100644 Binary files a/resources/[ERS]/night_ers/server/npcbackup_server.lua and b/resources/[ERS]/night_ers/server/npcbackup_server.lua differ diff --git a/resources/[ERS]/night_ers/server/pullover_server.lua b/resources/[ERS]/night_ers/server/pullover_server.lua index 21f3ff911..d1bbe62db 100644 Binary files a/resources/[ERS]/night_ers/server/pullover_server.lua and b/resources/[ERS]/night_ers/server/pullover_server.lua differ diff --git a/resources/[ERS]/night_ers/server/pursuit_server.lua b/resources/[ERS]/night_ers/server/pursuit_server.lua index 73c605bbf..c074d758d 100644 Binary files a/resources/[ERS]/night_ers/server/pursuit_server.lua and b/resources/[ERS]/night_ers/server/pursuit_server.lua differ diff --git a/resources/[ERS]/night_ers/server/server.lua b/resources/[ERS]/night_ers/server/server.lua index 20d2d57e0..5ea2e9222 100644 Binary files a/resources/[ERS]/night_ers/server/server.lua and b/resources/[ERS]/night_ers/server/server.lua differ diff --git a/resources/[ERS]/night_ers/server/spikestrip_server.lua b/resources/[ERS]/night_ers/server/spikestrip_server.lua index 64cb29ce6..034a50023 100644 Binary files a/resources/[ERS]/night_ers/server/spikestrip_server.lua and b/resources/[ERS]/night_ers/server/spikestrip_server.lua differ diff --git a/resources/[ERS]/night_ers/server/stretcher_server.lua b/resources/[ERS]/night_ers/server/stretcher_server.lua index 586b7940c..6969a64e6 100644 Binary files a/resources/[ERS]/night_ers/server/stretcher_server.lua and b/resources/[ERS]/night_ers/server/stretcher_server.lua differ diff --git a/resources/[ERS]/night_ers/server/towtools_server.lua b/resources/[ERS]/night_ers/server/towtools_server.lua index d4488ba38..303f7ea41 100644 Binary files a/resources/[ERS]/night_ers/server/towtools_server.lua and b/resources/[ERS]/night_ers/server/towtools_server.lua differ diff --git a/resources/[ERS]/night_ers/stream/[Breathalyzer]/prop_alcotest.ydr b/resources/[ERS]/night_ers/stream/[Breathalyzer]/prop_alcotest.ydr index a4daf5ab9..8624ef879 100644 --- a/resources/[ERS]/night_ers/stream/[Breathalyzer]/prop_alcotest.ydr +++ b/resources/[ERS]/night_ers/stream/[Breathalyzer]/prop_alcotest.ydr @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:47d39988db2ec8b8338e6a18c7ece73b06a42eab7681eebee9f082c85ebc3433 -size 1123652 +oid sha256:61bec3e377ee72f14913c67fffc5ecc11f7eef5e6c3987b85a185f7dcd714049 +size 1037399 diff --git a/resources/[ERS]/night_ers/stream/[Cages]/prop_dog_cage_03.ydr b/resources/[ERS]/night_ers/stream/[Cages]/prop_dog_cage_03.ydr index f8acdf377..05e00b50c 100644 --- a/resources/[ERS]/night_ers/stream/[Cages]/prop_dog_cage_03.ydr +++ b/resources/[ERS]/night_ers/stream/[Cages]/prop_dog_cage_03.ydr @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f2f606f11d551978130804dad19278866b63837757cc600e2e0a7fd7f592391c -size 296951 +oid sha256:731f203a77436493b95fab862449bd8e2529cdd21bdfea7ff824b71d809d123a +size 283459 diff --git a/resources/[ERS]/night_ers/stream/[Cages]/prop_dog_cage_04.ydr b/resources/[ERS]/night_ers/stream/[Cages]/prop_dog_cage_04.ydr index 858cc0fbd..08ecd09e9 100644 --- a/resources/[ERS]/night_ers/stream/[Cages]/prop_dog_cage_04.ydr +++ b/resources/[ERS]/night_ers/stream/[Cages]/prop_dog_cage_04.ydr @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:75d6d90db6786877ef1dcb83db1c3439d7d155c28ad25dc35b9eb5b4b01e02ea -size 303029 +oid sha256:184087526495fe35ae71328a8895bea7dd52306120835065af117941c46edf3a +size 285657 diff --git a/resources/[ERS]/night_ers/stream/[Cages]/prop_dog_cage_05.ydr b/resources/[ERS]/night_ers/stream/[Cages]/prop_dog_cage_05.ydr index b07dd440c..e264aab6b 100644 --- a/resources/[ERS]/night_ers/stream/[Cages]/prop_dog_cage_05.ydr +++ b/resources/[ERS]/night_ers/stream/[Cages]/prop_dog_cage_05.ydr @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:34327dce44721667c7346d30f86e1d64b560e3c766df6b67ba81d3e749707c63 -size 301864 +oid sha256:9e5e163d621ec35609913d04b8071bbb586ffd90e00c39de68c7e2a0e4046456 +size 286917 diff --git a/resources/[ERS]/night_ers/stream/[Cuffs]/p_cs_cuffs_02_s.ydr b/resources/[ERS]/night_ers/stream/[Cuffs]/p_cs_cuffs_02_s.ydr index 48d81677e..377b41781 100644 --- a/resources/[ERS]/night_ers/stream/[Cuffs]/p_cs_cuffs_02_s.ydr +++ b/resources/[ERS]/night_ers/stream/[Cuffs]/p_cs_cuffs_02_s.ydr @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8c1d634486a048f088ffd7eb3df862bac5d15a7b35950c33c389aaad5d7e30ec -size 1837203 +oid sha256:0e5a7cc15baf95b3bb75b0f1ac4bb02fda1b1c8faf02d37cecef8a8b0ae98966 +size 1109675 diff --git a/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_arrow_board_00.ydr b/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_arrow_board_00.ydr index 7f0783317..b5b0a7179 100644 --- a/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_arrow_board_00.ydr +++ b/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_arrow_board_00.ydr @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:20fb751141263dbe4b93ef8e8e1e34415b84f453c716a46d041efb752a654411 -size 208368 +oid sha256:9b30966fb460baabd8c2521c2f49680062dc8ceaccc2048a667b109edbc718ba +size 149589 diff --git a/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_arrow_board_00_l.ydr b/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_arrow_board_00_l.ydr index 152406a41..ccbeca5d5 100644 --- a/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_arrow_board_00_l.ydr +++ b/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_arrow_board_00_l.ydr @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3a305759c820b39804a0f6efdb6034c9c19a5e49071b6094354d96e74cb80c43 -size 206076 +oid sha256:d3737b1aadccc190dfd8dfe8c033f982582ab18a2c5330f70d261a4533c0bca3 +size 148139 diff --git a/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_arrow_board_00_r.ydr b/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_arrow_board_00_r.ydr index 5b22bad88..8de9f7608 100644 --- a/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_arrow_board_00_r.ydr +++ b/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_arrow_board_00_r.ydr @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cdf75c1c22029c676ec190749634d0b4017dfe9ac8e77e74c92a09cd57ef14c6 -size 213444 +oid sha256:a6248314e4a7a6f7869b7b05bc9fe3e30b3986c7d19f498df765b7b33ce6c5d4 +size 148334 diff --git a/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_barrier_00.ydr b/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_barrier_00.ydr index 37850be16..c40856d0a 100644 --- a/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_barrier_00.ydr +++ b/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_barrier_00.ydr @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f542c3b925d026a6d5ac1af458d8d256447911cf66789d75645ceb40a5db1367 -size 112759 +oid sha256:2759fd0cb064bc4f801ec5c54ccb89e936603f26f32fd6ae6ca4c3eab212b092 +size 67744 diff --git a/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_barrier_01.ydr b/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_barrier_01.ydr index 72a76eaf0..3a8af988e 100644 --- a/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_barrier_01.ydr +++ b/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_barrier_01.ydr @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f97d8b321cbabe07ffb424aab5efd3f2f95fe979b6c669741e32facff0c20831 -size 96006 +oid sha256:c37e7c8a9b702a93b1ce5666961293e257b58643b2e470d15184f30e10f00d03 +size 42341 diff --git a/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_barrier_02.ydr b/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_barrier_02.ydr index 7266f6fb6..664c9fd97 100644 --- a/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_barrier_02.ydr +++ b/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_barrier_02.ydr @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2532695da81b564444d10816fa54550d7187e3a86d09ce30491a33137d0eefd8 -size 47891 +oid sha256:8bfb01242b7ca2d58971b4f52f6079ef074b2fb557640e721bfed2d6b62ebd86 +size 25808 diff --git a/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_cone_00.ydr b/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_cone_00.ydr index c8ce5cb51..08ccca062 100644 --- a/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_cone_00.ydr +++ b/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_cone_00.ydr @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:08886d3dd7d6adebbd33d96e9d4872c1f881d101db4a9276a7af90f342b761af -size 25570 +oid sha256:ed574bef081fade578f99931cc82552715c20c0b28283afbb97e0db758aa1626 +size 14730 diff --git a/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_rubber_barrier_00.ydr b/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_rubber_barrier_00.ydr index c5c92bc52..c6e7de9d8 100644 --- a/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_rubber_barrier_00.ydr +++ b/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_rubber_barrier_00.ydr @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f826d7dc8013db4d1ad3c182a7ceb8802562cd890d11315f4eceebfecb64e1b -size 11869 +oid sha256:ab7288bf10e60089b0a8fb2ce17de22307701e46a644064955244b2038ed52d0 +size 7903 diff --git a/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_warning_tri_00.ydr b/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_warning_tri_00.ydr index 5010ab874..a0d13d7d0 100644 --- a/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_warning_tri_00.ydr +++ b/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_warning_tri_00.ydr @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b44a901c58f6e41f92413ec41052663e70efcbcaf77620f6c5a571ee492a62a2 -size 26812 +oid sha256:cb34139a3c89c459e36ba464a532ef150f5c3bb649e90b107ca79345b6fe42ce +size 20166 diff --git a/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_water_barrier_00.ydr b/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_water_barrier_00.ydr index 31cc3daed..39a519a60 100644 --- a/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_water_barrier_00.ydr +++ b/resources/[ERS]/night_ers/stream/[NXP Props]/neko_night_water_barrier_00.ydr @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:216632f5d7d484fb74df0edd7cf82b4c9ac997750fa16fe9d2eadd07660cac48 -size 148637 +oid sha256:c3f0d44b33206d6e8a36469538b5c9b801a5efd3f2da78619b35e07a0d65f961 +size 84742 diff --git a/resources/[ERS]/night_ers/stream/[SmartHose]/w_ers_npc_hose.ydr b/resources/[ERS]/night_ers/stream/[SmartHose]/w_ers_npc_hose.ydr index d0bdf3bd7..f10279011 100644 --- a/resources/[ERS]/night_ers/stream/[SmartHose]/w_ers_npc_hose.ydr +++ b/resources/[ERS]/night_ers/stream/[SmartHose]/w_ers_npc_hose.ydr @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b75afc48c06ee9489f59862f5dad7bd156d6df8a06939fbb8ea6dcbae576d96a -size 403069 +oid sha256:42257e94061a1b5c24c11978c0464ba3d8a1495887ea8047e70e39578da1c47a +size 251507 diff --git a/resources/[ERS]/night_ers/stream/[Stretcher]/stretcher.yft b/resources/[ERS]/night_ers/stream/[Stretcher]/stretcher.yft index 7a6293679..fdb885c9e 100644 --- a/resources/[ERS]/night_ers/stream/[Stretcher]/stretcher.yft +++ b/resources/[ERS]/night_ers/stream/[Stretcher]/stretcher.yft @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:44a176866171d5f5466ca7b355552d99585c8af3387f61879412af898107943d -size 10107862 +oid sha256:9d2a4a489f095eab9c1baf6073285021bf3f7956d711ad05faec9a42de10a584 +size 5925533 diff --git a/resources/[ERS]/night_ers/stream/[Stretcher]/stretcher_hi.yft b/resources/[ERS]/night_ers/stream/[Stretcher]/stretcher_hi.yft index f903ca75d..ae8d0a855 100644 --- a/resources/[ERS]/night_ers/stream/[Stretcher]/stretcher_hi.yft +++ b/resources/[ERS]/night_ers/stream/[Stretcher]/stretcher_hi.yft @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2de3e83ab6de0c92aac121277fe8de143552e38ed2f17302e8aace2d20ff8be3 -size 10578950 +oid sha256:9aac15c3a19a8e03ff99cb6c88bf2d245dbe118d9c09d6955687346c7f6e7584 +size 5925533 diff --git a/resources/[ERS]/night_ers_k9/.fxap b/resources/[ERS]/night_ers_k9/.fxap index 9f04d76b4..7262b1378 100644 Binary files a/resources/[ERS]/night_ers_k9/.fxap and b/resources/[ERS]/night_ers_k9/.fxap differ diff --git a/resources/[ERS]/night_ers_k9/NUI/main.js b/resources/[ERS]/night_ers_k9/NUI/main.js index b299301ab..c42f70058 100644 --- a/resources/[ERS]/night_ers_k9/NUI/main.js +++ b/resources/[ERS]/night_ers_k9/NUI/main.js @@ -1,72 +1,4 @@ -let crosshairElement = null; -let translations = null; -let hotkeys = null; - -window.addEventListener('message', (event) => { - const data = event.data; - - if (data.action == "setTranslations") { - translations = data.translations; - } - - if (data.action == "setHotkeys") { - hotkeys = data.hotkeys; - } - - if (data.action == "drawCrosshair") { - let display = data.display; - - // Get the crosshair element - if (!crosshairElement) { - crosshairElement = document.getElementById('crosshair'); - if (!crosshairElement) { - console.log("Crosshair element not found!"); - return; - } - } - - // Set display style directly - crosshairElement.style.display = display ? 'block' : 'none'; - } - - if (data.action == "ped-controls") { - let display = data.display; - togglePedControlsVisibility(display); - } - - if (data.action == "vehicle-controls") { - let display = data.display; - toggleVehicleControlsVisibility(display); - } -}); - - -function togglePedControlsVisibility(visible) { - const controls = document.getElementById('ped-controls'); - if (controls) { - if (visible === undefined) { - isPedControlsVisible = !isPedControlsVisible; - } else { - isPedControlsVisible = visible; - } - - if (isPedControlsVisible) { - controls.classList.remove('animate-fade-out'); - controls.classList.add('animate-fade-in'); - controls.style.display = 'block'; - } else { - controls.classList.remove('animate-fade-in'); - controls.classList.add('animate-fade-out'); - setTimeout(() => { - controls.style.display = 'none'; - }, 250); - } - } else { - // Build the element - const pedControlsElement = document.createElement('div'); - pedControlsElement.id = 'ped-controls'; - pedControlsElement.classList.add('fixed', 'bottom-16', 'right-16', 'z-10', 'inline-block', 'text-white', 'bg-gray-900', 'bg-opacity-50', 'border', 'border-gray-700', 'rounded-lg', 'shadow-lg', 'w-[600px]', 'transition-all', 'duration-300', 'opacity-100'); - pedControlsElement.innerHTML = ` +let crosshairElement=null,translations=null,hotkeys=null;function togglePedControlsVisibility(s){let t=document.getElementById("ped-controls");if(t)(isPedControlsVisible=void 0===s?!isPedControlsVisible:s)?(t.classList.remove("animate-fade-out"),t.classList.add("animate-fade-in"),t.style.display="block"):(t.classList.remove("animate-fade-in"),t.classList.add("animate-fade-out"),setTimeout(()=>{t.style.display="none"},250));else{let e=document.createElement("div");e.id="ped-controls",e.classList.add("fixed","bottom-16","right-16","z-10","inline-block","text-white","bg-gray-900","bg-opacity-50","border","border-gray-700","rounded-lg","shadow-lg","w-[600px]","transition-all","duration-300","opacity-100"),e.innerHTML=`
@@ -109,42 +41,7 @@ function togglePedControlsVisibility(visible) {
- `; - - // Append the element to the body - document.body.appendChild(pedControlsElement); - - // Toggle the visibility of the element - togglePedControlsVisibility(visible); - } -} - -function toggleVehicleControlsVisibility(visible) { - const controls = document.getElementById('vehicle-controls'); - if (controls) { - if (visible === undefined) { - isVehicleControlsVisible = !isVehicleControlsVisible; - } else { - isVehicleControlsVisible = visible; - } - - if (isVehicleControlsVisible) { - controls.classList.remove('animate-fade-out'); - controls.classList.add('animate-fade-in'); - controls.style.display = 'block'; - } else { - controls.classList.remove('animate-fade-in'); - controls.classList.add('animate-fade-out'); - setTimeout(() => { - controls.style.display = 'none'; - }, 250); - } - } else { - // Build the element - const vehicleControlsElement = document.createElement('div'); - vehicleControlsElement.id = 'vehicle-controls'; - vehicleControlsElement.classList.add('fixed', 'bottom-16', 'right-16', 'z-10', 'inline-block', 'text-white', 'bg-gray-900', 'bg-opacity-50', 'border', 'border-gray-700', 'rounded-lg', 'shadow-lg', 'w-[600px]', 'transition-all', 'duration-300', 'opacity-100'); - vehicleControlsElement.innerHTML = ` + `,document.body.appendChild(e),togglePedControlsVisibility(s)}}function toggleVehicleControlsVisibility(s){let t=document.getElementById("vehicle-controls");if(t)(isVehicleControlsVisible=void 0===s?!isVehicleControlsVisible:s)?(t.classList.remove("animate-fade-out"),t.classList.add("animate-fade-in"),t.style.display="block"):(t.classList.remove("animate-fade-in"),t.classList.add("animate-fade-out"),setTimeout(()=>{t.style.display="none"},250));else{let e=document.createElement("div");e.id="vehicle-controls",e.classList.add("fixed","bottom-16","right-16","z-10","inline-block","text-white","bg-gray-900","bg-opacity-50","border","border-gray-700","rounded-lg","shadow-lg","w-[600px]","transition-all","duration-300","opacity-100"),e.innerHTML=`
@@ -177,12 +74,4 @@ function toggleVehicleControlsVisibility(visible) {
- `; - - // Append the element to the body - document.body.appendChild(vehicleControlsElement); - - // Toggle the visibility of the element - toggleVehicleControlsVisibility(visible); - } -} \ No newline at end of file + `,document.body.appendChild(e),toggleVehicleControlsVisibility(s)}}window.addEventListener("message",s=>{let t=s.data;if("setTranslations"==t.action&&(translations=t.translations),"setHotkeys"==t.action&&(hotkeys=t.hotkeys),"drawCrosshair"==t.action){let e=t.display;if(!crosshairElement&&!(crosshairElement=document.getElementById("crosshair"))){console.log("Crosshair element not found!");return}crosshairElement.style.display=e?"block":"none"}"ped-controls"==t.action&&togglePedControlsVisibility(t.display),"vehicle-controls"==t.action&&toggleVehicleControlsVisibility(t.display)}); \ No newline at end of file diff --git a/resources/[ERS]/night_ers_k9/client/client.lua b/resources/[ERS]/night_ers_k9/client/client.lua index ff0555268..f3c11ffbf 100644 Binary files a/resources/[ERS]/night_ers_k9/client/client.lua and b/resources/[ERS]/night_ers_k9/client/client.lua differ diff --git a/resources/[ERS]/night_ers_k9/client/client_k9handler.lua b/resources/[ERS]/night_ers_k9/client/client_k9handler.lua index 9b8b187d4..6044f7c0d 100644 Binary files a/resources/[ERS]/night_ers_k9/client/client_k9handler.lua and b/resources/[ERS]/night_ers_k9/client/client_k9handler.lua differ diff --git a/resources/[ERS]/night_ers_k9/config/config.lua b/resources/[ERS]/night_ers_k9/config/config.lua index 6624d22c6..cc19c3eb7 100644 --- a/resources/[ERS]/night_ers_k9/config/config.lua +++ b/resources/[ERS]/night_ers_k9/config/config.lua @@ -1,6 +1,6 @@ Config = { - ConfigVersion = "1.1.4", + ConfigVersion = "1.0.0", --====================== DEVELOPER SETTINGS ======================-- @@ -44,106 +44,10 @@ Config = { K9Vehicles = { -- Base game vehicle example - { - hash = `policet`, spawnOffset = vector3(0.0 --[[Right/-Left]], -4.0 --[[Front/-Rear]], 0.5 --[[Up/-Down]]), - dogModelName = "a_c_shepherd", - props = { - -- Example: {prop type (Helmet), prop type index (Motorcycle helmet), prop colour index (Black colour)} - -- { drawable, texture, palette } - { 0, 1, 1 }, -- Hats / Helments - { 1, 1, 1 }, -- Glassess - { 2, 1, 1 }, -- Misc - { 3, 1, 1 }, - }, - components = { - -- Example: {component type (Mask), component type index (Clown Mask), component colour index (White colour)} - -- { drawable, texture, palette } - { 1, 1, 1 }, -- Mask - { 2, 1, 1 }, -- Hair - { 3, 1, 1 }, -- Upper body - { 4, 1, 1 }, -- Legs / Pants - { 5, 1, 1 }, -- Bags / Parachutes - { 6, 1, 1 }, -- Shoes - { 7, 1, 1 }, -- Neck / Scarfs - { 8, 1, 1 }, -- Shirt / Accessory (This palette is commonly used for the text on the K9 vest) - { 9, 1, 1 }, -- Body Armor - { 10, 1, 1 }, -- Badges / Logos - { 11, 1, 1 }, -- Jackets - }, - }, + {hash = `policet`, spawnOffset = vector3(0.0 --[[Right/-Left]], -4.0 --[[Front/-Rear]], 0.5 --[[Up/-Down]]), dogModelName = "a_c_shepherd"}, -- Custom vehicle example - { - hash = `forddsumo7`, spawnOffset = vector3(0.0, -4.0, 0.5), - dogModelName = "a_c_shepherd", - props = { - -- Example: {prop type (Helmet), prop type index (Motorcycle helmet), prop colour index (Black colour)} - -- { drawable, texture, palette } - { 0, 1, 1 }, -- Hats / Helments - { 1, 1, 1 }, -- Glassess - { 2, 1, 1 }, -- Misc - { 3, 1, 1 }, - }, - components = { - -- Example: {component type (Mask), component type index (Clown Mask), component colour index (White colour)} - -- { drawable, texture, palette } - { 1, 1, 1 }, -- Mask - { 2, 1, 1 }, -- Hair - { 3, 1, 1 }, -- Upper body - { 4, 1, 1 }, -- Legs / Pants - { 5, 1, 1 }, -- Bags / Parachutes - { 6, 1, 1 }, -- Shoes - { 7, 1, 1 }, -- Neck / Scarfs - { 8, 1, 3 }, -- Shirt / Accessory (This palette is commonly used for the text on the K9 vest) - { 9, 1, 1 }, -- Body Armor - { 10, 1, 1 }, -- Badges / Logos - { 11, 1, 1 }, -- Jackets - }, - }, - { - hash = `forddsumo7`, spawnOffset = vector3(0.0, -4.0, 0.5), - dogModelName = "a_c_shepherd", - props = { - -- Example: {prop type (Helmet), prop type index (Motorcycle helmet), prop colour index (Black colour)} - -- { drawable, texture, palette } - { 0, 1, 1 }, -- Hats / Helments - { 1, 1, 1 }, -- Glassess - { 2, 1, 1 }, -- Misc - { 3, 1, 1 }, - }, - components = { - -- Example: {component type (Mask), component type index (Clown Mask), component colour index (White colour)} - -- { drawable, texture, palette } - { 1, 1, 1 }, -- Mask - { 2, 1, 1 }, -- Hair - { 3, 1, 1 }, -- Upper body - { 4, 1, 1 }, -- Legs / Pants - { 5, 1, 1 }, -- Bags / Parachutes - { 6, 1, 1 }, -- Shoes - { 7, 1, 1 }, -- Neck / Scarfs - { 8, 1, 3 }, -- Shirt / Accessory (This palette is commonly used for the text on the K9 vest) - { 9, 1, 1 }, -- Body Armor - { 10, 1, 1 }, -- Badges / Logos - { 11, 1, 1 }, -- Jackets - }, - }, - - - - - - - - - - - - - - - - -- More examples - -- {hash = `police`, spawnOffset = vector3(0.0, -3.0, 0.5), dogModelName = "a_c_husky"}, + {hash = `forddsumo7`, spawnOffset = vector3(0.0, -4.0, 0.5), dogModelName = "a_c_shepherd"}, {hash = `23gmcleo`, spawnOffset = vector3(0.0, -4.0, 0.5), dogModelName = "a_c_shepherd"}, {hash = `23gmcleoslick`, spawnOffset = vector3(0.0, -4.0, 0.5), dogModelName = "a_c_shepherd"}, {hash = `sahp18tahoe`, spawnOffset = vector3(0.0, -4.0, 0.5), dogModelName = "a_c_shepherd"}, @@ -230,10 +134,10 @@ Config = { {hash = `hp15fpiu2`, spawnOffset = vector3(0.0, -4.0, 0.5), dogModelName = "a_c_shepherd"}, {hash = `hp16fpiu1`, spawnOffset = vector3(0.0, -4.0, 0.5), dogModelName = "a_c_shepherd"}, {hash = `hp16fpiu2`, spawnOffset = vector3(0.0, -4.0, 0.5), dogModelName = "a_c_shepherd"}, - - - - + -- More examples + -- {hash = `police`, spawnOffset = vector3(0.0, -3.0, 0.5), dogModelName = "a_c_husky"}, + -- {hash = `police2`, spawnOffset = vector3(0.0, -3.0, 0.5), dogModelName = "a_c_husky"}, + -- {hash = `police3`, spawnOffset = vector3(0.0, -3.0, 0.5), dogModelName = "a_c_husky"}, }, --====================== CONTROLS, COMMANDS, KEYMAPPING ======================-- diff --git a/resources/[ERS]/night_ers_k9/fxmanifest.lua b/resources/[ERS]/night_ers_k9/fxmanifest.lua index f9a9c9f79..78e1d847f 100644 --- a/resources/[ERS]/night_ers_k9/fxmanifest.lua +++ b/resources/[ERS]/night_ers_k9/fxmanifest.lua @@ -4,7 +4,7 @@ games { 'gta5' } author 'Night' description 'Nights Software - K9 Dog Handlers FiveM' -version '1.1.4' +version '1.1.3' lua54 'yes' shared_scripts { diff --git a/resources/[ERS]/night_ers_k9/server/server.lua b/resources/[ERS]/night_ers_k9/server/server.lua index 07624a095..c7aadbca8 100644 Binary files a/resources/[ERS]/night_ers_k9/server/server.lua and b/resources/[ERS]/night_ers_k9/server/server.lua differ diff --git a/resources/[ERS]/night_prop_system/.fxap b/resources/[ERS]/night_prop_system/.fxap index 2994113cc..56d2dcd66 100644 Binary files a/resources/[ERS]/night_prop_system/.fxap and b/resources/[ERS]/night_prop_system/.fxap differ diff --git a/resources/[ERS]/night_prop_system/client/client.lua b/resources/[ERS]/night_prop_system/client/client.lua index ee0b089b1..ec4f4e2c2 100644 Binary files a/resources/[ERS]/night_prop_system/client/client.lua and b/resources/[ERS]/night_prop_system/client/client.lua differ diff --git a/resources/[ERS]/night_prop_system/server/server.lua b/resources/[ERS]/night_prop_system/server/server.lua index 36f929c8c..f6f7fb5df 100644 Binary files a/resources/[ERS]/night_prop_system/server/server.lua and b/resources/[ERS]/night_prop_system/server/server.lua differ