|
| 1 | +#include "script_component.hpp" |
| 2 | +/* |
| 3 | + * Author: Ampersand, mharis001 |
| 4 | + * Draws a hint that contains icon and line elements in 2D (Zeus display map) |
| 5 | + * and 3D (in world) for the given duration. |
| 6 | + * |
| 7 | + * Will overwrite an existing hint when called using the same ID. Position |
| 8 | + * arguments can be given as OBJECTs, in which case the hint elements will |
| 9 | + * follow objects as they move and will be hidden if the object is deleted. |
| 10 | + * |
| 11 | + * The visual properties for "ICON" elements are: |
| 12 | + * 0: Position <ARRAY|OBJECT> |
| 13 | + * 1: Icon Texture <STRING> |
| 14 | + * 2: Color (RGBA) <ARRAY> (default: [1, 1, 1, 1]) |
| 15 | + * 3: Scale <NUMBER> (default: 1) |
| 16 | + * 4: Angle <NUMBER> (default: 0) |
| 17 | + * 5: Text <STRING> (default: "") |
| 18 | + * 6: Shadow <NUMBER|BOOL> (default: 0) |
| 19 | + * 7: Text Size <NUMBER> (default: 0.05) |
| 20 | + * 8: Font <STRING> (default: "RobotoCondensed") |
| 21 | + * 9: Align <STRING> (default: "center") |
| 22 | + * |
| 23 | + * The visual properties for "LINE" elements are: |
| 24 | + * 0: Start Position <ARRAY|OBJECT> |
| 25 | + * 1: End Position <ARRAY|OBJECT> |
| 26 | + * 2: Color (RGBA) <ARRAY> (default: [1, 1, 1, 1]) |
| 27 | + * |
| 28 | + * Arguments: |
| 29 | + * 0: Elements <ARRAY> |
| 30 | + * 0: Type <STRING> |
| 31 | + * - either "ICON" or "LINE". |
| 32 | + * 1: Visual Properties <ARRAY> |
| 33 | + * - depends on element type (see above for details). |
| 34 | + * 1: Duration (in seconds) <NUMBER> |
| 35 | + * 2: ID <STRING|OBJECT> (default: "") |
| 36 | + * - an ID is generated when an empty string is given. |
| 37 | + * - in the case of an OBJECT, the hash value is used. |
| 38 | + * |
| 39 | + * Return Value: |
| 40 | + * ID <STRING> |
| 41 | + * |
| 42 | + * Example: |
| 43 | + * [["ICON", [_unit, _texture]], 3] call zen_common_fnc_drawHint |
| 44 | + * |
| 45 | + * Public: No |
| 46 | + */ |
| 47 | + |
| 48 | +#define MAP_ICON_SIZE 24 |
| 49 | + |
| 50 | +params [ |
| 51 | + ["_elements", [], [[]]], |
| 52 | + ["_duration", 0, [0]], |
| 53 | + ["_id", "", ["", objNull]] |
| 54 | +]; |
| 55 | + |
| 56 | +private _ctrlMap = findDisplay IDD_RSCDISPLAYCURATOR displayCtrl IDC_RSCDISPLAYCURATOR_MAINMAP; |
| 57 | + |
| 58 | +// Map of hint IDs and their corresponding draw (2D and 3D) event handler IDs |
| 59 | +if (isNil QGVAR(drawHintMap)) then { |
| 60 | + GVAR(drawHintMap) = createHashMap; |
| 61 | +}; |
| 62 | + |
| 63 | +// Use an object's hash value as its hint ID |
| 64 | +if (_id isEqualType objNull) then { |
| 65 | + _id = hashValue _id; |
| 66 | +}; |
| 67 | + |
| 68 | +// Generate a hint ID if one is not given |
| 69 | +if (_id isEqualTo "") then { |
| 70 | + if (isNil QGVAR(drawHintCounter)) then { |
| 71 | + GVAR(drawHintCounter) = -1; |
| 72 | + }; |
| 73 | + |
| 74 | + GVAR(drawHintCounter) = GVAR(drawHintCounter) + 1; |
| 75 | + |
| 76 | + _id = [CBA_clientID, GVAR(drawHintCounter)] joinString ":"; |
| 77 | +}; |
| 78 | + |
| 79 | +// Remove an existing hint with the same ID |
| 80 | +if (_id in GVAR(drawHintMap)) then { |
| 81 | + GVAR(drawHintMap) deleteAt _id params ["_id2D", "_id3D"]; |
| 82 | + |
| 83 | + _ctrlMap ctrlRemoveEventHandler ["Draw", _id2D]; |
| 84 | + removeMissionEventHandler ["Draw3D", _id3D]; |
| 85 | +}; |
| 86 | + |
| 87 | +// Validate the given hint elements and separate them by type |
| 88 | +private _icons = []; |
| 89 | +private _lines = []; |
| 90 | + |
| 91 | +{ |
| 92 | + _x params [["_type", "", [""]], ["_args", [], [[]]]]; |
| 93 | + |
| 94 | + switch (_type) do { |
| 95 | + case "ICON": { |
| 96 | + _args params [ |
| 97 | + ["_position", [0, 0, 0], [[], objNull], 3], |
| 98 | + ["_icon", "", [""]], |
| 99 | + ["_color", [1, 1, 1, 1], [[]], 4], |
| 100 | + ["_scale", 1, [0]], |
| 101 | + ["_angle", 0, [0]], |
| 102 | + ["_text", "", [""]], |
| 103 | + ["_shadow", 0, [0, false]], |
| 104 | + ["_textSize", 0.05, [0]], |
| 105 | + ["_font", "RobotoCondensed", [""]], |
| 106 | + ["_align", "center", [""]] |
| 107 | + ]; |
| 108 | + |
| 109 | + _icons pushBack [_position, _icon, _color, _scale, _angle, _text, _shadow, _textSize, _font, _align]; |
| 110 | + }; |
| 111 | + case "LINE": { |
| 112 | + _args params [ |
| 113 | + ["_begPos", [0, 0, 0], [[], objNull], 3], |
| 114 | + ["_endPos", [0, 0, 0], [[], objNull], 3], |
| 115 | + ["_color", [1, 1, 1, 1], [[]], 4] |
| 116 | + ]; |
| 117 | + |
| 118 | + _lines pushBack [_begPos, _endPos, _color]; |
| 119 | + }; |
| 120 | + default { |
| 121 | + ERROR_1("Invalid hint element type - %1.",_type); |
| 122 | + }; |
| 123 | + }; |
| 124 | +} forEach _elements; |
| 125 | + |
| 126 | +// Add event handlers to draw the hint elements |
| 127 | +private _fnc_draw2D = { |
| 128 | + params ["_ctrlMap"]; |
| 129 | + _thisArgs params ["_icons", "_lines"]; |
| 130 | + |
| 131 | + { |
| 132 | + _x params ["_position", "_icon", "_color", "_scale", "_angle", "_text", "_shadow", "_textSize", "_font", "_align"]; |
| 133 | + |
| 134 | + if (_position isEqualTo objNull) then {continue}; |
| 135 | + |
| 136 | + _ctrlMap drawIcon [_icon, _color, _position, _scale * MAP_ICON_SIZE, _scale * MAP_ICON_SIZE, _angle, _text, _shadow, _textSize, _font, _align]; |
| 137 | + } forEach _icons; |
| 138 | + |
| 139 | + { |
| 140 | + _x params ["_begPos", "_endPos", "_color"]; |
| 141 | + |
| 142 | + if (objNull in [_begPos, _endPos]) then {continue}; |
| 143 | + |
| 144 | + _ctrlMap drawLine [_begPos, _endPos, _color]; |
| 145 | + } forEach _lines; |
| 146 | +}; |
| 147 | + |
| 148 | +private _fnc_draw3D = { |
| 149 | + _thisArgs params ["_icons", "_lines", "_endTime", "_id"]; |
| 150 | + |
| 151 | + // Exit if the Zeus display is closed or hint duration is complete |
| 152 | + if (isNull curatorCamera || {CBA_missionTime >= _endTime}) exitWith { |
| 153 | + GVAR(drawHintMap) deleteAt _id params ["_id2D", "_id3D"]; |
| 154 | + |
| 155 | + private _ctrlMap = findDisplay IDD_RSCDISPLAYCURATOR displayCtrl IDC_RSCDISPLAYCURATOR_MAINMAP; |
| 156 | + _ctrlMap ctrlRemoveEventHandler ["Draw", _id2D]; |
| 157 | + removeMissionEventHandler ["Draw3D", _id3D]; |
| 158 | + }; |
| 159 | + |
| 160 | + // No 3D drawing needed if the map is visible |
| 161 | + if (visibleMap) exitWith {}; |
| 162 | + |
| 163 | + { |
| 164 | + _x params ["_position", "_icon", "_color", "_scale", "_angle", "_text", "_shadow", "_textSize", "_font", "_align"]; |
| 165 | + |
| 166 | + if (_position isEqualTo objNull) then {continue}; |
| 167 | + |
| 168 | + if (_position isEqualType objNull) then { |
| 169 | + _position = unitAimPositionVisual _position; |
| 170 | + }; |
| 171 | + |
| 172 | + drawIcon3D [_icon, _color, _position, _scale, _scale, _angle, _text, _shadow, _textSize, _font, _align]; |
| 173 | + } forEach _icons; |
| 174 | + |
| 175 | + { |
| 176 | + _x params ["_begPos", "_endPos", "_color"]; |
| 177 | + |
| 178 | + if (objNull in [_begPos, _endPos]) then {continue}; |
| 179 | + |
| 180 | + if (_begPos isEqualType objNull) then { |
| 181 | + _begPos = unitAimPositionVisual _begPos; |
| 182 | + }; |
| 183 | + |
| 184 | + if (_endPos isEqualType objNull) then { |
| 185 | + _endPos = unitAimPositionVisual _endPos; |
| 186 | + }; |
| 187 | + |
| 188 | + drawLine3D [_begPos, _endPos, _color]; |
| 189 | + } forEach _lines; |
| 190 | +}; |
| 191 | + |
| 192 | +private _args = [_icons, _lines, CBA_missionTime + _duration, _id]; |
| 193 | +private _id2D = [_ctrlMap, "Draw", _fnc_draw2D, _args] call CBA_fnc_addBISEventHandler; |
| 194 | +private _id3D = [missionNamespace, "Draw3D", _fnc_draw3D, _args] call CBA_fnc_addBISEventHandler; |
| 195 | +GVAR(drawHintMap) set [_id, [_id2D, _id3D]]; |
| 196 | + |
| 197 | +// Return the hint ID (in case a generated one was used) |
| 198 | +_id |
0 commit comments