Last active
May 19, 2025 01:45
-
-
Save thegamecracks/9f564b8d4901ddd3902a20aeafc4dfef to your computer and use it in GitHub Desktop.
A proof-of-concept approximation of missile notching in Arma 3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| TGC_fnc_getAbsClosureSpeed = { | |
| params ["_observer", "_target"]; | |
| private _dir = getPosATL _target vectorFromTo getPosATL _observer; | |
| private _velocity = velocity _target; | |
| private _angle = vectorNormalized _velocity vectorDotProduct _dir; | |
| vectorMagnitude (_velocity vectorMultiply _angle) | |
| }; | |
| TGC_fnc_isRadarGuided = { | |
| params ["_ammo"]; | |
| private _property = configFile >> "CfgAmmo" >> _ammo >> "weaponLockSystem"; | |
| getNumber _property isEqualTo 8 || {"8" in getTextRaw _property} | |
| }; | |
| TGC_missiles = []; | |
| TGC_icon_vehicles = vehicles select {someAmmo _x}; | |
| TGC_notch_closure = 200 / 3.6; // Maximum closure speed required to break lock | |
| TGC_notch_duration = 2; // Approximate duration required to break lock | |
| TGC_notch_height = -50; // Minimum height difference required to break lock | |
| // Consider adding a EntityCreated mission event handler here | |
| { | |
| _x addEventHandler ["Fired", { | |
| params ["", "", "", "", "_ammo", "", "_projectile", "_vehicle"]; | |
| if !(_ammo isKindOf "MissileBase") exitWith {}; | |
| TGC_missiles pushBack _projectile; | |
| // For testing convenience | |
| if (local _vehicle) then {_vehicle setVehicleAmmo 1}; | |
| }]; | |
| } forEach vehicles; | |
| addMissionEventHandler ["Draw3D", { | |
| private _vehicle = objectParent focusOn; | |
| if (isNull _vehicle) exitWith {}; | |
| private _threats = getSensorThreats _vehicle; | |
| private _markingThreats = _threats select {_x # 1 == "marked"} apply {vehicle (_x # 0)}; | |
| private _lockingThreats = _threats select {_x # 1 == "locked"} apply {vehicle (_x # 0)}; | |
| { | |
| if (!alive _x) then {continue}; | |
| if (_x isEqualTo _vehicle) then {continue}; | |
| private _closure = [_x, _vehicle] call TGC_fnc_getAbsClosureSpeed; | |
| private _color = switch (true) do { | |
| case (_x in _markingThreats): {[1, 0.9, 0, 1]}; | |
| case (_x in _lockingThreats): {[1, 0.5, 0, 1]}; | |
| default {[1, 1, 1, 1]}; | |
| }; | |
| drawIcon3D [ | |
| getTextRaw (configOf _x >> "icon"), | |
| _color, | |
| getPosATL _x, | |
| 1, | |
| 1, | |
| 0, | |
| format [ | |
| "%1 km/h, %2km at %3m", | |
| _closure * 3.6 toFixed 0, | |
| (_vehicle distance _x) / 1000 toFixed 1, | |
| getPos _x # 2 max 0 toFixed 0 | |
| ], | |
| 2, | |
| 0.05 | |
| ]; | |
| } forEach TGC_icon_vehicles; | |
| { | |
| if (!alive _x) then {continue}; | |
| private _closure = [_x, _vehicle] call TGC_fnc_getAbsClosureSpeed; | |
| private _distance = _vehicle distance _x; | |
| private _scale = linearConversion [100, 2000, _distance, 2, 0.5, true]; | |
| private _locked = missileTarget _x isEqualTo _vehicle; | |
| private _color = if (_locked) then {[1, 0, 0, 1]} else {[0, 1, 0, 1]}; | |
| private _started = _x getVariable "TGC_notch_started"; | |
| private _text = format [ | |
| "%1 km/h, %2km at %3m%4%5", | |
| _closure * 3.6 toFixed 0, | |
| _distance / 1000 toFixed 1, | |
| getPos _x # 2 max 0 toFixed 0, | |
| endl, | |
| if (isNil "_started") then {""} else {format ["%1s", time - _started toFixed 1]} | |
| ]; | |
| drawIcon3D [ | |
| "a3\ui_f\data\igui\cfg\cursors\explosive_ca.paa", | |
| _color, | |
| getPosATL _x, | |
| _scale, | |
| _scale, | |
| time * 720, | |
| _text, | |
| 2, | |
| 0.05 | |
| ]; | |
| } forEach TGC_missiles; | |
| }]; | |
| TGC_missileNotchScript = 0 spawn {while {true} do { | |
| private _deadIndexes = []; | |
| { | |
| if (!alive _x) then {_deadIndexes pushBack _forEachIndex; continue}; | |
| private _target = missileTarget _x; | |
| if (isNull _target) then {continue}; | |
| if (!local _target) then {continue}; | |
| if !(typeOf _x call TGC_fnc_isRadarGuided) then {continue}; | |
| // Check that vehicle is notching the missile | |
| private _closure = [_x, _target] call TGC_fnc_getAbsClosureSpeed; | |
| if (_closure > TGC_notch_closure) then { | |
| _x setVariable ["TGC_notch_started", nil]; | |
| continue; | |
| }; | |
| // Check that missile is looking towards ground (cheap heuristic) | |
| private _altitudeDiff = getPos _x # 2 - getPos _target # 2; | |
| if (_altitudeDiff <= TGC_notch_height) then { | |
| _x setVariable ["TGC_notch_started", nil]; | |
| continue; | |
| }; | |
| if (isNil {_x getVariable "TGC_notch_started"}) then { | |
| _x setVariable ["TGC_notch_started", time]; | |
| continue; | |
| }; | |
| private _started = _x getVariable "TGC_notch_started"; | |
| if (time - _started < TGC_notch_duration) then {continue}; | |
| [_x, objNull] remoteExec ["setMissileTarget", _x]; | |
| } forEach TGC_missiles; | |
| {TGC_missiles deleteAt _x} forEachReversed _deadIndexes; | |
| sleep 0.25; | |
| }}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment