From 584be70f9347f4113d6601f612c57d75478781e8 Mon Sep 17 00:00:00 2001 From: Moritz Schmidt Date: Sat, 6 Aug 2022 20:57:56 +0200 Subject: [PATCH] new: local speed limits * add additional config `EGVAR(cars,townSpeedLimit)` * use map locations to determine if a vehicle is in a town * add speed limit zones to diagnostics views * add EGVAR(cars,customSpeedLimits) that may contain speed limits defined by a tuple (Location, number) --- addons/cars/README.md | 18 +++++++-- addons/cars/XEH_PREP.hpp | 3 ++ addons/cars/XEH_postInit.sqf | 19 ++++++++++ .../functions/fnc_determineSpeedLimits.sqf | 6 +++ .../functions/fnc_determineTownLocations.sqf | 10 +++++ addons/cars/functions/fnc_initConfig.sqf | 13 ++++++- addons/cars/functions/fnc_pfh_speedLimit.sqf | 19 ++++++++++ addons/cars/functions/fnc_spawnVehicle.sqf | 2 +- addons/diagnostics/README.md | 6 ++- addons/diagnostics/XEH_PREP.hpp | 2 + .../functions/fnc_drawSpeedLimitsOnMap.sqf | 37 +++++++++++++++++++ .../diagnostics/functions/fnc_initConfig.sqf | 12 +++++- .../functions/fnc_showInfoLine.sqf | 8 +++- .../functions/fnc_showSpeedLimitsOnMap.sqf | 22 +++++++++++ .../fnc_sm_business_state_transit_loop.sqf | 2 - .../fnc_sm_business_state_voyage_loop.sqf | 2 - 16 files changed, 169 insertions(+), 12 deletions(-) create mode 100644 addons/cars/functions/fnc_determineSpeedLimits.sqf create mode 100644 addons/cars/functions/fnc_determineTownLocations.sqf create mode 100644 addons/cars/functions/fnc_pfh_speedLimit.sqf create mode 100644 addons/diagnostics/functions/fnc_drawSpeedLimitsOnMap.sqf create mode 100644 addons/diagnostics/functions/fnc_showSpeedLimitsOnMap.sqf diff --git a/addons/cars/README.md b/addons/cars/README.md index 421bdf4d..838c2f7d 100644 --- a/addons/cars/README.md +++ b/addons/cars/README.md @@ -1,6 +1,6 @@ # grad\_civs\_cars -Basic handling of civs driving cars. +Basic handling of civs driving cars. As a user, see transit and voyage modules to actually get civs driving on the streets. @@ -12,6 +12,8 @@ animalTransportChance | 0.4 | Probability that a suitable vehicle w animalTransportVehicles | [] | optional list of class names whitelisting vehicles that are allowed to carry animals automaticVehicleGroupSize| 1 | Allow vehicles to be filled according to capacity, ignoring *initialGroupSize* (0,1). vehicles | ["C_Van_01_fuel_F", "C_Hatchback_01_F", "C_Offroad_02_unarmed_F", "C_Truck_02_fuel_F", "C_Truck_02_covered_F", "C_Offroad_01_F", "C_SUV_01_F", "C_Van_01_transport_F", "C_Van_01_box_F"] | All classnames of vehicles that civilians may drive. +globalSpeedLimit | 50 | Speed limit for civilian vehicles in km/h +townSpeedLimit | 30 | Speed limit for civilian vehicles in km/h while in the area of a city or village Location ## API @@ -35,13 +37,23 @@ vehicles | Array - All classnames of vehicles that civilians may drive. #### grad_civs_cars_car_added -```sqf +```sqf ["grad_civs_cars_car_added", { params ["_vehicle"]; }] call CBA_fnc_addEventHandler; ``` #### grad_civs_cars_vehKilled -```sqf +```sqf ["grad_civs_cars_vehKilled", { params ["_deathPos", "_killer", "_vehicle"]; }] call CBA_fnc_addEventHandler; ``` + +### Global variables + +#### grad_civs_cars_customSpeedLimits + +You may define speed limits by setting the `grad_civs_cars_customSpeedLimits` array. + +Each entry must be an array with two entries: a [Location](https://community.bistudio.com/wiki/Location) and a number (the speed limit in km/h). + +This array must be local on the machines running the civs, i.e. server and/or headless clients. diff --git a/addons/cars/XEH_PREP.hpp b/addons/cars/XEH_PREP.hpp index 774fb786..c2add8c0 100644 --- a/addons/cars/XEH_PREP.hpp +++ b/addons/cars/XEH_PREP.hpp @@ -1,8 +1,11 @@ +PREP(determineTownLocations); +PREP(determineSpeedLimits); PREP(dismountCondition); PREP(getGlobalVehicles); PREP(getGroupVehicle); PREP(initConfig); PREP(loadAnimals); +PREP(pfh_speedLimit); PREP(setGroupVehicle); PREP(setVehicles); PREP(sm_business_state_dismount_enter); diff --git a/addons/cars/XEH_postInit.sqf b/addons/cars/XEH_postInit.sqf index d32d016b..f8e93d14 100644 --- a/addons/cars/XEH_postInit.sqf +++ b/addons/cars/XEH_postInit.sqf @@ -5,5 +5,24 @@ if (isServer || CBA_isHeadlessClient) then { ["business", ["bus_rally"], FUNC(sm_business)] call EFUNC(common,augmentStateMachine); + + ISNILS(GVAR(pfh_speedLimit_interval), EGVAR(lifecycle,minCivUpdateTime)); + GVAR(pfh_speedLimit) = [FUNC(pfh_speedLimit), GVAR(pfh_speedLimit_interval)] call CBA_fnc_addPerFrameHandler; + + ISNILS(GVAR(localCars), []); + [QGVAR(car_added), { + params ["_veh"]; + if (local _veh) then { + GVAR(localCars) pushBackUnique _veh; + }; + }] call CBA_fnc_addEventHandler; + [QGVAR(vehKilled), { + params ["_veh"]; + GVAR(localCars) = GVAR(localCars) - [_veh]; + }] call CBA_fnc_addEventHandler; + GVAR(pfh_groomCarsArray) = [{ + GVAR(localCars) = GVAR(localCars) select {!(isNull _x)}; + }, 5] call CBA_fnc_addPerFrameHandler; + }; }] call CBA_fnc_addEventHandler; diff --git a/addons/cars/functions/fnc_determineSpeedLimits.sqf b/addons/cars/functions/fnc_determineSpeedLimits.sqf new file mode 100644 index 00000000..41e71784 --- /dev/null +++ b/addons/cars/functions/fnc_determineSpeedLimits.sqf @@ -0,0 +1,6 @@ +#include "..\script_component.hpp" + +ISNILS(GVAR(customSpeedLimits), []); // Array<(Location, number)> +ISNILS(GVAR(townSpeedLimits), ([] call FUNC(determineTownLocations)) apply {[ARR_2(_x, GVAR(townSpeedLimit))]}); + +GVAR(townSpeedLimits) + GVAR(customSpeedLimits) diff --git a/addons/cars/functions/fnc_determineTownLocations.sqf b/addons/cars/functions/fnc_determineTownLocations.sqf new file mode 100644 index 00000000..96362542 --- /dev/null +++ b/addons/cars/functions/fnc_determineTownLocations.sqf @@ -0,0 +1,10 @@ +#include "..\script_component.hpp" + +private _radius = worldSize / 2; +private _center = [_radius, _radius]; +private _townLocationTypes = ["NameCity", "NameCityCapital", "NameVillage", "FlatAreaCity", "FlatAreaCitySmall"]; +nearestLocations [ + _center, + _townLocationTypes, + _radius +] diff --git a/addons/cars/functions/fnc_initConfig.sqf b/addons/cars/functions/fnc_initConfig.sqf index 446a3fea..2eca7b9a 100644 --- a/addons/cars/functions/fnc_initConfig.sqf +++ b/addons/cars/functions/fnc_initConfig.sqf @@ -59,7 +59,18 @@ private _settingsGroup = ["GRAD Civilians", "7) cars - basic settings for civili "SLIDER", "Vehicle speed limit in km/h", _settingsGroup, - [-1, 360, 50, 0, false], + [0, 360, 50, 0, false], + false, + {}, + false +] call CBA_fnc_addSetting; + +[ + QGVAR(townSpeedLimit), + "SLIDER", + "Vehicle speed limit within towns in km/h", + _settingsGroup, + [0, 360, 30, 0, false], false, {}, false diff --git a/addons/cars/functions/fnc_pfh_speedLimit.sqf b/addons/cars/functions/fnc_pfh_speedLimit.sqf new file mode 100644 index 00000000..67174ffd --- /dev/null +++ b/addons/cars/functions/fnc_pfh_speedLimit.sqf @@ -0,0 +1,19 @@ +#include "..\script_component.hpp" + +private _speedLimits = call FUNC(determineSpeedLimits); + +{ + _x setVariable [QGVAR(speedLimit), GVAR(globalSpeedLimit)]; +} forEach GVAR(localCars); + +{ + _x params ["_location", "_speedLimit"]; + private _affectedCars = GVAR(localCars) inAreaArray _location; + { + _x setVariable [QGVAR(speedLimit), _speedLimit]; + } forEach _affectedCars; +} forEach _speedLimits; + +{ + _x limitSpeed (_x getVariable [QGVAR(speedLimit), GVAR(globalSpeedLimit)]); +} forEach GVAR(localCars); diff --git a/addons/cars/functions/fnc_spawnVehicle.sqf b/addons/cars/functions/fnc_spawnVehicle.sqf index ac0db053..4706f1be 100644 --- a/addons/cars/functions/fnc_spawnVehicle.sqf +++ b/addons/cars/functions/fnc_spawnVehicle.sqf @@ -28,7 +28,7 @@ _veh addEventHandler [ { params ["_unit", "_killer"]; - ["grad_civs_cars_vehKilled", [getPos _unit, _killer, _unit]] call CBA_fnc_globalEvent; + [QGVAR(vehKilled), [getPos _unit, _killer, _unit]] call CBA_fnc_globalEvent; } ]; diff --git a/addons/diagnostics/README.md b/addons/diagnostics/README.md index c2423b4e..3717eea4 100644 --- a/addons/diagnostics/README.md +++ b/addons/diagnostics/README.md @@ -1,6 +1,8 @@ # grad\_civs\_diagnostics -Debugging GUI stuff +Debugging GUI stuff. + +A lot of it only works in Singleplayer, as much of the relevant data is local where the civs are, and they're local on server or HCs. ## Settings @@ -11,4 +13,6 @@ showFps | false | Show server & HC fps showOnMap | false | Show civs on map showInfoLine | false | Show detailed info line on civilian showPinkArrows | false | Create 3D arrows over civ heads +showSpawnAttempts | false | Show short-lived markers on map to debug spawning +showSpeedLimitsOnMap | false | Show locations + corresponding speed limit on map showMisc | false | Miscellaneous stuff diff --git a/addons/diagnostics/XEH_PREP.hpp b/addons/diagnostics/XEH_PREP.hpp index 95cb1af6..4bca801c 100644 --- a/addons/diagnostics/XEH_PREP.hpp +++ b/addons/diagnostics/XEH_PREP.hpp @@ -1,4 +1,5 @@ PREP(drawFlyScarePoly); +PREP(drawSpeedLimitsOnMap); PREP(initConfig); PREP(showFps); PREP(showFlyScarePoly); @@ -14,5 +15,6 @@ PREP(showPinkArrows_arrowDelete); PREP(showPinkArrows_arrowEnsure); PREP(showPointingHints); PREP(showSpawnAttempts); +PREP(showSpeedLimitsOnMap); PREP(tempMarker); PREP(updateInfoLine); diff --git a/addons/diagnostics/functions/fnc_drawSpeedLimitsOnMap.sqf b/addons/diagnostics/functions/fnc_drawSpeedLimitsOnMap.sqf new file mode 100644 index 00000000..3a90360f --- /dev/null +++ b/addons/diagnostics/functions/fnc_drawSpeedLimitsOnMap.sqf @@ -0,0 +1,37 @@ +#include "..\script_component.hpp" + +params [ + ["_mode", "update", [""]] +]; + +ISNILS(GVAR(speedLimitMarkers), []); +{ + deleteMarkerLocal _x; +} forEach GVAR(speedLimitMarkers); +GVAR(speedLimitMarkers) = []; + +if (_mode == "delete") exitWith {}; + +private _speedLimits = call EFUNC(cars,determineSpeedLimits); + +{ + _x params ["_location", "_speedLimit"]; + + private _circle = createMarkerLocal [format ["speed_limit_town_%1_circle", _forEachIndex], position _location]; + _circle setMarkerShapeLocal "ELLIPSE"; + _circle setMarkerSizeLocal (size _location); + _circle setMarkerBrushLocal "SolidBorder"; + _circle setMarkerColorLocal "ColorBlue"; + _circle setMarkerAlphaLocal 0.5; + + private _text = createMarkerLocal [format ["speed_limit_town_%1_text", _forEachIndex], position _location]; + _text setMarkerShapeLocal "ICON"; + _text setMarkerTypeLocal "mil_circle_noShadow"; + _text setMarkerColorLocal "ColorBlue"; + _text setMarkerTextLocal (format ["%1 km/h", _speedLimit]); + + + GVAR(speedLimitMarkers) pushBack _circle; + GVAR(speedLimitMarkers) pushBack _text; + +} forEach _speedLimits; diff --git a/addons/diagnostics/functions/fnc_initConfig.sqf b/addons/diagnostics/functions/fnc_initConfig.sqf index b809dc70..22c57768 100644 --- a/addons/diagnostics/functions/fnc_initConfig.sqf +++ b/addons/diagnostics/functions/fnc_initConfig.sqf @@ -59,6 +59,17 @@ private _settingsGroup = ["GRAD Civilians", "c) diagnostics - debugging info"]; false ] call CBA_fnc_addSetting; +[ + QGVAR(showSpeedLimitsOnMap), + "CHECKBOX", + "Show speed limits on map", + _settingsGroup, + false, + false, + FUNC(showSpeedLimitsOnMap), + false +] call CBA_fnc_addSetting; + [ QGVAR(showMisc), "CHECKBOX", @@ -70,7 +81,6 @@ private _settingsGroup = ["GRAD Civilians", "c) diagnostics - debugging info"]; { deleteVehicle _x } forEach GVAR(dangerPolyGroundHelpers); [] call FUNC(showHonkAtArea); [] call FUNC(showFlyScarePoly); - }, false ] call CBA_fnc_addSetting; diff --git a/addons/diagnostics/functions/fnc_showInfoLine.sqf b/addons/diagnostics/functions/fnc_showInfoLine.sqf index d6049f58..c54c72b6 100644 --- a/addons/diagnostics/functions/fnc_showInfoLine.sqf +++ b/addons/diagnostics/functions/fnc_showInfoLine.sqf @@ -40,7 +40,13 @@ ISNILS(GVAR(userActionIds), []); private _driver = driver _veh; if ((_veh != _x) && (_driver != _x)) exitWith { "x" }; - format["%1 | %2km/h in speedmode: %3 %4", _x, round speed _veh, speedMode _x, if (leader _x == _x) then {"(is leader)"} else {""}]; + format["%1 | %2 / %3 km/h in speedmode: %4 %5", + _x, + round speed _veh, + round (_veh getVariable [QEGVAR(cars,speedLimit), -1]), + speedMode _x, + if (leader _x == _x) then {"(is leader)"} else {""} + ]; }; case 3: {format["%1 | %2 guns point at him", _x, _x getVariable [QEGVAR(interact,pointedAtCount), 0]]}; case 4: {format["%1 | is local at %2", _x, _x getVariable [QGVAR(localAt), 0]]}; diff --git a/addons/diagnostics/functions/fnc_showSpeedLimitsOnMap.sqf b/addons/diagnostics/functions/fnc_showSpeedLimitsOnMap.sqf new file mode 100644 index 00000000..0e3ae1f2 --- /dev/null +++ b/addons/diagnostics/functions/fnc_showSpeedLimitsOnMap.sqf @@ -0,0 +1,22 @@ +#include "..\script_component.hpp" + +ISNILS(GVAR(speedLimitsPfh), -1); + +if (!GVAR(showSpeedLimitsOnMap)) exitWith { + [GVAR(speedLimitsPfh)] call CBA_fnc_removePerFrameHandler; + GVAR(speedLimitsPfh) = -1; + ["delete"] call FUNC(drawSpeedLimitsOnMap); +}; + +if (GVAR(speedLimitsPfh) != -1) exitWith { + WARNING("showSpeedLimitsOnMap already has pfh, not adding another one"); +}; + +GVAR(speedLimitsPfh) = [ + { + if (!isGameFocused || isGamePaused) exitWith {}; + ["update"] call FUNC(drawSpeedLimitsOnMap); + }, + 2, + [] +] call CBA_fnc_addPerFrameHandler; diff --git a/addons/transit/functions/fnc_sm_business_state_transit_loop.sqf b/addons/transit/functions/fnc_sm_business_state_transit_loop.sqf index 1cad9112..95b27f07 100644 --- a/addons/transit/functions/fnc_sm_business_state_transit_loop.sqf +++ b/addons/transit/functions/fnc_sm_business_state_transit_loop.sqf @@ -9,5 +9,3 @@ if (isNull _group) exitWith { private _livedAs = _this getVariable ["grad_civs_livedAs", str _this]; WARNING_5("unit %1 (type %2) in voyage loop has no group. will ignore. alive %3 index %4 pos %5", _livedAs, typeof _this, alive _this, EGVAR(lifecycle,localCivs) find _this, getPos _this); }; - -(vehicle _this) limitSpeed EGVAR(cars,globalSpeedLimit); diff --git a/addons/voyage/functions/fnc_sm_business_state_voyage_loop.sqf b/addons/voyage/functions/fnc_sm_business_state_voyage_loop.sqf index b07e60ed..efa50c78 100644 --- a/addons/voyage/functions/fnc_sm_business_state_voyage_loop.sqf +++ b/addons/voyage/functions/fnc_sm_business_state_voyage_loop.sqf @@ -5,5 +5,3 @@ if (isNull _group) exitWith { private _livedAs = _this getVariable ["grad_civs_livedAs", str _this]; WARNING_5("unit %1 (type %2) in voyage loop has no group. will ignore. alive %3 index %4 pos %5", _livedAs, typeof _this, alive _this, EGVAR(lifecycle,localCivs) find _this, getPos _this); }; - -(vehicle _this) limitSpeed EGVAR(cars,globalSpeedLimit);