diff --git a/.gitea/workflows/create-testing-snapshot.yaml b/.gitea/workflows/create-testing-snapshot.yaml new file mode 100644 index 0000000..5fb5877 --- /dev/null +++ b/.gitea/workflows/create-testing-snapshot.yaml @@ -0,0 +1,71 @@ +name: Generate testing snapshot +on: + push: + branches: [develop] + +jobs: + Clean: + name: Create testing release + runs-on: windows + steps: + - name: Diagnostics + run: | + echo "repository: ${{ gitea.repository }}" + echo "ref: ${{ gitea.ref }}" + echo "ref_name: ${{ gitea.ref_name }}" + echo "sha: ${{ gitea.sha }}" + echo "api_url: ${{ gitea.api_url }}" + echo "workflow: ${{ gitea.workflow }}" + + - name: Checkout framework + uses: actions/checkout@v3 + with: + path: MissionFramework + + - name: Clean framework + run: | + Remove-Item -Recurse MissionFramework\aaFrameworkUtils + Remove-Item -Recurse MissionFramework\framework\x + Remove-Item -Recurse MissionFramework\.git* + + - name: Backup artifacts from runner + uses: actions/upload-artifact@v3 + with: + name: framework-test-snapshot + path: MissionFramework + + - name: Create archive + run: Compress-Archive MissionFramework framework-test-snapshot.zip + + - name: Delete old testing-release release + run: | + $headers = @{ + "accept" = "application/json" + "Authorization" = "token ${{secrets.RELEASE_TOKEN}}" + } + Invoke-WebRequest -Uri "${{ gitea.api_url }}/repos/${{ gitea.repository }}/releases/tags/testing-release" -Method Delete -Headers $headers + + - name: Delete old testing-release tag + run: | + $headers = @{ + "accept" = "application/json" + "Authorization" = "token ${{secrets.RELEASE_TOKEN}}" + } + Invoke-WebRequest -Uri "${{ gitea.api_url }}/repos/${{ gitea.repository }}/tags/testing-release" -Method Delete -Headers $headers + + - name: Create new testing-release tag + run: | + $headers = @{ + "accept" = "application/json" + "Authorization" = "token ${{secrets.RELEASE_TOKEN}}" + } + Invoke-WebRequest -Uri "${{ gitea.api_url }}/repos/${{ gitea.repository }}/tags" -Method Post -Headers $headers -ContentType "application/json" -Body "{`"message`": `"testing-release`", `"tag_name`": `"testing-release`", `"target`": `"${{ gitea.sha }}`"}" + + - name: Create new testing-release + uses: https://gitea.com/actions/gitea-release-action@v1.1.6 + with: + tag_name: 'testing-release' + name: 'testing-release' + prerelease: true + files: |- + framework-test-snapshot.zip diff --git a/custom_leaflets.hpp b/custom_leaflets.hpp new file mode 100644 index 0000000..8caadd4 --- /dev/null +++ b/custom_leaflets.hpp @@ -0,0 +1,39 @@ +// This contains custom definitions for leaflets. It is not required to set this up, but you're welcome to if you want to use them. + +// To use this, configure one or more of the below. Then use the pylon editor of a drone in EDEN to add the appropriate magazine type (like 1Rnd_Leaflets_Custom_01_F) to the drone. Then, when the drone is flying, do `drone1 fire "1Rnd_Leaflets_Custom_01_F";` to drop the leaflets. The leaflet will then be shown in the world, and can be picked up by players to read the text and see the image. + +class Custom_01 // configuration for 1Rnd_Leaflets_Custom_01_F +{ + text = "Leaflet text"; // text shown when previewing the leaflet full-screen. Ideally should be localized, so even player who cannot read the image can get the information + texture = "images\leaflets\leaflet_custom_01.paa"; // leaflet texture shown when previewing the leaflet full-screen +}; + +class Custom_02 // configuration for 1Rnd_Leaflets_Custom_02_F +{ + text = "Leaflet text"; // text shown when previewing the leaflet full-screen. Ideally should be localized, so even player who cannot read the image can get the information + texture = "images\leaflets\leaflet_custom_02.paa"; // leaflet texture shown when previewing the leaflet full-screen +}; + +class Custom_03 // configuration for 1Rnd_Leaflets_Custom_03_F +{ + text = "Leaflet text"; // text shown when previewing the leaflet full-screen. Ideally should be localized, so even player who cannot read the image can get the information + texture = "images\leaflets\leaflet_custom_03.paa"; // leaflet texture shown when previewing the leaflet full-screen +}; + +class Custom_04 // configuration for 1Rnd_Leaflets_Custom_04_F +{ + text = "Leaflet text"; // text shown when previewing the leaflet full-screen. Ideally should be localized, so even player who cannot read the image can get the information + texture = "images\leaflets\leaflet_custom_04.paa"; // leaflet texture shown when previewing the leaflet full-screen +}; + +class Custom_05 // configuration for 1Rnd_Leaflets_Custom_05_F +{ + text = "Leaflet text"; // text shown when previewing the leaflet full-screen. Ideally should be localized, so even player who cannot read the image can get the information + texture = "images\leaflets\leaflet_custom_05.paa"; // leaflet texture shown when previewing the leaflet full-screen +}; + +class Custom_06 // configuration for 1Rnd_Leaflets_Custom_06_F +{ + text = "Leaflet text"; // text shown when previewing the leaflet full-screen. Ideally should be localized, so even player who cannot read the image can get the information + texture = "images\leaflets\leaflet_custom_06.paa"; // leaflet texture shown when previewing the leaflet full-screen +}; \ No newline at end of file diff --git a/custom_scripts.hpp b/custom_scripts.hpp new file mode 100644 index 0000000..8b9b928 --- /dev/null +++ b/custom_scripts.hpp @@ -0,0 +1,11 @@ +// This file's contents will be included in the mission's CfgFunctions section, and serves to give you a place to define custom functions from files you've placed in /scripts. + +class milsim_scripts { + class functions { + file = "scripts"; + // Add your custom functions here, like so: + // class init {postInit = 1;}; // refers to scripts/fn_init.sqf. postInit=1 means it will be run on each machine when they're done loading the mission. + // class customFunction1 {}; // refers to the file scripts/fn_customFunction1.sqf, and is called as milsim_scripts_fnc_customFunction1 + // class customFunction2 {}; // refers to the file scripts/fn_customFunction2.sqf, and is called as milsim_scripts_fnc_customFunction2 + }; +}; \ No newline at end of file diff --git a/defines/SupplyCrates.hpp b/defines/SupplyCrates.hpp index 51245fd..9bf50cd 100644 --- a/defines/SupplyCrates.hpp +++ b/defines/SupplyCrates.hpp @@ -21,18 +21,14 @@ class SupplyCrates { {"rhsusf_200Rnd_556x45_mixed_soft_pouch_coyote",25}, {"rhsusf_20Rnd_762x51_m993_Mag",25}, {"SmokeShell",12}, - {"rhs_mag_m67",12}, + {"rhs_mag_m67",24}, {"1Rnd_Smoke_Grenade_shell",24}, {"1Rnd_SmokeRed_Grenade_shell",24}, {"1Rnd_SmokeGreen_Grenade_shell",24}, {"1Rnd_SmokeYellow_Grenade_shell",12}, {"Tier1_30Rnd_556x45_M856A1_EMag",25}, - {"Tier1_30Rnd_556x45_Mk318Mod0_EMag",75}, - {"ACE_30Rnd_65_Creedmor_mag",25}, + {"ACE_30Rnd_556x45_Stanag_M995_AP_mag",75}, {"SMA_30Rnd_762x35_BLK_EPR",25}, - {"Tier1_30Rnd_762x35_300BLK_SMK_PMAG",25}, - {"SMA_30Rnd_68x43_SPC_FMJ",25}, - {"SMA_30Rnd_68x43_SPC_FMJ_Tracer",25}, {"SMA_20Rnd_762x51mm_M80A1_EPR",25}, {"SMA_20Rnd_762x51mm_M80A1_EPR_Tracer",25}, {"SMA_20Rnd_762x51mm_Mk316_Mod_0_Special_Long_Range",25}, @@ -42,8 +38,6 @@ class SupplyCrates { {"ACE_20Rnd_762x51_M993_AP_Mag",25}, {"rhsusf_20Rnd_762x51_SR25_m993_Mag",25}, {"Tier1_20Rnd_762x51_M993_SR25_Mag",25}, - {"Tier1_20Rnd_65x48_Creedmoor_SR25_Mag",25}, - {"rhssaf_30rnd_556x45_EPR_G36", 25}, {"DemoCharge_Remote_Mag",16} }; items[] = {}; @@ -56,13 +50,15 @@ class SupplyCrates { icon = "\A3\ui_f\data\map\vehicleicons\iconCrateWpns_ca.paa"; backpacks[] = {}; - weapons[] = {}; + weapons[] = { + {"launch_MRAWS_green_F",2} + }; magazines[] = { {"MRAWS_HEAT_F",35}, {"MRAWS_HE_F",15}, {"Tier1_250Rnd_762x51_Belt_M993_AP",50}, {"Tier1_30Rnd_556x45_M856A1_EMag",25}, - {"Tier1_30Rnd_556x45_Mk318Mod0_EMag",50}, + {"ACE_30Rnd_556x45_Stanag_M995_AP_mag",50}, {"Titan_AA",10}, {"Titan_AT",10}, {"200Rnd_65x39_cased_Box_Tracer_Red",50} @@ -168,12 +164,15 @@ class SupplyCrates { icon = "\A3\ui_f\data\igui\cfg\simpleTasks\types\scout_ca.paa"; backpacks[] = {}; - weapons[] = {}; + weapons[] = { + {"rhs_weap_M136",2}, + {"twc_2inch_bag",3} + }; magazines[] = { {"twc_2inch_he_1rnd",70}, {"twc_2inch_smoke_1rnd",15}, {"twc_2inch_illum_1rnd",15}, - {"Tier1_30Rnd_556x45_Mk318Mod0_EMag",20} + {"ACE_30Rnd_556x45_Stanag_M995_AP_mag",20} }; items[] = {}; }; diff --git a/description.ext b/description.ext index b23393f..1efe1da 100644 --- a/description.ext +++ b/description.ext @@ -89,15 +89,16 @@ minPlayerDistance = 500; //-------------------------------------------BASE SETTINGS---------------------------------------------------------------// -class Params -{ +class Params {}; + +class CfgFunctions { + #include "framework\CfgFunctions.hpp" + #include "custom_scripts.hpp" }; - -// CfgFunctions -#include "framework\CfgFunctions.hpp" - - +class CfgLeaflets { + #include "custom_leaflets.hpp" +}; class CfgDebriefingSections { class acex_killTracker { diff --git a/framework/CfgFunctions.hpp b/framework/CfgFunctions.hpp index bfe7d28..744bea3 100644 --- a/framework/CfgFunctions.hpp +++ b/framework/CfgFunctions.hpp @@ -1,180 +1,188 @@ #include "script_mod.hpp" -class CfgFunctions { - - class DOUBLES(PREFIX,init) { - class functions { - file = "framework\init\functions"; - class initServer { postInit = 1;}; - class initClient { postInit = 1;}; - class setDefaults { postInit = 1; }; - class addAARChatHandler { postInit = 1; }; - class addRespawnChatHandler { postInit = 1; }; - }; +class DOUBLES(PREFIX,init) { + class functions { + file = "framework\init\functions"; + class initServer { postInit = 1;}; + class initClient { postInit = 1;}; + class setDefaults {}; + class addAARChatHandler {}; + class addRespawnChatHandler {}; + class checkMissionSettings {}; }; - - class PREFIX { - class ambience { - file = "framework\ambience"; - class flakInitVehicle {}; - class flakEH {}; - }; +}; + +class PREFIX { + class ambience { + file = "framework\ambience"; + class flakInitVehicle {}; + class flakEH {}; }; +}; - class DOUBLES(PREFIX,client) { - class functions { - file = "framework\client\functions"; - class bindEmptyGroupGarbageCleanup { postInit = 1; }; - class bindEventHandlers { postInit = 1; }; - class bindVehicleActions { postInit = 1; }; - class addZenModules {postInit = 1;}; - }; +class DOUBLES(PREFIX,client) { + class functions { + file = "framework\client\functions"; + class initClient {}; + class addDraw3DPFH {}; + class addGetNearMenPFH {}; + class addMicroDAGRWaypoints {}; + class addZenModules {}; + class bindEventHandlers {}; + class bindVehicleActions {}; + class clearPFHCode {}; + class logRespawnButtonUse {}; + class registerPFHCode {}; + class staticLineProtection {}; }; +}; - class DOUBLES(PREFIX,common) { - class functions { - file = "framework\common\functions"; - class addCBASettings { preInit = 1; }; - class logMissionInfo {}; - class addPlayerInfoToArray {}; - class createOrUpdateDiaryRecord {}; - class getApprovedAssetsCfg {}; - class getBattalionCfg {}; - class getNameOfBase {}; - class getNearestBase {}; - class log {}; - class checkPlayerInventory {}; - class logSettingChanged {}; - class padString {}; - class recurseSubclasses {}; - }; +class DOUBLES(PREFIX,common) { + class functions { + file = "framework\common\functions"; + class addCBASettings { preInit = 1; }; + class addPlayerInfoToArray {}; + class checkPlayerInventory {}; + class createOrUpdateDiaryRecord {}; + class draw3DIconStatus {}; + class getApprovedAssetsCfg {}; + class getBattalionCfg {}; + class getNameOfBase {}; + class getNearestBase {}; + class log {}; + class logMissionInfo {}; + class logSettingChanged {}; + class padString {}; + class recurseSubclasses {}; }; +}; - class DOUBLES(PREFIX,fbcb2_assets) { - class functions { - file = "framework\fbcb2_assets\functions"; - class addCBASettings {preInit=1;}; - class initServer {}; - class initClient {}; - class getCallsignFromClassname {}; - class getCurrentAssetsByBase {}; - class getInventory {}; - class getMagsForWeapon {}; - class getStartingAndCurrentAssets {}; - class getStartingAssetsByBase {}; - class getVehicleData {}; - class getWeaponry {}; - class hintAllApprovedAssets {}; - class isAssetInRangeOfBase {}; - class removeAssetDiaryRecords {}; - class removeMarkersOnMap {}; - class showMarkersOnMap {}; - class updateAssetDiary {}; - class updateAssetsByBase {}; - }; +class DOUBLES(PREFIX,fbcb2_assets) { + class functions { + file = "framework\fbcb2_assets\functions"; + class addCBASettings {preInit=1;}; + class initServer {}; + class initClient {}; + class getCallsignFromClassname {}; + class getCurrentAssetsByBase {}; + class getInventory {}; + class getMagsForWeapon {}; + class getStartingAndCurrentAssets {}; + class getStartingAssetsByBase {}; + class getVehicleData {}; + class getWeaponry {}; + class hintAllApprovedAssets {}; + class isAssetInRangeOfBase {}; + class removeAssetDiaryRecords {}; + class removeMarkersOnMap {}; + class showMarkersOnMap {}; + class updateAssetDiary {}; + class updateAssetsByBase {}; }; +}; - class DOUBLES(PREFIX,fbcb2_main) { - class functions { - file = "framework\fbcb2_main\functions"; - class initClient {}; - class addEnvironmentRecord {}; - class addFrequenciesRecord {}; - class addSignalColorsRecord {}; - }; - class util { - file = "framework\fbcb2_main\util"; - class formatRadioElementForDiary {}; - class generateElementFrequencyRecordText {}; - }; +class DOUBLES(PREFIX,fbcb2_main) { + class functions { + file = "framework\fbcb2_main\functions"; + class initClient {}; + class addEnvironmentRecord {}; + class addFrequenciesRecord {}; + class addSignalColorsRecord {}; }; - - class DOUBLES(PREFIX,mapcopy) { - class functions { - file = "framework\mapcopy\functions"; - class addCBASettings {preInit=1;}; - class initClient {}; - class getMapMarkers {}; - class loadMapMarkers {}; - class mapMarkerToString {}; - class stringToMapMarker {}; - }; + class util { + file = "framework\fbcb2_main\util"; + class formatRadioElementForDiary {}; + class generateElementFrequencyRecordText {}; }; +}; - class DOUBLES(PREFIX,performance) { - class functions { - file = "framework\performance\functions"; - class addCBASettings {preInit=1;}; - class addDNI_PlayerFPS { postInit = 1; }; - - // PFHs managed in addCBASettings onChange code - class addClientStatsPFH {}; - class calculateClientStats {}; - class addServerStatsPFH {}; - class calculateServerStats {}; - }; +class DOUBLES(PREFIX,mapcopy) { + class functions { + file = "framework\mapcopy\functions"; + class addCBASettings {preInit=1;}; + class initClient {}; + class getMapMarkers {}; + class loadMapMarkers {}; + class mapMarkerToString {}; + class stringToMapMarker {}; }; +}; - class DOUBLES(PREFIX,reinsert) { - class functions { - file = "framework\reinsert\functions"; - class addCBASettings {preInit=1;}; - }; - class server { - file = "framework\reinsert\server"; - class initServer {}; - class addToQueue {}; - class globalShowQueue {}; - class removeFromQueue {}; - class returnReinsertQueueNotification {}; - class validateQueue {}; - }; - class client { - file = "framework\reinsert\client"; - class initClient {}; - class addAceSelfActions {}; - class addCheckQueueSelfAction {}; - class requestShowQueue {}; - }; +class DOUBLES(PREFIX,performance) { + class functions { + file = "framework\performance\functions"; + class addCBASettings {preInit=1;}; + class addDNI_PlayerFPS {postInit = 1;}; + + // PFHs managed in addCBASettings onChange code + class addClientStatsPFH {}; + class calculateClientStats {}; + class addServerStatsPFH {}; + class calculateServerStats {}; + class addEmptyGroupCleanupPFH {}; }; +}; - class DOUBLES(PREFIX,resupply) { - class functions { - file = "framework\resupply\functions"; - class addCBASettings {preInit=1;}; - class initClient {}; - class createBox {}; - class getSupplyCratesCfg {}; - class addArsenalObjectSpawnBoxActions {}; - }; +class DOUBLES(PREFIX,reinsert) { + class functions { + file = "framework\reinsert\functions"; + class addCBASettings {preInit=1;}; }; - - class DOUBLES(PREFIX,triageIcons) { - class functions { - file = "framework\triageIcons\functions"; - class addCBASettings {preInit=1;}; - class initClient {}; - class addDrawIconsPFH {}; - class addGetEntitiesPFH {}; - class updateColors {}; - }; + class server { + file = "framework\reinsert\server"; + class initServer {}; + class addToQueue {}; + class globalShowQueue {}; + class removeFromQueue {}; + class returnReinsertQueueNotification {}; + class validateQueue {}; }; - - class DOUBLES(PREFIX,vehicleFlags) { - class functions { - file = "framework\vehicleFlags\functions"; - class initClient {}; - class getActionsFlagCategories {}; - class getVehicleFlagsCfg {}; - class isClassExcluded {}; - }; + class client { + file = "framework\reinsert\client"; + class initClient {}; + class addAceSelfActions {}; + class addCheckQueueSelfAction {}; + class requestShowQueue {}; }; +}; - class DOUBLES(PREFIX,zeus) { - class functions { - file = "framework\zeus\functions"; - class initClient {}; - class addZenModules {}; - }; +class DOUBLES(PREFIX,resupply) { + class functions { + file = "framework\resupply\functions"; + class addCBASettings {preInit=1;}; + class initClient {}; + class createBox {}; + class getSupplyCratesCfg {}; + class addArsenalObjectSpawnBoxActions {}; + }; +}; + +class DOUBLES(PREFIX,triageIcons) { + class functions { + file = "framework\triageIcons\functions"; + class addCBASettings {preInit=1;}; + class initClient {}; + class draw3D {}; + class updateColors {}; + }; +}; + +class DOUBLES(PREFIX,vehicleFlags) { + class functions { + file = "framework\vehicleFlags\functions"; + class initClient {}; + class addFlagActions {}; + class draw3D {}; + class getActionsFlagCategories {}; + class getVehicleFlagsCfg {}; + class isClassExcluded {}; + }; +}; + +class DOUBLES(PREFIX,zeus) { + class functions { + file = "framework\zeus\functions"; + class initClient {}; + class addZenModules {}; }; }; \ No newline at end of file diff --git a/framework/client/functions/fn_addDraw3DPFH.sqf b/framework/client/functions/fn_addDraw3DPFH.sqf new file mode 100644 index 0000000..8b0626a --- /dev/null +++ b/framework/client/functions/fn_addDraw3DPFH.sqf @@ -0,0 +1,10 @@ +#include "..\script_component.hpp" + + +if (!isNil QGVAR(draw3DPFH)) then { + [GVAR(draw3DPFH)] call CBA_fnc_removePerFrameHandler; +}; +// add pfh that processes queued code +GVAR(draw3DPFH) = [{ + {call _x; true;} count (localNamespace getVariable [QGVAR(pfhCode), []]); +}, 0] call CBA_fnc_addPerFrameHandler; diff --git a/framework/client/functions/fn_addGetNearMenPFH.sqf b/framework/client/functions/fn_addGetNearMenPFH.sqf new file mode 100644 index 0000000..dbad6c5 --- /dev/null +++ b/framework/client/functions/fn_addGetNearMenPFH.sqf @@ -0,0 +1,17 @@ +#include "..\script_component.hpp" + +// subroutine to gather nearest 50 units every 5 seconds and store in GVAR(nearMen) +// cleanup +if (!isNil QGVAR(getNearMenPFH)) then { + [GVAR(getNearMenPFH)] call CBA_fnc_removePerFrameHandler; +}; +// add pfh +GVAR(getNearMenPFH) = [{ + localNamespace setVariable [ + QGVAR(nearMen), + (nearestObjects [player,["Man"],50,false]) select { + !isNull _x && + player isNotEqualTo _x + } + ]; +}, 1] call CBA_fnc_addPerFrameHandler; diff --git a/framework/client/functions/fn_addMicroDAGRWaypoints.sqf b/framework/client/functions/fn_addMicroDAGRWaypoints.sqf new file mode 100644 index 0000000..832bc54 --- /dev/null +++ b/framework/client/functions/fn_addMicroDAGRWaypoints.sqf @@ -0,0 +1,76 @@ +#include "..\script_component.hpp" + +// adds default base locations to players' microDAGR as waypoints + +if (!hasInterface) exitWith {}; + +[{!isNull player}, { + + // add base locations (respawn modules) + { + private _wpName = [_x] call EFUNC(common,getNameOfBase); + private _posASL = getPosASL _x; + [_wpName, _posASL] call ace_microdagr_fnc_deviceAddWaypoint; + } forEach GVARMAIN(baseObjects); + + // add custom waypoints from mission_settings.hpp + private _customWaypoints = [missionConfigFile >> "custom_microdagr_waypoints", "ARRAY", []] call CBA_fnc_getConfigEntry; + { + _x params [ + ["_wpName", ""], + ["_pos", [0, 0, 0], [[], ""]], + ["_object", "", [""]] + ]; + private _realPos = nil; + // if pos was provided, process + if (count _pos >= 2) then { + switch (typeName _pos) do { + case "ARRAY": { + // pos is provided as an array + _realPos = _pos select [0, 2]; + _realPos set [2, getTerrainHeightASL _realPos]; + }; + case "STRING": { + // pos is provided as a string + _realPos = [_pos, true] call ACE_common_fnc_getMapPosFromGrid; + _realPos set [2, getTerrainHeightASL _realPos]; + }; + default { + [ + LEVEL_WARNING, + QUOTE(COMPONENT), + format["Invalid position for custom microDAGR waypoint: %1", _wpName], + [["name", _wpName], ["pos", _pos], ["object", _object]]] call EFUNC(common,log); + continue; + }; + }; + }; + // if object was provided, process and override any pos + if (count _object > 0) then { + // object is provided as a string variable name + private _realObject = missionNamespace getVariable _object; + if (isNull _realObject) then { + [ + LEVEL_WARNING, + QUOTE(COMPONENT), + format["Invalid object for custom microDAGR waypoint: %1", _wpName], + [["name", _wpName], ["pos", _pos], ["object", _object]]] call EFUNC(common,log); + continue; + }; + _realPos = getPosASL (missionNamespace getVariable _object); + }; + if (isNil "_realPos") then { + [ + LEVEL_WARNING, + QUOTE(COMPONENT), + format["Invalid waypoint position for custom microDAGR waypoint: %1", _wpName], + [["name", _wpName], ["pos", _pos], ["object", _object]]] call EFUNC(common,log); + continue; + }; + + [_wpName, _realPos] call ace_microdagr_fnc_deviceAddWaypoint; + true; + } count _customWaypoints; +}] call CBA_fnc_waitUntilAndExecute; + +nil; \ No newline at end of file diff --git a/framework/client/functions/fn_bindEventHandlers.sqf b/framework/client/functions/fn_bindEventHandlers.sqf index 802c2c5..53b2162 100644 --- a/framework/client/functions/fn_bindEventHandlers.sqf +++ b/framework/client/functions/fn_bindEventHandlers.sqf @@ -2,23 +2,6 @@ if ( !hasInterface ) exitWith {}; -player addEventHandler["Respawn", - { - params ["_unit", "_corpse"]; - private _killer = _corpse getVariable ["ace_medical_causeOfDeath", "#scripted"]; - if (_killer == "respawn_button") then { - [ - LEVEL_INFO, - QUOTE(COMPONENT), - "RESPAWNED WHILE UNCONSCIOUS", - [_unit] call EFUNC(common,addPlayerInfoToArray) - ] remoteExec [QEFUNC(common,log), 2]; - // format["%1 was unconscious then clicked the respawn button", name _unit] remoteExec["systemChat", 0]; - }; - } -]; - - [ { params ["_unit", "_object", "_cost"]; diff --git a/framework/client/functions/fn_clearPFHCode.sqf b/framework/client/functions/fn_clearPFHCode.sqf new file mode 100644 index 0000000..08129a5 --- /dev/null +++ b/framework/client/functions/fn_clearPFHCode.sqf @@ -0,0 +1,5 @@ +#include "..\script_component.hpp" + +localNamespace setVariable [QGVAR(pfhCode), []]; + +count []; \ No newline at end of file diff --git a/framework/client/functions/fn_initClient.sqf b/framework/client/functions/fn_initClient.sqf new file mode 100644 index 0000000..b60a487 --- /dev/null +++ b/framework/client/functions/fn_initClient.sqf @@ -0,0 +1,32 @@ +#include "..\script_component.hpp" + + +if (!hasInterface) exitWith {}; + +call FUNC(addMicroDAGRWaypoints); +call FUNC(addZenModules); +call FUNC(bindEventHandlers); +call FUNC(bindVehicleActions); + +// add core getNearMenPFH handler +localNamespace setVariable [QGVAR(nearMen), []]; +call FUNC(addGetNearMenPFH); +// add core draw3dPFH handler +localNamespace setVariable [QGVAR(pfhCode), []]; +call FUNC(addDraw3DPFH); + +// add listener that tracks using the respawn button while unconscious +call FUNC(logRespawnButtonUse); +// add conditional eject-from-vehicle handler to apply temp invincibility when static line jumping +call FUNC(staticLineProtection); + +[ + LEVEL_DEBUG, + QUOTE(COMPONENT), + "initClient complete", + [] +] call EFUNC(common,log); + +localNamespace setVariable [QGVAR(complete), true]; + +nil; \ No newline at end of file diff --git a/framework/client/functions/fn_logRespawnButtonUse.sqf b/framework/client/functions/fn_logRespawnButtonUse.sqf new file mode 100644 index 0000000..ec085e6 --- /dev/null +++ b/framework/client/functions/fn_logRespawnButtonUse.sqf @@ -0,0 +1,56 @@ +#include "..\script_component.hpp" + +if ( !hasInterface ) exitWith {}; + +["ace_killed", { + params ["_unit", "_causeOfDeath", "_killer", "_instigator"]; + + if (not (local _unit)) exitWith {}; + + private _causeOfDeath = _unit getVariable ["ace_medical_causeOfDeath", "#scripted"]; + + if (_causeOfDeath != "respawn_button") exitWith {}; + private _timeWentUnconscious = _unit getVariable [QGVARMAIN(lastTimeKnockedOut), -1]; + private _durationSpentUnconscious = -1; + if (_timeWentUnconscious != -1) then { + _durationSpentUnconscious = diag_tickTime - _timeWentUnconscious; + }; + + [ + LEVEL_INFO, + QUOTE(COMPONENT), + "RESPAWNED WHILE UNCONSCIOUS", + [_unit, [ + ["durationSpentUnconscious", _durationSpentUnconscious] + ]] call EFUNC(common,addPlayerInfoToArray) + ] remoteExec [QEFUNC(common,log), 2]; + // format["%1 was unconscious then clicked the respawn button", name _unit] remoteExec["systemChat", 0]; +}] call CBA_fnc_addEventHandler; + + +["ace_medical_knockOut", { // local event for module & epi event + // systemChat format["ace_medical_knockOut: %1", _this]; + private _unit = _this; + if (not (local _unit)) exitWith {}; + _this setVariable [QGVARMAIN(lastTimeKnockedOut), diag_tickTime]; +}] call CBA_fnc_addEventHandler; + +["ace_medical_WakeUp", { // local event for module & epi event + // systemChat format["ace_medical_WakeUp: %1", _this]; + private _unit = _this; + if (not (local _unit)) exitWith {}; + _this setVariable [QGVARMAIN(lastTimeKnockedOut), nil]; +}] call CBA_fnc_addEventHandler; + +["ace_unconscious", { // used when applying damage + params ["_unit", "_isUnconscious"]; + if (not (local _unit)) exitWith {}; + + if (_isUnconscious && isNil {_unit getVariable QGVARMAIN(lastTimeKnockedOut)}) then { + // systemChat format["%1 is unconscious", _unit]; + _unit setVariable [QGVARMAIN(lastTimeKnockedOut), diag_tickTime]; + } else { + // systemChat format["%1 is conscious", _unit]; + _unit setVariable [QGVARMAIN(lastTimeKnockedOut), nil]; + }; +}] call CBA_fnc_addEventHandler; \ No newline at end of file diff --git a/framework/client/functions/fn_registerPFHCode.sqf b/framework/client/functions/fn_registerPFHCode.sqf new file mode 100644 index 0000000..990dfec --- /dev/null +++ b/framework/client/functions/fn_registerPFHCode.sqf @@ -0,0 +1,9 @@ +#include "..\script_component.hpp" + +params [["_code", {}, [{}]]]; + +private _pfhCode = localNamespace getVariable [QGVAR(pfhCode), []]; +_pfhCode pushBack _code; +localNamespace setVariable [QGVAR(pfhCode), _pfhCode]; + +count _pfhCode; \ No newline at end of file diff --git a/framework/client/functions/fn_staticLineProtection.sqf b/framework/client/functions/fn_staticLineProtection.sqf new file mode 100644 index 0000000..7d562f3 --- /dev/null +++ b/framework/client/functions/fn_staticLineProtection.sqf @@ -0,0 +1,40 @@ +#include "..\script_component.hpp" + +if ( !hasInterface ) exitWith {}; + +// Add GetOutMan event handler to grant temporary invincibility to players ejecting from vehicles +// Only for players who have "hooked up" using VS static line +// and are ejecting from a plane or helicopter above 100m +player addEventHandler ["GetOutMan", { + params ["_unit", "_role", "_vehicle", "_turret", "_isEject"]; + if (!isEject) exitWith {}; + if (isNil {_unit getVariable "VS_Jump"}) exitWith {}; + if ( + not (_vehicle isKindOf "Plane" || _vehicle isKindOf "Helicopter") || + ((getPosATL _vehicle)#2) < 100 + ) exitWith {}; + + // disable damage for the unit to avoid collision damage + _unit allowDamage false; + // tested - vehicle _unit is the _unit, as this EH runs when they have left the vehicle + + + [ + {!isNull (objectParent _this)}, // condition - wait until player re-enters vehicle (chute) + { + // if they enter a chute within 5 seconds, disable chute damage + (vehicle _this) allowDamage false; + // then wait X seconds and re-enable damage for both + [{ + _this allowDamage true; + (vehicle _this) allowDamage true; + }, _this, 5] call CBA_fnc_waitAndExecute; + }, + _unit, // args + 2, // timeout + { // run on timeout, if for some reason they don't enter a chute + // re-enable damage for unit + _this allowDamage true; + } + ] call CBA_fnc_waitUntilAndExecute; +}]; \ No newline at end of file diff --git a/framework/common/functions/fn_draw3DIconStatus.sqf b/framework/common/functions/fn_draw3DIconStatus.sqf new file mode 100644 index 0000000..a697632 --- /dev/null +++ b/framework/common/functions/fn_draw3DIconStatus.sqf @@ -0,0 +1,54 @@ +#include "..\script_component.hpp" + +if (!hasInterface) exitWith {}; + +params [ + ["_drawTargets", [], [[]]], + ["_icon", "", [""]], + ["_text", "", [""]], + ["_color", [], [[]]] +]; + +if (count _drawTargets isEqualTo 0) exitWith {}; + +_cameraPos = positionCameraToWorld [0,0,0]; +_cameraPosASL = AGLToASL _cameraPos; + +{ + _target = _x; + _visible = [objNull, "VIEW"] checkVisibility [_cameraPosASL, eyePos _target]; + + if ( _visible isEqualTo 0 ) exitWith {}; + + _objectPos = (_target modelToWorldVisual (_target selectionPosition "pilot")); + _distance = (visiblePosition _target) vectorDiff _cameraPos; + + _scale = 0; + _heightOffset = 0; + _heightScaling = 0.012; + + if ( _icon isNotEqualTo "") then { + _heightOffset = 0.065; + _scale = 1; + _heightScaling = 0.075; + }; + + _drawPos = _objectPos vectorAdd [0, 0, (0.18 + _heightOffset) + (vectorMagnitude _distance * _heightScaling)]; + + drawIcon3D [ + _icon, + _color, + _drawPos, + _scale, + _scale, + 0, + _text, + 2, + 0.025 + ]; + + true; +} count _drawTargets; + +nil + diff --git a/framework/common/functions/fn_log.sqf b/framework/common/functions/fn_log.sqf index 716c0df..11487e6 100644 --- a/framework/common/functions/fn_log.sqf +++ b/framework/common/functions/fn_log.sqf @@ -24,10 +24,10 @@ if (_logLevel < DEBUG_MODE) exitWith {}; private _hash = createHashMapFromArray _data; // Replace square brackets with round brackets to avoid parsing issues. -_message regexReplace ['(\[)', "("]; -_message regexReplace ['(\])', ")"]; +[_message, "]", ")"] call CBA_fnc_replace; +[_message, "[", "("] call CBA_fnc_replace; private _json = [_hash] call CBA_fnc_encodeJSON; -_log = format ["[%1] [%2] [%3] [%4] :: %5", QUOTE(PREFIX), _component, _fnc_scriptNameParent, _message, _json]; +private _log = format ["[%1] [%2] [%3] [%4] :: %5", QUOTE(PREFIX), _component, _fnc_scriptNameParent, _message, _json]; diag_log text _log; \ No newline at end of file diff --git a/framework/init/functions/fn_addAARChatHandler.sqf b/framework/init/functions/fn_addAARChatHandler.sqf index 10f3979..88d5703 100644 --- a/framework/init/functions/fn_addAARChatHandler.sqf +++ b/framework/init/functions/fn_addAARChatHandler.sqf @@ -1,5 +1,7 @@ #include "..\script_component.hpp" +if (!hasInterface) exitWith {}; + [ "saveaar", { diff --git a/framework/init/functions/fn_addRespawnChatHandler.sqf b/framework/init/functions/fn_addRespawnChatHandler.sqf index 6e4c22f..cfb06d3 100644 --- a/framework/init/functions/fn_addRespawnChatHandler.sqf +++ b/framework/init/functions/fn_addRespawnChatHandler.sqf @@ -1,17 +1,27 @@ #include "..\script_component.hpp" +if (!hasInterface) exitWith {}; + [ "respawn", { _clientID = _thisArgs select 0; player setDamage 1; + private _timeWentUnconscious = player getVariable [QGVARMAIN(lastTimeKnockedOut), -1]; + private _durationSpentUnconscious = -1; + if (_timeWentUnconscious > - 1) then { + _durationSpentUnconscious = diag_tickTime - _timeWentUnconscious; + }; + // log to server RPT [ LEVEL_INFO, QUOTE(COMPONENT), "CHAT COMMAND RESPAWN", - [player] call EFUNC(common,addPlayerInfoToArray) + [player, [ + ["durationSpentUnconscious", _durationSpentUnconscious] + ]] call EFUNC(common,addPlayerInfoToArray) ] remoteExec [QEFUNC(common,log), 2]; // systemChat to all remote machines diff --git a/framework/init/functions/fn_checkMissionSettings.sqf b/framework/init/functions/fn_checkMissionSettings.sqf new file mode 100644 index 0000000..fa017d5 --- /dev/null +++ b/framework/init/functions/fn_checkMissionSettings.sqf @@ -0,0 +1,41 @@ +#include "..\script_component.hpp" + +if (!hasInterface || !is3DENPreview) exitWith {}; + +private _warningText = []; + +if (getText(missionConfigFile >> "author") in ["MISSION AUTHOR", ""]) then { + _warningText pushBack "mission_settings\author is blank or default!"; +}; +if (getText(missionConfigFile >> "onLoadName") in ["THIS APPEARS ON TOP OF THE LOADING SCREEN IMAGE", ""]) then { + _warningText pushBack "mission_settings\onLoadName is blank or default!"; +}; + +if (getText(missionConfigFile >> "briefingName") in ["THIS IS THE NAME ON THE #MISSIONS LIST", ""]) then { + _warningText pushBack "mission_settings\briefingName is blank or default!"; +}; +if (getText(missionConfigFile >> "overviewText") in ["THIS IS WHERE YOU DESCRIBE THE MISSION IN THE #MISSION LIST", ""]) then { + _warningText pushBack "mission_settings\overviewText is blank or default!"; +}; + +if (getText(missionConfigFile >> "missionSeries") in ["MY SERIES NAME", ""]) then { + _warningText pushBack "mission_settings\missionSeries is blank or default!"; +}; + +if (count GVARMAIN(baseObjects) isEqualTo 0) then { + _warningText pushBack "No respawn points placed!"; +}; + +if (count _warningText > 0) then { + [{ + if (isNull (call BIS_fnc_displayMission)) exitWith {}; + + (_this#0) spawn { + [_this joinString "
", "Issues found!", true, false] call BIS_fnc_guiMessage; + }; + [_this#1] call CBA_fnc_removePerFrameHandler; + + }, 1, _warningText] call CBA_fnc_addPerFrameHandler; +}; + +nil; \ No newline at end of file diff --git a/framework/init/functions/fn_initClient.sqf b/framework/init/functions/fn_initClient.sqf index 6e82106..8f09921 100644 --- a/framework/init/functions/fn_initClient.sqf +++ b/framework/init/functions/fn_initClient.sqf @@ -1,19 +1,17 @@ #include "..\script_component.hpp" -if ( !hasInterface ) exitWith {}; - -["milsim_logText", { - params [["_strArray", [""], [[]]]]; - { - diag_log text _x; - } forEach _strArray; -}] call CBA_fnc_addEventHandler; +if (!hasInterface) exitWith {}; // make sure the server has finished init waitUntil {!isNil QGVARMAIN(complete)}; ["InitializePlayer", [player, true]] call BIS_fnc_dynamicGroups; +// run primary init functions +call FUNC(addAARChatHandler); +call FUNC(addRespawnChatHandler); +call FUNC(setDefaults); + // Initialize a holder for managing local diary records // store records in format: // [subject, [ @@ -23,6 +21,7 @@ EGVAR(common,diaryRecords) = createHashMap; // initialize other modules +call EFUNC(client,initClient); call EFUNC(mapcopy,initClient); call EFUNC(reinsert,initClient); call EFUNC(resupply,initClient); @@ -33,6 +32,8 @@ call EFUNC(fbcb2_main,initClient); call EFUNC(fbcb2_assets,initClient); +call FUNC(checkMissionSettings); + [ LEVEL_DEBUG, QUOTE(COMPONENT), diff --git a/framework/init/functions/fn_initServer.sqf b/framework/init/functions/fn_initServer.sqf index 84e2666..c40180e 100644 --- a/framework/init/functions/fn_initServer.sqf +++ b/framework/init/functions/fn_initServer.sqf @@ -9,16 +9,6 @@ publicVariable QGVARMAIN(baseObjects); // Initializes the Dynamic Groups framework and groups ["Initialize", [true]] call BIS_fnc_dynamicGroups; -if (isDedicated) then { - ["milsim_logText", { - params [["_strArray", [""], [[]]]]; - { - diag_log text _x; - } forEach _strArray; - }] call CBA_fnc_addEventHandler; -}; - - // initialize other modules call EFUNC(common,logMissionInfo); call EFUNC(fbcb2_assets,initServer); diff --git a/framework/init/functions/fn_setDefaults.sqf b/framework/init/functions/fn_setDefaults.sqf index 45a18d3..6bd43f8 100644 --- a/framework/init/functions/fn_setDefaults.sqf +++ b/framework/init/functions/fn_setDefaults.sqf @@ -1,5 +1,7 @@ #include "..\script_component.hpp" +if (!hasInterface) exitWith {}; + enableSaving[false, false]; enableRadio false; diff --git a/framework/mapcopy/functions/fn_initClient.sqf b/framework/mapcopy/functions/fn_initClient.sqf index 3287103..51c4304 100644 --- a/framework/mapcopy/functions/fn_initClient.sqf +++ b/framework/mapcopy/functions/fn_initClient.sqf @@ -10,6 +10,9 @@ private _mapCopyAction = "\a3\ui_f\data\igui\cfg\actions\talk_ca.paa", { params ["_target", "_player", "_params"]; + if (!isPlayer _target) exitWith { + format["%1 is not a player", name _target] call CBA_fnc_notify; + }; format["Copying map markers from %1", name _target] call CBA_fnc_notify; [QGVAR(mapCopyRequest), _this, _target] call CBA_fnc_targetEvent; }, diff --git a/framework/performance/functions/fn_addCBASettings.sqf b/framework/performance/functions/fn_addCBASettings.sqf index 405e72c..947c1cb 100644 --- a/framework/performance/functions/fn_addCBASettings.sqf +++ b/framework/performance/functions/fn_addCBASettings.sqf @@ -1,5 +1,27 @@ #include "..\script_component.hpp" +[ + QGVAR(emptyGroupCleanup_enable), + "CHECKBOX", + "Empty Group Cleanup Enabled", + [QUOTE(SETTINGS_GROUP_NAME), QUOTE(COMPONENT_BEAUTIFIED)], + true, + true, + { + params ["_value"]; + [ + QGVAR(emptyGroupCleanup_enable), + _value + ] call EFUNC(common,logSettingChanged); + + if (!isNull (missionNamespace getVariable [QGVAR(emptyGroupCleanupPFH), locationNull])) then { + deleteLocation GVAR(emptyGroupCleanupPFH); + }; + + call FUNC(addEmptyGroupCleanupPFH); + } +] call CBA_fnc_addSetting; + //--------------------- // Server CPS //--------------------- diff --git a/framework/client/functions/fn_bindEmptyGroupGarbageCleanup.sqf b/framework/performance/functions/fn_addEmptyGroupCleanupPFH.sqf similarity index 71% rename from framework/client/functions/fn_bindEmptyGroupGarbageCleanup.sqf rename to framework/performance/functions/fn_addEmptyGroupCleanupPFH.sqf index 4833821..6dc4a90 100644 --- a/framework/client/functions/fn_bindEmptyGroupGarbageCleanup.sqf +++ b/framework/performance/functions/fn_addEmptyGroupCleanupPFH.sqf @@ -7,7 +7,7 @@ [] ] call EFUNC(common,log); -_emptyGroupPFH = [ +GVAR(emptyGroupCleanupPFH) = [ { { if (local _x) then { @@ -19,7 +19,7 @@ _emptyGroupPFH = [ }, 300, [], - { + { // on creation [ LEVEL_INFO, QUOTE(COMPONENT), @@ -27,15 +27,16 @@ _emptyGroupPFH = [ [] ] call EFUNC(common,log); }, - { [ + { // on deletion + [ LEVEL_INFO, QUOTE(COMPONENT), "Empty group deletion PFH unloaded", [] ] call EFUNC(common,log); }, - { true }, - { false }, + { (missionNamespace getVariable [QGVAR(emptyGroupCleanup_enable), false]) }, + { not (missionNamespace getVariable [QGVAR(emptyGroupCleanup_enable), false]) }, [] ] call CBA_fnc_createPerFrameHandlerObject; diff --git a/framework/triageIcons/functions/fn_addGetEntitiesPFH.sqf b/framework/triageIcons/functions/fn_addGetEntitiesPFH.sqf deleted file mode 100644 index 781227e..0000000 --- a/framework/triageIcons/functions/fn_addGetEntitiesPFH.sqf +++ /dev/null @@ -1,18 +0,0 @@ -#include "..\script_component.hpp" - -// subroutine to gather nearest 50 units every 5 seconds and store in GVAR(drawTargets) -// cleanup -if (!isNil QGVAR(getEntitiesPFH)) then { - [GVAR(getEntitiesPFH)] call CBA_fnc_removePerFrameHandler; -}; -// add pfh -GVAR(getEntitiesPFH) = [{ - GVAR(drawTargets) = ( - (allUnits + allDeadMen) select { - _x isKindOf "CAManBase" && - player distance _x < 50 && - !isNull _x && - player isNotEqualTo _x - } - ); -}, 10] call CBA_fnc_addPerFrameHandler; diff --git a/framework/triageIcons/functions/fn_addDrawIconsPFH.sqf b/framework/triageIcons/functions/fn_draw3D.sqf similarity index 64% rename from framework/triageIcons/functions/fn_addDrawIconsPFH.sqf rename to framework/triageIcons/functions/fn_draw3D.sqf index 6478264..21c9738 100644 --- a/framework/triageIcons/functions/fn_addDrawIconsPFH.sqf +++ b/framework/triageIcons/functions/fn_draw3D.sqf @@ -1,6 +1,6 @@ /* -milsim_fnc_addMedicalOverlayPFH +milsim_triageIcons_fnc_draw3D Author: IndigoFox @@ -14,30 +14,20 @@ Description: #include "..\script_component.hpp" +if (!hasInterface) exitWith {}; -// Per-frame handler to draw icons -// cleanup -if (!isNil QGVAR(drawIconsPfh)) then { - [GVAR(drawIconsPfh)] call CBA_fnc_removePerFrameHandler; -}; -// add pfh -GVAR(drawIconsPfh) = [{ + +// adds codeblock to common array to be processed per frame +private _code = { // if disabled, skip processing if (!GVAR(setting_enabled)) exitWith {false}; - // if no targets, skip processing - if (count GVAR(drawTargets) == 0) exitWith {false}; + // if the player doesn't have medical perms, skip processing if !([player] call ace_medical_treatment_fnc_isMedic) exitWith {false}; + { private _unit = _x; - // distance within X meters - if (player distance _unit > GVAR(setting_drawRange)) then {continue}; - // check unit not null, not conscious, and not in a vehicle - if ( - !(_unit getVariable ["ACE_isUnconscious", false]) || - !isNull (objectParent _unit) - ) then {continue}; - + // color based on triage level private _triageLevel = _unit getVariable ["ace_medical_triageLevel", 4]; if (_triageLevel == -1) then {continue}; @@ -57,6 +47,17 @@ GVAR(drawIconsPfh) = [{ true // outline // further params optional, omitted ]; - } forEach GVAR(drawTargets); -}, 0, []] call CBA_fnc_addPerFrameHandler; + + true; + } count ( + (localNamespace getVariable [QEGVAR(client,nearMen), []]) select { + // is unconscious and is NOT in vehicle and is within draw range + (_x getVariable ["ACE_isUnconscious", false]) && + isNull (objectParent _x) && + player distance _x <= GVAR(setting_drawRange) + } + ); +}; +// add codeblock to common array +[_code] call EFUNC(client,registerPFHCode); \ No newline at end of file diff --git a/framework/triageIcons/functions/fn_initClient.sqf b/framework/triageIcons/functions/fn_initClient.sqf index 7b22f9d..f14600a 100644 --- a/framework/triageIcons/functions/fn_initClient.sqf +++ b/framework/triageIcons/functions/fn_initClient.sqf @@ -1,7 +1,8 @@ #include "..\script_component.hpp" -// List of units to draw icons for -GVAR(drawTargets) = []; +if (!hasInterface) exitWith {}; + +call FUNC(draw3D); [ LEVEL_DEBUG, diff --git a/framework/vehicleFlags/functions/fn_addFlagActions.sqf b/framework/vehicleFlags/functions/fn_addFlagActions.sqf new file mode 100644 index 0000000..7b14721 --- /dev/null +++ b/framework/vehicleFlags/functions/fn_addFlagActions.sqf @@ -0,0 +1,103 @@ +#include "..\script_component.hpp" + +private _vehicleFlagsCfg = call FUNC(getVehicleFlagsCfg); + +if (!isClass _vehicleFlagsCfg) exitWith { + ["WARNING: Vehicle Flags: Vehicle Flags config not found. Vehicle Flags will not be available."] call BIS_fnc_error; +}; + +private _baseClassesToApplyActionsFor = + (_vehicleFlagsCfg >> "baseClassesToApplyActionsFor") call BIS_fnc_getCfgDataArray; +private _flagCategoryCfgs = (_vehicleFlagsCfg >> "FlagCategories") call BIS_fnc_returnChildren; + +{ // forEach _baseClassesToApplyActionsFor + private _parentClass = _x; + + //////////////////////////////////////////////////////////////////////// + // create the root action + //////////////////////////////////////////////////////////////////////// + private _rootActionID = QGVAR(SetVehicleFlagAction); + private _flagRootAction = [ + _rootActionID, // id + "Set Vehicle Flag", // displayed title + "\A3\ui_f\data\map\markers\flags\nato_ca.paa", // flag icon + { + params ["_target", "_player", "_params"]; + // set broadcasted variable of self to indicate we're looking at flags + _player setVariable [QGVAR(inFlagMenu), true, true]; + [{_this setVariable [QGVAR(inFlagMenu), false, true];}, _player, 3] call CBA_fnc_waitAndExecute; + true + }, // statement + { + params ["_target", "_player", "_params"]; + // _params params ["_parentActionID", "_flagCategories"]; + + // check if vehicle is excluded + private _excluded = [typeOf _target] call FUNC(isClassExcluded); + if (_excluded || !alive _target) exitWith {false}; + + true; + }, // condition + { + //////////////////////////////////////////////////////////////////////// + // create the flag category actions (with nested flag actions) + //////////////////////////////////////////////////////////////////////// + params ["_target", "_player", "_params"]; + _params params ["_rootActionID"]; + + private _vehicleFlagsCfg = call FUNC(getVehicleFlagsCfg); + if (isNull _vehicleFlagsCfg) exitWith {[]}; + private _flagCategoryCfgs = (_vehicleFlagsCfg >> "FlagCategories") call BIS_fnc_returnChildren; + + // return category child actions with individual flag actions nested as children + [_rootActionID, _flagCategoryCfgs] call FUNC(getActionsFlagCategories); + + }, // child code + [_rootActionID], // params + nil, // position + 4, // distance + [false, false, false, true, false], // other params - run on hover is true + nil // modifier function code + ] call ace_interact_menu_fnc_createAction; + + //////////////////////////////////////////////////////////////////////// + // add root action to add flags + //////////////////////////////////////////////////////////////////////// + [ + _parentClass, // parent classname + 0, // action 0 or self-action 1 + ["ACE_MainActions"], // parent + _flagRootAction, // action + true // apply to child classes + ] call ace_interact_menu_fnc_addActionToClass; + + //////////////////////////////////////////////////////////////////////// + // add action to remove flag under the root action + //////////////////////////////////////////////////////////////////////// + // create action + private _removeFlagAction = [ + _rootActionID + "_removeflag", // id + "Remove Flag", // displayed title + "\A3\ui_f\data\map\markers\flags\nato_ca.paa", // flag icon + { + params ["_target", "_player", "_params"]; + _target forceFlagTexture ""; + }, // statement + { + params ["_target", "_player", "_params"]; + alive _target && getForcedFlagTexture _target != ""; + }, // condition + nil // child code + ] call ace_interact_menu_fnc_createAction; + + // add the action to the vehicle + // in this class event handler, this#0 will be the vehicle + [ + _parentClass, // parent classname + 0, // action 0 or self-action 1 + ["ACE_MainActions", _rootActionID], // parent + _removeFlagAction, // action + true // apply to child classes + ] call ace_interact_menu_fnc_addActionToClass; + +} forEach _baseClassesToApplyActionsFor; \ No newline at end of file diff --git a/framework/vehicleFlags/functions/fn_draw3D.sqf b/framework/vehicleFlags/functions/fn_draw3D.sqf new file mode 100644 index 0000000..3b971a3 --- /dev/null +++ b/framework/vehicleFlags/functions/fn_draw3D.sqf @@ -0,0 +1,24 @@ +#include "..\script_component.hpp" + +// we'll use this to display status if nearby players are in the flag menu + +// adds codeblock to common array to be processed per frame +private _code = { + private _unitsToDraw = (localNamespace getVariable [QEGVAR(client,nearMen), []]) select { + (_x getVariable [QGVAR(inFlagMenu), false]) && { + // distance within X meters + player distance _x <= 15 || + // check unit not in a vehicle + isNull (objectParent _x) + } + }; + [ + _unitsToDraw, + "", + "Setting vehicle flag...", + [0.9, 0.9, 0.9, 1] + ] call EFUNC(common,draw3dIconStatus); +}; + +// add codeblock to common array +[_code] call EFUNC(client,registerPFHCode); \ No newline at end of file diff --git a/framework/vehicleFlags/functions/fn_initClient.sqf b/framework/vehicleFlags/functions/fn_initClient.sqf index b0d9537..f09a25c 100644 --- a/framework/vehicleFlags/functions/fn_initClient.sqf +++ b/framework/vehicleFlags/functions/fn_initClient.sqf @@ -2,101 +2,8 @@ if (!hasInterface) exitWith {}; -private _vehicleFlagsCfg = call FUNC(getVehicleFlagsCfg); - -if (!isClass _vehicleFlagsCfg) exitWith { - ["WARNING: Vehicle Flags: Vehicle Flags config not found. Vehicle Flags will not be available."] call BIS_fnc_error; -}; - -private _baseClassesToApplyActionsFor = - (_vehicleFlagsCfg >> "baseClassesToApplyActionsFor") call BIS_fnc_getCfgDataArray; -private _flagCategoryCfgs = (_vehicleFlagsCfg >> "FlagCategories") call BIS_fnc_returnChildren; - -{ // forEach _baseClassesToApplyActionsFor - private _parentClass = _x; - - //////////////////////////////////////////////////////////////////////// - // create the root action - //////////////////////////////////////////////////////////////////////// - private _rootActionID = QGVAR(SetVehicleFlagAction); - private _flagRootAction = [ - _rootActionID, // id - "Set Vehicle Flag", // displayed title - "\A3\ui_f\data\map\markers\flags\nato_ca.paa", // flag icon - {true}, // statement - { - params ["_target", "_player", "_params"]; - // _params params ["_parentActionID", "_flagCategories"]; - - // check if vehicle is excluded - private _excluded = [typeOf _target] call FUNC(isClassExcluded); - if (_excluded || !alive _target) exitWith {false}; - - true; - }, // condition - { - //////////////////////////////////////////////////////////////////////// - // create the flag category actions (with nested flag actions) - //////////////////////////////////////////////////////////////////////// - params ["_target", "_player", "_params"]; - _params params ["_rootActionID"]; - - private _vehicleFlagsCfg = call FUNC(getVehicleFlagsCfg); - if (isNull _vehicleFlagsCfg) exitWith {[]}; - private _flagCategoryCfgs = (_vehicleFlagsCfg >> "FlagCategories") call BIS_fnc_returnChildren; - - // return category child actions with individual flag actions nested as children - [_rootActionID, _flagCategoryCfgs] call FUNC(getActionsFlagCategories); - - }, // child code - [_rootActionID], // params - nil, // position - 4, // distance - [false, false, false, false, false], // other params - nil // modifier function code - ] call ace_interact_menu_fnc_createAction; - - //////////////////////////////////////////////////////////////////////// - // add root action to add flags - //////////////////////////////////////////////////////////////////////// - [ - _parentClass, // parent classname - 0, // action 0 or self-action 1 - ["ACE_MainActions"], // parent - _flagRootAction, // action - true // apply to child classes - ] call ace_interact_menu_fnc_addActionToClass; - - //////////////////////////////////////////////////////////////////////// - // add action to remove flag under the root action - //////////////////////////////////////////////////////////////////////// - // create action - private _removeFlagAction = [ - _rootActionID + "_removeflag", // id - "Remove Flag", // displayed title - "\A3\ui_f\data\map\markers\flags\nato_ca.paa", // flag icon - { - params ["_target", "_player", "_params"]; - _target forceFlagTexture ""; - }, // statement - { - params ["_target", "_player", "_params"]; - alive _target && getForcedFlagTexture _target != ""; - }, // condition - nil // child code - ] call ace_interact_menu_fnc_createAction; - - // add the action to the vehicle - // in this class event handler, this#0 will be the vehicle - [ - _parentClass, // parent classname - 0, // action 0 or self-action 1 - ["ACE_MainActions", _rootActionID], // parent - _removeFlagAction, // action - true // apply to child classes - ] call ace_interact_menu_fnc_addActionToClass; - -} forEach _baseClassesToApplyActionsFor; +call FUNC(addFlagActions); +call FUNC(draw3D); [ LEVEL_DEBUG, diff --git a/images/leaflets/.gitkeep b/images/leaflets/.gitkeep new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/images/leaflets/.gitkeep @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/images/leaflets/leaflet_template.jpg b/images/leaflets/leaflet_template.jpg new file mode 100644 index 0000000..23d90e5 Binary files /dev/null and b/images/leaflets/leaflet_template.jpg differ diff --git a/mission_settings.hpp b/mission_settings.hpp index 224ef78..a47eb0b 100644 --- a/mission_settings.hpp +++ b/mission_settings.hpp @@ -1,4 +1,4 @@ -author = "MISSION AUTHOR"; +author = "MISSION AUTHOR"; onLoadName = "THIS APPEARS ON TOP OF THE LOADING SCREEN IMAGE"; loadScreen = "mission.jpg"; onLoadMission = "THIS APPEARS BELOW THE LOADING SCREEN IMAGE"; @@ -9,8 +9,28 @@ overviewText = "THIS IS WHERE YOU DESCRIBE THE MISSION IN THE #MISSION LIST"; // The name for the series of missions of your campaign. Used for organizational and search purposes missionSeries = "MY SERIES NAME"; -// activate via #ace-fortify west base 2000 +// What kind of mission is this? (Use only one) +missionGroup = "17thSaturdayOp"; +// missionGroup = "17thFridayOp"; +// missionGroup = "17thWednesdayOp"; +// missionGroup = "17thFTX"; +// missionGroup = "17thTraining"; + +// Add waypoints to players' MicroDAGR devices +// respawn locations (bases) are added by default, don't put them here +custom_microdagr_waypoints[] = { + // the first element is the waypoint name + // the second element is the position of the waypoint - you may use a string for map grid (up to 10 digit) or an array for {X, Y} coordinates + // the third element is optional - provide the variable name of an object if you want to use its initial position instead + // {"WAYPOINT NAME", {POSITION <[x,y]>}, OBJECT }, + // EXAMPLES: + // {"KAVALA HOSPITAL", {1234.56, 7890.12}, ""}, + // {"CAMP TEMPEST", "03421460, ""}, + // {"MY CUSTOM OBJECT", {}, "myCustomObject"} +}; + +// activate via #ace-fortify west base 2000 class ACEX_Fortify_Presets { class base { displayName = "Ken Custom";