From 7268462138a86485e182c0d43864c0056cbfbf39 Mon Sep 17 00:00:00 2001 From: second_coming Date: Wed, 10 Aug 2016 17:01:48 +0100 Subject: [PATCH] V58 - Random AI Testing --- pre-packaged pbo/a3_exile_occupation.pbo | Bin 200655 -> 214296 bytes source/a3_exile_occupation/README.md | 4 +- source/a3_exile_occupation/changeLog.txt | 5 + source/a3_exile_occupation/config.cpp | 2 +- source/a3_exile_occupation/config.sqf | 22 +- source/a3_exile_occupation/initServer.sqf | 6 +- .../scripts/eventHandlers/driverKilled.sqf | 5 - .../eventHandlers/randomUnitMPKilled.sqf | 11 + .../eventHandlers/vehicleDestroyed.sqf | 11 +- .../scripts/functions/fnc_isSafePosRandom.sqf | 47 +++ .../scripts/functions/fnc_selectGear.sqf | 16 +- .../scripts/occupationMilitary.sqf | 4 +- .../scripts/occupationRandomSpawn.sqf | 323 +++++++++++++++++- .../scripts/startOccupation.sqf | 3 +- 14 files changed, 425 insertions(+), 34 deletions(-) create mode 100644 source/a3_exile_occupation/scripts/eventHandlers/randomUnitMPKilled.sqf create mode 100644 source/a3_exile_occupation/scripts/functions/fnc_isSafePosRandom.sqf diff --git a/pre-packaged pbo/a3_exile_occupation.pbo b/pre-packaged pbo/a3_exile_occupation.pbo index 70d8e6852ac5d43968b00a527c2e1ffd126bd800..25fa2c8d80a789a7eaf08594e2b9c131226fea32 100644 GIT binary patch delta 9036 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 delta 868 zcmZ9KZAep57{@(l(|MM>j6}vA=f~%>bq+&9 zIsR;vbr{B1OXyfiLfL6kXJ2ARbEFZcW~aEX5TfE-lEw6`eV_xm<0wu&&kv$k~LN zTV0OUy=`rUsL9oi6xG?}K%INr#V@ncmDeWoYqES!TV0qa<-%tgETbA{dO*Ys$ zUrn)C^~O|A9+v~Xahugzg|rk!xqE{`B+%;N_(%xVpc3g!Cb;b+hxsAL>EA~S|T`*=TxJSY$c zC@i2*z!UW&c?*88CrE2YXf2ZKzXUlT9E^D72n8x9Sw9OlkeN1U!p+~arP_1A^Nx&k z!48t{hI-Q34%123QJ5lKa>Hy|6TinW#7-bmGmM)f>k+syRZ06dWfPYj(v&g=`9W`x z4A`MTy5WP5_DI9`;ny_sX%rTco;hgIoZx*vFJ~qzqw-gLJqL3YmZfxhwGauL$(03Y zB#TI;m&iPPYm&qj_#!JU{`SO@NZt=OE#qY=XmM5uPp*CV E1HwNOYXATM diff --git a/source/a3_exile_occupation/README.md b/source/a3_exile_occupation/README.md index 2afe182..f0bc504 100644 --- a/source/a3_exile_occupation/README.md +++ b/source/a3_exile_occupation/README.md @@ -7,7 +7,9 @@ An AI spawner and monitor to be used in conjunction with DMS and will not work w http://www.exilemod.com/topic/61-dms-defents-mission-system/ Download the pbo version here: -https://www.dropbox.com/s/4c2dwwa6v86qhx9/a3_exile_occupation.pbo?dl=0 + +https://github.com/secondcoming/a3_exile_occupation/blob/development/pre-packaged%20pbo/a3_exile_occupation.pbo + To install place the pbo into the @ExileServer/addons folder diff --git a/source/a3_exile_occupation/changeLog.txt b/source/a3_exile_occupation/changeLog.txt index e5a4033..6c74643 100644 --- a/source/a3_exile_occupation/changeLog.txt +++ b/source/a3_exile_occupation/changeLog.txt @@ -1,3 +1,8 @@ +================================================================================= +V58 (10-08-2016) +================================================================================= +Initial version of random spawn module added + ================================================================================= V57 (09-08-2016) ================================================================================= diff --git a/source/a3_exile_occupation/config.cpp b/source/a3_exile_occupation/config.cpp index 5134643..777d135 100644 --- a/source/a3_exile_occupation/config.cpp +++ b/source/a3_exile_occupation/config.cpp @@ -4,7 +4,7 @@ class CfgPatches units[] = {}; weapons[] = {}; requiredVersion = 0.1; - a3_exile_occupation_version = "V57 (09-08-2016)"; + a3_exile_occupation_version = "V58 (10-08-2016)"; requiredAddons[] = {"a3_dms"}; author[]= {"second_coming"}; }; diff --git a/source/a3_exile_occupation/config.sqf b/source/a3_exile_occupation/config.sqf index 6ea9fb8..5e8f14e 100644 --- a/source/a3_exile_occupation/config.sqf +++ b/source/a3_exile_occupation/config.sqf @@ -45,7 +45,7 @@ SC_occupyTraders = true; // true if you want to create trader c SC_occupyStatic = false; // true if you want to add AI in specific locations SC_occupyTransport = true; // true if you want pubic transport (travels between traders) SC_occupyLootCrates = true; // true if you want to have random loot crates with guards -SC_occupyRandomSpawn = false; // (WORK IN PROGRESS, NOT WORKING YET) true if you want random spawning AI that hunt for nearby players +SC_occupyRandomSpawn = true; // (WORK IN PROGRESS) true if you want random spawning AI that hunt for nearby players SC_occupyMilitary = false; // true if you want military buildings patrolled SC_occupyVehicle = true; // true if you want to have roaming AI land vehicles SC_occupySky = true; // true if you want to have roaming AI helis @@ -61,12 +61,21 @@ SC_fastNightsEnds = 6; // End fast nights at this SC_fastNightsMultiplierDay = 4; // the time multiplier to use during daylight hours (4 = 4x speed) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Random Spawn Setup (not working yet) +// Random Spawn Setup (Work in progress) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SC_randomSpawnMinPlayers = 1; // Minimum number of players to be online before random spawning AI can spawn -SC_randomSpawnMaxAI = 5; // Maximum amount of random AI groups allowed at any time +SC_randomSpawnMaxGroups = 5; // Maximum amount of random AI groups allowed at any time +SC_randomSpawnMinGroupSize = 1; // Minimum amount of random AI groups allowed per group +SC_randomSpawnMaxGroupSize = 3; // Maximum amount of random AI groups allowed per group +SC_randomSpawnChance = 10; // Percentage chance of spawning if suitable player found SC_randomSpawnIgnoreCount = true; // true if you want spawn random AI groups regardless of overall AI count (they still count towards the total though) +SC_randomSpawnFrequency = 1800; // time in seconds between the possibility of random AI hunting the same player (1800 for 30 minutes) +SC_randomSpawnAnnounce = true; // true if you want a warning toast issued to all players when AI spawns + +SC_randomSpawnNearBases = false; // true if you want to allow random spawns in range of territories +SC_randomSpawnNearSpawns = false; // true if you want to allow random spawns in range of spawn zones +SC_randomSpawnTargetBambis = false; // true if you want to allow random spawns to target bambis ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Occupy Places Setup @@ -226,7 +235,7 @@ SC_HeliCrashMagazinesAmount = [2,2]; // [fixed amount to add, random amount to ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// SC_minimumCrewAmount = 2; // Maximum amount of AI allowed in a vehicle -SC_maximumCrewAmount = 6; // Maximum amount of AI allowed in a vehicle +SC_maximumCrewAmount = 4; // Maximum amount of AI allowed in a vehicle // (essential crew like drivers and gunners will always spawn regardless of these settings) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -450,9 +459,10 @@ if (SC_debug) then SC_extendedLogging = true; SC_processReporter = true; SC_mapMarkers = true; - SC_occupyPlaces = true; + SC_occupyPlaces = false; SC_occupyVehicle = false; SC_occupyMilitary = false; + SC_occupyRandomSpawn = true; SC_occupyStatic = false; SC_occupySky = false; SC_occupySea = false; @@ -491,6 +501,7 @@ SC_liveHelisArray = []; SC_liveBoats = 0; SC_liveBoatsArray = []; SC_liveStaticGroups = []; +SC_liveRandomGroups = []; SC_transportArray = []; // Remove spawn locations for roaming vehicles that aren't for this map @@ -511,6 +522,7 @@ publicVariable "SC_liveHelisArray"; publicVariable "SC_liveBoats"; publicVariable "SC_liveBoatsArray"; publicVariable "SC_liveStaticGroups"; +publicVariable "SC_liveRandomGroups"; publicVariable "SC_numberofLootCrates"; publicVariable "SC_transportArray"; publicVariable "SC_SurvivorSide"; diff --git a/source/a3_exile_occupation/initServer.sqf b/source/a3_exile_occupation/initServer.sqf index e1876e7..c230318 100644 --- a/source/a3_exile_occupation/initServer.sqf +++ b/source/a3_exile_occupation/initServer.sqf @@ -52,14 +52,16 @@ SC_occupationVersion = getText (configFile >> "CfgPatches" >> "a3_exile_occupati SC_fnc_getOffBus = compile preprocessFileLineNumbers "\x\addons\a3_exile_occupation\scripts\eventHandlers\getOffBus.sqf"; SC_fnc_getOnBus = compile preprocessFileLineNumbers "\x\addons\a3_exile_occupation\scripts\eventHandlers\getOnBus.sqf"; SC_fnc_locationUnitMPKilled = compile preprocessFileLineNumbers "\x\addons\a3_exile_occupation\scripts\eventHandlers\locationUnitMPKilled.sqf"; - SC_fnc_staticUnitMPKilled = compile preprocessFileLineNumbers "\x\addons\a3_exile_occupation\scripts\eventHandlers\staticUnitMPKilled.sqf"; + SC_fnc_staticUnitMPKilled = compile preprocessFileLineNumbers "\x\addons\a3_exile_occupation\scripts\eventHandlers\staticUnitMPKilled.sqf"; + SC_fnc_randomUnitMPKilled = compile preprocessFileLineNumbers "\x\addons\a3_exile_occupation\scripts\eventHandlers\randomUnitMPKilled.sqf"; SC_fnc_unitMPHit = compile preprocessFileLineNumbers "\x\addons\a3_exile_occupation\scripts\eventHandlers\unitMPHit.sqf"; SC_fnc_unitMPKilled = compile preprocessFileLineNumbers "\x\addons\a3_exile_occupation\scripts\eventHandlers\unitMPKilled.sqf"; SC_fnc_unitFired = compile preprocessFileLineNumbers "\x\addons\a3_exile_occupation\scripts\eventHandlers\unitFired.sqf"; SC_fnc_addMarker = compile preprocessFileLineNumbers "\x\addons\a3_exile_occupation\scripts\functions\fnc_addMarker.sqf"; SC_fnc_findsafePos = compile preprocessFileLineNumbers "\x\addons\a3_exile_occupation\scripts\functions\fnc_findsafePos.sqf"; - SC_fnc_isSafePos = compile preprocessFileLineNumbers "\x\addons\a3_exile_occupation\scripts\functions\fnc_isSafePos.sqf"; + SC_fnc_isSafePos = compile preprocessFileLineNumbers "\x\addons\a3_exile_occupation\scripts\functions\fnc_isSafePos.sqf"; + SC_fnc_isSafePosRandom = compile preprocessFileLineNumbers "\x\addons\a3_exile_occupation\scripts\functions\fnc_isSafePosRandom.sqf"; SC_fnc_selectGear = compile preprocessFileLineNumbers "\x\addons\a3_exile_occupation\scripts\functions\fnc_selectGear.sqf"; SC_fnc_selectName = compile preprocessFileLineNumbers "\x\addons\a3_exile_occupation\scripts\functions\fnc_selectName.sqf"; SC_fnc_spawnstatics = compile preprocessFileLineNumbers "\x\addons\a3_exile_occupation\scripts\functions\fnc_spawnStatics.sqf"; diff --git a/source/a3_exile_occupation/scripts/eventHandlers/driverKilled.sqf b/source/a3_exile_occupation/scripts/eventHandlers/driverKilled.sqf index 9e2dca9..3f0970e 100644 --- a/source/a3_exile_occupation/scripts/eventHandlers/driverKilled.sqf +++ b/source/a3_exile_occupation/scripts/eventHandlers/driverKilled.sqf @@ -37,11 +37,6 @@ if(count units _group > 0) then _driver = _groupMembers call BIS_fnc_selectRandom; if(_deadDriver == _driver) exitWith { [_vehicle] call SC_fnc_vehicleDestroyed; }; - - //_driver disableAI "TARGET"; - //_driver disableAI "AUTOTARGET"; - //_driver disableAI "AUTOCOMBAT"; - //_driver disableAI "COVER"; _driver assignAsDriver _vehicle; _driver setVariable ["DMS_AssignedVeh",_vehicle]; diff --git a/source/a3_exile_occupation/scripts/eventHandlers/randomUnitMPKilled.sqf b/source/a3_exile_occupation/scripts/eventHandlers/randomUnitMPKilled.sqf new file mode 100644 index 0000000..c48ce94 --- /dev/null +++ b/source/a3_exile_occupation/scripts/eventHandlers/randomUnitMPKilled.sqf @@ -0,0 +1,11 @@ +// Get the variables from the event handler +_unit = _this select 0; + +_group = group _unit; +_selectedPlayer = _group getVariable "SC_huntedPlayer"; + +if((count (units _group)) == 0) then +{ + // Remove the group + SC_liveRandomGroups = SC_liveRandomGroups - _group; +}; \ No newline at end of file diff --git a/source/a3_exile_occupation/scripts/eventHandlers/vehicleDestroyed.sqf b/source/a3_exile_occupation/scripts/eventHandlers/vehicleDestroyed.sqf index fbc20df..19c8881 100644 --- a/source/a3_exile_occupation/scripts/eventHandlers/vehicleDestroyed.sqf +++ b/source/a3_exile_occupation/scripts/eventHandlers/vehicleDestroyed.sqf @@ -1,8 +1,13 @@ _vehicle = _this select 0; -_vehicle removeAllMPEventHandlers "mphit"; +//_vehicle removeAllMPEventHandlers "mphit"; //_vehicle removeAllMPEventHandlers "mpkilled"; -_vehicle removeAllEventHandlers "getin"; -_vehicle removeAllEventHandlers "getout"; +//_vehicle removeAllEventHandlers "getin"; +//_vehicle removeAllEventHandlers "getout"; + +if((damage _vehicle) < 1) then +{ + _vehicle removeAllMPEventHandlers "mphit"; +}; if(_vehicle isKindOf "LandVehicle") then { diff --git a/source/a3_exile_occupation/scripts/functions/fnc_isSafePosRandom.sqf b/source/a3_exile_occupation/scripts/functions/fnc_isSafePosRandom.sqf new file mode 100644 index 0000000..df47234 --- /dev/null +++ b/source/a3_exile_occupation/scripts/functions/fnc_isSafePosRandom.sqf @@ -0,0 +1,47 @@ +private _position = _this select 0; +private _validspot = true; + +// Check if position is near a blacklisted area +{ + private _blacklistPos = _x select 0; + private _blacklistRadius = _x select 1; + private _blacklistMap = _x select 2; + if(isNil "_blacklistPos" OR isNil "_blacklistRadius" OR isNil "_blacklistMap") exitWith + { + _logDetail = format["[OCCUPATION]:: Invalid blacklist position supplied check SC_blackListedAreas in your config.sqf"]; + [_logDetail] call SC_fnc_log; + + }; + if (worldName == _blacklistMap) then + { + + _distance = _position distance2D _blacklistPos; + if(_distance < _blacklistRadius) then + { + _validspot = false; + diag_log format["%1 is %2m from blacklisted position %3 (blacklisted)",_position,_distance,_blacklistPos]; + }; + }; +}forEach SC_blackListedAreas; + +if(_validspot) then +{ + + // is position in range of a trader zone? + if([_position, SC_minDistanceToTraders] call ExileClient_util_world_isTraderZoneInRange) exitwith { _validspot = false; }; + + if(!SC_randomSpawnNearSpawns) then + { + // is position in range of a spawn zone? + if([_position, SC_minDistanceToSpawnZones] call ExileClient_util_world_isSpawnZoneInRange) exitwith { _validspot = false; }; + }; + + if(!SC_randomSpawnNearBases) then + { + // is position in range of a territory? + if([_position, SC_minDistanceToTerritory] call ExileClient_util_world_isTerritoryInRange) exitwith { _validspot = false; }; + }; + +}; + +_validspot \ No newline at end of file diff --git a/source/a3_exile_occupation/scripts/functions/fnc_selectGear.sqf b/source/a3_exile_occupation/scripts/functions/fnc_selectGear.sqf index 0023434..b4aa99d 100644 --- a/source/a3_exile_occupation/scripts/functions/fnc_selectGear.sqf +++ b/source/a3_exile_occupation/scripts/functions/fnc_selectGear.sqf @@ -53,7 +53,21 @@ switch (_side) do _magazines pushBack [_newMagazine,_quantity]; }; }; - }; + }; + case "cops": + { + _uniform = "U_B_GEN_Soldier_F"; + _vest = "V_TacVest_gen_F"; + _headgear = "H_Cap_police"; + _weapon = "SMG_05_F"; + _weaponAttachments = ["muzzle_snds_L"]; + _pistol = "hgun_Rook40_F"; + _pistolAttachments = ["muzzle_snds_L"]; + _launcher = ""; + _backpack = ""; + _assignedItems = ["ItemMap","ItemCompass","ItemRadio","ItemWatch"]; + _magazines = ["30Rnd_9x21_Mag_SMG_02","30Rnd_9x21_Mag_SMG_02","16Rnd_9x21_Mag","16Rnd_9x21_Mag"]; + }; }; _weaponAttachmentsChance = round (random 100); diff --git a/source/a3_exile_occupation/scripts/occupationMilitary.sqf b/source/a3_exile_occupation/scripts/occupationMilitary.sqf index 6cef502..13e714c 100644 --- a/source/a3_exile_occupation/scripts/occupationMilitary.sqf +++ b/source/a3_exile_occupation/scripts/occupationMilitary.sqf @@ -94,8 +94,8 @@ if(_aiActive > _maxAIcount) exitWith ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Get AI to patrol the area ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - _aiCount = 2 + (round (random 1)); - _groupRadius = 200; + _aiCount = 1 + (round (random 2)); + _groupRadius = 500; _difficulty = "random"; _side = SC_BanditSide; _spawnPosition = _pos; diff --git a/source/a3_exile_occupation/scripts/occupationRandomSpawn.sqf b/source/a3_exile_occupation/scripts/occupationRandomSpawn.sqf index 2059e60..d134ed6 100644 --- a/source/a3_exile_occupation/scripts/occupationRandomSpawn.sqf +++ b/source/a3_exile_occupation/scripts/occupationRandomSpawn.sqf @@ -15,10 +15,132 @@ _useLaunchers = DMS_ai_use_launchers; _scaleAI = SC_scaleAI; _side = "bandit"; +// Don't run for the first 5 minutes after restart +if(time < 300) exitWith +{ + if(SC_extendedLogging) then + { + _logDetail = format['[OCCUPATION:RandomSpawn] Waiting until the server has been up at least 5 minutes (it has currently been up for %1 seconds)',time]; + [_logDetail] call SC_fnc_log; + }; +}; + + +// Control Existing Random Spawns +{ + _group = _x; + if((count (units _group)) == 0) then + { + // Remove the group + SC_liveRandomGroups = SC_liveRandomGroups - [_group]; + if(SC_extendedLogging) then + { + _logDetail = format['[OCCUPATION:RandomSpawn] group %1 removed (killed by players)',_group]; + [_logDetail] call SC_fnc_log; + }; + } + else + { + _groupLeader = leader _group; + _distanceFromSelectedPlayer = 500; + _selectedPlayer = _group getVariable "SC_huntedPlayer"; + + if(alive _selectedPlayer) then + { + _distanceFromSelectedPlayer = _selectedPlayer distance _groupLeader; + }; + _selectedPlayer getVariable "SC_lastHunted"; + _suitableTargets = []; + + if(!alive _selectedPlayer OR _distanceFromSelectedPlayer >= 500) then + { + // Select a new target or despawn if not target near + _nearPlayers = player nearEntities ["Exile_Unit_Player", 250]; + { + _selectedPlayer = _x; + _playersPosition = position _selectedPlayer; + _suitablePlayer = [ _playersPosition ] call SC_fnc_isSafePosRandom; + _suitablePlayerisBambi = _selectedPlayer getVariable "ExileIsBambi"; + + if(_suitablePlayer && (!_suitablePlayerisBambi OR SC_randomSpawnTargetBambis)) then + { + _suitableTargets pushBack _selectedPlayer; + }; + }forEach _nearPlayers; + + if(count(_suitableTargets) > 0) then + { + _selectedPlayer = _suitableTargets call BIS_fnc_selectRandom; + _group setVariable ["SC_huntedPlayer",_selectedPlayer]; + + // Hunt the selected player + _group reveal [_selectedPlayer,1.5]; + _destination = getPos _selectedPlayer; + _group allowFleeing 0; + _wp = _group addWaypoint [_destination, 0] ; + _wp setWaypointFormation "Column"; + _wp setWaypointBehaviour "COMBAT"; + _wp setWaypointCombatMode "RED"; + _wp setWaypointCompletionRadius 25; + _wp setWaypointType "SAD"; + + [_group, _destination, 500] call bis_fnc_taskPatrol; + _group allowFleeing 0; + _group setBehaviour "AWARE"; + _group setCombatMode "RED"; + + } + else + { + // Remove the group + SC_liveRandomGroups = SC_liveRandomGroups - [_group]; + _cleanup = []; + { + _cleanup pushBack _x; + } forEach units _group; + _cleanup call DMS_fnc_CleanUp; + }; + } + else + { + { + + }forEach units _group; + + // Make sure the target is being hunted + _group reveal [_selectedPlayer,1.5]; + _destination = getPos _selectedPlayer; + _group allowFleeing 0; + _wp = _group addWaypoint [_destination, 0] ; + _wp setWaypointFormation "Column"; + _wp setWaypointBehaviour "COMBAT"; + _wp setWaypointCombatMode "RED"; + _wp setWaypointCompletionRadius 25; + _wp setWaypointType "SAD"; + + [_group, _destination, 500] call bis_fnc_taskPatrol; + _group allowFleeing 0; + _group setBehaviour "AWARE"; + _group setCombatMode "RED"; + }; + + }; + +}forEach SC_liveRandomGroups; + + +if(count(SC_liveRandomGroups) >= SC_randomSpawnMaxGroups) exitWith +{ + if(SC_extendedLogging) then + { + _logDetail = format['[OCCUPATION:RandomSpawn] End check %1 groups active (max %2) @ %3',count(SC_liveRandomGroups),SC_randomSpawnMaxGroups,time]; + [_logDetail] call SC_fnc_log; + }; +}; // more than _scaleAI players on the server and the max AI count drops per additional player _currentPlayerCount = count playableUnits; -if(_currentPlayerCount < SC_randomSPawnMinPlayers) exitWith +if(_currentPlayerCount < SC_randomSPawnMinPlayers OR _currentPlayerCount < count(SC_liveRandomGroups)) exitWith { if(SC_extendedLogging) then { @@ -43,19 +165,194 @@ if(diag_fps < _minFPS) exitWith _aiActive = { !isPlayer _x } count allunits; -if(_aiActive > _maxAIcount) exitWith -{ - if(SC_extendedLogging) then - { - _logDetail = format ["[OCCUPATION:RandomSpawn]:: %1 active AI, so not spawning AI this time",_aiActive]; - [_logDetail] call SC_fnc_log; - }; +if(!SC_randomSpawnIgnoreCount) then +{ + if(_aiActive > _maxAIcount) exitWith + { + if(SC_extendedLogging) then + { + _logDetail = format ["[OCCUPATION:RandomSpawn]:: %1 active AI, so not spawning AI this time",_aiActive]; + [_logDetail] call SC_fnc_log; + }; + }; }; -SC_suitablePlayers = []; -// Find a player to spawn AI near +// Get current targets +_huntedPlayers = []; { - _suitablePlayer = true; - - + _group = _x; + _huntedPlayer = _group getVariable "SC_huntedPlayer"; + _huntedPlayers pushback _huntedPlayer; +}forEach SC_liveRandomGroups; + +SC_suitablePlayers = []; + +// Find a player to hunt +{ + _selectedPlayer = _x; + _suitablePlayer = true; + _suitablePlayerisBambi = _selectedPlayer getVariable "ExileIsBambi"; + if(_suitablePlayerisBambi && !SC_randomSpawnTargetBambis) exitWith + { + _suitablePlayer = false; + if(SC_extendedLogging) then + { + _logDetail = format ["[OCCUPATION:RandomSpawn]:: %1 is still a bambi, awww!",_selectedPlayer]; + [_logDetail] call SC_fnc_log; + }; + }; + + if(_selectedPlayer in _huntedPlayers) exitWith + { + _suitablePlayer = false; + if(SC_extendedLogging) then + { + _logDetail = format ["[OCCUPATION:RandomSpawn]:: %1 is already being hunted",_selectedPlayer]; + [_logDetail] call SC_fnc_log; + }; + }; + + _lastHunted = _x getVariable "SC_lastHunted"; + if(isNil "_lastHunted") then + { + _lastHunted = -5000; + }; + + if((time - _lastHunted) < SC_randomSpawnFrequency) exitWith + { + _suitablePlayer = false; + if(SC_extendedLogging) then + { + _logDetail = format ["[OCCUPATION:RandomSpawn]:: %1 has been hunted recently, not spawning another group yet",_selectedPlayer]; + [_logDetail] call SC_fnc_log; + }; + }; + + if(vehicle _selectedPlayer != _selectedPlayer) exitWith + { + _suitablePlayer = false; + if(SC_extendedLogging) then + { + _logDetail = format ["[OCCUPATION:RandomSpawn]:: selected player %1 is in a vehicle, so not spawning AI this round",_selectedPlayer,_diceRoll,(100 - SC_randomSpawnChance)]; + [_logDetail] call SC_fnc_log; + }; + }; + + _diceRoll = random(100); + if(_diceRoll <= (100 - SC_randomSpawnChance)) exitWith + { + _suitablePlayer = false; + if(SC_extendedLogging) then + { + _logDetail = format ["[OCCUPATION:RandomSpawn]:: %1 rolled %2 (%3+ required) so not spawning another group yet",_selectedPlayer,_diceRoll,(100 - SC_randomSpawnChance)]; + [_logDetail] call SC_fnc_log; + }; + }; + + // rolled more than the needed amount and not spawned hunters recently + _playersPosition = position _selectedPlayer; + + // Is the player in a suitable place? + if(_suitablePlayer) then + { + _suitablePlayer = [ _playersPosition ] call SC_fnc_isSafePosRandom; + }; + + _spawnLocation = [0,0,0]; + + // Suitable player and location found + if(_suitablePlayer) then + { + + // Find a safe position to spawn + _suitableLocation = false; + _attempts = 1; + while{!_suitableLocation && _attempts < 50} do + { + _spawnLocation = [_playersPosition,250,450,15,0,20,0] call BIS_fnc_findSafePos; + _suitableLocation = [ _spawnLocation ] call SC_fnc_isSafePosRandom; + _attempts = _attempts + 1; + sleep 0.1; + }; + + if(!_suitableLocation) then + { + if(SC_extendedLogging) then + { + _logDetail = format ["[OCCUPATION:RandomSpawn]:: unable to find safe place near %1",_suitablePlayer]; + [_logDetail] call SC_fnc_log; + }; + } + else + { + _group = createGroup SC_BanditSide; + _group setVariable ["DMS_AllowFreezing",false]; + _group setVariable ["DMS_LockLocality",true]; + _group setVariable ["DMS_SpawnedGroup",true]; + _group setVariable ["DMS_Group_Side", SC_BanditSide]; + _group setVariable ["SC_huntedPlayer",_selectedPlayer]; + _selectedPlayer setVariable ["SC_lastHunted",time]; + SC_liveRandomGroups = SC_liveRandomGroups + [_group]; + + _groupSize = random [SC_randomSpawnMinGroupSize, SC_randomSpawnMinGroupSize+(SC_randomSpawnMaxGroupSize-SC_randomSpawnMinGroupSize)/2, SC_randomSpawnMaxGroupSize]; + for "_i" from 1 to _groupSize do + { + _loadOut = ["cops"] call SC_fnc_selectGear; + _unit = [_group,_spawnLocation,"custom","random",_side,"soldier",_loadOut] call DMS_fnc_SpawnAISoldier; + _unit allowFleeing 0; + _unit allowDamage false; + _unit disableAI "AUTOTARGET"; + _unit disableAI "TARGET"; + _unit disableAI "MOVE"; + _unitName = ["survivor"] call SC_fnc_selectName; + if(!isNil "_unitName") then { _unit setName _unitName; }; + _unit addMPEventHandler ["mpkilled", "_this call SC_fnc_randomUnitMPKilled;"]; + _unit addeventhandler ["Fired", {(vehicle (_this select 0)) setvehicleammo 1;}]; + }; + + { + _unit = _x; + _unit allowDamage true; + _unit enableAI "AUTOTARGET"; + _unit enableAI "TARGET"; + _unit enableAI "MOVE"; + _unit setCaptive false; + }foreach units _group; + + if(SC_randomSpawnAnnounce) then + { + ["toastRequest", ["InfoTitleAndText", ["Raid group Incoming!", "A squad of Police have been despatched to take out a trouble prisoner."]]] call ExileServer_system_network_send_broadcast; + }; + + _logDetail = format ["[OCCUPATION:RandomSpawn]:: Spawning a group of AI @ %2 to hunt player %1",_selectedPlayer,_spawnLocation]; + [_logDetail] call SC_fnc_log; + + + // Hunt the selected player + _group reveal [_selectedPlayer,1.5]; + _destination = getPos _selectedPlayer; + _group allowFleeing 0; + _wp = _group addWaypoint [_destination, 0] ; + _wp setWaypointFormation "Column"; + _wp setWaypointBehaviour "COMBAT"; + _wp setWaypointCombatMode "RED"; + _wp setWaypointCompletionRadius 25; + _wp setWaypointType "SAD"; + + [_group, _destination, 500] call bis_fnc_taskPatrol; + _group allowFleeing 0; + _group setBehaviour "AWARE"; + _group setCombatMode "RED"; + }; + } + else + { + if(SC_extendedLogging) then + { + _logDetail = format ["[OCCUPATION:RandomSpawn]:: %1 is not in a safe place to spawn AI",_selectedPlayer]; + [_logDetail] call SC_fnc_log; + }; + }; }forEach playableUnits; + + diff --git a/source/a3_exile_occupation/scripts/startOccupation.sqf b/source/a3_exile_occupation/scripts/startOccupation.sqf index a13a404..97e16ad 100644 --- a/source/a3_exile_occupation/scripts/startOccupation.sqf +++ b/source/a3_exile_occupation/scripts/startOccupation.sqf @@ -70,7 +70,8 @@ if(SC_occupyMilitary) then if(SC_occupyRandomSpawn) then { uiSleep 15; // delay the start - call compile preprocessFileLineNumbers "\x\addons\a3_exile_occupation\scripts\occupationRandomSpawn.sqf"; + fnc_occupyRandomSpawn = compile preprocessFileLineNumbers "\x\addons\a3_exile_occupation\scripts\occupationRandomSpawn.sqf"; + [SC_refreshTime, fnc_occupyRandomSpawn, [], true] call ExileServer_system_thread_addTask; }; if(SC_occupyLootCrates) then