mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
Zeus Suppression Module (#4977)
* add base structure * Add getModuleDestination * Add 2d map support, debug * Cleanup, handle weapon max range * Handle non-local units * Use new showMessage func * Run on groups when placed on leader * Support for Indirect Fire Vehicles * Cleanup * Use doArtilleryFire which was fixed in 1.68
This commit is contained in:
parent
08217f460e
commit
b3f03d5ffb
@ -160,6 +160,12 @@ class CfgVehicles {
|
||||
displayName = CSTRING(ModuleSearchNearby_DisplayName);
|
||||
function = QFUNC(moduleSearchNearby);
|
||||
};
|
||||
class GVAR(moduleSuppressiveFire): GVAR(moduleBase) {
|
||||
curatorCanAttach = 1;
|
||||
category = QGVAR(AI);
|
||||
displayName = CSTRING(ModuleSuppressiveFire_DisplayName);
|
||||
function = QFUNC(moduleSuppressiveFire);
|
||||
};
|
||||
class GVAR(moduleSetMedic): GVAR(moduleBase) {
|
||||
curatorCanAttach = 1;
|
||||
category = QGVAR(Medical);
|
||||
|
@ -4,6 +4,7 @@ PREP(bi_moduleCurator);
|
||||
PREP(bi_moduleMine);
|
||||
PREP(bi_moduleProjectile);
|
||||
PREP(bi_moduleRemoteControl);
|
||||
PREP(getModuleDestination);
|
||||
PREP(handleZeusUnitAssigned);
|
||||
PREP(moduleAddSpareTrack);
|
||||
PREP(moduleAddSpareWheel);
|
||||
@ -16,6 +17,8 @@ PREP(moduleSetMedic);
|
||||
PREP(moduleSetMedicalVehicle);
|
||||
PREP(moduleSetMedicalFacility);
|
||||
PREP(moduleSimulation);
|
||||
PREP(moduleSuppressiveFire);
|
||||
PREP(moduleSuppressiveFireLocal);
|
||||
PREP(moduleSurrender);
|
||||
PREP(moduleTeleportPlayers);
|
||||
PREP(moduleUnconscious);
|
||||
|
@ -14,6 +14,7 @@ QGVAR(GlobalSkillAI) addPublicVariableEventHandler FUNC(moduleGlobalSetSkill);
|
||||
[QGVAR(modulePatrolArea), CBA_fnc_taskPatrol] call CBA_fnc_addEventHandler;
|
||||
[QGVAR(moduleSearchNearby), CBA_fnc_searchNearby] call CBA_fnc_addEventHandler;
|
||||
[QGVAR(moduleSearchArea), CBA_fnc_taskSearchArea] call CBA_fnc_addEventHandler;
|
||||
[QGVAR(suppressiveFire), LINKFUNC(moduleSuppressiveFireLocal)] call CBA_fnc_addEventHandler;
|
||||
|
||||
// Editable object commands must be ran on server, this events are used in the respective module
|
||||
if (isServer) then {
|
||||
|
@ -12,6 +12,7 @@ class CfgPatches {
|
||||
QGVAR(moduleSearchArea),
|
||||
QGVAR(moduleSearchNearby),
|
||||
QGVAR(moduleSimulation),
|
||||
QGVAR(moduleSuppressiveFire),
|
||||
QGVAR(moduleTeleportPlayers)
|
||||
};
|
||||
weapons[] = {};
|
||||
|
79
addons/zeus/functions/fnc_getModuleDestination.sqf
Normal file
79
addons/zeus/functions/fnc_getModuleDestination.sqf
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Author: PabstMirror
|
||||
* Allows zeus to click to indicate a 3d position.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: The souce object <OBJECT>
|
||||
* 1: Code to run when position is ready <CODE>
|
||||
* - Code is passed [0: Successful <BOOL>, 1: Object <OBJECT>, 2: Position ASL <ARRAY>]
|
||||
* 2: Text <STRING><OPTIONAL>
|
||||
* 3: Icon image file <STRING><OPTIONAL>
|
||||
* 4: Icon color <ARRAY><OPTIONAL>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [player, {systemChat format ["Done %1", _this]}] call ace_zeus_fnc_getModuleDestination
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_object", "_code", ["_text", ""], ["_icon", "\a3\ui_f\data\IGUI\Cfg\Cursors\select_target_ca.paa"], ["_color", [1,0,0,1]]];
|
||||
|
||||
if (missionNamespace getVariable [QGVAR(moduleDestination_running), false]) exitWith {
|
||||
[false, _object, [0,0,0]] call _code;
|
||||
ERROR("getModuleDestination already running");
|
||||
};
|
||||
|
||||
GVAR(moduleDestination_running) = true;
|
||||
|
||||
// Add mouse button eh for the zeus display (triggered from 2d or 3d)
|
||||
GVAR(moduleDestination_displayEH) = [(findDisplay 312), "mouseButtonDown", {
|
||||
params ["", "_mouseButton"];
|
||||
if (_mouseButton != 0) exitWith {}; // Only watch for LMB
|
||||
_thisArgs params ["_object", "_code"];
|
||||
private _mousePosASL = if (ctrlShown ((findDisplay 312) displayCtrl 50)) then {
|
||||
private _pos2d = (((findDisplay 312) displayCtrl 50) ctrlMapScreenToWorld getMousePosition);
|
||||
_pos2d set [2, getTerrainHeightASL _pos2d];
|
||||
_pos2d
|
||||
} else {
|
||||
AGLToASL (screenToWorld getMousePosition);
|
||||
};
|
||||
TRACE_2("placed",_object,_mousePosASL);
|
||||
[true, _object, _mousePosASL] call _code;
|
||||
GVAR(moduleDestination_running) = false;
|
||||
}, [_object, _code]] call CBA_fnc_addBISEventHandler;
|
||||
|
||||
// Add draw eh for the zeus map - draws the 2d icon and line
|
||||
GVAR(moduleDestination_mapDrawEH) = [((findDisplay 312) displayCtrl 50), "draw", {
|
||||
params ["_mapCtrl"];
|
||||
_thisArgs params ["_object", "_text", "_icon", "_color"];
|
||||
|
||||
private _pos2d = (((findDisplay 312) displayCtrl 50) ctrlMapScreenToWorld getMousePosition);
|
||||
_mapCtrl drawIcon [_icon, _color, _pos2d, 24, 24, 45, _text, 1, 0.03, "TahomaB", "right"];
|
||||
_mapCtrl drawLine [getPos _object, _pos2d, _color];
|
||||
}, [_object, _text, _icon, _color]] call CBA_fnc_addBISEventHandler;
|
||||
|
||||
[{
|
||||
(_this select 0) params ["_object", "_code", "_text", "_icon", "_color"];
|
||||
if ((isNull _object) || {isNull findDisplay 312} || {!isNull findDisplay 49}) then {
|
||||
TRACE_3("null-exit",isNull _object,isNull findDisplay 312,isNull findDisplay 49);
|
||||
GVAR(moduleDestination_running) = false;
|
||||
[false, _object, [0,0,0]] call _code;
|
||||
};
|
||||
if (GVAR(moduleDestination_running)) then {
|
||||
// Draw the 3d icon and line
|
||||
private _mousePosAGL = screenToWorld getMousePosition;
|
||||
drawIcon3D [_icon, _color, _mousePosAGL, 1.5, 1.5, 45, _text];
|
||||
drawLine3D [_mousePosAGL, ASLtoAGL (getPosASL _object), _color];;
|
||||
} else {
|
||||
TRACE_3("cleaning up",_this select 1, GVAR(moduleDestination_displayEH), GVAR(moduleDestination_mapDrawEH));
|
||||
(_this select 1) call CBA_fnc_removePerFrameHandler;
|
||||
(findDisplay 312) displayRemoveEventHandler ["mouseButtonDown", GVAR(moduleDestination_displayEH)];
|
||||
((findDisplay 312) displayCtrl 50) ctrlRemoveEventHandler ["draw", GVAR(moduleDestination_mapDrawEH)];
|
||||
GVAR(moduleDestination_displayEH) = nil;
|
||||
GVAR(moduleDestination_mapDrawEH) = nil;
|
||||
};
|
||||
}, 0, [_object, _code, _text, _icon, _color]] call CBA_fnc_addPerFrameHandler;
|
117
addons/zeus/functions/fnc_moduleSuppressiveFire.sqf
Normal file
117
addons/zeus/functions/fnc_moduleSuppressiveFire.sqf
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Author: bux, PabstMirror
|
||||
* Commands the selected unit or group to start suppressive fire on the unit, group or location the module is placed on
|
||||
*
|
||||
* Arguments:
|
||||
* 0: The module logic <OBJECT>
|
||||
* 1: Synchronized units <ARRAY>
|
||||
* 2: Activated <BOOL>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
// #define DRAW_ZEUS_INFO
|
||||
#include "script_component.hpp"
|
||||
|
||||
if (canSuspend) exitWith {[FUNC(moduleSuppressiveFire), _this] call CBA_fnc_directCall;};
|
||||
|
||||
params ["_logic", "_units", "_activated"];
|
||||
|
||||
if !(_activated && local _logic) exitWith {};
|
||||
|
||||
// Validate the module target
|
||||
private _unit = effectiveCommander (attachedTo _logic);
|
||||
TRACE_3("moduleSuppressiveFire placed",_unit,typeOf _unit,typeOf _logic);
|
||||
|
||||
deleteVehicle _logic; // cleanup logic now, we just needed it to get the attached unit
|
||||
|
||||
if (isNull _unit) exitWith {
|
||||
[LSTRING(NothingSelected)] call FUNC(showMessage);
|
||||
};
|
||||
if (!alive _unit) exitWith {
|
||||
[localize LSTRING(OnlyAlive)] call FUNC(showMessage);
|
||||
};
|
||||
if ([_unit] call EFUNC(common,isPlayer)) exitWith {
|
||||
["str_a3_cfgvehicles_moduleremotecontrol_f_errorPlayer"] call FUNC(showMessage);
|
||||
};
|
||||
|
||||
[_unit, {
|
||||
params ["_successful", "_unit", "_mousePosASL"];
|
||||
TRACE_3("getModuleDestination return",_successful,_unit,_mousePosASL);
|
||||
if (!_successful) exitWith {};
|
||||
if (!alive _unit) exitWith {};
|
||||
private _vehicle = vehicle _unit;
|
||||
|
||||
private _targetASL = _mousePosASL vectorAdd [0,0,0.6]; // mouse pos is at ground level zero, raise up a bit;
|
||||
private _artilleryMag = "";
|
||||
|
||||
if ((getNumber (configFile >> "CfgVehicles" >> (typeOf _vehicle) >> "artilleryScanner")) == 1) then {
|
||||
// Artillery - Get mortar ammo type and verify in range
|
||||
if (isNull gunner _vehicle) exitWith {_targetASL = [];};
|
||||
{
|
||||
private _ammo = getText (configFile >> "CfgMagazines" >> _x >> "ammo");
|
||||
private _hit = getNumber (configFile >> "CfgAmmo" >> _ammo >> "hit");
|
||||
if (_hit > 20) exitWith {_artilleryMag = _x;};
|
||||
} forEach getArtilleryAmmo [_vehicle];
|
||||
TRACE_1("getArtilleryAmmo",_artilleryMag);
|
||||
if (_artilleryMag == "") exitWith {_targetASL = [];};
|
||||
private _eta = _vehicle getArtilleryETA [ASLtoAGL _targetASL, _artilleryMag];
|
||||
TRACE_1("getArtilleryETA",_eta);
|
||||
if (_eta < 0) exitWith {
|
||||
[ELSTRING(Interaction,NotInRange)] call FUNC(showMessage);
|
||||
_targetASL = [];
|
||||
};
|
||||
["TOF: %1 sec", _eta toFixed 1] call FUNC(showMessage);
|
||||
} else {
|
||||
// Direct fire - Get a target position that will work
|
||||
private _lis = lineIntersectsSurfaces [eyePos _unit, _targetASL, _unit, _vehicle];
|
||||
if ((count _lis) > 0) then { // If point is hidden, unit won't fire, do a ray cast to find where they should shoot at
|
||||
_targetASL = ((_lis select 0) select 0);
|
||||
TRACE_1("using ray cast pos",_mousePosASL distance _targetASL);
|
||||
};
|
||||
if (_unit isEqualTo _vehicle) then { // Max range a unit can fire seems to be based on the weapon's config
|
||||
private _distance = _targetASL vectorDistance eyePos _unit;
|
||||
private _maxWeaponRange = getNumber (configFile >> "CfgWeapons" >> (currentWeapon _unit) >> "maxRange");
|
||||
TRACE_3("",_distance,_maxWeaponRange,currentWeapon _unit);
|
||||
if (_distance > (_maxWeaponRange - 50)) then {
|
||||
if (_distance > (2.5 * _maxWeaponRange)) then {
|
||||
_targetASL = [];
|
||||
[ELSTRING(Interaction,NotInRange)] call FUNC(showMessage);
|
||||
} else {
|
||||
// 1-2.5x the weapon max range, find a virtual point the AI can shoot at (won't have accurate elevation, but it will put rounds downrange)
|
||||
private _fakeElevation = (_distance / 100000) * (_distance - _maxWeaponRange);
|
||||
_targetASL = (eyePos _unit) vectorAdd (((eyePos _unit) vectorFromTo _targetASL) vectorMultiply (_maxWeaponRange - 50)) vectorAdd [0,0,_fakeElevation];
|
||||
TRACE_2("using virtual halfway point",_mousePosASL distance _targetASL,_fakeElevation);
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
if (_targetASL isEqualTo []) exitWith {};
|
||||
|
||||
private _units = [_unit];
|
||||
if (_unit == (leader _unit)) then {_units = units _unit;};
|
||||
if (_artilleryMag != "") then {_units = [gunner _vehicle];};
|
||||
|
||||
{
|
||||
if (((_unit distance _x) < 30) && {!([_x] call EFUNC(common,isPlayer))} && {[_x] call EFUNC(common,isAwake)}) then {
|
||||
TRACE_2("sending event",_x,_targetASL);
|
||||
[QGVAR(suppressiveFire), [_x, _targetASL, _artilleryMag], _x] call CBA_fnc_targetEvent;
|
||||
};
|
||||
} forEach _units;
|
||||
|
||||
#ifdef DRAW_ZEUS_INFO
|
||||
[eyePos _unit, _mousePosASL, [0,0,1,1]] call EFUNC(common,addLineToDebugDraw);
|
||||
[eyePos _unit, _targetASL, [1,0,0,1]] call EFUNC(common,addLineToDebugDraw);
|
||||
if (_unit != _vehicle) then {
|
||||
[_vehicle] call CBA_fnc_addUnitTrackProjectiles;
|
||||
} else {
|
||||
{
|
||||
[_x] call CBA_fnc_addUnitTrackProjectiles;
|
||||
} forEach _units;
|
||||
};
|
||||
#endif
|
||||
|
||||
}, (localize LSTRING(ModuleSuppressiveFire_DisplayName))] call FUNC(getModuleDestination);
|
39
addons/zeus/functions/fnc_moduleSuppressiveFireLocal.sqf
Normal file
39
addons/zeus/functions/fnc_moduleSuppressiveFireLocal.sqf
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Author: bux, PabstMirror
|
||||
* Commands the selected unit or group to start suppressive fire on the unit, group or location the module is placed on
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Unit <OBJECT>
|
||||
* 1: Fire Pos ASL <ARRAY>
|
||||
* 2: Artiller Magazine <STRING>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_unit", "_targetASL", "_artilleryMag"];
|
||||
TRACE_4("moduleSuppressiveFireLocal",_unit,local _unit,_targetASL,_artilleryMag);
|
||||
|
||||
if (_artilleryMag != "") exitWith {
|
||||
(vehicle _unit) doArtilleryFire [ASLtoAGL _targetASL, _artilleryMag, 4];
|
||||
TRACE_3("doArtilleryFire",_unit,_targetASL,_artilleryMag);
|
||||
};
|
||||
|
||||
[{
|
||||
params ["_unit", "_burstsLeft", "_nextRun", "_targetASL", "_artilleryMag"];
|
||||
if (!alive _unit) exitWith {true};
|
||||
if (CBA_missionTime >= _nextRun) then {
|
||||
_burstsLeft = _burstsLeft - 1;
|
||||
_this set [1, _burstsLeft];
|
||||
_this set [2, _nextRun + 4];
|
||||
_unit doSuppressiveFire _targetASL;
|
||||
TRACE_2("doSuppressiveFire",_unit,_targetASL);
|
||||
};
|
||||
(_burstsLeft <= 0)
|
||||
}, {
|
||||
TRACE_1("Done",_this);
|
||||
}, [_unit, 11, CBA_missionTime, _targetASL, _artilleryMag]] call CBA_fnc_waitUntilAndExecute;
|
||||
|
@ -822,5 +822,8 @@
|
||||
<German>Ungültiger Radius eingegeben</German>
|
||||
<Korean>알 수 없는 반경 입력됨</Korean>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Zeus_ModuleSuppressiveFire_DisplayName">
|
||||
<English>Suppressive Fire</English>
|
||||
</Key>
|
||||
</Package>
|
||||
</Project>
|
||||
|
Loading…
Reference in New Issue
Block a user