diff --git a/Engima/Traffic/Common/Common.sqf b/Engima/Traffic/Common/Common.sqf new file mode 100644 index 00000000..7f388f08 --- /dev/null +++ b/Engima/Traffic/Common/Common.sqf @@ -0,0 +1,94 @@ +/* + * Summary: Gets a parameter value in a paired list on format ["KEY", value]. + * Arguments: + * _params: List of paired value parameters. + * _key: String with key to look for. + * _default: Value that is returned if key was not found. + * Returns: Value associated with key. ObjNull if no key was found. + */ +ENGIMA_TRAFFIC_GetParamValue = { + private ["_params", "_key"]; + private ["_value"]; + + _params = _this select 0; + _key = _this select 1; + _value = if (count _this > 2) then { _this select 2 } else { objNull }; + + { + if (_x select 0 == _key) then { + _value = _x select 1; + }; + } foreach (_params); + + _value +}; + +/* + * Summary: Checks if a marker exists. + * Arguments: + * _marker: Marker name of marker to test. + * Returns: true if marker exists, else false. + */ +ENGIMA_TRAFFIC_MarkerExists = { + private ["_exists", "_marker"]; + + _marker = _this select 0; + + _exists = false; + if (((getMarkerPos _marker) select 0) != 0 || ((getMarkerPos _marker) select 1 != 0)) then { + _exists = true; + }; + _exists +}; + +/* + * Summary: Checks if a position is inside a marker. + * Remarks: Marker can be of shape "RECTANGLE" or "ELLIPSE" and at any angle. + * Arguments: + * _markerName: Name of current marker. + * _pos: Position to test. + * Returns: true if position is inside marker. Else false. + */ +ENGIMA_TRAFFIC_PositionIsInsideMarker = { + private ["_markerName", "_pos"]; + private ["_isInside", "_px", "_py", "_mpx", "_mpy", "_msx", "_msy", "_ma", "_xmin", "_xmax", "_ymin", "_ymax", "_rpx", "_rpy", "_res"]; + + _pos = _this select 0; + _markerName = _this select 1; + + _px = _pos select 0; + _py = _pos select 1; + _mpx = (getMarkerPos _markerName) select 0; + _mpy = (getMarkerPos _markerName) select 1; + _msx = (getMarkerSize _markerName) select 0; + _msy = (getMarkerSize _markerName) select 1; + _ma = -(markerDir _markerName); + + _xmin = _mpx - _msx; + _xmax = _mpx + _msx; + _ymin = _mpy - _msy; + _ymax = _mpy + _msy; + + //Now, rotate point to investigate around markers center in order to check against a nonrotated marker + _rpx = ( (_px - _mpx) * cos(_ma) ) + ( (_py - _mpy) * sin(_ma) ) + _mpx; + _rpy = (-(_px - _mpx) * sin(_ma) ) + ( (_py - _mpy) * cos(_ma) ) + _mpy; + + _isInside = false; + + if (markerShape _markerName == "RECTANGLE") then { + if (((_rpx > _xmin) && (_rpx < _xmax)) && ((_rpy > _ymin) && (_rpy < _ymax))) then + { + _isInside = true; + }; + }; + + if (markerShape _markerName == "ELLIPSE") then { + _res = (((_rpx-_mpx)^2)/(_msx^2)) + (((_rpy-_mpy)^2)/(_msy^2)); + if ( _res < 1 ) then + { + _isInside = true; + }; + }; + + _isInside +}; diff --git a/Engima/Traffic/Common/Debug.sqf b/Engima/Traffic/Common/Debug.sqf new file mode 100644 index 00000000..67fd9280 --- /dev/null +++ b/Engima/Traffic/Common/Debug.sqf @@ -0,0 +1,179 @@ +ENGIMA_TRAFFIC_SilentDebugMode = false; + +ENGIMA_TRAFFIC_DebugTextEventArgs = []; // Empty +ENGIMA_TRAFFIC_DebugMarkerEventArgs = []; // [name, position, size, direction, shape ("RECTANGLE" or "ELLIPSE"), markerColor, markerText (optional)] or alternatively [name, position, type, markerColor (optional), markerText (optional)] +ENGIMA_TRAFFIC_DeleteDebugMarkerEventArgs = []; // [name] + +"ENGIMA_TRAFFIC_DebugTextEventArgs" addPublicVariableEventHandler { + ENGIMA_TRAFFIC_DebugTextEventArgs call ENGIMA_TRAFFIC_ShowDebugTextLocal; +}; + +"ENGIMA_TRAFFIC_DebugMarkerEventArgs" addPublicVariableEventHandler { + ENGIMA_TRAFFIC_DebugMarkerEventArgs call ENGIMA_TRAFFIC_SetDebugMarkerLocal; +}; + +"ENGIMA_TRAFFIC_DeleteDebugMarkerEventArgs" addPublicVariableEventHandler { + ENGIMA_TRAFFIC_DeleteDebugMarkerEventArgs call ENGIMA_TRAFFIC_DeleteDebugMarkerLocal; +}; + +/* + * Summary: Shows debug text on all clients. + * Remarks: + * if global variable "dre_var_CL_SilentDebugMode" is set to true, debug text will only be written to RTF-file and not shown on screen. + * Arguments: + * _text: Debug text. + */ +ENGIMA_TRAFFIC_ShowDebugTextAllClients = { + ENGIMA_TRAFFIC_DebugTextEventArgs = _this; + publicVariable "ENGIMA_TRAFFIC_DebugTextEventArgs"; + ENGIMA_TRAFFIC_DebugTextEventArgs call ENGIMA_TRAFFIC_ShowDebugTextLocal; +}; + +/* + * Summary: Shows debug text on local client. + * Remarks: + * if global variable "dre_var_CL_SilentDebugMode" is set to true, debug text will only be written to RTF-file and not shown on screen. + * Arguments: + * _text: Debug text. + */ +ENGIMA_TRAFFIC_ShowDebugTextLocal = { + private ["_minutes", "_seconds"]; + + if (!isNull player) then { + if (!ENGIMA_TRAFFIC_SilentDebugMode) then { + player sideChat (_this select 0); + }; + }; + + _minutes = floor (time / 60); + _seconds = floor (time - (_minutes * 60)); + diag_log ((str _minutes + ":" + str _seconds) + " Debug: " + (_this select 0)); +}; + +/* + * Summary: Shows debug marker on local client. + * Remarks: + * if global variable "dre_var_CL_SilentDebugMode" is set to true, debug marker will not shown. + * Arguments alternative #1 (Marker representing an area): + * _markerName: Marker's name. (must be global unique). + * _position: Marker's position. + * _size: Marker's size on array format [x, y]. + * _direction: Marker's direction. + * _shape: "RECTANGLE" or "ELLIPSE". + * _markerColor: Marker's color ("Default", "ColorRed", "ColorYellow" etc.). + * [_markerText]: Optional. Marker's text. + * Arguments alternative #2 (Marker representing an icon). + * _markerName: Marker's name. (must be global unique). + * _position: Marker's position. + * _type: Markers icon type (applies to icons in cfgIcons, like "Warning", "Dot" etc.). + * [_markerColor]: Optional. Marker's color ("Default", "ColorRed", "ColorYellow" etc.). + * [_markerText]. Optional. Marker's text. + */ +ENGIMA_TRAFFIC_SetDebugMarkerLocal = { + private ["_markerName", "_position", "_size", "_direction", "_type", "_shape", "_markerColor", "_markerText"]; + private ["_marker"]; + + if (!isNull player) then { + if (!ENGIMA_TRAFFIC_SilentDebugMode) then { + _markerName = _this select 0; + _position = _this select 1; + _markerColor = "Default"; + _markerText = ""; + + if (count _this == 6) then { + _size = _this select 2; + _direction = _this select 3; + _shape = _this select 4; + _markerColor = _this select 5; + }; + if (count _this == 7) then { + _size = _this select 2; + _direction = _this select 3; + _shape = _this select 4; + _markerColor = _this select 5; + _markerText = _this select 6; + }; + if (count _this == 3) then { + _type = _this select 2; + _shape = "ICON"; + }; + if (count _this == 4) then { + _type = _this select 2; + _shape = "ICON"; + _markerColor = _this select 3; + }; + if (count _this == 5) then { + _type = _this select 2; + _shape = "ICON"; + _markerColor = _this select 3; + _markerText = _this select 4; + }; + + // Delete old marker + if ([_markerName] call ENGIMA_TRAFFIC_MarkerExists) then { + deleteMarkerLocal _markerName; + }; + + // Set new marker + _marker = createMarkerLocal [_markerName, _position]; + _marker setMarkerShapeLocal _shape; + _marker setMarkerColorLocal _markerColor; + _marker setMarkerTextLocal _markerText; + + if (count _this == 6 || count _this == 7) then { + _marker setMarkerSizeLocal _size; + _marker setMarkerDirLocal _direction; + }; + if (count _this == 3 || count _this == 4 || count _this == 5) then { + _marker setMarkerTypeLocal _type; + }; + }; + }; +}; + +/* + * Summary: Shows debug marker on all clients. + * Remarks: + * if global variable "dre_var_CL_SilentDebugMode" is set to true, debug marker will not shown. + * Arguments alternative #1 (Marker representing an area): + * _markerName: Marker's name. (must be global unique). + * _position: Marker's position. + * _size: Marker's size on array format [x, y]. + * _direction: Marker's direction. + * _shape: "RECTANGLE" or "ELLIPSE". + * _markerColor: Marker's color ("Default", "ColorRed", "ColorYellow" etc.). + * [_markerText]: Optional. Marker's text. + * Arguments alternative #2 (Marker representing an icon). + * _markerName: Marker's name. (must be global unique). + * _position: Marker's position. + * _type: Markers icon type (applies to icons in cfgIcons, like "Warning", "Dot" etc.). + * [_markerColor]: Optional. Marker's color ("Default", "ColorRed", "ColorYellow" etc.). + * [_markerText]. Optional. Marker's text. + */ +ENGIMA_TRAFFIC_SetDebugMarkerAllClients = { + ENGIMA_TRAFFIC_DebugMarkerEventArgs = _this; + publicVariable "ENGIMA_TRAFFIC_DebugMarkerEventArgs"; + ENGIMA_TRAFFIC_DebugMarkerEventArgs call ENGIMA_TRAFFIC_SetDebugMarkerLocal; +}; + +/* + * Summary: Deletes a debug marker on local client. + * Arguments: + * _markerName: Name of marker to delete. + */ +ENGIMA_TRAFFIC_DeleteDebugMarkerLocal = { + private ["_markerName"]; + _markerName = _this select 0; + deleteMarkerLocal _markerName; +}; + +/* + * Summary: Deletes a debug marker on all clients. + * Arguments: + * _markerName: Name of marker to delete. + */ +ENGIMA_TRAFFIC_DeleteDebugMarkerAllClients = { + ENGIMA_TRAFFIC_DeleteDebugMarkerEventArgs = _this; + publicVariable "ENGIMA_TRAFFIC_DeleteDebugMarkerEventArgs"; + ENGIMA_TRAFFIC_DeleteDebugMarkerEventArgs call ENGIMA_TRAFFIC_DeleteDebugMarkerLocal; +}; diff --git a/Engima/Traffic/ConfigAndStart.sqf b/Engima/Traffic/ConfigAndStart.sqf new file mode 100644 index 00000000..feabca6f --- /dev/null +++ b/Engima/Traffic/ConfigAndStart.sqf @@ -0,0 +1,76 @@ +/* + * This file contains parameters to config and function call to start an instance of + * traffic in the mission. The file is edited by the mission developer. + * + * See file Engima\Traffic\Documentation.txt for documentation and a full reference of + * how to customize and use Engima's Traffic. + */ + + private ["_parameters"]; + +// Set traffic parameters. +_parameters = [ + ["SIDE", civilian], + ["VEHICLES", [ + "C_Offroad_01_F", + "C_Offroad_01_repair_F", + "C_Hatchback_01_F", + "C_Hatchback_01_sport_F", + "C_SUV_01_F", + "C_Van_01_transport_F", + "C_Van_01_box_F", + "C_Van_01_fuel_F", + + + "RDS_Gaz24_Civ_01", + "RDS_Gaz24_Civ_02", + "RDS_Gaz24_Civ_03", + "RDS_Gaz24_Civ_01", + "RDS_Gaz24_Civ_02", + "RDS_Gaz24_Civ_03", + "RDS_Gaz24_Civ_01", + "RDS_Gaz24_Civ_02", + "RDS_Gaz24_Civ_03", + + "RDS_Ikarus_Civ_01", + "RDS_Ikarus_Civ_02", + "RDS_Ikarus_Civ_02", + + "RDS_S1203_Civ_01", + "RDS_S1203_Civ_02", + "RDS_S1203_Civ_03", + + "RDS_Octavia_Civ_01", + + "RDS_Lada_Civ_01", + "RDS_Lada_Civ_02", + "RDS_Lada_Civ_03", + "RDS_Lada_Civ_04", + "RDS_Lada_Civ_05", + "RDS_Lada_Civ_01", + "RDS_Lada_Civ_02", + "RDS_Lada_Civ_03", + "RDS_Lada_Civ_04", + + "RDS_Zetor6945_Base", + + + "RHS_Ural_Civ_01", + "RHS_Ural_Civ_02", + "RHS_Ural_Civ_03", + "RHS_Ural_Open_Civ_01", + "RHS_Ural_Open_Civ_02", + "RHS_Ural_Open_Civ_03", + "RHS_UAZ_open_chdkz", + "RHS_UAZ_chdkz" + ]], + ["VEHICLES_COUNT", 10], + ["MIN_SPAWN_DISTANCE", 1500], + ["MAX_SPAWN_DISTANCE", 2500], + ["MIN_SKILL", 0.1], + ["MAX_SKILL", 0.2], + ["DEBUG", false] +]; + +// Start an instance of the traffic +_parameters spawn ENGIMA_TRAFFIC_StartTraffic; diff --git a/Engima/Traffic/Custom_GruppeAdler/createVehicle.sqf b/Engima/Traffic/Custom_GruppeAdler/createVehicle.sqf new file mode 100644 index 00000000..65014d4a --- /dev/null +++ b/Engima/Traffic/Custom_GruppeAdler/createVehicle.sqf @@ -0,0 +1,64 @@ +createTakistaniVehicle = { + _pos = _this select 0; + _vehicleType = _this select 1; + _side = _this select 2; + + _crewCount = floor (random 2); + + + _createDriver = { + _grp0 = _this select 0; + _car0 = _this select 1; + + _crewDriver = _grp0 createUnit ["C_man_1", _pos, [], 0, "CARGO"]; + + [_crewDriver] call randomCivilian; // civilian loadout + + _crewDriver assignAsDriver _car0; + _crewDriver moveInDriver _car0; + // hintsilent format ["ordered %1 to enter %2", _crewDriver,_car0]; + }; + + _createCargo = { + _grp1 = _this select 0; + _car1 = _this select 1; + + _crewCargo = _grp1 createUnit ["C_man_1", _pos, [], 0, "CARGO"]; + + [_crewCargo] call randomCivilian; // civilian loadout + + _crewCargo assignAsCargo _car1; + _crewCargo moveInCargo _car1; + }; + + _veh = createVehicle [_vehicleType, _pos, [], 0, "NONE"]; + waitUntil {!isNull _veh}; + if ((random 10) > 1) then { + _veh setVehicleLock "LOCKEDPLAYER"; + }; + + _group = createGroup _side; + + + [_group,_veh] call _createDriver; + + if (_vehicleType == "RDS_Ikarus_Civ_01" || _vehicleType == "RDS_Ikarus_Civ_02") exitWith { + + _crewCount = floor (random 15); + + for [{_i=0}, {_i<_crewCount}, {_i=_i+1}] do { + [_group,_veh] call _createCargo; + }; + }; + + + if (_crewCount > 0) then { + for [{_i=0}, {_i<_crewCount}, {_i=_i+1}] do { + [_group,_veh] call _createCargo; + }; + }; + + + [_veh,_group] + +}; \ No newline at end of file diff --git a/Engima/Traffic/Custom_GruppeAdler/randomCivilian.sqf b/Engima/Traffic/Custom_GruppeAdler/randomCivilian.sqf new file mode 100644 index 00000000..15099b6b --- /dev/null +++ b/Engima/Traffic/Custom_GruppeAdler/randomCivilian.sqf @@ -0,0 +1,102 @@ +/* + civ units made from rhs or rds +*/ + +randomCivilian = { +_unit = _this select 0; + +_rds_rhs_civilian = [ +"rds_schoolteacher", +"rds_Functionary1", +"rds_Functionary2", +"rds_doctor", +"rds_uniform_assistant", +"rds_uniform_Worker1", +"rds_uniform_Worker2", +"rds_uniform_Worker3", +"rds_uniform_Worker4", +"rds_uniform_Woodlander1", +"rds_uniform_Woodlander2", +"rds_uniform_Woodlander3", +"rds_uniform_Woodlander4", +"rds_uniform_Villager1", +"rds_uniform_Villager2", +"rds_uniform_Villager3", +"rds_uniform_Villager4", +"rds_uniform_Profiteer1", +"rds_uniform_Profiteer2", +"rds_uniform_Profiteer3", +"rds_uniform_Profiteer4", +"rds_uniform_citizen1", +"rds_uniform_citizen2", +"rds_uniform_citizen3", +"rds_uniform_citizen4" +] call BIS_fnc_selectRandom; + +_rhsHeadGear = [ +"rds_Villager_cap1", +"rds_Villager_cap2", +"rds_Villager_cap3", +"rds_Villager_cap4", +"rds_worker_cap1", +"rds_worker_cap2", +"rds_worker_cap3", +"rds_worker_cap4", +"rds_Profiteer_cap1", +"rds_Profiteer_cap2", +"rds_Profiteer_cap3", +"rds_Profiteer_cap4", +"rhs_beanie_green", +"rhs_beanie_green" +] call BIS_fnc_selectRandom; + +_taliFaces = [ +"PersianHead_A3_01", +"PersianHead_A3_02", +"PersianHead_A3_03", +"PersianHead_A3_01", +"PersianHead_A3_02", +"PersianHead_A3_03", +"PersianHead_A3_01", +"PersianHead_A3_02", +"PersianHead_A3_03", +"WhiteHead_08", +"WhiteHead_16", +"GreekHead_A3_01", +"GreekHead_A3_02", +"GreekHead_A3_03", +"GreekHead_A3_04" +] call BIS_fnc_selectRandom; + + + + +_stripHim = { + _it = _this select 0; + removeAllWeapons _it; + removeAllItems _it; + removeAllAssignedItems _it; + removeUniform _it; + removeVest _it; + removeBackpack _it; + removeHeadgear _it; + removeGoggles _it; +}; + +_reclotheHim = { + _guy = _this select 0; + _guy forceAddUniform _rds_rhs_civilian; + if (random 2 > 1) then { + _guy addHeadgear _rhsHeadGear; + }; + + [[_guy,_taliFaces], "setCustomFace"] call BIS_fnc_MP; + + +}; + +[_unit] call _stripHim; +sleep 0.1; +[_unit] call _reclotheHim; + +}; \ No newline at end of file diff --git a/Engima/Traffic/Documentation.txt b/Engima/Traffic/Documentation.txt new file mode 100644 index 00000000..feba680f --- /dev/null +++ b/Engima/Traffic/Documentation.txt @@ -0,0 +1,104 @@ +--- ENGIMA'S TRAFFIC (VER 1.30) --- + +Engima's Traffic is a set of scripts that adds traffic to an Arma 3 mission. + +Vehicles of different types are spawned in out of sight for the player(s). They get a waypoint to a random road segment +on the map, but are removed at a certain distance from the nearest player. + +Script can run different isntances of traffic, with different customized behaviors, simultaneously. For example, you +can run one script that puts a lot of civilians on the entire map, and one more that simultaneously control a few enemy armored +vehicles in one area and friendly vehicles in another (see USING MORE THAN ONE INSTANCE below). + +Script works in singleplayer, multiplayer, hosted, dedicated for JIPs, and on any map (at least official if it has roads). + + +--- CUSTOMIZATION --- + +The script can be customized for different behaviors. Customize a script by editing the startup parameters. The startup +parameters list is an array of key value pairs. A key value pair is a small array where the key object is a string +with the name of the parameter setting and the value object is the actual value. + +Here is the simplest example that starts the traffic script with all default parameters (civilian traffic). This code are to +be put in Engima\Traffic\ConfigAndStart.sqf. + +[] spawn ENGIMA_TRAFFIC_StartTraffic; + +Here is an example that uses all parameters and first saves them in a variable named "_parameters". The function call (or spawn) +that starts the traffic is beneath. This code are to be put in Engima\Traffic\ConfigAndStart.sqf. + +// Set traffic parameters. +_parameters = [ + ["SIDE", civilian], + ["VEHICLES", ["C_Offroad_01_F", "C_Offroad_01_repair_F", "C_Quadbike_01_F", "C_Hatchback_01_F", "C_Hatchback_01_sport_F", "C_SUV_01_F", "C_Van_01_transport_F", "C_Van_01_box_F", "C_Van_01_fuel_F"]], + ["VEHICLES_COUNT", 10], + ["MIN_SPAWN_DISTANCE", 800], + ["MAX_SPAWN_DISTANCE", 1200], + ["MIN_SKILL", 0.4], + ["MAX_SKILL", 0.6], + ["AREA_MARKER", "EnemyMarker1"], + ["HIDE_AREA_MARKER", true], + ["ON_SPAWN_CALLBACK", { hint ("Vehicle of type " + typeOf (_this select 0) + " created!")], + ["ON_REMOVE_CALLBACK", { hint "Vehicle of type " + typename _this + " removed!"; }], + ["DEBUG", true] +]; + +// Start an instance of the traffic +_parameters spawn ENGIMA_TRAFFIC_StartTraffic; + +Here is a complete list of the parameters and what they do: + +* SIDE (Side): Which side the spawned vehicles will be. Can be east, west, independent or civilian. + +* VEHICLES (Array): Array of vehicle classes that may be spawned. If you want to see more of one vehicle than another, + then have it occur a couple of more often in the array. The following example will spawn traffic where 75% of vehicles + are quadbikes and 25% is transports: + Example: ["C_Quadbike_01_F", "C_Quadbike_01_F", "C_Quadbike_01_F", "C_Van_01_transport_F"] + +* VEHICLES_COUNT (Number): Number of vehicles that exists on the map for the current traffic instance. + Example: If VEHICLES_COUNT is set to 10 and MAX_SPAWN_DISTANCE is set to 1000, then there will be 10 vehicles on an area + of 3142 square meters (1000 * pi). + +* MIN_SPAWN_DISTANCE (Number): Minimum spawn distance in meters from nearest human player on the map. Should be at least 100 + meters less than MAX_SPAWN_DISTANCE. + Example: 800 + +* MAX_SPAWN_DISTANCE (Number): Maximum spawn distance in meters from nearest player on the map. Vehicles beyond this + distance will be removed. Should be at least 100 meters greater than MIN_SPAWN_DISTANCE. + Example: 1200 + +* MIN_SKILL (Number): Vehicle crew's minimum skill. Must be between 0 and 1 and less than or equal to MAX_SKILL. Actual + skill of each spawned vehicle (and crew) will be a random number between MIN_SKILL and MAX_SKILL. + Example: 0.4 + +* MAX_SKILL (Number): Vehicle crew's maximum skill. Must be between 0 and 1 and greater than or equal to MIN_SKILL. Actual + skill of each spawned vehicle (and crew) will be a random number between MIN_SKILL and MAX_SKILL. + Example: 0.6 + +* AREA_MARKER (String): Name of a marker that sets bounds for the traffic. The marker needs to be of shape rectancle or + ellipse (not icon for obvious reasons), and it needs to contains road segments. All vehicles for the current traffic + will spawn inside this area, and all waypoints set to these vehicles will also be inside the area. However, it is Arma + that routes the vehicle to the destination, and so it can come to decide to use roads that are outside of the marker. Be + aware of this when you are planning the marker positions. Default value is an empty string ("") which means "the entire + map". + +* HIDE_AREA_MARKER (Boolean): Wether the area marker should be hidden or not. If true then the marker will be hidden on + the map for the players, otherwise it will be visible. Default value is true. + +* ON_SPAWN_CALLBACK (Code): Code that is executed when a vehicle has spawned. Parameter _this is an array: 0: created + vehicle (Object), 1: all crew (Array of Objects), 2: vehicle's group (Group). Default value is {}. + Example: { hint ("Vehicle of type " + typeOf (_this select 0) + " created!") + +* ON_REMOVE_CALLBACK (Code): Code that is executed just before a vehicle is removed. Vehicle is sent in as a parameter _this. + Default value is {}. + Example: { hint "Vehicle of type " + typename _this + " removed!"; } + +* DEBUG (Boolean): Whether script is running in debug mode or not. In debug mode all vehicles are marked as dots on the map. + Can be true or false. Default value is false. + + +- USING MORE THAN ONE INSTANCE - + +To excecute more instances of the script simultaneously, copy the parameters and the start spawn command in +Engima\Traffic\ConfigAndStart.sqf and adding them at bottom of the ConfigAndStart.sqf. It is important that all calls to +ENGIMA_TRAFFIC_startTraffic is made within two seconds. Otherwise the map's road segments will not be initialzied as +needed. diff --git a/Engima/Traffic/Init.sqf b/Engima/Traffic/Init.sqf new file mode 100644 index 00000000..106c72b3 --- /dev/null +++ b/Engima/Traffic/Init.sqf @@ -0,0 +1,27 @@ +call compile preprocessFileLineNumbers "Engima\Traffic\Common\Common.sqf"; +call compile preprocessFileLineNumbers "Engima\Traffic\Common\Debug.sqf"; + +ENGIMA_TRAFFIC_instanceIndex = -1; +ENGIMA_TRAFFIC_areaMarkerNames = []; +ENGIMA_TRAFFIC_roadSegments = []; +ENGIMA_TRAFFIC_edgeTopLeftRoads = []; +ENGIMA_TRAFFIC_edgeTopRightRoads = []; +ENGIMA_TRAFFIC_edgeBottomRightRoads = []; +ENGIMA_TRAFFIC_edgeBottomLeftRoads = []; +ENGIMA_TRAFFIC_edgeRoadsUseful = []; + +if (isServer) then { + call compile preprocessFileLineNumbers "Engima\Traffic\Server\Functions.sqf"; + call compile preprocessFileLineNumbers "Engima\Traffic\ConfigAndStart.sqf"; +}; + + +setCustomFace = +{ + _thisunit = _this select 0; + _face = _this select 1; + _thisunit setFace _face; + _thisunit disableConversation true; + enableSentences false; + _thisunit setVariable ["BIS_noCoreConversations", true]; +}; \ No newline at end of file diff --git a/Engima/Traffic/Server/Functions.sqf b/Engima/Traffic/Server/Functions.sqf new file mode 100644 index 00000000..23e8a949 --- /dev/null +++ b/Engima/Traffic/Server/Functions.sqf @@ -0,0 +1,565 @@ +if (!isNil "ENGIMA_TRAFFIC_functionsInitialized") exitWith {}; + +ENGIMA_TRAFFIC_FindEdgeRoads = { + private ["_minTopLeftDistances", "_minTopRightDistances", "_minBottomRightDistances", "_minBottomLeftDistances"]; + private ["_worldTrigger", "_worldSize", "_mapTopLeftPos", "_mapTopRightPos", "_mapBottomRightPos", "_mapBottomLeftPos", "_i", "_nextStartPos", "_segmentsCount"]; + + if (!isNil "ENGIMA_TRAFFIC_edgeRoadsInitializing") exitWith {}; + ENGIMA_TRAFFIC_edgeRoadsInitializing = true; + + sleep 2; // Wait for all traffic instances to be registered + + _worldTrigger = call BIS_fnc_worldArea; + _worldSize = triggerArea _worldTrigger; + _mapTopLeftPos = [0, 2 * (_worldSize select 1)]; + _mapTopRightPos = [2 * (_worldSize select 0), 2 * (_worldSize select 1)]; + _mapBottomRightPos = [2 * (_worldSize select 0), 0]; + _mapBottomLeftPos = [0, 0]; + + _minTopLeftDistances = []; + _minTopRightDistances = []; + _minBottomRightDistances = []; + _minBottomLeftDistances = []; + for "_i" from 0 to ENGIMA_TRAFFIC_instanceIndex do { + _minTopLeftDistances pushBack 1000000; + _minTopRightDistances pushBack 1000000; + _minBottomRightDistances pushBack 1000000; + _minBottomLeftDistances pushBack 1000000; + }; + + ENGIMA_TRAFFIC_allRoadSegments = [0,0,0] nearRoads 1000000; + sleep 0.01; + _segmentsCount = count ENGIMA_TRAFFIC_allRoadSegments; + + // Find all edge road segments + _i = 0; + _nextStartPos = 1; + while { _i < _segmentsCount } do { + private ["_index", "_road", "_roadPos", "_markerName", "_insideMarker", "_roads"]; + + _road = ENGIMA_TRAFFIC_allRoadSegments select _i; + _roadPos = getPos _road; + + _index = 0; + + // Top left + while { _index <= ENGIMA_TRAFFIC_instanceIndex } do { + _markerName = ENGIMA_TRAFFIC_areaMarkerNames select _index; // Get the marker name for the current instance + + _insideMarker = true; + if (_markerName != "") then { + _insideMarker = [_roadPos, _markerName] call ENGIMA_TRAFFIC_PositionIsInsideMarker; + }; + + if (_insideMarker) then { + _roads = ENGIMA_TRAFFIC_roadSegments select _index; + _roads pushBack _road; + + // Top left + if (_roadPos distance _mapTopLeftPos < (_minTopLeftDistances select _index)) then { + _minTopLeftDistances set [_index, _roadPos distance _mapTopLeftPos]; + ENGIMA_TRAFFIC_edgeTopLeftRoads set [_index, _road]; + }; + + // Top right + if (_roadPos distance _mapTopRightPos < (_minTopRightDistances select _index)) then { + _minTopRightDistances set [_index, _roadPos distance _mapTopRightPos]; + ENGIMA_TRAFFIC_edgeTopRightRoads set [_index, _road]; + }; + + // Bottom right + if (_roadPos distance _mapBottomRightPos < (_minBottomRightDistances select _index)) then { + _minBottomRightDistances set [_index, _roadPos distance _mapBottomRightPos]; + ENGIMA_TRAFFIC_edgeBottomRightRoads set [_index, _road]; + }; + + // Bottom left + if (_roadPos distance _mapBottomLeftPos < (_minBottomLeftDistances select _index)) then { + _minBottomLeftDistances set [_index, _roadPos distance _mapBottomLeftPos]; + ENGIMA_TRAFFIC_edgeBottomLeftRoads set [_index, _road]; + }; + + if (!(ENGIMA_TRAFFIC_edgeRoadsUseful select _index)) then { + ENGIMA_TRAFFIC_edgeRoadsUseful set [_index, true]; + }; + sleep 0.01; + }; + + _index = _index + 1; + }; + + sleep 0.01; + _i = _i + 50; + if (_i >= _segmentsCount) then { + _i = _nextStartPos; + _nextStartPos = _nextStartPos + 1; + if (_nextStartPos == 50) then { + _i = _segmentsCount; + }; + }; + }; + + ENGIMA_TRAFFIC_edgeRoadsInitialized = true; +}; + +ENGIMA_TRAFFIC_MoveVehicle = { + private ["_currentInstanceIndex", "_vehicle", "_firstDestinationPos", "_debug"]; + private ["_speed", "_roadSegments", "_destinationSegment"]; + private ["_destinationPos"]; + private ["_waypoint", "_fuel"]; + + _currentInstanceIndex = _this select 0; + _vehicle = _this select 1; + if (count _this > 2) then {_firstDestinationPos = _this select 2;} else {_firstDestinationPos = [];}; + if (count _this > 3) then {_debug = _this select 3;} else {_debug = false;}; + + // Set fuel to something in between 0.3 and 0.9. + _fuel = 0.3 + random (0.9 - 0.3); + _vehicle setFuel _fuel; + + if (count _firstDestinationPos > 0) then { + _destinationPos = + _firstDestinationPos; + } + else { + _roadSegments = ENGIMA_TRAFFIC_roadSegments select _currentInstanceIndex; + _destinationSegment = _roadSegments select floor random count _roadSegments; + _destinationPos = getPos _destinationSegment; + }; + + _speed = "NORMAL"; + if (_vehicle distance _destinationPos < 500) then { + _speed = "LIMITED"; + }; + + _waypoint = group _vehicle addWaypoint [_destinationPos, 10]; + _waypoint setWaypointBehaviour "SAFE"; + _waypoint setWaypointSpeed _speed; + _waypoint setWaypointCompletionRadius 10; + _waypoint setWaypointStatements ["true", "_nil = [" + str _currentInstanceIndex + ", " + vehicleVarName _vehicle + ", [], " + str _debug + "] spawn ENGIMA_TRAFFIC_MoveVehicle;"]; +}; + +ENGIMA_TRAFFIC_StartTraffic = { + + if (!isServer) exitWith {}; + + private ["_side", "_vehicleCount", "_minSpawnDistance", "_maxSpawnDistance", "_minSkill", "_maxSkill", "_areaMarkerName", "_hideAreaMarker", "_debug"]; + private ["_allPlayerPositions", "_allPlayerPositionsTemp", "_activeVehiclesAndGroup", "_vehicleGroup", "_spawnSegment", "_vehicle", "_group", "_result", "_possibleVehicles", "_vehicleType", "_vehiclesCrew", "_skill", "_minDistance", "_tries", "_trafficLocation"]; + private ["_currentEntityNo", "_vehicleVarName", "_tempVehiclesAndGroup", "_deletedVehiclesCount", "_firstIteration", "_roadSegments", "_destinationSegment", "_destinationPos", "_direction"]; + private ["_roadSegmentDirection", "_testDirection", "_facingAway", "_posX", "_posY", "_pos", "_currentInstanceIndex"]; + private ["_fnc_OnSpawnVehicle", "_fnc_OnRemoveVehicle", "_fnc_FindSpawnSegment"]; + private ["_debugMarkerName"]; + + _side = [_this, "SIDE", civilian] call ENGIMA_TRAFFIC_GetParamValue; + _possibleVehicles = [_this, "VEHICLES", ["C_Offroad_01_F", "C_Offroad_01_repair_F", "C_Quadbike_01_F", "C_Hatchback_01_F", "C_Hatchback_01_sport_F", "C_SUV_01_F", "C_Van_01_transport_F", "C_Van_01_box_F", "C_Van_01_fuel_F"]] call ENGIMA_TRAFFIC_GetParamValue; + _vehicleCount = [_this, "VEHICLES_COUNT", 10] call ENGIMA_TRAFFIC_GetParamValue; + _minSpawnDistance = [_this, "MIN_SPAWN_DISTANCE", 800] call ENGIMA_TRAFFIC_GetParamValue; + _maxSpawnDistance = [_this, "MAX_SPAWN_DISTANCE", 1200] call ENGIMA_TRAFFIC_GetParamValue; + _minSkill = [_this, "MIN_SKILL", 0.3] call ENGIMA_TRAFFIC_GetParamValue; + _maxSkill = [_this, "MAX_SKILL", 0.7] call ENGIMA_TRAFFIC_GetParamValue; + _areaMarkerName = [_this, "AREA_MARKER", ""] call ENGIMA_TRAFFIC_GetParamValue; + _hideAreaMarker = [_this, "HIDE_AREA_MARKER", true] call ENGIMA_TRAFFIC_GetParamValue; + _fnc_OnSpawnVehicle = [_this, "ON_SPAWN_CALLBACK", {}] call ENGIMA_TRAFFIC_GetParamValue; + _fnc_OnRemoveVehicle = [_this, "ON_REMOVE_CALLBACK", {}] call ENGIMA_TRAFFIC_GetParamValue; + _debug = [_this, "DEBUG", false] call ENGIMA_TRAFFIC_GetParamValue; + + + + if (_areaMarkerName != "" && _hideAreaMarker) then { + _areaMarkerName setMarkerAlpha 0; + }; + + sleep (random 1); + ENGIMA_TRAFFIC_instanceIndex = ENGIMA_TRAFFIC_instanceIndex + 1; + _currentInstanceIndex = ENGIMA_TRAFFIC_instanceIndex; + + ENGIMA_TRAFFIC_areaMarkerNames set [_currentInstanceIndex, _areaMarkerName]; + ENGIMA_TRAFFIC_edgeRoadsUseful set [_currentInstanceIndex, false]; + ENGIMA_TRAFFIC_roadSegments set [_currentInstanceIndex, []]; + + _activeVehiclesAndGroup = []; + + _fnc_FindSpawnSegment = { + private ["_currentInstanceIndex", "_allPlayerPositions", "_minSpawnDistance", "_maxSpawnDistance", "_activeVehiclesAndGroup"]; + private ["_insideMarker", "_areaMarkerName", "_refPlayerPos", "_roadSegments", "_roadSegment", "_isOk", "_tries", "_result", "_spawnDistanceDiff", "_refPosX", "_refPosY", "_dir", "_tooFarAwayFromAll", "_tooClose", "_tooCloseToAnotherVehicle"]; + + _currentInstanceIndex = _this select 0; + _allPlayerPositions = _this select 1; + _minSpawnDistance = _this select 2; + _maxSpawnDistance = _this select 3; + _activeVehiclesAndGroup = _this select 4; + + _spawnDistanceDiff = _maxSpawnDistance - _minSpawnDistance; + _roadSegment = "NULL"; + _refPlayerPos = (_allPlayerPositions select floor random count _allPlayerPositions); + _areaMarkerName = ENGIMA_TRAFFIC_areaMarkerNames select _currentInstanceIndex; + + _isOk = false; + _tries = 0; + while {!_isOk && _tries < 10} do { + _isOk = true; + + _dir = random 360; + + _refPosX = (_refPlayerPos select 0) + (_minSpawnDistance + _spawnDistanceDiff / 2) * sin _dir; + _refPosY = (_refPlayerPos select 1) + (_minSpawnDistance + _spawnDistanceDiff / 2) * cos _dir; + + _roadSegments = [_refPosX, _refPosY] nearRoads (_spawnDistanceDiff / 2); + + if (count _roadSegments > 0) then { + _roadSegment = _roadSegments select floor random count _roadSegments; + + // Check if road segment is ok + _tooFarAwayFromAll = true; + _tooClose = false; + _insideMarker = true; + _tooCloseToAnotherVehicle = false; + + if (_areaMarkerName != "" && !([getPos _roadSegment, _areaMarkerName] call ENGIMA_TRAFFIC_PositionIsInsideMarker)) then { + _insideMarker = false; + }; + + if (_insideMarker) then { + { + private ["_tooFarAway"]; + + _tooFarAway = false; + + if (_x distance (getPos _roadSegment) < _minSpawnDistance) then { + _tooClose = true; + }; + if (_x distance (getPos _roadSegment) > _maxSpawnDistance) then { + _tooFarAway = true; + }; + if (!_tooFarAway) then { + _tooFarAwayFromAll = false; + }; + + sleep 0.01; + } foreach _allPlayerPositions; + + { + private ["_vehicle"]; + _vehicle = _x select 0; + + if ((getPos _roadSegment) distance _vehicle < 100) then { + _tooCloseToAnotherVehicle = true; + }; + + sleep 0.01; + } foreach _activeVehiclesAndGroup; + }; + + _isOk = true; + + if (_tooClose || _tooFarAwayFromAll || _tooCloseToAnotherVehicle || !_insideMarker) then { + _isOk = false; + _tries = _tries + 1; + }; + } + else { + _isOk = false; + _tries = _tries + 1; + }; + + sleep 0.1; + }; + + if (!_isOk) then { + _result = "NULL"; + } + else { + _result = _roadSegment; + }; + + _result + }; + + _firstIteration = true; + + [] spawn ENGIMA_TRAFFIC_FindEdgeRoads; + waitUntil { sleep 1; (ENGIMA_TRAFFIC_edgeRoadsUseful select _currentInstanceIndex) }; + sleep 5; + + while {true} do { + scopeName "mainScope"; + private ["_sleepSeconds", "_correctedVehicleCount", "_markerSize", "_avgMarkerRadius", "_coveredShare", "_restDistance", "_coveredAreaShare"]; + + _allPlayerPositionsTemp = []; + if (isMultiplayer) then { + { + if (isPlayer _x) then { + _allPlayerPositionsTemp = _allPlayerPositionsTemp + [position vehicle _x]; + }; + } foreach (playableUnits); + } + else { + _allPlayerPositionsTemp = [position vehicle player]; + }; + + if (count _allPlayerPositionsTemp > 0) then { + _allPlayerPositions = _allPlayerPositionsTemp; + }; + + // If there are few vehicles, add a vehicle + + if (_areaMarkerName == "") then { + _correctedVehicleCount = _vehicleCount; + } + else { + _markerSize = getMarkerSize _areaMarkerName; + _avgMarkerRadius = ((_markerSize select 0) + (_markerSize select 1)) / 2; + + if (_avgMarkerRadius > _maxSpawnDistance) then { + _correctedVehicleCount = floor (_vehicleCount / 2); + _coveredShare = 0; + + { + _restDistance = _maxSpawnDistance - ((_x distance getMarkerPos _areaMarkerName) - _avgMarkerRadius); + _coveredAreaShare = _restDistance / (_maxSpawnDistance * 2); + if (_coveredAreaShare > _coveredShare) then { + _coveredShare = _coveredAreaShare; + }; + + sleep 0.01; + } foreach (_allPlayerPositions); + + _correctedVehicleCount = floor (_vehicleCount * _coveredShare); + } + else { + _correctedVehicleCount = _vehicleCount; + }; + }; + + _tries = 0; + while {count _activeVehiclesAndGroup < _correctedVehicleCount && _tries < 1} do { + sleep 0.1; + + // Get all spawn positions within range + if (_firstIteration) then { + _minDistance = 300; + + if (_minDistance > _maxSpawnDistance) then { + _minDistance = 0; + }; + } + else { + _minDistance = _minSpawnDistance; + }; + + _spawnSegment = [_currentInstanceIndex, _allPlayerPositions, _minDistance, _maxSpawnDistance, _activeVehiclesAndGroup] call _fnc_FindSpawnSegment; + + // If there were spawn positions + if (str _spawnSegment != """NULL""") then { + + // Get first destination + _trafficLocation = floor random 5; + switch (_trafficLocation) do { + case 0: { _roadSegments = (getPos (ENGIMA_TRAFFIC_edgeBottomLeftRoads select _currentInstanceIndex)) nearRoads 100; }; + case 1: { _roadSegments = (getPos (ENGIMA_TRAFFIC_edgeTopLeftRoads select _currentInstanceIndex)) nearRoads 100; }; + case 2: { _roadSegments = (getPos (ENGIMA_TRAFFIC_edgeTopRightRoads select _currentInstanceIndex)) nearRoads 100; }; + case 3: { _roadSegments = (getPos (ENGIMA_TRAFFIC_edgeBottomRightRoads select _currentInstanceIndex)) nearRoads 100; }; + default { _roadSegments = ENGIMA_TRAFFIC_roadSegments select _currentInstanceIndex }; + }; + + _destinationSegment = _roadSegments select floor random count _roadSegments; + _destinationPos = getPos _destinationSegment; + + _direction = ((_destinationPos select 0) - (getPos _spawnSegment select 0)) atan2 ((_destinationPos select 1) - (getpos _spawnSegment select 1)); + _roadSegmentDirection = getDir _spawnSegment; + + while {_roadSegmentDirection < 0} do { + _roadSegmentDirection = _roadSegmentDirection + 360; + }; + while {_roadSegmentDirection > 360} do { + _roadSegmentDirection = _roadSegmentDirection - 360; + }; + + while {_direction < 0} do { + _direction = _direction + 360; + }; + while {_direction > 360} do { + _direction = _direction - 360; + }; + + _testDirection = _direction - _roadSegmentDirection; + + while {_testDirection < 0} do { + _testDirection = _testDirection + 360; + }; + while {_testDirection > 360} do { + _testDirection = _testDirection - 360; + }; + + _facingAway = false; + if (_testDirection > 90 && _testDirection < 270) then { + _facingAway = true; + }; + + if (_facingAway) then { + _direction = _roadSegmentDirection + 180; + } + else { + _direction = _roadSegmentDirection; + }; + + _posX = (getPos _spawnSegment) select 0; + _posY = (getPos _spawnSegment) select 1; + + _posX = _posX + 2.5 * sin (_direction + 90); + _posY = _posY + 2.5 * cos (_direction + 90); + _pos = [_posX, _posY, 0]; + + // Create vehicle + _vehicleType = _possibleVehicles select floor (random count _possibleVehicles); + //_vehicleGroup = createGroup _side; + //_vehicle = createVehicle [_vehicleType, _pos, [], 0, "NONE"]; + // Run spawn script and attach handle to vehicle + _vehicleArray = [[_pos,_vehicleType,_side] call createTakistaniVehicle]; + // diag_log format ["vehicleArray I is %1",_vehicleArray]; + waitUntil {count _vehicleArray > 0}; + // diag_log format ["vehicleArray II is %1",_vehicleArray]; + _vehicle = (_vehicleArray select 0) select 0; + diag_log format ["traffic: vehicle is %1",_vehicle]; + //_result = [_pos, _direction, _vehicleType, _vehicleGroup] call BIS_fnc_spawnVehicle; + + // = [_vehicleType] ... "createVehicle.sqf"; + + _vehicleGroup = (_vehicleArray select 0) select 1; + _vehiclesCrew = units _vehicleGroup; + + + + _result = [_vehicle, _vehiclesCrew, _vehicleGroup]; + // Array - 0: created vehicle (Object), 1: all crew (Array of Objects), 2: vehicle's group (Group) + + // Name vehicle + sleep random 0.1; + if (isNil "dre_MilitaryTraffic_CurrentEntityNo") then { + dre_MilitaryTraffic_CurrentEntityNo = 0 + }; + + _currentEntityNo = dre_MilitaryTraffic_CurrentEntityNo; + dre_MilitaryTraffic_CurrentEntityNo = dre_MilitaryTraffic_CurrentEntityNo + 1; + + _vehicleVarName = "dre_MilitaryTraffic_Entity_" + str _currentEntityNo; + _vehicle setVehicleVarName _vehicleVarName; + _vehicle call compile format ["%1=_this;", _vehicleVarName]; + sleep 0.01; + + // Set crew skill + { + _skill = _minSkill + random (_maxSkill - _minSkill); + _x setSkill _skill; + sleep 0.01; + } foreach _vehiclesCrew; + + _debugMarkerName = "dre_MilitaryTraffic_DebugMarker" + str _currentEntityNo; + + // Start vehicle + [_currentInstanceIndex, _vehicle, _destinationPos, _debug] spawn ENGIMA_TRAFFIC_MoveVehicle; + _activeVehiclesAndGroup pushBack [_vehicle, _vehicleGroup, _vehiclesCrew, _debugMarkerName]; + sleep 0.01; + + // Run spawn script and attach handle to vehicle + _vehicle setVariable ["dre_scriptHandle", _result spawn _fnc_OnSpawnVehicle]; + }; + + _tries = _tries + 1; + }; + + _firstIteration = false; + + // If any vehicle is too far away, delete it + _tempVehiclesAndGroup = []; + _deletedVehiclesCount = 0; + { + private ["_closestUnitDistance", "_distance", "_crewUnits"]; + private ["_scriptHandle"]; + + _vehicle = _x select 0; + _group = _x select 1; + _crewUnits = _x select 2; + _debugMarkerName = _x select 3; + + _closestUnitDistance = 1000000; + + { + _distance = (_x distance _vehicle); + if (_distance < _closestUnitDistance) then { + _closestUnitDistance = _distance; + }; + + sleep 0.01; + } foreach _allPlayerPositions; + + if (_closestUnitDistance < _maxSpawnDistance) then { + _tempVehiclesAndGroup pushBack _x; + } + else { + // Run callback before deleting + _vehicle call _fnc_OnRemoveVehicle; + + // Delete crew + { + deleteVehicle _x; + } foreach _crewUnits; + + // Terminate script before deleting the vehicle + _scriptHandle = _vehicle getVariable "dre_scriptHandle"; + if (!(scriptDone _scriptHandle)) then { + waitUntil {scriptDone _scriptHandle}; + + }; + + deleteVehicle _vehicle; + deleteGroup _group; + + [_debugMarkerName] call ENGIMA_TRAFFIC_DeleteDebugMarkerAllClients; + _deletedVehiclesCount = _deletedVehiclesCount + 1; + }; + + sleep 0.01; + } foreach _activeVehiclesAndGroup; + + _activeVehiclesAndGroup = _tempVehiclesAndGroup; + + // Do nothing but update debug markers for X seconds + _sleepSeconds = 5; + if (_debug) then { + for "_i" from 1 to _sleepSeconds do { + { + private ["_debugMarkerColor"]; + + _vehicle = _x select 0; + _group = _x select 1; + _debugMarkerName = _x select 3; + _side = side _group; + + _debugMarkerColor = "Default"; + if (_side == west) then { + _debugMarkerColor = "ColorBlue"; + }; + if (_side == east) then { + _debugMarkerColor = "ColorRed"; + }; + if (_side == civilian) then { + _debugMarkerColor = "ColorYellow"; + }; + if (_side == resistance) then { + _debugMarkerColor = "ColorGreen"; + }; + + [_debugMarkerName, getPos (_vehicle), "mil_dot", _debugMarkerColor, "Traffic"] call ENGIMA_TRAFFIC_SetDebugMarkerAllClients; + + } foreach _activeVehiclesAndGroup; + + sleep 1; + }; + } + else { + sleep _sleepSeconds; + }; + }; +}; + +ENGIMA_TRAFFIC_functionsInitialized = true; diff --git a/Engima/Traffic/_old/Common/Common.sqf b/Engima/Traffic/_old/Common/Common.sqf new file mode 100644 index 00000000..f9a934cd --- /dev/null +++ b/Engima/Traffic/_old/Common/Common.sqf @@ -0,0 +1,42 @@ +/* + * Summary: Gets a parameter value in a paired list on format ["KEY", value]. + * Arguments: + * _params: List of paired value parameters. + * _key: String with key to look for. + * _default: Value that is returned if key was not found. + * Returns: Value associated with key. ObjNull if no key was found. + */ +ENGIMA_TRAFFIC_GetParamValue = { + private ["_params", "_key"]; + private ["_value"]; + + _params = _this select 0; + _key = _this select 1; + _value = if (count _this > 2) then { _this select 2 } else { objNull }; + + { + if (_x select 0 == _key) then { + _value = _x select 1; + }; + } foreach (_params); + + _value +}; + +/* + * Summary: Checks if a marker exists. + * Arguments: + * _marker: Marker name of marker to test. + * Returns: true if marker exists, else false. + */ +ENGIMA_TRAFFIC_MarkerExists = { + private ["_exists", "_marker"]; + + _marker = _this select 0; + + _exists = false; + if (((getMarkerPos _marker) select 0) != 0 || ((getMarkerPos _marker) select 1 != 0)) then { + _exists = true; + }; + _exists +}; diff --git a/Engima/Traffic/_old/Common/Debug.sqf b/Engima/Traffic/_old/Common/Debug.sqf new file mode 100644 index 00000000..67fd9280 --- /dev/null +++ b/Engima/Traffic/_old/Common/Debug.sqf @@ -0,0 +1,179 @@ +ENGIMA_TRAFFIC_SilentDebugMode = false; + +ENGIMA_TRAFFIC_DebugTextEventArgs = []; // Empty +ENGIMA_TRAFFIC_DebugMarkerEventArgs = []; // [name, position, size, direction, shape ("RECTANGLE" or "ELLIPSE"), markerColor, markerText (optional)] or alternatively [name, position, type, markerColor (optional), markerText (optional)] +ENGIMA_TRAFFIC_DeleteDebugMarkerEventArgs = []; // [name] + +"ENGIMA_TRAFFIC_DebugTextEventArgs" addPublicVariableEventHandler { + ENGIMA_TRAFFIC_DebugTextEventArgs call ENGIMA_TRAFFIC_ShowDebugTextLocal; +}; + +"ENGIMA_TRAFFIC_DebugMarkerEventArgs" addPublicVariableEventHandler { + ENGIMA_TRAFFIC_DebugMarkerEventArgs call ENGIMA_TRAFFIC_SetDebugMarkerLocal; +}; + +"ENGIMA_TRAFFIC_DeleteDebugMarkerEventArgs" addPublicVariableEventHandler { + ENGIMA_TRAFFIC_DeleteDebugMarkerEventArgs call ENGIMA_TRAFFIC_DeleteDebugMarkerLocal; +}; + +/* + * Summary: Shows debug text on all clients. + * Remarks: + * if global variable "dre_var_CL_SilentDebugMode" is set to true, debug text will only be written to RTF-file and not shown on screen. + * Arguments: + * _text: Debug text. + */ +ENGIMA_TRAFFIC_ShowDebugTextAllClients = { + ENGIMA_TRAFFIC_DebugTextEventArgs = _this; + publicVariable "ENGIMA_TRAFFIC_DebugTextEventArgs"; + ENGIMA_TRAFFIC_DebugTextEventArgs call ENGIMA_TRAFFIC_ShowDebugTextLocal; +}; + +/* + * Summary: Shows debug text on local client. + * Remarks: + * if global variable "dre_var_CL_SilentDebugMode" is set to true, debug text will only be written to RTF-file and not shown on screen. + * Arguments: + * _text: Debug text. + */ +ENGIMA_TRAFFIC_ShowDebugTextLocal = { + private ["_minutes", "_seconds"]; + + if (!isNull player) then { + if (!ENGIMA_TRAFFIC_SilentDebugMode) then { + player sideChat (_this select 0); + }; + }; + + _minutes = floor (time / 60); + _seconds = floor (time - (_minutes * 60)); + diag_log ((str _minutes + ":" + str _seconds) + " Debug: " + (_this select 0)); +}; + +/* + * Summary: Shows debug marker on local client. + * Remarks: + * if global variable "dre_var_CL_SilentDebugMode" is set to true, debug marker will not shown. + * Arguments alternative #1 (Marker representing an area): + * _markerName: Marker's name. (must be global unique). + * _position: Marker's position. + * _size: Marker's size on array format [x, y]. + * _direction: Marker's direction. + * _shape: "RECTANGLE" or "ELLIPSE". + * _markerColor: Marker's color ("Default", "ColorRed", "ColorYellow" etc.). + * [_markerText]: Optional. Marker's text. + * Arguments alternative #2 (Marker representing an icon). + * _markerName: Marker's name. (must be global unique). + * _position: Marker's position. + * _type: Markers icon type (applies to icons in cfgIcons, like "Warning", "Dot" etc.). + * [_markerColor]: Optional. Marker's color ("Default", "ColorRed", "ColorYellow" etc.). + * [_markerText]. Optional. Marker's text. + */ +ENGIMA_TRAFFIC_SetDebugMarkerLocal = { + private ["_markerName", "_position", "_size", "_direction", "_type", "_shape", "_markerColor", "_markerText"]; + private ["_marker"]; + + if (!isNull player) then { + if (!ENGIMA_TRAFFIC_SilentDebugMode) then { + _markerName = _this select 0; + _position = _this select 1; + _markerColor = "Default"; + _markerText = ""; + + if (count _this == 6) then { + _size = _this select 2; + _direction = _this select 3; + _shape = _this select 4; + _markerColor = _this select 5; + }; + if (count _this == 7) then { + _size = _this select 2; + _direction = _this select 3; + _shape = _this select 4; + _markerColor = _this select 5; + _markerText = _this select 6; + }; + if (count _this == 3) then { + _type = _this select 2; + _shape = "ICON"; + }; + if (count _this == 4) then { + _type = _this select 2; + _shape = "ICON"; + _markerColor = _this select 3; + }; + if (count _this == 5) then { + _type = _this select 2; + _shape = "ICON"; + _markerColor = _this select 3; + _markerText = _this select 4; + }; + + // Delete old marker + if ([_markerName] call ENGIMA_TRAFFIC_MarkerExists) then { + deleteMarkerLocal _markerName; + }; + + // Set new marker + _marker = createMarkerLocal [_markerName, _position]; + _marker setMarkerShapeLocal _shape; + _marker setMarkerColorLocal _markerColor; + _marker setMarkerTextLocal _markerText; + + if (count _this == 6 || count _this == 7) then { + _marker setMarkerSizeLocal _size; + _marker setMarkerDirLocal _direction; + }; + if (count _this == 3 || count _this == 4 || count _this == 5) then { + _marker setMarkerTypeLocal _type; + }; + }; + }; +}; + +/* + * Summary: Shows debug marker on all clients. + * Remarks: + * if global variable "dre_var_CL_SilentDebugMode" is set to true, debug marker will not shown. + * Arguments alternative #1 (Marker representing an area): + * _markerName: Marker's name. (must be global unique). + * _position: Marker's position. + * _size: Marker's size on array format [x, y]. + * _direction: Marker's direction. + * _shape: "RECTANGLE" or "ELLIPSE". + * _markerColor: Marker's color ("Default", "ColorRed", "ColorYellow" etc.). + * [_markerText]: Optional. Marker's text. + * Arguments alternative #2 (Marker representing an icon). + * _markerName: Marker's name. (must be global unique). + * _position: Marker's position. + * _type: Markers icon type (applies to icons in cfgIcons, like "Warning", "Dot" etc.). + * [_markerColor]: Optional. Marker's color ("Default", "ColorRed", "ColorYellow" etc.). + * [_markerText]. Optional. Marker's text. + */ +ENGIMA_TRAFFIC_SetDebugMarkerAllClients = { + ENGIMA_TRAFFIC_DebugMarkerEventArgs = _this; + publicVariable "ENGIMA_TRAFFIC_DebugMarkerEventArgs"; + ENGIMA_TRAFFIC_DebugMarkerEventArgs call ENGIMA_TRAFFIC_SetDebugMarkerLocal; +}; + +/* + * Summary: Deletes a debug marker on local client. + * Arguments: + * _markerName: Name of marker to delete. + */ +ENGIMA_TRAFFIC_DeleteDebugMarkerLocal = { + private ["_markerName"]; + _markerName = _this select 0; + deleteMarkerLocal _markerName; +}; + +/* + * Summary: Deletes a debug marker on all clients. + * Arguments: + * _markerName: Name of marker to delete. + */ +ENGIMA_TRAFFIC_DeleteDebugMarkerAllClients = { + ENGIMA_TRAFFIC_DeleteDebugMarkerEventArgs = _this; + publicVariable "ENGIMA_TRAFFIC_DeleteDebugMarkerEventArgs"; + ENGIMA_TRAFFIC_DeleteDebugMarkerEventArgs call ENGIMA_TRAFFIC_DeleteDebugMarkerLocal; +}; diff --git a/Engima/Traffic/_old/ConfigAndStart.sqf b/Engima/Traffic/_old/ConfigAndStart.sqf new file mode 100644 index 00000000..e5e62668 --- /dev/null +++ b/Engima/Traffic/_old/ConfigAndStart.sqf @@ -0,0 +1,81 @@ +/* + * This file contains parameters to config and function call to start an instance of + * traffic in the mission. The file is edited by the mission developer. + * + * See file Engima\Traffic\Documentation.txt for documentation and a full reference of + * how to customize and use Engima's Traffic. + */ + + private ["_parameters"]; + +// Set traffic parameters. +_parameters = [ + ["SIDE", civilian], + ["VEHICLES", [ + "C_Offroad_01_F", + "C_Offroad_01_repair_F", + "C_Hatchback_01_F", + "C_Hatchback_01_sport_F", + "C_SUV_01_F", + "C_Van_01_transport_F", + "C_Van_01_box_F", + "C_Van_01_fuel_F", + + + "RDS_Gaz24_Civ_01", + "RDS_Gaz24_Civ_02", + "RDS_Gaz24_Civ_03", + "RDS_Gaz24_Civ_01", + "RDS_Gaz24_Civ_02", + "RDS_Gaz24_Civ_03", + "RDS_Gaz24_Civ_01", + "RDS_Gaz24_Civ_02", + "RDS_Gaz24_Civ_03", + + "RDS_Ikarus_Civ_01", + "RDS_Ikarus_Civ_02", + "RDS_Ikarus_Civ_02", + + "RDS_S1203_Civ_01", + "RDS_S1203_Civ_02", + "RDS_S1203_Civ_03", + + "RDS_Octavia_Civ_01", + + "RDS_Lada_Civ_01", + "RDS_Lada_Civ_02", + "RDS_Lada_Civ_03", + "RDS_Lada_Civ_04", + "RDS_Lada_Civ_05", + "RDS_Lada_Civ_01", + "RDS_Lada_Civ_02", + "RDS_Lada_Civ_03", + "RDS_Lada_Civ_04", + + + "RHS_Ural_Civ_01", + "RHS_Ural_Civ_02", + "RHS_Ural_Civ_03", + "RHS_Ural_Open_Civ_01", + "RHS_Ural_Open_Civ_02", + "RHS_Ural_Open_Civ_03", + "RHS_UAZ_open_chdkz", + "RHS_UAZ_chdkz", + + "COREV_O_TKG_LandRover", + "COREV_O_TKG_LandRover" + ]], + ["VEHICLES_COUNT", 30], + ["MIN_SPAWN_DISTANCE", 1200], + ["MAX_SPAWN_DISTANCE", 1500], + ["MIN_SKILL", 0.4], + ["MAX_SKILL", 0.6], + ["CREATE_VEHICLE_CREW", { + 0 = [(_this select 0),(_this select 1)] execVM 'Engima\Traffic\Custom_GruppeAdler\randomPassenger.sqf'; + }], + ["AREA_MARKER", "EnemyMarker1"], + ["DEBUG", false] +]; + +// Start an instance of the traffic +_parameters spawn ENGIMA_TRAFFIC_StartTraffic; diff --git a/Engima/Traffic/_old/Server/Functions.sqf b/Engima/Traffic/_old/Server/Functions.sqf new file mode 100644 index 00000000..87c2d8bf --- /dev/null +++ b/Engima/Traffic/_old/Server/Functions.sqf @@ -0,0 +1,456 @@ +if (!isNil "ENGIMA_TRAFFIC_functionsInitialized") exitWith {}; + +ENGIMA_TRAFFIC_FindEdgeRoads = { + private ["_minTopLeftDistance", "_minTopRightDistance", "_minBottomRightDistance", "_minBottomLeftDistance"]; + private ["_worldTrigger", "_worldSize", "_mapTopLeftPos", "_mapTopRightPos", "_mapBottomRightPos", "_mapBottomLeftPos"]; + + if (!isNil "ENGIMA_TRAFFIC_edgeRoadsInitializing") exitWith {}; + ENGIMA_TRAFFIC_edgeRoadsInitializing = true; + + _worldTrigger = call BIS_fnc_worldArea; + _worldSize = triggerArea _worldTrigger; + deleteVehicle _worldTrigger; + _mapTopLeftPos = [0, 2 * (_worldSize select 1)]; + _mapTopRightPos = [2 * (_worldSize select 0), 2 * (_worldSize select 1)]; + _mapBottomRightPos = [2 * (_worldSize select 0), 0]; + _mapBottomLeftPos = [0, 0]; + + _minTopLeftDistance = 1000000; + _minTopRightDistance = 1000000; + _minBottomRightDistance = 1000000; + _minBottomLeftDistance = 1000000; + + ENGIMA_TRAFFIC_allRoadSegments = [0,0,0] nearRoads 1000000; + + // Find all edge road segments + { + private "_roadPos"; + + _roadPos = getPos _x; + + // Top left + if (_roadPos distance _mapTopLeftPos < _minTopLeftDistance) then { + _minTopLeftDistance = _roadPos distance _mapTopLeftPos; + ENGIMA_TRAFFIC_topLeftRoad = _x; + }; + + // Top right + if (_roadPos distance _mapTopRightPos < _minTopRightDistance) then { + _minTopRightDistance = _roadPos distance _mapTopRightPos; + ENGIMA_TRAFFIC_topRightRoad = _x; + }; + + // Top left + if (_roadPos distance _mapBottomRightPos < _minBottomRightDistance) then { + _minBottomRightDistance = _roadPos distance _mapBottomRightPos; + ENGIMA_TRAFFIC_bottomRightRoad = _x; + }; + + // Top left + if (_roadPos distance _mapBottomLeftPos < _minBottomLeftDistance) then { + _minBottomLeftDistance = _roadPos distance _mapBottomLeftPos; + ENGIMA_TRAFFIC_bottomLeftRoad = _x; + }; + + ENGIMA_TRAFFIC_edgeRoadsUseful = true; + + sleep 0.01; + } foreach (ENGIMA_TRAFFIC_allRoadSegments); + + ENGIMA_TRAFFIC_edgeRoadsInitialized = true; +}; + +ENGIMA_TRAFFIC_MoveVehicle = { + private ["_vehicle", "_firstDestinationPos", "_debug"]; + private ["_speed", "_roadSegments", "_destinationSegment"]; + private ["_destinationPos"]; + private ["_waypoint", "_fuel"]; + + _vehicle = _this select 0; + if (count _this > 1) then {_firstDestinationPos = _this select 1;} else {_firstDestinationPos = [];}; + if (count _this > 2) then {_debug = _this select 2;} else {_debug = false;}; + + // Set fuel to something in between 0.2 and 0.9. + _fuel = 0.2 + random (0.9 - 0.2); + _vehicle setFuel _fuel; + + if (count _firstDestinationPos > 0) then { + _destinationPos = + _firstDestinationPos; + } + else { + _roadSegments = _vehicle nearRoads 1000000; + _destinationSegment = _roadSegments select floor random count _roadSegments; + _destinationPos = getPos _destinationSegment; + }; + + _speed = "NORMAL"; + if (_vehicle distance _destinationSegment < 500) then { + _speed = "LIMITED"; + }; + + _waypoint = group _vehicle addWaypoint [_destinationPos, 10]; + _waypoint setWaypointBehaviour "SAFE"; + _waypoint setWaypointSpeed _speed; + _waypoint setWaypointCompletionRadius 10; + _waypoint setWaypointStatements ["true", "_nil = [" + vehicleVarName _vehicle + ", [], " + str _debug + "] spawn ENGIMA_TRAFFIC_MoveVehicle;"]; +}; + +ENGIMA_TRAFFIC_StartTraffic = { + if (!isServer) exitWith {}; + +// if (isNil "dre_var_commonLibInitialized") then { call compile preprocessFileLineNumbers "Engima\CommonLib\CommonLib.sqf"; }; +// if (isNil "ENGIMA_TRAFFIC_functionsInitialized") then { call compile preprocessFileLineNumbers "Engima\Traffic\Functions.sqf"; }; + + private ["_side", "_vehicleCount", "_minSpawnDistance", "_maxSpawnDistance", "_minSkill", "_maxSkill", "_debug"]; + private ["_allPlayerPositions", "_allPlayerPositionsTemp", "_activeVehiclesAndGroup", "_vehiclesGroup", "_spawnSegment", "_vehicle", "_group", "_result", "_possibleVehicles", "_vehicleType", "_vehiclesCrew", "_skill", "_minDistance", "_tries", "_trafficLocation"]; + private ["_currentEntityNo", "_vehicleVarName", "_tempVehiclesAndGroup", "_deletedVehiclesCount", "_firstIteration", "_roadSegments", "_destinationSegment", "_destinationPos", "_direction"]; + private ["_roadSegmentDirection", "_testDirection", "_facingAway", "_posX", "_posY", "_pos"]; + private ["_fnc_OnSpawnVehicle", "_fnc_CreateVehicleCrew","_fnc_OnRemoveVehicle", "_fnc_FindSpawnSegment"]; + private ["_debugMarkerName"]; + + _side = [_this, "SIDE", civilian] call ENGIMA_TRAFFIC_GetParamValue; + _possibleVehicles = [_this, "VEHICLES", ["C_Offroad_01_F", "C_Offroad_01_repair_F", "C_Quadbike_01_F", "C_Hatchback_01_F", "C_Hatchback_01_sport_F", "C_SUV_01_F", "C_Van_01_transport_F", "C_Van_01_box_F", "C_Van_01_fuel_F"]] call ENGIMA_TRAFFIC_GetParamValue; + _vehicleCount = [_this, "VEHICLES_COUNT", 10] call ENGIMA_TRAFFIC_GetParamValue; + _minSpawnDistance = [_this, "MIN_SPAWN_DISTANCE", 800] call ENGIMA_TRAFFIC_GetParamValue; + _maxSpawnDistance = [_this, "MAX_SPAWN_DISTANCE", 1200] call ENGIMA_TRAFFIC_GetParamValue; + _minSkill = [_this, "MIN_SKILL", 0.3] call ENGIMA_TRAFFIC_GetParamValue; + _maxSkill = [_this, "MAX_SKILL", 0.7] call ENGIMA_TRAFFIC_GetParamValue; + _fnc_CreateVehicleCrew = [_this, "CREATE_VEHICLE_CREW", {}] call ENGIMA_TRAFFIC_GetParamValue; + _fnc_OnSpawnVehicle = [_this, "ON_SPAWN_CALLBACK", {}] call ENGIMA_TRAFFIC_GetParamValue; + _fnc_OnRemoveVehicle = [_this, "ON_REMOVE_CALLBACK", {}] call ENGIMA_TRAFFIC_GetParamValue; + _debug = [_this, "DEBUG", false] call ENGIMA_TRAFFIC_GetParamValue; + + if (_debug) then { + ["Starting Military Traffic " + str _side + "..."] call ENGIMA_TRAFFIC_ShowDebugTextAllClients; + }; + + _activeVehiclesAndGroup = []; + + _fnc_FindSpawnSegment = { + private ["_allPlayerPositions", "_minSpawnDistance", "_maxSpawnDistance", "_activeVehiclesAndGroup"]; + private ["_refPlayerPos", "_roadSegments", "_roadSegment", "_isOk", "_tries", "_result", "_spawnDistanceDiff", "_refPosX", "_refPosY", "_dir", "_tooFarAwayFromAll", "_tooClose", "_tooCloseToAnotherVehicle"]; + + _allPlayerPositions = _this select 0; + _minSpawnDistance = _this select 1; + _maxSpawnDistance = _this select 2; + _activeVehiclesAndGroup = _this select 3; + + _spawnDistanceDiff = _maxSpawnDistance - _minSpawnDistance; + _roadSegment = "NULL"; + _refPlayerPos = (_allPlayerPositions select floor random count _allPlayerPositions); + + _isOk = false; + _tries = 0; + while {!_isOk && _tries < 5} do { + _isOk = true; + + _dir = random 360; + + _refPosX = (_refPlayerPos select 0) + (_minSpawnDistance + _spawnDistanceDiff) * sin _dir; + _refPosY = (_refPlayerPos select 1) + (_minSpawnDistance + _spawnDistanceDiff) * cos _dir; + + _roadSegments = [_refPosX, _refPosY] nearRoads (_spawnDistanceDiff); + + if (count _roadSegments > 0) then { + _roadSegment = _roadSegments select floor random count _roadSegments; + + // Check if road segment is at spawn distance + _tooFarAwayFromAll = true; + _tooClose = false; + { + private ["_tooFarAway"]; + + _tooFarAway = false; + + if (_x distance (getPos _roadSegment) < _minSpawnDistance) then { + _tooClose = true; + }; + if (_x distance (getPos _roadSegment) > _maxSpawnDistance) then { + _tooFarAway = true; + }; + if (!_tooFarAway) then { + _tooFarAwayFromAll = false; + }; + + _tooCloseToAnotherVehicle = false; + { + private ["_vehicle"]; + _vehicle = _x select 0; + + if ((getPos _roadSegment) distance _vehicle < 100) then { + _tooCloseToAnotherVehicle = true; + }; + } foreach _activeVehiclesAndGroup; + } foreach _allPlayerPositions; + + _isOk = true; + + if (_tooClose || _tooFarAwayFromAll || _tooCloseToAnotherVehicle) then { + _isOk = false; + _tries = _tries + 1; + }; + } + else { + _isOk = false; + _tries = _tries + 1; + }; + }; + + if (!_isOk) then { + _result = "NULL"; + } + else { + _result = _roadSegment; + }; + + _result + }; + + //_iterationNo = 0; + _firstIteration = true; + + [] spawn ENGIMA_TRAFFIC_FindEdgeRoads; + waitUntil { !isNil "ENGIMA_TRAFFIC_edgeRoadsUseful" }; + + while {true} do { + scopeName "mainScope"; + + _allPlayerPositionsTemp = []; + if (isMultiplayer) then { + { + if (isPlayer _x) then { + _allPlayerPositionsTemp = _allPlayerPositionsTemp + [position vehicle _x]; + }; + } foreach (playableUnits); + } + else { + _allPlayerPositionsTemp = [position vehicle player]; + }; + + if (count _allPlayerPositionsTemp > 0) then { + _allPlayerPositions = _allPlayerPositionsTemp; + }; + + // If there are few vehicles, add a vehicle + + _tries = 0; + while {count _activeVehiclesAndGroup < _vehicleCount && _tries < 1} do { + sleep 1; + + // Get all spawn positions within range + if (_firstIteration) then { + _minDistance = 300; + + if (_minDistance > _maxSpawnDistance) then { + _minDistance = 0; + }; + } + else { + _minDistance = _minSpawnDistance; + }; + + _spawnSegment = [_allPlayerPositions, _minDistance, _maxSpawnDistance, _activeVehiclesAndGroup] call _fnc_FindSpawnSegment; + + // If there were spawn positions + if (str _spawnSegment != """NULL""") then { + _tries = 0; + + // Get first destination + _trafficLocation = floor random 5; + switch (_trafficLocation) do { + case 0: { _roadSegments = (getPos ENGIMA_TRAFFIC_bottomLeftRoad) nearRoads 300; }; + case 1: { _roadSegments = (getPos ENGIMA_TRAFFIC_topLeftRoad) nearRoads 300; }; + case 2: { _roadSegments = (getPos ENGIMA_TRAFFIC_topRightRoad) nearRoads 300; }; + case 3: { _roadSegments = (getPos ENGIMA_TRAFFIC_bottomRightRoad) nearRoads 300; }; + default { _roadSegments = ENGIMA_TRAFFIC_allRoadSegments }; + }; + + _destinationSegment = _roadSegments select floor random count _roadSegments; + _destinationPos = getPos _destinationSegment; + + _direction = ((_destinationPos select 0) - (getPos _spawnSegment select 0)) atan2 ((_destinationPos select 1) - (getpos _spawnSegment select 1)); + _roadSegmentDirection = getDir _spawnSegment; + + while {_roadSegmentDirection < 0} do { + _roadSegmentDirection = _roadSegmentDirection + 360; + }; + while {_roadSegmentDirection > 360} do { + _roadSegmentDirection = _roadSegmentDirection - 360; + }; + + while {_direction < 0} do { + _direction = _direction + 360; + }; + while {_direction > 360} do { + _direction = _direction - 360; + }; + + _testDirection = _direction - _roadSegmentDirection; + + while {_testDirection < 0} do { + _testDirection = _testDirection + 360; + }; + while {_testDirection > 360} do { + _testDirection = _testDirection - 360; + }; + + _facingAway = false; + if (_testDirection > 90 && _testDirection < 270) then { + _facingAway = true; + }; + + if (_facingAway) then { + _direction = _roadSegmentDirection + 180; + } + else { + _direction = _roadSegmentDirection; + }; + + _posX = (getPos _spawnSegment) select 0; + _posY = (getPos _spawnSegment) select 1; + + _posX = _posX + 2.5 * sin (_direction + 90); + _posY = _posY + 2.5 * cos (_direction + 90); + _pos = [_posX, _posY, 0]; + + // Create vehicle + _vehicleType = _possibleVehicles select floor (random count _possibleVehicles); + //_result = [_pos, _direction, _vehicleType, _side] call BIS_fnc_spawnVehicle; + + _vehicleGroup = createGroup _side; + // Run spawn script and attach handle to vehicle + [_vehicleType,_vehicleGroup] call _fnc_CreateVehicleCrew; + + _result = [_pos, _direction, _vehicleType, _vehicleGroup] call BIS_fnc_spawnVehicle; + _vehicle = _result select 0; + _vehiclesCrew = _result select 1; + _vehiclesGroup = _result select 2; + + // Name vehicle + sleep random 0.05; + if (isNil "dre_MilitaryTraffic_CurrentEntityNo") then { + dre_MilitaryTraffic_CurrentEntityNo = 0 + }; + + _currentEntityNo = dre_MilitaryTraffic_CurrentEntityNo; + dre_MilitaryTraffic_CurrentEntityNo = dre_MilitaryTraffic_CurrentEntityNo + 1; + + _vehicleVarName = "dre_MilitaryTraffic_Entity_" + str _currentEntityNo; + _vehicle setVehicleVarName _vehicleVarName; + _vehicle call compile format ["%1=_this;", _vehicleVarName]; + + // Set crew skill + { + _skill = _minSkill + random (_maxSkill - _minSkill); + _x setSkill _skill; + } foreach _vehiclesCrew; + + _debugMarkerName = "dre_MilitaryTraffic_DebugMarker" + str _currentEntityNo; + + //_vehicle setDir _direction; + + // Start vehicle + [_vehicle, _destinationPos, _debug] spawn ENGIMA_TRAFFIC_MoveVehicle; + _activeVehiclesAndGroup set [count _activeVehiclesAndGroup, [_vehicle, _vehiclesGroup, _vehiclesCrew, _debugMarkerName]]; + + // Run spawn script and attach handle to vehicle + _vehicle setVariable ["dre_scriptHandle2", _result spawn _fnc_OnSpawnVehicle]; + + if (_debug) then { + ["Vehicle '" + vehicleVarName _vehicle + "' created! Total vehicles = " + str count _activeVehiclesAndGroup] call ENGIMA_TRAFFIC_ShowDebugTextAllClients; + }; + } + else { + _tries = _tries + 1; + }; + }; + + _firstIteration = false; + + if (_debug) then { + { + private ["_debugMarkerColor"]; + + _vehicle = _x select 0; + _group = _x select 1; + _debugMarkerName = _x select 3; + _side = side _group; + + _debugMarkerColor = "Default"; + if (_side == west) then { + _debugMarkerColor = "ColorBlue"; + }; + if (_side == east) then { + _debugMarkerColor = "ColorRed"; + }; + if (_side == civilian) then { + _debugMarkerColor = "ColorYellow"; + }; + if (_side == resistance) then { + _debugMarkerColor = "ColorGreen"; + }; + + [_debugMarkerName, getPos (_vehicle), "mil_dot", _debugMarkerColor, "Traffic"] call ENGIMA_TRAFFIC_SetDebugMarkerAllClients; + + } foreach _activeVehiclesAndGroup; + }; + + // If any vehicle is too far away, delete it + _tempVehiclesAndGroup = []; + _deletedVehiclesCount = 0; + { + private ["_closestUnitDistance", "_distance", "_crewUnits"]; + private ["_scriptHandle"]; + + _vehicle = _x select 0; + _group = _x select 1; + _crewUnits = _x select 2; + _debugMarkerName = _x select 3; + + _closestUnitDistance = 1000000; + + { + _distance = (_x distance _vehicle); + if (_distance < _closestUnitDistance) then { + _closestUnitDistance = _distance; + }; + } foreach _allPlayerPositions; + + if (_closestUnitDistance < _maxSpawnDistance) then { + _tempVehiclesAndGroup set [count _tempVehiclesAndGroup, _x]; + } + else { + // Run callback before deleting + _vehicle call _fnc_OnRemoveVehicle; + + // Delete crew + { + deleteVehicle _x; + } foreach _crewUnits; + + // Terminate script before deleting the vehicle + _scriptHandle = _vehicle getVariable "dre_scriptHandle"; + if (!(scriptDone _scriptHandle)) then { + terminate _scriptHandle; + }; + + + deleteVehicle _vehicle; + deleteGroup _group; + + [_debugMarkerName] call ENGIMA_TRAFFIC_DeleteDebugMarkerAllClients; + _deletedVehiclesCount = _deletedVehiclesCount + 1; + + if (_debug) then { + ["Vehicle deleted! Total vehicles = " + str (count _activeVehiclesAndGroup - _deletedVehiclesCount)] call ENGIMA_TRAFFIC_ShowDebugTextAllClients + }; + }; + } foreach _activeVehiclesAndGroup; + + _activeVehiclesAndGroup = _tempVehiclesAndGroup; + + sleep 1; + }; +}; + +ENGIMA_TRAFFIC_functionsInitialized = true; diff --git a/Engima/Traffic/setVehicleLightHit.sqf b/Engima/Traffic/setVehicleLightHit.sqf new file mode 100644 index 00000000..026c1088 --- /dev/null +++ b/Engima/Traffic/setVehicleLightHit.sqf @@ -0,0 +1,21 @@ +private ["_object","_sPos","_tPos","_bullet","_bPos","_heading","_velocity"]; + +_object = _this select 0; // In this case a named object but can be determined via nearestBuilding or other similar methods. +_side = _this select 1; + +_sPosR = _object selectionPosition "Light_R"; // The selection position of the center of the main light in model space. +_sPosL = _object selectionPosition "Light_L"; +if (_side == "left") then { +_tPos = _object modelToWorld _sPosR; // The center of the main light in world space. +} else { +_tPos = _object modelToWorld _sPosR; +}; + +//Run a loop that creates a .50cal bullets and directs it to hit the light + +_bullet = "B_127x99_Ball" createVehicle _tPos; +_bPos = getPosASL _bullet; +_heading = [_bPos,_tPos] call BIS_fnc_vectorFromXToY; +_velocity = [_heading, 1000] call BIS_fnc_vectorMultiply; +_bullet setVectorDir _heading; +_bullet setVelocity _velocity; \ No newline at end of file diff --git a/init.sqf b/init.sqf index 6ec2b30e..f39b7ab8 100644 --- a/init.sqf +++ b/init.sqf @@ -88,7 +88,10 @@ if (!isMultiplayer) then { // Editor /* {_x disableAI "MOVE"} forEach allUnits;*/ }; +call compile preprocessfile "Engima\Traffic\Custom_GruppeAdler\createVehicle.sqf"; +call compile preprocessfile "Engima\Traffic\Custom_GruppeAdler\randomCivilian.sqf"; +[] execVM "Engima\Traffic\Init.sqf"; if (isServer) then { // allow view distance to be up to 10k