diff --git a/pre-packaged pbo/a3_exile_occupation.pbo b/pre-packaged pbo/a3_exile_occupation.pbo index 70d8e68..25fa2c8 100644 Binary files a/pre-packaged pbo/a3_exile_occupation.pbo and b/pre-packaged pbo/a3_exile_occupation.pbo differ 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