diff --git a/Project_0.Altis/GameMode/GameModeBase.sqf b/Project_0.Altis/GameMode/GameModeBase.sqf index fb8530ea4..7da2aa5ac 100644 --- a/Project_0.Altis/GameMode/GameModeBase.sqf +++ b/Project_0.Altis/GameMode/GameModeBase.sqf @@ -145,7 +145,6 @@ CLASS("GameModeBase", "") private _cmdr = CALL_STATIC_METHOD("AICommander", "getCommanderAIOfSide", [_side]); if(!IS_NULL_OBJECT(_cmdr)) then { - OOP_DEBUG_MSG("founc cmdr %1 for loc %2", [_cmdr ARG _loc]); CALLM(_cmdr, "registerLocation", [_loc]); private _gar = T_CALLM("initGarrison", [_loc ARG _side]); @@ -158,8 +157,23 @@ CLASS("GameModeBase", "") }; }; - // Send intel to commanders private _type = GETV(_loc, "type"); + private _radius = GETV(_loc, "boundingRadius"); + + // Create vehicles in civilian area for player to steal + if(_type == LOCATION_TYPE_CITY) then { + private _gar = NEW("Garrison", [CIVILIAN]); + private _maxCars = 3 max (25 min (0.03 * _radius)); + for "_i" from 0 to _maxCars do { + private _newUnit = NEW("Unit", [tCIVILIAN ARG T_VEH ARG T_VEH_DEFAULT ARG -1 ARG ""]); + CALLM(_gar, "addUnit", [_newUnit]); + }; + CALLM1(_gar, "setLocation", _loc); + CALLM1(_loc, "registerGarrison", _gar); + CALLM0(_gar, "activate"); + }; + + // Send intel to commanders { private _sideCommander = GETV(_x, "side"); if (_sideCommander != WEST) then { // Enemies are smart diff --git a/Project_0.Altis/Garrison/Garrison.sqf b/Project_0.Altis/Garrison/Garrison.sqf index 4ad930563..8f1ede92f 100644 --- a/Project_0.Altis/Garrison/Garrison.sqf +++ b/Project_0.Altis/Garrison/Garrison.sqf @@ -333,9 +333,10 @@ CLASS("Garrison", "MessageReceiverEx"); // Check spawn state if active if (T_GETV("active")) then { - T_CALLM("updateSpawnState", []); + T_CALLM("updateSpawnState", []); + // If we are empty except for vehicles then we must abandon them - if(T_CALLM("isOnlyEmptyVehicles", [])) then { + if(T_GETV("side") != CIVILIAN and {T_CALLM("isOnlyEmptyVehicles", [])}) then { OOP_INFO_MSG("This garrison only has vehicles left, abandoning them", []); // Move the units to the abandoned vehicle garrison CALLM(gGarrisonAbandonedVehicles, "addGarrison", [_thisObject]); @@ -1771,7 +1772,6 @@ CLASS("Garrison", "MessageReceiverEx"); if(IS_GARRISON_DESTROYED(_thisObject)) exitWith { WARN_GARRISON_DESTROYED; __MUTEX_UNLOCK; - +T_EFF_null }; // Call handleUnitKilled of the group of this unit @@ -1823,7 +1823,6 @@ CLASS("Garrison", "MessageReceiverEx"); if(IS_GARRISON_DESTROYED(_thisObject)) exitWith { WARN_GARRISON_DESTROYED; __MUTEX_UNLOCK; - +T_EFF_null }; // Get garrison of the unit that entered the vehicle diff --git a/Project_0.Altis/Garrison/updateSpawnState.sqf b/Project_0.Altis/Garrison/updateSpawnState.sqf index 91de21660..84d913ff0 100644 --- a/Project_0.Altis/Garrison/updateSpawnState.sqf +++ b/Project_0.Altis/Garrison/updateSpawnState.sqf @@ -31,7 +31,11 @@ pr _thisPos = if (_loc == "") then { pr _speedMax = 200; // Get distances to all garrisons of other sides -pr _garrisonDist = CALL_STATIC_METHOD("Garrison", "getAllActive", [[] ARG [_side]]) apply {CALLM(_x, "getPos", []) distance _thisPos}; +pr _garrisonDist = if(_side != CIVILIAN) then { + CALL_STATIC_METHOD("Garrison", "getAllActive", [[] ARG [_side ARG CIVILIAN]]) apply {CALLM(_x, "getPos", []) distance _thisPos} + } else { + [] + }; pr _dstMin = if (count _garrisonDist > 0) then {selectMin _garrisonDist} else {_dstSpawnMax}; // Double check unit distances as well if(_dstMin >= _dstSpawnMax) then { diff --git a/Project_0.Altis/JeroenArsenal/Fuel/fn_fuel_addActionRefuel.sqf b/Project_0.Altis/JeroenArsenal/Fuel/fn_fuel_addActionRefuel.sqf index 5e6003070..7b22e0eae 100644 --- a/Project_0.Altis/JeroenArsenal/Fuel/fn_fuel_addActionRefuel.sqf +++ b/Project_0.Altis/JeroenArsenal/Fuel/fn_fuel_addActionRefuel.sqf @@ -20,7 +20,7 @@ params["_vehicle","_fuelCargoCapacity",["_fuelCargo",0]]; //check if it already has a action -if !isnil(_vehicle getVariable "refuelAction_id")exitWith{diag_log ("JN_fuel already init for object: "+str _vehicle)}; +if (!isnil{ _vehicle getVariable "refuelAction_id" }) exitWith{diag_log ("JN_fuel already init for object: "+str _vehicle)}; pr _id = _vehicle addaction [ "place holder", diff --git a/Project_0.Altis/Location/Location.sqf b/Project_0.Altis/Location/Location.sqf index e85a04e05..420a84357 100644 --- a/Project_0.Altis/Location/Location.sqf +++ b/Project_0.Altis/Location/Location.sqf @@ -509,6 +509,8 @@ CLASS("Location", "MessageReceiverEx") Returns: Array, [_pos, _dir] */ + #define ROAD_DIR_LIMIT 15 + STATIC_METHOD("findSafePosOnRoad") { params ["_thisClass", ["_startPos", [], [[]]], ["_className", "", [""]] ]; @@ -530,34 +532,32 @@ CLASS("Location", "MessageReceiverEx") private _rct = roadsConnectedTo _road; // TODO: we can preprocess spawn locations better than this probably. // Need a connected road (this is guaranteed probably?) - if (count _rct > 0 and - // Avoid spawning on a person or another car - {count (nearestObjects [getPos _road, ["LandVehicle", "Man"], 10]) == 0} and - // Avoid spawning too close to a junction - {{ count (roadsConnectedTo _x) > 2} count ((getPos _road) nearRoads 10) == 0}) then { // We better don't use terminal road pieces - - // Check position if it's safe - private _dir = _road getDir (_rct select 0); - // Get Z component of ATL height from two nearest road pieces - // private _z0 = (getPosASL (_rct select 0)) select 2; - // private _z1 = (getPosASL (_rct select 1)) select 2; - // private _posRoad = getPosASL _road; - //_posRoad set [2, 0.5*(_z0 + _z1)]; - //_posRoad = ASLToATL _posRoad; - private _posRoad = getPos _road; - - private _foundSafePos = []; - for "_offs" from 2 to 8 step 2 do { - // Find offset position away from center of road - private _spawnPos = [_posRoad, _offs, _dir + 90] call BIS_Fnc_relPos; - if(!CALLSM3("Location", "isPosSafe", _spawnPos, _dir, _className)) exitWith {}; - _foundSafePos = _spawnPos; - }; - - //diag_log format ["--- road: %1, pos atl: %2", _road, getPosATL _road]; - if (!(_foundSafePos isEqualTo [])) then { - _return = [_foundSafePos, _dir]; - _found = true; + // Avoid spawning too close to a junction + if(count _rct > 0) then { + private _dir = _road getDir _rct#0; + if ({ + private _rctOther = roadsConnectedTo _x; + if(count _rctOther == 0) exitWith { false }; + private _dirOther = _x getDir _rctOther#0; + private _relDir = _dir - _dirOther; + if(_relDir < 0) then { _relDir = _relDir + 360 }; + (_relDir > ROAD_DIR_LIMIT and _relDir < 180-ROAD_DIR_LIMIT) or (_relDir > 180+ROAD_DIR_LIMIT and _relDir < 360-ROAD_DIR_LIMIT) + } count ((getPos _road) nearRoads 25) == 0) then { + // Check position if it's safe + + private _width = [_road, 1, 8] call misc_fnc_getRoadWidth; + // Move to the edge + private _pos = [getPos _road, _width - 3, _dir + (selectRandom [90, 270]) ] call BIS_Fnc_relPos; + // Move up and down the street a bit + _pos = [_pos, _width * 0.5, _dir + (selectRandom [0, 180]) ] call BIS_Fnc_relPos; + // Perturb the direction a bit + private _dirPert = _dir + random [-20, 0, 20] + (selectRandom [0, 180]); + // Perturb the position a bit + private _posPert = _pos vectorAdd [random [-1, 0, 1], random [-1, 0, 1], 0]; + if(CALLSM3("Location", "isPosEvenSafer", _posPert, _dirPert, _className)) then { + _return = [_posPert, _dirPert]; + _found = true; + }; }; }; _i = _i + 1; @@ -585,12 +585,12 @@ CLASS("Location", "MessageReceiverEx") Returns: [_pos, _dir] */ STATIC_METHOD("findSafeSpawnPos") { - params ["_thisObject", ["_className", "", [""]], ["_startPos", [], [[]]]]; + params ["_thisClass", ["_className", "", [""]], ["_startPos", [], [[]]]]; private _found = false; private _searchRadius = 50; - pr _posAndDir = []; - while {!_found} do { + pr _posAndDir = [_startPos, 0]; + while {!_found and _searchRadius < 2000} do { for "_i" from 0 to 16 do { pr _pos = _startPos vectorAdd [-_searchRadius + random(2*_searchRadius), -_searchRadius + random(2*_searchRadius), 0]; if (CALLSM3("Location", "isPosSafe", _pos, 0, _className) && ! (surfaceIsWater _pos)) exitWith { @@ -701,6 +701,10 @@ CLASS("Location", "MessageReceiverEx") // Checks if given position is safe to spawn a vehicle here STATIC_METHOD_FILE("isPosSafe", "Location\isPosSafe.sqf"); + // Checks if given position is even safer to spawn a vehicle here (conservative, doesn't allow spawning + // in buildings etc.) + STATIC_METHOD_FILE("isPosEvenSafer", "Location\isPosEvenSafer.sqf"); + // Returns the nearest location to given position and distance to it STATIC_METHOD_FILE("getNearestLocation", "Location\getNearestLocation.sqf"); diff --git a/Project_0.Altis/Location/getSpawnPos.sqf b/Project_0.Altis/Location/getSpawnPos.sqf index e3d68e1d5..56d79d104 100644 --- a/Project_0.Altis/Location/getSpawnPos.sqf +++ b/Project_0.Altis/Location/getSpawnPos.sqf @@ -136,9 +136,13 @@ if(_found) then {//If the spawn position has been found _return = [ ( _locPos vectorAdd [-_r + (random (2*_r)), -_r + (random (2*_r)), 0] ), 0]; OOP_WARNING_MSG("[Location::getSpawnPos] Warning: spawn position not found for unit: %1. Returning default position.", [_catID ARG _subcatID ARG _groupType]); } else { - // Try to find a safe position on a road for this vehicle + // Try to find a random safe position on a road for this vehicle private _locPos = GET_VAR(_thisObject, "pos"); - _return = CALLSM2("Location", "findSafePosOnRoad", _locPos, _className); + private _locRadius = GET_VAR(_thisObject, "boundingRadius"); + private _testPos = [_locPos, _locRadius min random [0, 0, _locRadius*5], random 360] call BIS_fnc_relPos; + // DUMP_CALLSTACK; + // [[[_locPos, _locRadius]],[]] call BIS_fnc_randomPos; + _return = CALLSM2("Location", "findSafePosOnRoad", _testPos, _className); }; }; diff --git a/Project_0.Altis/Location/isPosEvenSafer.sqf b/Project_0.Altis/Location/isPosEvenSafer.sqf new file mode 100644 index 000000000..de5b600fe --- /dev/null +++ b/Project_0.Altis/Location/isPosEvenSafer.sqf @@ -0,0 +1,66 @@ +// Class: Location +/* +Method: (static)isPosEvenSafer +Returns true if the place is guaranteed safe for spawning specific vehicle. +It is very conservative and as such will disallow spawning in buildings or too close +to existing objects. + +Parameters: _pos, _dir, _className +_pos - position ATL +_dir - direction +_className - vehicle class name + +Returns: Bool + +Author: Sparker 29.07.2018 +*/ + +//#define DEBUG + +pr0_fn_getGlobalRectAndSize = { + params [["_pos", [], [[]]], ["_dir", 0, [0]], ["_bbox", [], [[]]] ]; + + private _bx = _bbox select 1 select 0; //width + private _by = _bbox select 1 select 1; //length + private _bz = _bbox select 1 select 2; //height + + private _c = cos _dir; + private _s = sin _dir; + + private _posASL = ATLTOASL _pos; + private _pos_0 = _posASL vectorAdd [_bx*_c + _by*_s, -_bx*_s + _by*_c, 0]; + private _pos_1 = _posASL vectorAdd [_bx*_c - _by*_s, -_bx*_s - _by*_c, 0]; + private _pos_2 = _posASL vectorAdd [-_bx*_c - _by*_s, _bx*_s - _by*_c, 0]; + private _pos_3 = _posASL vectorAdd [-_bx*_c + _by*_s, _bx*_s + _by*_c, 0]; + private _rect = [_pos_0, _pos_1, _pos_2, _pos_3]; + [_rect, [_bx, _by, _bz]] +}; + +params [ ["_thisClass", "", [""]], ["_pos", [], [[]]], ["_dir", 0, [0]], ["_className", "", [""]] ]; + +// Bail if Z is below surface, as it happens with positions of bridges +if (_pos#2 < -0.3) exitWith { + false +}; + +([ + _pos, _dir, + [_className] call misc_fnc_boundingBoxReal +] call pr0_fn_getGlobalRectAndSize) params ["_rect3D", "_size"]; + +// TODO: expand the class set here? +private _o = nearestObjects [_pos, [], 15, true] - (_pos nearRoads 15); + +_o findIf { + #ifndef _SQF_VM + private _bbox = 0 boundingBoxReal _x; + #else + private _bbox = [[0,0,0],[1,1,1],1]; + #endif + ([getPos _x, getDir _x, _bbox] call pr0_fn_getGlobalRectAndSize) params ["_oRect3D", "_oSize"]; + if(_oSize#2 > 0.3) then { + [_rect3D, _oRect3D] call misc_fnc_polygonCollision + } else { + false + } +} == -1 diff --git a/Project_0.Altis/Misc/Math/fn_polygonCollision.sqf b/Project_0.Altis/Misc/Math/fn_polygonCollision.sqf new file mode 100644 index 000000000..6e462460d --- /dev/null +++ b/Project_0.Altis/Misc/Math/fn_polygonCollision.sqf @@ -0,0 +1,45 @@ +// See https://gist.github.com/nyorain/dc5af42c6e83f7ac6d831a2cfd5fbece +private _fn_separatedPolys = { + params ["_a", "_b"]; + private _result = false; + for "_i" from 0 to (count _a - 1) do + { + // calculate the normal vector of the current edge + // this is the axis will we check in this loop + private _current = _a select _i; + private _next = _a select ((_i + 1) % count _a); + private _edge = [_next#0 - _current#0, _next#1 - _current#1]; + private _axis = [-(_edge#1), _edge#0]; + + // loop over all vertices of both polygons and project them + // onto the axis. We are only interested in max/min projections + private _aMaxProj = -1000000; + private _aMinProj = 1000000; + private _bMaxProj = -1000000; + private _bMinProj = 1000000; + + { + private _proj = _axis#0 * _x#0 + _axis#1 * _x#1; + _aMinProj = _aMinProj min _proj; + _aMaxProj = _aMaxProj max _proj; + } forEach _a; + + { + private _proj = _axis#0 * _x#0 + _axis#1 * _x#1; + _bMinProj = _bMinProj min _proj; + _bMaxProj = _bMaxProj max _proj; + } forEach _b; + + // now check if the intervals the both polygons projected on the + // axis overlap. If they don't, we have found an axis of separation and + // the given polygons cannot overlap + if(_aMaxProj < _bMinProj or _aMinProj > _bMaxProj) exitWith { + _result = true; + }; + }; + _result +}; + +params ["_a", "_b"]; + +!(([_a, _b] call _fn_separatedPolys) or {([_b, _a] call _fn_separatedPolys)}) \ No newline at end of file diff --git a/Project_0.Altis/Misc/initFunctions.sqf b/Project_0.Altis/Misc/initFunctions.sqf index 6f8beb1ab..e76a910b4 100644 --- a/Project_0.Altis/Misc/initFunctions.sqf +++ b/Project_0.Altis/Misc/initFunctions.sqf @@ -13,4 +13,6 @@ misc_fnc_mapDrawLineLocal = compile preprocessFileLineNumbers "Misc\fn_mapDrawLi misc_fnc_dateToNumber = compile preprocessFileLineNumbers "Misc\fn_dateToNumber.sqf"; misc_fnc_getRoadDirection = compile preprocessFileLineNumbers "Misc\fn_getRoadDirection.sqf"; -misc_fnc_getRoadWidth = compile preprocessFileLineNumbers "Misc\fn_getRoadWidth.sqf"; \ No newline at end of file +misc_fnc_getRoadWidth = compile preprocessFileLineNumbers "Misc\fn_getRoadWidth.sqf"; + +misc_fnc_polygonCollision = compile preprocessFileLineNumbers "Misc\Math\fn_polygonCollision.sqf"; \ No newline at end of file diff --git a/Project_0.Altis/Templates/CIVILIAN.sqf b/Project_0.Altis/Templates/CIVILIAN.sqf new file mode 100644 index 000000000..7fa4838e9 --- /dev/null +++ b/Project_0.Altis/Templates/CIVILIAN.sqf @@ -0,0 +1,164 @@ +/* +POLICE templates for ARMA III +*/ + +// //==== Infantry ==== +// _inf = []; +// _inf set [T_INF_SIZE-1, nil]; //Make an array full of nil +// _inf set [T_INF_DEFAULT, ["B_GEN_Soldier_F"]]; //Default infantry if nothing is found + +// _inf set [T_INF_SL, ["B_Captain_Dwarden_F"]]; +// _inf set [T_INF_TL, ["B_Captain_Dwarden_F"]]; +// _inf set [T_INF_officer, ["B_GEN_Commander_F"]]; +// _inf set [T_INF_GL, ["B_GEN_Soldier_F"]]; +// _inf set [T_INF_rifleman, ["B_GEN_Soldier_F"]]; +// _inf set [T_INF_marksman, ["B_GEN_Soldier_F"]]; +// _inf set [T_INF_sniper, ["B_GEN_Soldier_F"]]; +// _inf set [T_INF_spotter, ["B_GEN_Soldier_F"]]; +// _inf set [T_INF_exp, ["B_GEN_Soldier_F"]]; +// _inf set [T_INF_ammo, ["B_GEN_Soldier_F"]]; +// _inf set [T_INF_LAT, ["B_GEN_Soldier_F"]]; +// _inf set [T_INF_AT, ["B_GEN_Soldier_F"]]; +// _inf set [T_INF_AA, ["B_GEN_Soldier_F"]]; +// _inf set [T_INF_LMG, ["B_GEN_Soldier_F"]]; +// _inf set [T_INF_HMG, ["B_GEN_Soldier_F"]]; +// _inf set [T_INF_medic, ["B_GEN_Soldier_F"]]; +// _inf set [T_INF_engineer, ["B_GEN_Soldier_F"]]; +// _inf set [T_INF_crew, ["B_GEN_Soldier_F"]]; +// _inf set [T_INF_crew_heli, ["B_GEN_Soldier_F"]]; +// _inf set [T_INF_pilot, ["B_GEN_Soldier_F"]]; +// _inf set [T_INF_pilot_heli, ["B_GEN_Soldier_F"]]; +// _inf set [T_INF_survivor, ["B_GEN_Soldier_F"]]; +// _inf set [T_INF_unarmed, ["B_GEN_Soldier_F"]]; + +//==== Vehicles ==== +_veh = []; +_veh set [T_VEH_SIZE-1, nil]; +_veh set [T_VEH_default, [ + "C_Hatchback_01_sport_F", + "C_Hatchback_01_F", + "C_Truck_02_box_F", + "C_Truck_02_fuel_F", + "C_Offroad_02_unarmed_F", + "C_Van_01_fuel_F", + "C_Truck_02_transport_F", + "C_Truck_02_covered_F", + "C_Offroad_01_F", + "C_Offroad_01_repair_F", + "C_Quadbike_01_F", + "C_SUV_01_F", + "C_Van_01_transport_F", + "C_Van_02_medevac_F", + "C_Van_02_vehicle_F", + "C_Van_02_service_F", + "C_Van_02_transport_F" +]]; +_vehWeights = []; +_vehWeights set [T_VEH_SIZE-1, nil]; +_vehWeights set [T_VEH_default, [ + 5, /* "C_Hatchback_01_sport_F" */ + 20, /* "C_Hatchback_01_F" */ + 3, /* "C_Truck_02_box_F" */ + 0.1, /* "C_Truck_02_fuel_F" */ + 10, /* "C_Offroad_02_unarmed_F" */ + 0.1, /* "C_Van_01_fuel_F" */ + 3, /* "C_Truck_02_transport_F" */ + 3, /* "C_Truck_02_covered_F" */ + 5, /* "C_Offroad_01_F" */ + 0.1, /* "C_Offroad_01_repair_F" */ + 1, /* "C_Quadbike_01_F" */ + 3, /* "C_SUV_01_F" */ + 1, /* "C_Van_01_transport_F" */ + 1, /* "C_Van_02_medevac_F" */ + 1, /* "C_Van_02_vehicle_F" */ + 1, /* "C_Van_02_service_F" */ + 1 /* "C_Van_02_transport_F" */ +]]; +// _veh set [T_VEH_car_unarmed, ["B_MRAP_01_F"]]; +// _veh set [T_VEH_car_armed, ["B_MRAP_01_hmg_F"]]; +// _veh set [T_VEH_MRAP_unarmed, ["B_MRAP_01_F"]]; +// _veh set [T_VEH_MRAP_HMG, ["B_MRAP_01_hmg_F"]]; +// _veh set [T_VEH_MRAP_GMG, ["B_MRAP_01_gmg_F"]]; +// _veh set [T_VEH_IFV, ["B_APC_Wheeled_01_cannon_F"]]; //Marshal IFV +// _veh set [T_VEH_APC, ["B_APC_Tracked_01_rcws_F"]]; //Panther +// _veh set [T_VEH_MBT, ["B_MBT_01_cannon_F", "B_MBT_01_TUSK_F"]]; +// _veh set [T_VEH_MRLS, ["B_MBT_01_mlrs_F"]]; +// _veh set [T_VEH_SPA, ["B_MBT_01_arty_F"]]; +// _veh set [T_VEH_SPAA, ["B_APC_Tracked_01_AA_F"]]; +// _veh set [T_VEH_stat_HMG_high, ["B_HMG_01_high_F"]]; +// _veh set [T_VEH_stat_GMG_high, ["B_GMG_01_high_F"]]; +// _veh set [T_VEH_stat_HMG_low, ["B_HMG_01_F"]]; +// _veh set [T_VEH_stat_GMG_low, ["B_GMG_01_F"]]; +// _veh set [T_VEH_stat_AA, ["B_static_AA_F"]]; +// _veh set [T_VEH_stat_AT, ["B_static_AT_F"]]; +// _veh set [T_VEH_stat_mortar_light, ["B_Mortar_01_F"]]; +// //_veh set [T_VEH_stat_mortar_heavy, ["B_Mortar_01_F"]]; +// _veh set [T_VEH_heli_light, ["B_Heli_Light_01_F"]]; +// _veh set [T_VEH_heli_heavy, ["B_Heli_Transport_01_F"]]; +// _veh set [T_VEH_heli_cargo, ["B_Heli_Transport_03_unarmed_F"]]; +// _veh set [T_VEH_heli_attack, ["B_Heli_Attack_01_dynamicLoadout_F"]]; +// _veh set [T_VEH_plane_attack, ["B_Plane_CAS_01_dynamicLoadout_F"]]; +// _veh set [T_VEH_plane_fighter , ["B_Plane_Fighter_01_F"]]; +// //_veh set [T_VEH_plane_cargo, [" "]]; +// //_veh set [T_VEH_plane_unarmed , [" "]]; +// //_veh set [T_VEH_plane_VTOL, [" "]]; +// _veh set [T_VEH_boat_unarmed, ["B_Boat_Transport_01_F"]]; +// _veh set [T_VEH_boat_armed, ["B_Boat_Armed_01_minigun_F"]]; +// _veh set [T_VEH_personal, ["B_GEN_Offroad_01_gen_F"]]; +// _veh set [T_VEH_truck_inf, ["B_GEN_Van_02_transport_F"]]; +// _veh set [T_VEH_truck_cargo, ["B_GEN_Van_02_vehicle_F"]]; +// _veh set [T_VEH_truck_ammo, ["B_Truck_01_ammo_F"]]; +// _veh set [T_VEH_truck_repair, ["B_Truck_01_Repair_F"]]; +// _veh set [T_VEH_truck_medical , ["B_Truck_01_medical_F"]]; +// _veh set [T_VEH_truck_fuel, ["B_Truck_01_fuel_F"]]; +// _veh set [T_VEH_submarine, ["B_SDV_01_F"]]; + + +// //==== Drones ==== +// _drone = []; +// _drone set [T_DRONE_SIZE-1, nil]; +// _drone set [T_DRONE_DEFAULT, ["O_UAV_01_F"]]; + +// _drone set [T_DRONE_UGV_unarmed, ["O_UGV_01_F"]]; +// _drone set [T_DRONE_UGV_armed, ["O_UGV_01_rcws_F"]]; +// _drone set [T_DRONE_plane_attack, ["O_UAV_02_dynamicLoadout_F"]]; +// //_drone set [T_DRONE_plane_unarmed, ["O_UAV_02_dynamicLoadout_F"]]; +// //_drone set [T_DRONE_heli_attack, ["O_T_UAV_04_CAS_F"]]; +// _drone set [T_DRONE_quadcopter, ["O_UAV_01_F"]]; +// _drone set [T_DRONE_designator, ["O_Static_Designator_02_F"]]; +// _drone set [T_DRONE_stat_HMG_low, ["O_HMG_01_A_F"]]; +// _drone set [T_DRONE_stat_GMG_low, ["O_GMG_01_A_F"]]; +// //_drone set [T_DRONE_stat_AA, ["O_SAM_System_04_F"]]; + + +// //==== Groups ==== +// _group = []; +// _group set [T_GROUP_SIZE-1, nil]; +// _group set [T_GROUP_DEFAULT, [configfile >> "CfgGroups" >> "East" >> "BLU_F" >> "Infantry" >> "Bus_InfSquad"]]; + +// _group set [T_GROUP_inf_AA_team, [configfile >> "CfgGroups" >> "East" >> "OPF_F" >> "Infantry" >> "OIA_InfTeam_AA"]]; +// _group set [T_GROUP_inf_AT_team, [configfile >> "CfgGroups" >> "East" >> "OPF_F" >> "Infantry" >> "OIA_InfTeam_AT"]]; +// _group set [T_GROUP_inf_rifle_squad, [configfile >> "CfgGroups" >> "East" >> "OPF_F" >> "Infantry" >> "OIA_InfSquad"]]; +// _group set [T_GROUP_inf_assault_squad, [configfile >> "CfgGroups" >> "East" >> "OPF_F" >> "Infantry" >> "OIA_InfAssault"]]; +// _group set [T_GROUP_inf_weapons_squad, [configfile >> "CfgGroups" >> "East" >> "OPF_F" >> "Infantry" >> "OIA_InfSquad_Weapons"]]; +// _group set [T_GROUP_inf_fire_team, [configfile >> "CfgGroups" >> "East" >> "OPF_F" >> "Infantry" >> "OIA_InfTeam"]]; +// _group set [T_GROUP_inf_recon_patrol, [configfile >> "CfgGroups" >> "East" >> "OPF_F" >> "Infantry" >> "OI_reconPatrol"]]; +// _group set [T_GROUP_inf_recon_sentry, [configfile >> "CfgGroups" >> "East" >> "OPF_F" >> "Infantry" >> "OI_reconSentry"]]; +// _group set [T_GROUP_inf_recon_squad, [configfile >> "CfgGroups" >> "East" >> "OPF_F" >> "Infantry" >> "OIA_ReconSquad"]]; +// _group set [T_GROUP_inf_recon_team, [configfile >> "CfgGroups" >> "East" >> "OPF_F" >> "Infantry" >> "OI_reconTeam"]]; +// _group set [T_GROUP_inf_sentry, [configfile >> "CfgGroups" >> "East" >> "OPF_F" >> "Infantry" >> "OIA_InfSentry"]]; +// _group set [T_GROUP_inf_sniper_team, [configfile >> "CfgGroups" >> "East" >> "OPF_F" >> "Infantry" >> "OI_SniperTeam"]]; + + +//==== Set arrays ==== +_array = []; + +_array set [T_SIZE*2-1, nil]; //Make an array having the size equal to the number of categories first + +_array set [T_INF, []]; +_array set [T_VEH, _veh]; +_array set [T_DRONE, []]; +_array set [T_GROUP, []]; +_array set [T_VEH+T_WEIGHTS_OFFSET, _vehWeights]; + +_array diff --git a/Project_0.Altis/Templates/fn_selectRandom.sqf b/Project_0.Altis/Templates/fn_selectRandom.sqf index 1850926e9..f365e9bf3 100644 --- a/Project_0.Altis/Templates/fn_selectRandom.sqf +++ b/Project_0.Altis/Templates/fn_selectRandom.sqf @@ -1,3 +1,4 @@ +#include "..\OOP_Light\OOP_Light.h" /* Select a random classname from subcategory from a category from a template array parameters: @@ -32,7 +33,30 @@ else diag_log format ["fn_selectRandom.sqf: Template: subcategory not found: %1 in category: %2", _subcatID, _catID]; _subcat = _cat select 0; //Return default value }; - private _classID = floor (random (count _subcat)); + private _weightsCat = if(count _template > (_catID+T_WEIGHTS_OFFSET)) then { + _template select (_catID+T_WEIGHTS_OFFSET) + } else { + nil + }; + private _weightsSubcat = if(isNil "_weightsCat") then { nil } else { _weightsCat select _subcatID }; + private _classID = if(isNil "_weightsSubcat") then + { + floor (random (count _subcat)) + } + else + { + _subcat find (_subcat selectRandomWeighted _weightsSubcat) + }; + if(_classID == -1) then { + DUMP_CALLSTACK; + diag_log format["RANDOM %1", _this]; + }; + private _class = _subcat select _classID; + if(isNil "_class") then { + DUMP_CALLSTACK; + diag_log format["RANDOM %1", _this]; + }; + // private _classID = floor (random (count _subcat)); [_subcat select _classID, _classID] }; }; diff --git a/Project_0.Altis/Templates/initCategories.sqf b/Project_0.Altis/Templates/initCategories.sqf index 8a7290303..947c9778f 100644 --- a/Project_0.Altis/Templates/initCategories.sqf +++ b/Project_0.Altis/Templates/initCategories.sqf @@ -15,6 +15,7 @@ Author: Sparker 08.2017 */ T_SIZE = 4; //Number of categories in template +T_WEIGHTS_OFFSET = 4; //Number of categories in template T_INF = 0; //The ID of this category T_INF_SIZE = 34; //The size of this category diff --git a/Project_0.Altis/init.sqf b/Project_0.Altis/init.sqf index 95a7f094f..e6d6cee73 100644 --- a/Project_0.Altis/init.sqf +++ b/Project_0.Altis/init.sqf @@ -2,6 +2,8 @@ #define OOP_DEBUG #include "OOP_Light\OOP_Light.h" +#define DEBUG + #ifndef _SQF_VM // No saving enableSaving [ false, false ]; // Saving disabled without autosave. @@ -25,11 +27,11 @@ if (!IS_SERVER) then { // if(true) exitWith {}; // Keep it here in case we want to not start the actual mission but to test some other code if(IS_SERVER) then { gGameModeName = switch (PROFILE_NAME) do { - case "Sparker": { "GameModeRandom" }; - case "billw": { "RedVsGreenGameMode" }; + case "Sparker": { "GameModeRandom" }; + case "billw": { "CivilWarGameMode" }; case "Jeroen not": { "EmptyGameMode" }; - case "Marvis": { "StatusQuoGameMode" }; - default { "CivilWarGameMode" }; + case "Marvis": { "StatusQuoGameMode" }; + default { "CivilWarGameMode" }; }; PUBLIC_VARIABLE "gGameModeName"; } else { @@ -45,4 +47,137 @@ CRITICAL_SECTION { serverInitDone = 1; PUBLIC_VARIABLE "serverInitDone"; -}; \ No newline at end of file +}; + +// pr0_fn_getGlobalRectAndSize = { +// params [["_pos", [], [[]]], ["_dir", 0, [0]], ["_bbox", [], [[]]] ]; + +// private _bx = _bbox select 1 select 0; //width +// private _by = _bbox select 1 select 1; //length +// private _bz = _bbox select 1 select 2; //height + +// private _c = cos _dir; +// private _s = sin _dir; + +// private _posASL = ATLTOASL _pos; +// private _pos_0 = _posASL vectorAdd [_bx*_c + _by*_s, -_bx*_s + _by*_c, 0]; +// private _pos_1 = _posASL vectorAdd [_bx*_c - _by*_s, -_bx*_s - _by*_c, 0]; +// private _pos_2 = _posASL vectorAdd [-_bx*_c - _by*_s, _bx*_s - _by*_c, 0]; +// private _pos_3 = _posASL vectorAdd [-_bx*_c + _by*_s, _bx*_s + _by*_c, 0]; + +// private _color = [1,1,0,1]; +// drawLine3D [ASLToAGL _pos_0, ASLToAGL _pos_1, _color]; +// drawLine3D [ASLToAGL _pos_1, ASLToAGL _pos_2, _color]; +// drawLine3D [ASLToAGL _pos_2, ASLToAGL _pos_3, _color]; +// drawLine3D [ASLToAGL _pos_3, ASLToAGL _pos_0, _color]; +// private _rect = [_pos_0, _pos_1, _pos_2, _pos_3]; +// [_rect, [_bx, _by, _bz]] +// }; + +// fn_isect_update = +// { +// params ["_obj"]; + +// private _pos = getPos _obj; +// private _dir = getDir _obj; +// private _className = typeOf _obj; + +// ([ +// _pos, _dir, +// [_className] call misc_fnc_boundingBoxReal +// ] call pr0_fn_getGlobalRectAndSize) params ["_rect3D", "_size"]; + +// private _o = +// lineIntersectsSurfaces [_rect3D#0, _rect3D#2, _obj, objNull, false]; +// _o append lineIntersectsSurfaces [_rect3D#1, _rect3D#3, _obj, objNull, false]; +// _o append lineIntersectsSurfaces [_rect3D#1, _rect3D#2, _obj, objNull, false]; +// _o append lineIntersectsSurfaces [_rect3D#0, _rect3D#3, _obj, objNull, false]; + +// { +// _x params ["_intersectPosASL", "_surfaceNormal", "_intersectObj", "_parentObject"]; +// drawIcon3D ["\a3\ui_f\data\gui\cfg\hints\BasicLook_ca.paa", [1,1,1,1], ASLToAGL _intersectPosASL, 1, 1, 45, "RayHit", 1, 0.05, "TahomaB"]; +// } forEach _o; + +// private _radius = sqrt (_size#0*_size#0 + _size#1*_size#1); +// private _o = nearestObjects [_pos, [], 15, true] - [_obj] - (_pos nearRoads 15); + +// { +// private _className = typeOf _x; +// private _bbox = +// //if(_className != "") then { +// // [_className] call misc_fnc_boundingBoxReal +// //} else { +// 0 boundingBoxReal _x; +// //}; +// ([getPos _x, getDir _x, _bbox] call pr0_fn_getGlobalRectAndSize) params ["_oRect3D", "_oSize"]; +// if(_oSize#2 > 0.3) then { +// if([_rect3D, _oRect3D] call misc_fnc_polygonCollision) then { +// drawIcon3D ["\a3\ui_f\data\gui\cfg\hints\BasicLook_ca.paa", [1,0.5,0.5,1], ASLToAGL getPosASL _x, 1, 1, 45, +// format["%1 (%2) %3", str _x, typeOf _x, _oSize], 1, 0.05, "TahomaB"]; +// }; +// }; +// } forEach _o; +// }; + + +// // fn_isect_update = { +// // params ["_obj"]; + +// // private _pos = getPos _obj; +// // private _dir = getDir _obj; +// // private _className = typeOf _obj; + +// // private _bb = [_className] call misc_fnc_boundingBoxReal; +// // private _bx = _bb select 1 select 0; //width +// // private _by = _bb select 1 select 1; //lenth +// // private _bz = _bb select 1 select 2; //height + +// // private _c = cos _dir; +// // private _s = sin _dir; + + +// // private _posASL = ATLTOASL _pos; +// // private _pos_0 = _posASL vectorAdd [_bx*_c + _by*_s, -_bx*_s + _by*_c, 1]; +// // private _pos_1 = _posASL vectorAdd [_bx*_c - _by*_s, -_bx*_s - _by*_c, 1]; +// // private _pos_2 = _posASL vectorAdd [-_bx*_c - _by*_s, _bx*_s - _by*_c, 1]; +// // private _pos_3 = _posASL vectorAdd [-_bx*_c + _by*_s, _bx*_s + _by*_c, 1]; + +// // private _posArray = [_pos_0, _pos_1, _pos_2, _pos_3]; + +// // private _color = [1,1,0,1]; +// // drawLine3D [ASLToAGL _pos_0, ASLToAGL _pos_2, _color]; +// // drawLine3D [ASLToAGL _pos_1, ASLToAGL _pos_3, _color]; +// // drawLine3D [ASLToAGL _pos_1, ASLToAGL _pos_2, _color]; +// // drawLine3D [ASLToAGL _pos_0, ASLToAGL _pos_3, _color]; + +// // //Find objects +// // //First check with line intersections +// // private _o = +// // lineIntersectsSurfaces [_pos_0, _pos_2, _obj, objNull, false]; //CF_FIRST_CONTACT + CF_ALL_OBJECTS +// // _o append lineIntersectsSurfaces [_pos_1, _pos_3, _obj, objNull, false]; //CF_FIRST_CONTACT + CF_ALL_OBJECTS +// // _o append lineIntersectsSurfaces [_pos_1, _pos_2, _obj, objNull, false]; //CF_FIRST_CONTACT + CF_ALL_OBJECTS +// // _o append lineIntersectsSurfaces [_pos_0, _pos_3, _obj, objNull, false]; //CF_FIRST_CONTACT + CF_ALL_OBJECTS +// // { +// // _x params ["_intersectPosASL", "_surfaceNormal", "_intersectObj", "_parentObject"]; +// // drawIcon3D ["\a3\ui_f\data\gui\cfg\hints\BasicLook_ca.paa", [1,1,1,1], ASLToAGL _intersectPosASL, 1, 1, 45, "RayHit", 1, 0.05, "TahomaB"]; +// // } forEach _o; + +// // private _radius = sqrt (_bx*_bx + _by*_by); +// // private _o = nearestObjects [_pos, [], (_radius + 1) max 1.7, true] - [_obj]; + +// // // private _collisions = _o select { _x isKindOf "allVehicles" }; +// // { +// // drawIcon3D ["\a3\ui_f\data\gui\cfg\hints\BasicLook_ca.paa", [1,0.5,0.5,1], ASLToAGL getPosASL _x, 1, 1, 45, typeOf _x, 1, 0.05, "TahomaB"]; +// // } forEach _o; +// // }; + +// fn_do_thing = { +// currObj = cursorObject; +// currObj allowDamage false; +// currObj enableSimulation false; +// onEachFrame { +// [currObj] call fn_isect_update; +// }; +// }; + +// player addAction ["dd", fn_do_thing]; \ No newline at end of file diff --git a/Project_0.Altis/initModules.sqf b/Project_0.Altis/initModules.sqf index 69081a08c..fcf8ce1b4 100644 --- a/Project_0.Altis/initModules.sqf +++ b/Project_0.Altis/initModules.sqf @@ -24,6 +24,7 @@ tCSAT = call compile preprocessFileLineNumbers "Templates\CSAT.sqf"; tAAF = call compile preprocessFileLineNumbers "Templates\AAF.sqf"; tGUERILLA = call compile preprocessFileLineNumbers "Templates\GUERILLA.sqf"; tPOLICE = call compile preprocessFileLineNumbers "Templates\POLICE.sqf"; +tCIVILIAN = call compile preprocessFileLineNumbers "Templates\CIVILIAN.sqf"; // Initialize GameModes