diff --git a/README.md b/README.md index 66af3f11..39563ce4 100644 --- a/README.md +++ b/README.md @@ -35,21 +35,24 @@ Add the class `cfgGradCivs` to your `description.ext`. Use the following attribu ## Attributes -Attribute | Default Value | Explanation ---------------------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------ -autoInit | 1 | Toggles on automatic initialization of module on missions start (0/1). Turn this off if you want to use functions to set civs properties first. -maxCivs | 60 | Maximum number of civs that can exist at any time. -spawnDistances | [1000,4500] | Minimum and maximum distance to players that civilians can spawn in. -debugMode | 0 | Toggles debug mode (0/1). -onSpawn | "" | Code to execute on civilian spawn. Passed parameters are: [civilian]. -onHeldUp | "" | Code to execute when civilian stops because a weapon is pointed at him. Passed parameters are: [civilian]. -exitOn | "" | Condition upon which grad-civs loops will stop. -clothes | [] | All classnames of clothes that civilians may wear. -faces | [] | All classnames of faces that civilians may have. -goggles | [] | All classnames of goggles that civilians may wear. -headgear | [] | All classnames of headgear that civilians may wear. -backpacks | [] | All classnames of backpacks that civilians may wear. -backpackProbability | 0.5 | Probability that a civilian will wear a backpack. +Attribute | Default Value | Explanation +-------------------------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------ +autoInit | 1 | Toggles on automatic initialization of module on missions start (0/1). Turn this off if you want to use functions to set civs properties first. +maxCivsOnFoot | 30 | Maximum number of civs on foot. +maxCivsInVehicles | 10 | Maximum number of civs in vehicles. +spawnDistancesOnFoot | [1000,4500] | Minimum and maximum distance to players that civilians on foot can spawn in. +spawnDistancesInVehicles | [1500,6000] | Minimum and maximum distance to players that civilians in vehicles can spawn in. +debugMode | 0 | Toggles debug mode (0/1). +onSpawn | "" | Code to execute on civilian spawn. Passed parameters are: [civilian]. +onHeldUp | "" | Code to execute when civilian stops because a weapon is pointed at him. Passed parameters are: [civilian]. +exitOn | "" | Condition upon which grad-civs loops will stop. +clothes | [] | All classnames of clothes that civilians may wear. +faces | [] | All classnames of faces that civilians may have. +goggles | [] | All classnames of goggles that civilians may wear. +headgear | [] | All classnames of headgear that civilians may wear. +backpacks | [] | All classnames of backpacks that civilians may wear. +vehicles | [] | All classnames of vehicles that civilians may drive. +backpackProbability | 0.5 | Probability that a civilian will wear a backpack. ## Example diff --git a/cfgFunctions.hpp b/cfgFunctions.hpp index 54755bfe..debb5589 100644 --- a/cfgFunctions.hpp +++ b/cfgFunctions.hpp @@ -51,11 +51,13 @@ class grad_civs { class spawn { file = MODULES_DIRECTORY\grad-civs\functions\spawn; - class addNewCivilian {}; + class spawnCivilian {}; class cleanup {}; class dressAndBehave {}; - class findSpawnSegment {}; + class findSpawnPosition {}; class getPlayerPositions {}; + class addToVehicle {}; class serverLoop {}; + class spawnVehicle {}; }; }; diff --git a/functions/behaviour/fn_taskPatrol.sqf b/functions/behaviour/fn_taskPatrol.sqf index dc0a7cb5..915ca1fd 100644 --- a/functions/behaviour/fn_taskPatrol.sqf +++ b/functions/behaviour/fn_taskPatrol.sqf @@ -12,7 +12,7 @@ #include "..\..\component.hpp" -params ["_group","_centerPosition","_radius","_count",["_timeout",[0,0,0]]]; +params ["_group","_centerPosition","_radius","_count",["_timeout",[0,0,0]],["_findPosOfInterest",false],["_findRoadPos",false],["_findWaterPos",false]]; private ["_waypoint","_position"]; private _group = if (typeName _group == "OBJECT") then {group _group} else {_group}; @@ -26,8 +26,8 @@ if !(local _group) exitWith {}; //create waypoints for [{_i=0}, {_i<_count}, {_i=_i+1}] do { - _searchPosition = [_centerPosition,[0,_radius],[0,360]] call grad_civs_fnc_findRandomPos; - _position = if (80 > random 100) then {[_searchPosition] call grad_civs_fnc_findPositionOfInterest} else {_searchPosition}; + _searchPosition = [_centerPosition,[0,_radius],[0,360],nil,_findWaterPos,_findRoadPos] call grad_civs_fnc_findRandomPos; + _position = if (_findPosOfInterest && {80 > random 100}) then {[_searchPosition] call grad_civs_fnc_findPositionOfInterest} else {_searchPosition}; _waypoint = _group addWaypoint [_position, 0]; _waypoint setWaypointType "MOVE"; diff --git a/functions/common/fn_findRandomPos.sqf b/functions/common/fn_findRandomPos.sqf index 391aaab2..c95af6b9 100644 --- a/functions/common/fn_findRandomPos.sqf +++ b/functions/common/fn_findRandomPos.sqf @@ -1,6 +1,6 @@ #include "..\..\component.hpp" -params ["_center", ["_radii", [0,15]], ["_angles", [0,360]], ["_vehicleType", "B_Soldier_F"], ["_findWaterPos",false]]; +params ["_center", ["_radii", [0,15]], ["_angles", [0,360]], ["_vehicleType", "B_Soldier_F"], ["_findWaterPos",false], ["_findRoadPos",false]]; private ["_pos"]; _radii params ["_minRad", "_maxRad"]; @@ -13,8 +13,13 @@ for [{private _i=0}, {_i<50}, {_i=_i+1}] do { _searchAngle = (random (_maxAngle - _minAngle)) + _minAngle; _searchPos = _center getPos [_searchDist, _searchAngle]; - _pos = if (_vehicleType != "") then {_searchPos findEmptyPosition [0,10,_vehicleType]} else {_searchPos}; - if (str _pos != "[]" && {(surfaceIsWater _pos) isEqualTo _findWaterPos}) exitWith {}; + if (_findRoadPos) then { + _nearRoads = _searchPos nearRoads 50; + _searchPos = if (count _nearRoads > 0) then {getPos (_nearRoads select 0)} else {[]}; + }; + + _pos = if (_vehicleType != "" && {count _searchPos > 0}) then {_searchPos findEmptyPosition [0,10,_vehicleType]} else {_searchPos}; + if (count _pos > 0 && {(surfaceIsWater _pos) isEqualTo _findWaterPos}) exitWith {}; }; if (str _pos == "[]") then { diff --git a/functions/debug/fn_mapMarkers.sqf b/functions/debug/fn_mapMarkers.sqf index 89f793a7..968f1b42 100644 --- a/functions/debug/fn_mapMarkers.sqf +++ b/functions/debug/fn_mapMarkers.sqf @@ -9,7 +9,7 @@ GRAD_CIVS_DEBUGMODE = _onOff; if (_onOff) then { GRAD_CIVS_DRAWUNITSEH = ((findDisplay 12) displayCtrl 51) ctrlAddEventHandler ["Draw",{ [_this select 0,"GRAD_CIVS_ONFOOTUNITS","iconMan"] call grad_civs_fnc_drawCivs; - [_this select 0,"GRAD_CIVS_INVEHICLEUNITS","iconCar"] call grad_civs_fnc_drawCivs; + [_this select 0,"GRAD_CIVS_INVEHICLESUNITS","iconCar"] call grad_civs_fnc_drawCivs; [_this select 0,"GRAD_CIVS_INAIRCRAFTUNITS","iconHelicopter"] call grad_civs_fnc_drawCivs; }]; } else { diff --git a/functions/debug/fn_showWhatTheyThink.sqf b/functions/debug/fn_showWhatTheyThink.sqf index 6a62595f..e202ad40 100644 --- a/functions/debug/fn_showWhatTheyThink.sqf +++ b/functions/debug/fn_showWhatTheyThink.sqf @@ -21,5 +21,5 @@ GRAD_CIVS_DEBUGMODE = _onOff; ]; }; _draw forEach (missionNamespace getVariable ["GRAD_CIVS_ONFOOTUNITS",[]]); - _draw forEach (missionNamespace getVariable ["GRAD_CIVS_INVEHICLEUNITS",[]]); + _draw forEach (missionNamespace getVariable ["GRAD_CIVS_INVEHICLESUNITS",[]]); } , 0, []] call CBA_fnc_addPerFrameHandler; diff --git a/functions/init/fn_initModule.sqf b/functions/init/fn_initModule.sqf index fe803af3..7153eede 100644 --- a/functions/init/fn_initModule.sqf +++ b/functions/init/fn_initModule.sqf @@ -12,22 +12,36 @@ if (isServer) then { if (isNil "GRAD_CIVS_FACES") then {missionNamespace setVariable ["GRAD_CIVS_FACES",[missionConfigFile >> "cfgGradCivs","faces",[]] call BIS_fnc_returnConfigEntry,true]}; if (isNil "GRAD_CIVS_GOGGLES") then {missionNamespace setVariable ["GRAD_CIVS_GOGGLES",[missionConfigFile >> "cfgGradCivs","goggles",[]] call BIS_fnc_returnConfigEntry,true]}; if (isNil "GRAD_CIVS_BACKPACKS") then {missionNamespace setVariable ["GRAD_CIVS_BACKPACKS",[missionConfigFile >> "cfgGradCivs","backpacks",[]] call BIS_fnc_returnConfigEntry,true]}; + if (isNil "GRAD_CIVS_VEHICLES") then {missionNamespace setVariable ["GRAD_CIVS_VEHICLES",[missionConfigFile >> "cfgGradCivs","vehicles",[]] call BIS_fnc_returnConfigEntry,true]}; + if (isNil "GRAD_CIVS_BACKPACKPROBABILITY") then {missionNamespace setVariable ["GRAD_CIVS_BACKPACKPROBABILITY",[missionConfigFile >> "cfgGradCivs","backpackProbability",0.5] call BIS_fnc_returnConfigEntry,true]}; + if (isNil "GRAD_CIVS_DEBUGMODE") then {missionNamespace setVariable ["GRAD_CIVS_DEBUGMODE",([missionConfigFile >> "cfgGradCivs","debugMode",0] call BIS_fnc_returnConfigEntry) == 1,false]}; - missionNamespace setVariable ["GRAD_CIVS_EXITON",compile ([missionConfigFile >> "cfgGradCivs","exitOn",""] call BIS_fnc_returnConfigEntry),true]; - missionNamespace setVariable ["GRAD_CIVS_MAXCOUNT",[missionConfigFile >> "cfgGradCivs","maxCivs",""] call BIS_fnc_returnConfigEntry,true]; + missionNamespace setVariable ["GRAD_CIVS_ENABLEDONFOOT",([missionConfigFile >> "cfgGradCivs","enableOnFoot",1] call BIS_fnc_returnConfigEntry) == 1]; + missionNamespace setVariable ["GRAD_CIVS_ENABLEDINVEHICLES",([missionConfigFile >> "cfgGradCivs","enableInVehicles",1] call BIS_fnc_returnConfigEntry) == 1]; + + missionNamespace setVariable ["GRAD_CIVS_MAXCIVSONFOOT",[missionConfigFile >> "cfgGradCivs","maxCivsOnFoot",30] call BIS_fnc_returnConfigEntry,true]; + missionNamespace setVariable ["GRAD_CIVS_MAXCIVSINVEHICLES",[missionConfigFile >> "cfgGradCivs","maxCivsInVehicles",10] call BIS_fnc_returnConfigEntry,true]; + missionNamespace setVariable ["GRAD_CIVS_EXITON",compile ([missionConfigFile >> "cfgGradCivs","exitOn",""] call BIS_fnc_returnConfigEntry),true]; missionNamespace setVariable ["GRAD_CIVS_ONSPAWN",compile ([missionConfigFile >> "cfgGradCivs","onSpawn",""] call BIS_fnc_returnConfigEntry),true]; missionNamespace setVariable ["GRAD_CIVS_ONHELDUP",compile ([missionConfigFile >> "cfgGradCivs","onHeldUp",""] call BIS_fnc_returnConfigEntry),true]; - _distances = [missionConfigFile >> "cfgGradCivs","spawnDistances",[1000,4500]] call BIS_fnc_returnConfigEntry; - missionNamespace setVariable ["GRAD_CIVS_SPAWNDISTANCEMIN",_distances select 0,true]; - missionNamespace setVariable ["GRAD_CIVS_SPAWNDISTANCEMAX",_distances select 1,true]; + _distances = [missionConfigFile >> "cfgGradCivs","spawnDistancesOnFoot",[1000,4500]] call BIS_fnc_returnConfigEntry; + missionNamespace setVariable ["GRAD_CIVS_SPAWNDISTANCEONFOOTMIN",_distances select 0,true]; + missionNamespace setVariable ["GRAD_CIVS_SPAWNDISTANCEONFOOTMAX",_distances select 1,true]; + + _distances = [missionConfigFile >> "cfgGradCivs","spawnDistancesInVehicles",[1500,6000]] call BIS_fnc_returnConfigEntry; + missionNamespace setVariable ["GRAD_CIVS_SPAWNDISTANCEINVEHICLESMIN",_distances select 0,true]; + missionNamespace setVariable ["GRAD_CIVS_SPAWNDISTANCEINVEHICLESMAX",_distances select 1,true]; GRAD_CIVS_ONFOOTCOUNT = 0; GRAD_CIVS_ONFOOTUNITS = []; + GRAD_CIVS_INVEHICLESCOUNT = 0; + GRAD_CIVS_INVEHICLESUNITS = []; + [] call grad_civs_fnc_serverLoop; }; @@ -37,6 +51,6 @@ if (hasInterface) then { [] call grad_civs_fnc_playerLoop; if (GRAD_CIVS_DEBUGMODE) then { [] call grad_civs_fnc_showWhatTheyThink; - [{!isNull (findDisplay 12)}, {[] call grad_civs_fnc_mapMarkers}, []] call CBA_fnc_waitUntilAndExecute; + [{!isNull (findDisplay 12)}, {[] call grad_civs_fnc_mapMarkers}, []] call CBA_fnc_waitUntilAndExecute; }; }; diff --git a/functions/spawn/fn_addNewCivilian.sqf b/functions/spawn/fn_addNewCivilian.sqf deleted file mode 100644 index 8c1bdd2b..00000000 --- a/functions/spawn/fn_addNewCivilian.sqf +++ /dev/null @@ -1,33 +0,0 @@ -#include "..\..\component.hpp" - -params ["_playerPositions"]; - -private _position = [ - _playerPositions, - GRAD_CIVS_SPAWNDISTANCEMIN, - GRAD_CIVS_SPAWNDISTANCEMAX, - GRAD_CIVS_ONFOOTUNITS -] call grad_civs_fnc_findSpawnSegment; - -if (_position isEqualTo [0,0,0]) exitWith {}; - -INFO_1("Position: %1", _position); - -private _group = createGroup [civilian, true]; -private _unit = _group createUnit ["C_man_1", _position, [], 0, "NONE"]; - -_unit disableAI "FSM"; -_unit setBehaviour "CARELESS"; - -[_unit] call grad_civs_fnc_dressAndBehave; -_unit enableDynamicSimulation true; - -[_unit, _position, 400 - (random 300), [3,6], [0,2,10]] call grad_civs_fnc_taskPatrol; - -GRAD_CIVS_ONFOOTCOUNT = GRAD_CIVS_ONFOOTCOUNT + 1; -GRAD_CIVS_ONFOOTUNITS = GRAD_CIVS_ONFOOTUNITS + [_unit]; -if (GRAD_CIVS_DEBUGMODE) then {publicVariable "GRAD_CIVS_ONFOOTUNITS"; publicVariable "GRAD_CIVS_ONFOOTCOUNT"}; - -INFO_1("added civilian on foot, now %1", GRAD_CIVS_ONFOOTCOUNT); - -[_unit] call GRAD_CIVS_ONSPAWN; diff --git a/functions/spawn/fn_addToVehicle.sqf b/functions/spawn/fn_addToVehicle.sqf new file mode 100644 index 00000000..e4238915 --- /dev/null +++ b/functions/spawn/fn_addToVehicle.sqf @@ -0,0 +1,3 @@ +#include "..\..\component.hpp" + +params ["_grp"]; diff --git a/functions/spawn/fn_cleanup.sqf b/functions/spawn/fn_cleanup.sqf index 481b5e25..c6282a6d 100644 --- a/functions/spawn/fn_cleanup.sqf +++ b/functions/spawn/fn_cleanup.sqf @@ -1,15 +1,23 @@ #include "..\..\component.hpp" params ["_playerPositions","_mode"]; -private ["_cleanupDistance","_civsArray","_civsArrayVar","_idVar"]; +private ["_cleanupDistance","_civsArray","_civsArrayVar","_counterVar","_idVar"]; switch (_mode) do { case ("onfoot"): { - _cleanupDistance = GRAD_CIVS_SPAWNDISTANCEMAX * 1,2; + _cleanupDistance = GRAD_CIVS_SPAWNDISTANCEONFOOTMAX * 1.2; _civsArray = GRAD_CIVS_ONFOOTUNITS; _civsArrayVar = "GRAD_CIVS_ONFOOTUNITS"; + _counterVar = "GRAD_CIVS_ONFOOTCOUNT"; _idVar = "GRAD_CIVS_CLEANUPID_ONFOOT"; }; + case ("invehicles"): { + _cleanupDistance = GRAD_CIVS_SPAWNDISTANCEINVEHICLESMAX * 1.5; + _civsArray = GRAD_CIVS_INVEHICLESUNITS; + _civsArrayVar = "GRAD_CIVS_INVEHICLESUNITS"; + _counterVar = "GRAD_CIVS_INVEHICLESCOUNT"; + _idVar = "GRAD_CIVS_CLEANUPID_INVEHICLES"; + }; }; if (count _civsArray == 0) exitWith {}; @@ -23,8 +31,8 @@ private _delete = ({_civ distance _x < _cleanupDistance} count _playerPositions) if (_delete) then { _civsArray deleteAt _id; - GRAD_CIVS_ONFOOTCOUNT = GRAD_CIVS_ONFOOTCOUNT - 1; - if (GRAD_CIVS_DEBUGMODE) then {publicVariable _civsArrayVar; publicVariable "GRAD_CIVS_ONFOOTCOUNT"}; + missionNamespace setVariable [_counterVar,(missionNamespace getVariable [_counterVar,0])-1]; + if (GRAD_CIVS_DEBUGMODE) then {publicVariable _civsArrayVar; publicVariable _counterVar}; - deleteVehicle _civ; + if (vehicle _civ != _civ) then {deleteVehicle vehicle _civ} else {deleteVehicle _civ}; }; diff --git a/functions/spawn/fn_findSpawnSegment.sqf b/functions/spawn/fn_findSpawnPosition.sqf similarity index 100% rename from functions/spawn/fn_findSpawnSegment.sqf rename to functions/spawn/fn_findSpawnPosition.sqf diff --git a/functions/spawn/fn_serverLoop.sqf b/functions/spawn/fn_serverLoop.sqf index 4d0dc2ca..97d69b6f 100644 --- a/functions/spawn/fn_serverLoop.sqf +++ b/functions/spawn/fn_serverLoop.sqf @@ -1,15 +1,60 @@ #include "..\..\component.hpp" -grad_civs_mainLoop = [{ +if (!isServer) exitWith {}; + +private _mainLoop = { params ["_args", "_handle"]; - if (call GRAD_CIVS_EXITON) exitWith { [_handle] call CBA_fnc_removePerFrameHandler; }; + if (call GRAD_CIVS_EXITON) exitWith {[_handle] call CBA_fnc_removePerFrameHandler}; _playerPositions = [] call grad_civs_fnc_getPlayerPositions; - if (GRAD_CIVS_ONFOOTCOUNT < GRAD_CIVS_MAXCOUNT) then { - [_playerPositions] call grad_civs_fnc_addNewCivilian; + if (GRAD_CIVS_ENABLEDONFOOT) then { + if (GRAD_CIVS_ONFOOTCOUNT < GRAD_CIVS_MAXCIVSONFOOT) then { + _pos = [ + _playerPositions, + GRAD_CIVS_SPAWNDISTANCEONFOOTMIN, + GRAD_CIVS_SPAWNDISTANCEONFOOTMAX, + GRAD_CIVS_ONFOOTUNITS + ] call grad_civs_fnc_findSpawnPosition; + + if (_pos isEqualTo [0,0,0]) exitWith {}; + + _unit = [_pos] call grad_civs_fnc_spawnCivilian; + + GRAD_CIVS_ONFOOTCOUNT = GRAD_CIVS_ONFOOTCOUNT + 1; + GRAD_CIVS_ONFOOTUNITS pushBack _unit; + if (GRAD_CIVS_DEBUGMODE) then {publicVariable "GRAD_CIVS_ONFOOTUNITS"; publicVariable "GRAD_CIVS_ONFOOTCOUNT"}; + + [_unit,_pos,400 - (random 300),[3,6],[0,2,10],true] call grad_civs_fnc_taskPatrol; + }; + [_playerPositions,"onfoot"] call grad_civs_fnc_cleanup; + }; + + if (GRAD_CIVS_ENABLEDINVEHICLES) then { + if (GRAD_CIVS_INVEHICLESCOUNT < GRAD_CIVS_MAXCIVSINVEHICLES) then { + _pos = [ + _playerPositions, + GRAD_CIVS_SPAWNDISTANCEINVEHICLESMIN, + GRAD_CIVS_SPAWNDISTANCEINVEHICLESMAX, + GRAD_CIVS_INVEHICLESUNITS + ] call grad_civs_fnc_findSpawnPosition; + + if (_pos isEqualTo [0,0,0]) exitWith {}; + + _veh = [_pos,selectRandom GRAD_CIVS_VEHICLES] call grad_civs_fnc_spawnVehicle; + _unit = [_pos] call grad_civs_fnc_spawnCivilian; + _unit assignAsDriver _veh; + _unit moveinAny _veh; + (group _unit) setSpeedMode "NORMAL"; + [_unit,_pos,2500,3,[0,0,0],false,true] call grad_civs_fnc_taskPatrol; + + GRAD_CIVS_INVEHICLESCOUNT = GRAD_CIVS_INVEHICLESCOUNT + 1; + GRAD_CIVS_INVEHICLESUNITS pushBack _unit; + if (GRAD_CIVS_DEBUGMODE) then {publicVariable "GRAD_CIVS_INVEHICLESUNITS"; publicVariable "GRAD_CIVS_INVEHICLESCOUNT"}; + }; + [_playerPositions,"invehicles"] call grad_civs_fnc_cleanup; }; - [_playerPositions,"onfoot"] call grad_civs_fnc_cleanup; +}; -},10,[]] call CBA_fnc_addPerFrameHandler; +grad_civs_mainLoop = [_mainLoop,10,[]] call CBA_fnc_addPerFrameHandler; diff --git a/functions/spawn/fn_spawnCivilian.sqf b/functions/spawn/fn_spawnCivilian.sqf new file mode 100644 index 00000000..d58a86f3 --- /dev/null +++ b/functions/spawn/fn_spawnCivilian.sqf @@ -0,0 +1,18 @@ +#include "..\..\component.hpp" + +params ["_pos"]; + +INFO_1("POS: %1",_pos); + +private _group = createGroup [civilian, true]; +private _unit = _group createUnit ["C_man_1", _pos, [], 0, "NONE"]; + +_unit disableAI "FSM"; +_unit setBehaviour "CARELESS"; + +[_unit] call grad_civs_fnc_dressAndBehave; +_unit enableDynamicSimulation true; + +[_unit] call GRAD_CIVS_ONSPAWN; + +_unit diff --git a/functions/spawn/fn_spawnVehicle.sqf b/functions/spawn/fn_spawnVehicle.sqf new file mode 100644 index 00000000..0b01eaa8 --- /dev/null +++ b/functions/spawn/fn_spawnVehicle.sqf @@ -0,0 +1,12 @@ +#include "..\..\component.hpp" + +params ["_pos","_type"]; + +private _veh = _type createVehicle _pos; + +clearBackpackCargo _veh; +clearWeaponCargoGlobal _veh; +clearItemCargoGlobal _veh; +clearMagazineCargoGlobal _veh; + +_veh