- Modification of actions data structure to separate action parameters from children

- The action tree of each interaction point is parsed before drawing, pruning inactive actions
- Parent actions without statements or active children are not drawn, in order to reduce clutter
This commit is contained in:
Nicolás Badano 2015-03-02 23:29:57 -03:00
parent 094be22a19
commit 83572921ae
12 changed files with 230 additions and 195 deletions

View File

@ -5,7 +5,7 @@ ADDON = false;
PREP(addAction);
PREP(compileMenu);
PREP(compileMenuSelfAction);
PREP(collectActiveChildren);
PREP(collectActiveActionTree);
PREP(keyDown);
PREP(keyDownSelfAction);
PREP(keyUp);
@ -13,6 +13,7 @@ PREP(keyUpSelfAction);
PREP(removeAction);
PREP(render);
PREP(renderIcon);
PREP(renderBaseMenu);
PREP(renderMenu);
PREP(rotateVectLine);
PREP(rotateVectLineGetMap);
@ -43,6 +44,4 @@ GVAR(startHoverTime) = diag_tickTime;
GVAR(iconCtrls) = [];
GVAR(iconCount) = 0;
GVAR(uidCounter) = 0;
ADDON = true;

View File

@ -36,17 +36,18 @@ if((count _actions) == 0) then {
private "_entry";
_entry = [
_displayName,
_icon,
_position,
_statement,
_condition,
_distance,
[],
GVAR(uidCounter),
+ _fullPath
[
_displayName,
_icon,
_position,
_statement,
_condition,
_distance,
[false,false,false],
+ _fullPath
],
[]
];
GVAR(uidCounter) = GVAR(uidCounter) + 1;
_actions pushBack _entry;

View File

@ -0,0 +1,72 @@
/*
* Author: CAA-Picard
* Collect a entire tree of active actions
*
* Argument:
* 0: Object <OBJECT>
* 1: Original action tree <ARRAY>
*
* Return value:
* Active children <ARRAY>
*
* Public: No
*/
#include "script_component.hpp"
EXPLODE_2_PVT(_this,_object,_origAction);
EXPLODE_2_PVT(_origAction,_origActionData,_origActionChildren);
private ["_resultingAction","_target","_player","_activeChildren","_action","_actionData","_x"];
_target = _object;
_player = ACE_player;
// Return nothing if the action itself is not active
if !([_target, ACE_player] call (_origActionData select 4)) exitWith {
[]
};
_activeChildren = [];
// Collect children class actions
{
_action = [_object, _x] call FUNC(collectActiveActionTree);
if ((count _action) > 0) then {
_activeChildren pushBack _action;
};
} forEach _origActionChildren;
// Collect children object actions
{
_action = _x;
_actionData = _action select 0;
// Check if the action is children of the original action
if ((count (_actionData select 7)) == (count (_origActionData select 7) + 1)) then {
// Compare parent path to see if it's a suitable child
private "_isChild";
_isChild = true;
{
if !(_x isEqualTo ((_actionData select 7) select _forEachIndex)) exitWith {
_isChild = false;
};
} forEach (_origActionData select 7);
if (_isChild) then {
_action = [_object, _action] call FUNC(collectActiveActionTree);
if ((count _action) > 0) then {
_activeChildren pushBack _action;
};
};
};
} forEach GVAR(objectActions);
// If the original action has no statement, and no children, don't display it
if ((count _activeChildren) == 0 && ((_origActionData select 3) isEqualTo {})) exitWith {
// @todo: Account for showDisabled?
[]
};
[_origActionData, _activeChildren]

View File

@ -1,58 +0,0 @@
/*
* Author: CAA-Picard
* For a given action, collect all active children
*
* Argument:
* 0: Object <OBJECT>
* 1: Action data <ARRAY>
*
* Return value:
* Active children <ARRAY>
*
* Public: No
*/
#include "script_component.hpp"
EXPLODE_2_PVT(_this,_object,_parentAction);
private ["_activeChildren","_target","_player","_action"];
_activeChildren = [];
_target = _object;
_player = ACE_player;
// Collect children class actions
{
_action = _x;
if([_object, ACE_player] call (_action select 4)) then {
_activeChildren pushBack _action;
};
} forEach (_parentAction select 6);
// Collect children object actions
{
_action = _x;
// Check if the action is children of the selected menu
if ((count (_action select 8)) == (count (_parentAction select 8) + 1)) then {
// Compare parent path to see if it's a suitable child
private "_isChild";
_isChild = true;
{
if !(_x isEqualTo ((_action select 8) select _forEachIndex)) exitWith {
_isChild = false;
};
} forEach (_parentAction select 8);
if (_isChild) then {
if ([_target, ACE_player] call (_action select 4)) then {
_activeChildren pushBack _action;
};
};
};
} forEach GVAR(objectActions);
_activeChildren

View File

@ -45,8 +45,9 @@ _recurseFnc = {
// Add canInteract (including exceptions) and canInteractWith to condition
_condition = _condition + format [QUOTE( && {%1 call EGVAR(common,canInteract)} && {[ARR_2(ACE_player, _target)] call EFUNC(common,canInteractWith)} ), getArray (_entryCfg >> "exceptions")];
_showDisabled = getNumber (_entryCfg >> "showDisabled");
_enableInside = getNumber (_entryCfg >> "enableInside");
_showDisabled = (getNumber (_entryCfg >> "showDisabled")) > 0;
_enableInside = (getNumber (_entryCfg >> "enableInside")) > 0;
_canCollapse = (getNumber (_entryCfg >> "canCollapse")) > 0;
_fullPath = (+ _parentPath);
_fullPath pushBack (configName _entryCfg);
@ -55,18 +56,18 @@ _recurseFnc = {
_children = [_entryCfg, _fullPath] call _recurseFnc;
_entry = [
_displayName,
_icon,
_selection,
_statement,
_condition,
_distance,
_children,
GVAR(uidCounter),
_fullPath
[
_displayName,
_icon,
_selection,
_statement,
_condition,
_distance,
[_showDisabled,_enableInside,_canCollapse],
_fullPath
],
_children
];
GVAR(uidCounter) = GVAR(uidCounter) + 1;
_actions pushBack _entry;
};
};
@ -81,15 +82,17 @@ missionNamespace setVariable [_actionsVarName, [_actionsCfg, []] call _recurseFn
/*
[
[
"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,
["ACE_MainActions","TeamManagement","MyAction"]
[
"My Action",
"\a3\ui_f\data\IGUI\Cfg\Actions\eject_ca.paa",
[0,0,0],
{ (_this select 0) setVelocity [0,0,10]; },
{ true },
1,
[false,false,false]
["ACE_MainActions","TeamManagement","MyAction"]
],
[children actions]
]
]
*/

View File

@ -42,8 +42,9 @@ _recurseFnc = {
// Add canInteract (including exceptions) and canInteractWith to condition
_condition = _condition + format [QUOTE( && {%1 call EGVAR(common,canInteract)} && {[ARR_2(ACE_player, _target)] call EFUNC(common,canInteractWith)} ), getArray (_entryCfg >> "exceptions")];
_showDisabled = getNumber (_entryCfg >> "showDisabled");
_enableInside = getNumber (_entryCfg >> "enableInside");
_showDisabled = (getNumber (_entryCfg >> "showDisabled")) > 0;
_enableInside = (getNumber (_entryCfg >> "enableInside")) > 0;
_canCollapse = (getNumber (_entryCfg >> "canCollapse")) > 0;
_fullPath = (+ _parentPath);
_fullPath pushBack (configName _entryCfg);
@ -52,18 +53,18 @@ _recurseFnc = {
_children = [_entryCfg, _fullPath] call _recurseFnc;
_entry = [
_displayName,
_icon,
[0,0,0],
_statement,
_condition,
10, //distace
_children,
GVAR(uidCounter),
_fullPath
[
_displayName,
_icon,
[0,0,0],
_statement,
_condition,
10, //distace
[_showDisabled,_enableInside,_canCollapse],
_fullPath
],
_children
];
GVAR(uidCounter) = GVAR(uidCounter) + 1;
_actions pushBack _entry;
};
};
@ -74,18 +75,20 @@ private "_actionsCfg";
_actionsCfg = configFile >> "CfgVehicles" >> _objectType >> "ACE_SelfActions";
// Create a master action to base on self action
_actions = [[
"Self Actions",
"\a3\ui_f\data\IGUI\Cfg\Actions\eject_ca.paa",
"Spine3",
{ true },
{ true },
10,
[_actionsCfg, ["ACE_SelfActions"]] call _recurseFnc,
GVAR(uidCounter),
["ACE_SelfActions"]
]
_actions = [
[
[
"Self Actions",
"\a3\ui_f\data\IGUI\Cfg\Actions\eject_ca.paa",
"Spine3",
{ true },
{ true },
10,
[false,true,false],
["ACE_SelfActions"]
],
[_actionsCfg, ["ACE_SelfActions"]] call _recurseFnc
]
];
GVAR(uidCounter) = GVAR(uidCounter) + 1;
missionNamespace setVariable [_actionsVarName, _actions];

View File

@ -33,6 +33,5 @@ if(!GVAR(keyDownSelfAction)) then {
};
GVAR(selfMenuOffset) = (positionCameraToWorld [0, 0, 2]) vectorDiff (positionCameraToWorld [0, 0, 0]);
//systemChat format ["GVAR(selfMenuOffset) %1",GVAR(selfMenuOffset)];
};
true

View File

@ -24,7 +24,7 @@ _varName = [QGVAR(actions),QGVAR(selfActions)] select _typeNum;
_actions = _object getVariable [_varName, []];
{
if ((_x select 8) isEqualTo _fullPath) exitWith {
if (((_x select 0) select 7) isEqualTo _fullPath) exitWith {
_actions deleteAt _forEachIndex;
};
} forEach _actions;

View File

@ -22,7 +22,7 @@ GVAR(selfMenuScale) = (((worldToScreen (positionCameraToWorld [1,0,2])) select 0
//systemChat format ["selfMenuScale: %1", GVAR(selfMenuScale)];
GVAR(currentOptions) = [];
private ["_actionsVarName","_classActions","_objectActions","_target","_player","_actionItem","_active"];
private ["_actionsVarName","_classActions","_objectActions","_target","_player","_action","_actionData","_active"];
_player = ACE_player;
if (GVAR(keyDown)) then {
[] call FUNC(updateVecLineMap);
@ -44,11 +44,11 @@ if (GVAR(keyDown)) then {
_actionsVarName = format [QGVAR(Act_%1), typeOf _target];
GVAR(objectActions) = _target getVariable [QGVAR(actions), []];
{
_actionItem = _x;
_action = _x;
// Only render them directly if they are base level actions
if (count (_actionItem select 8) == 1) then {
if (count ((_action select 0) select 7) == 1) then {
// Try to render the menu
if ([_target, _actionItem, false, [180, 360]] call FUNC(renderMenu)) then {
if ([_target, _action] call FUNC(renderBaseMenu)) then {
_numInteractions = _numInteractions + 1;
};
};
@ -57,9 +57,9 @@ if (GVAR(keyDown)) then {
// Iterate through base level class actions and render them if appropiate
_classActions = missionNamespace getVariable [_actionsVarName, []];
{
_actionItem = _x;
_action = _x;
// Try to render the menu
if ([_target, _actionItem, false, [180, 360]] call FUNC(renderMenu)) then {
if ([_target, _action] call FUNC(renderBaseMenu)) then {
_numInteractions = _numInteractions + 1;
};
} forEach _classActions;
@ -86,14 +86,10 @@ if (GVAR(keyDown)) then {
GVAR(objectActions) = _target getVariable [QGVAR(selfActions), []];
/*
{
_actionItem = _x;
_action = _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 {
[_target, _actionItem, 0, [180, 360]] call FUNC(renderMenu);
};
if (count (_action select 7) == 1) then {
[_target, _action, 0, [180, 360]] call FUNC(renderMenu);
};
} forEach GVAR(objectActions);
*/
@ -102,14 +98,10 @@ if (GVAR(keyDown)) then {
_actionsVarName = format [QGVAR(SelfAct_%1), typeOf _target];
_classActions = missionNamespace getVariable [_actionsVarName, []];
{
_actionItem = _x;
_active = [_target, ACE_player] call (_actionItem select 4);
_action = _x;
if (_active) then {
//_pos = (ACE_player modelToWorld (ACE_player selectionPosition "spine3")) vectorAdd GVAR(selfMenuOffset) vectorAdd [0,0,0.25];
_pos = _cursorPos1 vectorAdd GVAR(selfMenuOffset);
[_target, _actionItem, true, [180, 360], _pos] call FUNC(renderMenu);
};
_pos = _cursorPos1 vectorAdd GVAR(selfMenuOffset);
[_target, _action, _pos] call FUNC(renderBaseMenu);
} forEach _classActions;
};
};
@ -154,9 +146,10 @@ if(GVAR(keyDown) || GVAR(keyDownSelfAction)) then {
_foundTarget = true;
GVAR(actionSelected) = true;
GVAR(selectedTarget) = (_closest select 0) select 0;
GVAR(selectedAction) = ((_closest select 0) select 1) select 3;
GVAR(selectedAction) = (((_closest select 0) select 1) select 0) select 3;
_misMatch = false;
_hoverPath = (_closest select 2);
if((count GVAR(lastPath)) != (count _hoverPath)) then {
_misMatch = true;
} else {

View File

@ -0,0 +1,66 @@
/*
* Author: NouberNou and CAA-Picard
* Render the interaction menu for a base action
*
* Argument:
* 0: Object <OBJECT>
* 1: Action data <ARRAY>
* 2: 3D position <ARRAY> (Optional)
*
* Return value:
* Was the menu rendered <BOOL>
*
* Public: No
*/
#include "script_component.hpp"
private ["_distance","_pos","_weaponDir","_ref","_cameraPos","_sPos","_activeActionTree"];
EXPLODE_2_PVT(_this,_object,_baseAction);
EXPLODE_1_PVT(_baseAction,_actionData);
_distance = _actionData select 5;
// Obtain a 3D position for the action
if((count _this) > 2) then {
_pos = _this select 2;
} else {
if(typeName (_actionData select 2) == "ARRAY") then {
_pos = _object modelToWorld (_actionData select 2);
} else {
if ((_actionData select 2) == "weapon") then {
// Craft a suitable position for weapon interaction
_weaponDir = _object weaponDirection currentWeapon _object;
_ref = _weaponDir call EFUNC(common,createOrthonormalReference);
_pos = (_object modelToWorld (_object selectionPosition "righthand")) vectorAdd ((_ref select 2) vectorMultiply 0.1);
} else {
_pos = _object modelToWorld (_object selectionPosition (_actionData select 2));
};
};
};
// For non-self actions, exit if the action is too far away
_cameraPos = positionCameraToWorld [0, 0, 0];
if (GVAR(keyDown) && {_cameraPos distance _pos >= _distance}) exitWith {false};
// Exit if the action is behind you
_sPos = worldToScreen _pos;
if(count _sPos == 0) exitWith {false};
// Exit if the action is off screen
if ((_sPos select 0) < safeZoneXAbs || (_sPos select 0) > safeZoneXAbs + safeZoneWAbs) exitWith {false};
if ((_sPos select 1) < safeZoneY || (_sPos select 1) > safeZoneY + safeZoneH) exitWith {false};
// Collect active tree
// @todo: cache activeActionTree?
_activeActionTree = ([_object, _baseAction] call FUNC(collectActiveActionTree));
// Check if there's something left for rendering
if (count _activeActionTree == 0) exitWith {false};
//EXPLODE_2_PVT(_activeActionTree,_actionData,_actionChildren);
[_object, _activeActionTree, _pos, [180,360]] call FUNC(renderMenu);
true

View File

@ -40,11 +40,10 @@ if(count _sPos > 0) then {
if(_icon == "") then {
_icon = DEFAULT_ICON;
};
//systemChat format ["Ctrl: %1, %2,%3", _text,_sPos select 0, _sPos select 1];
_text = format ["<img image='%1' color='%2' align='center'/><br/><t color ='%3' size='0.75' align='center'>%4</t>", _icon, _color, _color, _text];
_ctrl ctrlSetStructuredText (parseText _text);
_ctrl ctrlSetPosition [(_sPos select 0)-(0.2*SafeZoneW), (_sPos select 1)-(0.0095*SafeZoneW), 0.4*SafeZoneW, 0.035*SafeZoneW];
//_ctrl ctrlSetBackgroundColor [1, 0, 0, 0.1];
// _ctrl ctrlSetBackgroundColor [1,0,0,1];
//_ctrl ctrlSetBackgroundColor [1,0,0,1];
_ctrl ctrlCommit 0;
};

View File

@ -1,70 +1,32 @@
/*
* Author: NouberNou and CAA-Picard
* Render a interaction menu and it's children recursively
* Render an interaction menu and it's children recursively
*
* Argument:
* 0: Object <OBJECT>
* 1: Action data <ARRAY>
* 2: Was the condition already checked? <BOOL>
* 2: 3D position <ARRAY>
* 3: Angle range available for rendering <ARRAY>
* 4: 3D position <ARRAY> (Optional)
*
* Return value:
* Was the menu rendered <BOOL>
* None
*
* Public: No
*/
#include "script_component.hpp"
private ["_distance", "_uid", "_pos", "_cameraPos", "_path", "_menuDepth", "_opacity", "_currentRenderDepth", "_radialOffset", "_active", "_x", "_offset", "_newPos", "_forEachIndex"];
private ["_menuInSelectedPath", "_path", "_menuDepth", "_currentRenderDepth", "_x", "_offset", "_newPos", "_forEachIndex"];
EXPLODE_4_PVT(_this,_object,_actionData,_wasConditionChecked,_angles);
EXPLODE_4_PVT(_this,_object,_action,_pos,_angles);
EXPLODE_2_PVT(_action,_actionData,_activeChildren);
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 {
if(typeName (_actionData select 2) == "ARRAY") then {
_pos = _object modelToWorld (_actionData select 2);
} else {
if ((_actionData select 2) == "weapon") then {
// Craft a suitable position for weapon interaction
_weaponDir = _object weaponDirection currentWeapon _object;
_ref = _weaponDir call EFUNC(common,createOrthonormalReference);
_pos = (_object modelToWorld (_object selectionPosition "righthand")) vectorAdd ((_ref select 2) vectorMultiply 0.1);
} else {
_pos = _object modelToWorld (_object selectionPosition (_actionData select 2));
};
};
};
// For non-self actions, exit if the action is too far away
_cameraPos = positionCameraToWorld [0, 0, 0];
if (GVAR(keyDown) && {_cameraPos distance _pos >= _distance}) exitWith {false};
// Exit if the action is behind you
_sPos = worldToScreen _pos;
if(count _sPos == 0) exitWith {false};
// Exit if the action is off screen
if ((_sPos select 0) < safeZoneXAbs || (_sPos select 0) > safeZoneXAbs + safeZoneWAbs) exitWith {false};
if ((_sPos select 1) < safeZoneY || (_sPos select 1) > safeZoneY + safeZoneH) exitWith {false};
// If the condition was not checked, check it and exit if needed
if (!_wasConditionChecked && {!([_target, ACE_player] call (_actionItem select 4))}) exitWith {false};
_menuDepth = (count GVAR(menuDepthPath)) - 1;
// Store path to action
_path = [_object];
_path = _path + (_actionData select 8);
_path = [_object] + (_actionData select 7);
// Check if the menu is on the selected path
private "_menuInSelectedPath";
_menuInSelectedPath = true;
{
if (_forEachIndex >= (count GVAR(menuDepthPath))) exitWith {
@ -93,10 +55,6 @@ GVAR(currentOptions) pushBack [_this, _pos, _path];
// Exit without rendering children if it isn't
if !(_menuInSelectedPath) exitWith {true};
// Collect all active children actions
private "_activeChildren";
_activeChildren = [_object,_actionData] call FUNC(collectActiveChildren);
private ["_angleSpan","_angle"];
_angleSpan = _maxAngleSpan min (55 * ((count _activeChildren) - 1));
if (_angleSpan >= 305) then {
@ -109,12 +67,12 @@ _angle = _centerAngle - _angleSpan / 2;
_player = ACE_player;
_offset = [GVAR(vecLineMap), _angle] call FUNC(rotateVectLine);
_mod = (0.15 max (0.15 * (_cameraPos distance _pos))) / GVAR(selfMenuScale);
_mod = (0.15 max (0.15 * ((positionCameraToWorld [0, 0, 0]) distance _pos))) / GVAR(selfMenuScale);
_newPos = _pos vectorAdd (_offset vectorMultiply _mod);
// drawLine3D [_pos, _newPos, [1,0,0,0.5]];
//drawLine3D [_pos, _newPos, [1,0,0,0.5]];
[_object, _x, true, [_angle, 140], _newPos] call FUNC(renderMenu);
[_object, _x, _newPos, [_angle, 140]] call FUNC(renderMenu);
if (_angleSpan == 360) then {
_angle = _angle + _angleSpan / (count _activeChildren);