Major plumbing upgrades on interact_menu:

- Store only one compiled menu per class
- Actions added through apis for invidual objects stored on the object separately
- Replaced the concept of uids by paths. This allows adding/removing actions inside other actions loaded from config seamlessly.
- Temporarily removed caching of nearby actions (probe). We may go back to that if needed pretty easily. This allows the player to move freely with the interaction menu opened.
This commit is contained in:
Nicolás Badano 2015-02-27 01:55:16 -03:00
parent 3721e14561
commit 310710b6e2
13 changed files with 361 additions and 316 deletions

View File

@ -4,14 +4,8 @@
_fnc = {
_this call FUNC(render);
};
// [_fnc, 0, []] call cba_fnc_addPerFrameHandler;
addMissionEventHandler ["Draw3D", _fnc];
_fnc = {
_this call FUNC(probe);
};
[_fnc, 0.5, []] call cba_fnc_addPerFrameHandler;
["ACE3",
"Interact Key",
{_this call FUNC(keyDown)},

View File

@ -9,15 +9,13 @@ PREP(keyDown);
PREP(keyDownSelfAction);
PREP(keyUp);
PREP(keyUpSelfAction);
PREP(probe);
PREP(removeAction);
PREP(render);
PREP(renderIcon);
PREP(renderMenu);
PREP(rotateVectLine);
PREP(rotateVectLineGetMap);
GVAR(toRender) = [];
PREP(updateVecLineMap);
GVAR(keyDown) = false;
GVAR(keyDownSelfAction) = false;
@ -30,8 +28,6 @@ GVAR(selectedAction) = {};
GVAR(actionSelected) = false;
GVAR(selectedTarget) = objNull;
GVAR(filter) = [];
GVAR(menuDepthPath) = [];
GVAR(renderDepth) = 0;
GVAR(lastRenderDepth) = 0;
@ -49,8 +45,6 @@ GVAR(startHoverTime) = diag_tickTime;
GVAR(iconCtrls) = [];
GVAR(iconCount) = 0;
GVAR(objectActionsHash) = HASH_CREATE;
GVAR(uidCounter) = 0;
ADDON = true;

View File

@ -1,39 +1,37 @@
/*
* Author: commy2 and NouberNou
* Add an ACE action to an object or inside a parent action. Note: This function is NOT global.
* Author: commy2, NouberNou and CAA-Picard
* Add an ACE action to an object, under a certain config path
* Note: This function is NOT global.
*
* Argument:
* 0: Object the action should be assigned to or parent action <OBJECT> or <ARRAY>
* 1: Name of the action shown in the menu <STRING>
* 2: Icon <STRING>
* 3: Position (Position or Selection Name) <POSITION> or <STRING>
* 4: Statement <CODE>
* 5: Condition <CODE>
* 6: Distance <NUMBER>
* 0: Object the action should be assigned to <OBJECT>
* 1: Type of action, 0 for actions, 1 for self-actions <NUMBER>
* 2: Full path of the new action <ARRAY>
* 3: Name of the action shown in the menu <STRING>
* 4: Icon <STRING>
* 5: Position (Position or Selection Name) <POSITION> or <STRING>
* 6: Statement <CODE>
* 7: Condition <CODE>
* 8: Distance <NUMBER>
*
* Return value:
* The entry array, which can be used to remove the entry, or add children entries <ARRAY>.
* The entry full path, which can be used to remove the entry, or add children entries <ARRAY>.
*
* Public: No
*/
#include "script_component.hpp"
EXPLODE_7_PVT(_this,_object,_displayName,_icon,_position,_statement,_condition,_distance);
EXPLODE_9_PVT(_this,_object,_typeNum,_fullPath,_displayName,_icon,_position,_statement,_condition,_distance);
private ["_varName","_actions"];
private ["_actions","_entry"];
_actions = [];
if(IS_OBJECT(_object)) then {
_actions = _object getVariable [QUOTE(GVAR(actionData)), []];
if((count _actions) == 0) then {
_object setVariable [QUOTE(GVAR(actionData)), _actions]
};
} else {
if(IS_ARRAY(_object)) then {
_actions = _object select 6;
};
_varName = [QGVAR(actions),QGVAR(selfActions)] select _typeNum;
_actions = _object getVariable [_varName, []];
if((count _actions) == 0) then {
_object setVariable [_varName, _actions];
};
private "_entry";
_entry = [
_displayName,
_icon,
@ -42,8 +40,11 @@ _entry = [
_condition,
_distance,
[],
GVAR(uidCounter)
GVAR(uidCounter),
+ _fullPath
];
GVAR(uidCounter) = GVAR(uidCounter) + 1;
_actions pushBack _entry;
_entry;
_fullPath

View File

@ -1,6 +1,6 @@
/*
* Author: NouberNou
* Compile the action menu from config for a given object.
* Author: NouberNou and CAA-Picard
* Compile the action menu from config for an object's class
*
* Argument:
* 0: Object <OBJECT>
@ -14,31 +14,21 @@
EXPLODE_1_PVT(_this,_object);
/*
[
[
"Launch",
"\a3\ui_f\data\IGUI\Cfg\Actions\eject_ca.paa",
[0,0,0],
{ (_this select 0) setVelocity [0,0,10]; },
{ true },
1,
[]
]
]
*/
private ["_objectType","_recurseFnc","_actions"];
private ["_objectType","_actionsVarName"];
_objectType = typeOf _object;
_actionsCfg = configFile >> "CfgVehicles" >> _objectType >> "ACE_Actions";
_actionsVarName = format [QGVAR(Act_%1), _objectType];
// Exit if the action menu is already compiled for this class
if !(isNil {missionNamespace getVariable [_actionsVarName, nil]}) exitWith {};
private "_recurseFnc";
_recurseFnc = {
private ["_actions", "_displayName", "_distance", "_icon", "_statement", "_selection", "_condition", "_showDisabled",
"_enableInside", "_children", "_entry", "_actionsCfg"];
"_enableInside", "_children", "_entry", "_entryCfg", "_fullPath"];
EXPLODE_2_PVT(_this,_actionsCfg,_parentPath);
_actions = [];
_actionsCfg = _this select 0;
for "_i" from 0 to (count _actionsCfg)-1 do {
for "_i" from 0 to (count _actionsCfg) - 1 do {
_entryCfg = _actionsCfg select _i;
if(isClass _entryCfg) then {
_displayName = getText (_entryCfg >> "displayName");
@ -58,8 +48,12 @@ _recurseFnc = {
_showDisabled = getNumber (_entryCfg >> "showDisabled");
_enableInside = getNumber (_entryCfg >> "enableInside");
_fullPath = (+ _parentPath);
_fullPath pushBack (configName _entryCfg);
_condition = compile _condition;
_children = [_entryCfg] call _recurseFnc;
_children = [_entryCfg, _fullPath] call _recurseFnc;
_entry = [
_displayName,
_icon,
@ -68,8 +62,10 @@ _recurseFnc = {
_condition,
_distance,
_children,
GVAR(uidCounter)
GVAR(uidCounter),
_fullPath
];
GVAR(uidCounter) = GVAR(uidCounter) + 1;
_actions pushBack _entry;
};
@ -77,6 +73,23 @@ _recurseFnc = {
_actions
};
_actions = [_actionsCfg] call _recurseFnc;
private "_actionsCfg";
_actionsCfg = configFile >> "CfgVehicles" >> _objectType >> "ACE_Actions";
_object setVariable [QUOTE(GVAR(actionData)), _actions];
missionNamespace setVariable [_actionsVarName, [_actionsCfg, []] call _recurseFnc];
/*
[
[
"My Action",
"\a3\ui_f\data\IGUI\Cfg\Actions\eject_ca.paa",
[0,0,0],
{ (_this select 0) setVelocity [0,0,10]; },
{ true },
1,
[],
uid,
["MainActions","TeamManagement","MyAction"]
]
]
*/

View File

@ -1,6 +1,6 @@
/*
* Author: NouberNou and CAA-Picard
* Compile the self action menu from config for a given object.
* Compile the self action menu from config for an object's class
*
* Argument:
* 0: Object <OBJECT>
@ -14,34 +14,25 @@
EXPLODE_1_PVT(_this,_object);
/*
[
[
"Launch",
"\a3\ui_f\data\IGUI\Cfg\Actions\eject_ca.paa",
[0,0,0],
{ (_this select 0) setVelocity [0,0,10]; },
{ true },
1,
[]
]
]
*/
private ["_objectType","_recurseFnc","_actions"];
private ["_objectType","_actionsVarName"];
_objectType = typeOf _object;
_actionsCfg = configFile >> "CfgVehicles" >> _objectType >> "ACE_SelfActions";
_actionsVarName = format [QGVAR(SelfAct_%1), _objectType];
// Exit if the action menu is already compiled for this class
if !(isNil {missionNamespace getVariable [_actionsVarName, nil]}) exitWith {};
private "_recurseFnc";
_recurseFnc = {
private ["_actions", "_displayName", "_distance", "_icon", "_statement", "_condition", "_showDisabled",
"_enableInside", "_children", "_entry", "_actionsCfg"];
private ["_actions", "_displayName", "_distance", "_icon", "_statement", "_selection", "_condition", "_showDisabled",
"_enableInside", "_children", "_entry", "_entryCfg", "_fullPath"];
EXPLODE_2_PVT(_this,_actionsCfg,_parentPath);
_actions = [];
_actionsCfg = _this select 0;
for "_i" from 0 to (count _actionsCfg)-1 do {
for "_i" from 0 to (count _actionsCfg) - 1 do {
_entryCfg = _actionsCfg select _i;
if(isClass _entryCfg) then {
_displayName = getText (_entryCfg >> "displayName");
_icon = getText (_entryCfg >> "icon");
_statement = compile (getText (_entryCfg >> "statement"));
@ -54,8 +45,12 @@ _recurseFnc = {
_showDisabled = getNumber (_entryCfg >> "showDisabled");
_enableInside = getNumber (_entryCfg >> "enableInside");
_fullPath = (+ _parentPath);
_fullPath pushBack (configName _entryCfg);
_condition = compile _condition;
_children = [_entryCfg] call _recurseFnc;
_children = [_entryCfg, _fullPath] call _recurseFnc;
_entry = [
_displayName,
_icon,
@ -64,8 +59,10 @@ _recurseFnc = {
_condition,
10, //distace
_children,
GVAR(uidCounter)
GVAR(uidCounter),
_fullPath
];
GVAR(uidCounter) = GVAR(uidCounter) + 1;
_actions pushBack _entry;
};
@ -73,7 +70,8 @@ _recurseFnc = {
_actions
};
_actions = [_actionsCfg] call _recurseFnc;
private "_actionsCfg";
_actionsCfg = configFile >> "CfgVehicles" >> _objectType >> "ACE_SelfActions";
// Create a master action to base on self action
_actions = [[
@ -83,10 +81,11 @@ _actions = [[
{ true },
{ true },
10,
_actions,
GVAR(uidCounter)
[_actionsCfg, ["SelfActions"]] call _recurseFnc,
GVAR(uidCounter),
["SelfActions"]
]
];
GVAR(uidCounter) = GVAR(uidCounter) + 1;
_object setVariable [QUOTE(GVAR(selfActionData)), _actions];
missionNamespace setVariable [_actionsVarName, _actions];

View File

@ -17,7 +17,7 @@ if(GVAR(actionSelected)) then {
this = GVAR(selectedTarget);
_player = ACE_Player;
_target = GVAR(selectedTarget);
[GVAR(selectedTarget), player] call GVAR(selectedAction);
[GVAR(selectedTarget), ACE_player] call GVAR(selectedAction);
};
GVAR(expanded) = false;
GVAR(lastPath) = [];

View File

@ -17,7 +17,7 @@ if(GVAR(actionSelected)) then {
this = GVAR(selectedTarget);
_player = ACE_Player;
_target = GVAR(selectedTarget);
[GVAR(selectedTarget), player] call GVAR(selectedAction);
[GVAR(selectedTarget), ACE_player] call GVAR(selectedAction);
};
GVAR(expanded) = false;
GVAR(lastPath) = [];

View File

@ -1,55 +0,0 @@
/*
* Author: NouberNou
* Scan de vicinity of the player and collect every interaction available around it on
* the GVAR(toRender) array.
*
* Argument:
* None
*
* Return value:
* None
*
* Public: No
*/
#include "script_component.hpp"
private ["_nearestObjects", "_actionObject", "_x", "_actionData", "_renderData", "_actionItem", "_active", "_renderItem", "_object", "_forEachIndex"];
if(!GVAR(keyDown)) then {
_nearestObjects = nearestObjects [(getPos ACE_player), ["All"], 100];
GVAR(toRender) = [];
{
_actionObject = _x;
_actionData = _actionObject getVariable [QUOTE(GVAR(actionData)), []];
if((count _actionData) > 0) then {
_renderData = [];
{
_actionItem = _x;
this = _actionObject;
_target = _actionObject;
_player = ACE_player;
_active = [_target, ACE_player] call (_actionItem select 4);
systemChat format ["%1 %2 is active %3", _actionObject, _actionItem select 0, _active];
// player sideChat format["_active: %1 %2", _actionItem select 0, _active];
if(_active) then {
_renderItem = +_actionItem;
_renderItem set[4, true];
_renderData set[(count _renderData), _renderItem];
};
} forEach _actionData;
if((count _renderData) > 0) then {
GVAR(toRender) set[(count GVAR(toRender)), [_actionObject, _renderData]];
};
};
} forEach _nearestObjects;
// player sideChat format["p: %1", count GVAR(toRender)];
} else {
GVAR(filter) = [];
{
_object = _x select 0;
if(_object distance ACE_player > 100) then {
GVAR(filter) set[(count GVAR(filter)), _forEachIndex];
};
} forEach GVAR(toRender);
};

View File

@ -1,10 +1,11 @@
/*
* Author: commy2 and NouberNou
* Author: commy2, NouberNou and CAA-Picard
* Remove an action from an object
*
* Argument:
* 0: Object the action should be assigned to <OBJECT>
* 1: Entry to remove <ARRAY> or <NUMBER>
* 0: Object the action is assigned to <OBJECT>
* 1: Type of action, 0 for actions, 1 for self-actions <NUMBER>
* 2: Full path of the action to remove <ARRAY>
*
* Return value:
* None
@ -13,38 +14,14 @@
*/
#include "script_component.hpp"
EXPLODE_2_PVT(_this,_object,_entry);
EXPLODE_2_PVT(_this,_object,_fullPath);
private ["_found", "_actions", "_searchFnc"];
private ["_varName","_actions"];
_varName = [QGVAR(actions),QGVAR(selfActions)] select _typeNum;
_actions = _object getVariable [_varName, []];
if(!IS_OBJECT(_object)) exitWith {false};
_actions = _object getVariable [QUOTE(GVAR(actionData)), []];
if(IS_ARRAY(_entry)) then {
_entry = _entry select 7;
};
_found = false;
_searchFnc = {
private ["_actions", "_entry", "_childActions"];
_actions = _this select 0;
_entry = _this select 1;
{
if((_x select 7) == _entry) then {
_actions set[_forEachIndex, "aceactiondelete"];
_actions = _actions - ["aceactiondelete"];
_found = true;
} else {
if(!_found && {count (_x select 6) > 0}) then {
_childActions = [(_x select 6), _entry] call _searchFnc;
_x set[6, _childActions];
};
};
} forEach _actions;
_actions;
};
_actions = [_actions, _entry] call _searchFnc;
_object setVariable [QUOTE(GVAR(actionData)), _actions];
_found;
{
if ((_x select 8) isEqualTo _fullPath) exitWith {
_actions deleteAt _forEachIndex;
};
} forEach _actions;

View File

@ -16,41 +16,95 @@ private ["_cursorPos1", "_cursorPos2", "_cursorVec", "_p1", "_p2", "_p", "_v", "
_foundTarget = false;
_cursorPos1 = positionCameraToWorld [0, 0, 0];
_cursorPos2 = positionCameraToWorld [0, 0, 2];
GVAR(currentOptions) = [];
if((count GVAR(toRender)) > 0 && (GVAR(keyDown) || GVAR(keyDownSelfAction))) then {
if((count GVAR(vecLineMap)) == 0 || ((count GVAR(menuDepthPath)) > 0 && (getPosASL player) distance GVAR(lastPos) > 0.01)) then {
GVAR(lastPos) = getPosASL player;
_cursorVec = [_cursorPos2, _cursorPos1] call BIS_fnc_vectorFromXtoY;
_p1 = [0,0,0];
_p2 = +_cursorVec;
_p = (_cursorVec call CBA_fnc_vect2polar);
_v = [(_p select 0), (_p select 1), (_p select 2)+90] call CBA_fnc_polar2vect;
_cp = [_cursorVec, _v] call BIS_fnc_crossProduct;
GVAR(vecLineMap) = [_cp, _p1, _p2] call FUNC(rotateVectLineGetMap);
};
if (GVAR(keyDown)) then {
// Render all nearby interaction menus
private ["_actionsVarName","_classActions","_objectActions","_target","_player","_actionItem","_active"];
if (GVAR(keyDown)) then {
[] call FUNC(updateVecLineMap);
// Render all nearby interaction menus
_nearestObjects = nearestObjects [(getPos ACE_player), ["All"], 15];
{
_target = _x;
_player = ACE_player;
// Iterate through object actions, find base level actions and render them if appropiate
_actionsVarName = format [QGVAR(Act_%1), typeOf _target];
GVAR(objectActions) = _target getVariable [QGVAR(actions), []];
{
if(!(_forEachIndex in GVAR(filter))) then {
GVAR(renderDepth) = 0;
_renderTargets = _x;
{
[_renderTargets select 0, _x, 0, [180, 360]] call FUNC(renderMenu);
} forEach (_renderTargets select 1);
};
} forEach GVAR(toRender);
} else {
// Render only the self action menu
_actions = (ACE_player getVariable QGVAR(selfActionData)) select 0;
_pos = (ACE_player modelToWorld (ACE_player selectionPosition "spine3")) vectorAdd GVAR(selfMenuOffset) vectorAdd [0,0,0.25];
[ACE_player, _actions, 0, [180, 360], _pos] call FUNC(renderMenu);
};
_actionItem = _x;
// Only render them directly if they are base level actions
if (count (_actionItem select 8) == 1) then {
_active = [_target, ACE_player] call (_actionItem select 4);
// player sideChat format["c: %1", count GVAR(toRender)];
if (_active) then {
GVAR(renderDepth) = 0;
[_target, _actionItem, 0, [180, 360]] call FUNC(renderMenu);
};
};
} forEach GVAR(objectActions);
// Iterate through base level class actions and render them if appropiate
_classActions = missionNamespace getVariable [_actionsVarName, []];
{
_actionItem = _x;
_active = [_target, ACE_player] call (_actionItem select 4);
if (_active) then {
GVAR(renderDepth) = 0;
[_target, _actionItem, 0, [180, 360]] call FUNC(renderMenu);
};
} forEach _classActions;
} forEach _nearestObjects;
} else {
if (GVAR(keyDownSelfAction)) then {
[] call FUNC(updateVecLineMap);
// Render only the self action menu
_target = vehicle ACE_player;
_player = ACE_player;
// Iterate through object actions, find base level actions and render them if appropiate
_actionsVarName = format [QGVAR(SelfAct_%1), typeOf _target];
GVAR(objectActions) = _target getVariable [QGVAR(selfActions), []];
{
_actionItem = _x;
// Only render them directly if they are base level actions
if (count (_actionItem select 8) == 1) then {
_active = [_target, ACE_player] call (_actionItem select 4);
if (_active) then {
GVAR(renderDepth) = 0;
[_target, _actionItem, 0, [180, 360]] call FUNC(renderMenu);
};
};
} forEach GVAR(objectActions);
// Iterate through base level class actions and render them if appropiate
_actionsVarName = format [QGVAR(SelfAct_%1), typeOf _target];
_classActions = missionNamespace getVariable [_actionsVarName, []];
{
_actionItem = _x;
_active = [_target, ACE_player] call (_actionItem select 4);
if (_active) then {
GVAR(renderDepth) = 0;
_pos = (ACE_player modelToWorld (ACE_player selectionPosition "spine3")) vectorAdd GVAR(selfMenuOffset) vectorAdd [0,0,0.25];
[ACE_player, _actionItem, 0, [180, 360], _pos] call FUNC(renderMenu);
};
} forEach _classActions;
};
};
if(GVAR(keyDown) || GVAR(keyDownSelfAction)) then {
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selected_ca.paa", [1,0,0,1], _cursorPos2, 1, 1, 0, "", 0.5, 0.025, "TahomaB"];
_cursorScreenPos = worldToScreen _cursorPos2;
_closestDistance = 1000000;
@ -67,48 +121,50 @@ if(GVAR(keyDown) || GVAR(keyDownSelfAction)) then {
};
} forEach GVAR(currentOptions);
if(_closestSelection != -1) then {
_closest = GVAR(currentOptions) select _closestSelection;
if(_closestSelection == -1) exitWith {};
_pos = _closest select 1;
_cTime = diag_tickTime;
_delta = _cTime - GVAR(lastTime);
GVAR(lastTime) = _cTime;
GVAR(rotationAngle) = GVAR(rotationAngle) + (180*_delta);
if(GVAR(rotationAngle) > 360) then {
GVAR(rotationAngle) = GVAR(rotationAngle) - 360;
};
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [1,0,0,.75], _pos, 0.6*SafeZoneW, 0.6*SafeZoneW, GVAR(rotationAngle), "", 0.5, 0.025, "TahomaB"];
_foundTarget = true;
GVAR(actionSelected) = true;
GVAR(selectedTarget) = (_closest select 0) select 0;
GVAR(selectedAction) = ((_closest select 0) select 1) select 3;
_misMatch = false;
_hoverPath = (_closest select 2);
if((count GVAR(lastPath)) != (count _hoverPath)) then {
_misMatch = true;
} else {
{
if(_x != (_hoverPath select _forEachIndex)) exitWith {
_misMatch = true;
};
} forEach GVAR(lastPath);
};
_closest = GVAR(currentOptions) select _closestSelection;
if(_misMatch) then {
GVAR(lastPath) = _hoverPath;
GVAR(startHoverTime) = diag_tickTime;
GVAR(expanded) = false;
} else {
if(!GVAR(expanded) && diag_tickTime-GVAR(startHoverTime) > 0.25) then {
GVAR(expanded) = true;
GVAR(menuDepthPath) = +GVAR(lastPath);
_pos = _closest select 1;
_cTime = diag_tickTime;
_delta = _cTime - GVAR(lastTime);
GVAR(lastTime) = _cTime;
GVAR(rotationAngle) = GVAR(rotationAngle) + (180*_delta);
if(GVAR(rotationAngle) > 360) then {
GVAR(rotationAngle) = GVAR(rotationAngle) - 360;
};
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selectover_ca.paa", [1,0,0,.75], _pos, 0.6*SafeZoneW, 0.6*SafeZoneW, GVAR(rotationAngle), "", 0.5, 0.025, "TahomaB"];
_foundTarget = true;
GVAR(actionSelected) = true;
GVAR(selectedTarget) = (_closest select 0) select 0;
GVAR(selectedAction) = ((_closest select 0) select 1) select 3;
_misMatch = false;
_hoverPath = (_closest select 2);
if((count GVAR(lastPath)) != (count _hoverPath)) then {
_misMatch = true;
} else {
{
if(_x != (_hoverPath select _forEachIndex)) exitWith {
_misMatch = true;
};
} forEach GVAR(lastPath);
};
if(_misMatch) then {
GVAR(lastPath) = _hoverPath;
GVAR(startHoverTime) = diag_tickTime;
GVAR(expanded) = false;
} else {
if(!GVAR(expanded) && diag_tickTime-GVAR(startHoverTime) > 0.25) then {
GVAR(expanded) = true;
GVAR(menuDepthPath) = +GVAR(lastPath);
};
};
drawIcon3D ["\a3\ui_f\data\IGUI\Cfg\Cursors\selected_ca.paa", [1,0,0,1], _cursorPos2, 1, 1, 0, "", 0.5, 0.025, "TahomaB"];
//diag_log format ["GVAR(menuDepthPath): %1", GVAR(menuDepthPath)];
};
if(!_foundTarget && GVAR(actionSelected)) then {
GVAR(actionSelected) = false;
GVAR(expanded) = false;

View File

@ -24,6 +24,8 @@ _color = _this select 1;
_pos = _this select 2;
_icon = _this select 6;
//systemChat format ["Icon %1 - %2,%3,%4", _text, _pos select 0, _pos select 1, _pos select 2];
_sPos = worldToScreen _pos;
// _sPos = _pos;
if(count _sPos > 0) then {

View File

@ -1,6 +1,6 @@
/*
* Author: NouberNou and CAA-Picard
* Render a interaction menu
* Render a interaction menu and it's children recursively
*
* Argument:
* 0: Object <OBJECT>
@ -8,7 +8,6 @@
* 2: ?
* 3: Angle range available for rendering <ARRAY>
* 4: 3D position <ARRAY> (Optional)
* 5: Path of UIDs <ARRAY> (Optional)
*
* Return value:
* None
@ -17,16 +16,15 @@
*/
#include "script_component.hpp"
private ["_object", "_actionData", "_distance", "_uid", "_pos", "_cursorScreenPos", "_path", "_menuDepth", "_opacity", "_currentRenderDepth", "_radialOffset", "_active", "_x", "_offset", "_newPos", "_forEachIndex"];
private ["_distance", "_uid", "_pos", "_cursorScreenPos", "_path", "_menuDepth", "_opacity", "_currentRenderDepth", "_radialOffset", "_active", "_x", "_offset", "_newPos", "_forEachIndex"];
_object = _this select 0;
_actionData = _this select 1;
_uid = _actionData select 7;//_this select 2;
_angles = _this select 3;
_distance = _actionData select 5;
EXPLODE_4_PVT(_this,_object,_actionData,_dummy,_angles);
EXPLODE_2_PVT(_angles,_centerAngle,_maxAngleSpan);
_uid = _actionData select 7;
_distance = _actionData select 5;
// Obtain a 3D position for the action
if((count _this) > 4) then {
_pos = _this select 4;
} else {
@ -36,70 +34,123 @@ if((count _this) > 4) then {
_pos = _object modelToWorld (_object selectionPosition (_actionData select 2));
};
};
_cursorScreenPos = (positionCameraToWorld [0, 0, 0]);
if(_cursorScreenPos distance _pos <= _distance) then {
_path = [];
if((count _this) > 5) then {
_path = +(_this select 5);
// Exit if the action is too far away
if(_cursorScreenPos distance _pos >= _distance) exitWith {};
// Exit if the action is behind you
if(_cursorScreenPos select 2 < 0) exitWith {};
_menuDepth = (count GVAR(menuDepthPath)) - 1;
// Store path to action
_path = [_object];
_path = _path + (_actionData select 8);
// Check if the menu is on the selected path
private "_menuInSelectedPath";
_menuInSelectedPath = true;
{
if (_forEachIndex >= (count GVAR(menuDepthPath))) exitWith {
_menuInSelectedPath = false;
};
_menuDepth = (count GVAR(menuDepthPath));
// ARGB Color (First Hex Pair is transparancy)
_color = "#FFFFFFFF";
if(_menuDepth > 0 && _uid != (GVAR(menuDepthPath) select (GVAR(renderDepth)))) then {
_color = format ["#%1FFFFFF", [255 * (((GVAR(renderDepth)/_menuDepth)) max 0.25)] call EFUNC(common,toHex)];
if (_x != (GVAR(menuDepthPath) select _forEachIndex)) exitWith {
_menuInSelectedPath = false;
};
_path set[(count _path), _uid];
[_actionData select 0, _color, _pos, 1, 1, 0, _actionData select 1, 0.5, 0.025, "TahomaB"] call FUNC(renderIcon);
GVAR(currentOptions) set[(count GVAR(currentOptions)), [_this, _pos, _path]];
_currentRenderDepth = -1;
_currentRenderDepth = GVAR(renderDepth);
GVAR(renderDepth) = GVAR(renderDepth) + 1;
if(_uid == (GVAR(menuDepthPath) select (GVAR(renderDepth)-1))) then {
// Count how many actions are active
private "_numActions";
_numActions = 0;
{
this = _object;
_target = _object;
_player = ACE_player;
_active = [_object, ACE_player] call (_x select 4);
if(_active) then {
_numActions = _numActions + 1;
};
} forEach (_actionData select 6);
systemChat format ["Menu %1, _numActions: %2", _actionData select 0, _numActions];
} forEach _path;
private "_angleSpan";
_angleSpan = _maxAngleSpan min (55 * (_numActions - 1));
private "_angle";
_angle = _centerAngle - _angleSpan / 2;
{
this = _object;
_target = _object;
_player = ACE_player;
_active = [_object, ACE_player] call (_x select 4);
// diag_log text format["_active: %1: %2", (_x select 0), _active];
if(_active) then {
//systemChat format ["_angle: %1", _angle];
_offset = [GVAR(vecLineMap), _angle] call FUNC(rotateVectLine);
_mod = 0.15 max (0.15 * (_cursorScreenPos distance _pos)); //0.5;//0.1*_distance;
_newPos = [
(_pos select 0) + ((_offset select 0)*_mod),
(_pos select 1) + ((_offset select 1)*_mod),
(_pos select 2) + ((_offset select 2)*_mod)
];
// drawLine3D [_pos, _newPos, [1,0,0,0.5]];
[_object, _x, _forEachIndex, [_angle, 150], _newPos, _path] call FUNC(renderMenu);
if (_angle == 360) then {
_angle = _angle + _angleSpan / _numActions;
} else {
_angle = _angle + _angleSpan / ((_numActions-1) max 1);
};
};
} forEach (_actionData select 6);
};
GVAR(renderDepth) = GVAR(renderDepth) - 1;
// Render icon
// ARGB Color (First Hex Pair is transparancy)
_color = "#FFFFFFFF";
if(_menuDepth > 0 && !_menuInSelectedPath) then {
_color = format ["#%1FFFFFF", [255 min (255 * (((GVAR(renderDepth)/_menuDepth)) max 0.25))] call EFUNC(common,toHex)];
};
[_actionData select 0, _color, _pos, 1, 1, 0, _actionData select 1, 0.5, 0.025, "TahomaB"] call FUNC(renderIcon);
// Add the action to current options
GVAR(currentOptions) pushBack [_this, _pos, _path];
_currentRenderDepth = GVAR(renderDepth);
GVAR(renderDepth) = GVAR(renderDepth) + 1;
//systemChat format ["Menu %1, _menuInSelectedPath: %2", _actionData select 8, _menuInSelectedPath];
// Exit without rendering children if it isn't
if !(_menuInSelectedPath) exitWith {
//diag_log text format ["Exiting on _path: %1",_path];
//diag_log text format ["GVAR(menuDepthPath): %1",GVAR(menuDepthPath)];
};
// Collect all active children actions
private "_activeChildren";
_activeChildren = [];
// Collect children class actions
{
_target = _object;
_player = ACE_player;
_active = [_object, ACE_player] call (_x select 4);
if(_active) then {
_activeChildren pushBack _x;
};
} forEach (_actionData select 6);
// Collect children object actions
{
_actionItem = _x;
/*diag_log text format ["_path: %1",_path];
diag_log text format ["(_actionItem select 8): %1",(_actionItem select 8)];
diag_log text format ["(_actionData select 8): %1",(_actionData select 8)];*/
// Check if the action is children of the selected menu
if ((count (_actionItem select 8)) == (count _path)) then {
// Compare parent path to see if it's a suitable child
private "_isChild";
_isChild = true;
for "_i" from 0 to (count (_actionItem select 8)) - 2 do {
if !(((_actionItem select 8) select _i) isEqualTo (_path select (_i + 1))) exitWith {
_isChild = false;
};
};
if (_isChild) exitWith {
_target = _object;
_player = ACE_player;
_active = [_target, ACE_player] call (_actionItem select 4);
if (_active) then {
_activeChildren pushBack _actionItem;
};
};
};
} forEach GVAR(objectActions);
private ["_angleSpan","_angle"];
_angleSpan = _maxAngleSpan min (55 * ((count _activeChildren) - 1));
if (_angleSpan >= 305) then {
_angleSpan = 360;
};
_angle = _centerAngle - _angleSpan / 2;
//systemChat format ["Menu %1, _numA: %2, _aSpan: %3", _actionData select 8, count _activeChildren, _angleSpan];
{
_target = _object;
_player = ACE_player;
_offset = [GVAR(vecLineMap), _angle] call FUNC(rotateVectLine);
_mod = 0.15 max (0.15 * (_cursorScreenPos distance _pos));
_newPos = _pos vectorAdd (_offset vectorMultiply _mod);
// drawLine3D [_pos, _newPos, [1,0,0,0.5]];
[_object, _x, _forEachIndex, [_angle, 140], _newPos] call FUNC(renderMenu);
if (_angleSpan == 360) then {
_angle = _angle + _angleSpan / (count _activeChildren);
} else {
_angle = _angle + _angleSpan / (((count _activeChildren)-1) max 1);
};
} forEach _activeChildren;
GVAR(renderDepth) = GVAR(renderDepth) - 1;

View File

@ -0,0 +1,13 @@
#include "script_component.hpp";
if((count GVAR(vecLineMap)) == 0 || ((count GVAR(menuDepthPath)) > 0 && (getPosASL player) distance GVAR(lastPos) > 0.01)) then {
GVAR(lastPos) = getPosASL player;
_cursorVec = [_cursorPos2, _cursorPos1] call BIS_fnc_vectorFromXtoY;
_p1 = [0,0,0];
_p2 = +_cursorVec;
_p = (_cursorVec call CBA_fnc_vect2polar);
_v = [(_p select 0), (_p select 1), (_p select 2)+90] call CBA_fnc_polar2vect;
_cp = [_cursorVec, _v] call BIS_fnc_crossProduct;
GVAR(vecLineMap) = [_cp, _p1, _p2] call FUNC(rotateVectLineGetMap);
};