diff --git a/A3_Exile_VEMF_Reloaded.7z b/A3_Exile_VEMF_Reloaded.7z new file mode 100644 index 0000000..8b1b0ba Binary files /dev/null and b/A3_Exile_VEMF_Reloaded.7z differ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..28403f2 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,206 @@ +## VEMF Changelog + +#### `v0740.30` +*Server-side*
+**[ADDED]** Option to prevent AI from having TWS (thermal) scopes
+**[CHANGED]** Order of config settings from being a total mess to being alphabetically sorted.
+
+ +#### `v0740.27` +*Server-side*
+**[ADDED]** More advanced ammo distribution system for AI units
+**[FIXED]** Sometimes no .50 cals at missions
+**[FIXED]** "Error: no vehicle" when killing AI with Helicopter
+**[CHANGED]** A few comments in config.cpp to improve clearness
+
+ +#### `v0740.19` +*Server-side*
+**[ADDED]** Option to enable/disable respect punishment for roadkilling AI
+**[ADDED]** Option to remove "toolbelt" items like GPS, Radio, Map and Compass from AI
+**[ADDED]** New options class to control AI cleanup-related settings
+**[ADDED]** AI units now randomly have random weapon attachments
+**[NEW]** Config.cpp does NOT use -1 anymore to disable things. It is now 0 instead.
+**[CHANGED]** Config.cpp option comments
+**[CHANGED]** On roadkill, kill message shows [Roadkill] instead of vehicle used
+**[IMPROVED]** Overall code performance and use of newer commands
+**[FIXED]** Mines are not working
+**[REMOVED]** fn_random.sqf, replaced by selectRandom command https://community.bistudio.com/wiki/selectRandom
+
+ +#### `v0740.6` +*Server-side*
+**[CHANGED]** BIS_fnc_param replaced by new param command
+**[CHANGED]** Blacklist method for locations. Seperate classes for each map for easier use
+
+*Client-side*
+No Changes.
+
+ +#### `v0732.8` +*Server-side:*
+**[ADDED]** AI static spawns
+**[ADDED]** fn_aiKilled: now shows the name of vehicle used to road-kill an AI
+**[ADDED]** fn_checkLoot: RPT log message if loot validation is enabled but no debug allowed
+**[IMPROVED]** Descriptions and naming of config values
+**[IMPROVED]** fn_aiKilled: now shows killer [weapon, range] victim
+**[IMPROVED]** fn_log: is now faster and much more simple
+**[FIXED]** fn_aiKilled: if killer using vehicle gun, it shows the primaryweapon of the killer instead of the vehicle turret as the weapon used
+**[CHANGED]** Mission complete logs now show the name of location in which the mission was
+**[CHANGED]** Name of pbo is now all lowercase
+
+*Client-side:*
+**[CHANGED]** mission notification messages now have VEMFr as tag instead of the old VEMF tag
+
+ +#### `v0730.21` +**[REMOVED]** Medikit and toolkit from loot crate(s)
+
+ +#### `v0730.20` +**[ADDED]** Option to control the classname of the AI units
+**[ADDED]** Automatic detection of AI unit's side to make sure they get put into a correct group type
+
+ +#### `v0730.15` +**[ADDED]** Option enable/disable the ability to lift loot crate
+
+ +#### `v0730.14` +**[FIXED]** Loss of respect when using vehicle turret
+**[FIXED]** Server-side script error caused by killTheLights
+
+ +#### `v0730.2` +**[NEW]** refreshed mission notification with new animations
+**[FIXED]** difficult to see quickly if mission message means new one or a defeated one
+**[FIXED]** network load peak and fps lag when mines are placed by mission
+**[CHANGED]** server-side message broadcasting to accommodate for including the notification type in the broadcast
+
+ +#### `v0729.1` +**[CHANGED]** increased detection speed of players for triggering missions from 200 to 250
+**[REMOVED]** any usage of playableUnits command
+**[REMOVED]** any checks for the player's side
+**[FIXED]** old stuff in fn_checkLoot.sqf
+**[FIXED]** mission amount can go beyond the limit
+**[FIXED]** fn_playerCount.sqf: unreliable detection of player amount
+**[FIXED]** VEMF_Reloaded started anyway without the actual amount of minimal players to be ingame
+**[IMPROVED]** fail-safe "if checks" in fn_missionTimer.sqf
+ +#### `v0728.6` +**[FIXED]** Instabilities in spawning/despawning of missions
+**[FIXED]** First mission does not timeout
+**[ADDED]** Option to blacklist certain buildings using their classnames
+**[NEW]** Each DynamicLocationInvasion mission type has its own marker color
+
+ +#### `v0727.15` +**[FIX ATTEMPT]** Missions not spawning anymore under very specific conditions
+
+ +#### `v1.0727.13` +**[FIXED]** fn_loadInv not working for the bad guys
+**[FIXED]** random missions not working if mission announcements were disabled
+
+ +#### `v1.0727.11` +**[FIXED]** Missions stop spawning after a certain amount of time
+
+ +#### `v1.0727.9` +**[ADDED]** Option to disable/enable mission announcements
+
+ +#### `v1.0727.3` +**[CHANGED]** Exile_VEMF is now called Exile_VEMF_Reloaded because the original creator of VEMF is proceeding on VEMF
+**[ADDED]** S.W.A.T. AI
+**[ADDED]** Option to send kill messages only to the killer (@KillingRe)
+
+ +#### `v1.0725.6` +**[NEW]** Option to control deletion of .50 cals when mission done
+**[IMPROVED]** Respect reward system
+**[FIXED]** Players getting respect if AI kill other AI
+
+ +#### `v1.0724.1` +**[NEW]** Option to control distance between each mission
+**[CHANGED]** Server-side folder is now called Exile_VEMF
+
+ +#### `v1.0723.1 HOTFIX` +**[FIXED]** fn_aiKilled.sqf: error Undefined variable in expression unit
+
+ +#### `v1.0722.15` +**[NEW]** Player now get reputation for killing AI. Dynamically increases depending on kill distance
+**[FIXED]** Unstable fn_random.sqf
+
+ +#### `v1.0721.15` +**[NEW]** AI will now spawn in houses
+**[NEW]** Mounted (bipod) .50 cals in/on houses if enabled
+**[ADDED]** Option to enable/disable AI "Cop mode"
+**[CHANGED]** fn_spawnAI.sqf to allow spawning in houses
+**[TWEAKED]** fn_loadInv.sqf
+
+#### `v1.0721.1` +**[FIXED]** fn_spawnAI.sqf: Suspending not allowed in this context, line 72
+
+ +#### `v1.0720.6` +**[NEW]** Automatic removal of loot crate marker when player gets close
+**[ADDED]** Option to enable/disable mission markers
+**[ADDED]** Ability to put `maxGlobalMissions` on -1. Disables the mission limit
+**[ADDED]** Exile default safe zones to mission blacklist positions
+**[ADDED]** Option to enable/disable loot crate markers
+**[ADDED]** Option to enable/disable loot crate parachute spawn
+**[ADDED]** Option to enable/disable loot crate visual smoke/chemlights
+**[ADDED]** Option to enable/disable loot crate spawn sound (once)
+**[ADDED]** Logging of successfull removal/exploding of mines
+**[ADDED]** Code changes to fn_missionTimer.sqf to allow ignoring of global mission count
+**[ADDED]** Code changes to DLI mission to prevent removal of non-existing mission marker
+**[CHANGED]** several config options from negative to positive
+**[CHANGED]** Default debug mode from 2 to 0 (errors only)
+**[CHANGED]** AI difficulty config now less lines
+**[CHANGED]** AI Veteran and Harcore difficulty increased
+**[CHANGED]** Mines are now switched off by default
+**[CHANGED]** Default mine removal mode is now explode
+**[CHANGED]** fn_loadLoot.sqf: now empties the crate instead of the mission itself
+**[FIXED]** Error in expression fn_findPos.sqf
+**[FIXED]** Error in expression fn_loadInv.sqf with specific set of config settings
+
+ +#### `v1.0719.10` +**[ADDED]** Option to enable/disable the placement of a marker on the loot crate
+**[ADDED]** Attempt to fix the floating crate problem
+**[ADDED]** Fail-safety for fn_checkPlayerPresence.sqf
+**[ADDED]** Fail-safety for fn_placeMines.sqf
+**[ADDED]** Fail-safety for fn_spawnAI.sqf
+**[CHANGED]** Default value of `validateLoot` from 1 to -1
+**[REMOVED]** Option to enable/disable sound on the loot crate
+**[FIXED]** Mines not removing or exploding
+**[FIXED]** Structure error in fn_findPos.sqf
+
+#### `v1.0718.11` +**NOTE:** VEMFclient code has been changed!
+**[ADDED]** AI difficulty presets
+**[CHANGED]** Default cleanMines setting changed from 2 to 1
+**[CHANGED]** fn_broadCast.sqf for new broadcast system
+**[CHANGED]** fn_loadLoot.sqf: fail-safety removed
+**[CHANGED]** fn_spawnAI.sqf: implementation of AI difficulty presets
+**[CHANGED]** Veteran AI difficulty lowered. Too close to aimbots
+**[FIXED]** Duplicate spawns on locations
+**[FIXED]** Player getting side ENEMY for attacking AI
+**[FIXED]** Loot crate not falling down
+**[FIXED]** Loot crate not making a sound
+
+#### `v1.0717.7` +**[FIXED]** No loot in crate
+**[FIXED]** AI not shooting at player
+
+ +#### `v1.0716.14` +**[NEW]** VEMF ported to Exile :)
+
diff --git a/Exile.MapName/VEMFr_client/CfgFunctions.hpp b/Exile.MapName/VEMFr_client/CfgFunctions.hpp new file mode 100644 index 0000000..8259420 --- /dev/null +++ b/Exile.MapName/VEMFr_client/CfgFunctions.hpp @@ -0,0 +1,10 @@ +class VEMF_Reloaded +{ + tag = "VEMFr"; + class clientFunctions + { + file = "VEMFr_client\functions"; + class handleMessage {}; + class clientInit { postInit = 1; }; + }; +}; diff --git a/Exile.MapName/VEMFr_client/functions/fn_clientInit.sqf b/Exile.MapName/VEMFr_client/functions/fn_clientInit.sqf new file mode 100644 index 0000000..0dcf227 --- /dev/null +++ b/Exile.MapName/VEMFr_client/functions/fn_clientInit.sqf @@ -0,0 +1,36 @@ +if (hasInterface) then +{ + uiNamespace setVariable ["RscDisplayVEMFrClientMsgQueue", []]; + uiNamespace setVariable ["RscDisplayVEMFrClient", displayNull]; + // custom addPublicVariableEventHandler. Those bloody BE filters..... + [] spawn + { + while {true} do + { + waitUntil { uiSleep 0.05; not isNil"VEMFrClientMsg" }; + if (typeName VEMFrClientMsg isEqualTo "ARRAY") then + { + _data = +[VEMFrClientMsg]; + VEMFrClientMsg = nil; + _data = _data select 0; + [_data] spawn + { + _data = _this select 0; + _mode = [_data, 1, "", [""]] call BIS_fnc_param; + _msg = [_data, 0, "", [[],format[""]]] call BIS_fnc_param; + switch _mode do + { + case "sys": + { + systemChat _msg; + }; + default + { + [_msg select 0, _msg select 1] spawn VEMFr_fnc_handleMessage; + }; + }; + }; + }; + }; + }; +}; diff --git a/Exile.MapName/VEMFr_client/functions/fn_handleMessage.sqf b/Exile.MapName/VEMFr_client/functions/fn_handleMessage.sqf new file mode 100644 index 0000000..2471a4a --- /dev/null +++ b/Exile.MapName/VEMFr_client/functions/fn_handleMessage.sqf @@ -0,0 +1,118 @@ +_txt = [_this, 0, "", [""]] call BIS_fnc_param; +_type = [_this, 1, "", [""]] call BIS_fnc_param; +if not(_txt isEqualTo "") then +{ + _msgQueue = uiNamespace getVariable ["RscDisplayVEMFrClientMsgQueue", []]; + _msgQueue pushBack _txt; + disableSerialization; + _dsp = uiNamespace getVariable ["RscDisplayVEMFrClient", displayNull]; + _doAnim = + { + for "_g" from 1 to (count _txt) do + { + _ctrl ctrlSetText (_txt select [0, _g]); + if isNull (findDisplay 49) then + { + if not isNull _dsp then + { + playSound "ReadOutClick" + }; + }; + uiSleep 0.05; + }; + _chars = []; + for "_t" from 1 to (count _txt) do + { + _char = _txt select [_t, 1]; + _chars pushBack _char; + }; + _writeThis = +_chars; + uiSleep ((count _txt)/6); + for "_i" from (count _chars) to 1 step -1 do + { + _charID = floor random count _chars; + _deleted = _chars deleteAt _charID; + if not(_deleted isEqualTo "") then + { + _charToSet = _writeThis find _deleted; + if not(_deleted isEqualTo " ") then + { + _binaries = ["0","1"]; + _writeThis set [_charToSet, _binaries select floor random count _binaries]; + }; + _string = ""; + { + _string = _string + _x; + } forEach _writeThis; + _ctrl ctrlSetText _string; + if isNull(findDisplay 49) then + { + if not isNull _dsp then + { + playSound "ReadOutHideClick1" + }; + }; + uiSleep 0.05; + }; + }; + + if (typeName _msgQueue isEqualTo "ARRAY") then + { + _index = _msgQueue find _txt; + if (_index > -1) then + { + _msgQueue deleteAt _index; + }; + }; + + if (count _msgQueue isEqualTo 0) then + { + _ctrl ctrlSetPosition [(ctrlPosition _ctrl) select 0, (ctrlPosition _ctrl) select 1, 0 * safezoneW, (ctrlPosition _ctrl) select 3]; + _ctrl ctrlCommit 0.5; + uiSleep 0.5; + _ctrlTag ctrlSetPosition [(ctrlPosition _ctrlTag) select 0, (ctrlPosition _ctrlTag) select 1, (ctrlPosition _ctrlTag) select 2, 0 * safezoneH]; + _ctrlTag ctrlCommit 0.3; + _ctrlTag ctrlSetText ""; + uiSleep 0.3; + _ctrlMsgType ctrlSetPosition [(ctrlPosition _ctrlMsgType) select 0, (ctrlPosition _ctrlMsgType) select 1, 0 * safezoneW, (ctrlPosition _ctrlMsgType) select 3]; + _ctrlMsgType ctrlCommit 0.3; + uiSleep 0.3; + (["RscDisplayVEMFrClient"] call BIS_fnc_rscLayer) cutFadeOut 0.3; + }; + }; + if isNull _dsp then + { // Make sure the display is actually active + (["RscDisplayVEMFrClient"] call BIS_fnc_rscLayer) cutRsc["RscDisplayVEMFrClient", "PLAIN", 0, true]; + _dsp = uiNamespace getVariable ["RscDisplayVEMFrClient", displayNull]; + if ((count _msgQueue) > 0) then + { + _ctrlMsgType = _dsp displayCtrl 1002; + _ctrlMsgType ctrlSetText _type; + _ctrlMsgType ctrlSetPosition [(ctrlPosition _ctrlMsgType) select 0, (ctrlPosition _ctrlMsgType) select 1, 0.1 * safezoneW, (ctrlPosition _ctrlMsgType) select 3]; + _ctrlMsgType ctrlCommit 0.3; + uiSleep 0.3; + _ctrlTag = _dsp displayCtrl 1001; + _ctrlTag ctrlSetPosition [(ctrlPosition _ctrlTag) select 0, (ctrlPosition _ctrlTag) select 1, (ctrlPosition _ctrlTag) select 2, 0.03 * safezoneH]; + _ctrlTag ctrlCommit 0.3; + uiSleep 0.3; + _ctrlTag ctrlSetText toString [86,69,77,70,114]; + _ctrl = _dsp displayCtrl 1000; + _ctrl ctrlSetPosition [(ctrlPosition _ctrl) select 0, (ctrlPosition _ctrl) select 1, 0.4375 * safezoneW, (ctrlPosition _ctrl) select 3]; + _ctrl ctrlCommit 0.3; + uiSleep 0.3; + call _doAnim; + }; + }; + if not isNull _dsp then + { + waitUntil { uiSleep 1; (_msgQueue select 0) isEqualTo _txt }; + if not isNull _dsp then + { + _ctrlMsgType = _dsp displayCtrl 1002; + _ctrlMsgType ctrlSetText _type; + _ctrlTag = _dsp displayCtrl 1001; + _ctrl = _dsp displayCtrl 1000; + call _doAnim; + }; + }; +}; diff --git a/Exile.MapName/VEMFr_client/gui/hpp_mainVEMFrClient.hpp b/Exile.MapName/VEMFr_client/gui/hpp_mainVEMFrClient.hpp new file mode 100644 index 0000000..4407cb2 --- /dev/null +++ b/Exile.MapName/VEMFr_client/gui/hpp_mainVEMFrClient.hpp @@ -0,0 +1,43 @@ +class RscDisplayVEMFrClient +{ + idd = 2991; + fadeIn = 0.2; + fadeOut = 1; + duration = 99999; + onLoad = "uiNamespace setVariable ['RscDisplayVEMFrClient', _this select 0]"; + movingEnable = 0; + class IGUIBack + { + type = 0; + text = ""; + colorText[] = {0,0,0,0}; + font = "PuristaMedium"; + sizeEx = 0; + shadow = 0; + style = 128; + colorBackground[] = {0,0,0,1}; + }; + class RscText + { + shadow = 0; + deletable = 0; + fade = 0; + sizeEx = "(((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 1)"; + font = "PuristaLight"; + style = 0; + access = 0; + type = 0; + fixedWidth = 0; + colorShadow[] = {0,0,0,0.5}; + lineSpacing = 1; + tooltipColorText[] = {1,1,1,0.9}; + tooltipColorBox[] = {1,1,1,0.2}; + tooltipColorShade[] = {0,0,0,0.7}; + colorText[] = {0.22,0.745,0.882,1}; + colorBackground[] = {0.071,0.078,0.094,1}; + }; + class controls + { + #include "hpp_rscVEMFrClient.hpp" + }; +}; diff --git a/Exile.MapName/VEMFr_client/gui/hpp_rscVEMFrClient.hpp b/Exile.MapName/VEMFr_client/gui/hpp_rscVEMFrClient.hpp new file mode 100644 index 0000000..c0cc61e --- /dev/null +++ b/Exile.MapName/VEMFr_client/gui/hpp_rscVEMFrClient.hpp @@ -0,0 +1,36 @@ +class txtType: RscText +{ + idc = 1002; + font = "PuristaSemiBold"; + text = ""; + colorText[] = {0,0,0,0.9}; + colorBackground[] = {1,1,1,0.9}; + x = 0.25 * safezoneW + safezoneX; + y = 0.88 * safezoneH + safezoneY; + w = 0 * safezoneW; + h = 0.02 * safezoneH; +}; +class txtTag: RscText +{ + idc = 1001; + font = "PuristaBold"; + text = ""; + sizeEx = "(((((safezoneW / safezoneH) min 1.2) / 1.2) / 25) * 1.3)"; + colorText[] = {0,0,0,0.9}; + colorBackground[] = {1,1,1,0.9}; + x = 0.25 * safezoneW + safezoneX; + y = 0.9 * safezoneH + safezoneY; + w = 0.05 * safezoneW; + h = 0 * safezoneH; +}; +class txtMsg: RscText +{ + idc = 1000; + text = ""; + colorText[] = {1,1,1,0.9}; + colorBackground[] = {0,0,0,0.9}; + x = 0.3 * safezoneW + safezoneX; + y = 0.9 * safezoneH + safezoneY; + w = 0 * safezoneW; + h = 0.03 * safezoneH; +}; diff --git a/Exile.MapName/description.ext b/Exile.MapName/description.ext new file mode 100644 index 0000000..a3a3f74 --- /dev/null +++ b/Exile.MapName/description.ext @@ -0,0 +1,9 @@ +class cfgFunctions +{ + #include "VEMFr_client\CfgFunctions.hpp" +}; + +class RscTitles +{ + #include "VEMFr_client\gui\hpp_mainVEMFrClient.hpp" +}; diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..512131e --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,67 @@ +================================================================================================ +====== LICENSE INFORMATION =================================================================== +================================================================================================ + + VEMF code is provided under an Attribution Non-Commercial ShareAlike 4.0 Commons License. +Link: http://creativecommons.org/licenses/by-nc-sa/4.0/ + + The majority of the code is created by the VEMF license holder, but not all of it. +Very small samples of code may belong to the "Exile Mod" for Arma 3 made by the Exile Mod Team. + + The "Exile Mod" code is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License +Link: http://creativecommons.org/licenses/by-nc-nd/4.0/ +Website: http://exilemod.com/ + + VEMF being programmed for the Arma 3 engine means you must also comply to Bohemia +Interactive's End User License Agreement, and Game Content Usage Rules. +EULA: http://www.bistudio.com/community/licenses/arma3-end-user-license +GCUR: http://www.bistudio.com/community/game-content-usage-rules + +================================================================================================ +What does this mean for me? + + You are able to share VEMF under any format, torrents, file hosts, ftp etc, +however it must be free to be able to access the downloads. If you have to pay +for an account to access the download link you are in violation of the license. + + You can adapt the work as you please inside of the terms of the license. + + If you want to release an adapted version of VEMF, you must give appropriate +credit to the original authors, provide a link to the license, indicate if changes +were made (via a changelog), and share the new version under the same license. + + You must do this in a way that does not indicate that the original authors +endorses you or your use. (An example would be advertising your new adaptation +as originally coming from VEMF. The key being "Advertise" instead of simply listing it.) + + Finally, this content cannot be commercialized. If you are receiving ANY +monetary funds where VEMF is included in your work, you are breaking the terms of this license. +Donations are to be given without any return consideration. The person donating cannot have +the intention of receiving something in return from you for making their donation. + +This include but is not limited to: + - Selling access to a server that runs VEMF. + - Allowing users of your server to purchase "perks" somehow related to VEMF. (Mission GPS?) + - Including VEMF in a mod that is being sold for a profit. + - Preventing access to VEMF files or content based on donations. + +================================================================================================ +So do I need to ask for your permission to modify VEMF? + + As a non-binding request, I ask that you make a concerted effort to try to contact me +to ask for my permission before you start modifying VEMF. I would like to know about modified +versions of VEMF before they are released. This request does not apply to individuals +("Individuals" not "groups") or "clans" that wish to modify VEMF for their individual server. + + Even though this license seems a little overkill, I'm a fairly likeable guy. If you're +trying to contact me for a non-commercial interest, I'll most likely allow it. + + If you cannot reach me within a month, and you meet all the other requirements of this license, +you can modify VEMF freely within the terms of the license. + +================================================================================================ +I feel VEMF is infringing upon my work. + + If you think VEMF infringes upon your work, please contact me. + You can contact me on: +EpochMod.com (IT07), Reddit (IT07), forums.bistudio.com (IT07) and Exilemod.com (IT07) diff --git a/README.md b/README.md index e4bebb9..8e320b3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,64 @@ -# ArmA3_exile_vemf_reloaded -Contains VEMFr (a.k.a. VEMF Reloaded) for ArmA 3 Exile Mod +# A3_Exile_VEMF_Reloaded +**Not to confuse with VEMF**

+ +#### How to download? +**Because of its new location, the download process is a little different:**
+Click the .7z file and then click the "Raw" button. You will then get the exile_vemf_reloaded folder and the Exile.MapName folder inside of a packed .7z :)
+
+ +#### How to install? +**Server-side files**
+- copy the `exile_vemf_reloaded` folder over into where your server's `@ExileServer\addons\` folder is located.
+- navigate into the `exile_vemf_reloaded` folder that you just copied over into your server.
+- open the config.cpp and READ IT. There is A LOT of settings in there that you can adjust to change VEMFr.
+- when done changing stuff in the config.cpp, simply pack **the contents(!)** of the parent folder into a pbo called `exile_vemf_reloaded`
+- you can delete the `exile_vemf_reloaded` folder that the program you use to pack into a pbo might have left behind. You don't have to though.
+
+**Client-side files**
+- whatever your server setup might be, you need to open/download/unpack your server's mission file. If you are running the Altis map for example, it will be a .pbo called `Exile.Altis`. Or when you are running Esseker for example, then it will be `Exile.Esseker`. Normally that file is located inside the *mpmissions* folder which is in the root of your server's installation path. Simply unpack that file and go into the folder that comes out of it. There should be a file called `description.ext` in there. Open that. Then look for a line that says `class CfgFunctions`. If you can not find it, then add this somewhere near the bottom of your description.ext:
+``` +class cfgFunctions +{ + #include "VEMFr_client\CfgFunctions.hpp" +}; +``` +
+However, if you DO have a `class CfgFunctions` in your description.ext, then simply add `#include "VEMFr_client\CfgFunctions.hpp"` between the `{` (opening bracket) and `};` (closing bracket), like this:
+``` +class cfgFunctions +{ + class justAnExample + { + tag = "Exile"; + class fkasjhdfksahfkhsd + { + file = "dssdf"; + class fdshjlkfhasjdk {}; + }; + }; + #include "VEMFr_client\CfgFunctions.hpp" +}; +``` +
+- now the last part: `class RscTitles`. Try and find it in your description.ext, if it is not there, then just simply add this to the bottom of your description.ext:
+``` +class RscTitles +{ + #include "VEMFr_client\gui\hpp_mainVEMFrClient.hpp" +}; +``` +
+BUT, if you DO have a `class RscTitles` already, then just make a new line just before the `};` and then put this on that new line:
+`#include "VEMFr_client\gui\hpp_mainVEMFrClient.hpp"`
+Just an example of how it would look with other stuff in between the brackets of `class RscTitles`:
+``` +class RscTitles +{ + #include "some\other\scriptszzzzz\file.hpp" + #include "bla\addons\dialog.hpp" + #include "addons\scripts\gui\someFile.hpp" + #include "VEMFr_client\gui\hpp_mainVEMFrClient.hpp" +}; +``` + +*Done!* diff --git a/exile_vemf_reloaded/addons/VEMFAddons.txt b/exile_vemf_reloaded/addons/VEMFAddons.txt new file mode 100644 index 0000000..8e47d00 --- /dev/null +++ b/exile_vemf_reloaded/addons/VEMFAddons.txt @@ -0,0 +1 @@ +VEMF Addon scripts can be added here. \ No newline at end of file diff --git a/exile_vemf_reloaded/config.cpp b/exile_vemf_reloaded/config.cpp new file mode 100644 index 0000000..677f6c2 --- /dev/null +++ b/exile_vemf_reloaded/config.cpp @@ -0,0 +1,397 @@ +/* + Author: IT07 + + Description: + cpp config file for exile_vemf_reloaded + + What is exile_vemf_reloaded? (short: VEMFr) + It is a complete remake (and port to Exile) of VEMF (for Epoch) by TheVampire. + exile_vemf_reloaded was originally called VEMF but because the original creator (TheVampire) wanted to continue his work on VEMF, + this remade version of VEMF had its name changed into exile_vemf_reloaded. +*/ + +/////////////// +/// NOTE: settings that are set to 0 means they are DISABLED | settings set to 1 (or higher) are either enabled or have a specific function +/////////////// + +class CfgVemfReloaded +{ + /////// Debugging/learning mode /////// + debugMode = 2; // 0 = no debugging | 1 = ERRORS only | 2 = INFO only | 3 = ERRORS & INFO + /////////////////////////////////////// + + // Global settings + addons[] = {}; // Not used for now + headLessClientSupport = 0; + headLessClientNames[] = {"HC1"}; + housesBlackList[] = {"Land_Pier_F"}; + killPercentage = 100; // How much of total AI has to be killed for mission completion (in percentage) + maxGlobalMissions = 10; // Enable/disable global mission amount limit + maxNew = 2; // Enable/disable MAXIMUM time (in minutes) before new mission can run + minNew = 1; // Enable/disable MINIMUM time (in minutes) before new mission can run + minPlayers = 1; // Enable/disable minimal required player count for (new) missions to (start) spawn(ing) + minServerFPS = 20; // Enable/disable minimum server FPS for VEMF to keep spawning missions + missionDistance = 2000; // Enable/disable minimum distance between missions + missionList[] = {"DynamicLocationInvasion"}; // Each entry should represent an .sqf file in the missions folder + noMissionPos[] = {{{2998.62,18175.4,0.00143886},500},{{14601.3,16799.3,0.00143814},800},{{23334.8,24189.5,0.00132132},600}}; // Format: {{position},radius} | Default: Exile safezones + nonPopulated = 1; // Enable/disable allowance of missions at locations WITHOUT (enterable) buildings + punishRoadKills = 1; // Enable/disable respect deduction if player roadkills AI + removeAllAssignedItems = 0; // Enable/disable removal of Map, Compass, Watch and Radio from all AI + sayKilled = 1; // Enable/disable AI kill messages + timeOutTime = 25; // Enable/disable mission timeOutTime (in minutes) + validateLoot = 1; // Enable/disable validation of all defined loot classnames. Checks if classnames exist in server's game configFile + + // Exile specific settings + aiMode = 1; // 0 = normal soldier AI | 1 = regular police AI | 2 = S.W.A.T. AI + respectReward = 20; // 0 = no respect for killing AI | respectReward > 0 = amount of minimum respect reward for player + respectRoadKillDeduct = 20; // 0 = no deduction for roadkilling AI | respectRoadKillDeduct > = amount of respect to deduct from player; + + // AI Unit settings + unitClass = "B_G_Soldier_AR_F"; // Default: "B_G_Soldier_AR_F" + // NOTE: VEMFr will automatically adjust the AI's side that belongs to the unit of given unitClass + + class locationBlackLists + { // NOTE: If the map you use is not listed below, simply add it by yourself or put the locations you want to blacklist into the locations array of the Other class + class Altis + { + locations[] = {"Sagonisi","Monisi","Fournos","Savri","Atsalis","Polemista","Cap Makrinos","Pyrgi","Makrynisi","Chelonisi","Almyra","Surf Club"}; + }; + class Stratis + { + locations[] = {"Marina Bay","Kamino Bay","Keiros Bay","Limeri Bay","Tsoukala Bay","Jay Cove","Strogos Bay","Kyfi Bay","Nisi Bay"}; + }; + class Namalsk + { + locations[] = {"Nemsk Bay","Brensk Bay","Seraja Bay","Lubjansk Bay","Tara Strait"}; + }; + class Other + { + locations[] = {}; + }; + }; + + class DynamicLocationInvasion // DynamicLocationInvasion (mission) settings + { + allowCrateLift = 0; // Allow/disallow the loot crate to be lifted with helicopter + aiLaunchers = 1; // Allow/disallow AI to HAVE rocket launchers + allowTWS = 0; // Enable/disable the usage of TWS scopes by AI + announce = 1; // Enable/disable mission notificatons + cal50s = 3; // Max amount of .50 caliber machineguns at mission | Needs to be lower than total unit count per mission + cal50sDelete = 1; // Enable/disable the removal of .50cal | 2 = destroy (not remove) + crateTypes[] = {"I_CargoNet_01_ammo_F","O_CargoNet_01_ammo_F","B_CargoNet_01_ammo_F","I_supplyCrate_F","Box_East_AmmoVeh_F","Box_NATO_AmmoVeh_F"}; + flairTypes[] = {"Chemlight_green","Chemlight_red","Chemlight_yellow","Chemlight_blue"}; + groupCount[] = {2,4}; // In format: {minimum, maximum}; VEMF will pick a random number between min and max. If you want the same amount always, use same numbers for minimum and maximum. + groupUnits[] = {4,6}; // How much units in each group. Works the same like groupCount + hasLauncherChance = 25; // In percentage. How big the chance that each AI gets a launcher + marker = 1; // Enable/disable mission markers + markCrateOnMap = 1; // Enable/disable loot crate marker on map called "Loot" + markCrateVisual = 1; // Enable/disable loot crate VISUAL marker (smoke and/or chem) + maxDistance = 15000; // Maximum distance from random player for mission location selection + /* maxDistance NOTE: make sure to keep this number very high. 15000 is for Altis */ + maxDistancePrefered = 7000; // Prefered maximum mission distance from player + maxInvasions = 7; // Max amount of active uncompleted invasions allowed at the same time + mines = 0; // Enable/disable mines at mission | 1 = anti-Armor mines | 2 = anti-Personell mines | 3 = both anti-Armor and anti-Personell mines + minesAmount = 20; // Ignore if placeMines = 0; + minesCleanup = 1; // Enable/disable the removal of mines once mission has been completed | 2 = explode mines + parachuteCrate[] = {0, 250}; // default: {disabled, 250 meters} | use 1 as first number to enable crate parachute spawn + randomModes = 1; // Enable/disable randomization of AI types (linked to aiMode setting) + skipDistance = 800; // No missions at locations which have players within this range (in meters) + smokeTypes[] = {"SmokeShell","SmokeShellBlue","SmokeShellGreen","SmokeShellOrange","SmokeShellRed","SmokeShellYellow"}; + streetLights = 0; // Enable/disable street lights at mission location + streetLightsRestore = 1; // Enable/disable restoration of street lights after mission completion + streetLightsRange = 500; // Affects streetlights within this distance from mission's center + }; + + class aiCleanUp // Contains settings for removal of items from each AI that gets eliminated + { + aiDeathRemovalEffect = 0; // Enable/disable the "death effect" from Virtual Arsenal. Flashes AI and deletes it after being eliminated + removeHeadGear = 0; // Enable/disable removal of headgear after AI has been eliminated, obviously + removeLaunchers = 0; // Enable/disable removal of rocket launchers from AI after they are eliminated + }; + + class aiStatic + { + amount[] = {10,20,12,11,40,21,19}; // How much AI units on each seperate position. Example: 1st location, 10. 2nd location, 20. 3rd location, 12. And so on.... + enabled = 0; // Enable/disable static AI spawning + positions[] = {}; // Add positions here. Each position must have {} around it and must be seperated with a comma if multiple positions present. Last position in list should NOT have a comma behind it! + random = 1; // Enable/disable randomization of AI units amount + }; + + // Global AI skill settings. They affect each VEMF unit for any default VEMF mission + class aiSkill // Minimum: 0 | Maximum: 1 + { + difficulty = "Veteran"; // Options: "Easy" "Normal" "Veteran" "Hardcore" | Default: Veteran + class Easy // AI looks stupid with this setting xD + { + accuracy = 0.4; aimingShake = 0.20; aimingSpeed = 0.3; endurance = 0.25; spotDistance = 0.5; spotTime = 0.7; courage = 1; reloadSpeed = 0.3; commanding = 0.8; general = 0.3; + }; + class Normal + { + accuracy = 0.4; aimingShake = 0.20; aimingSpeed = 0.3; endurance = 0.25; spotDistance = 0.5; spotTime = 0.7; courage = 1; reloadSpeed = 0.3; commanding = 0.8; general = 0.4; + }; + class Veteran + { + accuracy = 0.4; aimingShake = 0.20; aimingSpeed = 0.3; endurance = 0.25; spotDistance = 0.5; spotTime = 0.7; courage = 1; reloadSpeed = 0.3; commanding = 0.8; general = 0.5; + }; + class Hardcore // Also known as Aimbots + { + accuracy = 0.4; aimingShake = 0.20; aimingSpeed = 0.3; endurance = 0.25; spotDistance = 0.5; spotTime = 0.7; courage = 1; reloadSpeed = 0.3; commanding = 0.8; general = 0.7; + }; + }; + + class policeConfig + { + backpacks[] = { + "B_AssaultPack_khk","B_AssaultPack_dgtl","B_AssaultPack_rgr","B_AssaultPack_sgg","B_AssaultPack_cbr", + "B_AssaultPack_mcamo","B_TacticalPack_rgr","B_TacticalPack_mcamo","B_TacticalPack_ocamo","B_TacticalPack_blk", + "B_TacticalPack_oli","B_FieldPack_khk","B_FieldPack_ocamo","B_FieldPack_oucamo","B_FieldPack_cbr", + "B_FieldPack_blk","B_Carryall_ocamo","B_Carryall_oucamo","B_Carryall_mcamo","B_Carryall_khk","B_Carryall_cbr", + "B_Parachute","B_FieldPack_oli","B_Carryall_oli","B_Kitbag_Base","B_Kitbag_cbr","B_Kitbag_mcamo", + "B_Kitbag_rgr","B_Kitbag_sgg","B_OutdoorPack_Base","B_OutdoorPack_blk","B_OutdoorPack_blu", + "B_OutdoorPack_tan" + }; + headGear[] = { + "H_Cap_police","H_Beret_blk_POLICE","H_Cap_blk_ION","H_Cap_khaki_specops_UK","H_Cap_tan_specops_US","H_Cap_brn_SPECOPS","H_Cap_blk_CMMG","H_Cap_blk","H_Cap_blu","H_Cap_red", + "H_Cap_press","H_Cap_usblack","H_Beret_brn_SF","H_Beret_Colonel" + }; + pistols[] = {"hgun_ACPC2_F","hgun_P07_F","hgun_Pistol_heavy_01_F","hgun_Pistol_heavy_02_F","hgun_Rook40_F"}; + rifles[] = { + "arifle_Katiba_F","arifle_Katiba_C_F","arifle_Katiba_GL_F","arifle_Mk20_F","arifle_Mk20_plain_F","arifle_Mk20C_F","arifle_Mk20C_plain_F","arifle_Mk20_GL_F","arifle_Mk20_GL_plain_F", + "arifle_MXC_F","arifle_MX_F","arifle_MX_SW_F","arifle_MXC_Black_F","arifle_MX_Black_F","arifle_TRG21_F","arifle_TRG20_F","arifle_TRG21_GL_F","hgun_PDW2000_F","SMG_01_F","SMG_02_F" + }; + uniforms[] = {"U_C_Journalist","U_Rangemaster","U_Marshal","U_Competitor"}; + vests[] = {"V_TacVest_blk_POLICE","V_PlateCarrierSpec_blk","V_PlateCarrierGL_blk","V_TacVestCamo_khk","V_TacVest_blk","V_BandollierB_blk","V_Rangemaster_belt"}; + }; + + // Loot crate configuration + class crateLoot + { + primarySlotsMax = 10; // Maximum primary weapons in each loot crate + primarySlotsMin = 4; // Minimum primary weapons in each loot crate + primaryWeaponLoot[] = + { // The number after each classname means how much of that type will be put in crate. WARNING: DO NOT USE NUMBERS WITH DECIMALS. + {"srifle_DMR_01_F",2},{"srifle_EBR_F",3},{"srifle_GM6_F",1},{"LMG_Mk200_F",3},{"LMG_Zafir_F",3},{"arifle_Katiba_F",3},{"arifle_Katiba_GL_F",2},{"arifle_Mk20_F",2}, + {"arifle_Mk20_plain_F",2},{"arifle_Mk20C_F",2},{"arifle_Mk20C_plain_F",2},{"arifle_Mk20_GL_F",2},{"arifle_Mk20_GL_plain_F",2},{"arifle_MXC_F",2},{"arifle_MX_F",2}, + {"arifle_MX_GL_F",2},{"arifle_MX_SW_F",2},{"arifle_MXM_F",2},{"arifle_MXC_Black_F",2},{"arifle_MX_Black_F",2},{"arifle_MX_GL_Black_F",2},{"arifle_MX_SW_Black_F",2}, + {"arifle_MXM_Black_F",2},{"arifle_SDAR_F",2},{"arifle_TRG21_F",2},{"arifle_TRG20_F",2},{"arifle_TRG21_GL_F",2},{"SMG_01_F",2},{"SMG_02_F",2},{"srifle_GM6_camo_F",2}, + {"srifle_LRR_camo_F",2},{"srifle_DMR_02_F",2},{"srifle_DMR_02_camo_F",2},{"srifle_DMR_02_sniper_F",2},{"srifle_DMR_03_F",2},{"srifle_DMR_03_khaki_F",2},{"srifle_DMR_03_tan_F",2}, + {"srifle_DMR_03_multicam_F",2},{"srifle_DMR_03_woodland_F",2},{"srifle_DMR_04_F",2},{"srifle_DMR_04_Tan_F",2},{"srifle_DMR_05_blk_F",2},{"srifle_DMR_05_hex_F",2},{"srifle_DMR_05_tan_f",2},{"srifle_DMR_06_camo_F",2},{"srifle_DMR_06_olive_F",2},{"MMG_01_hex_F",2},{"MMG_01_tan_F",2},{"MMG_02_camo_F",2}, + {"MMG_02_black_F",2},{"MMG_02_sand_F",2} + }; + + secondarySlotsMax = 4; // Maximum number of secondary weapons to be in each loot crate + secondarySlotsMin = 2; // Minimum number of secondary weapons to be in each loot crate + secondaryWeaponLoot[] = + { // The number after each classname means how much of that type will be put in crate. WARNING: DO NOT USE NUMBERS WITH DECIMALS. + {"hgun_ACPC2_F",3},{"hgun_P07_F",3},{"hgun_Pistol_heavy_01_F",3},{"hgun_Pistol_heavy_02_F",3},{"hgun_Rook40_F",3} + }; + + magSlotsMax = 6; // Maximum number of magazine slots in each loot crate + magSlotsMin = 4; // Minimum number of magazine slots in each loot crate + magLoot[] = + { // The number after each classname means how much of that type will be put in crate. WARNING: DO NOT USE NUMBERS WITH DECIMALS. + {"30Rnd_556x45_Stanag",20},{"30Rnd_556x45_Stanag_Tracer_Red",20},{"30Rnd_556x45_Stanag_Tracer_Green",20}, + {"30Rnd_556x45_Stanag_Tracer_Yellow",20},{"30Rnd_65x39_caseless_mag",20},{"30Rnd_65x39_caseless_green",20},{"30Rnd_65x39_caseless_mag_Tracer",20}, + {"30Rnd_65x39_caseless_green_mag_Tracer",20},{"20Rnd_762x51_Mag",20},{"7Rnd_408_Mag",20},{"5Rnd_127x108_Mag",20},{"100Rnd_65x39_caseless_mag",20}, + {"100Rnd_65x39_caseless_mag_Tracer",20},{"200Rnd_65x39_cased_Box",20},{"200Rnd_65x39_cased_Box_Tracer",20},{"30Rnd_9x21_Mag",20},{"16Rnd_9x21_Mag",20}, + {"30Rnd_45ACP_Mag_SMG_01",20},{"30Rnd_45ACP_Mag_SMG_01_Tracer_Green",20},{"9Rnd_45ACP_Mag",20},{"150Rnd_762x51_Box",20},{"150Rnd_762x51_Box_Tracer",20}, + {"150Rnd_762x54_Box",20},{"150Rnd_762x54_Box_Tracer",20},{"11Rnd_45ACP_Mag",20},{"6Rnd_45ACP_Cylinder",20},{"10Rnd_762x51_Mag",20},{"10Rnd_762x54_Mag",20}, + {"5Rnd_127x108_APDS_Mag",20},{"10Rnd_338_Mag",20},{"130Rnd_338_Mag",20},{"10Rnd_127x54_Mag",20},{"150Rnd_93x64_Mag",20},{"10Rnd_93x64_DMR_05_Mag",20} + }; + + attSlotsMax = 4; // Maximum number of attachment slots in each loot crate + attSlotsMin = 2; // Minimum number of attachment slots in each loot crate + attLoot[] = + { // The number after each classname means how much of that type will be put in crate. WARNING: DO NOT USE NUMBERS WITH DECIMALS. + {"ItemGPS",5},{"ItemRadio",4},{"ItemMap",6},{"MineDetector",1},{"Binocular",4},{"Rangefinder",2},{"muzzle_snds_H",2}, + {"muzzle_snds_L",2},{"muzzle_snds_M",2},{"muzzle_snds_B",2},{"muzzle_snds_H_MG",2},{"muzzle_snds_H_SW",2}, + {"optic_Arco",3},{"optic_Aco",3},{"optic_ACO_grn",3},{"optic_Aco_smg",3},{"optic_ACO_grn_smg",3},{"optic_Holosight",3}, + {"optic_Holosight_smg",3},{"optic_SOS",3},{"acc_flashlight",3},{"acc_pointer_IR",3},{"optic_MRCO",3},{"muzzle_snds_acp",3}, + {"optic_NVS",3},{"optic_DMS",3},{"optic_Yorris",2},{"optic_MRD",2},{"optic_LRPS",3},{"muzzle_snds_338_black",3},{"muzzle_snds_338_green",3}, + {"muzzle_snds_338_sand",3},{"muzzle_snds_93mmg",3},{"muzzle_snds_93mmg_tan",3},{"optic_AMS",3},{"optic_AMS_khk",3},{"bipod_03_F_oli",3}, + {"optic_AMS_snd",3},{"optic_KHS_blk",3},{"optic_KHS_hex",3},{"optic_KHS_old",3},{"optic_KHS_tan",3},{"bipod_01_F_snd",3}, + {"bipod_01_F_blk",3},{"bipod_01_F_mtp",3},{"bipod_02_F_blk",3},{"bipod_02_F_tan",3},{"bipod_02_F_hex",3},{"bipod_03_F_blk",3} + }; + + itemSlotsMax = 4; // Maximum number of attachment slots in each loot crate + itemSlotsMin = 2; // Minimum number of attachment slots in each loot crate + itemLoot[] = + { // The number after each classname means how much of that type will be put in crate. WARNING: DO NOT USE NUMBERS WITH DECIMALS. + {"Exile_Item_Flag",3},{"Exile_Item_FuelCanisterFull",2},{"Exile_Item_FuelCanisterEmpty",1},{"Exile_Item_InstaDoc",4},{"Exile_Item_Matches",3},{"Exile_Item_PlasticBottleFreshWater",5} + }; + + vestSlotsMax = 4; // Maximum number of vest slots in each loot crate + vestSlotsMin = 2; // Minimum number of vest slots in each loot crate + vestLoot[] = // NOTE ABOUT VESTS: it is recommended to keep amount for each vest at 1 because vests do not stack unlike weapons, items and magazines + { // The number after each classname means how much of that type will be put in crate. WARNING: DO NOT USE NUMBERS WITH DECIMALS. + {"V_PlateCarrier1_rgr",1},{"V_PlateCarrier2_rgr",1},{"V_PlateCarrier3_rgr",1},{"V_PlateCarrierGL_rgr",1},{"V_PlateCarrier1_blk",1}, + {"V_PlateCarrierSpec_rgr",1},{"V_Chestrig_khk",1},{"V_Chestrig_rgr",1},{"V_Chestrig_blk",1},{"V_Chestrig_oli",1},{"V_TacVest_khk",1}, + {"V_TacVest_brn",1},{"V_TacVest_oli",1},{"V_TacVest_blk",1},{"V_TacVest_camo",1},{"V_TacVest_blk_POLICE",1},{"V_TacVestIR_blk",1},{"V_TacVestCamo_khk",1}, + {"V_HarnessO_brn",1},{"V_HarnessOGL_brn",1},{"V_HarnessO_gry",1},{"V_HarnessOGL_gry",1},{"V_HarnessOSpec_brn",1},{"V_HarnessOSpec_gry",1}, + {"V_PlateCarrierIA1_dgtl",1},{"V_PlateCarrierIA2_dgtl",1},{"V_PlateCarrierIAGL_dgtl",1},{"V_RebreatherB",1},{"V_RebreatherIR",1},{"V_RebreatherIA",1}, + {"V_PlateCarrier_Kerry",1},{"V_PlateCarrierL_CTRG",1},{"V_PlateCarrierH_CTRG",1},{"V_I_G_resistanceLeader_F",1},{"V_Press_F",1} + }; + + headGearSlotsMax = 4; // Maximum number of headGear slots in each loot crate + headGearSlotsMin = 2; // Minimum number of headGear slots in each loot crate + headGearLoot[] = // NOTE ABOUT HEADGEAR: it is recommended to keep amount for each headGear item at 1 because headGear items do not stack unlike weapons, items and magazines + { // The number after each classname means how much of that type will be put in crate. WARNING: DO NOT USE NUMBERS WITH DECIMALS. + {"H_HelmetB",1},{"H_HelmetB_camo",1},{"H_HelmetB_paint",1},{"H_HelmetB_light",1},{"H_Booniehat_khk",1},{"H_Booniehat_oli",1},{"H_Booniehat_indp",1}, + {"H_Booniehat_mcamo",1},{"H_Booniehat_grn",1},{"H_Booniehat_tan",1},{"H_Booniehat_dirty",1},{"H_Booniehat_dgtl",1},{"H_Booniehat_khk_hs",1},{"H_HelmetB_plain_mcamo",1}, + {"H_HelmetB_plain_blk",1},{"H_HelmetSpecB",1},{"H_HelmetSpecB_paint1",1},{"H_HelmetSpecB_paint2",1},{"H_HelmetSpecB_blk",1},{"H_HelmetIA",1},{"H_HelmetIA_net",1}, + {"H_HelmetIA_camo",1},{"H_Helmet_Kerry",1},{"H_HelmetB_grass",1},{"H_HelmetB_snakeskin",1},{"H_HelmetB_desert",1},{"H_HelmetB_black",1},{"H_HelmetB_sand",1}, + {"H_Cap_red",1},{"H_Cap_blu",1},{"H_Cap_oli",1},{"H_Cap_headphones",1},{"H_Cap_tan",1},{"H_Cap_blk",1},{"H_Cap_blk_CMMG",1},{"H_Cap_brn_SPECOPS",1},{"H_Cap_tan_specops_US",1}, + {"H_Cap_khaki_specops_UK",1},{"H_Cap_grn",1},{"H_Cap_grn_BI",1},{"H_Cap_blk_Raven",1},{"H_Cap_blk_ION",1},{"H_Cap_oli_hs",1},{"H_Cap_press",1},{"H_Cap_usblack",1},{"H_Cap_police",1}, + {"H_HelmetCrew_B",1},{"H_HelmetCrew_O",1},{"H_HelmetCrew_I",1},{"H_PilotHelmetFighter_B",1},{"H_PilotHelmetFighter_O",1},{"H_PilotHelmetFighter_I",1}, + {"H_PilotHelmetHeli_B",1},{"H_PilotHelmetHeli_O",1},{"H_PilotHelmetHeli_I",1},{"H_CrewHelmetHeli_B",1},{"H_CrewHelmetHeli_O",1},{"H_CrewHelmetHeli_I",1},{"H_HelmetO_ocamo",1}, + {"H_HelmetLeaderO_ocamo",1},{"H_MilCap_ocamo",1},{"H_MilCap_mcamo",1},{"H_MilCap_oucamo",1},{"H_MilCap_rucamo",1},{"H_MilCap_gry",1},{"H_MilCap_dgtl",1}, + {"H_MilCap_blue",1},{"H_HelmetB_light_grass",1},{"H_HelmetB_light_snakeskin",1},{"H_HelmetB_light_desert",1},{"H_HelmetB_light_black",1},{"H_HelmetB_light_sand",1},{"H_BandMask_blk",1}, + {"H_BandMask_khk",1},{"H_BandMask_reaper",1},{"H_BandMask_demon",1},{"H_HelmetO_oucamo",1},{"H_HelmetLeaderO_oucamo",1},{"H_HelmetSpecO_ocamo",1},{"H_HelmetSpecO_blk",1}, + {"H_Bandanna_surfer",1},{"H_Bandanna_khk",1},{"H_Bandanna_khk_hs",1},{"H_Bandanna_cbr",1},{"H_Bandanna_sgg",1},{"H_Bandanna_sand",1},{"H_Bandanna_surfer_blk",1},{"H_Bandanna_surfer_grn",1}, + {"H_Bandanna_gry",1},{"H_Bandanna_blu",1},{"H_Bandanna_camo",1},{"H_Bandanna_mcamo",1},{"H_Shemag_khk",1},{"H_Shemag_tan",1},{"H_Shemag_olive",1},{"H_Shemag_olive_hs",1}, + {"H_ShemagOpen_khk",1},{"H_ShemagOpen_tan",1},{"H_Beret_blk",1},{"H_Beret_blk_POLICE",1},{"H_Beret_red",1},{"H_Beret_grn",1},{"H_Beret_grn_SF",1},{"H_Beret_brn_SF",1}, + {"H_Beret_ocamo",1},{"H_Beret_02",1},{"H_Beret_Colonel",1},{"H_Watchcap_blk",1},{"H_Watchcap_cbr",1},{"H_Watchcap_khk",1},{"H_Watchcap_camo",1},{"H_Watchcap_sgg",1}, + {"H_TurbanO_blk",1},{"H_Cap_marshal",1} + }; + + bagSlotsMax = 4; + bagSlotsMin = 2; + backpackLoot[] = // NOTE ABOUT BACKPACKS: it is recommended to keep amount for each bag at 1 because bags do not stack unlike weapons, items and magazines + { // The number after each classname means how much of that type will be put in crate. WARNING: DO NOT USE NUMBERS WITH DECIMALS. + {"B_AssaultPack_khk",1},{"B_AssaultPack_dgtl",1},{"B_AssaultPack_rgr",1},{"B_AssaultPack_sgg",1},{"B_AssaultPack_cbr",1}, + {"B_AssaultPack_mcamo",1},{"B_TacticalPack_rgr",1},{"B_TacticalPack_mcamo",1},{"B_TacticalPack_ocamo",1},{"B_TacticalPack_blk",1}, + {"B_TacticalPack_oli",1},{"B_FieldPack_khk",1},{"B_FieldPack_ocamo",1},{"B_FieldPack_oucamo",1},{"B_FieldPack_cbr",1}, + {"B_FieldPack_blk",1},{"B_Carryall_ocamo",1},{"B_Carryall_oucamo",1},{"B_Carryall_mcamo",1},{"B_Carryall_khk",1},{"B_Carryall_cbr",1}, + {"B_Parachute",1},{"B_FieldPack_oli",1},{"B_Carryall_oli",1},{"B_Kitbag_Base",1},{"B_Kitbag_cbr",1},{"B_Kitbag_mcamo",1}, + {"B_Kitbag_rgr",1},{"B_Kitbag_sgg",1},{"B_OutdoorPack_Base",1},{"B_OutdoorPack_blk",1},{"B_OutdoorPack_blu",1}, + {"B_OutdoorPack_tan",1} + }; + + blackListLoot[] = + { + "DemoCharge_Remote_Mag","SatchelCharge_Remote_Mag","ATMine_Range_Mag","ClaymoreDirectionalMine_Remote_Mag", + "APERSMine_Range_Mag","APERSBoundingMine_Range_Mag","SLAMDirectionalMine_Wire_Mag","APERSTripMine_Wire_Mag", + "ChainSaw","srifle_DMR_03_spotter_F" + }; + // End of loot crate configuration + }; + class aiGear + { + // Configuration of what AI have + aiHeadGear[] = + { + "H_HelmetB","H_HelmetB_camo","H_HelmetB_paint","H_HelmetB_light","H_Booniehat_khk","H_Booniehat_oli","H_Booniehat_indp", + "H_Booniehat_mcamo","H_Booniehat_grn","H_Booniehat_tan","H_Booniehat_dirty","H_Booniehat_dgtl","H_Booniehat_khk_hs","H_HelmetB_plain_mcamo", + "H_HelmetB_plain_blk","H_HelmetSpecB","H_HelmetSpecB_paint1","H_HelmetSpecB_paint2","H_HelmetSpecB_blk","H_HelmetIA","H_HelmetIA_net", + "H_HelmetIA_camo","H_Helmet_Kerry","H_HelmetB_grass","H_HelmetB_snakeskin","H_HelmetB_desert","H_HelmetB_black","H_HelmetB_sand", + "H_Cap_red","H_Cap_blu","H_Cap_oli","H_Cap_headphones","H_Cap_tan","H_Cap_blk","H_Cap_blk_CMMG","H_Cap_brn_SPECOPS","H_Cap_tan_specops_US", + "H_Cap_khaki_specops_UK","H_Cap_grn","H_Cap_grn_BI","H_Cap_blk_Raven","H_Cap_blk_ION","H_Cap_oli_hs","H_Cap_press","H_Cap_usblack","H_Cap_police", + "H_HelmetCrew_B","H_HelmetCrew_O","H_HelmetCrew_I","H_PilotHelmetFighter_B","H_PilotHelmetFighter_O","H_PilotHelmetFighter_I", + "H_PilotHelmetHeli_B","H_PilotHelmetHeli_O","H_PilotHelmetHeli_I","H_CrewHelmetHeli_B","H_CrewHelmetHeli_O","H_CrewHelmetHeli_I","H_HelmetO_ocamo", + "H_HelmetLeaderO_ocamo","H_MilCap_ocamo","H_MilCap_mcamo","H_MilCap_oucamo","H_MilCap_rucamo","H_MilCap_gry","H_MilCap_dgtl", + "H_MilCap_blue","H_HelmetB_light_grass","H_HelmetB_light_snakeskin","H_HelmetB_light_desert","H_HelmetB_light_black","H_HelmetB_light_sand","H_BandMask_blk", + "H_BandMask_khk","H_BandMask_reaper","H_BandMask_demon","H_HelmetO_oucamo","H_HelmetLeaderO_oucamo","H_HelmetSpecO_ocamo","H_HelmetSpecO_blk", + "H_Bandanna_surfer","H_Bandanna_khk","H_Bandanna_khk_hs","H_Bandanna_cbr","H_Bandanna_sgg","H_Bandanna_sand","H_Bandanna_surfer_blk","H_Bandanna_surfer_grn", + "H_Bandanna_gry","H_Bandanna_blu","H_Bandanna_camo","H_Bandanna_mcamo","H_Shemag_khk","H_Shemag_tan","H_Shemag_olive","H_Shemag_olive_hs", + "H_ShemagOpen_khk","H_ShemagOpen_tan","H_Beret_blk","H_Beret_blk_POLICE","H_Beret_red","H_Beret_grn","H_Beret_grn_SF","H_Beret_brn_SF", + "H_Beret_ocamo","H_Beret_02","H_Beret_Colonel","H_Watchcap_blk","H_Watchcap_cbr","H_Watchcap_khk","H_Watchcap_camo","H_Watchcap_sgg", + "H_TurbanO_blk","H_Cap_marshal" + }; + aiUniforms[] = + { + "U_I_CombatUniform","U_I_CombatUniform_tshirt","U_I_CombatUniform_shortsleeve","U_I_pilotCoveralls", + "U_I_GhillieSuit","U_I_OfficerUniform","U_MillerBody","U_KerryBody","U_IG_Guerilla1_1","U_IG_Guerilla2_1", + "U_IG_Guerilla2_2","U_IG_Guerilla2_3","U_IG_Guerilla3_1","U_IG_Guerilla3_2","U_IG_leader","U_BG_Guerilla1_1", + "U_BG_Guerilla2_1","U_BG_Guerilla2_3","U_BG_Guerilla3_1","U_BG_Guerilla3_2","U_BG_leader","U_OG_Guerilla1_1", + "U_OG_Guerilla2_1","U_OG_Guerilla2_2","U_OG_Guerilla2_3","U_OG_Guerilla3_1","U_OG_Guerilla3_2","U_OG_leader", + "U_C_WorkerCoveralls","U_C_HunterBody_grn","U_C_HunterBody_brn","U_B_CTRG_1","U_B_CTRG_2","U_B_CTRG_3","U_B_survival_uniform", + "U_I_G_Story_Protagonist_F","U_I_G_resistanceLeader_F","U_IG_Guerrilla_6_1","U_BG_Guerrilla_6_1","U_OG_Guerrilla_6_1", + "U_B_FullGhillie_lsh","U_B_FullGhillie_sard","U_B_FullGhillie_ard","U_O_FullGhillie_lsh","U_O_FullGhillie_sard", + "U_O_FullGhillie_ard","U_I_FullGhillie_lsh","U_I_FullGhillie_sard","U_I_FullGhillie_ard" + }; + aiVests[] = + { + "V_PlateCarrier1_rgr","V_PlateCarrier2_rgr","V_PlateCarrier3_rgr","V_PlateCarrierGL_rgr","V_PlateCarrier1_blk", + "V_PlateCarrierSpec_rgr","V_Chestrig_khk","V_Chestrig_rgr","V_Chestrig_blk","V_Chestrig_oli","V_TacVest_khk", + "V_TacVest_brn","V_TacVest_oli","V_TacVest_blk","V_TacVest_camo","V_TacVest_blk_POLICE","V_TacVestIR_blk","V_TacVestCamo_khk", + "V_HarnessO_brn","V_HarnessOGL_brn","V_HarnessO_gry","V_HarnessOGL_gry","V_HarnessOSpec_brn","V_HarnessOSpec_gry", + "V_PlateCarrierIA1_dgtl","V_PlateCarrierIA2_dgtl","V_PlateCarrierIAGL_dgtl","V_RebreatherB","V_RebreatherIR","V_RebreatherIA", + "V_PlateCarrier_Kerry","V_PlateCarrierL_CTRG","V_PlateCarrierH_CTRG","V_I_G_resistanceLeader_F","V_Press_F" + }; + aiRifles[] = + { + "srifle_EBR_F","srifle_DMR_01_F","arifle_Katiba_F","arifle_Katiba_C_F","arifle_Katiba_GL_F","arifle_MXC_F", + "arifle_MX_F","arifle_MX_GL_F","arifle_MXM_F","arifle_SDAR_F","arifle_TRG21_F","arifle_TRG20_F", + "arifle_TRG21_GL_F","arifle_Mk20_F","arifle_Mk20C_F","arifle_Mk20_GL_F","arifle_Mk20_plain_F", + "arifle_Mk20C_plain_F","arifle_Mk20_GL_plain_F","SMG_01_F","SMG_02_F","hgun_PDW2000_F","arifle_MXM_Black_F", + "arifle_MX_GL_Black_F","arifle_MX_Black_F","arifle_MXC_Black_F","LMG_Mk200_F","arifle_MX_SW_F", + "LMG_Zafir_F","arifle_MX_SW_Black_F" + }; + aiBackpacks[] = + { + "B_AssaultPack_khk","B_AssaultPack_dgtl","B_AssaultPack_rgr","B_AssaultPack_sgg","B_AssaultPack_cbr", + "B_AssaultPack_mcamo","B_TacticalPack_rgr","B_TacticalPack_mcamo","B_TacticalPack_ocamo","B_TacticalPack_blk", + "B_TacticalPack_oli","B_FieldPack_khk","B_FieldPack_ocamo","B_FieldPack_oucamo","B_FieldPack_cbr", + "B_FieldPack_blk","B_Carryall_ocamo","B_Carryall_oucamo","B_Carryall_mcamo","B_Carryall_khk","B_Carryall_cbr", + "B_Parachute","B_FieldPack_oli","B_Carryall_oli","B_Kitbag_Base","B_Kitbag_cbr","B_Kitbag_mcamo", + "B_Kitbag_rgr","B_Kitbag_sgg","B_OutdoorPack_Base","B_OutdoorPack_blk","B_OutdoorPack_blu", + "B_OutdoorPack_tan" + }; + aiLaunchers[] = + { + "launch_NLAW_F","launch_RPG32_F","launch_B_Titan_F","launch_B_Titan_short_F" + }; + aiPistols[] = + { + "hgun_ACPC2_F","hgun_Rook40_F","hgun_P07_F","hgun_Pistol_heavy_01_F","hgun_Pistol_heavy_02_F" + }; + }; +}; + +class CfgPatches +{ + class exile_vemf_reloaded + { + units[] = {}; + requiredAddons[] = {"exile_server"}; + fileName = "exile_vemf_reloaded.pbo"; + requiredVersion = 1.56; // VEMF does not work on older versions due to use of the latest scripting commands + version = 0740.30; // Do NOT change + author[]= {"IT07"}; + }; +}; + +class CfgFunctions +{ + class exile_vemf_reloaded + { + tag = "VEMFr"; + class serverFunctions + { + file = "exile_vemf_reloaded\functions"; + class log {}; + class getSetting {}; + class aiKilled {}; + class findPos {}; + class broadCast {}; + class playerCount {}; + class headLessClient {}; + class signAI {}; + class transferOwner {}; + class checkPlayerPresence {}; + class loadInv {}; + class giveAmmo {}; + class giveWeaponItems {}; + class spawnAI {}; + class spawnStaticAI {}; + class loadLoot {}; + class placeMines {}; + class waitForPlayers {}; + class waitForMissionDone {}; + class checkLoot {}; + class missionTimer {}; + class launch { postInit = 1; }; + class REMOTEguard { postInit = 1; }; + }; + }; +}; diff --git a/exile_vemf_reloaded/functions/fn_REMOTEguard.sqf b/exile_vemf_reloaded/functions/fn_REMOTEguard.sqf new file mode 100644 index 0000000..19b03df --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_REMOTEguard.sqf @@ -0,0 +1,38 @@ +/* + Author: IT07 + + Description: + this function makes sure that AI spawned by VEMF does NOT become local to the server. + On detection of a local group, it will reassign it to a client or Headless Client if enabled. + + Params: + none, this is a Standalone function + + Returns: + nothing +*/ + +[] spawn +{ + uiNamespace setVariable ["VEMFrHcLoad", []]; + uiNamespace setVariable ["vemfGroups", []]; + while {true} do + { + _groups = uiNamespace getVariable "vemfGroups"; + waitUntil { uiSleep 1; count _groups > 0 }; + { + if (local _x) then + { + if ((count units _x) < 1) then + { + deleteGroup _x; + }; + if (count (units _x) > 0) then + { + // Group still has units, check if there is anyone that can be the owner + [_x] call VEMFr_fnc_transferOwner; + }; + }; + } forEach _groups; + }; +}; diff --git a/exile_vemf_reloaded/functions/fn_aiKilled.sqf b/exile_vemf_reloaded/functions/fn_aiKilled.sqf new file mode 100644 index 0000000..9530a78 --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_aiKilled.sqf @@ -0,0 +1,199 @@ +/* + VEMF AI Killed by Vampire, rewritten by IT07 + + Description: + removes launchers if desired and announces the kill if enabled in config.cpp + + Params: + _this: ARRAY + _this select 0: OBJECT - the killed AI + _this select 1: OBJECT - killer + + Returns: + nothing +*/ + +if (_this isEqualType []) then +{ + _target = param [0, objNull, [objNull]]; + if not isNull _target then + { + _target removeAllEventHandlers "MPKilled"; + _settings = [["aiCleanup"],["removeLaunchers","aiDeathRemovalEffect","removeHeadGear"]] call VEMFr_fnc_getSetting; + _removeLaunchers = _settings select 0; + if (_removeLaunchers isEqualTo 1) then + { + _secWeapon = secondaryWeapon _target; + if not(_secWeapon isEqualTo "") then + { + _target removeWeaponGlobal _secWeapon; + _missiles = getArray (configFile >> "cfgWeapons" >> _secWeapon >> "magazines"); + { + if (_x in _missiles) then + { + _target removeMagazineGlobal _x; + }; + } forEach (magazines _target); + }; + }; + + + _killer = param [1, objNull, [objNull]]; + if isPlayer _killer then // Only allow this function to work if killer is an actual player + { + if (vehicle _killer isEqualTo _killer) then // If killer is on foot + { + _respectReward = "respectReward" call VEMFr_fnc_getSetting; + if (_respectReward > 1) then + { + _message = [[]]; + _killMsg = selectRandom ["AI WACKED","AI CLIPPED","AI DISABLED","AI DISQUALIFIED","AI WIPED","AI ERASED","AI LYNCHED","AI WRECKED","AI NEUTRALIZED","AI SNUFFED","AI WASTED","AI ZAPPED"]; + (_message select 0) pushBack [_killMsg,_respectReward]; + _dist = _target distance _killer; + switch true do + { + case (_dist <= 5): + { + (_message select 0) pushBack ["CQB Master", 25] + }; + case (_dist <= 10): + { + (_message select 0) pushBack ["Close one", 15] + }; + case (_dist <= 50): + { + (_message select 0) pushBack ["Danger close", 15] + }; + case (_dist <= 100): + { + (_message select 0) pushBack ["Lethal aim", 20] + }; + case (_dist <= 200): + { + (_message select 0) pushBack ["Deadly.", 25] + }; + case (_dist <= 500): + { + (_message select 0) pushBack ["Niiiiice.", 30] + }; + case (_dist <= 1000): + { + (_message select 0) pushBack ["Dat distance...", 45] + }; + case (_dist <= 2000): + { + (_message select 0) pushBack ["Danger far.", 50] + }; + case (_dist > 2000): + { + (_message select 0) pushBack [format["hax? %1m!!!", round _dist], 65] + }; + }; + if not(_killer isEqualTo (driver (vehicle _killer))) then + { + _killer = gunner _killer; + }; + if (_killer isEqualTo (driver(vehicle _killer))) then + { + _killer = driver (vehicle _killer); + }; + _curRespect = _killer getVariable ["ExileScore", 0]; + //diag_log text format["_curRespect of _killer (%1) is %2", _killer, _curRespect]; + _respectToGive = (((_message select 0) select 1) select 1); + _newRespect = _curRespect + _respectToGive + _respectReward; + _killer setVariable ["ExileScore", _newRespect]; + ExileClientPlayerScore = _newRespect; + (owner _killer) publicVariableClient "ExileClientPlayerScore"; + ExileClientPlayerScore = nil; + [_killer, "showFragRequest", _message] call ExileServer_system_network_send_to; + format["setAccountMoneyAndRespect:%1:%2:%3", _killer getVariable ["ExileMoney", 0], _newRespect, (getPlayerUID _killer)] call ExileServer_system_database_query_fireAndForget; + }; + + _sayKilled = "sayKilled" call VEMFr_fnc_getSetting; + if (_sayKilled > 0) then // Send kill message if enabled + { + _killer = param [1, objNull, [objNull]]; + _dist = _target distance _killer; + if (_dist > 1) then + { + private ["_curWeapon"]; + if (vehicle _killer isEqualTo _killer) then // If on foot + { + _curWeapon = currentWeapon _killer; + }; + if not(vehicle _killer isEqualTo _killer) then // If in vehicle + { + _curWeapon = currentWeapon (vehicle _killer); + }; + if (_sayKilled isEqualTo 1) then + { + _kMsg = format["(VEMFr) %1 [%2, %3m] AI", name _killer, getText(configFile >> "CfgWeapons" >> _curWeapon >> "displayName"), round _dist]; + [_kMsg, "sys"] spawn VEMFr_fnc_broadCast; + }; + if (_sayKilled isEqualTo 2) then + { + VEMFrClientMsg = [format["(VEMFr) You [%1, %2m] AI", getText(configFile >> "CfgWeapons" >> _curWeapon >> "displayName"), round _dist], "sys"]; + (owner _killer) publicVariableClient "VEMFrClientMsg"; + VEMFrClientMsg = nil; + }; + }; + }; + }; + + if not(vehicle _killer isEqualTo _killer) then // If killer is driver + { // Send kill message if enabled + _dist = _target distance _killer; + if (_dist < 5) then + { + if (("sayKilled" call VEMFr_fnc_getSetting) isEqualTo 1) then + { + if (isPlayer _killer) then // Should prevent Error:NoUnit + { + _kMsg = format["(VEMFr) %1 [Roadkill] AI", name _killer]; + //_kMsg = format["(VEMFr) %1 [%2] AI", name _killer, getText(configFile >> "CfgVehicles" >> typeOf (vehicle _killer) >> "displayName")]; + [_kMsg, "sys"] spawn VEMFr_fnc_broadCast; + }; + }; + if (("punishRoadKills" call VEMFr_fnc_getSetting) isEqualTo 1) then + { + _respectDeduct = "respectRoadKillDeduct" call VEMFr_fnc_getSetting; + _curRespect = _killer getVariable ["ExileScore", 0]; + //diag_log text format["_curRespect of _killer (%1) is %2", _killer, _curRespect]; + _newRespect = _curRespect - _respectDeduct; + _killer setVariable ["ExileScore", _newRespect]; + ExileClientPlayerScore = _newRespect; + (owner _killer) publicVariableClient "ExileClientPlayerScore"; + ExileClientPlayerScore = nil; + [_killer, "showFragRequest", [[["ROADKILL..."],["Respect Penalty:", -_respectDeduct]]]] call ExileServer_system_network_send_to; + format["setAccountMoneyAndRespect:%1:%2:%3", _killer getVariable ["ExileMoney", 0], _newRespect, (getPlayerUID _killer)] call ExileServer_system_database_query_fireAndForget; + }; + }; + }; + }; + + if (_settings select 2 isEqualTo 1) then // If removeHeadGear setting is enabled + { + removeHeadGear _target; + }; + + if (_settings select 1 isEqualTo 1) then // If killEffect enabled + { + playSound3D ["A3\Missions_F_Bootcamp\data\sounds\vr_shutdown.wss", _target, false, getPosASL _target, 2, 1, 60]; + for "_u" from 1 to 12 do + { + if not(isObjectHidden _target) then + { + _target hideObjectGlobal true; + } else + { + _target hideObjectGlobal false; + }; + uiSleep 0.12; + }; + _target hideObjectGlobal true; + removeAllWeapons _target; + // Automatic cleanup yaaay + deleteVehicle _target; + }; + }; +}; diff --git a/exile_vemf_reloaded/functions/fn_broadCast.sqf b/exile_vemf_reloaded/functions/fn_broadCast.sqf new file mode 100644 index 0000000..5785d4d --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_broadCast.sqf @@ -0,0 +1,30 @@ +/* + Author: IT07 + + Description: + will alert players + + Params: + _this select 0: FORMATTED STRING - thing to send + _this select 1: STRING - mode to send to client + + Returns: + nothing +*/ + +private ["_msg","_mode"]; +_msg = param [0, "", [[],format[""]]]; +if not(_msg isEqualTo "") then +{ + _mode = param [1, "", [""]]; + if (count allPlayers > 0) then + { + { + if (isPlayer _x) then + { + VEMFrClientMsg = [_msg, _mode]; + (owner _x) publicVariableClient "VEMFrClientMsg"; + }; + } forEach allPlayers; + }; +}; diff --git a/exile_vemf_reloaded/functions/fn_checkLoot.sqf b/exile_vemf_reloaded/functions/fn_checkLoot.sqf new file mode 100644 index 0000000..4fc174b --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_checkLoot.sqf @@ -0,0 +1,70 @@ +/* + Author: IT07 + + Description: + checks the VEMF loot table for invalid classnames. Reports to RPT if invalid classes found. + + Params: + none + + Returns: + nothing +*/ + +_validateLoot = if ("validateLoot" call VEMFr_fnc_getSetting isEqualTo 1) then { true } else { false }; +if _validateLoot then +{ + // _validateLoot is enabled, go ahead... + if ("debugMode" call VEMFr_fnc_getSetting isEqualTo 0) then + { + ["CheckLoot", 0, "validateLoot is enabled, but no feedback allowed by debugMode setting!"] spawn VEMFr_fnc_log; + }; + ["CheckLoot", 1, "Validating loot tables..."] spawn VEMFr_fnc_log; + _invalidClasses = []; + + _mags = []; + _cfgMags = "_mags pushBack (configName _x); true" configClasses (configFile >> "cfgMagazines"); + + _weapons = []; + _cfgWeapons = "_weapons pushBack (configName _x); true" configClasses (configFile >> "cfgWeapons"); + + _bags = []; + _cfgBags = "getText (_x >> 'vehicleClass') isEqualTo 'Backpacks'" configClasses (configFile >> "cfgVehicles"); + { + _bags pushBack (configName _x); + } forEach _cfgBags; + + _aiGear = [["aiGear"],["aiUniforms","aiVests","aiRifles","aiBackpacks","aiLaunchers","aiPistols"]] call VEMFr_fnc_getSetting; + { + { + if not((_x in _mags) OR (_x in _weapons) OR (_x in _bags)) then + { + _invalidClasses pushBack _x; + }; + } forEach _x; + } forEach _aiGear; + + _loot = [["crateLoot"],["primaryWeaponLoot","secondaryWeaponLoot","magazinesLoot","attachmentsLoot","itemsLoot","vestsLoot","headGearLoot","backpacksLoot"]] call VEMFr_fnc_getSetting; + { + { + _class = _x select 0; + if not((_class in _mags) OR (_class in _weapons) OR (_class in _bags)) then + { + _invalidClasses pushBack _x; + }; + } forEach _x; + } forEach _loot; + + _invalid = if (count _invalidClasses isEqualTo 0) then { false } else { true }; + switch true do + { + case _invalid: + { + ["CheckLoot", 0, format["Invalid classes found in loot! | %1", _invalidClasses]] spawn VEMFr_fnc_log; + }; + case (not _invalid): + { + ["CheckLoot", 1, "Loot tables are all valid :)"] spawn VEMFr_fnc_log; + }; + }; +}; diff --git a/exile_vemf_reloaded/functions/fn_checkPlayerPresence.sqf b/exile_vemf_reloaded/functions/fn_checkPlayerPresence.sqf new file mode 100644 index 0000000..96e7623 --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_checkPlayerPresence.sqf @@ -0,0 +1,40 @@ +/* + Author: IT07 + + Description: + checks for players within given distance of given location/position + + Params: + _this select 0: POSITION - center of area to check around + _this select 1: SCALAR - radius around the position to check for players + + Returns: + BOOL - true if player(s) found +*/ + +private ["_pos","_rad","_objs","_found","_isClose"]; // Prevents these variables overwriting existing vars from where this was called from +// By default, we assume that there are no players close. The distance check below should prove otherwise if there are players close +_found = false; +_pos = param [0, [], [[]]]; +if (count _pos isEqualTo 3) then +{ + _rad = param [1, -1, [0]]; + if (_rad > -1) then + { // Check all player distances from _loc + if (count allPlayers > 0) then + { + { + if (isPlayer _x) then + { + if (speed _x < 250) then // Ignore fast moving players + { + _isClose = if ((position _x distance _pos) < _rad) then { true } else { false }; + if _isClose then { _found = true }; + }; + }; + } forEach allPlayers; + }; + }; +}; + +_found diff --git a/exile_vemf_reloaded/functions/fn_findPos.sqf b/exile_vemf_reloaded/functions/fn_findPos.sqf new file mode 100644 index 0000000..c8b8bff --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_findPos.sqf @@ -0,0 +1,221 @@ +/* + Author: IT07 + + Description: + can find a location or pos randomly on the map where there are no players + + Params: + _this select 0: STRING - Mode to use. Options: "loc" or "pos" + _this select 1: BOOLEAN - True if _pos needs to be a road + _this select 2: OBJECT - Center for nearestLocations check + _this select 3: SCALAR - Max distance in meters from center to search for _pos + _this select 4: SCALAR - Distance in meters. Locations closer than that will be excluded + _this select 5: SCALAR - Max prefered distance in meters from center. If not achievable, further dest will be selected + _this select 6: SCALAR - Distance in meters to check from _cntr for players + + Returns: + ARRAY - [name of town, town position] +*/ + +private ["_settings","_locPos","_loc","_locName","_ret","_continue","_settings","_blackList","_usedLocs","_checkRange","_tooCloseRange","_maxPrefered","_skipDistance","_nonPopulated","_mode","_pos","_hasPlayers","_blackPos","_checkBlackPos"]; + +_ret = false; +// Define settings +_settings = [["nonPopulated","noMissionPos","missionDistance"]] call VEMFr_fnc_getSetting; +_nonPopulated = _settings param [0, 1, [0]]; +_blackPos = _settings param [1, [], [[]]]; +_missionDistance = _settings param [2, 3000, [0]]; +_checkBlackPos = false; +if (count _blackPos > 0) then +{ + _checkBlackPos = true; +}; +_mode = param [0, "", [""]]; +if not(_mode isEqualTo "") then +{ + _onRoad = param [1, false, [false]]; + _roadRange = 5000; + _cntr = param [2, [], [[]]]; + if (count _cntr > 0) then + { + _rad = param [3, -1, [0]]; + if (_rad > -1) then + { + _tooCloseRange = param [4, -1, [0]]; + if (_tooCloseRange > -1) then + { + _maxPrefered = param [5, -1, [0]]; + if (_maxPrefered > -1) then + { + _skipDistance = param [6, -1, [0]]; + if (_skipDistance > -1) then + { + if (_mode isEqualTo "loc") then + { + // Get a list of locations close to _cntr (position of player) + _locs = nearestLocations [_cntr, ["Area","BorderCrossing","CityCenter","Hill","fakeTown","Name","RockArea","Strategic","StrongpointArea","ViewPoint","NameVillage","NameCity","NameCityCapital",if(_nonPopulated isEqualTo 1)then{"nameLocal"}], _rad]; + if (count _locs > 0) then + { + _usedLocs = uiNamespace getVariable "VEMFrUsedLocs"; + _remLocs = []; + _blackListMapClasses = "true" configClasses (configFile >> "CfgVemfReloaded" >> "locationBlackLists"); + _listedMaps = []; // Define + { // Make a list of locationBlackLists's children + _listedMaps pushBack (configName _x); + } forEach _blackListMapClasses; + private ["_blackList"]; + if (worldName in _listedMaps) then { _blackList = ([["locationBlackLists", worldName],["locations"]] call VEMFr_fnc_getSetting) select 0 }; + if not(worldName in _listedMaps) then { _blackList = ([["locationBlackLists","Other"],["locations"]] call VEMFr_fnc_getSetting) select 0 }; + + { // Check _locs for invalid locations (too close, hasPlayers or inBlacklist) + _hasPlayers = [locationPosition _x, _skipDistance] call VEMFr_fnc_checkPlayerPresence; + if _hasPlayers then + { + _remLocs pushBack _x; + }; + if not _hasPlayers then + { + if _checkBlackPos then + { + private ["_locPos","_loc"]; + _locPos = locationPosition _x; + _loc = _x; + { + if (count _x isEqualTo 2) then + { + _pos = _x param [0, [0,0,0], [[]]]; + if not(_pos isEqualTo [0,0,0]) then + { + _range = _x param [1, 600, [0]]; + if ((_pos distance _locPos) < _range) then + { + _remLocs pushBack _loc; + }; + }; + }; + if not(count _x isEqualTo 2) then + { + ["fn_findPos", 0, format["found invalid entry in mission blacklist: %1", _x]] spawn VEMFr_fnc_log; + }; + } forEach _blackPos; + }; + if ((text _x) in _blackList) then + { + _remLocs pushBack _x; + }; + if not((text _x) in _blackList) then + { + if (_cntr distance (locationPosition _x) < _tooCloseRange) then + { + _remLocs pushBack _x; + }; + if (_cntr distance (locationPosition _x) > _tooCloseRange) then + { + if (([text _x, locationPosition _x]) in _usedLocs) then + { + _remLocs pushBack _x; + }; + }; + }; + if (count _usedLocs > 0) then + { + private ["_loc"]; + _loc = _x; + { + if (((locationPosition _loc) distance (_x select 1)) < _missionDistance) then + { + _remLocs pushBack _loc; + }; + } forEach _usedLocs; + }; + }; + } forEach _locs; + + { // Remove all invalid locations from _locs + _index = _locs find _x; + _locs deleteAt _index; + } forEach _remLocs; + + // Check what kind of distances we have + _far = []; // Further than _maxPrefered + _pref = []; // Closer then _maxPrefered + { + _dist = _cntr distance (locationPosition _x); + if (_dist > _maxPrefered) then + { + _far pushBack _x; + }; + if (_dist < _maxPrefered) then + { + _pref pushBack _x; + }; + } forEach _locs; + + // Check if there are any prefered locations. If yes, randomly select one + if (count _pref > 0) then + { + _loc = selectRandom _pref; + }; + + // Check if _far has any locations and if _pref is empty + if (count _far > 0) then + { + if (count _pref isEqualTo 0) then + { + _loc = selectRandom _far; + }; + }; + + // Validate _locs just to prevent the .RPT from getting spammed + if (count _locs > 0) then + { + // Return Name and POS + _ret = [text _loc, locationPosition _loc]; + (uiNamespace getVariable "VEMFrUsedLocs") pushBack _ret; + }; + }; + }; + if (_mode isEqualTo "pos") then + { + _valid = false; + for "_p" from 1 to 10 do + { + if (_ret isEqualType true) then + { + if not _ret then + { + _pos = [_cntr, _tooCloseRange, _rad, 2, 0, 500, 0] call BIS_fnc_findSafePos; + if _onRoad then + { + _roads = _pos nearRoads _roadRange; + if (count _roads > 0) then + { + private ["_closest","_dist"]; + _closest = ["", _roadRange]; + { // Find the closest road + _dist = _x distance _pos; + if (_dist < (_closest select 1)) then + { + _closest = [_x, _dist]; + }; + } forEach _roads; + _pos = position (_closest select 0); + }; + }; + _hasPlayers = [_pos, _skipDistance] call VEMFr_fnc_checkPlayerPresence; + if not(_hasPlayers) then + { + _ret = _pos; + }; + }; + }; + }; + }; + }; + }; + }; + }; + }; +}; + +_ret diff --git a/exile_vemf_reloaded/functions/fn_getSetting.sqf b/exile_vemf_reloaded/functions/fn_getSetting.sqf new file mode 100644 index 0000000..73f2e7a --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_getSetting.sqf @@ -0,0 +1,83 @@ +/* + Author: IT07 + + Description: + gets config value of given var from VEMF config OR cfgPath + + Params: + method 1: + _this: STRING - SINGLE config value to get from root of CfgVemfReloaded + method 2: + _this select 0: ARRAY of STRINGS - MULTIPLE config values to get from root of VEMFconfig + method 3: + _this select 0: ARRAY of STRINGS - config path to get value from. Example: "root","subclass" + _this select 1: ARRAY of STRINGS - MULTIPLE config values to get from given path + + Returns: + ARRAY - Result +*/ + +private["_cfg","_v","_r","_path","_check"]; +_r = []; +_check = +{ + if (isNumber _cfg) then + { + _v = getNumber _cfg + }; + if not(isNumber _cfg) then + { + if (isText _cfg) then + { + _v = getText _cfg + }; + if not(isText _cfg) then + { + if (isArray _cfg) then + { + _v = getArray _cfg + }; + }; + }; +}; + +if (_this isEqualType "") then +{ + _cfg = configFile >> "CfgVemfReloaded" >> _this; + call _check; + if not(isNil"_v") then + { + _r = _v; + }; +}; + +if (_this isEqualType []) then +{ + if (count _this isEqualTo 2) then + { + _cfg = configFile >> "CfgVemfReloaded"; + _path = _cfg; + { + _path = _path >> _x; // Build the config path + } forEach (_this select 0); + { + _cfg = _path >> _x; + call _check; + if not isNil"_v" then + { + _r pushBack _v + }; + } forEach (_this select 1); + }; + if (count _this isEqualTo 1) then + { + { + _cfg = configFile >> "CfgVemfReloaded" >> _x; + call _check; + _r pushBack _v; + } forEach (_this select 0); + }; +}; + +if isNil"_v" then { _r = nil }; +_r diff --git a/exile_vemf_reloaded/functions/fn_giveAmmo.sqf b/exile_vemf_reloaded/functions/fn_giveAmmo.sqf new file mode 100644 index 0000000..b7a3e1f --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_giveAmmo.sqf @@ -0,0 +1,119 @@ +/* + Author: IT07 + + Description: + Adds magazines to given unit's vest/backpack if it flairTypes + + Params: + _this: ARRAY + _this select 0: OBJECT - unit to give ammo to + + Returns: + BOOLEAN - true if successful +*/ + +private ["_done"]; +_done = false; +if (_this isEqualType []) then +{ + private ["_unit"]; + _unit = param [0, objNull, [objNull]]; + if not isNull _unit then + { + if local _unit then + { + if not(primaryWeapon _unit isEqualTo "") then + { + if not(vest _unit isEqualTo "") then + { + private ["_itemMass","_weapon","_mag","_magMass","_vestMass","_itemMass"]; + _weapon = primaryWeapon _unit; + _mag = selectRandom (getArray (configFile >> "CfgWeapons" >> _weapon >> "magazines")); + _magMass = getNumber (configFile >> "CfgMagazines" >> _mag >> "mass"); + _vestMass = getNumber (configFile >> "CfgWeapons" >> (vest _unit) >> "ItemInfo" >> "mass"); + { + _itemMass = getNumber (configFile >> "CfgMagazines" >> _x >> "ItemInfo" >> "mass"); + if (_itemMass isEqualTo 0) then + { + _itemMass = getNumber (configFile >> "CfgWeapons" >> _x >> "WeaponSlotsInfo" >> "mass"); + }; + _vestMass = _vestMass - _itemMass; + } forEach (vestItems _unit); + if (_vestMass >= _magMass) then + { + for "_m" from 1 to (round(_vestMass / _magMass)) do + { + _unit addItemToVest _mag; + }; + }; + }; + }; + if not (secondaryWeapon _unit isEqualTo "") then + { + if not(backPack _unit isEqualTo "") then + { + private ["_weapon","_mag","_magMass"]; + _weapon = secondaryWeapon _unit; + _mag = selectRandom (getArray (configFile >> "CfgWeapons" >> _weapon >> "magazines")); + _magMass = getNumber (configFile >> "CfgMagazines" >> _mag >> "mass"); + if not(backpack _unit isEqualTo "") then + { + private ["_packMass"]; + _packMass = getNumber (configFile >> "CfgVehicles" >> (backpack _unit) >> "mass"); + { + private ["_itemMass"]; + _itemMass = getNumber (configFile >> "CfgMagazines" >> _x >> "mass"); + if (_itemMass isEqualTo 0) then + { + _itemMass = getNumber (configFile >> "CfgWeapons" >> _x >> "WeaponSlotsInfo" >> "mass"); + }; + _packMass = _packMass - _itemMass; + } forEach (backpackItems _unit); + if (_packMass >= _magMass) then + { + for "_m" from 1 to (round(_packMass / _magMass)) do + { + _unit addItemToBackpack _mag; + }; + }; + }; + }; + }; + if not (handGunWeapon _unit isEqualTo "") then + { + if not(uniform _unit isEqualTo "") then + { + private ["_weapon","_mag","_uniformMass"]; + _weapon = handGunWeapon _unit; + _mag = selectRandom (getArray (configFile >> "CfgWeapons" >> _weapon >> "magazines")); + _magMass = getNumber (configFile >> "CfgMagazines" >> _mag >> "mass"); + _uniformMass = getNumber (configFile >> "CfgWeapons" >> (uniform _unit) >> "ItemInfo" >> "mass"); + { + private ["_itemMass"]; + _itemMass = getNumber (configFile >> "CfgMagazines" >> _x >> "mass"); + if (_itemMass isEqualTo 0) then + { + _itemMass = getNumber (configFile >> "CfgWeapons" >> _x >> "WeaponSlotsInfo" >> "mass"); + }; + _uniformMass = _uniformMass - _itemMass; + } forEach (uniformItems _unit); + for "_m" from 1 to (round(_uniformMass / _magMass)) do + { + _unit addItemToUniform _mag; + }; + }; + }; + _done = true; + }; + if not local _unit then + { + ["fn_giveAmmo", 0, format["%1 is not local. Can not execute!", _unit]] spawn VEMfr_fnc_log; + }; + }; + if isNull _unit then + { + ["fn_giveAmmo", 0, "_unit isNull. Can not execute!"] spawn VEMFr_fnc_log; + }; +}; + +_done diff --git a/exile_vemf_reloaded/functions/fn_giveWeaponItems.sqf b/exile_vemf_reloaded/functions/fn_giveWeaponItems.sqf new file mode 100644 index 0000000..1f083d7 --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_giveWeaponItems.sqf @@ -0,0 +1,78 @@ +/* + Author: IT07 + + Description: + Gives random weapon attachments to given unit + + Params: + _this: ARRAY + _this select 0: OBJECT - unit + + Returns: BOOLEAN - if not isNull _unit, returns true +*/ + +private ["_done","_unit","_randomPattern","_primaryWeapon","_unit","_handgunWeapon"]; +_done = false; +if (_this isEqualType []) then +{ + _unit = param [0, objNull, [objNull]]; + if not (isNull _unit) then + { + // primaryWeapon items + private ["_randomPattern"]; + _randomPattern = [1,0,1,0,1,1,1,1,0,0,1,1,1]; + _primaryWeapon = primaryWeapon _unit; + if (selectRandom _randomPattern isEqualTo 1) then + { // Select random scope + _scopes = getArray (configFile >> "CfgWeapons" >> _primaryWeapon >> "WeaponSlotsInfo" >> "CowsSlot" >> "compatibleItems"); + if ([["DynamicLocationInvasion"],["allowTWS"]] call VEMFr_fnc_getSetting isEqualTo 0) then + { + private["_indexes"]; + _indexes = []; + { + if not(_x find "tws" isEqualTo -1) then + { + _indexes pushBack _forEachIndex; + }; + if not(_x find "TWS" isEqualTo -1) then + { + _indexes pushBack _forEachIndex; + }; + } forEach _scopes; + if (count _indexes > 0) then + { + { + _scopes deleteAt _x; + } forEach _indexes; + }; + }; + _unit addPrimaryWeaponItem (selectRandom _scopes); + }; + if (selectRandom _randomPattern isEqualTo 1) then + { // Select random muzzle + _unit addPrimaryWeaponItem (selectRandom (getArray (configFile >> "CfgWeapons" >> _primaryWeapon >> "WeaponSlotsInfo" >> "MuzzleSlot" >> "compatibleItems"))); + }; + if (selectRandom _randomPattern isEqualTo 1) then + { // Select random pointer + _unit addPrimaryWeaponItem (selectRandom (getArray (configFile >> "CfgWeapons" >> _primaryWeapon >> "WeaponSlotsInfo" >> "PointerSlot" >> "compatibleItems"))); + }; + if (selectRandom _randomPattern isEqualTo 1) then + { // Select random bipod + _unit addPrimaryWeaponItem (selectRandom (getArray (configFile >> "CfgWeapons" >> _primaryWeapon >> "WeaponSlotsInfo" >> "UnderbarrelSlot" >> "compatibleItems"))); + }; + + // handgunWeapon items + _handgunWeapon = handgunWeapon _unit; + _randomPattern = [1,0,1,0,0,1,0,0,0,0,1,1,1]; + if (selectRandom _randomPattern isEqualTo 1) then + { // Select random scope + _unit addSecondaryWeaponItem (selectRandom (getArray (configFile >> "CfgWeapons" >> _handgunWeapon >> "WeaponSlotsInfo" >> "CowsSlot" >> "compatibleItems"))); + }; + if (selectRandom _randomPattern isEqualTo 1) then + { // Select random muzzle + _unit addSecondaryWeaponItem (selectRandom (getArray (configFile >> "CfgWeapons" >> _handgunWeapon >> "WeaponSlotsInfo" >> "MuzzleSlot" >> "compatibleItems"))); + }; + _done = true; + }; +}; +_done diff --git a/exile_vemf_reloaded/functions/fn_headLessClient.sqf b/exile_vemf_reloaded/functions/fn_headLessClient.sqf new file mode 100644 index 0000000..ac77a75 --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_headLessClient.sqf @@ -0,0 +1,52 @@ +/* + Author: IT07 + + Description: + selects a headless client with least (VEMF) load + + Params: + None + + Returns: + OBJECT - the headless client +*/ + +if (("headLessClientSupport" call VEMFr_fnc_getSetting) isEqualTo 1) then +{ + // Ok, Headless Clients enabled. let us continue + _hcList = "headLessClientNames" call VEMFr_fnc_getSetting; + // We have the names now, check if any of them is actually ingame + _ingameHCs = []; + { + if (typeOf _x isEqualTo "HeadlessClient_F") then + { + if (_x in _hcList) then + { + _ingameHCs pushBack [_x, name _x]; + }; + }; + } forEach allPlayers; + if (count _ingameHCs > 0) then + { + // At least 1 of given headless clients is ingame, lets check their load + _globalLoad = uiNamespace getVariable "VEMFrHcLoad"; + _lowestLoad = 99999; + _hasLowest = ""; + { // Find the lowest load number + _load = _x select 1; + if (_load < _lowestLoad) then + { + _lowestLoad = _load; + _hasLowest = _x select 0; + }; + } forEach _globalLoad; + // HC with lowest load found, add +1 to its current load + _index = _globalLoad find [_hasLowest, _lowestLoad]; + if (_index > -1) then + { + _globalLoad set [_index,[_hasLowest, _lowestLoad +1]] + }; + }; +}; +// Lowest load found, send it +_hasLowest diff --git a/exile_vemf_reloaded/functions/fn_launch.sqf b/exile_vemf_reloaded/functions/fn_launch.sqf new file mode 100644 index 0000000..24055f2 --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_launch.sqf @@ -0,0 +1,15 @@ +/* + Author: IT07 + + Description: + launches VEMFr (You don't say?) +*/ + +["Launcher", 2, format["/// STARTING v%1 \\\", getNumber (configFile >> "CfgPatches" >> "Exile_VEMF_Reloaded" >> "version")]] spawn VEMFr_fnc_log; +uiNamespace setVariable ["VEMFrUsedLocs", []]; +uiNamespace setVariable ["VEMFrHcLoad", []]; +[] spawn VEMFr_fnc_checkLoot; // Check loot tables if enabled +[] spawn VEMFr_fnc_missionTimer; // Launch mission timer +[] spawn VEMFr_fnc_spawnStaticAI; // Launch Static AI spawner +west setFriend [independent, 0]; +independent setFriend [west, 0]; diff --git a/exile_vemf_reloaded/functions/fn_loadInv.sqf b/exile_vemf_reloaded/functions/fn_loadInv.sqf new file mode 100644 index 0000000..6d08f4b --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_loadInv.sqf @@ -0,0 +1,220 @@ +/* + Author: VAMPIRE, rebooted by IT07 + + Description: + loads AI inventory + + Param: + _this: ARRAY + _this select 0: ARRAY - units to load inventory for + _this select 1: STRING - what type of mission the loadout should be for + _this select 2: SCALAR - inventory mode + + Returns: + BOOLEAN - true if nothing failed +*/ + +private ["_ok","_params","_units","_mode","_settings","_aiLaunchers","_aiGear","_uniforms","_headGear","_vests","_backpacks","_launchers","_rifles","_pistols","_aiMode","_givenAmmo"]; +_ok = false; +_params = _this; +if (_this isEqualType []) then +{ + _units = param [0, [], [[]]]; + if (count _units > 0) then + { + _mode = param [1, "", [""]]; + if not(_mode isEqualTo "") then + { + _aiMode = param [2, 0, [0]]; + if (_aiMode isEqualTo 0) then + { + // Define settings + _aiGear = [["aiGear"],["aiUniforms","aiHeadGear","aiVests","aiBackpacks","aiLaunchers","aiRifles","aiPistols"]] call VEMFr_fnc_getSetting; + _uniforms = _aiGear select 0; + _headGear = _aiGear select 1; + _vests = _aiGear select 2; + _backpacks = _aiGear select 3; + _rifles = _aiGear select 5; + _pistols = _aiGear select 6; + _aiLaunchers = ([["DynamicLocationInvasion"],["aiLaunchers"]] call VEMFr_fnc_getSetting) select 0; + if (_aiLaunchers isEqualTo 1) then + { + _launchers = _aiGear select 4; + }; + { + private ["_unit","_gear","_ammo"]; + _unit = _x; + // Strip it + removeAllWeapons _unit; + removeAllItems _unit; + if ("removeAllAssignedItems" call VEMFr_fnc_getSetting isEqualTo 1) then + { + removeAllAssignedItems _unit; + }; + removeUniform _unit; + removeVest _unit; + removeBackpack _unit; + removeGoggles _unit; + removeHeadGear _unit; + + _gear = selectRandom _uniforms; + _unit forceAddUniform _gear; // Give the poor naked guy some clothing :) + + _gear = selectRandom _headGear; + _unit addHeadGear _gear; + + _gear = selectRandom _vests; + _unit addVest _gear; + + if ((floor random 2) isEqualTo 0) then + { + _gear = selectRandom _backpacks; + _unit addBackpack _gear; + if (_aiLaunchers isEqualTo 1) then + { + if ((floor random 4) isEqualTo 0) then + { + private ["_ammo"]; + _gear = selectRandom _launchers; + _unit addWeapon _gear; + _ammo = getArray (configFile >> "cfgWeapons" >> _gear >> "magazines"); + if (count _ammo > 2) then + { + _ammo resize 2; + }; + for "_i" from 0 to (2 + (round random 1)) do + { + _unit addMagazine (selectRandom _ammo); + }; + }; + }; + }; + + // Add Weapons & Ammo + _gear = selectRandom _rifles; + _unit addWeapon _gear; + _unit selectWeapon _gear; + + _gear = selectRandom _pistols; + _unit addWeapon _gear; + + // Give this guy some ammo + _givenAmmo = [_unit] call VEMFr_fnc_giveAmmo; + if not _givenAmmo then + { + ["fn_loadInv", 0, format["FAILED to give ammo to AI: %1", _unit]] spawn VEMFr_fnc_log; + }; + // Give this guy some weaponItems + _giveAttachments = [_unit] call VEMFr_fnc_giveWeaponItems; + if not _giveAttachments then + { + ["fn_loadInv", 0, format["FAILED to giveWeaponItems to %1", _unit]] spawn VEMFr_fnc_log; + }; + + } forEach _units; + _ok = true; + }; + + if (_aiMode isEqualTo 1) then + { + private ["_policeGear","_headGear","_vests"]; + _policeGear = [["policeConfig"],["headGear","vests","uniforms","rifles","pistols","backpacks"]] call VEMFr_fnc_getSetting; + _headGear = _policeGear select 0; + _vests = _policeGear select 1; + _uniforms = _policeGear select 2; + _rifles = _policeGear select 3; + _pistols = _policeGear select 4; + _backpacks = _policeGear select 5; + { + _unit = _x; + // Strip it + removeAllWeapons _unit; + removeAllItems _unit; + if ("removeAllAssignedItems" call VEMFr_fnc_getSetting isEqualTo 1) then + { + removeAllAssignedItems _unit; + }; + removeUniform _unit; + removeVest _unit; + removeBackpack _unit; + removeGoggles _unit; + removeHeadGear _unit; + + _hat = selectRandom _headGear; + _unit addHeadGear _hat; + _vest = selectRandom _vests; + _unit addVest _vest; + _uniform = selectRandom _uniforms; + _unit forceAddUniform _uniform; + _rifle = selectRandom _rifles; + _unit addWeapon _rifle; + _unit selectWeapon _rifle; + _pistol = selectRandom _pistols; + _unit addWeapon _pistol; + _backpack = selectRandom _backpacks; + _unit addBackPack _backpack; + + // Give this guy some ammo + _givenAmmo = [_unit] call VEMFr_fnc_giveAmmo; + if not _givenAmmo then + { + ["fn_loadInv", 0, format["FAILED to give ammo to AI: %1", _unit]] spawn VEMFr_fnc_log; + }; + // Give this guy some weaponItems + _giveAttachments = [_unit] call VEMFr_fnc_giveWeaponItems; + if not _giveAttachments then + { + ["fn_loadInv", 0, format["FAILED to giveWeaponItems to %1", _unit]] spawn VEMFr_fnc_log; + }; + } forEach _units; + }; + + if (_aiMode isEqualTo 2) then + { + private ["_policeGear","_headGear","_vests"]; + _policeGear = [["policeConfig"],["rifles","pistols"]] call VEMFr_fnc_getSetting; + _rifles = _policeGear select 0; + _pistols = _policeGear select 1; + { + _unit = _x; + // Strip it + removeAllWeapons _unit; + removeAllItems _unit; + if ("removeAllAssignedItems" call VEMFr_fnc_getSetting isEqualTo 1) then + { + removeAllAssignedItems _unit; + }; + removeUniform _unit; + removeVest _unit; + removeBackpack _unit; + removeGoggles _unit; + removeHeadGear _unit; + _unit addHeadGear "H_HelmetB_light_black"; + _unit addGoggles "G_Balaclava_blk"; + _unit addVest "V_PlateCarrier2_blk"; + _unit forceAddUniform "Exile_Uniform_ExileCustoms"; + _rifle = selectRandom _rifles; + _unit addWeapon _rifle; + _unit selectWeapon _rifle; + _pistol = selectRandom _pistols; + _unit addWeapon _pistol; + + // Give this guy some ammo + _givenAmmo = [_unit] call VEMFr_fnc_giveAmmo; + if not _givenAmmo then + { + ["fn_loadInv", 0, format["FAILED to give ammo to AI: %1", _unit]] spawn VEMFr_fnc_log; + }; + // Give this guy some weaponItems + _giveAttachments = [_unit] call VEMFr_fnc_giveWeaponItems; + if not _giveAttachments then + { + ["fn_loadInv", 0, format["FAILED to giveWeaponItems to %1", _unit]] spawn VEMFr_fnc_log; + }; + } forEach _units; + }; + }; + }; +}; + +_ok diff --git a/exile_vemf_reloaded/functions/fn_loadLoot.sqf b/exile_vemf_reloaded/functions/fn_loadLoot.sqf new file mode 100644 index 0000000..a63a603 --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_loadLoot.sqf @@ -0,0 +1,143 @@ +/* + Author: VAMPIRE, rebooted by IT07 + + Description: + loads loot crate inventory + + Returns: + BOOL - true if everything went ok +*/ +private +[ + "_crate","_settings","_loot","_amount","_quant","_prim","_sec","_mags","_att","_items","_vests","_packs","_primaries","_secondaries", + "_magazines","_attachments","_items","_vests","_backpacks","_headGear","_blackList","_maxPrim","_minPrim","_maxSec","_minSec", + "_maxMagSlots","_minMagSlots","_maxAttSlots","_minAttSlots","_maxItemSlots","_minItemSlots","_maxVestSlots","_minVestSlots", + "_maxHeadGearSlots","_minHeadGearSlots","_maxBagSlots","_minBagSlots","_ok" +]; + +_ok = false; +// Define _vars +_crate = param [0, objNull, [objNull]]; +if not isNull _crate then +{ + clearWeaponCargoGlobal _crate; + clearMagazineCargoGlobal _crate; + clearBackpackCargoGlobal _crate; + clearItemCargoGlobal _crate; + _settings = + [ + ["crateLoot"], + [ + "primarySlotsMax","primarySlotsMin","secondarySlotsMax","secondarySlotsMin","magSlotsMax","magSlotsMin","attSlotsMax","attSlotsMin","itemSlotsMax","itemSlotsMin", + "vestSlotsMax","vestSlotsMin","headGearSlotsMax","headGearSlotsMin","bagSlotsMax","bagSlotsMin","primaryWeaponLoot","secondaryWeaponLoot","magLoot","attLoot", + "itemLoot","vestLoot","backpackLoot","headGearLoot","blackListLoot" + ] + ] call VEMFr_fnc_getSetting; + _maxPrim = _settings select 0; + _minPrim = _settings select 1; + _maxSec = _settings select 2; + _minSec = _settings select 3; + _maxMagSlots = _settings select 4; + _minMagSlots = _settings select 5; + _maxAttSlots = _settings select 6; + _minAttSlots = _settings select 7; + _maxItemSlots = _settings select 8; + _minItemSlots = _settings select 9; + _maxVestSlots = _settings select 10; + _minVestSlots = _settings select 11; + _maxHeadGearSlots = _settings select 12; + _minHeadGearSlots = _settings select 13; + _maxBagSlots = _settings select 14; + _minBagSlots = _settings select 15; + _primaries = _settings select 16; + _secondaries = _settings select 17; + _magazines = _settings select 18; + _attachments = _settings select 19; + _items = _settings select 20; + _vests = _settings select 21; + _backpacks = _settings select 22; + _headGear = _settings select 23; + _blackList = _settings select 24; + + // Add primary weapons + for "_j" from 0 to (_maxPrim - _minPrim + floor random _minPrim) do + { + _prim = _primaries call BIS_fnc_selectRandom; + if not((_prim select 0) in _blackList) then + { + _crate addWeaponCargoGlobal [_prim select 0, _prim select 1]; + }; + }; + + // Secondary weapons + for "_j" from 0 to (_maxSec - _minSec + floor random _minSec) do + { + _sec = _secondaries call BIS_fnc_selectRandom; + if not((_sec select 0) in _blackList) then + { + _crate addWeaponCargoGlobal [_sec select 0, _sec select 1]; + }; + }; + + // Magazines + for "_j" from 0 to (_maxMagSlots - _minMagSlots + floor random _minMagSlots) do + { + _mag = _magazines call BIS_fnc_selectRandom; + if not((_mag select 0) in _blackList) then + { + _crate addMagazineCargoGlobal [_mag select 0, _mag select 1]; + }; + }; + + // Weapon attachments + for "_j" from 0 to (_maxAttSlots - _minAttSlots + floor random _minAttSlots) do + { + _att = _attachments call BIS_fnc_selectRandom; + if not((_att select 0) in _blackList) then + { + _crate addItemCargoGlobal [_att select 0, _att select 1]; + }; + }; + + // Items + for "_j" from 0 to (_maxItemSlots - _minItemSlots + floor random _minItemSlots) do + { + _item = _items call BIS_fnc_selectRandom; + if not((_item select 0) in _blacklist) then + { + _crate addItemCargoGlobal [_item select 0, _item select 1]; + }; + }; + + // Vests + for "_j" from 0 to (_maxVestSlots - _minVestSlots + floor random _minVestSlots) do + { + _vest = _vests call BIS_fnc_selectRandom; + if not((_vest select 0) in _blackList) then + { + _crate addItemCargoGlobal [_vest select 0, _vest select 1]; + }; + }; + + // Helmets / caps / berets / bandanas + for "_j" from 0 to (_maxHeadGearSlots - _minHeadGearSlots + floor random _minHeadGearSlots) do + { + _headGearItem = _headGear call BIS_fnc_selectRandom; + if not((_headGearItem select 0) in _blackList) then + { + _crate addItemCargoGlobal [_headGearItem select 0, _headGearItem select 1]; + }; + }; + + // Backpacks + for "_j" from 0 to (_maxBagSlots - _minBagSlots + floor random _minBagSlots) do + { + _pack = _backpacks call BIS_fnc_selectRandom; + if not((_pack select 0) in _blackList) then + { + _crate addBackpackCargoGlobal [_pack select 0, _pack select 1]; + }; + }; + _ok = true; +}; +_ok diff --git a/exile_vemf_reloaded/functions/fn_log.sqf b/exile_vemf_reloaded/functions/fn_log.sqf new file mode 100644 index 0000000..0b9745e --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_log.sqf @@ -0,0 +1,37 @@ +/* + Author: IT07 + + Description: + will log given data if debug is enabled + + Params: + _this: ARRAY - contains data required for logging + _this select 0: STRING - prefix. Use "" if none + _this select 1: SCALAR - 0 = error, 1 = info, 2 = special + _this select 2: STRING - the thing to log + + Returns: + nothing (use spawn, not call) +*/ + +private ["_param","_prefix","_mode","_logThis","_logModesAllowed","_loggingEnabled"]; +_loggingEnabled = "debugMode" call VEMFr_fnc_getSetting; +if (_loggingEnabled > 0) then +{ + if (_loggingEnabled < 4) then + { + _type = param [1, 3, [0]]; + _line = param [2, "", [""]]; + if (_type < _loggingEnabled) then + { + if not(_line isEqualTo "") then + { + diag_log text format["IT07: [exile_vemf_reloaded] %1", _line]; + }; + }; + if (_type isEqualTo 2) then // Always allow log type 2 no matter which debugMode is set + { + diag_log text format["IT07: [exile_vemf_reloaded] %1", _line]; + }; + }; +}; diff --git a/exile_vemf_reloaded/functions/fn_missionTimer.sqf b/exile_vemf_reloaded/functions/fn_missionTimer.sqf new file mode 100644 index 0000000..d31b32e --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_missionTimer.sqf @@ -0,0 +1,85 @@ +/* + Author: IT07 + + Description: + Handles the start and timeout of missions + + Params: + none + + Returns: + nothing +*/ + +_minFPS = "minServerFPS" call VEMFr_fnc_getSetting; +if (_minFPS > -1) then +{ + _minPlayers = "minPlayers" call VEMFr_fnc_getSetting; + if (_minPlayers > -1) then + { + _maxGlobalMissions = "maxGlobalMissions" call VEMFr_fnc_getSetting; + if (_maxGlobalMissions > -2) then + { + _minNew = "minNew" call VEMFr_fnc_getSetting; + if (_minNew > -1) then + { + _maxNew = "maxNew" call VEMFr_fnc_getSetting; + if (_maxNew > 0) then + { + _missionList = "missionList" call VEMFr_fnc_getSetting; + if (count _missionList > 0) then + { + waitUntil { uiSleep 5; (if (([_minPlayers] call VEMFr_fnc_playerCount) AND (diag_fps > _minFPS)) then { true } else { false }) }; + ["missionTimer", 1, format["Minimal player count of %1 reached! Starting timer...", _minPlayers]] spawn VEMFr_fnc_log; + + VEMFr_missionCount = 0; + private ["_ignoreLimit"]; + _ignoreLimit = false; + if (_maxGlobalMissions isEqualTo 0) then + { + _ignoreLimit = true; + }; + while {true} do + { + // Wait random amount + uiSleep ((_minNew*60)+ floor random ((_maxNew*60)-(_minNew*60))); + + // Pick A Mission if enough players online + if ([_minPlayers] call VEMFr_fnc_playerCount) then + { + if _ignoreLimit then + { + _missVar = selectRandom _missionList; + [] execVM format["exile_vemf_reloaded\missions\%1.sqf", _missVar]; + _lastMission = serverTime; + }; + if not _ignoreLimit then + { + if (VEMFr_missionCount <= _maxGlobalMissions) then + { + _missVar = selectRandom _missionList; + [] execVM format["exile_vemf_reloaded\missions\%1.sqf", _missVar]; + VEMFr_missionCount = VEMFr_missionCount +1; + _lastMission = serverTime; + }; + }; + }; + }; + }; + }; + }; + }; + if (_maxGlobalMissions < -1) then + { + ["missionTimer", 0, format["Invalid maximum global missions number! it is: %1", _maxGlobalMissions]] spawn VEMFr_fnc_log; + }; + }; + if (_minPlayers < 0) then + { + ["missionTimer", 0, format["Invalid minimum player setting of %1", _minPlayers]] spawn VEMFr_fnc_log; + }; +}; +if (_minFPS < 0) then +{ + ["missionTimer", 0, format["Invalid minimum server FPS setting of %1", _minFPS]] spawn VEMFr_fnc_log; +}; diff --git a/exile_vemf_reloaded/functions/fn_placeMines.sqf b/exile_vemf_reloaded/functions/fn_placeMines.sqf new file mode 100644 index 0000000..454843a --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_placeMines.sqf @@ -0,0 +1,52 @@ +/* + Author: IT07 + + Description: + places mines around given position within given radius + + Params: + _this select 0: POSITION - center of area to place mines around + _this select 1: SCALAR - the minimum distance + _this select 2: SCALAR - the maximum distance (must be higher than minimum of course) + + Returns: + BOOL - true if all OK +*/ + +private ["_ok","_enabled","_pos","_min","_max","_amount","_minePos","_mine","_mines","_mines","_mineTypes"]; +_ok = false; +_enabled = ([["DynamicLocationInvasion"],["mines"]] call VEMFr_fnc_getSetting) select 0; +if (_enabled > 0) then +{ + _pos = param [0, [], [[]]]; + if (count _pos isEqualTo 3) then + { + _min = param [1, -1, [0]]; + if (_min > -1) then + { + _max = param [2, -1, [0]]; + if (_max > _min) then + { + _amount = ([["DynamicLocationInvasion"],["minesAmount"]] call VEMFr_fnc_getSetting) select 0; + if (_amount > -1) then + { + _mines = [["DynamicLocationInvasion"],["mines"]] call VEMFr_fnc_getSetting param [0, 1, [0]]; + if (_mines isEqualTo 1) then { _mineTypes = ["ATMine"] }; + if (_mines isEqualTo 2) then { _mineTypes = ["APERSMine"] }; + if (_mines isEqualTo 3) then { _mineTypes = ["ATMine","APERSMine"] }; + _mines = []; + ["fn_placeMines", 1, format["Placing %1 mines at %2", _amount, _pos]] spawn VEMFr_fnc_log; + for "_m" from 1 to _amount do + { + _mine = createMine [selectRandom _mineTypes, ([_pos, _min, _max, 2, 0, 20, 0] call BIS_fnc_findSafePos), [], 0]; + uiSleep 0.5; + _mines pushBack _mine; + }; + _ok = [_mines]; + }; + }; + }; + }; +}; + +_ok diff --git a/exile_vemf_reloaded/functions/fn_playerCount.sqf b/exile_vemf_reloaded/functions/fn_playerCount.sqf new file mode 100644 index 0000000..93c3f8d --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_playerCount.sqf @@ -0,0 +1,38 @@ +/* + Author: IT07 + + Description: + checks if player count is above or equal to given number. If no number given, default of 1 will be used. + + Params: + none + + Returns: + ARRAY - [false if current player count is below minimum, true if (more than OR equalTo) minimum] +*/ + +private ["_minimum","_players","_ok"]; +_ok = false; +if (_this isEqualType []) then +{ + _minimum = param [0, -1, [0]]; + if (_minimum > -1) then + { + if (count allPlayers >= _minimum) then + { + _players = 0; + { + if (isPlayer _x) then + { + _players = _players + 1; + }; + } forEach allPlayers; + if not(_players isEqualTo 0) then + { + _ok = true + }; + }; + }; +}; + +_ok diff --git a/exile_vemf_reloaded/functions/fn_signAI.sqf b/exile_vemf_reloaded/functions/fn_signAI.sqf new file mode 100644 index 0000000..c69940b --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_signAI.sqf @@ -0,0 +1,23 @@ +/* + Author: IT07 + + Description: + marks given group(!) as VEMF AI which will then be used by REMOTEguard for monitor of groupOwner + + Params: + _this: ARRAY + _this select 0: GROUP - group to sign as VEMF AI + + Returns: + BOOL - true if OK +*/ + +private["_signed","_abort"]; +_ok = false; +_group = param [0, grpNull, [grpNull]]; +if not isNull _group then +{ + (uiNamespace getVariable "vemfGroups") pushBack _group; + _ok = true +}; +_ok diff --git a/exile_vemf_reloaded/functions/fn_spawnAI.sqf b/exile_vemf_reloaded/functions/fn_spawnAI.sqf new file mode 100644 index 0000000..6b6430b --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_spawnAI.sqf @@ -0,0 +1,235 @@ +/* + Author: original by Vampire, completely rewritten by IT07 + + Description: + spawns AI using given _pos and unit/group count. + + Params: + _this select 0: POSITION - where to spawn the units around + _this select 1: SCALAR - how many groups to spawn + _this select 2: SCALAR - how many units to put in each group + _this select 3: SCALAR - AI mode + + Returns: + ARRAY of UNITS +*/ + +private // Make sure that the vars in this function do not interfere with vars in the calling script +[ + "_pos","_grpCount","_unitsPerGrp","_sldrClass","_groups","_settings","_hc","_skills","_newPos","_return","_waypoints","_wp","_cyc","_units", + "_accuracy","_aimShake","_aimSpeed","_stamina","_spotDist","_spotTime","_courage","_reloadSpd","_commanding","_general","_loadInv","_noHouses","_cal50sVehs","_mode" +]; + +_spawned = [[],[]]; +_pos = param [0, [], [[]]]; +if (count _pos isEqualTo 3) then +{ + _grpCount = param [1, 1, [0]]; + if (_grpCount > 0) then + { + _unitsPerGrp = param [2, 1, [0]]; + if (_unitsPerGrp > 0) then + { + _mode = param [3, -1, [0]]; + _sldrClass = "unitClass" call VEMFr_fnc_getSetting; + _groups = []; + _hc = "headLessClientSupport" call VEMFr_fnc_getSetting; + _aiDifficulty = [["aiSkill"],["difficulty"]] call VEMFr_fnc_getSetting param [0, "Veteran", [""]]; + _skills = [["aiSkill", _aiDifficulty],["accuracy","aimingShake","aimingSpeed","endurance","spotDistance","spotTime","courage","reloadSpeed","commanding","general"]] call VEMFr_fnc_getSetting; + _accuracy = _skills select 0; + _aimShake = _skills select 1; + _aimSpeed = _skills select 2; + _stamina = _skills select 3; + _spotDist = _skills select 4; + _spotTime = _skills select 5; + _courage = _skills select 6; + _reloadSpd = _skills select 7; + _commanding = _skills select 8; + _general = _skills select 9; + + _houses = nearestTerrainObjects [_pos, ["House"], 200]; // Find some houses to spawn in + _notTheseHouses = "housesBlackList" call VEMFr_fnc_getSetting; + _goodHouses = []; + { // Filter the houses that are too small for one group + if not(typeOf _x in _notTheseHouses) then + { + if ([_x, _unitsPerGrp] call BIS_fnc_isBuildingEnterable) then + { + _goodHouses pushBack _x; + }; + }; + } forEach _houses; + _goodHouses = _goodHouses call BIS_fnc_arrayShuffle; + _noHouses = false; + if (count _goodHouses < _grpCount) then + { + _noHouses = true; + }; + + _cal50s = [["DynamicLocationInvasion"],["cal50s"]] call VEMFr_fnc_getSetting param [0, 3, [0]]; + if (_cal50s > 0) then + { + _cal50sVehs = []; + }; + _units = []; // Define units array. the for loops below will fill it with units + for "_g" from 1 to _grpCount do // Spawn Groups near Position + { + if not _noHouses then + { + if (count _goodHouses < 1) then + { + _noHouses = true + }; + }; + private ["_unitSide","_grp","_unit"]; + _unitSide = getText (configFile >> "CfgVehicles" >> ("unitClass" call VEMFr_fnc_getSetting) >> "faction"); + switch _unitSide do + { + case "BLU_G_F": + { + _grp = createGroup WEST; + }; + case "CIV_F": + { + _grp = createGroup civilian; + }; + case "IND_F": + { + _grp = createGroup independent; + }; + case "IND_G_F": + { + _grp = createGroup resistance; + }; + case "OPF_F": + { + _grp = createGroup EAST; + }; + default + { + ["fn_spawnAI", 0, format["Unknown side %1", _unitSide]] spawn VEMFr_fnc_log; + }; + }; + if not isNil"_grp" then + { + if not _noHouses then + { + _grp enableAttack false; + }; + _grp setBehaviour "AWARE"; + _grp setCombatMode "RED"; + _grp allowFleeing 0; + private ["_house","_housePositions"]; + if not _noHouses then + { + _house = selectRandom _goodHouses; + _houseID = _goodHouses find _house; + _goodHouses deleteAt _houseID; + _housePositions = [_house] call BIS_fnc_buildingPositions; + }; + + _placed50 = false; + for "_u" from 1 to _unitsPerGrp do + { + private ["_spawnPos","_hmg"]; + if not _noHouses then + { + _spawnPos = selectRandom _housePositions; + if not _placed50 then + { + _placed50 = true; + if (_cal50s > 0) then + { + _hmg = createVehicle ["B_HMG_01_high_F", _spawnPos, [], 0, "CAN_COLLIDE"]; + _hmg setVehicleLock "LOCKEDPLAYER"; + (_spawned select 1) pushBack _hmg; + }; + }; + }; + if _noHouses then + { + _spawnPos = [_pos,20,250,1,0,200,0] call BIS_fnc_findSafePos; // Find Nearby Position + }; + + _unit = _grp createUnit [_sldrClass, _spawnPos, [], 0, "CAN_COLLIDE"]; // Create Unit There + if not _noHouses then + { + doStop _unit; + if (_cal50s > 0) then + { + if not isNil"_hmg" then + { + if not isNull _hmg then + { + _unit moveInGunner _hmg; + _hmg = nil; + _cal50s = _cal50s - 1; + }; + }; + }; + + _houseIndex = _housePositions find _spawnPos; + _housePositions deleteAt _houseIndex; + }; + + _unit addMPEventHandler ["mpkilled","if (isDedicated) then { [_this select 0, _this select 1] spawn VEMFr_fnc_aiKilled }"]; + (_spawned select 0) pushBack _unit; + // Set skills + _unit setSkill ["aimingAccuracy", _accuracy]; + _unit setSkill ["aimingShake", _aimShake]; + _unit setSkill ["aimingSpeed", _aimSpeed]; + _unit setSkill ["endurance", _stamina]; + _unit setSkill ["spotDistance", _spotDist]; + _unit setSkill ["spotTime", _spotTime]; + _unit setSkill ["courage", _courage]; + _unit setSkill ["reloadSpeed", _reloadSpd]; + _unit setSkill ["commanding", _commanding]; + _unit setSkill ["general", _general]; + _unit setRank "Private"; // Set rank + }; + _grp selectLeader _unit; // Leader Assignment + _groups pushBack _grp; // Push it into the _groups array + }; + }; + + _invLoaded = [_spawned select 0, "Invasion", _mode] call VEMFr_fnc_loadInv; // Load the AI's inventory + if isNil"_invLoaded" then + { + ["fn_spawnAI", 0, "failed to load AI's inventory..."] spawn VEMFr_fnc_log; + }; + + if (count _groups isEqualTo _grpCount) then + { + if not _noHouses then + { + { + [_x] spawn VEMFr_fnc_signAI; + } forEach _groups; + }; + if _noHouses then + { + _waypoints = + [ + [(_pos select 0), (_pos select 1)+50, 0], + [(_pos select 0)+50, (_pos select 1), 0], + [(_pos select 0), (_pos select 1)-50, 0], + [(_pos select 0)-50, (_pos select 1), 0] + ]; + { // Make them Patrol + for "_z" from 1 to (count _waypoints) do + { + _wp = _x addWaypoint [(_waypoints select (_z-1)), 10]; + _wp setWaypointType "SAD"; + _wp setWaypointCompletionRadius 20; + }; + _cyc = _x addWaypoint [_pos,10]; + _cyc setWaypointType "CYCLE"; + _cyc setWaypointCompletionRadius 20; + [_x] spawn VEMFr_fnc_signAI; + } forEach _groups; + }; + }; + }; + }; +}; +_spawned diff --git a/exile_vemf_reloaded/functions/fn_spawnStaticAI.sqf b/exile_vemf_reloaded/functions/fn_spawnStaticAI.sqf new file mode 100644 index 0000000..36a3c2e --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_spawnStaticAI.sqf @@ -0,0 +1,28 @@ +/* + Author: IT07 + + Description: + spawns AI at all given locations in config file + + Params: + none + + Returns: + nothing +*/ + +if ([["aiStatic"],["enabled"]] call VEMFr_fnc_getSetting isEqualTo 1) then +{ + ["spawnStaticAI", 3, "launching..."] spawn VEMFr_fnc_log; + _settings = [["aiStatic"],["positions","amount"]] call VEMFr_fnc_getSetting; + _positions = _settings select 0; + if (count _positions > 0) then + { + ["spawnStaticAI", 3, "spawning AI on positions..."] spawn VEMFr_fnc_log; + _amounts = _settings select 1; + { + _amount = _amounts select _foreachindex; + [_x, 2, _amount / 2, "aiMode" call VEMFr_fnc_getSetting] spawn VEMFr_fnc_spawnAI; + } forEach _positions; + }; +}; diff --git a/exile_vemf_reloaded/functions/fn_transferOwner.sqf b/exile_vemf_reloaded/functions/fn_transferOwner.sqf new file mode 100644 index 0000000..7485279 --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_transferOwner.sqf @@ -0,0 +1,86 @@ +/* + Author: IT07 + + Description: + handles the transfer of ownership to another given unit/client/object. + Will transfer complete group to the same (new) owner. + + Params: + _this select 0: GROUP - the group of which the ownership should be transfered + + Returns: + BOOLEAN - true if transfer was successful +*/ + +private ["_toTransfer","_hcEnabled","_hcUIDs","_hcClients","_to","_transfer"]; +_transfer = false; +_toTransfer = param [0, grpNull, [grpNull]]; +if not isNull _toTransfer then +{ + // Check if HC is enabled + _hcEnabled = "headLessClientSupport" call VEMFr_fnc_getSetting; + _forceClients = uiNamespace getVariable ["VEMFr_forceAItoClients", nil]; + if not(isNil"_forceClients") then + { + if _forceClients then + { + _hcEnabled = -1; + }; + }; + if (_hcEnabled isEqualTo 1) then + { // Gather the Headless Client(s) + _hcClients = []; + { + if (typeOf _x isEqualTo "HeadlessClient_F") then // it is an HC + { + _hcClients pushBack [_x, owner _x]; + }; + } forEach allPlayers; + if (count _hcClients > 0) then + { + _to = call VEMFr_fnc_headLessClient; // Select a random hc + }; + if (count _hcClients isEqualTo 0) then + { + uiNamespace setVariable ["VEMFr_forceAItoClients", true]; + }; + }; + if (_hcEnabled isEqualTo 0) then + { + if ([1] call VEMFr_fnc_playerCount) then + { + _closest = [0,0,0]; + { + if (isPlayer _x) then + { + _leaderPos = position (leader _toTransfer); + _dist = _leaderPos distance (position _x); + if (_dist < (_leaderPos distance _closest)) then + { // Find the closest player + _closest = position _x; + _to = _x; + }; + }; + } forEach allPlayers; + }; + }; + if not isNil"_to" then + { + _transfer = _toTransfer setGroupOwner (owner _to); + _load = uiNamespace getVariable ["VEMFrHcLoad", nil]; + if not isNil"_load" then + { + _index = _load find _to; + if (_index > -1) then + { + _load set [_index, ((_load select _index) select 1) + 1]; + }; + if (_index isEqualTo -1) then + { + _load pushBack [_to, 1]; + }; + }; + }; +}; + +_transfer // Return the value of this var to the calling script diff --git a/exile_vemf_reloaded/functions/fn_waitForMissionDone.sqf b/exile_vemf_reloaded/functions/fn_waitForMissionDone.sqf new file mode 100644 index 0000000..ac5ed5c --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_waitForMissionDone.sqf @@ -0,0 +1,60 @@ +/* + Author: VAMPIRE, rebooted by IT07 + + Description: + fn_waitForMissionDone - waits for mission to be done + + Params: + _this select 0: STRING - name of mission location + _this select 1: POSITION - center of area to be waiting for + _this select 2: ARRAY - array of units to check for + _this select 3: SCALAR - radius around center to check for players + + Returns: + BOOL - true when mission is done +*/ + +private ["_pos","_unitArr","_unitCount","_killed","_killToComplete","_rad","_playerNear","_complete"]; +_complete = false; +_pos = param [1, [], [[]]]; +if (count _pos isEqualTo 3) then +{ + _unitArr = param [2, [], [[]]]; + if (count _unitArr > 0) then + { + _unitCount = count _unitArr; + _killed = []; + _killToComplete = round(("killPercentage" call VEMFr_fnc_getSetting)/100*_unitCount); + _rad = param [3, 0, [0]]; + if (_rad > 0) then + { + while {not _complete} do + { + // First check for a player + if not _complete then { uiSleep 1; }; + _playerNear = [_pos, _rad] call VEMFr_fnc_checkPlayerPresence; + if (_playerNear) then + { + { + if not(alive _x) then + { + _killed pushBack _x; + }; + } forEach _unitArr; + { // Delete the not(alive) units + _index = _unitArr find _x; + if not(_index isEqualTo -1) then + { + _unitArr deleteAt _index; + }; + } forEach _killed; + }; + if not _complete then { uiSleep 1 }; + if (((count _killed) isEqualTo _killToComplete) OR ((count _killed) > _killToComplete)) then { _complete = true }; + if not _complete then { uiSleep 1 }; + }; + ["fn_waitForMissionDone", 1, format["mission in %1 completed!", _this select 0]] spawn VEMFr_fnc_log; + }; + }; +}; +_complete diff --git a/exile_vemf_reloaded/functions/fn_waitForPlayers.sqf b/exile_vemf_reloaded/functions/fn_waitForPlayers.sqf new file mode 100644 index 0000000..6c67e0a --- /dev/null +++ b/exile_vemf_reloaded/functions/fn_waitForPlayers.sqf @@ -0,0 +1,43 @@ +/* + Author: IT07 + + Description: + fn_waitForPlayers - waits for player to be nearby given pos + + Params: + _this select 0: POSITION - center of area to check for players + _this select 1: SCALAR - radius to check around POSITION + + Returns: + BOOL - true if there is a player present +*/ + +private ["_playerNear","_pos","_rad","_time","_timeOutTime","_pp"]; +_playerNear = false; +_pos = param [0, [], [[]]]; +if (count _pos isEqualTo 3) then +{ + _rad = param [1, -1, [0]]; + if (_rad > -1) then + { + _time = round time; + // Define _settings + _timeOutTime = ("timeOutTime" call VEMFr_fnc_getSetting)*60; + // _pp = playerPresence + _pp = [_pos, _rad] call VEMFr_fnc_checkPlayerPresence; + if _pp then + { + _playerNear = true; + }; + if not _pp then + { + waitUntil { uiSleep 2; (([_pos, _rad] call VEMFr_fnc_checkPlayerPresence) OR (round time - _time > _timeOutTime)) }; + if ([_pos, _rad] call VEMFr_fnc_checkPlayerPresence) then + { + _playerNear = true; + }; + }; + }; +}; + +_playerNear diff --git a/exile_vemf_reloaded/missions/DynamicLocationInvasion.sqf b/exile_vemf_reloaded/missions/DynamicLocationInvasion.sqf new file mode 100644 index 0000000..6befda8 --- /dev/null +++ b/exile_vemf_reloaded/missions/DynamicLocationInvasion.sqf @@ -0,0 +1,362 @@ +/* + DynamicLocationInvasion by Vampire, rewritten by IT07 +*/ +private ["_settings","_grpCount","_groupUnits","_skipDistance","_loc","_hasPlayers","_spawned","_grpArr","_unitArr","_done","_boxes","_box","_chute","_colors","_lightType","_light","_smoke"]; + +// Define _settings +_settings = [["DynamicLocationInvasion"],["maxInvasions","groupCount","groupUnits","maxDistance","maxDistancePrefered","skipDistance","marker","parachuteCrate","markCrateVisual","markCrateOnMap","announce","streetLights","streetLightsRestore","streetLightsRange","allowCrateLift"]] call VEMFr_fnc_getSetting; +_maxInvasions = _settings select 0; +if isNil"VEMFr_invasCount" then +{ + VEMFr_invasCount = 0; +}; +VEMFr_invasCount = VEMFr_invasCount + 1; +if (VEMFr_invasCount <= _maxInvasions) then +{ + _grpCount = _settings select 1; + _groupUnits = _settings select 2; + _range = _settings select 3; + _maxPref = _settings select 4; + _skipDistance = _settings select 5; + _useMissionMarker = _settings select 6; + _useChute = (_settings select 7) select 0; + _crateAltitude = (_settings select 7) select 1; + _markCrateVisual = _settings select 8; + _markCrateOnMap = _settings select 9; + _announce = _settings select 10; + _streetLights = _settings select 11; + _streetLightsRestore = _settings select 12; + _streetLightsRange = _settings select 13; + _allowCrateLift = _settings select 14; + + _loc = ["loc", false, position (selectRandom allPlayers), _range, _skipDistance, _maxPref, _skipDistance] call VEMFr_fnc_findPos; + if (_loc isEqualType []) then + { + _locName = _loc select 0; + if (_locName isEqualTo "") then { _locName = "Area"; }; + ["DynamicLocationInvasion", 1, format["Invading %1...", _locName]] spawn VEMFr_fnc_log; + VEMFr_invasCount = VEMFr_invasCount + 1; + // Send message to all players + private ["_mode"]; + _mode = "aiMode" call VEMFr_fnc_getSetting; + _randomModes = ([["DynamicLocationInvasion"],["randomModes"]] call VEMFr_fnc_getSetting) select 0; + if (_randomModes isEqualTo 1) then + { + _mode = selectRandom [0,1,2]; + }; + if (_announce isEqualTo 1) then + { + if (_mode isEqualTo 0) then + { + [[format["Plundering groups have invaded %1 @ %2", _locName, mapGridPosition (_loc select 1)], "NEW INVASION"], ""] spawn VEMFr_fnc_broadCast; + }; + if (_mode isEqualTo 1) then + { + [[format["%1 Police forces are now controlling %2 @ %3", worldName, _locName, mapGridPosition (_loc select 1)], "NEW MISSION"], ""] spawn VEMFr_fnc_broadCast; + }; + if (_mode isEqualTo 2) then + { + [[format["%1 S.W.A.T. teams are now raiding %2 @ %3", worldName, _locName, mapGridPosition (_loc select 1)], "NEW RAID"], ""] spawn VEMFr_fnc_broadCast; + }; + }; + private["_marker"]; + if (_useMissionMarker isEqualTo 1) then + { // Create/place the marker if enabled + _marker = createMarker [format["VEMFr_DynaLocInva_ID%1", random 9000], (_loc select 1)]; + _marker setMarkerShape "ICON"; + _marker setMarkerType "o_unknown"; + switch true do + { + case (_mode isEqualTo 0): + { + _marker setMarkerColor "ColorEAST"; + }; + case (_mode isEqualTo 1): + { + _marker setMarkerColor "ColorWEST"; + }; + case (_mode isEqualTo 2): + { + _marker setMarkerColor "ColorBlack"; + }; + }; + }; + + // If enabled, kill all the lights + if (_streetLights isEqualTo 0) then + { + private ["_all"]; + _all = nearestObjects [_loc select 1, ["Lamps_Base_F","PowerLines_base_F","Land_PowerPoleWooden_L_F"], _streetLightsRange]; + { + if (damage _x < 0.95) then + { + _x setDamage 0.95; + uiSleep 0.1; + }; + } forEach _all; + }; + + // Usage: POSITION, Radius + _playerNear = [_loc select 1, 800] call VEMFr_fnc_waitForPlayers; + if _playerNear then + { + // Player is Near, so Spawn the Units + _spawned = [_loc select 1, ((_grpCount select 0) + round random ((_grpCount select 1) - (_grpCount select 0))), ((_groupUnits select 0) + round random ((_groupUnits select 1) - (_groupUnits select 0))), _mode] call VEMFr_fnc_spawnAI; + if (count (_spawned select 0) > 0) then + { + private ["_cal50s"]; + if (count (_spawned select 1) > 0) then + { + _cal50s = _spawned select 1; + }; + // Place mines if enabled + private ["_minesPlaced","_mines"]; + _mines = [["DynamicLocationInvasion"],["mines"]] call VEMFr_fnc_getSetting param [0, 0, [0]]; + if (_mines > 0) then + { + _minesPlaced = [_loc select 1, 5, 100] call VEMFr_fnc_placeMines param [0, [], [[]]]; + if (count _minesPlaced > 0) then + { + ["DynamicLocationInvasion", 1, format["Successfully placed mines at %1", _locName]] spawn VEMFr_fnc_log; + }; + if (count _minesPlaced isEqualto 0) then + { + ["DynamicLocationInvasion", 0, format["Failed to place mines at %1", _locName]] spawn VEMFr_fnc_log; + _minesPlaced = nil; + }; + }; + + // Wait for Mission Completion + _done = [_loc select 0, _loc select 1, _spawned select 0, _skipDistance] call VEMFr_fnc_waitForMissionDone; + _usedLocs = uiNamespace getVariable "VEMFrUsedLocs"; + _index = _usedLocs find [_loc select 0, _loc select 1]; + if (_index > -1) then + { + _usedLocs deleteAt _index; + }; + if _done then + { + // Broadcast + if (_announce isEqualTo 1) then + { + if (_mode isEqualTo 0) then + { + [[format["%1 @ %2 has been cleared of %3 bad guys", _locName, mapGridPosition (_loc select 1), worldName], "COMPLETED"], ""] spawn VEMFr_fnc_broadCast; + }; + if (_mode isEqualTo 1) then + { + [[format["%1 @ %2 has been cleared of %3 Police forces", _locName, mapGridPosition (_loc select 1), worldName], "CLEARED"], ""] spawn VEMFr_fnc_broadCast; + }; + if (_mode isEqualTo 2) then + { + [[format["S.W.A.T. raid on %1 @ %2 has been eliminated", _locName, mapGridPosition (_loc select 1)], "DEFEATED"], ""] spawn VEMFr_fnc_broadCast; + }; + }; + // Deal with the 50s + if not isNil"_cal50s" then + { + private["_cal50sDelete"]; + _cal50sDelete = ([["DynamicLocationInvasion"],["cal50sDelete"]] call VEMFr_fnc_getSetting) select 0; + if (_cal50sDelete > 0) then + { + { + if (_cal50sDelete isEqualTo 1) then + { + deleteVehicle _x; + }; + if (_cal50sDelete isEqualTo 2) then + { + _x setDamage 1; + }; + } forEach _cal50s; + }; + }; + // Choose a box + _boxes = [["DynamicLocationInvasion"],["crateTypes"]] call VEMFr_fnc_getSetting; + _box = (_boxes select 0) call BIS_fnc_selectRandom; + _pos = [_loc select 1, 0, 100, 0, 0, 300, 0] call bis_fnc_findSafePos; + private ["_crate"]; + if (_useChute isEqualTo 1) then + { + _chute = createVehicle ["I_Parachute_02_F", _pos, [], 0, "FLY"]; + _chute setPos [getPos _chute select 0, getPos _chute select 1, _crateAltitude]; + _chute enableSimulationGlobal true; + + if not isNull _chute then + { + _crate = createVehicle [_box, getPos _chute, [], 0, "NONE"]; + _crate allowDamage false; + _crate enableSimulationGlobal true; + _crate attachTo [_chute, [0,0,0]]; + if (_allowCrateLift isEqualTo 0) then + { + _crate enableRopeAttach false; + }; + ["DynamicLocationInvasion", 1, format ["Crate parachuted at: %1 / Grid: %2", (getPosATL _crate), mapGridPosition (getPosATL _crate)]] spawn VEMFr_fnc_log; + _lootLoaded = [_crate] call VEMFr_fnc_loadLoot; + if _lootLoaded then { ["DynamicLocationInvasion", 1, "Loot loaded successfully into parachuting crate"] spawn VEMFr_fnc_log }; + }; + }; + if (_useChute isEqualTo 0) then + { + _crate = createVehicle [_box, _pos, [], 0, "NONE"]; + _crate allowDamage false; + if (_allowCrateLift isEqualTo 0) then + { + _crate enableRopeAttach false; + }; + _lootLoaded = [_crate] call VEMFr_fnc_loadLoot; + if _lootLoaded then { ["DynamicLocationInvasion", 1, "Loot loaded successfully into crate"] spawn VEMFr_fnc_log }; + }; + if (_markCrateVisual isEqualTo 1) then + { + uiSleep 0.5; + // If night, attach a chemlight + if (dayTime < 5 OR dayTime > 19) then + { + _colors = [["DynamicLocationInvasion"],["flairTypes"]] call VEMFr_fnc_getSetting param [0, [], [[]]]; + if (count _colors > 0) then + { + _lightType = selectRandom _colors; + _light = _lightType createVehicle (position _crate); + _light attachTo [_crate,[0,0,0]]; + }; + }; + // Attach smoke + _colors = [["DynamicLocationInvasion"],["smokeTypes"]] call VEMFr_fnc_getSetting param [0, [], [[]]]; + if (count _colors > 0) then + { + _rndmColor = selectRandom _colors; + _smoke = createVehicle [_rndmColor, getPos _crate, [], 0, "CAN_COLLIDE"]; + _smoke attachTo [_crate,[0,0,0]]; + }; + }; + if (_useChute isEqualTo 1) then + { + waitUntil { uiSleep 1; (((getPos _crate) select 2) < 7) }; + detach _crate; + }; + if not isNil"_marker" then + { + deleteMarker _marker + }; + VEMFr_invasCount = VEMFr_invasCount - 1; + VEMFr_missionCount = VEMFr_missionCount - 1; + + // Put a marker on the crate if enabled + if not isNil "_crate" then + { + if not isNull _crate then + { + if not ([getPos _crate, 2] call VEMFr_fnc_checkPlayerPresence) then + { + _addMarker = [["DynamicLocationInvasion"],["markCrateOnMap"]] call VEMFr_fnc_getSetting param [0, 1, [0]]; + if (_addMarker isEqualTo 1) then + { + private ["_crateMarker"]; + _crateMarker = createMarker [format["VEMF_lootCrate_ID%1", random 9000], position _crate]; + _crateMarker setMarkerShape "ICON"; + _crateMarker setMarkerType "mil_box"; + _crateMarker setMarkerColor "colorBlack"; + _crateMarker setMarkerText " Loot"; + [_crate, _crateMarker] spawn + { + _crate = _this select 0; + _crateMarker = _this select 1; + waitUntil { uiSleep 4; [getPos _crate, 3] call VEMFr_fnc_checkPlayerPresence }; + deleteMarker _crateMarker; + }; + }; + }; + }; + }; + + if isNil "_crate" then + { + ["DynamicLocationInvasion", 0, "ERROR! _crate not found"] spawn VEMFr_fnc_log; + }; + + // Explode or remove the mines + if not isNil"_minesPlaced" then + { + private ["_cleanMines"]; + _cleanMines = [["DynamicLocationInvasion"],["minesCleanup"]] call VEMFr_fnc_getSetting param [0, 1, [0]]; + if (_cleanMines isEqualTo 2) then + { + { + if not isNull _x then + { + _x setDamage 1; + uiSleep (2 + round random 2); + }; + } forEach _minesPlaced; + ["DynamicLocationInvasion", 1, format["Successfully exploded all %1 mines at %2", count _minesPlaced, _locName]] spawn VEMFr_fnc_log; + _minesPlaced = nil; + }; + if (_cleanMines isEqualTo 1) then + { + { + if not isNull _x then + { + deleteVehicle _x; + }; + } forEach _minesPlaced; + ["DynamicLocationInvasion", 1, format["Successfully deleted all %1 mines at %2", count _minesPlaced, _locName]] spawn VEMFr_fnc_log; + _minesPlaced = nil; + }; + }; + + // If enabled, fix all the lights + if (_streetLightsRestore isEqualTo 1) then + { + private ["_all"]; + _all = nearestObjects [_loc select 1, ["Lamps_Base_F","PowerLines_base_F","Land_PowerPoleWooden_L_F"], _streetLightsRange]; + { + if (damage _x > 0.94) then + { + _x setDamage 0; + uiSleep 0.2; + }; + } forEach _all; + }; + }; + }; + if isNil"_spawned" then + { + ["DynamicLocationInvasion", 0, format["Failed to spawn AI in %1", _locName]] spawn VEMFr_fnc_log; + if not isNil"_marker" then + { + deleteMarker _marker + }; + VEMFr_invasCount = VEMFr_invasCount - 1; + VEMFr_missionCount = VEMFr_missionCount - 1; + }; + }; + if not _playerNear then + { + ["DynamicLocationInvasion", 1, format["Invasion of %1 timed out.", _locName]] spawn VEMFr_fnc_log; + if not isNil"_marker" then + { + deleteMarker _marker + }; + _usedLocs = uiNamespace getVariable "VEMFrUsedLocs"; + _index = _usedLocs find _loc; + if (_index > -1) then + { + _usedLocs deleteAt _index; + }; + VEMFr_invasCount = VEMFr_invasCount - 1; + VEMFr_missionCount = VEMFr_missionCount - 1; + }; + }; + if not(_loc isEqualType []) then + { + VEMFr_invasCount = VEMFr_invasCount - 1; + VEMFr_missionCount = VEMFr_missionCount - 1; + }; +}; +if (VEMFr_invasCount >= _maxInvasions) then +{ + VEMFr_invasCount = VEMFr_invasCount - 1; + VEMFr_missionCount = VEMFr_missionCount - 1; +};