diff --git a/@ExileServer/addons/a3_dms/config.sqf b/@ExileServer/addons/a3_dms/config.sqf index a154dd6..2a8fdda 100644 --- a/@ExileServer/addons/a3_dms/config.sqf +++ b/@ExileServer/addons/a3_dms/config.sqf @@ -58,16 +58,6 @@ DMS_DEBUG = false; /* AI Settings */ - DMS_ai_wep_accessories = ["acc_pointer_IR","acc_flashlight"]; - DMS_ai_wep_suppressors = [ - "muzzle_snds_H", - "muzzle_snds_L", - "muzzle_snds_M", - "muzzle_snds_B", - "muzzle_snds_H_MG", - "muzzle_snds_acp" - ]; - DMS_banditSide = EAST; // The side (team) that AI Bandits will spawn on DMS_clear_AI_body = false; // Clear AI body when they die @@ -78,7 +68,8 @@ DMS_DEBUG = false; DMS_ai_share_info_distance = 300; // The distance killer's info will be shared to other AI DMS_ai_use_launchers = true; // Enable/disable spawning an AI in a group with a launcher - DMS_ai_use_launchers_chance = 0.5; // Percentage chance to actually spawn the launcher (per-group) + DMS_ai_use_launchers_chance = 50; // Percentage chance to actually spawn the launcher (per-group) + DMS_ai_nighttime_accessory_chance = 75; // Percentage chance that AI will have a flashlight or laser pointer on their guns if spawned during nighttime DMS_ai_remove_launchers = false; // Remove rocket launchers on AI death DMS_ai_enable_water_equipment = true; // Enable/disable overriding default weapons of an AI if it spawns on/in water @@ -96,6 +87,24 @@ DMS_DEBUG = false; "O_HMG_01_high_F" ]; + DMS_ai_default_items = [ // Toolbelt items each AI will spawn with + "ItemWatch", + "ItemMap", + "ItemCompass", + "ItemRadio" + ]; + + DMS_ai_BipodList = [ + "bipod_01_F_blk", + "bipod_01_F_mtp", + "bipod_01_F_snd", + "bipod_02_F_blk", + "bipod_02_F_hex", + "bipod_02_F_tan", + "bipod_03_F_blk", + "bipod_03_F_oli" + ]; + //Assault Class DMS_assault_weps = [ // Assault Rifles "arifle_Katiba_GL_F", @@ -109,7 +118,7 @@ DMS_DEBUG = false; "arifle_Mk20_plain_F", "arifle_Mk20_F" ]; - DMS_assault_pistols = [ // Pistols for Assault Class + DMS_assault_pistols = [ // Pistols for Assault Class (Set to empty array if you don't want to give them any pistols) "hgun_PDW2000_F", "hgun_ACPC2_F", "hgun_Rook40_F", @@ -125,7 +134,9 @@ DMS_DEBUG = false; "optic_MRCO", "optic_DMS" ]; - DMS_assault_scope_chance = 0.75; // Percentage chance that Assault class AI will get an optic on their weapons + DMS_assault_optic_chance = 75; // Percentage chance that an Assault Class AI will get an optic + DMS_assault_bipod_chance = 25; // Percentage chance that an Assault Class AI will get a bipod + DMS_assault_suppressor_chance = 25; // Percentage chance that an Assault Class AI will get a suppressor DMS_assault_items = ["ItemGPS"]; DMS_assault_helmets = [ // Helmets for Assault Class "H_HelmetSpecB_paint1", @@ -177,7 +188,7 @@ DMS_DEBUG = false; "arifle_MX_SW_Black_F", "MMG_01_hex_F" ]; - DMS_MG_pistols = [ // Pistols for MG Class + DMS_MG_pistols = [ // Pistols for MG Class (Set to empty array if you don't want to give them any pistols) "hgun_PDW2000_F", "hgun_ACPC2_F", "hgun_Rook40_F", @@ -191,8 +202,10 @@ DMS_DEBUG = false; "optic_Holosight", "optic_MRCO" ]; - DMS_MG_scope_chance = 0.5; // Percentage chance that MG Class AI will get an optic on their weapons - DMS_MG_items = ["ItemWatch","ItemMap","ItemCompass","Binocular"]; + DMS_MG_optic_chance = 50; // Percentage chance that an MG Class AI will get an optic + DMS_MG_bipod_chance = 90; // Percentage chance that an MG Class AI will get a bipod + DMS_MG_suppressor_chance = 10; // Percentage chance that an MG Class AI will get a suppressor + DMS_MG_items = ["Binocular"]; DMS_MG_helmets = [ // Helmets for MG Class "H_PilotHelmetHeli_I", "H_PilotHelmetHeli_O", @@ -252,7 +265,7 @@ DMS_DEBUG = false; "arifle_MXM_Black_F", "srifle_DMR_02_F" ]; - DMS_sniper_pistols = [ // Pistols for Sniper Class + DMS_sniper_pistols = [ // Pistols for Sniper Class (Set to empty array if you don't want to give them any pistols) "hgun_PDW2000_F", "hgun_ACPC2_F", "hgun_Rook40_F", @@ -265,7 +278,9 @@ DMS_DEBUG = false; "optic_DMS", "optic_LRPS" ]; - DMS_sniper_scope_chance = 1; // Percentage chance that Sniper Class AI will get an optic on their weapons + DMS_sniper_optic_chance = 100; // Percentage chance that a Sniper Class AI will get an optic + DMS_sniper_bipod_chance = 90; // Percentage chance that a Sniper Class AI will get a bipod + DMS_sniper_suppressor_chance = 15; // Percentage chance that a Sniper Class AI will get a suppressor DMS_sniper_items = ["Rangefinder","ItemGPS"]; DMS_sniper_helmets = [ // Helmets for Sniper Class "H_HelmetSpecB_paint1", @@ -308,16 +323,23 @@ DMS_DEBUG = false; "B_Carryall_cbr", "B_Bergen_blk" ]; + + DMS_ai_SupportedClasses = [ // Allowed AI classes. If you want to create your own class, make sure you define everything as I've defined above, and add it here + "assault", + "MG", + "sniper" + ]; DMS_random_AI = [ // The classes that a "random" AI can spawn as | DEFAULT: 60% Assault, 20% MG, 20% Sniper "assault", "assault", "assault", - "machine", + "MG", "sniper" ]; DMS_AI_wep_launchers = ["Exile_Melee_Axe"]; + /* AI Settings */ @@ -386,12 +408,12 @@ DMS_DEBUG = false; ]; DMS_BoxItems = DMS_BoxSurvivalSupplies+DMS_BoxBuildingSupplies+DMS_BoxOptics; // Random "items" can spawn optics, survival supplies, or building supplies - DMS_RareLoot = true; // Potential chance to spawn rare loot in any crate. + DMS_RareLoot = true; // Potential chance to spawn rare loot in any crate. DMS_RareLootList = [ // List of rare loot to spawn "Exile_Item_SafeKit", "Exile_Item_CodeLock" ]; - DMS_RareLootChance = 0.1; // Chance to spawn rare loot in any crate | Default: 10% + DMS_RareLootChance = 10; // Percentage Chance to spawn rare loot in any crate | Default: 10% // Vehicles DMS_ArmedVehicles = [ // List of armed vehicles that can spawn diff --git a/@ExileServer/addons/a3_dms/fn_DMS_preInit.sqf b/@ExileServer/addons/a3_dms/fn_DMS_preInit.sqf index 88a7a61..417bbda 100644 --- a/@ExileServer/addons/a3_dms/fn_DMS_preInit.sqf +++ b/@ExileServer/addons/a3_dms/fn_DMS_preInit.sqf @@ -5,7 +5,6 @@ /* compiles DMS_CreateMarker = compileFinal preprocessFileLineNumbers "\x\addons\dms\scripts\DMS_CreateMarker.sqf"; -DMS_spawnAI = compileFinal preprocessFileLineNumbers "\x\addons\dms\scripts\DMS_spawnAI.sqf"; spawn_group = compileFinal preprocessFileLineNumbers "\x\addons\dms\scripts\spawn_group.sqf"; spawn_soldier = compileFinal preprocessFileLineNumbers "\x\addons\dms\scripts\spawn_soldier.sqf"; spawn_static = compileFinal preprocessFileLineNumbers "\x\addons\dms\scripts\spawn_static.sqf"; @@ -32,6 +31,8 @@ DMS_isNearWater = compileFinal preprocessFileLineNumbers "\x\addons\dms\scr DMS_RemoveMarkers = compileFinal preprocessFileLineNumbers "\x\addons\dms\scripts\RemoveMarkers.sqf"; DMS_selectMagazine = compileFinal preprocessFileLineNumbers "\x\addons\dms\scripts\SelectMagazine.sqf"; DMS_TargetsKilled = compileFinal preprocessFileLineNumbers "\x\addons\dms\scripts\TargetsKilled.sqf"; +DMS_SpawnAIGroup = compileFinal preprocessFileLineNumbers "\x\addons\dms\scripts\SpawnAIGroup.sqf"; +DMS_SpawnAISoldier = compileFinal preprocessFileLineNumbers "\x\addons\dms\scripts\SpawnAISoldier.sqf"; //Load config #include "config.sqf"; \ No newline at end of file diff --git a/@ExileServer/addons/a3_dms/scripts/FillCrate.sqf b/@ExileServer/addons/a3_dms/scripts/FillCrate.sqf index e65f2bc..afba3d4 100644 --- a/@ExileServer/addons/a3_dms/scripts/FillCrate.sqf +++ b/@ExileServer/addons/a3_dms/scripts/FillCrate.sqf @@ -89,7 +89,7 @@ if ((_wepCount>0) && {count _weps>0}) then _weapon = _weps call BIS_fnc_selectRandom; _ammo = _weapon call DMS_selectMagazine; _box addWeaponCargoGlobal _weapon; - _box addMagazineCargoGlobal [_ammo, (2 + floor(random 3))]; + _box addMagazineCargoGlobal [_ammo, (4 + floor(random 3))]; }; }; diff --git a/@ExileServer/addons/a3_dms/scripts/SpawnAIGroup.sqf b/@ExileServer/addons/a3_dms/scripts/SpawnAIGroup.sqf new file mode 100644 index 0000000..41ade2f --- /dev/null +++ b/@ExileServer/addons/a3_dms/scripts/SpawnAIGroup.sqf @@ -0,0 +1,88 @@ +/* + DMS_SpawnAIGroup + Created by eraser1 + Based off of WAI + + Usage: + [ + _pos, // Position of AI + _count, // Number of AI + _difficulty, // "random","hardcore","difficult","moderate", or "easy" + _type // "random","assault","MG","sniper" or "unarmed" + _side // "bandit","hero", etc. + ] call DMS_SpawnAIGroup; +*/ +//<------ TODO + +_position = _this select 0; + _pos_x = _position select 0; + _pos_y = _position select 1; + _pos_z = _position select 2; +_count = _this select 1; +_difficulty = _this select 2; +_type = _this select 3; +_side = _this select 4; + + +if(debug_mode) then { diag_log("WAI: Spawning AI " + str(_side)); }; + +// if soldier have AT/AA weapons +if (typeName _type == "ARRAY") then { + _launcher = _type select 1; + _type = _type select 0; +}; + +// Create AI group +_unitGroup = createGroup wai_bandit_side; + +// Find position +if(_pos_z == 0) then { + if(floor(random 2) == 1) then { + _pos_x = _pos_x - (5 + random(10)); + } else { + _pos_x = _pos_x + (5 + random(10)); + }; + + if(floor(random 2) == 1) then { + _pos_y = _pos_y - (5 + random(10)); + } else { + _pos_y = _pos_y + (5 + random(10)); + }; +}; + +// spawn X numvbers of AI in the group +for "_x" from 1 to _count do { + _unit = [_unitGroup,[_pos_x,_pos_y,_pos_z],_type,_difficulty,_side] call DMS_SpawnAISoldier; + ai_ground_units = (ai_ground_units + 1); +}; + +if (!isNil "_launcher" && wai_use_launchers) then { + call { + if (_launcher == "at") exitWith { _launcher = ai_wep_launchers_AT call BIS_fnc_selectRandom; }; + if (_launcher == "aa") exitWith { _launcher = ai_wep_launchers_AA call BIS_fnc_selectRandom; }; + }; + _rocket = _launcher call find_suitable_ammunition; + _unit addItemToBackpack _rocket; + _unit addItemToBackpack _rocket; + _unit addWeapon _launcher; + _unit addBackpack "B_Carryall_mcamo"; + + if(debug_mode) then { diag_log("WAI: AI "+str(_unit) + " have " + str(_rocket)); }; +}; + +_unitGroup setFormation "ECH LEFT"; +_unitGroup selectLeader ((units _unitGroup) select 0); + +if (!isNil "_mission") then { + if(debug_mode) then { diag_log("WAI: mission nr " + str(_mission)); }; + [_unitGroup, _mission] spawn bandit_behaviour; +} else { + [_unitGroup] spawn bandit_behaviour; +}; + +if(_pos_z == 0) then { + [_unitGroup,[_pos_x,_pos_y,_pos_z],_difficulty] spawn group_waypoints; +}; + +diag_log format ["WAI: Spawned a group of %1 AI at %2",_count,_position]; +_unitGroup \ No newline at end of file diff --git a/@ExileServer/addons/a3_dms/scripts/SpawnAISoldier.sqf b/@ExileServer/addons/a3_dms/scripts/SpawnAISoldier.sqf new file mode 100644 index 0000000..1a512c4 --- /dev/null +++ b/@ExileServer/addons/a3_dms/scripts/SpawnAISoldier.sqf @@ -0,0 +1,278 @@ +/* + DMS_SpawnAISoldier + Created by eraser1 + Based off of WAI + + Usage: + [ + _group, // Group the AI will belong to + _pos, // Position of AI + _type, // "random","assault","MG","sniper" or "unarmed" + _difficulty, // "random","hardcore","difficult","moderate", or "easy" + _side, // "bandit","hero", etc. + _optionalGearSet // OPTIONAL: Manually defined AI gear. + ] call DMS_SpawnAIGroup; + + Usage for _optionalGearSet: + [ + _weapon, // String | EG: "LMG_Zafir_F" + _weaponAttachments, // Array of strings | EG: ["optic_dms","bipod_03_F_blk"] + _magazines, // Array of arrays | EG: [["150Rnd_762x54_Box",2],["16Rnd_9x21_Mag",3]] + _pistol, // String | EG: "hgun_Pistol_heavy_01_snds_F" + _pistolAttachments, // Array of strings | EG: ["optic_MRD","muzzle_snds_acp"] + _items, // Array of strings | EG: ["Rangefinder","ItemGPS","Exile_Item_InstaDoc"] + _helmet, // String | EG: "H_HelmetLeaderO_ocamo" + _uniform, // String | EG: "U_O_GhillieSuit" + _vest, // String | EG: "V_PlateCarrierGL_blk" + _backpack // String | EG: "B_Carryall_oli" + ] +*/ +//<------ TODO: SETUP PRIVATE VARS + +_OK = params +[ + ["_group",(createGroup DMS_banditSide),[grpNull]], + ["_pos",[0,0,0],[[]],[3]], + ["_type","random",[""]], + ["_difficulty","random",[""]], + ["_side","bandit",[""]] +]; +_useCustomGear = false; +_unarmed = false; + +if (!_OK) then +{ + diag_log format ["DMS ERROR :: DMS_SpawnAISoldier called with invalid parameters: %1",_this]; +} +else +{ + if ((_type isEqualTo "custom") && {((count _this)>5)}) then + { + _customGear = _this select 5; + _useCustomGear = true; + }; +}; + +//Create unit +_unit = _group createUnit ["O_recon_F", _pos, [], 0,"FORM"]; +_unit allowFleeing 0; +[_unit] joinSilent _group; + +// Remove existing gear +removeAllWeapons _unit; +removeAllItems _unit; +removeAllAssignedItems _unit; +removeUniform _unit; +removeVest _unit; +removeBackpack _unit; +removeHeadgear _unit; +removeGoggles _unit; + +// Give default items +if !(DMS_ai_default_items isEqualTo []) then +{ + {_unit linkItem _x;false;} count DMS_ai_default_items; +}; + +/* +call { + if(_side == "bandit") exitWith { _unit setVariable ["Bandit",true];}; + if(_side == "hero") exitWith { _unit setVariable ["Hero",true];}; + if(_side == "special") exitWith { _unit setVariable ["Special",true];}; +}; +*/ + +call +{ + if (_type isEqualTo "random") exitWith { _type = DMS_random_AI call BIS_fnc_selectRandom;}; + if (_type isEqualTo "unarmed") exitWith { _type = "assault";_unarmed = true; }; +}; + +// Unit name +_unit setName format["[DMS_Unit_%1%2]",_type,floor(random 1000)]; + +if (!_useCustomGear) then +{ + if !(_type in DMS_ai_SupportedClasses) exitWith + { + diag_log format ["DMS ERROR :: DMS_SpawnAISoldier called with unsupported _type: %1 | _this: %2",_type,_this]; + };// No more idiot-proofing for the following configs + + // Items + {_unit linkItem _x;false;} count (missionNamespace getVariable [format ["DMS_%1_items",_type],[]]); + + // Clothes + _unit addHeadgear ((missionNamespace getVariable [format ["DMS_%1_helmets",_type],[]]) call BIS_fnc_selectRandom); + _unit forceAddUniform ((missionNamespace getVariable [format ["DMS_%1_clothes",_type],[]]) call BIS_fnc_selectRandom); + _unit addVest ((missionNamespace getVariable [format ["DMS_%1_vests",_type],[]]) call BIS_fnc_selectRandom); + _unit addBackpack ((missionNamespace getVariable [format ["DMS_%1_backpacks",_type],[]]) call BIS_fnc_selectRandom); + + // Make AI effective at night + _nighttime = (sunOrMoon != 1); + if (_nighttime) then + { + _unit linkItem "NVGoggles"; + }; + + if (!_unarmed) then + { + _weapon = (missionNamespace getVariable [format ["DMS_%1_weps",_type],[]) call BIS_fnc_selectRandom; + _muzzle = [_unit, _weapon, 4 + floor(random 3)] call BIS_fnc_addWeapon; + _unit selectWeapon _weapon; + + + if((random 100) <= (missionNamespace getVariable [format["DMS_%1_optic_chance",_type],0])) then + { + _unit addPrimaryWeaponItem ((missionNamespace getVariable [format ["DMS_%1_optics",_type],[]) call BIS_fnc_selectRandom); + }; + + if (_nighttime && {(random 100) <= DMS_ai_nighttime_accessory_chance}) then + { + _unit addPrimaryWeaponItem (["acc_pointer_IR","acc_flashlight"] call BIS_fnc_selectRandom); + }; + + if((random 100) <= (missionNamespace getVariable [format["DMS_%1_bipod_chance",_type],0])) then + { + _unit addPrimaryWeaponItem (DMS_ai_BipodList call BIS_fnc_selectRandom); + }; + + + if((random 100) <= (missionNamespace getVariable [format["DMS_%1_suppressor_chance",_type],0])) then + { + _suppressor = _weapon call find_suitable_suppressor; + if(_suppressor != "") then + { + _unit addPrimaryWeaponItem _suppressor; + }; + }; + + // In case spawn position is water + if (DMS_ai_enable_water_equipment && {surfaceIsWater _pos}) then + { + removeHeadgear _unit; + removeAllWeapons _unit; + _unit forceAddUniform "U_O_Wetsuit"; + _unit addVest "V_RebreatherIA"; + _unit addGoggles "G_Diving"; + _muzzle = [_unit, "arifle_SDAR_F", 4 + floor(random 3), "20Rnd_556x45_UW_mag"] call BIS_fnc_addWeapon; + }; + + _pistols = missionNamespace getVariable [format ["DMS_%1_pistols",_type],[]; + if !(_pistols isEqualTo []) then + { + _pistol = _pistols call BIS_fnc_selectRandom; + _muzzle = [_unit, _pistol, 2 + floor(random 2)] call BIS_fnc_addWeapon; + }; + + // Infinite Ammo + _unit addeventhandler ["Fired", {(_this select 0) setvehicleammo 1;}]; + }; +} +else +{ + _OK = _optionalGearSet params + [ + ["_weapon","",[""]], + ["_weaponAttachments",[],[[]]], + ["_magazines",[],[[]]], + ["_pistol","",[""]], + ["_pistolAttachments",[],[[]]], + ["_items",[],[[]]], + ["_helmet","",[""]], + ["_uniform","",[""]], + ["_vest","",[""]], + ["_backpack","",[""]] + ]; + + if (!_OK) exitWith + { + diag_log format ["DMS ERROR :: Calling DMS_SpawnAISoldier with invalid _optionalGearSet: %1 | _this: %2",_optionalGearSet,_this]; + }; + + // Clothes + if !(_helmet isEqualTo "") then + { + _unit addHeadgear _helmet; + }; + + if !(_uniform isEqualTo "") then + { + _unit forceAddUniform _uniform; + }; + + if !(_vest isEqualTo "") then + { + _unit addVest _vest; + }; + + if !(_backpack isEqualTo "") then + { + _unit addBackpack _backpack; + }; + + + // Add Magazines before weapon so that gun will be loaded + { + if ((typeName _x) isEqualTo "STRING") then + { + _x = [_x,1]; + }; + _unit addMagazines _x; + false; + } count _magazines; + + + // Add gun and attachments + if !(_weapon isEqualTo "") then + { + _muzzle = [_unit, _weapon, 0] call BIS_fnc_addWeapon; + + { + _unit addPrimaryWeaponItem _x; + false; + } count _weaponAttachments; + + _unit selectWeapon _weapon; + }; + + + // Add pistol and attachments + if !(_pistol isEqualTo "") then + { + _muzzle = [_unit, _pistol, 0] call BIS_fnc_addWeapon; + + { + _unit addPrimaryWeaponItem _x; + false; + } count _pistolAttachments; + }; + + // Add items + { + _unit addItem _x; + false; + } count _items; +}; + +if(_difficulty isEqualTo "random") then +{ + _difficulty = DMS_ai_skill_random call BIS_fnc_selectRandom; +}; + +_skillArray = missionNamespace getVariable [format["DMS_ai_skill_%1",_difficulty],[]]; + +{ + _unit setSkill [(_x select 0),(_x select 1)]; + false; +} count _skillArray; + +// Ground unit +_unit addEventHandler ["Killed",{[_this, "soldier"] call DMS_OnKill;}]; + +_unit enableAI "TARGET"; +_unit enableAI "AUTOTARGET"; +_unit enableAI "MOVE"; +_unit enableAI "ANIM"; +_unit enableAI "FSM"; + +_unit \ No newline at end of file