mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
Spectator overhaul (#5171)
- Overhauls the spectator module entirely to share a similar UX to BI's "End Game Spectator" while maintaining some of the extended flexibility of ACE Spectator. - Simplifies spectator setup by reducing the number of settings. More advanced setup is still possible via the API functions provided.
This commit is contained in:
parent
606e9c088d
commit
d3ce75daef
@ -77,6 +77,7 @@ PREP(getTurretDirection);
|
||||
PREP(getUavControlPosition);
|
||||
PREP(getVehicleCargo);
|
||||
PREP(getVehicleCodriver);
|
||||
PREP(getVehicleIcon);
|
||||
PREP(getVersion);
|
||||
PREP(getWeaponAzimuthAndInclination);
|
||||
PREP(getWeaponIndex);
|
||||
@ -99,6 +100,7 @@ PREP(isEngineer);
|
||||
PREP(isEOD);
|
||||
PREP(isFeatureCameraActive);
|
||||
PREP(isInBuilding);
|
||||
PREP(isMedic);
|
||||
PREP(isModLoaded);
|
||||
PREP(isPlayer);
|
||||
PREP(isUnderwater);
|
||||
|
50
addons/common/functions/fnc_getVehicleIcon.sqf
Normal file
50
addons/common/functions/fnc_getVehicleIcon.sqf
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Author: AACO
|
||||
* Function used to get the vehicle icon for provided object (cached for repeat use)
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Object to get icon of <OBJECT/STRING>
|
||||
*
|
||||
* Return Value:
|
||||
* Icon of vehicle <STRING>
|
||||
*
|
||||
* Examples:
|
||||
* ["B_Soldier_F"] call ace_common_fnc_getVehicleIcon;
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
#define DEFAULT_TEXTURE "\A3\ui_f\data\Map\VehicleIcons\iconVehicle_ca.paa"
|
||||
|
||||
params [["_object", objNull, [objNull, ""]]];
|
||||
|
||||
if ((_object isEqualType objNull && {isNull _object}) || {_object isEqualType "" && {_object == ""}}) exitWith { DEFAULT_TEXTURE };
|
||||
|
||||
ISNILS(GVAR(vehicleIconCache),call CBA_fnc_createNamespace);
|
||||
|
||||
private _objectType = if (_object isEqualType objNull) then {
|
||||
typeOf _object
|
||||
} else {
|
||||
_object
|
||||
};
|
||||
private _cachedValue = GVAR(vehicleIconCache) getVariable _objectType;
|
||||
|
||||
if (isNil "_cachedValue") then {
|
||||
private _vehicleValue = getText (configfile >> "CfgVehicles" >> _objectType >> "icon");
|
||||
private _vehicleIconValue = getText (configfile >> "CfgVehicleIcons" >> _vehicleValue);
|
||||
|
||||
if (_vehicleIconValue == "") then {
|
||||
if (_vehicleValue != "" && {((toLower _vehicleValue) find ".paa") > -1}) then {
|
||||
_cachedValue = _vehicleValue;
|
||||
} else {
|
||||
_cachedValue = DEFAULT_TEXTURE;
|
||||
};
|
||||
} else {
|
||||
_cachedValue = _vehicleIconValue;
|
||||
};
|
||||
|
||||
GVAR(vehicleIconCache) setVariable [_objectType, _cachedValue];
|
||||
};
|
||||
|
||||
_cachedValue
|
23
addons/common/functions/fnc_isMedic.sqf
Normal file
23
addons/common/functions/fnc_isMedic.sqf
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Check if a unit is a medic
|
||||
*
|
||||
* Arguments:
|
||||
* 0: The Unit <OBJECT>
|
||||
*
|
||||
* ReturnValue:
|
||||
* Unit is medic <BOOL>
|
||||
*
|
||||
* Example:
|
||||
* [player] call ace_common_fnc_isMedic
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_unit"];
|
||||
|
||||
private _isMedic = _unit getVariable [QEGVAR(medical,medicClass), getNumber (configFile >> "CfgVehicles" >> typeOf _unit >> "attendant")];
|
||||
|
||||
_isMedic > 0
|
@ -1,24 +1,16 @@
|
||||
class ACE_Settings {
|
||||
class GVAR(filterUnits) {
|
||||
displayName = CSTRING(units_DisplayName);
|
||||
description = CSTRING(units_Description);
|
||||
typeName = "SCALAR";
|
||||
value = 2;
|
||||
values[] = {CSTRING(units_none), CSTRING(units_players), CSTRING(units_playable), CSTRING(units_all)};
|
||||
};
|
||||
class GVAR(filterSides) {
|
||||
displayName = CSTRING(sides_DisplayName);
|
||||
description = CSTRING(sides_Description);
|
||||
typeName = "SCALAR";
|
||||
class GVAR(enableAI) {
|
||||
displayName = CSTRING(ai_DisplayName);
|
||||
description = CSTRING(ai_Description);
|
||||
typeName = "BOOL";
|
||||
value = 0;
|
||||
values[] = {CSTRING(sides_player), CSTRING(sides_friendly), CSTRING(sides_hostile), CSTRING(sides_all)};
|
||||
};
|
||||
class GVAR(restrictModes) {
|
||||
displayName = CSTRING(modes_DisplayName);
|
||||
description = CSTRING(modes_Description);
|
||||
typeName = "SCALAR";
|
||||
value = 0;
|
||||
values[] = {CSTRING(modes_all), CSTRING(modes_unit), CSTRING(modes_free), CSTRING(modes_internal), CSTRING(modes_external)};
|
||||
values[] = {CSTRING(modes_all), CSTRING(modes_unit), "$STR_A3_Spectator_free_camera_tooltip", "$STR_A3_Spectator_1pp_camera_tooltip", "$STR_A3_Spectator_3pp_camera_tooltip"};
|
||||
};
|
||||
class GVAR(restrictVisions) {
|
||||
displayName = CSTRING(visions_DisplayName);
|
||||
@ -27,4 +19,10 @@ class ACE_Settings {
|
||||
value = 0;
|
||||
values[] = {CSTRING(modes_all), CSTRING(visions_nv), CSTRING(visions_ti), "$STR_Special_None"};
|
||||
};
|
||||
class GVAR(mapLocations) {
|
||||
displayName = CSTRING(mapLocations_DisplayName);
|
||||
description = CSTRING(mapLocations_Description);
|
||||
typeName = "BOOL";
|
||||
value = 0;
|
||||
};
|
||||
};
|
||||
|
@ -16,3 +16,15 @@ class Extended_PostInit_EventHandlers {
|
||||
init = QUOTE(call COMPILE_FILE(XEH_postInit));
|
||||
};
|
||||
};
|
||||
|
||||
class Extended_DisplayLoad_EventHandlers {
|
||||
class RscRespawnCounter {
|
||||
ADDON = QUOTE(_this call FUNC(compat_counter));
|
||||
};
|
||||
class RscDisplayEGSpectator {
|
||||
ADDON = QUOTE(_this call FUNC(compat_spectatorBI));
|
||||
};
|
||||
class RscDisplayCurator {
|
||||
ADDON = QUOTE(_this call FUNC(compat_zeus));
|
||||
};
|
||||
};
|
||||
|
@ -3,59 +3,17 @@ class CfgVehicles {
|
||||
class GVAR(moduleSettings): ACE_Module {
|
||||
scope = 2;
|
||||
displayName = CSTRING(Settings_DisplayName);
|
||||
icon = QPATHTOF(UI\Icon_Module_Spectator_ca.paa);
|
||||
icon = QPATHTOF(data\Icon_Module_Spectator_ca.paa);
|
||||
category = "ACE";
|
||||
function = QFUNC(moduleSpectatorSettings);
|
||||
isGlobal = 1;
|
||||
author = ECSTRING(common,ACETeam);
|
||||
class Arguments {
|
||||
class unitsFilter {
|
||||
displayName = CSTRING(units_DisplayName);
|
||||
description = CSTRING(units_Description);
|
||||
typeName = "NUMBER";
|
||||
class values {
|
||||
class none {
|
||||
name = CSTRING(units_none);
|
||||
value = 0;
|
||||
};
|
||||
class players {
|
||||
name = CSTRING(units_players);
|
||||
value = 1;
|
||||
};
|
||||
class playable {
|
||||
name = CSTRING(units_playable);
|
||||
value = 2;
|
||||
default = 1;
|
||||
};
|
||||
class all {
|
||||
name = CSTRING(units_all);
|
||||
value = 3;
|
||||
};
|
||||
};
|
||||
};
|
||||
class sidesFilter {
|
||||
displayName = CSTRING(sides_DisplayName);
|
||||
description = CSTRING(sides_Description);
|
||||
typeName = "NUMBER";
|
||||
class values {
|
||||
class player {
|
||||
name = CSTRING(sides_player);
|
||||
value = 0;
|
||||
default = 1;
|
||||
};
|
||||
class friendly {
|
||||
name = CSTRING(sides_friendly);
|
||||
value = 1;
|
||||
};
|
||||
class hostile {
|
||||
name = CSTRING(sides_hostile);
|
||||
value = 2;
|
||||
};
|
||||
class all {
|
||||
name = CSTRING(sides_all);
|
||||
value = 3;
|
||||
};
|
||||
};
|
||||
class enableAI {
|
||||
displayName = CSTRING(ai_DisplayName);
|
||||
description = CSTRING(ai_Description);
|
||||
typeName = "BOOL";
|
||||
defaultValue = 0;
|
||||
};
|
||||
class cameraModes {
|
||||
displayName = CSTRING(modes_DisplayName);
|
||||
@ -72,15 +30,15 @@ class CfgVehicles {
|
||||
value = 1;
|
||||
};
|
||||
class free {
|
||||
name = CSTRING(modes_free);
|
||||
name = "$STR_A3_Spectator_free_camera_tooltip";
|
||||
value = 2;
|
||||
};
|
||||
class internal {
|
||||
name = CSTRING(modes_internal);
|
||||
name = "$STR_A3_Spectator_1pp_camera_tooltip";
|
||||
value = 3;
|
||||
};
|
||||
class external {
|
||||
name = CSTRING(modes_external);
|
||||
name = "$STR_A3_Spectator_3pp_camera_tooltip";
|
||||
value = 4;
|
||||
};
|
||||
};
|
||||
@ -109,9 +67,28 @@ class CfgVehicles {
|
||||
};
|
||||
};
|
||||
};
|
||||
class mapLocations {
|
||||
displayName = CSTRING(mapLocations_DisplayName);
|
||||
description = CSTRING(mapLocations_Description);
|
||||
typeName = "BOOL";
|
||||
defaultValue = 0;
|
||||
};
|
||||
};
|
||||
class ModuleDescription {
|
||||
description = CSTRING(Settings_Description);
|
||||
};
|
||||
};
|
||||
class VirtualMan_F;
|
||||
class GVAR(virtual): VirtualMan_F {
|
||||
author = ECSTRING(common,ACETeam);
|
||||
displayName = CSTRING(DisplayName);
|
||||
scope = 2;
|
||||
scopeArsenal = 0;
|
||||
scopeCurator = 0;
|
||||
|
||||
weapons[] = {};
|
||||
|
||||
delete ACE_Actions;
|
||||
delete ACE_SelfActions;
|
||||
};
|
||||
};
|
||||
|
@ -1,255 +0,0 @@
|
||||
// Temporary fix until BI take care of it
|
||||
class RscFrame {
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = 0;
|
||||
h = 0;
|
||||
};
|
||||
|
||||
|
||||
class RscButtonMenu;
|
||||
class RscControlsGroupNoScrollbars;
|
||||
//class RscFrame;
|
||||
class RscListBox;
|
||||
class RscMapControl;
|
||||
class RscPicture;
|
||||
class RscText;
|
||||
class RscTree;
|
||||
|
||||
class GVAR(interface) {
|
||||
idd = 12249;
|
||||
enableSimulation = 1;
|
||||
movingEnable = 0;
|
||||
onLoad = QUOTE([ARR_2('onLoad',_this)] call FUNC(handleInterface));
|
||||
onUnload = QUOTE([ARR_2('onUnload',_this)] call FUNC(handleInterface));
|
||||
onKeyDown = QUOTE([ARR_2('onKeyDown',_this)] call FUNC(handleInterface));
|
||||
onKeyUp = QUOTE([ARR_2('onKeyUp',_this)] call FUNC(handleInterface));
|
||||
class controlsBackground {
|
||||
class mouseHandler: RscControlsGroupNoScrollbars {
|
||||
x = safeZoneXAbs;
|
||||
y = safeZoneY;
|
||||
w = safeZoneWAbs;
|
||||
h = safeZoneH;
|
||||
onMouseButtonDown = QUOTE([ARR_2('onMouseButtonDown',_this)] call FUNC(handleInterface));
|
||||
onMouseButtonUp = QUOTE([ARR_2('onMouseButtonUp',_this)] call FUNC(handleInterface));
|
||||
onMouseZChanged = QUOTE([ARR_2('onMouseZChanged',_this)] call FUNC(handleInterface));
|
||||
onMouseMoving = QUOTE([ARR_2('onMouseMoving',_this)] call FUNC(handleInterface));
|
||||
onMouseHolding = QUOTE([ARR_2('onMouseMoving',_this)] call FUNC(handleInterface));
|
||||
};
|
||||
};
|
||||
class controls {
|
||||
class compass: RscControlsGroupNoScrollbars {
|
||||
idc = IDC_COMP;
|
||||
x = COMPASS_X;
|
||||
y = safeZoneY;
|
||||
w = COMPASS_W;
|
||||
h = TOOL_H;
|
||||
class controls {
|
||||
class compassBack: RscText {
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = COMPASS_W;
|
||||
h = TOOL_H;
|
||||
colorBackground[] = {COL_BACK};
|
||||
};
|
||||
class compass0_90: RscPicture {
|
||||
idc = IDC_COMP_0;
|
||||
x = COMPASS_W * 0.5;
|
||||
y = 0;
|
||||
w = COMPASS_W * 0.5;
|
||||
h = TOOL_H;
|
||||
text = "A3\UI_F_Curator\Data\CfgIngameUI\compass\texture180_ca.paa";
|
||||
};
|
||||
class compass90_180: compass0_90 {
|
||||
idc = IDC_COMP_90;
|
||||
x = COMPASS_W;
|
||||
text = "A3\UI_F_Curator\Data\CfgIngameUI\compass\texture270_ca.paa";
|
||||
};
|
||||
class compass180_270: compass0_90 {
|
||||
idc = IDC_COMP_180;
|
||||
x = 0;
|
||||
text = "A3\UI_F_Curator\Data\CfgIngameUI\compass\texture0_ca.paa";
|
||||
};
|
||||
class compass270_0: compass0_90 {
|
||||
idc = IDC_COMP_270;
|
||||
x = COMPASS_W * -0.5;
|
||||
text = "A3\UI_F_Curator\Data\CfgIngameUI\compass\texture90_ca.paa";
|
||||
};
|
||||
class compassCaret: RscFrame {
|
||||
x = COMPASS_W * 0.5;
|
||||
y = 0;
|
||||
w = 0;
|
||||
h = TOOL_H;
|
||||
colorText[] = {COL_FORE};
|
||||
};
|
||||
class compassFrame: compassBack {
|
||||
style = 64;
|
||||
shadow=2;
|
||||
colorText[] = {COL_FORE};
|
||||
};
|
||||
};
|
||||
};
|
||||
class toolbar: RscControlsGroupNoScrollbars {
|
||||
idc = IDC_TOOL;
|
||||
x = safeZoneX;
|
||||
y = safeZoneY + safeZoneH - TOOL_H;
|
||||
w = safeZoneW;
|
||||
h = TOOL_H;
|
||||
class controls {
|
||||
class nameTool: RscText {
|
||||
idc = IDC_TOOL_NAME;
|
||||
style = 2;
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = TOOL_W * 2;
|
||||
h = TOOL_H;
|
||||
shadow = 2;
|
||||
colorText[]={COL_FORE};
|
||||
colorBackground[] = {COL_BACK};
|
||||
sizeEx = H_PART(1);
|
||||
};
|
||||
class nameFrame: nameTool {
|
||||
idc = -1;
|
||||
style = 64;
|
||||
};
|
||||
class viewTool: nameTool {
|
||||
idc = IDC_TOOL_VIEW;
|
||||
x = TOOL_W * 2 + MARGIN;
|
||||
w = TOOL_W;
|
||||
};
|
||||
class viewFrame: viewTool {
|
||||
idc = -1;
|
||||
style = 64;
|
||||
};
|
||||
class visionTool: viewTool {
|
||||
idc = IDC_TOOL_VISION;
|
||||
x = TOOL_W * 3 + MARGIN * 2;
|
||||
};
|
||||
class visionFrame: visionTool {
|
||||
idc = -1;
|
||||
style = 64;
|
||||
};
|
||||
class clockTool: viewTool {
|
||||
idc = IDC_TOOL_CLOCK;
|
||||
x = safeZoneW - TOOL_W * 3 - MARGIN * 2;
|
||||
};
|
||||
class clockFrame: clockTool {
|
||||
idc = -1;
|
||||
style = 64;
|
||||
};
|
||||
class zoomTool: viewTool {
|
||||
idc = IDC_TOOL_FOV;
|
||||
x = safeZoneW - TOOL_W * 2 - MARGIN;
|
||||
};
|
||||
class zoomFrame: zoomTool {
|
||||
idc = -1;
|
||||
style = 64;
|
||||
};
|
||||
class speedTool: viewTool {
|
||||
idc = IDC_TOOL_SPEED;
|
||||
x = safeZoneW - TOOL_W;
|
||||
};
|
||||
class speedFrame: speedTool {
|
||||
idc = -1;
|
||||
style = 64;
|
||||
};
|
||||
};
|
||||
};
|
||||
class unitWindow: RscControlsGroupNoScrollbars {
|
||||
idc = IDC_UNIT;
|
||||
x = safeZoneX;
|
||||
y = safeZoneY + TOOL_H * 6;
|
||||
w = TOOL_W * 2;
|
||||
h = safeZoneH - TOOL_H * 13;
|
||||
class controls {
|
||||
class unitTitle: RscText {
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = TOOL_W * 2;
|
||||
h = H_PART(1);
|
||||
style = 2;
|
||||
colorText[] = {COL_FORE};
|
||||
colorBackground[] = {COL_FORE_D};
|
||||
sizeEx = H_PART(1);
|
||||
text = CSTRING(UnitTitle);
|
||||
};
|
||||
class unitTree: RscTree {
|
||||
idc = IDC_UNIT_TREE;
|
||||
x = 0;
|
||||
y = H_PART(1);
|
||||
w = TOOL_W * 2;
|
||||
h = safeZoneH - TOOL_H * 14;
|
||||
sizeEx = H_PART(0.8);
|
||||
colorText[] = {COL_FORE};
|
||||
colorBorder[] = {0,0,0,0};
|
||||
colorBackground[] = {COL_BACK};
|
||||
colorSelect[] = {
|
||||
"profilenamespace getVariable ['GUI_BCG_RGB_R',0.77]",
|
||||
"profilenamespace getVariable ['GUI_BCG_RGB_G',0.51]",
|
||||
"profilenamespace getVariable ['GUI_BCG_RGB_B',0.08]",
|
||||
1
|
||||
};
|
||||
multiselectEnabled = 0;
|
||||
disableKeyboardSearch = 1;
|
||||
onTreeDblClick = QUOTE([ARR_2('onTreeDblClick',_this)] call FUNC(handleInterface));
|
||||
};
|
||||
class unitFrame: RscFrame {
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = TOOL_W * 2;
|
||||
h = safeZoneH - TOOL_H * 13;
|
||||
shadow = 2;
|
||||
colorText[] = {COL_FORE};
|
||||
};
|
||||
};
|
||||
};
|
||||
class helpWindow: RscControlsGroupNoScrollbars {
|
||||
idc = IDC_HELP;
|
||||
x = safeZoneX + safeZoneW - TOOL_W * 2;
|
||||
y = safeZoneY + TOOL_H * 6;
|
||||
w = TOOL_W * 2;
|
||||
h = safeZoneH - TOOL_H * 13;
|
||||
class controls {
|
||||
class helpTitle: RscText {
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = TOOL_W * 2;
|
||||
h = H_PART(1);
|
||||
style = 2;
|
||||
colorText[] = {COL_FORE};
|
||||
colorBackground[] = {COL_FORE_D};
|
||||
sizeEx = H_PART(1);
|
||||
text = CSTRING(HelpTitle);
|
||||
};
|
||||
class helpContent: RscListBox {
|
||||
idc = IDC_HELP_LIST;
|
||||
x = 0;
|
||||
y = H_PART(1);
|
||||
w = TOOL_W * 2;
|
||||
h = safeZoneH - TOOL_H * 14;
|
||||
colorBackground[] = {COL_BACK};
|
||||
sizeEx = H_PART(0.8);
|
||||
default = 1;
|
||||
};
|
||||
class helpFrame: RscFrame {
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = TOOL_W * 2;
|
||||
h = safeZoneH - TOOL_H * 13;
|
||||
shadow = 2;
|
||||
colorText[] = {COL_FORE};
|
||||
};
|
||||
};
|
||||
};
|
||||
class mapOverlay: RscMapControl {
|
||||
idc = IDC_MAP;
|
||||
type = 100;
|
||||
x = safeZoneX;
|
||||
y = safeZoneY;
|
||||
w = safeZoneW;
|
||||
h = safeZoneH;
|
||||
onMouseButtonDown = QUOTE([ARR_2('onMapClick',_this)] call FUNC(handleInterface));
|
||||
onDraw = QUOTE(_this call FUNC(handleMap));
|
||||
};
|
||||
};
|
||||
};
|
@ -1,23 +1,67 @@
|
||||
// Camera functions
|
||||
PREP(cam);
|
||||
PREP(cam_prepareTarget);
|
||||
PREP(cam_resetTarget);
|
||||
PREP(cam_setCameraMode);
|
||||
PREP(cam_setTarget);
|
||||
PREP(cam_setVisionMode);
|
||||
PREP(cam_tick);
|
||||
PREP(cam_toggleSlow);
|
||||
|
||||
PREP(cacheUnitInfo);
|
||||
PREP(cycleCamera);
|
||||
PREP(handleCamera);
|
||||
PREP(handleCompass);
|
||||
PREP(handleIcons);
|
||||
PREP(handleInterface);
|
||||
PREP(handleMap);
|
||||
PREP(handleMouse);
|
||||
PREP(handleToolbar);
|
||||
PREP(handleUnits);
|
||||
PREP(interrupt);
|
||||
// UI functions
|
||||
PREP(ui);
|
||||
PREP(ui_draw3D);
|
||||
PREP(ui_fadeList);
|
||||
PREP(ui_getTreeDataIndex);
|
||||
PREP(ui_handleChildDestroyed);
|
||||
PREP(ui_handleKeyDown);
|
||||
PREP(ui_handleKeyUp);
|
||||
PREP(ui_handleListClick);
|
||||
PREP(ui_handleMapClick);
|
||||
PREP(ui_handleMapDraw);
|
||||
PREP(ui_handleMouseButtonDblClick);
|
||||
PREP(ui_handleMouseButtonDown);
|
||||
PREP(ui_handleMouseMoving);
|
||||
PREP(ui_handleMouseZChanged);
|
||||
PREP(ui_handleTabSelected);
|
||||
PREP(ui_toggleMap);
|
||||
PREP(ui_toggleUI);
|
||||
PREP(ui_updateCamButtons);
|
||||
PREP(ui_updateHelp);
|
||||
PREP(ui_updateIconsToDraw);
|
||||
PREP(ui_updateListEntities);
|
||||
PREP(ui_updateListFocus);
|
||||
PREP(ui_updateListLocations);
|
||||
PREP(ui_updateWidget);
|
||||
|
||||
// Utility functions
|
||||
PREP(compat_counter);
|
||||
PREP(compat_spectatorBI);
|
||||
PREP(compat_zeus);
|
||||
PREP(getGroupIcon);
|
||||
PREP(getTargetEntities);
|
||||
PREP(handleFired);
|
||||
PREP(moduleSpectatorSettings);
|
||||
PREP(respawnTemplate);
|
||||
PREP(setFocus);
|
||||
PREP(stageSpectator);
|
||||
PREP(switchFocus);
|
||||
|
||||
// Public functions
|
||||
PREP(addLocation);
|
||||
PREP(getCameraAttributes);
|
||||
PREP(players);
|
||||
PREP(removeLocation);
|
||||
PREP(setCameraAttributes);
|
||||
PREP(setSpectator);
|
||||
PREP(stageSpectator);
|
||||
PREP(transitionCamera);
|
||||
PREP(toggleInterface);
|
||||
PREP(updateCameraModes);
|
||||
PREP(updateSpectatableSides);
|
||||
PREP(updateSides);
|
||||
PREP(updateUnits);
|
||||
PREP(updateVisionModes);
|
||||
|
||||
// Deprecated (temp)
|
||||
PREP(interrupt);
|
||||
DFUNC(updateSpectatableSides) = {
|
||||
ACE_DEPRECATED(QFUNC(updateSpectatableSides),"3.12.0",QFUNC(updateSides));
|
||||
_this call FUNC(updateSides);
|
||||
};
|
||||
|
@ -1,31 +1,51 @@
|
||||
#include "script_component.hpp"
|
||||
//#include "initKeybinds.sqf";
|
||||
|
||||
// Add interaction menu exception
|
||||
["isNotSpectating", {!(GETVAR((_this select 0),GVAR(isStaged),false))}] call EFUNC(common,addCanInteractWithCondition);
|
||||
|
||||
["ace_settingsInitialized", {
|
||||
GVAR(availableModes) = [[0,1,2], [1,2], [0], [1], [2]] select GVAR(restrictModes);
|
||||
GVAR(availableVisions) = [[-2,-1,0,1], [-2,-1], [-2,0,1], [-2]] select GVAR(restrictVisions);
|
||||
}] call CBA_fnc_addEventHandler;
|
||||
|
||||
// Create a radio channel for any spectators to text chat in
|
||||
if (isServer) then {
|
||||
GVAR(channel) = radioChannelCreate [[0.729,0.149,0.098,1],"Spectator","Spectator (%UNIT_NAME)",[]];
|
||||
publicVariable QGVAR(channel);
|
||||
};
|
||||
|
||||
// Should prevent unending spectator on mission end
|
||||
if (isServer) then {
|
||||
addMissionEventHandler ["Ended", {
|
||||
[QGVAR(endMission), []] call CBA_fnc_globalEvent;
|
||||
}];
|
||||
};
|
||||
|
||||
[QGVAR(endMission), {
|
||||
if (GVAR(isSet)) then {
|
||||
[false] call FUNC(setSpectator);
|
||||
if (GVAR(mapLocations)) then {
|
||||
private _worldWidth = worldSize / 2;
|
||||
{
|
||||
[locationPosition _x, [text _x] call CBA_fnc_capitalize] call FUNC(addLocation);
|
||||
} forEach nearestLocations [
|
||||
[_worldWidth, _worldWidth],
|
||||
["NameVillage", "NameCity", "NameCityCapital", "NameLocal", "NameMarine"],
|
||||
_worldWidth * sqrt 2
|
||||
];
|
||||
};
|
||||
}] call CBA_fnc_addEventHandler;
|
||||
|
||||
if (isServer) then {
|
||||
// Create a radio channel for any spectators to text chat in
|
||||
GVAR(channel) = radioChannelCreate [[0.729,0.149,0.098,1],"Spectator","Spectator (%UNIT_NAME)",[]];
|
||||
publicVariable QGVAR(channel);
|
||||
|
||||
// Used by the template to transfer zeus to virtual unit
|
||||
// Commands must be ran on server
|
||||
[QGVAR(transferZeus),{
|
||||
unassignCurator (_this select 1);
|
||||
|
||||
// Can only re-assign when ready
|
||||
[
|
||||
{isNull getAssignedCuratorUnit (_this select 0)},
|
||||
{(_this select 0) assignCurator (_this select 1)},
|
||||
_this
|
||||
] call CBA_fnc_waitUntilAndExecute;
|
||||
}] call CBA_fnc_addEventHandler;
|
||||
};
|
||||
|
||||
[QGVAR(stageSpectator), FUNC(stageSpectator)] call CBA_fnc_addEventHandler;
|
||||
|
||||
// Delay until local player (must not be ACE_Player) is fully initalized
|
||||
[
|
||||
{ !isNil { player } && { !isNull player } },
|
||||
{
|
||||
// Initalise virtual spectator players (must not be ACE_Player)
|
||||
[QGVAR(virtual),"initpost",{
|
||||
if !(GVAR(isSet)) then {
|
||||
if (player == (_this select 0)) then { [true] call FUNC(setSpectator) };
|
||||
};
|
||||
},false,[],true] call CBA_fnc_addClassEventHandler;
|
||||
},[]
|
||||
] call CBA_fnc_waitUntilAndExecute;
|
||||
|
@ -6,39 +6,17 @@ PREP_RECOMPILE_START;
|
||||
#include "XEH_PREP.hpp"
|
||||
PREP_RECOMPILE_END;
|
||||
|
||||
// Reset the stored display
|
||||
SETUVAR(GVAR(interface),displayNull);
|
||||
|
||||
// Permanent variables
|
||||
GVAR(availableModes) = [0,1,2];
|
||||
// Used by public functions
|
||||
GVAR(availableModes) = [MODE_FREE, MODE_FPS, MODE_FOLLOW];
|
||||
GVAR(availableSides) = [west,east,resistance,civilian];
|
||||
GVAR(availableVisions) = [-2,-1,0,1];
|
||||
|
||||
GVAR(camAgent) = objNull;
|
||||
GVAR(camDistance) = 10;
|
||||
GVAR(camMode) = 0;
|
||||
GVAR(camPan) = 0;
|
||||
GVAR(camPos) = ATLtoASL [worldSize * 0.5, worldSize * 0.5, 20];
|
||||
GVAR(camSpeed) = 1.5;
|
||||
GVAR(camTilt) = -10;
|
||||
GVAR(camUnit) = objNull;
|
||||
GVAR(camVision) = -2;
|
||||
GVAR(camZoom) = 1.25;
|
||||
|
||||
GVAR(availableVisions) = [VISION_NORM,VISION_NVG,0,1];
|
||||
GVAR(interrupts) = [];
|
||||
GVAR(isSet) = false;
|
||||
|
||||
GVAR(showComp) = true;
|
||||
GVAR(showHelp) = true;
|
||||
GVAR(showIcons) = true;
|
||||
GVAR(showInterface) = true;
|
||||
GVAR(showMap) = false;
|
||||
GVAR(showTool) = true;
|
||||
GVAR(showUnit) = true;
|
||||
|
||||
GVAR(unitList) = [];
|
||||
GVAR(locationCount) = 0;
|
||||
GVAR(locationsList) = [];
|
||||
GVAR(unitBlacklist) = [];
|
||||
GVAR(unitWhitelist) = [];
|
||||
GVAR(groupList) = [];
|
||||
|
||||
// Tracks whether spectator is active
|
||||
GVAR(isSet) = false;
|
||||
|
||||
ADDON = true;
|
||||
|
@ -17,13 +17,13 @@ class CfgPatches {
|
||||
#include "ACE_Settings.hpp"
|
||||
#include "CfgEventHandlers.hpp"
|
||||
#include "CfgVehicles.hpp"
|
||||
#include "ui\interface.hpp"
|
||||
#include "ui.hpp"
|
||||
|
||||
class CfgRespawnTemplates {
|
||||
class ADDON {
|
||||
displayName = CSTRING(DisplayName);
|
||||
onPlayerKilled = QFUNC(respawnTemplate);
|
||||
onPlayerRespawn = QFUNC(respawnTemplate);
|
||||
respawnTypes[] = {2,3};
|
||||
respawnTypes[] = {1,2,3,4,5};
|
||||
};
|
||||
};
|
||||
|
BIN
addons/spectator/data/b_air.paa
Normal file
BIN
addons/spectator/data/b_air.paa
Normal file
Binary file not shown.
BIN
addons/spectator/data/b_armor.paa
Normal file
BIN
addons/spectator/data/b_armor.paa
Normal file
Binary file not shown.
BIN
addons/spectator/data/b_art.paa
Normal file
BIN
addons/spectator/data/b_art.paa
Normal file
Binary file not shown.
BIN
addons/spectator/data/b_inf.paa
Normal file
BIN
addons/spectator/data/b_inf.paa
Normal file
Binary file not shown.
BIN
addons/spectator/data/b_installation.paa
Normal file
BIN
addons/spectator/data/b_installation.paa
Normal file
Binary file not shown.
BIN
addons/spectator/data/b_maint.paa
Normal file
BIN
addons/spectator/data/b_maint.paa
Normal file
Binary file not shown.
BIN
addons/spectator/data/b_mech_inf.paa
Normal file
BIN
addons/spectator/data/b_mech_inf.paa
Normal file
Binary file not shown.
BIN
addons/spectator/data/b_med.paa
Normal file
BIN
addons/spectator/data/b_med.paa
Normal file
Binary file not shown.
BIN
addons/spectator/data/b_mortar.paa
Normal file
BIN
addons/spectator/data/b_mortar.paa
Normal file
Binary file not shown.
BIN
addons/spectator/data/b_motor_inf.paa
Normal file
BIN
addons/spectator/data/b_motor_inf.paa
Normal file
Binary file not shown.
BIN
addons/spectator/data/b_naval.paa
Normal file
BIN
addons/spectator/data/b_naval.paa
Normal file
Binary file not shown.
BIN
addons/spectator/data/b_plane.paa
Normal file
BIN
addons/spectator/data/b_plane.paa
Normal file
Binary file not shown.
BIN
addons/spectator/data/b_recon.paa
Normal file
BIN
addons/spectator/data/b_recon.paa
Normal file
Binary file not shown.
BIN
addons/spectator/data/b_service.paa
Normal file
BIN
addons/spectator/data/b_service.paa
Normal file
Binary file not shown.
BIN
addons/spectator/data/b_support.paa
Normal file
BIN
addons/spectator/data/b_support.paa
Normal file
Binary file not shown.
BIN
addons/spectator/data/b_uav.paa
Normal file
BIN
addons/spectator/data/b_uav.paa
Normal file
Binary file not shown.
BIN
addons/spectator/data/b_unknown.paa
Normal file
BIN
addons/spectator/data/b_unknown.paa
Normal file
Binary file not shown.
BIN
addons/spectator/data/c_air.paa
Normal file
BIN
addons/spectator/data/c_air.paa
Normal file
Binary file not shown.
BIN
addons/spectator/data/c_car.paa
Normal file
BIN
addons/spectator/data/c_car.paa
Normal file
Binary file not shown.
BIN
addons/spectator/data/c_plane.paa
Normal file
BIN
addons/spectator/data/c_plane.paa
Normal file
Binary file not shown.
BIN
addons/spectator/data/c_ship.paa
Normal file
BIN
addons/spectator/data/c_ship.paa
Normal file
Binary file not shown.
BIN
addons/spectator/data/c_unknown.paa
Normal file
BIN
addons/spectator/data/c_unknown.paa
Normal file
Binary file not shown.
73
addons/spectator/functions/fnc_addLocation.sqf
Normal file
73
addons/spectator/functions/fnc_addLocation.sqf
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, SilentSpike
|
||||
* Add a location that can be seen in spectator view. Local effect.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Position <ARRAY or OBJECT>
|
||||
* 1: Display Name <STRING> (Default: "")
|
||||
* 2: Description <STRING> (Default: "")
|
||||
* 3: Texture <STRING> (Default: "")
|
||||
* 4: Camera Offset Vector <Array> (Default: [0,0,0])
|
||||
*
|
||||
* Notes:
|
||||
* - Position array is of form ATL
|
||||
* - Position objects will remove location upon objNull
|
||||
* - If an empty name is supplied, a descriptive name will be used
|
||||
* - Camera offset is used when teleporting to location, default is treated as random
|
||||
*
|
||||
* Return Value:
|
||||
* Unique ID (used to remove a location) <STRING>
|
||||
*
|
||||
* Example:
|
||||
* [[2000, 3202, 0], "Objective Alpha"] call ace_spectator_fnc_addLocation
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params [
|
||||
["_pos",[],[[],objNull],3],
|
||||
["_name","",[""]],
|
||||
["_description","",[""]],
|
||||
["_texture","",[""]],
|
||||
["_offset",[0,0,0],[[]],3]
|
||||
];
|
||||
|
||||
private _id = "";
|
||||
|
||||
if (_pos isEqualTo []) then {
|
||||
WARNING("Invalid position supplied");
|
||||
} else {
|
||||
// Get a unique ID
|
||||
INC(GVAR(locationCount));
|
||||
_id = [QGVAR(id),GVAR(locationCount)] joinString "";
|
||||
|
||||
// Must have a name to display in the list
|
||||
if (_name == "") then {
|
||||
if (_pos isEqualType objNull) then {
|
||||
_name = [_pos] call EFUNC(common,getName);
|
||||
} else {
|
||||
_name = _pos call BIS_fnc_locationDescription;
|
||||
};
|
||||
};
|
||||
|
||||
// AGL is used for rendering purposes, but it makes sense for public function to take ATL
|
||||
if (_pos isEqualType []) then {
|
||||
_pos = ASLtoAGL ATLtoASL _pos;
|
||||
};
|
||||
|
||||
// When no texture, just use a transparent procedural
|
||||
if (_texture == "") then { _texture = "#(rgb,8,8,3)color(0,0,0,0)"; };
|
||||
|
||||
GVAR(locationsList) pushBack [_id, _name, _description, _texture, _pos, _offset];
|
||||
|
||||
// Update the list if appropriate
|
||||
if !(isNull SPEC_DISPLAY) then {
|
||||
if (GVAR(uiListType) == LIST_LOCATIONS) then {
|
||||
[] call FUNC(ui_updateListLocations);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
_id
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Caches the units information for quick retrevial in spectator interface PFHs
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Unit to have info cached for <OBJECT>
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
*
|
||||
* Example:
|
||||
* [vehicle player] call ace_spectator_fnc_cacheUnitInfo
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_unit"];
|
||||
private ["_color","_icon","_name"];
|
||||
|
||||
// Group info only needs to be cached once (groups can't change)
|
||||
if (isNil { GETVAR((group _unit),GVAR(gColor),nil) }) then {
|
||||
_color = [side group _unit] call BIS_fnc_sideColor;
|
||||
SETVAR((group _unit),GVAR(gColor),_color);
|
||||
};
|
||||
|
||||
// Unit info should be updated each time
|
||||
_icon = getText (configFile >> "CfgVehicles" >> typeOf _unit >> "Icon");
|
||||
_name = [_unit,false] call EFUNC(common,getName);
|
||||
|
||||
// Handle CfgVehicleIcons
|
||||
if (isText (configFile >> "CfgVehicleIcons" >> _icon)) then {
|
||||
_icon = getText (configFile >> "CfgVehicleIcons" >> _icon);
|
||||
};
|
||||
|
||||
SETVAR(_unit,GVAR(uIcon),_icon);
|
||||
SETVAR(_unit,GVAR(uName),_name);
|
143
addons/spectator/functions/fnc_cam.sqf
Normal file
143
addons/spectator/functions/fnc_cam.sqf
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, SilentSpike
|
||||
* Handles camera initialisation and destruction
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Init/Terminate <BOOL>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [true] call ace_spectator_fnc_cam
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_init"];
|
||||
|
||||
// No change
|
||||
if (_init isEqualTo !isNil QGVAR(camera)) exitWith {};
|
||||
|
||||
// Note that init and destroy intentionally happen in reverse order
|
||||
// Init: Vars > Camera > Camera Stuff
|
||||
// Destroy: Camera Stuff > Camera > Vars
|
||||
if (_init) then {
|
||||
// Start tracking camera attributes if not pre-set by public function
|
||||
ISNILS(GVAR(camMode),MODE_FREE);
|
||||
ISNILS(GVAR(camVision),VISION_NORM);
|
||||
ISNILS(GVAR(camTarget),objNull);
|
||||
ISNILS(GVAR(camOnLocation),false);
|
||||
|
||||
// Ticking related
|
||||
GVAR(camDeltaTime) = 0;
|
||||
GVAR(camLastTickTime) = 0;
|
||||
GVAR(camHasTarget) = false;
|
||||
GVAR(camTargetInVehicle) = false;
|
||||
|
||||
// Follow camera related
|
||||
GVAR(camDistance) = 0;
|
||||
GVAR(camDistanceTemp) = 0;
|
||||
GVAR(camYaw) = 0;
|
||||
GVAR(camPitch) = 0;
|
||||
|
||||
// Toggles
|
||||
GVAR(camSlow) = false;
|
||||
GVAR(camLights) = [];
|
||||
GVAR(camLight) = false;
|
||||
|
||||
// Handle pre-set pos and dir (delete GVARs when done)
|
||||
private _pos = if (isNil QGVAR(camPos)) then {eyePos player} else {GVAR(camPos)};
|
||||
private _dir = if (isNil QGVAR(camDir)) then {getDirVisual player} else {GVAR(camDir)};
|
||||
GVAR(camPos) = nil;
|
||||
GVAR(camDir) = nil;
|
||||
|
||||
// Create the camera (CamCurator required for engine driven controls)
|
||||
private _camera = "CamCurator" camCreate _pos;
|
||||
|
||||
if (isNull _camera) exitWith { ERROR("Camera wasn't created successfully"); };
|
||||
|
||||
// Switch to the camera and set its attributes
|
||||
_camera cameraEffect ["internal", "back"];
|
||||
_camera setPosASL _pos;
|
||||
_camera setDir _dir;
|
||||
_camera camCommand "maxPitch 89";
|
||||
_camera camCommand "minPitch -89";
|
||||
_camera camCommand format ["speedDefault %1", SPEED_DEFAULT];
|
||||
_camera camCommand format ["speedMax %1", SPEED_FAST];
|
||||
_camera camCommand "ceilingHeight 5000";
|
||||
cameraEffectEnableHUD true;
|
||||
|
||||
// If camera followed terrain it would be annoying to track units, etc.
|
||||
_camera camCommand "atl off";
|
||||
|
||||
// Camera speed should be consistent irrespective of height (painfully slow otherwise)
|
||||
_camera camCommand "surfaceSpeed off";
|
||||
|
||||
// Store camera
|
||||
GVAR(camera) = _camera;
|
||||
|
||||
// Create dummy target used for follow camera
|
||||
GVAR(camDummy) = "Logic" createVehicleLocal getPosASLVisual GVAR(camTarget);
|
||||
|
||||
// Handle initial camera mode limitation
|
||||
if !(GVAR(camMode) in GVAR(availableModes)) then {
|
||||
GVAR(camMode) = GVAR(availableModes) select 0;
|
||||
};
|
||||
|
||||
// If inital camera mode is not free cam and no focus, find initial focus
|
||||
if (GVAR(camMode) != MODE_FREE && isNull GVAR(camTarget)) then {
|
||||
[true] call FUNC(setFocus);
|
||||
};
|
||||
|
||||
// Set the initial camera mode (could be pre-set or limited)
|
||||
[GVAR(camMode)] call FUNC(cam_setCameraMode);
|
||||
|
||||
// Handle initial vision mode limitation
|
||||
if !(GVAR(camVision) in GVAR(availableVisions)) then {
|
||||
GVAR(camVision) = GVAR(availableVisions) select 0;
|
||||
};
|
||||
|
||||
// Set the initial vision mode (could be pre-set or limited)
|
||||
[GVAR(camVision)] call FUNC(cam_setVisionMode);
|
||||
|
||||
// Start ticking (follow camera requires EachFrame to avoid jitter)
|
||||
GVAR(camTick) = addMissionEventHandler ["EachFrame", {call FUNC(cam_tick)}];
|
||||
} else {
|
||||
// Stop ticking
|
||||
removeMissionEventHandler ["EachFrame", GVAR(camTick)];
|
||||
GVAR(camTick) = nil;
|
||||
|
||||
// Return to player view
|
||||
if !(isNull GVAR(camera)) then {
|
||||
GVAR(camera) cameraEffect ["terminate", "back"];
|
||||
deleteVehicle GVAR(camera);
|
||||
};
|
||||
player switchCamera "internal";
|
||||
|
||||
// Remove camera variable
|
||||
GVAR(camera) = nil;
|
||||
|
||||
// Destroy dummy target
|
||||
deleteVehicle (GVAR(camDummy));
|
||||
GVAR(camDummy) = nil;
|
||||
|
||||
// Stop tracking everything
|
||||
GVAR(camMode) = nil;
|
||||
GVAR(camVision) = nil;
|
||||
GVAR(camTarget) = nil;
|
||||
GVAR(camOnLocation) = nil;
|
||||
GVAR(camDeltaTime) = nil;
|
||||
GVAR(camLastTickTime) = nil;
|
||||
GVAR(camHasTarget) = nil;
|
||||
GVAR(camTargetInVehicle) = nil;
|
||||
GVAR(camDistance) = nil;
|
||||
GVAR(camDistanceTemp) = nil;
|
||||
GVAR(camYaw) = nil;
|
||||
GVAR(camPitch) = nil;
|
||||
GVAR(camSlow) = nil;
|
||||
GVAR(camLights) = nil;
|
||||
GVAR(camLight) = nil;
|
||||
};
|
51
addons/spectator/functions/fnc_cam_prepareTarget.sqf
Normal file
51
addons/spectator/functions/fnc_cam_prepareTarget.sqf
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, SilentSpike
|
||||
* Moves the spectator camera to a position relative to the camera focus.
|
||||
* Used for 3PP camera and teleporting, etc.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: New Target <OBJECT>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [player] call ace_spectator_fnc_cam_prepareTarget
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
private _focus = vehicle (param [0, objNull, [objNull]]);
|
||||
|
||||
if !(isNull _focus) then {
|
||||
// Interpolate zoom
|
||||
private _zoom = [0, GVAR(camDistance)] select (GVAR(camMode) == MODE_FOLLOW);
|
||||
private _zoomTemp = GVAR(camDistanceTemp);
|
||||
|
||||
if (_zoomTemp != _zoom) then {
|
||||
_zoomTemp = [_zoomTemp, _zoom, 10, GVAR(camDeltaTime)] call BIS_fnc_lerp;
|
||||
GVAR(camDistanceTemp) = _zoomTemp;
|
||||
};
|
||||
|
||||
// The distance at which to place camera from the focus pivot
|
||||
private _bbd = [_focus] call BIS_fnc_getObjectBBD;
|
||||
private _distance = (_bbd select 1) + _zoomTemp;
|
||||
|
||||
// The pivot on the target vehicle
|
||||
private _isMan = _focus isKindOf "Man";
|
||||
private _height = if !(_isMan) then { (_bbd select 2) / 3 } else { switch (stance _focus) do { case "STAND": {1.4}; case "CROUCH": {0.8}; default {0.4}; }; };
|
||||
|
||||
private _center = if (_isMan) then { AGLToASL (_focus modelToWorldVisual (_focus selectionPosition "Spine3")) } else { AGLToASL (_focus modelToWorldVisual [0,0,_height]) };
|
||||
|
||||
// Set dummy location and rotation
|
||||
private _dummy = GVAR(camDummy);
|
||||
|
||||
_dummy setPosASL _center;
|
||||
[_dummy, [GVAR(camYaw), GVAR(camPitch), 0]] call BIS_fnc_setObjectRotation;
|
||||
|
||||
// Apply location and rotation to camera
|
||||
GVAR(camera) setPosASL (AGLToASL (_dummy modelToWorldVisual [0, -_distance, 0]));
|
||||
GVAR(camera) setVectorDirAndUp [vectorDirVisual _dummy, vectorUpVisual _dummy];
|
||||
};
|
29
addons/spectator/functions/fnc_cam_resetTarget.sqf
Normal file
29
addons/spectator/functions/fnc_cam_resetTarget.sqf
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, SilentSpike
|
||||
* Removes the current camera interest and detaches dummy target.
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [] call ace_spectator_fnc_cam_resetTarget
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
private _camera = GVAR(camera);
|
||||
private _dummy = GVAR(camDummy);
|
||||
|
||||
if !(isNull _camera || isNull _dummy) then {
|
||||
_camera camPrepareTarget objNull;
|
||||
_camera camCommitPrepared 0;
|
||||
|
||||
detach _dummy;
|
||||
|
||||
GVAR(camHasTarget) = false;
|
||||
};
|
89
addons/spectator/functions/fnc_cam_setCameraMode.sqf
Normal file
89
addons/spectator/functions/fnc_cam_setCameraMode.sqf
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, AACO, SilentSpike
|
||||
* Function used to select the camera mode
|
||||
*
|
||||
* Intended to run even if new mode == old mode, as it handles focus
|
||||
*
|
||||
* Arguments:
|
||||
* 0: New camera mode <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [1] call ace_spectator_fnc_cam_setCameraMode
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_newMode"];
|
||||
|
||||
private _oldMode = GVAR(camMode);
|
||||
private _modes = GVAR(availableModes);
|
||||
private _focus = GVAR(camTarget);
|
||||
|
||||
// If new mode isn't available then keep current (unless current also isn't)
|
||||
if !(_newMode in _modes) then {
|
||||
_newMode = _modes select ((_modes find _oldMode) max 0);
|
||||
};
|
||||
|
||||
// Can't switch camera from free mode when focus is a location
|
||||
if (!(isNull _focus || GVAR(camOnLocation)) || _newMode == MODE_FREE) then {
|
||||
private _camera = GVAR(camera);
|
||||
private _showHUD = [true,true,true,true,true,true,true,true];
|
||||
|
||||
if (_newMode == MODE_FPS) then {
|
||||
_camera cameraEffect ["Terminate", "BACK"];
|
||||
_focus switchCamera "INTERNAL";
|
||||
|
||||
// Reset vision mode
|
||||
[VISION_NORM] call FUNC(cam_setVisionMode);
|
||||
|
||||
[] call FUNC(cam_resetTarget);
|
||||
|
||||
// Disable camera input
|
||||
_camera camCommand "manual off";
|
||||
|
||||
// Hide all unit/group information in first person view
|
||||
_showHUD = [true,false,false,false,false,false,false,true];
|
||||
};
|
||||
|
||||
if (_newMode == MODE_FOLLOW) then {
|
||||
_camera cameraEffect ["Internal", "BACK"];
|
||||
_focus switchCamera "EXTERNAL";
|
||||
|
||||
[] call FUNC(cam_resetTarget);
|
||||
|
||||
// Disable camera input
|
||||
_camera camCommand "manual off";
|
||||
};
|
||||
|
||||
if (_newMode == MODE_FREE) then {
|
||||
_camera cameraEffect ["Internal", "BACK"];
|
||||
player switchCamera "INTERNAL";
|
||||
_camera setDir getDirVisual _camera;
|
||||
|
||||
if (!isNull _focus) then {
|
||||
if (_oldMode == MODE_FPS) then {
|
||||
[_focus] call FUNC(cam_prepareTarget);
|
||||
};
|
||||
[_focus] call FUNC(cam_setTarget);
|
||||
};
|
||||
|
||||
// Enable camera input
|
||||
_camera camCommand "manual on";
|
||||
};
|
||||
|
||||
// Update the HUD
|
||||
cameraEffectEnableHUD true;
|
||||
showHUD _showHUD;
|
||||
GVAR(camMode) = _newMode;
|
||||
|
||||
// Only update display if it exists, this function is independent of it
|
||||
if !(isNull SPEC_DISPLAY) then {
|
||||
[] call FUNC(ui_updateCamButtons);
|
||||
[] call FUNC(ui_updateHelp);
|
||||
};
|
||||
};
|
32
addons/spectator/functions/fnc_cam_setTarget.sqf
Normal file
32
addons/spectator/functions/fnc_cam_setTarget.sqf
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, SilentSpike
|
||||
* Sets the current camera interest using dummy target.
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [player] call ace_spectator_fnc_cam_setTarget
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
#define CAMERA_TARGET_CHANGE_TIME 0.5
|
||||
|
||||
params ["_object"];
|
||||
|
||||
private _camera = GVAR(camera);
|
||||
private _dummy = GVAR(camDummy);
|
||||
private _location = _object worldToModel (_object modelToWorldVisual (_object selectionPosition "Head"));
|
||||
|
||||
if (!isNull _camera && !isNull _dummy) then {
|
||||
_dummy attachTo [vehicle _object, _location];
|
||||
_camera camPrepareTarget _dummy;
|
||||
_camera camCommitPrepared CAMERA_TARGET_CHANGE_TIME;
|
||||
|
||||
GVAR(camhasTarget) = true;
|
||||
};
|
45
addons/spectator/functions/fnc_cam_setVisionMode.sqf
Normal file
45
addons/spectator/functions/fnc_cam_setVisionMode.sqf
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Function used to select the camera vision mode
|
||||
*
|
||||
* Arguments:
|
||||
* 0: New vision mode <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [-1] call ace_spectator_fnc_cam_setVisionMode
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_newVision"];
|
||||
|
||||
private _oldVision = GVAR(camVision);
|
||||
private _visions = GVAR(availableVisions);
|
||||
|
||||
// If new vision isn't available then keep current (unless current also isn't)
|
||||
if !(_newVision in _visions) then {
|
||||
_newVision = _visions select ((_visions find _oldVision) max 0);
|
||||
};
|
||||
|
||||
// Vision mode does not apply to fps view
|
||||
if (GVAR(camMode) != MODE_FPS) then {
|
||||
// 0+ are all thermal vision types
|
||||
if (_newVision < 0) then {
|
||||
false setCamUseTi 0;
|
||||
camUseNVG (_newVision >= VISION_NVG);
|
||||
} else {
|
||||
true setCamUseTi _newVision;
|
||||
};
|
||||
|
||||
// Give user feedback that vision mode changed
|
||||
if (_newVision != _oldVision) then {
|
||||
playSound "RscDisplayCurator_visionMode";
|
||||
|
||||
GVAR(camVision) = _newVision;
|
||||
};
|
||||
};
|
84
addons/spectator/functions/fnc_cam_tick.sqf
Normal file
84
addons/spectator/functions/fnc_cam_tick.sqf
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, AACO, SilentSpike
|
||||
* Function used to perform camera ticks
|
||||
*
|
||||
* Updates camera position in follow mode
|
||||
* Updates camera focus if current focus becomes null (in unit modes)
|
||||
* Updates camera when focus enters/exits a vehicle
|
||||
* Updates camera lights position
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* addMissionEventHandler ["EachFrame", {call ace_spectator_fnc_cam_tick}]
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
BEGIN_COUNTER(camTick);
|
||||
private _cameraMode = GVAR(camMode);
|
||||
private _camTarget = GVAR(camTarget);
|
||||
|
||||
// UI mouse handler makes use of delta time between camera ticks
|
||||
private _currentTime = diag_tickTime;
|
||||
GVAR(camDeltaTime) = _currentTime - GVAR(camLastTickTime);
|
||||
GVAR(camLastTickTime) = _currentTime;
|
||||
|
||||
|
||||
// If no focus in unit camera modes try to find a new one
|
||||
if (_cameraMode != MODE_FREE) then {
|
||||
private _focus = if (isNull _camTarget) then {
|
||||
private _testFocus = ([] call FUNC(getTargetEntities)) select 0;
|
||||
if (isNil "_testFocus") then {
|
||||
objNull
|
||||
} else {
|
||||
_testFocus
|
||||
}
|
||||
} else {
|
||||
_camTarget
|
||||
};
|
||||
|
||||
// If new focus was found then switch to it
|
||||
if (!isNull _focus && {_focus != _camTarget}) then {
|
||||
[_focus] call FUNC(setFocus);
|
||||
};
|
||||
|
||||
// Update the follow camera position
|
||||
if (!isNull _focus && {_cameraMode == MODE_FOLLOW}) then {
|
||||
[_focus] call FUNC(cam_prepareTarget);
|
||||
};
|
||||
};
|
||||
|
||||
// Refresh the local variable
|
||||
_camTarget = GVAR(camTarget);
|
||||
|
||||
// Focus get in / out of vehicle state
|
||||
if !(isNull _camTarget) then {
|
||||
private _targetInVeh = GVAR(camTargetInVehicle);
|
||||
|
||||
if (GVAR(camHasTarget)) then {
|
||||
if (!_targetInVeh && { vehicle _camTarget != _camTarget }) then {
|
||||
[_camTarget] call FUNC(cam_setTarget);
|
||||
GVAR(camTargetInVehicle) = true;
|
||||
};
|
||||
|
||||
if (_targetInVeh && { vehicle _camTarget == _camTarget }) then {
|
||||
[_camTarget] call FUNC(cam_setTarget);
|
||||
GVAR(camTargetInVehicle) = false;
|
||||
};
|
||||
};
|
||||
} else {
|
||||
GVAR(camTargetInVehicle) = false;
|
||||
};
|
||||
|
||||
// Camera lights
|
||||
if (count GVAR(camLights) > 1) then {
|
||||
(GVAR(camLights) select 1) setPosASL (AGLToASL (screenToWorld getMousePosition));
|
||||
};
|
||||
END_COUNTER(camTick);
|
36
addons/spectator/functions/fnc_cam_toggleSlow.sqf
Normal file
36
addons/spectator/functions/fnc_cam_toggleSlow.sqf
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, SilentSpike
|
||||
* Function used to set camera slow speed mode
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Enable slow speed <BOOL>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [true] call ace_spectator_fnc_cam_toggleSlow
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_slowSpeed"];
|
||||
|
||||
if !(GVAR(camSlow) isEqualTo _slowSpeed) then {
|
||||
private _camera = GVAR(camera);
|
||||
|
||||
if (GVAR(camMode) == MODE_FREE) then {
|
||||
GVAR(camSlow) = _slowSpeed;
|
||||
|
||||
if (_slowSpeed) then {
|
||||
_camera camCommand format ["speedDefault %1", SPEED_SLOW];
|
||||
} else {
|
||||
_camera camCommand format ["speedDefault %1", SPEED_DEFAULT];
|
||||
};
|
||||
} else {
|
||||
_camera camCommand format ["speedDefault %1", SPEED_DEFAULT];
|
||||
GVAR(camSlow) = false;
|
||||
};
|
||||
};
|
36
addons/spectator/functions/fnc_compat_counter.sqf
Normal file
36
addons/spectator/functions/fnc_compat_counter.sqf
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Handles integrating the counter respawn template into the spectator UI
|
||||
*
|
||||
* Should be called from both RscRespawnCounter XEH and spectator init to account for arbitrary order
|
||||
*
|
||||
* Arguments:
|
||||
* 0: RscRespawnCounter <DISPLAY>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [GETUVAR(RscRespawnCounter,displayNull)] call ace_spectator_fnc_compat_counter
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
#define IDC_COUNTER_TITLE 1001
|
||||
#define IDC_COUNTER_BACK 1002
|
||||
#define IDC_COUNTER_TEXT 1003
|
||||
|
||||
params ["_display"];
|
||||
|
||||
if (isNull _display) exitWith {};
|
||||
|
||||
{
|
||||
private _ctrl = _display displayCtrl _x;
|
||||
|
||||
(ctrlPosition _ctrl) params ["_xOld","","_w","_h"];
|
||||
|
||||
// Center controls at top middle of screen
|
||||
_ctrl ctrlSetPosition [_xOld, safeZoneY, _w, _h];
|
||||
_ctrl ctrlCommit 0;
|
||||
} forEach [IDC_COUNTER_TITLE, IDC_COUNTER_BACK, IDC_COUNTER_TEXT];
|
53
addons/spectator/functions/fnc_compat_spectatorBI.sqf
Normal file
53
addons/spectator/functions/fnc_compat_spectatorBI.sqf
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Handles "compatibility" (i.e. override) for BI spectator respawn types 1, 4 & 5
|
||||
*
|
||||
* Called from the RscDisplayEGSpectator XEH
|
||||
*
|
||||
* Arguments:
|
||||
* 0: RscDisplayEGSpectator <DISPLAY>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* _this call ace_spectator_fnc_compat_spectatorBI
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
private _respawn = getMissionConfigValue ["respawn",0];
|
||||
if (_respawn isEqualType "") then { _respawn = ["","bird","","","group","side"] find (toLower _respawn); };
|
||||
if !(_respawn in [1,4,5]) exitWith {};
|
||||
|
||||
// Remember to check for side specific templates
|
||||
private _templates = getMissionConfigValue [["respawnTemplates",side group player] joinString "",getMissionConfigValue ["respawnTemplates",[]]];
|
||||
if !(QUOTE(ADDON) in _templates) exitWith {};
|
||||
|
||||
// Kill BI spectator
|
||||
["Terminate"] call BIS_fnc_EGSpectator;
|
||||
|
||||
// Start our spectator
|
||||
[true] call FUNC(setSpectator);
|
||||
|
||||
// Delete the seagull that spawns (not actually the player, a CfgNonAIVehicles object)
|
||||
// Respawn type 1 is handled in the template where seagull is passed as paremeter
|
||||
if (_respawn in [4,5]) then {
|
||||
// This could delete seagulls created by a wildlife module (a necessary evil)
|
||||
// TODO: Try to find seagull position and delete more accurately with reduced radius
|
||||
{ if (_x isKindOf "seagull") then {deleteVehicle _x;}; } forEach (nearestObjects [player, [], 250]);
|
||||
};
|
||||
|
||||
// Switch to a virtual unit so draw3D continues to work
|
||||
private _grp = createGroup [sideLogic, true];
|
||||
private _virtual = _grp createUnit [QGVAR(virtual),[0,0,0],[],0,""];
|
||||
|
||||
// Transfer assigned zeus if applicable
|
||||
private _zeus = getAssignedCuratorLogic player;
|
||||
if !(isNull _zeus) then {
|
||||
[QGVAR(transferZeus), [_virtual,_zeus]] call CBA_fnc_serverEvent;
|
||||
};
|
||||
|
||||
selectPlayer _virtual;
|
34
addons/spectator/functions/fnc_compat_zeus.sqf
Normal file
34
addons/spectator/functions/fnc_compat_zeus.sqf
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Handles compatibility with curator interface (i.e. re-opens spectator if applicable)
|
||||
*
|
||||
* Called from the RscDisplayCurator XEH
|
||||
*
|
||||
* Arguments:
|
||||
* 0: RscDisplayCurator <DISPLAY>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* _this call ace_spectator_fnc_compat_zeus
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_display"];
|
||||
|
||||
_display displayAddEventHandler ["Unload",{
|
||||
// Only re-open if still a spectator (and not remote-controlling)
|
||||
if (GVAR(isSet) && {isNull (GETMVAR(bis_fnc_moduleRemoteControl_unit,objNull))}) then {
|
||||
// Display must be opened next frame to prevent game crash
|
||||
[{
|
||||
// Reset the camera and vision modes
|
||||
[GVAR(camMode)] call FUNC(cam_setCameraMode);
|
||||
[GVAR(camVision)] call FUNC(cam_setVisionMode);
|
||||
[true] call FUNC(ui);
|
||||
}] call CBA_fnc_execNextFrame;
|
||||
};
|
||||
}];
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Cycle through the spectator camera vision/view/units in steps
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Camera mode steps <NUMBER>
|
||||
* 1: Camera unit steps <NUMBER>
|
||||
* 2: Vision mode steps <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
*
|
||||
* Example:
|
||||
* [0, -1] call ace_spectator_fnc_cycleCamera
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params [["_stepMode",0], ["_stepUnit",0], ["_stepVision",0]];
|
||||
private ["_modes","_visions","_iMode","_iVision","_countModes","_countVisions","_newMode","_newVision","_newUnit"];
|
||||
|
||||
_modes = GVAR(availableModes);
|
||||
_units = GVAR(unitList);
|
||||
_visions = GVAR(availableVisions);
|
||||
|
||||
// Get current index
|
||||
_iMode = (_modes find GVAR(camMode)) max 0;
|
||||
_iUnit = (_units find GVAR(camUnit)) max 0;
|
||||
_iVision = (_visions find GVAR(camVision)) max 0;
|
||||
|
||||
_countModes = count _modes;
|
||||
_countUnits = count _units;
|
||||
_countVisions = count _visions;
|
||||
|
||||
// Step index by step number (loop at ends)
|
||||
if (_countModes != 0) then {
|
||||
_iMode = (_iMode + _stepMode) % _countModes;
|
||||
if (_iMode < 0) then { _iMode = _countModes + _iMode; };
|
||||
};
|
||||
|
||||
if (_countUnits != 0) then {
|
||||
_iUnit = (_iUnit + _stepUnit) % _countUnits;
|
||||
if (_iUnit < 0) then { _iUnit = _countUnits + _iUnit; };
|
||||
};
|
||||
|
||||
if (_countVisions != 0) then {
|
||||
_iVision = (_iVision + _stepVision) % _countVisions;
|
||||
if (_iVision < 0) then { _iVision = _countVisions + _iVision; };
|
||||
};
|
||||
|
||||
// Get value at new index
|
||||
_newMode = _modes select _iMode;
|
||||
_newUnit = _units select _iUnit;
|
||||
_newVision = _visions select _iVision;
|
||||
|
||||
[_newMode, _newUnit, _newVision] call FUNC(transitionCamera);
|
30
addons/spectator/functions/fnc_getCameraAttributes.sqf
Normal file
30
addons/spectator/functions/fnc_getCameraAttributes.sqf
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Returns the current spectator camera attributes (see setCameraAttributes for details).
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* [Mode, Focus, Vision, Position, Direction] <ARRAY>
|
||||
*
|
||||
* Example:
|
||||
* [] call ace_spectator_fnc_getCameraAttributes
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
if !(isNil QGVAR(camera)) then {
|
||||
[GVAR(camMode), GVAR(camTarget), GVAR(camVision), getPosATL GVAR(camera), getDirVisual GVAR(camera)]
|
||||
} else {
|
||||
// These values could be pre-set by function
|
||||
[
|
||||
GETMVAR(GVAR(camMode),0),
|
||||
GETMVAR(GVAR(camTarget),objNull),
|
||||
GETMVAR(GVAR(camVision),-2),
|
||||
GETMVAR(GVAR(camPos),[ARR_3(0,0,0)]),
|
||||
GETMVAR(GVAR(camDir),0)
|
||||
]
|
||||
};
|
162
addons/spectator/functions/fnc_getGroupIcon.sqf
Normal file
162
addons/spectator/functions/fnc_getGroupIcon.sqf
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Function used to get an appropriate icon for provided group. Approximate.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Group to get the icon of <GROUP>
|
||||
* 1: Return icons for draw3D use <BOOL> (Default: false)
|
||||
*
|
||||
* Return Value:
|
||||
* Icon of group <STRING>
|
||||
*
|
||||
* Examples:
|
||||
* [group player] call ace_spectator_fnc_getGroupIcon
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
#define ICON_PATH(var1) QUOTE(a3\ui_f\data\Map\Markers\NATO\var1)
|
||||
|
||||
// Military icons
|
||||
#define ICON_UNKNOWN [ICON_PATH(b_unknown.paa), QPATHTOF(data\b_unknown.paa)] select _forDraw
|
||||
#define ICON_UAV [ICON_PATH(b_uav.paa), QPATHTOF(data\b_uav.paa)] select _forDraw
|
||||
#define ICON_SUPPORT [ICON_PATH(b_support.paa), QPATHTOF(data\b_support.paa)] select _forDraw
|
||||
#define ICON_SERVICE [ICON_PATH(b_service.paa), QPATHTOF(data\b_service.paa)] select _forDraw
|
||||
#define ICON_RECON [ICON_PATH(b_recon.paa), QPATHTOF(data\b_recon.paa)] select _forDraw
|
||||
#define ICON_PLANE [ICON_PATH(b_plane.paa), QPATHTOF(data\b_plane.paa)] select _forDraw
|
||||
#define ICON_NAVAL [ICON_PATH(b_naval.paa), QPATHTOF(data\b_naval.paa)] select _forDraw
|
||||
#define ICON_MOTOR_INF [ICON_PATH(b_motor_inf.paa), QPATHTOF(data\b_motor_inf.paa)] select _forDraw
|
||||
#define ICON_MORTAR [ICON_PATH(b_mortar.paa), QPATHTOF(data\b_mortar.paa)] select _forDraw
|
||||
#define ICON_MED [ICON_PATH(b_med.paa), QPATHTOF(data\b_med.paa)] select _forDraw
|
||||
#define ICON_MECH_INF [ICON_PATH(b_mech_inf.paa), QPATHTOF(data\b_mech_inf.paa)] select _forDraw
|
||||
#define ICON_MAINT [ICON_PATH(b_maint.paa), QPATHTOF(data\b_maint.paa)] select _forDraw
|
||||
#define ICON_INSTALLATION [ICON_PATH(b_installation.paa), QPATHTOF(data\b_installation.paa)] select _forDraw
|
||||
#define ICON_INF [ICON_PATH(b_inf.paa), QPATHTOF(data\b_inf.paa)] select _forDraw
|
||||
#define ICON_ART [ICON_PATH(b_art.paa), QPATHTOF(data\b_art.paa)] select _forDraw
|
||||
#define ICON_ARMOR [ICON_PATH(b_armor.paa), QPATHTOF(data\b_armor.paa)] select _forDraw
|
||||
#define ICON_AIR [ICON_PATH(b_air.paa), QPATHTOF(data\b_air.paa)] select _forDraw
|
||||
|
||||
// Civilian icons
|
||||
#define CIV_ICON_UNKNOWN [ICON_PATH(c_unknown.paa), QPATHTOF(data\c_unknown.paa)] select _forDraw
|
||||
#define CIV_ICON_AIR [ICON_PATH(c_air.paa), QPATHTOF(data\c_air.paa)] select _forDraw
|
||||
#define CIV_ICON_CAR [ICON_PATH(c_car.paa), QPATHTOF(data\c_car.paa)] select _forDraw
|
||||
#define CIV_ICON_PLANE [ICON_PATH(c_plane.paa), QPATHTOF(data\c_plane.paa)] select _forDraw
|
||||
#define CIV_ICON_SHIP [ICON_PATH(c_ship.paa), QPATHTOF(data\c_ship.paa)] select _forDraw
|
||||
|
||||
params [["_group", grpNull, [grpNull]], ["_forDraw", false, [true]]];
|
||||
|
||||
// Handle empty or null group
|
||||
private _leader = leader _group;
|
||||
if (isNull _leader) exitWith { [ICON_UNKNOWN, CIV_ICON_UNKNOWN] select (side _group == civilian) };
|
||||
|
||||
// Civilians are easy, just check leader's vehicle (unlikely group is large)
|
||||
if (side _group == civilian) exitWith {
|
||||
if (_leader != vehicle _leader) then {
|
||||
// More common cases should be checked first
|
||||
(vehicle _leader) call {
|
||||
if (_this isKindOf "Car") exitWith {
|
||||
CIV_ICON_CAR
|
||||
};
|
||||
|
||||
// Plane inherits Air, check first
|
||||
if (_this isKindOf "Plane") exitWith {
|
||||
CIV_ICON_PLANE
|
||||
};
|
||||
|
||||
if (_this isKindOf "Air") exitWith {
|
||||
CIV_ICON_AIR
|
||||
};
|
||||
|
||||
if (_this isKindOf "Ship") exitWith {
|
||||
CIV_ICON_SHIP
|
||||
};
|
||||
|
||||
CIV_ICON_UNKNOWN
|
||||
};
|
||||
} else {
|
||||
CIV_ICON_UNKNOWN
|
||||
};
|
||||
};
|
||||
|
||||
// Handle military groups
|
||||
private _units = units _group;
|
||||
private _vehicles = (_units apply { vehicle _x }) - _units;
|
||||
|
||||
// If more than 33% of the group is mounted, use most common vehicle
|
||||
if (count _vehicles >= 0.33 * count _units) exitWith {
|
||||
// Check the most likely cases first
|
||||
_vehicles call {
|
||||
private _threshold = 0.5 * count _this;
|
||||
|
||||
if ("Car" countType _this >= _threshold) exitWith {
|
||||
ICON_MOTOR_INF
|
||||
};
|
||||
|
||||
// APC inherits Tank, check first
|
||||
if ("APC" countType _this >= _threshold) exitWith {
|
||||
ICON_MECH_INF
|
||||
};
|
||||
|
||||
// MBT_01_arty_base_F inherits Tank, check first
|
||||
// Unfortunately no common arty class to check
|
||||
if ("MBT_01_arty_base_F" countType _this >= _threshold) exitWith {
|
||||
ICON_ART
|
||||
};
|
||||
if ("MBT_02_arty_base_F" countType _this >= _threshold) exitWith {
|
||||
ICON_ART
|
||||
};
|
||||
|
||||
if ("Tank" countType _this >= _threshold) exitWith {
|
||||
ICON_ARMOR
|
||||
};
|
||||
|
||||
// UAV inherits Plane, check first
|
||||
if ("UAV" countType _this >= _threshold) exitWith {
|
||||
ICON_UAV
|
||||
};
|
||||
|
||||
// Plane inherits Air, check first
|
||||
if ("Plane" countType _this >= _threshold) exitWith {
|
||||
ICON_PLANE
|
||||
};
|
||||
|
||||
if ("Air" countType _this >= _threshold) exitWith {
|
||||
ICON_AIR
|
||||
};
|
||||
|
||||
if ("Ship" countType _this >= _threshold) exitWith {
|
||||
ICON_NAVAL
|
||||
};
|
||||
|
||||
// StaticMortar inherits StaticWeapon, check first
|
||||
if ("StaticMortar" countType _this >= _threshold) exitWith {
|
||||
ICON_MORTAR
|
||||
};
|
||||
|
||||
if ("StaticWeapon" countType _this >= _threshold) exitWith {
|
||||
ICON_INSTALLATION
|
||||
};
|
||||
|
||||
// If it reaches here then it's a mixed group of vehicles
|
||||
ICON_UNKNOWN
|
||||
};
|
||||
};
|
||||
|
||||
// Check leader for medic/engineer/etc, otherwise just default to infantry
|
||||
private _medic = [_leader] call EFUNC(common,isMedic);
|
||||
private _engineer = [_leader] call EFUNC(common,isEngineer);
|
||||
|
||||
if (_medic && _engineer) exitWith {
|
||||
ICON_SUPPORT
|
||||
};
|
||||
|
||||
if (_medic) exitWith {
|
||||
ICON_MED
|
||||
};
|
||||
|
||||
if (_engineer) exitWith {
|
||||
ICON_MAINT
|
||||
};
|
||||
|
||||
ICON_INF
|
45
addons/spectator/functions/fnc_getTargetEntities.sqf
Normal file
45
addons/spectator/functions/fnc_getTargetEntities.sqf
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Gets the possible entities to spectate based on settings.
|
||||
* Optionally includes dead units for the list and switching.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Include dead <BOOL>
|
||||
*
|
||||
* Return Value:
|
||||
* Valid entities <ARRAY>
|
||||
*
|
||||
* Example:
|
||||
* [true] call ace_spectator_fnc_getTargetEntities
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
// Include dead units if specified (used by entity list)
|
||||
private _entities = allUnits;
|
||||
if (param [0,false]) then { _entities append allDeadMen; };
|
||||
|
||||
// Quicker to use local vars that are accessed often in iteration
|
||||
private _sides = GVAR(availableSides);
|
||||
|
||||
// Apply entity filtering
|
||||
_entities = _entities select {
|
||||
(GVAR(enableAI) || {isPlayer _x}) && // AI setting
|
||||
{(side group _x) in _sides} && // Available sides
|
||||
{simulationEnabled _x && {simulationEnabled vehicle _x}} && // Hide disabled things
|
||||
{ !isObjectHidden _x && {!isObjectHidden vehicle _x} } // Hide hidden things
|
||||
};
|
||||
|
||||
// Respect the blacklist
|
||||
_entities = _entities - GVAR(unitBlacklist);
|
||||
|
||||
// Whitelist overrides filtering
|
||||
_entities append GVAR(unitWhitelist);
|
||||
|
||||
// Never include the local player
|
||||
_entities deleteAt (_entities find player);
|
||||
|
||||
// Return no duplicates
|
||||
_entities arrayIntersect _entities
|
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Author: F3 Project, Head, SilentSpike
|
||||
* Handles free camera manipulation according to input
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Parameters <ANY>
|
||||
* 1: PFH handle <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
*
|
||||
* Example:
|
||||
* [ace_spectator_fnc_handleCamera, 0] call CBA_fnc_addPerFrameHandler;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
// Kill PFH when not in free cam (or display is closed)
|
||||
if (isNil QGVAR(camHandler)) exitWith { [_this select 1] call CBA_fnc_removePerFrameHandler; };
|
||||
|
||||
private ["_camera","_pan","_tilt"];
|
||||
|
||||
_pan = (GVAR(camPan) + 360) % 360;
|
||||
_tilt = GVAR(camTilt);
|
||||
|
||||
if (GVAR(camMode) == 0) then {
|
||||
private ["_oldPos","_altMod","_zoomMod","_mX","_mY","_mZ","_x","_y","_z"];
|
||||
_camera = GVAR(freeCamera);
|
||||
_oldPos = GVAR(camPos);
|
||||
|
||||
// Dolly/Boom amount should be influnced by zoom level (it should really be exponential)
|
||||
// Dollying should also slow as the camera gets close to the ground
|
||||
_zoomMod = (GVAR(camZoom) * 0.8) max 1;
|
||||
_altMod = ((((getPos _camera) select 2) * 0.05) max 0.1) min 1;
|
||||
|
||||
_mX = (GVAR(camDolly) select 0) * _altMod / _zoomMod;
|
||||
_mY = (GVAR(camDolly) select 1) * _altMod / _zoomMod;
|
||||
_mZ = GVAR(camBoom) / _zoomMod;
|
||||
|
||||
_x = (_oldPos select 0) + (_mX * cos(_pan)) + (_mY * sin(_pan));
|
||||
_y = (_oldPos select 1) - (_mX * sin(_pan)) + (_mY * cos(_pan));
|
||||
_z = (_oldPos select 2) + _mZ;
|
||||
|
||||
// Prevent camera going under terrain
|
||||
GVAR(camPos) = [_x,_y,_z max (getTerrainHeightASL [_x,_y])];
|
||||
|
||||
// Update camera position and rotation
|
||||
_camera setPosASL GVAR(camPos);
|
||||
_camera setDir _pan;
|
||||
[_camera, _tilt, 0] call BIS_fnc_setPitchBank;
|
||||
} else {
|
||||
private ["_unit","_target","_distance","_vector"];
|
||||
_camera = GVAR(unitCamera);
|
||||
|
||||
_unit = GVAR(camUnit);
|
||||
_target = GVAR(targetCamera);
|
||||
_distance = GVAR(camDistance);
|
||||
|
||||
// Generate a position vector relative to the unit
|
||||
_vector = [0,-_distance*cos(_tilt),0];
|
||||
_vector = [_vector,[-_pan] call CBA_fnc_simplifyAngle180] call BIS_fnc_rotateVector2D;
|
||||
_vector = _vector vectorAdd [0,0,_distance*sin(-_tilt)];
|
||||
|
||||
// Update the position of the target camera (used for smooth unit tracking)
|
||||
_target camSetPos ((ASLToAGL getPosASLVisual _unit) vectorAdd [0,0,1.5]);
|
||||
_target camCommit 0;
|
||||
|
||||
// Update the relative position of the unit camera
|
||||
_camera camSetRelPos _vector;
|
||||
_camera camCommit 0;
|
||||
|
||||
GVAR(camPos) = getPosASL _camera;
|
||||
};
|
@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Author: SilentSpike, voiper
|
||||
* Handles the spectator UI compass
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Parameters <ANY>
|
||||
* 1: PFH handle <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
*
|
||||
* Example:
|
||||
* [ace_spectator_fnc_handleCompass, 0, _display] call CBA_fnc_addPerFrameHandler;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_display"];
|
||||
|
||||
// Kill PFH when compass hidden (or display is closed)
|
||||
if (isNil QGVAR(compHandler)) exitWith { [_this select 1] call CBA_fnc_removePerFrameHandler; };
|
||||
|
||||
private ["_compass","_NE","_ES","_SW","_WN","_compassW","_degree","_heading","_offset","_positions","_sequence"];
|
||||
|
||||
_compass = _display displayCtrl IDC_COMP;
|
||||
|
||||
_NE = _compass controlsGroupCtrl IDC_COMP_0;
|
||||
_ES = _compass controlsGroupCtrl IDC_COMP_90;
|
||||
_SW = _compass controlsGroupCtrl IDC_COMP_180;
|
||||
_WN = _compass controlsGroupCtrl IDC_COMP_270;
|
||||
|
||||
_compassW = (ctrlPosition _compass) select 2;
|
||||
_degree = _compassW / 180;
|
||||
|
||||
// Get direction of screen rather than object (accounts for unit freelook)
|
||||
_heading = (positionCameraToWorld [0,0,1]) vectorDiff (positionCameraToWorld [0,0,0]);
|
||||
_heading = (((_heading select 0) atan2 (_heading select 1)) + 360) % 360;
|
||||
_offset = -(_heading % 90) * _degree;
|
||||
|
||||
_positions = [
|
||||
[_compassW * -0.5 + _offset, 0],
|
||||
[_offset, 0],
|
||||
[_compassW * 0.5 + _offset, 0],
|
||||
[_compassW + _offset, 0]
|
||||
];
|
||||
|
||||
_sequence = [
|
||||
[_SW, _WN, _NE, _ES],
|
||||
[_WN, _NE, _ES, _SW],
|
||||
[_NE, _ES, _SW, _WN],
|
||||
[_ES, _SW, _WN, _NE]
|
||||
] select floor(_heading/90);
|
||||
|
||||
|
||||
{
|
||||
_x ctrlSetPosition (_positions select _forEachIndex);
|
||||
_x ctrlCommit 0;
|
||||
} forEach _sequence;
|
48
addons/spectator/functions/fnc_handleFired.sqf
Normal file
48
addons/spectator/functions/fnc_handleFired.sqf
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, AACO, SilentSpike
|
||||
* Function used to add projectiles to be drawn when a unit fires
|
||||
*
|
||||
* Arguments:
|
||||
* Fired EH arguments
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* _unit addEventHandler ["Fired",{_this call ace_spectator_fnc_handleFired}]
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params [
|
||||
"_unit",
|
||||
["_weapon", "", [""]],
|
||||
"", // Muzzle
|
||||
"", // Mode
|
||||
"", // Ammo
|
||||
"", // Magazine
|
||||
["_projectile", objNull, [objNull]]
|
||||
];
|
||||
|
||||
// Remove the EH when spectator is no longer active or unit is removed
|
||||
if (isNil QGVAR(entitiesToDraw) || {!(_unit in GVAR(entitiesToDraw))}) exitWith {
|
||||
//USES_VARIABLES ["_thisEventHandler"]
|
||||
_unit removeEventHandler ["Fired", _thisEventHandler];
|
||||
SETVAR(_unit,GVAR(firedEH),nil);
|
||||
};
|
||||
|
||||
// Fire time used for unit icon highlighting
|
||||
_unit setVariable [QGVAR(highlightTime), time + FIRE_HIGHLIGHT_TIME];
|
||||
|
||||
// Store projectiles / grenades for drawing
|
||||
if (GVAR(drawProjectiles) && {!isNull _projectile}) then {
|
||||
if (_weapon == "Throw") then {
|
||||
if (count GVAR(grenadesToDraw) > MAX_GRENADES) then { GVAR(grenadesToDraw) deleteAt 0; };
|
||||
GVAR(grenadesToDraw) pushBack _projectile;
|
||||
} else {
|
||||
if (count GVAR(projectilesToDraw) > MAX_PROJECTILES) then { GVAR(projectilesToDraw) deleteAt 0; };
|
||||
GVAR(projectilesToDraw) pushBack [_projectile, [[getPosVisual _projectile, [1,0,0,0]]]];
|
||||
};
|
||||
};
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Author: Head, SilentSpike
|
||||
* Handles rendering the spectator 3D unit icons
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Parameters <ANY>
|
||||
* 1: PFH handle <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
*
|
||||
* Example:
|
||||
* [ace_spectator_fnc_handleIcons, 0] call CBA_fnc_addPerFrameHandler;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
if !(GVAR(showIcons)) exitWith {};
|
||||
private ["_refPoint","_drawVehicles","_leader","_color","_txt","_unit"];
|
||||
|
||||
// Draw groups unless leader is within distance
|
||||
_refPoint = [GVAR(freeCamera),GVAR(camUnit)] select (GVAR(camMode) > 0);
|
||||
_drawVehicles = [];
|
||||
{
|
||||
_leader = leader _x;
|
||||
if ((_leader distanceSqr _refPoint) > 40000) then {
|
||||
_color = GETVAR(_x,GVAR(gColor),[ARR_4(0,0,0,0)]);
|
||||
_txt = groupID _x;
|
||||
|
||||
drawIcon3D ["\A3\ui_f\data\map\markers\nato\b_inf.paa", _color, (_leader modelToWorldVisual (_leader selectionPosition "Head")) vectorAdd [0,0,28.5], 1, 1, 0, _txt, 2, 0.02];
|
||||
} else {
|
||||
_drawVehicles append (units _x);
|
||||
};
|
||||
false
|
||||
} count GVAR(groupList);
|
||||
|
||||
// Draw units for groups within distance
|
||||
{
|
||||
_color = GETVAR((group _x),GVAR(gColor),[ARR_4(0,0,0,0)]);
|
||||
_txt = ["", GETVAR(_x,GVAR(uName),"")] select (isPlayer _x);
|
||||
|
||||
drawIcon3D ["a3\Ui_f\data\GUI\Rsc\RscDisplayEGSpectator\UnitIcon_ca.paa", _color, (_x modelToWorldVisual (_x selectionPosition "Head")) vectorAdd [0,0,1.5], 0.7, 0.7, 0, _txt, 1, 0.02];
|
||||
false
|
||||
} count (_drawVehicles arrayIntersect GVAR(unitList));
|
@ -1,494 +0,0 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Handles spectator interface events
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Event name <STRING>
|
||||
* 1: Event arguments <ANY>
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
*
|
||||
* Example:
|
||||
* ["onLoad",_this] call ace_spectator_fnc_handleInterface
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_mode",["_args",[]]];
|
||||
|
||||
switch (toLower _mode) do {
|
||||
case "onload": {
|
||||
_args params ["_display"];
|
||||
SETUVAR(GVAR(interface),_display);
|
||||
|
||||
// Always show interface and hide map upon opening
|
||||
[_display,nil,nil,!GVAR(showInterface),GVAR(showMap)] call FUNC(toggleInterface);
|
||||
|
||||
// Initalize the unit tree
|
||||
["onUnitsUpdate",[(_display displayCtrl IDC_UNIT) controlsGroupCtrl IDC_UNIT_TREE]] call FUNC(handleInterface);
|
||||
|
||||
// Keep unit list and tree up to date
|
||||
[FUNC(handleUnits), 9, _display] call CBA_fnc_addPerFrameHandler;
|
||||
|
||||
// Handle 3D unit icons
|
||||
GVAR(iconHandler) = addMissionEventHandler ["Draw3D", {call FUNC(handleIcons)}];
|
||||
|
||||
// Populate the help window
|
||||
private _help = (_display displayCtrl IDC_HELP) controlsGroupCtrl IDC_HELP_LIST;
|
||||
{
|
||||
_i = _help lbAdd (_x select 0);
|
||||
if ((_x select 1) == "") then {
|
||||
_help lbSetPicture [_i,"\A3\ui_f\data\map\markers\military\dot_CA.paa"];
|
||||
_help lbSetPictureColor [_i,[COL_FORE]];
|
||||
} else {
|
||||
_help lbSetTooltip [_i,_x select 1];
|
||||
};
|
||||
} forEach [
|
||||
[localize LSTRING(uiControls),""],
|
||||
[localize LSTRING(uiToggleUnits),keyName 2],
|
||||
[localize LSTRING(uiToggleHelp),keyName 3],
|
||||
[localize LSTRING(uiToggleTools),keyName 4],
|
||||
[localize LSTRING(uiToggleCompass),keyName 5],
|
||||
[localize LSTRING(uiToggleIcons),keyName 6],
|
||||
[localize LSTRING(uiToggleMap),keyName 50],
|
||||
[localize LSTRING(uiToggleInterface),keyName 14],
|
||||
[localize LSTRING(freeCamControls),""],
|
||||
[localize LSTRING(freeCamForward),keyName 17],
|
||||
[localize LSTRING(freeCamBackward),keyName 31],
|
||||
[localize LSTRING(freeCamLeft),keyName 30],
|
||||
[localize LSTRING(freeCamRight),keyName 32],
|
||||
[localize LSTRING(freeCamUp),keyName 16],
|
||||
[localize LSTRING(freeCamDown),keyName 44],
|
||||
[localize LSTRING(freeCamPan),"RMB (Hold)"],
|
||||
[localize LSTRING(freeCamDolly),"LMB (Hold)"],
|
||||
[localize LSTRING(freeCamBoost),"Shift (Hold)"],
|
||||
[localize LSTRING(attributeControls),""],
|
||||
[localize LSTRING(nextCam),keyName 200],
|
||||
[localize LSTRING(prevCam),keyName 208],
|
||||
[localize LSTRING(nextUnit),keyName 205],
|
||||
[localize LSTRING(prevUnit),keyName 203],
|
||||
[localize LSTRING(nextVis),keyName 49],
|
||||
[localize LSTRING(prevVis),format["%1 + %2",keyName 29,keyname 49]],
|
||||
[localize LSTRING(adjZoom),"Scrollwheel"],
|
||||
[localize LSTRING(adjSpeed),format["%1 + Scrollwheel",keyName 29]],
|
||||
[localize LSTRING(incZoom),format["%1/%2",keyName 74,keyName 78]],
|
||||
[localize LSTRING(incSpeed),format["%1 + %2/%3",keyName 29,keyName 74,keyName 78]],
|
||||
[localize LSTRING(reZoom),format["%1 + %2",keyName 56,keyName 74]],
|
||||
[localize LSTRING(reSpeed),format["%1 + %2",keyName 56,keyName 78]]
|
||||
];
|
||||
|
||||
// Handle support for BI's respawn counter
|
||||
[{
|
||||
if !(isNull (GETUVAR(RscRespawnCounter,displayNull))) then {
|
||||
disableSerialization;
|
||||
private ["_counter","_title","_back","_timer","_frame","_x","_y"];
|
||||
_counter = GETUVAR(RscRespawnCounter,displayNull);
|
||||
_title = _counter displayCtrl 1001;
|
||||
_back = _counter displayCtrl 1002;
|
||||
_timer = _counter displayCtrl 1003;
|
||||
_frame = _counter ctrlCreate ["RscFrame",1008];
|
||||
|
||||
_x = safeZoneX + safeZoneW - TOOL_W * 4 - MARGIN * 3;
|
||||
_y = safeZoneY + safeZoneH - TOOL_H;
|
||||
|
||||
// Timer
|
||||
_title ctrlSetPosition [_x,_y,TOOL_W,TOOL_H];
|
||||
_back ctrlSetPosition [_x,_y,TOOL_W,TOOL_H];
|
||||
_timer ctrlSetPosition [_x,_y,TOOL_W,TOOL_H];
|
||||
_frame ctrlSetPosition [_x,_y,TOOL_W,TOOL_H];
|
||||
|
||||
_title ctrlSetBackgroundColor [0,0,0,0];
|
||||
_back ctrlSetBackgroundColor [COL_BACK];
|
||||
_timer ctrlSetFontHeight TOOL_H;
|
||||
_frame ctrlSetTextColor [COL_FORE];
|
||||
|
||||
_title ctrlCommit 0;
|
||||
_back ctrlCommit 0;
|
||||
_timer ctrlCommit 0;
|
||||
_frame ctrlCommit 0;
|
||||
};
|
||||
},[],0.5] call CBA_fnc_waitAndExecute;
|
||||
};
|
||||
case "onunload": {
|
||||
// Kill GUI PFHs
|
||||
removeMissionEventHandler ["Draw3D",GVAR(iconHandler)];
|
||||
GVAR(camHandler) = nil;
|
||||
GVAR(compHandler) = nil;
|
||||
GVAR(iconHandler) = nil;
|
||||
GVAR(toolHandler) = nil;
|
||||
|
||||
// Reset variables
|
||||
GVAR(camBoom) = 0;
|
||||
GVAR(camDolly) = [0,0];
|
||||
GVAR(ctrlKey) = false;
|
||||
GVAR(heldKeys) = [];
|
||||
GVAR(heldKeys) resize 255;
|
||||
GVAR(mouse) = [false,false];
|
||||
GVAR(mousePos) = [0.5,0.5];
|
||||
};
|
||||
// Mouse events
|
||||
case "onmousebuttondown": {
|
||||
_args params ["_ctrl","_button"];
|
||||
GVAR(mouse) set [_button,true];
|
||||
|
||||
// Detect right click
|
||||
if ((_button == 1) && (GVAR(camMode) == 1)) then {
|
||||
// In first person toggle sights mode
|
||||
GVAR(camGun) = !GVAR(camGun);
|
||||
[] call FUNC(transitionCamera);
|
||||
};
|
||||
};
|
||||
case "onmousebuttonup": {
|
||||
_args params ["_ctrl","_button"];
|
||||
|
||||
GVAR(mouse) set [_button,false];
|
||||
if (_button == 0) then { GVAR(camDolly) = [0,0]; };
|
||||
};
|
||||
case "onmousezchanged": {
|
||||
_args params ["_ctrl","_zChange"];
|
||||
|
||||
// Scroll to modify distance value in third person
|
||||
if (GVAR(camMode) == 0) then {
|
||||
// Scroll to change speed, modifier for zoom
|
||||
if (GVAR(ctrlKey)) then {
|
||||
[nil,nil,nil,nil,nil,nil,nil, GVAR(camSpeed) + _zChange * 0.2] call FUNC(setCameraAttributes);
|
||||
} else {
|
||||
[nil,nil,nil,nil,nil,nil, GVAR(camZoom) + _zChange * 0.1] call FUNC(setCameraAttributes);
|
||||
};
|
||||
} else {
|
||||
GVAR(camDistance) = ((GVAR(camDistance) - _zChange * 2) max 5) min 50;
|
||||
};
|
||||
};
|
||||
case "onmousemoving": {
|
||||
_args params ["_ctrl","_x","_y"];
|
||||
|
||||
[_x,_y] call FUNC(handleMouse);
|
||||
};
|
||||
// Keyboard events
|
||||
case "onkeydown": {
|
||||
_args params ["_display","_dik","_shift","_ctrl","_alt"];
|
||||
|
||||
if ((alive player) && {_dik in (actionKeys "curatorInterface")} && {!isNull (getAssignedCuratorLogic player)}) exitWith {
|
||||
[QGVAR(zeus)] call FUNC(interrupt);
|
||||
["zeus"] call FUNC(handleInterface);
|
||||
};
|
||||
if (_dik in (actionKeys "Chat")) exitWith {
|
||||
false
|
||||
};
|
||||
if (_dik in (actionKeys "PrevChannel" + actionKeys "NextChannel")) exitWith {
|
||||
!(isServer || serverCommandAvailable "#kick")
|
||||
};
|
||||
|
||||
// Handle held keys (prevent repeat calling)
|
||||
if (GVAR(heldKeys) param [_dik,false]) exitWith {};
|
||||
// Exclude movement/adjustment keys so that speed can be adjusted on fly
|
||||
if !(_dik in [16,17,30,31,32,44,74,78]) then {
|
||||
GVAR(heldKeys) set [_dik,true];
|
||||
};
|
||||
|
||||
switch (_dik) do {
|
||||
case 1: { // Esc
|
||||
[QGVAR(escape)] call FUNC(interrupt);
|
||||
["escape"] call FUNC(handleInterface);
|
||||
};
|
||||
case 2: { // 1
|
||||
[_display,nil,nil,nil,nil,nil,true] call FUNC(toggleInterface);
|
||||
};
|
||||
case 3: { // 2
|
||||
[_display,nil,true] call FUNC(toggleInterface);
|
||||
};
|
||||
case 4: { // 3
|
||||
[_display,nil,nil,nil,nil,true] call FUNC(toggleInterface);
|
||||
};
|
||||
case 5: { // 4
|
||||
[_display,true] call FUNC(toggleInterface);
|
||||
};
|
||||
case 6: { // 5
|
||||
GVAR(showIcons) = !GVAR(showIcons);
|
||||
};
|
||||
case 14: { // Backspace
|
||||
[_display,nil,nil,true] call FUNC(toggleInterface);
|
||||
};
|
||||
case 16: { // Q
|
||||
GVAR(camBoom) = 0.5 * GVAR(camSpeed) * ([1, 2] select _shift);
|
||||
};
|
||||
case 17: { // W
|
||||
GVAR(camDolly) set [1, GVAR(camSpeed) * ([1, 2] select _shift)];
|
||||
};
|
||||
case 29: { // Ctrl
|
||||
GVAR(ctrlKey) = true;
|
||||
};
|
||||
case 30: { // A
|
||||
GVAR(camDolly) set [0, -GVAR(camSpeed) * ([1, 2] select _shift)];
|
||||
};
|
||||
case 31: { // S
|
||||
GVAR(camDolly) set [1, -GVAR(camSpeed) * ([1, 2] select _shift)];
|
||||
};
|
||||
case 32: { // D
|
||||
GVAR(camDolly) set [0, GVAR(camSpeed) * ([1, 2] select _shift)];
|
||||
};
|
||||
case 44: { // Z
|
||||
GVAR(camBoom) = -0.5 * GVAR(camSpeed) * ([1, 2] select _shift);
|
||||
};
|
||||
case 49: { // N
|
||||
if (GVAR(camMode) != 1) then {
|
||||
if (_ctrl) then {
|
||||
[nil,nil,-1] call FUNC(cycleCamera);
|
||||
} else {
|
||||
[nil,nil,1] call FUNC(cycleCamera);
|
||||
};
|
||||
};
|
||||
};
|
||||
case 50: { // M
|
||||
[_display,nil,nil,nil,true] call FUNC(toggleInterface);
|
||||
};
|
||||
case 57: { // Spacebar
|
||||
// Switch between unit and freecam here
|
||||
};
|
||||
case 74: { // Num -
|
||||
if (_alt) exitWith { [nil,nil,nil,nil,nil,nil, 1.25] call FUNC(setCameraAttributes); };
|
||||
if (_ctrl) then {
|
||||
[nil,nil,nil,nil,nil,nil,nil, GVAR(camSpeed) - 0.05] call FUNC(setCameraAttributes);
|
||||
} else {
|
||||
[nil,nil,nil,nil,nil,nil, GVAR(camZoom) - 0.01] call FUNC(setCameraAttributes);
|
||||
};
|
||||
};
|
||||
case 78: { // Num +
|
||||
if (_alt) exitWith { [nil,nil,nil,nil,nil,nil,nil, 1.5] call FUNC(setCameraAttributes); };
|
||||
if (_ctrl) then {
|
||||
[nil,nil,nil,nil,nil,nil,nil, GVAR(camSpeed) + 0.05] call FUNC(setCameraAttributes);
|
||||
} else {
|
||||
[nil,nil,nil,nil,nil,nil, GVAR(camZoom) + 0.01] call FUNC(setCameraAttributes);
|
||||
};
|
||||
};
|
||||
case 200: { // Up arrow
|
||||
[-1] call FUNC(cycleCamera);
|
||||
};
|
||||
case 203: { // Left arrow
|
||||
[nil,1] call FUNC(cycleCamera);
|
||||
};
|
||||
case 205: { // Right arrow
|
||||
[nil,-1] call FUNC(cycleCamera);
|
||||
};
|
||||
case 208: { // Down arrow
|
||||
[1] call FUNC(cycleCamera);
|
||||
};
|
||||
};
|
||||
|
||||
true
|
||||
};
|
||||
case "onkeyup": {
|
||||
_args params ["_display","_dik","_shift","_ctrl","_alt"];
|
||||
|
||||
// No longer being held
|
||||
GVAR(heldKeys) set [_dik,nil];
|
||||
|
||||
switch (_dik) do {
|
||||
case 16: { // Q
|
||||
GVAR(camBoom) = 0;
|
||||
};
|
||||
case 17: { // W
|
||||
GVAR(camDolly) set [1, 0];
|
||||
};
|
||||
case 29: { // Ctrl
|
||||
GVAR(ctrlKey) = false;
|
||||
};
|
||||
case 30: { // A
|
||||
GVAR(camDolly) set [0, 0];
|
||||
};
|
||||
case 31: { // S
|
||||
GVAR(camDolly) set [1, 0];
|
||||
};
|
||||
case 32: { // D
|
||||
GVAR(camDolly) set [0, 0];
|
||||
};
|
||||
case 44: { // Z
|
||||
GVAR(camBoom) = 0;
|
||||
};
|
||||
};
|
||||
|
||||
true
|
||||
};
|
||||
// Tree events
|
||||
case "ontreedblclick": {
|
||||
// Update camera view when listbox unit is double clicked on
|
||||
_args params ["_tree","_sel"];
|
||||
|
||||
// Ensure a unit was selected
|
||||
if (count _sel == 3) then {
|
||||
private ["_netID","_newUnit","_newMode"];
|
||||
_netID = (_args select 0) tvData _sel;
|
||||
_newUnit = objectFromNetId _netID;
|
||||
|
||||
// When unit is reselected, toggle camera mode
|
||||
if (_newUnit == GVAR(camUnit) || GVAR(camMode) == 0) then {
|
||||
_newMode = [2,2,1] select GVAR(camMode);
|
||||
};
|
||||
|
||||
[_newMode,_newUnit] call FUNC(transitionCamera);
|
||||
};
|
||||
};
|
||||
case "onunitsupdate": {
|
||||
_args params ["_tree"];
|
||||
private ["_cachedUnits","_cachedGrps","_cachedSides","_sT","_gT","_uT","_s","_g","_u","_grp","_unit","_side"];
|
||||
|
||||
// Cache existing group and side nodes and cull removed data
|
||||
_cachedUnits = [];
|
||||
_cachedGrps = [];
|
||||
_cachedSides = [];
|
||||
// Track deleted nodes to account for decrease in index
|
||||
_sT = _tree tvCount [];
|
||||
for [{_s = 0;}, {_s < _sT}, {_s = _s + 1}] do {
|
||||
_gT = _tree tvCount [_s];
|
||||
|
||||
for [{_g = 0;}, {_g < _gT}, {_g = _g + 1}] do {
|
||||
_grp = groupFromNetID (_tree tvData [_s,_g]);
|
||||
|
||||
if (_grp in GVAR(groupList)) then {
|
||||
_cachedGrps pushBack _grp;
|
||||
_cachedGrps pushBack _g;
|
||||
|
||||
_uT = _tree tvCount [_s,_g];
|
||||
for [{_u = 0;}, {_u < _uT}, {_u = _u + 1}] do {
|
||||
_unit = objectFromNetId (_tree tvData [_s,_g,_u]);
|
||||
|
||||
if (_unit in GVAR(unitList)) then {
|
||||
_cachedUnits pushBack _unit;
|
||||
} else {
|
||||
_tree tvDelete [_s,_g,_u];
|
||||
_u = _u - 1;
|
||||
_uT = _uT - 1;
|
||||
};
|
||||
};
|
||||
} else {
|
||||
_tree tvDelete [_s,_g];
|
||||
_g = _g - 1;
|
||||
_gT = _gT - 1;
|
||||
};
|
||||
};
|
||||
|
||||
if ((_tree tvCount [_s]) > 0) then {
|
||||
_cachedSides pushBack (_tree tvText [_s]);
|
||||
_cachedSides pushBack _s;
|
||||
} else {
|
||||
_tree tvDelete [_s];
|
||||
_s = _s - 1;
|
||||
_sT = _sT - 1;
|
||||
};
|
||||
};
|
||||
|
||||
// Update the tree from the unit list
|
||||
{
|
||||
_grp = group _x;
|
||||
_side = [side _grp] call BIS_fnc_sideName;
|
||||
|
||||
// Use correct side node
|
||||
if !(_side in _cachedSides) then {
|
||||
// Add side node
|
||||
_s = _tree tvAdd [[], _side];
|
||||
_tree tvExpand [_s];
|
||||
|
||||
_cachedSides pushBack _side;
|
||||
_cachedSides pushBack _s;
|
||||
} else {
|
||||
// If side already processed, use existing node
|
||||
_s = _cachedSides select ((_cachedSides find _side) + 1);
|
||||
};
|
||||
|
||||
// Use correct group node
|
||||
if !(_grp in _cachedGrps) then {
|
||||
// Add group node
|
||||
_g = _tree tvAdd [[_s], groupID _grp];
|
||||
_tree tvSetData [[_s,_g], netID _grp];
|
||||
|
||||
_cachedGrps pushBack _grp;
|
||||
_cachedGrps pushBack _g;
|
||||
} else {
|
||||
// If group already processed, use existing node
|
||||
_g = _cachedGrps select ((_cachedGrps find _grp) + 1);
|
||||
};
|
||||
|
||||
_u = _tree tvAdd [[_s,_g], GETVAR(_x,GVAR(uName),"")];
|
||||
_tree tvSetData [[_s,_g,_u], netID _x];
|
||||
_tree tvSetPicture [[_s,_g,_u], GETVAR(_x,GVAR(uIcon),"")];
|
||||
_tree tvSetPictureColor [[_s,_g,_u], GETVAR(_grp,GVAR(gColor),[ARR_4(1,1,1,1)])];
|
||||
|
||||
_tree tvSort [[_s,_g],false];
|
||||
} forEach (GVAR(unitList) - _cachedUnits);
|
||||
|
||||
_tree tvSort [[],false];
|
||||
|
||||
if ((_tree tvCount []) <= 0) then {
|
||||
_tree tvAdd [[], localize LSTRING(units_none)];
|
||||
};
|
||||
};
|
||||
// Map events
|
||||
case "onmapclick": {
|
||||
_args params ["_map","_button","_x","_y","_shift","_ctrl","_alt"];
|
||||
private ["_newPos","_oldZ"];
|
||||
|
||||
if ((GVAR(camMode) == 0) && (_button == 0)) then {
|
||||
_newPos = _map ctrlMapScreenToWorld [_x,_y];
|
||||
_oldZ = (ASLtoATL GVAR(camPos)) select 2;
|
||||
_newPos set [2, _oldZ];
|
||||
[nil,nil,nil, _newPos] call FUNC(setCameraAttributes);
|
||||
};
|
||||
};
|
||||
// Interrupt events
|
||||
case "escape": {
|
||||
createDialog (["RscDisplayInterrupt", "RscDisplayMPInterrupt"] select isMultiplayer);
|
||||
|
||||
disableSerialization;
|
||||
private _dlg = finddisplay 49;
|
||||
_dlg displayAddEventHandler ["KeyDown", {
|
||||
_key = _this select 1;
|
||||
!(_key == 1)
|
||||
}];
|
||||
|
||||
// Disable save, respawn, options & manual buttons
|
||||
(_dlg displayCtrl 103) ctrlEnable false;
|
||||
if !(alive player) then {
|
||||
(_dlg displayCtrl 1010) ctrlEnable false;
|
||||
};
|
||||
(_dlg displayCtrl 101) ctrlEnable false;
|
||||
(_dlg displayCtrl 122) ctrlEnable false;
|
||||
|
||||
// Initalize abort button (the "spawn" is a necessary evil)
|
||||
(_dlg displayCtrl 104) ctrlAddEventHandler ["ButtonClick",{_this spawn {
|
||||
disableSerialization;
|
||||
_display = ctrlparent (_this select 0);
|
||||
_abort = [localize "str_msg_confirm_return_lobby",nil,localize "str_disp_xbox_hint_yes",localize "str_disp_xbox_hint_no",_display,nil,true] call BIS_fnc_guiMessage;
|
||||
if (_abort) then {_display closeDisplay 2; failMission "loser"};
|
||||
}}];
|
||||
|
||||
// PFH to re-open display when menu closes
|
||||
[{
|
||||
if !(isNull (_this select 0)) exitWith {};
|
||||
|
||||
// If still a spectator then re-enter the interface
|
||||
[QGVAR(escape),false] call FUNC(interrupt);
|
||||
|
||||
[_this select 1] call CBA_fnc_removePerFrameHandler;
|
||||
},0,_dlg] call CBA_fnc_addPerFrameHandler;
|
||||
};
|
||||
case "zeus": {
|
||||
openCuratorInterface;
|
||||
|
||||
[{
|
||||
// PFH to re-open display when menu closes
|
||||
[{
|
||||
if !((isNull curatorCamera) && {isNull (GETMVAR(bis_fnc_moduleRemoteControl_unit,objNull))}) exitWith {};
|
||||
|
||||
// If still a spectator then re-enter the interface
|
||||
[QGVAR(zeus),false] call FUNC(interrupt);
|
||||
|
||||
[_this select 1] call CBA_fnc_removePerFrameHandler;
|
||||
},0] call CBA_fnc_addPerFrameHandler;
|
||||
},[],5] call CBA_fnc_waitAndExecute;
|
||||
|
||||
true
|
||||
};
|
||||
};
|
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Author: Head, SilentSpike
|
||||
* Handles rendering the spectator map icons
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Parameters <ANY>
|
||||
* 1: PFH handle <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
*
|
||||
* Example:
|
||||
* [ace_spectator_fnc_handleIcons, 0] call CBA_fnc_addPerFrameHandler;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_map"];
|
||||
private ["_center","_radius","_scaled","_drawVehicles","_leader","_color","_cachedVehicles","_unit","_icon","_txt"];
|
||||
|
||||
if (GVAR(camMode) == 0) then {
|
||||
_map drawIcon ["\A3\UI_F\Data\GUI\Rsc\RscDisplayMissionEditor\iconcamera_ca.paa",[0,0,0,1],GVAR(freeCamera),20,20,GVAR(camPan)];
|
||||
};
|
||||
|
||||
_center = _map ctrlMapScreenToWorld [0.5,0.5];
|
||||
_radius = (_map ctrlMapScreenToWorld [safeZoneX,safeZoneY]) distance2D _center;
|
||||
_scaled = (ctrlMapScale _map) > 0.2;
|
||||
|
||||
// Draw only group icons when scaled out
|
||||
_drawVehicles = [];
|
||||
{
|
||||
_leader = leader _x;
|
||||
if (_scaled) then {
|
||||
_color = GETVAR(_x,GVAR(gColor),[ARR_4(0,0,0,0)]);
|
||||
_map drawIcon ["\A3\ui_f\data\map\markers\nato\b_inf.paa", _color, _leader, 20, 20, 0, "", 0, 0];
|
||||
} else {
|
||||
if ((_leader distance2D _center) < _radius) then {
|
||||
_drawVehicles append (units _x);
|
||||
};
|
||||
};
|
||||
nil
|
||||
} count GVAR(groupList);
|
||||
|
||||
// Draw units when group leader is within screen bounds
|
||||
_cachedVehicles = [];
|
||||
{
|
||||
_unit = vehicle _x;
|
||||
|
||||
if !(_unit in _cachedVehicles) then {
|
||||
_cachedVehicles pushBack _unit;
|
||||
|
||||
// Use previously cached info where possible
|
||||
if (GETVAR(_unit,GVAR(uIcon),"") == "") then {
|
||||
[_unit] call FUNC(cacheUnitInfo);
|
||||
};
|
||||
|
||||
// Function has caching built in
|
||||
_color = [side effectiveCommander _unit] call BIS_fnc_sideColor;
|
||||
_icon = GETVAR(_unit,GVAR(uIcon),"");
|
||||
_txt = ["", GETVAR(_x,GVAR(uName),"")] select (isPlayer _x);
|
||||
|
||||
_map drawIcon [_icon, _color, _unit, 19, 19, getDir _unit, _txt, 1, 0.04];
|
||||
};
|
||||
nil
|
||||
} count (_drawVehicles arrayIntersect GVAR(unitList));
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Author: F3 Project, Head, SilentSpike
|
||||
* Processes the change in mouse position for the spectator camera
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Mouse x coord <NUMBER>
|
||||
* 1: Mouse y coord <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
*
|
||||
* Example:
|
||||
* [0.5, 0.5] call ace_spectator_fnc_handleMouse;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_x","_y"];
|
||||
private ["_leftButton","_rightButton","_oldX","_oldY","_deltaX","_deltaY","_zoomMod"];
|
||||
|
||||
_leftButton = GVAR(mouse) select 0;
|
||||
_rightButton = GVAR(mouse) select 1;
|
||||
|
||||
_oldX = GVAR(mousePos) select 0;
|
||||
_oldY = GVAR(mousePos) select 1;
|
||||
|
||||
// Get change in pos
|
||||
_deltaX = _oldX - _x;
|
||||
_deltaY = _oldY - _y;
|
||||
|
||||
if (_leftButton) then {
|
||||
GVAR(camDolly) set [0, _deltaX * -100 * GVAR(camSpeed)];
|
||||
GVAR(camDolly) set [1, _deltaY * 100 * GVAR(camSpeed)];
|
||||
} else {
|
||||
if (_rightButton) then {
|
||||
// Pan/Tilt amount should be influnced by zoom level (it should really be exponential)
|
||||
_zoomMod = (GVAR(camZoom) * 0.8) max 1;
|
||||
|
||||
GVAR(camPan) = GVAR(camPan) - ((_deltaX * 360) / _zoomMod);
|
||||
GVAR(camTilt) = ((GVAR(camTilt) + ((_deltaY * 180) / _zoomMod)) min 89) max -89;
|
||||
};
|
||||
};
|
||||
|
||||
GVAR(mousePos) = [_x,_y];
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* Author: Karel Moricky, SilentSpike
|
||||
* Handles the spectator UI toolbar values
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Parameters <ANY>
|
||||
* 1: PFH handle <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
*
|
||||
* Example:
|
||||
* [ace_spectator_fnc_handleToolbar, 0, _display] call CBA_fnc_addPerFrameHandler;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_display"];
|
||||
|
||||
// Kill PFH when toolbar hidden (or display is closed)
|
||||
if (isNil QGVAR(toolHandler)) exitWith { [_this select 1] call CBA_fnc_removePerFrameHandler; };
|
||||
|
||||
private ["_name","_vision","_fov","_speed","_mode","_time","_toolbar"];
|
||||
_toolbar = _display displayCtrl IDC_TOOL;
|
||||
|
||||
// Find all tool values
|
||||
if (GVAR(camVision) >= 0) then {
|
||||
_vision = localize LSTRING(VisionThermal);
|
||||
} else {
|
||||
_vision = [localize LSTRING(VisionNight), localize LSTRING(VisionNormal)] select (GVAR(camVision) < -1);
|
||||
};
|
||||
|
||||
if (GVAR(camMode) == 0) then {
|
||||
_fov = format ["%1x", floor(GVAR(camZoom) * 100) * 0.01];
|
||||
_speed = format ["%1 m/s", floor(GVAR(camSpeed) * 100) * 0.01];
|
||||
} else {
|
||||
_vision = [side group GVAR(camUnit)] call BIS_fnc_sideName;
|
||||
_fov = format ["%1 m", floor(getPosASL GVAR(camUnit) select 2)];
|
||||
_speed = format ["%1 km/h", floor(speed GVAR(camUnit)) max 0];
|
||||
};
|
||||
|
||||
if (alive GVAR(camUnit)) then {
|
||||
_name = GETVAR(GVAR(camUnit),GVAR(uName),"");
|
||||
} else {
|
||||
_name = localize "STR_Special_None";
|
||||
};
|
||||
|
||||
_mode = [localize LSTRING(ViewFree),localize LSTRING(ViewInternal),localize LSTRING(ViewExternal)] select GVAR(camMode);
|
||||
_time = [daytime,"HH:MM"] call BIS_fnc_timeToString;
|
||||
|
||||
// Update the UI tools
|
||||
(_toolbar controlsGroupCtrl IDC_TOOL_CLOCK) ctrlSetText _time;
|
||||
(_toolbar controlsGroupCtrl IDC_TOOL_VISION) ctrlSetText _vision;
|
||||
(_toolbar controlsGroupCtrl IDC_TOOL_FOV) ctrlSetText _fov;
|
||||
(_toolbar controlsGroupCtrl IDC_TOOL_NAME) ctrlSetText _name;
|
||||
(_toolbar controlsGroupCtrl IDC_TOOL_SPEED) ctrlSetText _speed;
|
||||
(_toolbar controlsGroupCtrl IDC_TOOL_VIEW) ctrlSetText _mode;
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Maintains the spectatable unit list and updates the unit tree accordingly
|
||||
* Also updates current camera unit when status changes
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Parameters <ANY>
|
||||
* 1: PFH handle <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
*
|
||||
* Example:
|
||||
* [ace_spectator_fnc_handleUnits, 10, _display] call CBA_fnc_addPerFrameHandler;
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_display"];
|
||||
|
||||
// Kill PFH when display is closed
|
||||
if (isNull _display) exitWith { [_this select 1] call CBA_fnc_removePerFrameHandler; };
|
||||
|
||||
// Remove all dead and null units from the list
|
||||
[] call FUNC(updateUnits);
|
||||
|
||||
// Camera shouldn't stay on unit that isn't in the list (unless dead)
|
||||
if !(GVAR(camUnit) in GVAR(unitList)) then {
|
||||
if (alive GVAR(camUnit) || isNull GVAR(camUnit)) then {
|
||||
[nil,1] call FUNC(cycleCamera);
|
||||
};
|
||||
};
|
||||
|
||||
// Reduce overhead when unit tree is hidden
|
||||
if (ctrlShown (_display displayCtrl IDC_UNIT)) then {
|
||||
// Reduce overhead by spreading across frames
|
||||
[FUNC(handleInterface),["onUnitsUpdate",[(_display displayCtrl IDC_UNIT) controlsGroupCtrl IDC_UNIT_TREE]],1] call CBA_fnc_waitAndExecute;
|
||||
};
|
@ -1,27 +1,17 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Interrupts the spectator interface for external systems
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Reason <STRING>
|
||||
* 1: Interrupting <BOOL> (default: true)
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
*
|
||||
* Example:
|
||||
* ["mySystem"] call ace_spectator_fnc_interrupt
|
||||
*
|
||||
* Public: Yes
|
||||
* Deprecated. Technically never publically documented, but just in case.
|
||||
*/
|
||||
#include "script_component.hpp"
|
||||
|
||||
params [["_reason", "", [""]], ["_interrupt", true, [true]]];
|
||||
|
||||
ACE_DEPRECATED(QFUNC(interrupt),"3.12.0","just close and reopen spectator");
|
||||
|
||||
// Nothing to do when spectator is closed
|
||||
if !(GVAR(isSet)) exitWith {};
|
||||
|
||||
if (_reason == "") exitWith { ERROR("Invalid Reason"); };
|
||||
if (_reason == "") exitWith { WARNING("Invalid Reason"); };
|
||||
if (_interrupt) then {
|
||||
GVAR(interrupts) pushBack _reason;
|
||||
} else {
|
||||
@ -29,16 +19,11 @@ if (_interrupt) then {
|
||||
};
|
||||
|
||||
if (GVAR(interrupts) isEqualTo []) then {
|
||||
if (isNull (GETUVAR(GVAR(interface),displayNull))) then {
|
||||
(findDisplay 46) createDisplay QGVAR(interface);
|
||||
[] call FUNC(transitionCamera);
|
||||
if (isNull SPEC_DISPLAY) then {
|
||||
[true] call FUNC(ui);
|
||||
};
|
||||
} else {
|
||||
if !(isNull (GETUVAR(GVAR(interface),displayNull))) then {
|
||||
while {dialog} do {
|
||||
closeDialog 0;
|
||||
};
|
||||
|
||||
(GETUVAR(GVAR(interface),displayNull)) closeDisplay 0;
|
||||
if !(isNull SPEC_DISPLAY) then {
|
||||
[false] call FUNC(ui);
|
||||
};
|
||||
};
|
||||
|
@ -8,7 +8,7 @@
|
||||
* 2: activated <BOOL>
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [LOGIC, [bob, kevin], true] call ace_spectator_fnc_moduleSpectatorSettings
|
||||
@ -22,7 +22,7 @@ params ["_logic", "_units", "_activated"];
|
||||
|
||||
if !(_activated) exitWith {};
|
||||
|
||||
[_logic, QGVAR(filterUnits), "unitsFilter"] call EFUNC(common,readSettingFromModule);
|
||||
[_logic, QGVAR(filterSides), "sidesFilter"] call EFUNC(common,readSettingFromModule);
|
||||
[_logic, QGVAR(enableAI), "enableAI"] call EFUNC(common,readSettingFromModule);
|
||||
[_logic, QGVAR(restrictModes), "cameraModes"] call EFUNC(common,readSettingFromModule);
|
||||
[_logic, QGVAR(restrictVisions), "visionModes"] call EFUNC(common,readSettingFromModule);
|
||||
[_logic, QGVAR(mapLocations), "mapLocations"] call EFUNC(common,readSettingFromModule);
|
||||
|
19
addons/spectator/functions/fnc_players.sqf
Normal file
19
addons/spectator/functions/fnc_players.sqf
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Return all of the player entities who are currently in ace spectator
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* Spectator Players <ARRAY>
|
||||
*
|
||||
* Example:
|
||||
* [] call ace_spectator_fnc_players
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
allPlayers select { GETVAR(_x,GVAR(isSet),false) }
|
39
addons/spectator/functions/fnc_removeLocation.sqf
Normal file
39
addons/spectator/functions/fnc_removeLocation.sqf
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, SilentSpike
|
||||
* Remove a location that can be seen in spectator view. Local effect.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Unique ID <STRING>
|
||||
*
|
||||
* Return Value:
|
||||
* Success <BOOL>
|
||||
*
|
||||
* Example:
|
||||
* [_id] call ace_spectator_fnc_removeLocation
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params [["_id","",[""]]];
|
||||
|
||||
private _index = -1;
|
||||
|
||||
{
|
||||
if ((_x select 0) == _id) exitWith {
|
||||
_index = _forEachIndex;
|
||||
};
|
||||
} forEach GVAR(locationsList);
|
||||
|
||||
GVAR(locationsList) deleteAt _index;
|
||||
|
||||
// Update the list if appropriate
|
||||
if !(isNull SPEC_DISPLAY) then {
|
||||
if (GVAR(uiListType) == LIST_LOCATIONS) then {
|
||||
[] call FUNC(ui_updateListLocations);
|
||||
};
|
||||
};
|
||||
|
||||
// Return
|
||||
_index != -1
|
@ -1,7 +1,8 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* The ace_spectator respawn template, handles killed + respawn
|
||||
* Can be used via BI's respawn framework, see:
|
||||
* The ace_spectator respawn template, compatible with types 1,2,3,4 & 5
|
||||
*
|
||||
* Handles killed and respawned events as per BI's respawn framework:
|
||||
* https://community.bistudio.com/wiki/Arma_3_Respawn
|
||||
*
|
||||
* Arguments:
|
||||
@ -21,26 +22,18 @@
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params [["_unit",objNull,[objNull]], ["_killer",objNull,[objNull]], ["_respawn",0,[0]], ["_respawnDelay",0,[0]]];
|
||||
params [["_newCorpse",objNull,[objNull]], ["_oldKiller",objNull,[objNull]], ["_respawn",0,[0]], ["_respawnDelay",0,[0]]];
|
||||
|
||||
// Some environment information can be used for the initial camera attributes
|
||||
if (isNull _killer) then {_killer = _unit};
|
||||
private _vision = [-2,-1] select (sunOrMoon < 1);
|
||||
private _pos = (getPosATL _unit) vectorAdd [0,0,5];
|
||||
|
||||
// Enter/exit spectator based on the respawn type and whether killed/respawned
|
||||
if (alive _unit) then {
|
||||
if (_respawn == 1) then {
|
||||
[_unit] call FUNC(stageSpectator);
|
||||
[2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes);
|
||||
[true] call FUNC(setSpectator);
|
||||
} else {
|
||||
[false] call FUNC(setSpectator);
|
||||
};
|
||||
} else {
|
||||
// Negligible respawn delay can result in entering spectator after respawn
|
||||
if (playerRespawnTime <= 1) exitWith {};
|
||||
|
||||
[2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes);
|
||||
[true] call FUNC(setSpectator);
|
||||
// Compatibility handled via spectator display XEH
|
||||
if (_respawn in [0,1,4,5]) exitWith {
|
||||
// This only applies to respawn type 1 (BIRD/SPECTATOR)
|
||||
// Remove the seagull (not actually the player, a CfgNonAIVehicles object)
|
||||
if (typeOf _newCorpse == "seagull") then { deleteVehicle _newCorpse; };
|
||||
};
|
||||
|
||||
// If player died while already in spectator, ignore
|
||||
if (!GVAR(isSet) || {alive _newCorpse}) then {
|
||||
// Negligible respawn delay can result in entering spectator after respawn
|
||||
// So we just use this value rather than living state of the unit
|
||||
[playerRespawnTime > 1] call FUNC(setSpectator);
|
||||
};
|
||||
|
@ -1,27 +1,30 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Sets the spectator camera attributes as desired
|
||||
* All values are optional and default to whatever the current value is
|
||||
* Sets the spectator camera attributes as desired. Local effect.
|
||||
* All values are optional and default to no change.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Camera mode <NUMBER>
|
||||
* - 0: Free
|
||||
* - 1: Internal
|
||||
* - 2: External
|
||||
* 1: Camera unit (objNull for random) <OBJECT>
|
||||
* - 1: First Person
|
||||
* - 2: Follow
|
||||
* 1: Camera focus <OBJECT or BOOL>
|
||||
* 2: Camera vision <NUMBER>
|
||||
* - -2: Normal
|
||||
* - -1: Night vision
|
||||
* - 0: Thermal white hot
|
||||
* - 1: Thermal black hot
|
||||
* - ...
|
||||
* 3: Camera position (ATL) <ARRAY>
|
||||
* 4: Camera pan (0 - 360) <NUMBER>
|
||||
* 5: Camera tilt (-90 - 90) <NUMBER>
|
||||
* 6: Camera zoom (0.01 - 2) <NUMBER>
|
||||
* 7: Camera speed in m/s (0.05 - 10) <NUMBER>
|
||||
* 4: Camera direction (0 - 360) <NUMBER>
|
||||
*
|
||||
* Notes:
|
||||
* - If camera mode is not free and camera has no focus, random will be used
|
||||
* - To remove any current camera focus in free cam, use objNull
|
||||
* - To select a random camera focus, use a boolean
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [1, objNull] call ace_spectator_fnc_setCameraAttributes
|
||||
@ -32,37 +35,68 @@
|
||||
#include "script_component.hpp"
|
||||
|
||||
params [
|
||||
["_mode",GVAR(camMode),[0]],
|
||||
["_unit",GVAR(camUnit),[objNull]],
|
||||
["_vision",GVAR(camVision),[0]],
|
||||
["_position",ASLtoATL GVAR(camPos),[[]],3],
|
||||
["_heading",GVAR(camPan),[0]],
|
||||
["_tilt",GVAR(camTilt),[0]],
|
||||
["_zoom",GVAR(camZoom),[0]],
|
||||
["_speed",GVAR(camSpeed),[0]]
|
||||
["_mode",nil,[0]],
|
||||
["_focus",nil,[objNull,true]],
|
||||
["_vision",nil,[0]],
|
||||
["_position",nil,[[]],3],
|
||||
["_direction",nil,[0]]
|
||||
];
|
||||
|
||||
// Normalize input
|
||||
if !(_mode in GVAR(availableModes)) then {
|
||||
_mode = GVAR(availableModes) select ((GVAR(availableModes) find GVAR(camMode)) max 0);
|
||||
if (count _this > 5) then {
|
||||
ACE_DEPRECATED("Use of ""tilt"", ""zoom"" and ""speed"" camera attributes","3.12.0","N/A")
|
||||
};
|
||||
|
||||
if !(_vision in GVAR(availableVisions)) then {
|
||||
_vision = GVAR(availableVisions) select ((GVAR(availableVisions) find GVAR(camVision)) max 0);
|
||||
};
|
||||
|
||||
GVAR(camPan) = _heading % 360;
|
||||
GVAR(camSpeed) = (_speed max 0.05) min 10;
|
||||
GVAR(camTilt) = (_tilt max -89) min 89;
|
||||
GVAR(camUnit) = _unit;
|
||||
GVAR(camVision) = _vision;
|
||||
GVAR(camZoom) = (_zoom min 2) max 0.01;
|
||||
|
||||
// Apply if camera exists
|
||||
if (GVAR(isSet)) then {
|
||||
GVAR(camPos) = (ATLtoASL _position); // Camera position will be updated in FUNC(handleCamera)
|
||||
[_mode,_unit,_vision] call FUNC(transitionCamera);
|
||||
if !(isNil QGVAR(camera)) then {
|
||||
// These functions are smart and handle unavailable inputs
|
||||
if !(isNil "_focus") then {
|
||||
[_focus] call FUNC(setFocus);
|
||||
};
|
||||
|
||||
if !(isNil "_mode") then {
|
||||
// If mode not free and no focus, find focus
|
||||
if ((_mode != MODE_FREE) && {isNull GVAR(camTarget) || GVAR(camOnLocation)}) then {
|
||||
[true] call FUNC(setFocus);
|
||||
};
|
||||
|
||||
[_mode] call FUNC(cam_setCameraMode);
|
||||
};
|
||||
|
||||
if !(isNil "_vision") then {
|
||||
[_vision] call FUNC(cam_setVisionMode);
|
||||
};
|
||||
|
||||
if !(isNil "_position") then {
|
||||
GVAR(camera) setPosATL _position;
|
||||
};
|
||||
|
||||
if !(isNil "_direction") then {
|
||||
GVAR(camera) setDir _direction;
|
||||
};
|
||||
} else {
|
||||
GVAR(camMode) = _mode;
|
||||
GVAR(camPos) = (ATLtoASL _position);
|
||||
if !(isNil "_focus") then {
|
||||
// If there are no entities this becomes nil, handled on camera startup
|
||||
if (_focus isEqualType true) then {
|
||||
_focus = ([] call FUNC(getTargetEntities)) select 0;
|
||||
};
|
||||
|
||||
GVAR(camTarget) = _focus;
|
||||
};
|
||||
|
||||
if !(isNil "_mode") then {
|
||||
GVAR(camMode) = _mode;
|
||||
};
|
||||
|
||||
if !(isNil "_vision") then {
|
||||
GVAR(camVision) = _vision;
|
||||
};
|
||||
|
||||
// GVARs exits purely for pre-setting of these attributes
|
||||
if !(isNil "_position") then {
|
||||
GVAR(camPos) = ATLtoASL _position;
|
||||
};
|
||||
|
||||
if !(isNil "_direction") then {
|
||||
GVAR(camDir) = _direction;
|
||||
};
|
||||
};
|
||||
|
68
addons/spectator/functions/fnc_setFocus.sqf
Normal file
68
addons/spectator/functions/fnc_setFocus.sqf
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Author: AACO, SilentSpike
|
||||
* Function used to set the camera focus
|
||||
*
|
||||
* Arguments:
|
||||
* 0: New focus <OBJECT>
|
||||
* 1: Focus is a location <BOOL>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [player, false] call ace_spectator_fnc_setFocus
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params [["_newFocus", objNull, [objNull,true]], ["_focusIsLocation",false]];
|
||||
|
||||
// If boolean provided then first find a focus
|
||||
if (_newFocus isEqualType true) then {
|
||||
private _testFocus = ([] call FUNC(getTargetEntities)) select 0;
|
||||
|
||||
if (isNil "_testFocus") then {
|
||||
if (MODE_FREE in GVAR(availableModes)) then {
|
||||
WARNING("No available entities to focus on. Switching to free cam.");
|
||||
[MODE_FREE] call FUNC(cam_setCameraMode);
|
||||
_newFocus = objNull;
|
||||
} else {
|
||||
// Default to player if necessary
|
||||
WARNING("No available entities to focus on. Using player.");
|
||||
_newFocus = player;
|
||||
};
|
||||
} else {
|
||||
_newFocus = _testFocus;
|
||||
};
|
||||
};
|
||||
|
||||
if (_newFocus != GVAR(camTarget) && { !(isNull _newFocus && { isNull GVAR(camTarget) }) }) then {
|
||||
GVAR(camTarget) = _newFocus;
|
||||
|
||||
if (isNull _newFocus) then {
|
||||
if (GVAR(camMode) == MODE_FREE) then {
|
||||
[] call FUNC(cam_resetTarget);
|
||||
} else {
|
||||
[MODE_FREE] call FUNC(cam_setCameraMode);
|
||||
};
|
||||
} else {
|
||||
// Locations can only be focused on in free camera
|
||||
if (_focusIsLocation) then {
|
||||
[MODE_FREE] call FUNC(cam_setCameraMode);
|
||||
} else {
|
||||
[GVAR(camMode)] call FUNC(cam_setCameraMode);
|
||||
};
|
||||
};
|
||||
|
||||
// GVAR used to prevent camera switching and UI info on locations
|
||||
GVAR(camOnLocation) = _focusIsLocation;
|
||||
|
||||
// Only update display if it exists, this function is independent of it
|
||||
if !(isNull SPEC_DISPLAY) then {
|
||||
[] call FUNC(ui_updateListFocus);
|
||||
[] call FUNC(ui_updateWidget);
|
||||
[] call FUNC(ui_updateHelp);
|
||||
};
|
||||
};
|
@ -1,17 +1,17 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Sets local client to the given spectator state (virtually)
|
||||
* To physically handle a spectator see ace_spectator_fnc_stageSpectator
|
||||
* Enter/exit spectator mode for the local player
|
||||
*
|
||||
* Client will be able to communicate in ACRE/TFAR as appropriate
|
||||
* The spectator interface will be opened/closed
|
||||
* If "hide player" is true player will be hidden from group, invisible and invulnerable, but unmoved
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Spectator state of local client <BOOL> (default: true)
|
||||
* 1: Force interface <BOOL> (default: true)
|
||||
* 2: Hide player (if alive) <BOOL> (default: true)
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [true] call ace_spectator_fnc_setSpectator
|
||||
@ -21,47 +21,43 @@
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params [["_set",true,[true]], ["_force",true,[true]]];
|
||||
params [["_set",true,[true]], ["_force",true,[true]], ["_hide",true,[true]]];
|
||||
|
||||
// Only clients can be spectators
|
||||
if !(hasInterface) exitWith {};
|
||||
|
||||
// Exit if no change
|
||||
// Let the display know if it is or isn't forced
|
||||
// Could be switched after spectator has already started
|
||||
GVAR(uiForced) = _force;
|
||||
|
||||
// Exit if no change (everything above this may need to be ran again)
|
||||
if (_set isEqualTo GVAR(isSet)) exitWith {};
|
||||
|
||||
// Handle common addon audio
|
||||
// Delay if local player (must not be ACE_Player) is not fully initalized
|
||||
if (isNil { player } || { isNull player }) exitWith {
|
||||
[
|
||||
{ !isNil { player } && { !isNull player } },
|
||||
FUNC(setSpectator),
|
||||
_this
|
||||
] call CBA_fnc_waitUntilAndExecute;
|
||||
};
|
||||
|
||||
// Remove any current deafness and disable volume updates while spectating
|
||||
if (["ace_hearing"] call EFUNC(common,isModLoaded)) then {
|
||||
EGVAR(hearing,disableVolumeUpdate) = _set;
|
||||
EGVAR(hearing,deafnessDV) = 0;
|
||||
};
|
||||
|
||||
// Toggle spectator mode in 3rd party radio addons
|
||||
if (["acre_sys_radio"] call EFUNC(common,isModLoaded)) then {[_set] call acre_api_fnc_setSpectator};
|
||||
if (["task_force_radio"] call EFUNC(common,isModLoaded)) then {[player, _set] call TFAR_fnc_forceSpectator};
|
||||
|
||||
if (_set) then {
|
||||
// Initalize camera variables
|
||||
GVAR(camBoom) = 0;
|
||||
GVAR(camDolly) = [0,0];
|
||||
GVAR(camGun) = false;
|
||||
// Initalize the camera
|
||||
[true] call FUNC(cam);
|
||||
|
||||
// Initalize display variables
|
||||
GVAR(ctrlKey) = false;
|
||||
GVAR(heldKeys) = [];
|
||||
GVAR(heldKeys) resize 255;
|
||||
GVAR(mouse) = [false,false];
|
||||
GVAR(mousePos) = [0.5,0.5];
|
||||
|
||||
// Update units before opening to support pre-set camera unit
|
||||
[] call FUNC(updateUnits);
|
||||
|
||||
// Initalize the camera objects
|
||||
GVAR(freeCamera) = "Camera" camCreate (ASLtoATL GVAR(camPos));
|
||||
GVAR(unitCamera) = "Camera" camCreate [0,0,0];
|
||||
GVAR(targetCamera) = "Camera" camCreate [0,0,0];
|
||||
|
||||
// Initalize view
|
||||
GVAR(unitCamera) camSetTarget GVAR(targetCamera);
|
||||
GVAR(unitCamera) camCommit 0;
|
||||
[] call FUNC(transitionCamera);
|
||||
// Create the display when main display is ready
|
||||
[{ !isNull MAIN_DISPLAY },{ [true] call FUNC(ui) }] call CBA_fnc_waitUntilAndExecute;
|
||||
|
||||
// Cache current channel to switch back to on exit
|
||||
GVAR(channelCache) = currentChannel;
|
||||
@ -70,35 +66,6 @@ if (_set) then {
|
||||
GVAR(channel) radioChannelAdd [player];
|
||||
setCurrentChannel (5 + GVAR(channel));
|
||||
|
||||
// Close map and clear the chat
|
||||
openMap [false,false];
|
||||
clearRadio;
|
||||
enableRadio false;
|
||||
|
||||
// Disable BI damage effects
|
||||
BIS_fnc_feedback_allowPP = false;
|
||||
|
||||
// Close any open dialogs
|
||||
while {dialog} do {
|
||||
closeDialog 0;
|
||||
};
|
||||
|
||||
[{
|
||||
disableSerialization;
|
||||
// Create the display
|
||||
_display = (findDisplay 46) createDisplay QGVAR(interface);
|
||||
|
||||
// If not forced, make esc end spectator
|
||||
if (_this) then {
|
||||
_display displayAddEventHandler ["KeyDown", {
|
||||
if (_this select 1 == 1) then {
|
||||
[false] call FUNC(setSpectator);
|
||||
true
|
||||
};
|
||||
}];
|
||||
};
|
||||
}, !_force] call CBA_fnc_execNextFrame;
|
||||
|
||||
// Cache and disable nametag settings
|
||||
if (["ace_nametags"] call EFUNC(common,isModLoaded)) then {
|
||||
GVAR(nametagSettingCache) = [EGVAR(nametags,showPlayerNames), EGVAR(nametags,showNamesForAI)];
|
||||
@ -106,19 +73,14 @@ if (_set) then {
|
||||
EGVAR(nametags,showNamesForAI) = false;
|
||||
};
|
||||
} else {
|
||||
// Close any open dialogs (could be interrupts)
|
||||
while {dialog} do {
|
||||
closeDialog 0;
|
||||
};
|
||||
// Kill the display (ensure main display exists, handles edge case where spectator turned off before display exists)
|
||||
[{ !isNull MAIN_DISPLAY },{ [false] call FUNC(ui) }] call CBA_fnc_waitUntilAndExecute;
|
||||
|
||||
// Kill the display
|
||||
(GETUVAR(GVAR(interface),displayNull)) closeDisplay 0;
|
||||
// This variable doesn't matter anymore
|
||||
GVAR(uiForced) = nil;
|
||||
|
||||
// Terminate camera
|
||||
GVAR(freeCamera) cameraEffect ["terminate", "back"];
|
||||
camDestroy GVAR(freeCamera);
|
||||
camDestroy GVAR(unitCamera);
|
||||
camDestroy GVAR(targetCamera);
|
||||
[false] call FUNC(cam);
|
||||
|
||||
// Remove from spectator chat
|
||||
GVAR(channel) radioChannelRemove [player];
|
||||
@ -127,35 +89,6 @@ if (_set) then {
|
||||
setCurrentChannel GVAR(channelCache);
|
||||
GVAR(channelCache) = nil;
|
||||
|
||||
// Clear any residual spectator chat
|
||||
clearRadio;
|
||||
enableRadio true;
|
||||
|
||||
// Return to player view
|
||||
player switchCamera "internal";
|
||||
|
||||
// Enable BI damage effects
|
||||
BIS_fnc_feedback_allowPP = true;
|
||||
|
||||
// Cleanup camera variables
|
||||
GVAR(camBoom) = nil;
|
||||
GVAR(camDolly) = nil;
|
||||
GVAR(camGun) = nil;
|
||||
GVAR(freeCamera) = nil;
|
||||
GVAR(unitCamera) = nil;
|
||||
GVAR(targetCamera) = nil;
|
||||
|
||||
//Kill these PFEH handlers now because the PFEH can run before the `onunload` event is handled
|
||||
GVAR(camHandler) = nil;
|
||||
GVAR(compHandler) = nil;
|
||||
GVAR(toolHandler) = nil;
|
||||
|
||||
// Cleanup display variables
|
||||
GVAR(ctrlKey) = nil;
|
||||
GVAR(heldKeys) = nil;
|
||||
GVAR(mouse) = nil;
|
||||
GVAR(mousePos) = nil;
|
||||
|
||||
// Reset nametag settings
|
||||
if (["ace_nametags"] call EFUNC(common,isModLoaded)) then {
|
||||
EGVAR(nametags,showPlayerNames) = GVAR(nametagSettingCache) select 0;
|
||||
@ -164,10 +97,27 @@ if (_set) then {
|
||||
};
|
||||
};
|
||||
|
||||
// Hide/Unhide the player if enabled and alive
|
||||
if (alive player) then {
|
||||
private _hidden = (_hide && _set);
|
||||
|
||||
// Ignore damage (vanilla and ace_medical)
|
||||
player allowDamage !_hidden;
|
||||
player setVariable [QEGVAR(medical,allowDamage), !_hidden];
|
||||
|
||||
// Move to/from group as appropriate
|
||||
[player, _hidden, QGVAR(isSet), side group player] call EFUNC(common,switchToGroupSide);
|
||||
|
||||
// Ghosts can't talk
|
||||
[_hidden, QGVAR(isSet)] call EFUNC(common,hideUnit);
|
||||
[_hidden, QGVAR(isSet)] call EFUNC(common,muteUnit);
|
||||
};
|
||||
|
||||
// Reset interruptions
|
||||
GVAR(interrupts) = [];
|
||||
|
||||
// Mark spectator state for reference
|
||||
GVAR(isSet) = _set;
|
||||
player setVariable [QGVAR(isSet), true, true];
|
||||
|
||||
["ace_spectatorSet", [_set]] call CBA_fnc_localEvent;
|
||||
["ace_spectatorSet", [_set, player]] call CBA_fnc_globalEvent;
|
||||
|
@ -1,26 +1,27 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Sets target unit to the given spectator state (physically)
|
||||
* To virtually handle a spectator see ace_spectator_fnc_setSpectator
|
||||
* Stores and hides a player safely out of the way (used by setSpectator on living players)
|
||||
*
|
||||
* Units will be gathered at marker ace_spectator_respawn (or [0,0,0] by default)
|
||||
* Upon unstage, units will be moved to the position they were in upon staging
|
||||
* Upon unstage, units will be moved to the position they were in before staging
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Unit to put into spectator stage <OBJECT> (default: player)
|
||||
* 1: Unit should be staged <BOOL> (default: true)
|
||||
* 0: Unit to handle <OBJECT>
|
||||
* 1: Stage/Unstage <BOOL>
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [player, false] call ace_spectator_fnc_stageSpectator
|
||||
* [player, true] call ace_spectator_fnc_stageSpectator
|
||||
*
|
||||
* Public: Yes
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
ACE_DEPRECATED(QFUNC(stageSpectator),"3.12.0",[ARR_2(QFUNC(setSpectator),"'s new 3rd parameter")] joinString "");
|
||||
|
||||
params [["_unit",player,[objNull]], ["_set",true,[true]]];
|
||||
|
||||
// No change, no service (but allow spectators to be reset)
|
||||
@ -39,20 +40,35 @@ _unit enableSimulation !_set;
|
||||
if (_set) then {
|
||||
// Position should only be saved on first entry
|
||||
if !(GETVAR(_unit,GVAR(isStaged),false)) then {
|
||||
GVAR(oldPos) = getPosATL _unit;
|
||||
SETVAR(_unit,GVAR(preStagePos),getPosATL _unit);
|
||||
|
||||
// Handle players respawning via pause menu (or script)
|
||||
private _id = _unit addEventHandler ["Respawn",{
|
||||
params ["_unit"];
|
||||
[_unit] call FUNC(stageSpectator);
|
||||
}];
|
||||
|
||||
SETVAR(_unit,GVAR(respawnEH),_id);
|
||||
};
|
||||
|
||||
// Ghosts can't talk
|
||||
[_unit, QGVAR(isStaged)] call EFUNC(common,hideUnit);
|
||||
[_unit, QGVAR(isStaged)] call EFUNC(common,muteUnit);
|
||||
|
||||
// Position defaults to [0,0,0] if marker doesn't exist
|
||||
_unit setPos (markerPos QGVAR(respawn));
|
||||
} else {
|
||||
// Physical beings can talk
|
||||
[_unit, QGVAR(isStaged)] call EFUNC(common,unhideUnit);
|
||||
[_unit, QGVAR(isStaged)] call EFUNC(common,unmuteUnit);
|
||||
|
||||
_unit setPosATL GVAR(oldPos);
|
||||
// Restore original position and delete stored value
|
||||
_unit setPosATL (GETVAR(_unit,GVAR(preStagePos),getPosATL _unit));
|
||||
SETVAR(_unit,GVAR(preStagePos),nil);
|
||||
|
||||
// Remove the respawn handling
|
||||
_unit removeEventHandler ["Respawn",GETVAR(_unit,GVAR(respawnEH),-1)];
|
||||
SETVAR(_unit,GVAR(respawnEH),nil);
|
||||
};
|
||||
|
||||
// Spectators ignore damage (vanilla and ace_medical)
|
||||
@ -62,17 +78,12 @@ _unit setVariable [QEGVAR(medical,allowDamage), !_set];
|
||||
// No theoretical change if an existing spectator was reset
|
||||
if !(_set isEqualTo (GETVAR(_unit,GVAR(isStaged),false))) then {
|
||||
// Mark spectator state for reference
|
||||
_unit setVariable [QGVAR(isStaged), _set, true];
|
||||
|
||||
["ace_spectatorStaged", [_set]] call CBA_fnc_localEvent;
|
||||
_unit setVariable [QGVAR(isStaged), _set];
|
||||
};
|
||||
|
||||
//BandAid for #2677 - if player in unitList weird before being staged, weird things can happen
|
||||
if ((player in GVAR(unitList)) || {ACE_player in GVAR(unitList)}) then {
|
||||
[] call FUNC(updateUnits); //update list now
|
||||
if (!(isNull (findDisplay 12249))) then {//If display is open now, close it and restart
|
||||
WARNING("Player in unitList, call ace_spectator_fnc_stageSpectator before ace_spectator_fnc_setSpectator");
|
||||
["fixWeirdList", true] call FUNC(interrupt);
|
||||
[{["fixWeirdList", false] call FUNC(interrupt);}, []] call CBA_fnc_execNextFrame;
|
||||
// If display exists already update the entity list to hide player
|
||||
if !(isNull SPEC_DISPLAY) then {
|
||||
if (GVAR(uiListType) == LIST_ENTITIES) then {
|
||||
[] call FUNC(ui_updateListEntities);
|
||||
};
|
||||
};
|
||||
|
31
addons/spectator/functions/fnc_switchFocus.sqf
Normal file
31
addons/spectator/functions/fnc_switchFocus.sqf
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, SilentSpike
|
||||
* Function used to switch to next or previous camera focus
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Next/Prev unit <BOOL>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [false] call ace_spectator_fnc_switchFocus
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
private _next = param [0, true];
|
||||
private _entities = [true] call FUNC(getTargetEntities);
|
||||
private _focus = GVAR(camTarget);
|
||||
|
||||
// No entities to switch to
|
||||
if ((_entities isEqualTo []) || (_entities isEqualTo [_focus])) exitWith {};
|
||||
|
||||
private _index = (_entities find _focus) max 0;
|
||||
|
||||
_index = (_index + ([-1, 1] select _next)) % (count _entities);
|
||||
if (_index < 0) then { _index = count _entities + _index; };
|
||||
|
||||
[_entities select _index] call FUNC(setFocus);
|
@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Correctly handles toggling of spectator interface elements for clean UX
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Display <DISPLAY>
|
||||
* 1: Toogle compass <BOOL> <OPTIONAL>
|
||||
* 2: Toogle help <BOOL> <OPTIONAL>
|
||||
* 3: Toogle interface <BOOL> <OPTIONAL>
|
||||
* 4: Toogle map <BOOL> <OPTIONAL>
|
||||
* 5: Toogle toolbar <BOOL> <OPTIONAL>
|
||||
* 6: Toogle unit list <BOOL> <OPTIONAL>
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
*
|
||||
* Example:
|
||||
* [_display, nil, true] call ace_spectator_fnc_toggleInterface
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_display", ["_toggleComp",false], ["_toggleHelp",false], ["_toggleInterface",false], ["_toggleMap",false], ["_toggleTool",false], ["_toggleUnit",false]];
|
||||
|
||||
private ["_comp","_help","_map","_tool","_unit"];
|
||||
_comp = _display displayCtrl IDC_COMP;
|
||||
_help = _display displayCtrl IDC_HELP;
|
||||
_map = _display displayCtrl IDC_MAP;
|
||||
_tool = _display displayCtrl IDC_TOOL;
|
||||
_unit = _display displayCtrl IDC_UNIT;
|
||||
|
||||
// Map operates outside of interface
|
||||
GVAR(showMap) = [GVAR(showMap), !GVAR(showMap)] select _toggleMap;
|
||||
_map ctrlShow GVAR(showMap);
|
||||
|
||||
if (GVAR(showMap)) then {
|
||||
// When map is shown, temporarily hide interface to stop overlapping
|
||||
{
|
||||
_x ctrlShow false;
|
||||
} forEach [_comp,_help,_tool,_unit];
|
||||
|
||||
// Centre map on camera/unit upon opening
|
||||
if (_toggleMap) then {
|
||||
_map ctrlMapAnimAdd [0, 0.5, [GVAR(camUnit),GVAR(freeCamera)] select (GVAR(camMode) == 0)];
|
||||
ctrlMapAnimCommit _map;
|
||||
};
|
||||
} else {
|
||||
// Can only toggle interface with map minimised
|
||||
GVAR(showInterface) = [GVAR(showInterface), !GVAR(showInterface)] select _toggleInterface;
|
||||
|
||||
if (GVAR(showInterface)) then {
|
||||
// Can only toggle interface elements with interface shown
|
||||
GVAR(showComp) = [GVAR(showComp), !GVAR(showComp)] select _toggleComp;
|
||||
GVAR(showHelp) = [GVAR(showHelp), !GVAR(showHelp)] select _toggleHelp;
|
||||
GVAR(showTool) = [GVAR(showTool), !GVAR(showTool)] select _toggleTool;
|
||||
GVAR(showUnit) = [GVAR(showUnit), !GVAR(showUnit)] select _toggleUnit;
|
||||
|
||||
_comp ctrlShow GVAR(showComp);
|
||||
_help ctrlShow GVAR(showHelp);
|
||||
_tool ctrlShow GVAR(showTool);
|
||||
_unit ctrlShow GVAR(showUnit);
|
||||
} else {
|
||||
{
|
||||
_x ctrlShow false;
|
||||
} forEach [_comp,_help,_tool,_unit];
|
||||
};
|
||||
};
|
||||
|
||||
// Only run PFHs when respective control is shown, otherwise kill
|
||||
if (ctrlShown _comp) then {
|
||||
if (isNil QGVAR(compHandler)) then { GVAR(compHandler) = [FUNC(handleCompass), 0, _display] call CBA_fnc_addPerFrameHandler; };
|
||||
} else {
|
||||
GVAR(compHandler) = nil;
|
||||
};
|
||||
|
||||
if (ctrlShown _tool) then {
|
||||
if (isNil QGVAR(toolHandler)) then { GVAR(toolHandler) = [FUNC(handleToolbar), 0, _display] call CBA_fnc_addPerFrameHandler; };
|
||||
} else {
|
||||
GVAR(toolHandler) = nil;
|
||||
};
|
@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Transitions the spectator camera vision/view/unit
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Camera mode <NUMBER>
|
||||
* - 0: Free
|
||||
* - 1: Internal
|
||||
* - 2: External
|
||||
* 1: Camera unit <OBJECT>
|
||||
* 2: Vision mode <NUMBER>
|
||||
* - -2: Normal
|
||||
* - -1: NV
|
||||
* - 0: White hot
|
||||
* - 1: Black hot
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
*
|
||||
* Example:
|
||||
* [0,objNull] call ace_spectator_fnc_transitionCamera
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params [["_newMode",GVAR(camMode)], ["_newUnit",GVAR(camUnit)], ["_newVision",GVAR(camVision)]];
|
||||
|
||||
// If new mode isn't available then keep current (unless current also isn't)
|
||||
if !(_newMode in GVAR(availableModes)) then {
|
||||
_newMode = GVAR(availableModes) select ((GVAR(availableModes) find GVAR(camMode)) max 0);
|
||||
};
|
||||
|
||||
// When no units available to spectate, exit to freecam
|
||||
if ((GVAR(unitList) isEqualTo []) && (alive _newUnit || isNull _newUnit)) then {
|
||||
_newMode = 0;
|
||||
_newUnit = objNull;
|
||||
};
|
||||
|
||||
// Reset gun cam if not internal
|
||||
if (_newMode != 1) then {
|
||||
GVAR(camGun) = false;
|
||||
};
|
||||
|
||||
private ["_camera"];
|
||||
if (_newMode == 0) then { // Free
|
||||
_camera = GVAR(freeCamera);
|
||||
|
||||
// Preserve camUnit value for consistency when manually changing view
|
||||
_camera cameraEffect ["internal", "back"];
|
||||
|
||||
// Apply the camera zoom
|
||||
_camera camSetFov -(linearConversion [0.01,2,GVAR(camZoom),-2,-0.01,true]);
|
||||
_camera camCommit 0;
|
||||
|
||||
// Agent is switched to in free cam to hide death table and prevent AI chat while allowing icons to draw (also prevents systemChat and unit HUD)
|
||||
// (Why is so much stuff tied into the current camera unit BI?!)
|
||||
if (isNull GVAR(camAgent)) then {
|
||||
GVAR(camAgent) = createAgent ["VirtualMan_F",markerPos QGVAR(respawn),[],0,""];
|
||||
};
|
||||
|
||||
GVAR(camAgent) switchCamera "internal";
|
||||
} else {
|
||||
_camera = GVAR(unitCamera);
|
||||
|
||||
// When null unit is given choose random
|
||||
if (isNull _newUnit) then {
|
||||
_newUnit = selectRandom GVAR(unitList);
|
||||
};
|
||||
|
||||
// Switch camera view to internal unit view (external uses the camera)
|
||||
if (GVAR(camGun)) then {
|
||||
_newUnit switchCamera "gunner";
|
||||
} else {
|
||||
_newUnit switchCamera "internal";
|
||||
};
|
||||
|
||||
// Handle camera differently for internal/external view
|
||||
if (_newMode == 1) then {
|
||||
// Terminate camera view
|
||||
_camera cameraEffect ["terminate", "back"];
|
||||
GVAR(camHandler) = nil;
|
||||
} else {
|
||||
// Switch to the camera
|
||||
_camera cameraEffect ["internal", "back"];
|
||||
};
|
||||
|
||||
GVAR(camUnit) = _newUnit;
|
||||
};
|
||||
|
||||
if (_newMode in [0,2]) then {
|
||||
// Set up camera UI
|
||||
showCinemaBorder false;
|
||||
cameraEffectEnableHUD true;
|
||||
|
||||
// Handle camera movement
|
||||
if (isNil QGVAR(camHandler)) then { GVAR(camHandler) = [FUNC(handleCamera), 0] call CBA_fnc_addPerFrameHandler; };
|
||||
|
||||
// If new vision isn't available then keep current (unless current also isn't)
|
||||
if !(_newVision in GVAR(availableVisions)) then {
|
||||
_newVision = GVAR(availableVisions) select ((GVAR(availableVisions) find GVAR(camVision)) max 0);
|
||||
};
|
||||
|
||||
// Vision mode applies to free and external cam
|
||||
if (_newVision < 0) then {
|
||||
false setCamUseTi 0;
|
||||
camUseNVG (_newVision >= -1);
|
||||
} else {
|
||||
true setCamUseTi _newVision;
|
||||
};
|
||||
GVAR(camVision) = _newVision;
|
||||
};
|
||||
|
||||
GVAR(camMode) = _newMode;
|
146
addons/spectator/functions/fnc_ui.sqf
Normal file
146
addons/spectator/functions/fnc_ui.sqf
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Handles UI initialisation and destruction
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Init/Terminate <BOOL>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [false] call ace_spectator_fnc_ui
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_init"];
|
||||
|
||||
// No change
|
||||
if (_init isEqualTo !isNull SPEC_DISPLAY) exitWith {};
|
||||
|
||||
// Close map
|
||||
openMap [false,false];
|
||||
|
||||
// Close any open dialogs
|
||||
while {dialog} do {
|
||||
closeDialog 0;
|
||||
};
|
||||
|
||||
// Note that init and destroy intentionally happen in reverse order
|
||||
// Init: Vars > Display > UI Stuff
|
||||
// Destroy: UI Stuff > Display > Vars
|
||||
if (_init) then {
|
||||
// UI visibility tracking
|
||||
GVAR(uiVisible) = true;
|
||||
GVAR(uiHelpVisible) = true;
|
||||
GVAR(uiMapVisible) = true;
|
||||
GVAR(uiWidgetVisible) = true;
|
||||
|
||||
// Drawing related
|
||||
GVAR(drawProjectiles) = false;
|
||||
GVAR(drawUnits) = true;
|
||||
GVAR(entitiesToDraw) = [];
|
||||
GVAR(grenadesToDraw) = [];
|
||||
GVAR(iconsToDraw) = [];
|
||||
GVAR(locationsToDraw) = [];
|
||||
GVAR(projectilesToDraw) = [];
|
||||
|
||||
// RMB tracking is used for follow camera mode
|
||||
GVAR(holdingRMB) = false;
|
||||
|
||||
// List type is used for list updates and interaction
|
||||
GVAR(uiListType) = LIST_ENTITIES;
|
||||
|
||||
// Highlighted map object is used for click and drawing events
|
||||
GVAR(uiMapHighlighted) = objNull;
|
||||
|
||||
// Holds the current list data
|
||||
GVAR(curList) = [];
|
||||
|
||||
// Cache view distance and set spectator default
|
||||
GVAR(oldViewDistance) = viewDistance;
|
||||
setViewDistance DEFAULT_VIEW_DISTANCE;
|
||||
|
||||
// If counter already exists handle it, otherwise display XEH will handle it
|
||||
[GETUVAR(RscRespawnCounter,displayNull)] call FUNC(compat_counter);
|
||||
|
||||
// Create the display
|
||||
MAIN_DISPLAY createDisplay QGVAR(display);
|
||||
|
||||
// Store default H value for scaling purposes
|
||||
GVAR(uiHelpH) = (ctrlPosition CTRL_HELP) select 3;
|
||||
|
||||
// Initially hide map
|
||||
[] call FUNC(ui_toggleMap);
|
||||
|
||||
// Initially fade the list
|
||||
[true] call FUNC(ui_fadeList);
|
||||
|
||||
// Initalise the help, widget and list information
|
||||
[] call FUNC(ui_updateCamButtons);
|
||||
[] call FUNC(ui_updateListEntities);
|
||||
[] call FUNC(ui_updateListFocus);
|
||||
[] call FUNC(ui_updateWidget);
|
||||
[] call FUNC(ui_updateHelp);
|
||||
|
||||
// Start updating things to draw
|
||||
GVAR(collectPFH) = [LINKFUNC(ui_updateIconsToDraw), 0.2] call CBA_fnc_addPerFrameHandler;
|
||||
|
||||
// Draw icons and update the cursor object
|
||||
GVAR(uiDraw3D) = addMissionEventHandler ["Draw3D", {call FUNC(ui_draw3D)}];
|
||||
|
||||
// Periodically update list and focus widget
|
||||
GVAR(uiPFH) = [{
|
||||
if (GVAR(uiListType) == LIST_ENTITIES) then {
|
||||
[] call FUNC(ui_updateListEntities);
|
||||
} else {
|
||||
[] call FUNC(ui_updateListLocations);
|
||||
};
|
||||
|
||||
[] call FUNC(ui_updateWidget);
|
||||
}, 5] call CBA_fnc_addPerFrameHandler;
|
||||
} else {
|
||||
// Stop updating the list and focus widget
|
||||
[GVAR(uiPFH)] call CBA_fnc_removePerFrameHandler;
|
||||
|
||||
// Stop drawing icons and tracking cursor object
|
||||
removeMissionEventHandler ["Draw3D", GVAR(uiDraw3D)];
|
||||
GVAR(uiDraw3D) = nil;
|
||||
|
||||
// Stop updating things to draw
|
||||
[GVAR(collectPFH)] call CBA_fnc_removePerFrameHandler;
|
||||
GVAR(collectPFH) = nil;
|
||||
|
||||
// Destroy the display
|
||||
SPEC_DISPLAY closeDisplay 1;
|
||||
|
||||
// Stop tracking everything
|
||||
GVAR(uiVisible) = nil;
|
||||
GVAR(uiHelpVisible) = nil;
|
||||
GVAR(uiMapVisible) = nil;
|
||||
GVAR(uiWidgetVisible) = nil;
|
||||
GVAR(holdingRMB) = nil;
|
||||
GVAR(uiListType) = nil;
|
||||
GVAR(uiMapHighlighted) = nil;
|
||||
GVAR(curList) = nil;
|
||||
GVAR(uiHelpH) = nil;
|
||||
|
||||
// Stop drawing
|
||||
GVAR(drawProjectiles) = nil;
|
||||
GVAR(drawUnits) = nil;
|
||||
GVAR(entitiesToDraw) = nil;
|
||||
GVAR(grenadesToDraw) = nil;
|
||||
GVAR(iconsToDraw) = nil;
|
||||
GVAR(locationsToDraw) = nil;
|
||||
GVAR(projectilesToDraw) = nil;
|
||||
|
||||
// Reset view distance
|
||||
setViewDistance GVAR(oldViewDistance);
|
||||
GVAR(oldViewDistance) = nil;
|
||||
|
||||
// Ensure chat is shown again
|
||||
showChat true;
|
||||
};
|
156
addons/spectator/functions/fnc_ui_draw3D.sqf
Normal file
156
addons/spectator/functions/fnc_ui_draw3D.sqf
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, AACO, SilentSpike
|
||||
* Function used to draw the 3D icons and track the cursor object
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* addMissionEventHandler ["Draw3D", {call ace_spectator_fnc_ui_draw3D}]
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
#define HEIGHT_OFFSET 1.5
|
||||
|
||||
BEGIN_COUNTER(updateCursor);
|
||||
private _camTarget = GVAR(camTarget);
|
||||
private _cursorObject = objNull;
|
||||
|
||||
// This function doesn't work for units underwater, due to use of screenToWorld. Would be complicated to work around this.
|
||||
private _intersections = [getMousePosition select 0, getMousePosition select 1, _camTarget, vehicle _camTarget] call BIS_fnc_getIntersectionsUnderCursor;
|
||||
|
||||
if !(_intersections isEqualTo []) then {
|
||||
_cursorObject = (_intersections select 0) select 3;
|
||||
};
|
||||
|
||||
if !(_cursorObject isKindOf "Man") then {
|
||||
_cursorObject = effectiveCommander _cursorObject;
|
||||
};
|
||||
|
||||
GVAR(cursorObject) = _cursorObject;
|
||||
END_COUNTER(updateCursor);
|
||||
|
||||
if !(GVAR(uiMapVisible)) then {
|
||||
if (GVAR(drawUnits)) then {
|
||||
BEGIN_COUNTER(drawTags);
|
||||
// Groups and Units
|
||||
{
|
||||
_x params ["_unit", "_type", "_icon"];
|
||||
private _position = (_unit modelToWorldVisual (_unit selectionPosition "Head")) vectorAdd [0,0,HEIGHT_OFFSET];
|
||||
|
||||
if (_type == 2 && { _unit distanceSqr GVAR(camera) < DISTANCE_NAMES_SQR } && {_unit in _camTarget || _unit in _cursorObject}) then {
|
||||
drawIcon3D [
|
||||
ICON_BACKGROUND_UNIT,
|
||||
[0, 0, 0, [0.4, 0.8] select (_unit in _camTarget)],
|
||||
_position,
|
||||
5,
|
||||
4,
|
||||
0,
|
||||
"",
|
||||
0,
|
||||
0.035,
|
||||
"PuristaMedium",
|
||||
"center"
|
||||
];
|
||||
};
|
||||
|
||||
// Apply modifiers
|
||||
if (_type == 1 && { time <= GETVAR(_unit,GVAR(highlightTime),0) }) then {
|
||||
_icon set [1, [1,1,1, ((_icon select 1) select 3)]];
|
||||
};
|
||||
_icon set [2, _position];
|
||||
|
||||
// Draw icon
|
||||
drawIcon3D _icon;
|
||||
|
||||
nil // Speed loop
|
||||
} count GVAR(iconsToDraw);
|
||||
|
||||
// Draw locations
|
||||
{
|
||||
_x params ["_pos", "_name", "_texture"];
|
||||
|
||||
if (_pos isEqualType objNull) then {
|
||||
_pos = (_pos modelToWorldVisual (_pos selectionPosition "Head")) vectorAdd [0,0,2*HEIGHT_OFFSET];
|
||||
};
|
||||
|
||||
drawIcon3D [_texture, [1,1,1,0.4], _pos, 0.8, 0.8, 0, _name];
|
||||
|
||||
nil // Speed loop
|
||||
} count (GVAR(locationsToDraw));
|
||||
END_COUNTER(drawTags);
|
||||
};
|
||||
|
||||
// Draw projectiles and grenades paths
|
||||
if (GVAR(drawProjectiles)) then {
|
||||
BEGIN_COUNTER(drawTracers);
|
||||
private _projectilesNew = [];
|
||||
private _grenadesNew = [];
|
||||
|
||||
// Draw projectiles if there are any
|
||||
{
|
||||
_x params [
|
||||
["_projectile", objNull, [objNull]],
|
||||
["_segments", [], [[]]]
|
||||
];
|
||||
|
||||
if !(isNull _projectile) then {
|
||||
// Store new segment
|
||||
private _newestIndex = _segments pushBack [
|
||||
getPosVisual _projectile,
|
||||
(vectorMagnitude velocity _projectile) call {
|
||||
if (_this < 250) exitWith { [0,0,1,1] };
|
||||
if (_this < 500) exitWith { [0,1,0,1] };
|
||||
[1,0,0,1]
|
||||
}
|
||||
];
|
||||
|
||||
// Clamp number of segments to be drawn
|
||||
if (_newestIndex > MAX_PROJECTILE_SEGMENTS) then {
|
||||
_segments deleteAt 0;
|
||||
DEC(_newestIndex);
|
||||
};
|
||||
|
||||
// Store projectiles for next frame
|
||||
_projectilesNew pushBack [_projectile, _segments];
|
||||
|
||||
// Draw all projectile segments
|
||||
private _oldLoc = [];
|
||||
{
|
||||
_x params ["_locNew", "_colorNew"];
|
||||
if !(_oldLoc isEqualTo []) then {
|
||||
drawLine3D [_oldLoc, _locNew, _colorNew];
|
||||
};
|
||||
_oldLoc = _locNew;
|
||||
|
||||
nil // Speed loop
|
||||
} count _segments;
|
||||
};
|
||||
|
||||
nil // Speed loop
|
||||
} count GVAR(projectilesToDraw);
|
||||
GVAR(projectilesToDraw) = _projectilesNew;
|
||||
|
||||
{
|
||||
if !(isNull _x) then {
|
||||
private _grenadeVelocityMagnitude = vectorMagnitude velocity _x;
|
||||
|
||||
// Draw grenade (rotate icon to represent spinning)
|
||||
drawIcon3D [ICON_GRENADE, [1,0,0,1], getPosVisual _x, 0.6, 0.6, if (_grenadeVelocityMagnitude > 0) then { time * 100 * _grenadeVelocityMagnitude } else { 0 }, "", 0, 0.05, "TahomaB"];
|
||||
|
||||
// Store grenade for next frame
|
||||
_grenadesNew pushBack _x;
|
||||
};
|
||||
|
||||
nil // Speed loop
|
||||
} count GVAR(grenadesToDraw);
|
||||
|
||||
GVAR(grenadesToDraw) = _grenadesNew;
|
||||
END_COUNTER(drawTracers);
|
||||
};
|
||||
};
|
47
addons/spectator/functions/fnc_ui_fadeList.sqf
Normal file
47
addons/spectator/functions/fnc_ui_fadeList.sqf
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, AACO
|
||||
* Function used to fade/unfade the entitiy/location list
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Fade the list <BOOL>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [false] call ace_spectator_fnc_ui_fadeList
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_fadeList"];
|
||||
|
||||
if (GVAR(uiVisible)) then {
|
||||
private _list = CTRL_LIST;
|
||||
|
||||
if (_fadeList) then {
|
||||
_list ctrlSetBackgroundColor [0,0,0,0];
|
||||
_list ctrlSetFade 0.8;
|
||||
ctrlSetFocus CTRL_MOUSE;
|
||||
|
||||
// if (GVAR(camMode) == MODE_FREE) then {
|
||||
// GVAR(camera) camCommand "manual on";
|
||||
// };
|
||||
|
||||
showChat true;
|
||||
} else {
|
||||
_list ctrlSetBackgroundColor [0,0,0,0.75];
|
||||
_list ctrlSetFade 0;
|
||||
ctrlSetFocus _list;
|
||||
|
||||
// Disable camera input while using the list
|
||||
// GVAR(camera) camCommand "manual off";
|
||||
|
||||
// List overlaps with chat
|
||||
showChat false;
|
||||
};
|
||||
|
||||
_list ctrlCommit 0.2;
|
||||
};
|
45
addons/spectator/functions/fnc_ui_getTreeDataIndex.sqf
Normal file
45
addons/spectator/functions/fnc_ui_getTreeDataIndex.sqf
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, AACO
|
||||
* Function used to find a tree path of a unit
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Data to search tree for <STRING>
|
||||
*
|
||||
* Return Value:
|
||||
* Tree path to data <ARRAY>
|
||||
*
|
||||
* Example:
|
||||
* [groupID _group] call ace_spectator_fnc_ui_getTreeDataIndex
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params [["_data", "", [""]]];
|
||||
|
||||
scopeName QGVAR(getTreeDataIndex);
|
||||
|
||||
// Make sure data is not empty
|
||||
if (_data != "") then {
|
||||
private _ctrl = CTRL_LIST;
|
||||
|
||||
// This also handles the locations list (_sideIndex = _locationIndex)
|
||||
for "_sideIndex" from 0 to ((_ctrl tvCount []) - 1) do {
|
||||
if (_ctrl tvData [_sideIndex] == _data) then {
|
||||
[_sideIndex] breakOut QGVAR(getTreeDataIndex);
|
||||
};
|
||||
for "_groupIndex" from 0 to ((_ctrl tvCount [_sideIndex]) - 1) do {
|
||||
if (_ctrl tvData [_sideIndex, _groupIndex] == _data) then {
|
||||
[_sideIndex, _groupIndex] breakOut QGVAR(getTreeDataIndex);
|
||||
};
|
||||
for "_unitIndex" from 0 to ((_ctrl tvCount [_sideIndex, _groupIndex]) - 1) do {
|
||||
if (_ctrl tvData [_sideIndex, _groupIndex, _unitIndex] == _data) then {
|
||||
[_sideIndex, _groupIndex, _unitIndex] breakOut QGVAR(getTreeDataIndex);
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
[-1] // return empty path if not found (worst case)
|
28
addons/spectator/functions/fnc_ui_handleChildDestroyed.sqf
Normal file
28
addons/spectator/functions/fnc_ui_handleChildDestroyed.sqf
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Author: Nelson Duarte
|
||||
* Function used to handle child destroyed event
|
||||
* This only matters when abort button is pressed in child escape menu
|
||||
* Will close main display to exit client from mission
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Spectator display <DISPLAY>
|
||||
* 1: Child display <DISPLAY>
|
||||
* 2: Exit code of child <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* _this call ace_spectator_fnc_ui_handleChildDestroyed
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_display","_child","_exitCode"];
|
||||
|
||||
if (_exitCode == 104) then {
|
||||
_display closeDisplay 2;
|
||||
MAIN_DISPLAY closeDisplay 2;
|
||||
};
|
209
addons/spectator/functions/fnc_ui_handleKeyDown.sqf
Normal file
209
addons/spectator/functions/fnc_ui_handleKeyDown.sqf
Normal file
@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, AACO, SilentSpike
|
||||
* Function used to handle key down event
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Spectator display <DISPLAY>
|
||||
* 1: Key DIK code <NUMBER>
|
||||
* 2: State of shift <BOOL>
|
||||
* 3: State of ctrl <BOOL>
|
||||
* 4: State of alt <BOOL>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* _this call ace_spectator_fnc_ui_handleKeyDown
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
#include "\A3\ui_f\hpp\defineDIKCodes.inc"
|
||||
|
||||
params ["","_key","_shift","_ctrl","_alt"];
|
||||
|
||||
// Handle map toggle
|
||||
if (_key == DIK_M) exitWith {
|
||||
[] call FUNC(ui_toggleMap);
|
||||
true
|
||||
};
|
||||
|
||||
// Handle very fast speed
|
||||
if (_key == DIK_LALT) exitWith {
|
||||
[true] call FUNC(cam_toggleSlow);
|
||||
true
|
||||
};
|
||||
|
||||
// Handle escape menu
|
||||
if (_key == DIK_ESCAPE) exitWith {
|
||||
if (GVAR(uiMapVisible)) then {
|
||||
[] call FUNC(ui_toggleMap);
|
||||
} else {
|
||||
if (GVAR(uiForced)) then {
|
||||
private _displayType = ["RscDisplayInterrupt","RscDisplayMPInterrupt"] select isMultiplayer;
|
||||
SPEC_DISPLAY createDisplay _displayType;
|
||||
} else {
|
||||
[false] call FUNC(setSpectator);
|
||||
};
|
||||
};
|
||||
true
|
||||
};
|
||||
|
||||
// Handle perspective cycling
|
||||
if (_key in [DIK_SPACE, DIK_NUMPADENTER]) exitWith {
|
||||
private _oldMode = GVAR(camMode);
|
||||
private _modes = GVAR(availableModes);
|
||||
|
||||
// Get current index and index count
|
||||
private _iMode = (_modes find _oldMode) max 0;
|
||||
private _countModes = count _modes;
|
||||
|
||||
if (_countModes != 0) then {
|
||||
_iMode = (_iMode + 1) % _countModes;
|
||||
if (_iMode < 0) then { _iMode = _countModes + _iMode; };
|
||||
};
|
||||
|
||||
private _newMode = _modes select _iMode;
|
||||
|
||||
[_newMode] call FUNC(cam_setCameraMode);
|
||||
|
||||
true
|
||||
};
|
||||
|
||||
// Handle vision mode cycling
|
||||
if (_key == DIK_N) exitWith {
|
||||
private _oldVision = GVAR(camVision);
|
||||
private _visions = GVAR(availableVisions);
|
||||
|
||||
// Get current index and index count
|
||||
private _iVision = (_visions find _oldVision) max 0;
|
||||
private _countVisions = count _visions;
|
||||
|
||||
if (_countVisions != 0) then {
|
||||
_iVision = (_iVision + 1) % _countVisions;
|
||||
if (_iVision < 0) then { _iVision = _countVisions + _iVision; };
|
||||
};
|
||||
|
||||
private _newVision = _visions select _iVision;
|
||||
|
||||
[_newVision] call FUNC(cam_setVisionMode);
|
||||
true
|
||||
};
|
||||
|
||||
// Handle postive change in draw
|
||||
if (_key == DIK_PGUP) exitWith {
|
||||
setViewDistance ((viewDistance + 250) min MAX_VIEW_DISTANCE);
|
||||
true
|
||||
};
|
||||
|
||||
// Handle negative change in draw
|
||||
if (_key == DIK_PGDN) exitWith {
|
||||
setViewDistance ((viewDistance - 250) max MIN_VIEW_DISTANCE);
|
||||
true
|
||||
};
|
||||
|
||||
// Handle spectate lights
|
||||
if (_key == DIK_L) exitWith {
|
||||
if (GVAR(camLight)) then {
|
||||
{ deleteVehicle _x; } forEach GVAR(camLights);
|
||||
GVAR(camLights) = [];
|
||||
} else {
|
||||
private _cameraLight = "#lightpoint" createvehicleLocal getPosASL GVAR(camera);
|
||||
_cameraLight setLightBrightness 2;
|
||||
_cameraLight setLightAmbient [1,1,1];
|
||||
_cameraLight setLightColor [0,0,0];
|
||||
_cameraLight lightAttachObject [GVAR(camera), [0,0,0]];
|
||||
|
||||
private _pointerLight = "#lightpoint" createvehicleLocal getPosASL GVAR(camera);
|
||||
_pointerLight setLightBrightness 1;
|
||||
_pointerLight setLightAmbient [1,1,1];
|
||||
_pointerLight setLightColor [0,0,0];
|
||||
|
||||
GVAR(camLights) = [_cameraLight, _pointerLight];
|
||||
};
|
||||
|
||||
GVAR(camLight) = !GVAR(camLight);
|
||||
|
||||
true
|
||||
};
|
||||
|
||||
// Handle toggling the UI
|
||||
if (_key == DIK_BACKSPACE) exitWith {
|
||||
[] call FUNC(ui_toggleUI);
|
||||
true
|
||||
};
|
||||
|
||||
// Handle toggling help
|
||||
if (_key == DIK_F1) exitWith {
|
||||
GVAR(uiHelpVisible) = !GVAR(uiHelpVisible);
|
||||
|
||||
[] call FUNC(ui_updateHelp);
|
||||
|
||||
CTRL_HELP ctrlShow GVAR(uiHelpVisible);
|
||||
CTRL_HELP_BACK ctrlShow GVAR(uiHelpVisible);
|
||||
|
||||
true
|
||||
};
|
||||
|
||||
// Handle toggle focus info widget
|
||||
if (_key == DIK_P) exitWith {
|
||||
GVAR(uiWidgetVisible) = !GVAR(uiWidgetVisible);
|
||||
[] call FUNC(ui_updateWidget);
|
||||
true
|
||||
};
|
||||
|
||||
// Handle toggling projectile drawing
|
||||
if (_key == DIK_O) exitWith {
|
||||
GVAR(drawProjectiles) = !GVAR(drawProjectiles);
|
||||
true
|
||||
};
|
||||
|
||||
// Handle toggling unit drawing
|
||||
if (_key == DIK_I) exitWith {
|
||||
GVAR(drawUnits) = !GVAR(drawUnits);
|
||||
true
|
||||
};
|
||||
|
||||
// Handle getting next focus target
|
||||
if (_key == DIK_RIGHT) exitWith {
|
||||
[true] call FUNC(switchFocus);
|
||||
true
|
||||
};
|
||||
|
||||
// Handle getting previous focus target
|
||||
if (_key == DIK_LEFT) exitWith {
|
||||
[false] call FUNC(switchFocus);
|
||||
true
|
||||
};
|
||||
|
||||
// If the zeus key is pressed and unit is curator, open zeus interface
|
||||
if ((_key in (actionKeys "CuratorInterface")) && {!isNull (getAssignedCuratorLogic player)}) exitWith {
|
||||
// Close the UI and disable camera input
|
||||
[false] call FUNC(ui);
|
||||
GVAR(camera) camCommand "manual off";
|
||||
|
||||
// Display XEH handles re-opening
|
||||
openCuratorInterface;
|
||||
|
||||
// Set the curator camera to the spectator camera location
|
||||
[{!isNull curatorCamera},{
|
||||
curatorCamera setPosASL (getPosASL GVAR(camera));
|
||||
curatorCamera setDir (getDirVisual GVAR(camera));
|
||||
|
||||
// Curator tracks its own vision mode
|
||||
[getAssignedCuratorLogic player, 0] call bis_fnc_toggleCuratorVisionMode;
|
||||
}] call CBA_fnc_waitUntilAndExecute;
|
||||
true
|
||||
};
|
||||
|
||||
// Handle acre spectate headset down (if present)
|
||||
if (
|
||||
["acre_sys_radio"] call EFUNC(common,isModLoaded) &&
|
||||
{ [_key, [_shift, _ctrl, _alt]] isEqualTo ((["ACRE2", "HeadSet"] call CBA_fnc_getKeybind) select 5) }
|
||||
) exitWith {
|
||||
[] call acre_sys_core_fnc_toggleHeadset;
|
||||
true
|
||||
};
|
||||
|
||||
false // default to unhandled
|
31
addons/spectator/functions/fnc_ui_handleKeyUp.sqf
Normal file
31
addons/spectator/functions/fnc_ui_handleKeyUp.sqf
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, SilentSpike
|
||||
* Function used to handle key up event
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Spectator display <DISPLAY>
|
||||
* 1: Key DIK code <NUMBER>
|
||||
* 2: State of shift <BOOL>
|
||||
* 3: State of ctrl <BOOL>
|
||||
* 4: State of alt <BOOL>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* _this call ace_spectator_fnc_ui_handleKeyUp
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
#include "\A3\ui_f\hpp\defineDIKCodes.inc"
|
||||
|
||||
params ["","_key","_shift","_ctrl","_alt"];
|
||||
|
||||
if (_key == DIK_LALT) exitWith {
|
||||
[false] call FUNC(cam_toggleSlow);
|
||||
true
|
||||
};
|
||||
|
||||
false
|
110
addons/spectator/functions/fnc_ui_handleListClick.sqf
Normal file
110
addons/spectator/functions/fnc_ui_handleListClick.sqf
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, AACO, SilentSpike
|
||||
* Function used to handle list single/double clicks
|
||||
*
|
||||
* Expected behaviour:
|
||||
* Clicking an entry focuses the camera on it (any camera mode)
|
||||
* Double clicking an entry teleports the free camera nearby and focuses on it
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Double clicked <BOOL>
|
||||
* 1: List Click EH's _this <ARRAY>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [false, _this] call ace_spectator_fnc_ui_handleListClick
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_dblClick","_params"];
|
||||
_params params ["_list","_index"];
|
||||
|
||||
private _handled = false;
|
||||
private _entityList = GVAR(uiListType) == LIST_ENTITIES;
|
||||
private _data = _list tvData _index;
|
||||
|
||||
if (_entityList) then {
|
||||
// List contains unique object variables
|
||||
private _object = missionNamespace getVariable [_data, objNull];
|
||||
|
||||
if !(isNull _object) then {
|
||||
if (_dblClick) then {
|
||||
// Place camera within ~10m of the object and above ground level
|
||||
private _pos = getPosASLVisual _object;
|
||||
GVAR(camera) setPosASL (AGLtoASL (_pos getPos [1 + random 10, random 360]) vectorAdd [0,0,2 + random 10]);
|
||||
|
||||
// Reset the focus
|
||||
[objNull] call FUNC(setFocus);
|
||||
[_object] call FUNC(setFocus);
|
||||
|
||||
_handled = true;
|
||||
} else {
|
||||
if (_object != GVAR(camTarget)) then {
|
||||
[_object] call FUNC(setFocus);
|
||||
|
||||
_handled = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
} else {
|
||||
private _location = [];
|
||||
|
||||
// Try to find the location
|
||||
{
|
||||
if ((_x select 0) == _data) exitWith {
|
||||
// Don't want to accidentally modify the GVAR
|
||||
_location = +_x;
|
||||
};
|
||||
} forEach GVAR(locationsList);
|
||||
|
||||
if !(_location isEqualTo []) then {
|
||||
_location params ["", "_name", "_description", "", "_pos", "_offset"];
|
||||
|
||||
// Use dummy object if location is a position array
|
||||
private _dummy = GVAR(camDummy);
|
||||
if (_pos isEqualType objNull) then {
|
||||
_dummy = _pos;
|
||||
} else {
|
||||
// Use dummy to have camera target the location position
|
||||
detach _dummy;
|
||||
_dummy setPosASL _pos;
|
||||
};
|
||||
|
||||
// If in a unit camera mode then only focus when double click
|
||||
if (GVAR(camMode) == MODE_FREE || {_dblClick && {FREE_MODE in GVAR(availableModes)}}) then {
|
||||
// Reset the focus
|
||||
[objNull] call FUNC(setFocus);
|
||||
[_dummy, true] call FUNC(setFocus);
|
||||
};
|
||||
|
||||
// If double clicked ande mode is now free camera, teleport the camera
|
||||
if (_dblClick && {GVAR(camMode) == MODE_FREE}) then {
|
||||
// If location has unspecified offset place randomly within ~30m above ground level
|
||||
if (_offset isEqualTo [0,0,0]) then {
|
||||
_pos = AGLtoASL (_pos getPos [5 + random 30, random 360]) vectorAdd [0,0,2 + random 28];
|
||||
} else {
|
||||
if (_pos isEqualType objNull) then {
|
||||
_pos = (getPosASL _pos) vectorAdd _offset;
|
||||
} else {
|
||||
_pos = (AGLtoASL _pos) vectorAdd _offset;
|
||||
};
|
||||
};
|
||||
GVAR(camera) setPosASL _pos;
|
||||
|
||||
// Location info text
|
||||
[parseText format [ "<t align='right' size='1.2'><t font='PuristaBold' size='1.6'>""%1""</t><br/>%2</t>", _name, _description], true, nil, 7, 0.7, 0] spawn BIS_fnc_textTiles;
|
||||
};
|
||||
|
||||
_handled = true;
|
||||
};
|
||||
};
|
||||
|
||||
if (_handled) then {
|
||||
playSound "ReadoutClick";
|
||||
};
|
||||
|
||||
_handled
|
40
addons/spectator/functions/fnc_ui_handleMapClick.sqf
Normal file
40
addons/spectator/functions/fnc_ui_handleMapClick.sqf
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, AACO
|
||||
* Function used to handle map mouse click events
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Map control <CONTROL>
|
||||
* 1: Mouse button pressed <NUMBER>
|
||||
* 2: x screen coordinate clicked <BOOL>
|
||||
* 3: y screen coordinate clicked <BOOL>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* _this call ace_spectator_fnc_ui_handleMapClick
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["", "", "_x", "_y"];
|
||||
|
||||
if (isNull GVAR(uiMapHighlighted)) then {
|
||||
// Give user feedback that camera is no longer focused
|
||||
if !(isNull GVAR(camTarget)) then {
|
||||
playSound "ReadoutHideClick1";
|
||||
};
|
||||
|
||||
// Preserve camera height on teleport
|
||||
private _pos = CTRL_MAP ctrlMapScreenToWorld [_x, _y];
|
||||
_pos set [2, (getPosASLVisual GVAR(camera)) select 2];
|
||||
|
||||
GVAR(camera) setPosASL _pos;
|
||||
} else {
|
||||
// Give user feedback that camera is focused on highlighted unit
|
||||
playSound "ReadoutClick";
|
||||
};
|
||||
|
||||
[GVAR(uiMapHighlighted)] call FUNC(setFocus);
|
96
addons/spectator/functions/fnc_ui_handleMapDraw.sqf
Normal file
96
addons/spectator/functions/fnc_ui_handleMapDraw.sqf
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, AACO
|
||||
* Function used to handle map draw
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Map control <CONTROL>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* _this call ace_spectator_fnc_ui_handleMapDraw
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
#define MAP_MIN_ENTITY_DISTANCE 30
|
||||
|
||||
// Moved timer into map controls group, update here
|
||||
CTRL_TIME ctrlSetText (["+", [time / 3600] call BIS_fnc_timeToString] joinString "");
|
||||
|
||||
BEGIN_COUNTER(drawMap);
|
||||
|
||||
params ["_map"];
|
||||
|
||||
// Track nearest unit
|
||||
private _loc = _map ctrlMapScreenToWorld getMousePosition;
|
||||
private _nearestEntity = objNull;
|
||||
private _minDist = 999999;
|
||||
|
||||
// Draw unit icons
|
||||
private _handledVehicles = [];
|
||||
{
|
||||
private _dist = _x distance2D _loc;
|
||||
|
||||
if (_dist < _minDist && { _dist < MAP_MIN_ENTITY_DISTANCE }) then {
|
||||
_minDist = _dist;
|
||||
_nearestEntity = _x;
|
||||
};
|
||||
|
||||
private _vehicle = vehicle _x;
|
||||
if !(_vehicle in _handledVehicles) then {
|
||||
_handledVehicles pushBack _vehicle;
|
||||
|
||||
private _vehicleTexture = [_vehicle] call EFUNC(common,getVehicleIcon);
|
||||
private _sideColor = [side group _vehicle] call BIS_fnc_sideColor;
|
||||
private _text = "";
|
||||
|
||||
if (GVAR(uiMapHighlighted) == _vehicle || {GVAR(uiMapHighlighted) in _vehicle}) then {
|
||||
_text = ([GVAR(uiMapHighlighted)] call EFUNC(common,getName)) select [0, NAME_MAX_CHARACTERS];
|
||||
if !(isPlayer GVAR(uiMapHighlighted)) then { _text = format ["%1: %2", localize "str_player_ai", _text]; };
|
||||
_sideColor = [0.8, 0.8, 0.5, 1];
|
||||
};
|
||||
|
||||
if (NEEDS_REVIVE(_vehicle)) then {
|
||||
_vehicleTexture = ICON_REVIVE;
|
||||
_sideColor = [0.5, 0, 0, 1];
|
||||
};
|
||||
|
||||
if (time <= _vehicle getVariable [QGVAR(highlightTime), 0]) then {
|
||||
_sideColor = [1, 1, 1, 1];
|
||||
};
|
||||
|
||||
_map drawIcon [_vehicleTexture, _sideColor, getPosASLVisual _vehicle, 24, 24, getDirVisual _vehicle, _text, 1, 0.04, "TahomaB", "right"];
|
||||
};
|
||||
nil // Speed loop
|
||||
} count ([] call FUNC(getTargetEntities));
|
||||
|
||||
// Set highlighted unit
|
||||
private _text = if (isNull _nearestEntity) then {
|
||||
""
|
||||
} else {
|
||||
format ["%1 [%2 m]", [_nearestEntity] call EFUNC(common,getName), round (_nearestEntity distance2D GVAR(camera))]
|
||||
};
|
||||
|
||||
GVAR(uiMapHighlighted) = _nearestEntity;
|
||||
CTRL_MAP_FOOTER ctrlSetText _text;
|
||||
|
||||
// Draw camera icon
|
||||
if !(isNil QGVAR(camera)) then {
|
||||
private _cameraPos = getPosASLVisual GVAR(camera);
|
||||
private _cameraDir = getDirVisual GVAR(camera);
|
||||
_map drawIcon [ICON_CAMERA, [0.5, 1, 0.5, 1], _cameraPos, 32, 48, _cameraDir, "", 1, 0.05, "TahomaB", "right"];
|
||||
_map drawArrow [_cameraPos, (_cameraPos getPos [300, _cameraDir]), [0.5, 1, 0.5, 1]];
|
||||
};
|
||||
|
||||
// Draw locations
|
||||
{
|
||||
_x params ["", "_name", "", "_texture", "_pos"];
|
||||
_map drawIcon [_texture, [1,1,1,0.5], _pos, 36, 36, 0, _name, true, 0.04, "TahomaB", "right"];
|
||||
|
||||
nil // Speed loop
|
||||
} count (GVAR(locationsList));
|
||||
|
||||
END_COUNTER(drawMap);
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, AACO, SilentSpike
|
||||
* Function used to handle mouse button double clicks
|
||||
*
|
||||
* Expected behaviour:
|
||||
* Double left click teleports free camera toward the unit, but does not focus
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Control <CONTROL>
|
||||
* 1: Mouse button pressed <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* _this call ace_spectator_fnc_ui_handleMouseButtonDblClick
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["", "_button"];
|
||||
|
||||
if (_button == 0 && {!isNull GVAR(cursorObject)}) then {
|
||||
[GVAR(cursorObject)] call FUNC(cam_prepareTarget);
|
||||
};
|
50
addons/spectator/functions/fnc_ui_handleMouseButtonDown.sqf
Normal file
50
addons/spectator/functions/fnc_ui_handleMouseButtonDown.sqf
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, AACO, SilentSpike
|
||||
* Function used to handle mouse down event
|
||||
*
|
||||
* Expected behaviour:
|
||||
* Left clicking a unit focuses the camera on that unit (in any camera mode)
|
||||
* Left clicking empty space removes the current camera focus in free camera
|
||||
* Right clicking removes the camera lock, but retains the focus in free camera
|
||||
* Right clicking and dragging orbits around the unit in follow camera
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Control <CONTROL>
|
||||
* 1: Mouse button pressed <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* _this call ace_spectator_fnc_ui_handleMouseButtonDown
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["", "_button"];
|
||||
|
||||
// Left click
|
||||
if (_button == 0) exitWith {
|
||||
if (isNull GVAR(cursorObject)) then {
|
||||
if (GVAR(camMode) == MODE_FREE && { !isNull GVAR(camTarget) }) then {
|
||||
playSound "ReadoutHideClick1";
|
||||
[objNull] call FUNC(setFocus);
|
||||
};
|
||||
} else {
|
||||
playSound "ReadoutClick";
|
||||
|
||||
// Focus will be at screen center
|
||||
[GVAR(cursorObject)] call FUNC(setFocus);
|
||||
setMousePosition [0.5, 0.5];
|
||||
};
|
||||
};
|
||||
|
||||
// Right click
|
||||
if (_button == 1) then {
|
||||
if (GVAR(camMode) == MODE_FREE && { !isNull GVAR(camTarget) } && { !isNull (attachedTo GVAR(camDummy)) }) then {
|
||||
[] call FUNC(cam_resetTarget);
|
||||
};
|
||||
GVAR(holdingRMB) = true;
|
||||
};
|
31
addons/spectator/functions/fnc_ui_handleMouseMoving.sqf
Normal file
31
addons/spectator/functions/fnc_ui_handleMouseMoving.sqf
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, AACO
|
||||
* Function used to handle mouse moving event
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Control <CONTROL>
|
||||
* 1: Change in x <NUMBER>
|
||||
* 2: Change in y <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* _this call ace_spectator_fnc_ui_handleMouseMoving
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
if (GVAR(holdingRMB) && { GVAR(camMode) == MODE_FOLLOW }) then {
|
||||
params ["", "_deltaX", "_deltaY"];
|
||||
|
||||
if (_deltaX != 0) then {
|
||||
GVAR(camYaw) = ((GVAR(camYaw) + (_deltaX * 100 * GVAR(camDeltaTime)) + 180) % 360) - 180;
|
||||
};
|
||||
|
||||
if (_deltaY != 0) then {
|
||||
GVAR(camPitch) = (((GVAR(camPitch) - (_deltaY * 100 * GVAR(camDeltaTime))) max -90) min 90);
|
||||
};
|
||||
};
|
27
addons/spectator/functions/fnc_ui_handleMouseZChanged.sqf
Normal file
27
addons/spectator/functions/fnc_ui_handleMouseZChanged.sqf
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, AACO
|
||||
* Function used to handle mouse scroll event
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Control <CONTROL>
|
||||
* 1: Change in Z <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* _this call ace_spectator_fnc_ui_handleMouseZChanged
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
#define FOLLOW_CAMERA_MAX_DISTANCE 5
|
||||
|
||||
if (GVAR(camMode) == MODE_FOLLOW) then {
|
||||
if ((_this select 1) > 0) then {
|
||||
GVAR(camDistance) = (GVAR(camDistance) - 1) max 0;
|
||||
} else {
|
||||
GVAR(camDistance) = (GVAR(camDistance) + 1) min FOLLOW_CAMERA_MAX_DISTANCE;
|
||||
};
|
||||
};
|
37
addons/spectator/functions/fnc_ui_handleTabSelected.sqf
Normal file
37
addons/spectator/functions/fnc_ui_handleTabSelected.sqf
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, SilentSpike
|
||||
* Function used to handle list tab change
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Control <CONTROL>
|
||||
* 1: New tab index <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* _this call ace_spectator_fnc_ui_handleTabSelected
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params ["_ctrl", "_index"];
|
||||
|
||||
// Nothing to do if it's the same tab
|
||||
private _newType = [LIST_ENTITIES, LIST_LOCATIONS] select _index;
|
||||
if (GVAR(uiListType) == _newType) exitWith {};
|
||||
|
||||
// Clear list
|
||||
tvClear CTRL_LIST;
|
||||
|
||||
// Force initial update
|
||||
if (_index == 0) then {
|
||||
[] call FUNC(ui_updateListEntities);
|
||||
} else {
|
||||
[] call FUNC(ui_updateListLocations);
|
||||
};
|
||||
|
||||
// Track current list type
|
||||
GVAR(uiListType) = _newType;
|
46
addons/spectator/functions/fnc_ui_toggleMap.sqf
Normal file
46
addons/spectator/functions/fnc_ui_toggleMap.sqf
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, AACO
|
||||
* Function used to toggle the map
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [] call ace_spectator_fnc_ui_toggleMap
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
if (GVAR(uiMapVisible)) then {
|
||||
CTRL_MAP ctrlShow false;
|
||||
CTRL_MAP_GROUP ctrlShow false;
|
||||
|
||||
ctrlSetFocus CTRL_MOUSE;
|
||||
|
||||
// if (GVAR(camMode) == MODE_FREE) then {
|
||||
// GVAR(camera) camCommand "manual on";
|
||||
// };
|
||||
} else {
|
||||
CTRL_MAP ctrlShow true;
|
||||
CTRL_MAP_GROUP ctrlShow true;
|
||||
|
||||
CTRL_MAP_TITLE ctrlSetText (getMissionConfigValue ["onLoadName", getMissionConfigValue ["briefingName", localize ELSTRING(common,unknown)]]);
|
||||
CTRL_MAP_SPEC_NUM ctrlSetText str ({GETVAR(_x,GVAR(isSet),false)} count allPlayers);
|
||||
|
||||
CTRL_MAP ctrlMapAnimAdd [0, 0.05, getPosASLVisual GVAR(camera)];
|
||||
ctrlMapAnimCommit CTRL_MAP;
|
||||
|
||||
// Disable camera input while map is open
|
||||
// GVAR(camera) camCommand "manual off";
|
||||
};
|
||||
|
||||
// Toggle the tracking variable
|
||||
GVAR(uiMapVisible) = !GVAR(uiMapVisible);
|
||||
|
||||
// Reset highlighted object
|
||||
GVAR(uiMapHighlighted) = objNull;
|
34
addons/spectator/functions/fnc_ui_toggleUI.sqf
Normal file
34
addons/spectator/functions/fnc_ui_toggleUI.sqf
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, AACO, SilentSpike
|
||||
* Function used to toggle the whole user interface
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [] call ace_spectator_fnc_ui_toggleUI
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
private _visible = !GVAR(uiVisible);
|
||||
|
||||
{
|
||||
private _fade = 1;
|
||||
if (_visible) then {
|
||||
_fade = getNumber (configFile >> QGVAR(display) >> "Controls" >> ctrlClassName _x >> "fade");
|
||||
};
|
||||
|
||||
_x ctrlSetFade _fade;
|
||||
_x ctrlCommit 0.25;
|
||||
} forEach [CTRL_LIST, CTRL_TABS, CTRL_CAM_TYPES, CTRL_WIDGET];
|
||||
|
||||
showChat !_visible;
|
||||
playSound (["HintExpand","HintCollapse"] select _visible);
|
||||
|
||||
GVAR(uiVisible) = _visible;
|
38
addons/spectator/functions/fnc_ui_updateCamButtons.sqf
Normal file
38
addons/spectator/functions/fnc_ui_updateCamButtons.sqf
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Used to update the docked camera buttons
|
||||
* Disables unavailable, highlights current
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [] call ace_spectator_fnc_ui_updateCamButtons
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
// These correspond to the camera mode indices
|
||||
#define ENUM_IDCs [IDC_FREE, IDC_FPS, IDC_FOLLOW]
|
||||
#define ENUM_ACTIVE [CAM_ICON_FREE_SELECTED, CAM_ICON_FPS_SELECTED, CAM_ICON_FOLLOW_SELECTED]
|
||||
#define ENUM_INACTIVE [CAM_ICON_FREE, CAM_ICON_FPS, CAM_ICON_FOLLOW]
|
||||
|
||||
private _current = ENUM_IDCs select GVAR(camMode);
|
||||
|
||||
{
|
||||
if (_forEachIndex in GVAR(availableModes)) then {
|
||||
// Highlight the current camera mode button
|
||||
private _icon = ([ENUM_INACTIVE, ENUM_ACTIVE] select (_x == _current)) select _forEachIndex;
|
||||
|
||||
(CTRL_CAM_TYPES controlsGroupCtrl _x) ctrlSetText _icon;
|
||||
(CTRL_CAM_TYPES controlsGroupCtrl _x) ctrlShow true;
|
||||
} else {
|
||||
// Disable any inactive camera modes
|
||||
(CTRL_CAM_TYPES controlsGroupCtrl _x) ctrlShow false;
|
||||
};
|
||||
} forEach ENUM_IDCs;
|
138
addons/spectator/functions/fnc_ui_updateHelp.sqf
Normal file
138
addons/spectator/functions/fnc_ui_updateHelp.sqf
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, SilentSpike
|
||||
* Updates spectator UI help element
|
||||
*
|
||||
* Note that there are some redundant conditions in this file
|
||||
* This is intentional, since controls appear via priority que
|
||||
* The overhead is minimal
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [] call ace_spectator_fnc_ui_updateHelp
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
#include "\A3\ui_f\hpp\defineDIKCodes.inc"
|
||||
#define MAX_CONTROLS_HELP_ENTRIES 12
|
||||
|
||||
if !(GVAR(uiHelpVisible)) exitWith {};
|
||||
|
||||
private _cameraMode = GVAR(camMode);
|
||||
private _availableModes = GVAR(availableModes);
|
||||
private _hasTarget = !isNull GVAR(camTarget);
|
||||
|
||||
private _controls = [];
|
||||
|
||||
// When not in first person, camera rotation applies
|
||||
if (_cameraMode != MODE_FPS) then {
|
||||
_controls pushback ["[RMB]", localize "STR_A3_Spectator_Helper_CameraRotation"];
|
||||
};
|
||||
|
||||
// When in free camera, focus/un-focus with LMB
|
||||
if (_cameraMode == MODE_FREE) then {
|
||||
if (_hasTarget) then {
|
||||
_controls pushBack ["[LMB]", localize "STR_A3_Spectator_Helper_Unfocus"];
|
||||
} else {
|
||||
_controls pushBack ["[LMB]", localize "STR_A3_Spectator_Helper_Focus"];
|
||||
};
|
||||
};
|
||||
|
||||
// When the camera has a focus, switch mode applies (if other modes are available)
|
||||
if (_hasTarget && {!GVAR(camOnLocation)} && {count _availableModes > 1}) then {
|
||||
_controls pushBack [
|
||||
format ["[%1]", toUpper ([DIK_SPACE] call CBA_fnc_localizeKey)],
|
||||
localize "STR_A3_Spectator_Helper_CameraMode"
|
||||
];
|
||||
};
|
||||
|
||||
if (_cameraMode == MODE_FREE) then {
|
||||
_controls pushback [
|
||||
format ["[%1/%2]", [DIK_W] call CBA_fnc_localizeKey, [DIK_S] call CBA_fnc_localizeKey],
|
||||
localize "STR_A3_Spectator_Helper_Movement"
|
||||
];
|
||||
_controls pushback [
|
||||
format ["[%1/%2]", [DIK_A] call CBA_fnc_localizeKey, [DIK_D] call CBA_fnc_localizeKey],
|
||||
localize "STR_A3_Spectator_Helper_Strafing"
|
||||
];
|
||||
_controls pushback [
|
||||
format ["[%1/%2]", [DIK_Q] call CBA_fnc_localizeKey, [DIK_Z] call CBA_fnc_localizeKey],
|
||||
localize "STR_A3_Spectator_Helper_Height"
|
||||
];
|
||||
} else {
|
||||
_controls pushback [
|
||||
format ["[%1]", toUpper ([DIK_RIGHT] call CBA_fnc_localizeKey)],
|
||||
localize LSTRING(nextUnit)
|
||||
];
|
||||
_controls pushback [
|
||||
format ["[%1]", toUpper ([DIK_LEFT] call CBA_fnc_localizeKey)],
|
||||
localize LSTRING(prevUnit)
|
||||
];
|
||||
};
|
||||
|
||||
if (_cameraMode != MODE_FPS) then {
|
||||
_controls pushback [
|
||||
format ["[%1]", ([DIK_N] call CBA_fnc_localizeKey)],
|
||||
localize LSTRING(nextVis)
|
||||
];
|
||||
};
|
||||
|
||||
_controls pushBack [
|
||||
format ["[%1]", toUpper ([DIK_BACK] call CBA_fnc_localizeKey)],
|
||||
localize "STR_A3_Spectator_Helper_Interface"
|
||||
];
|
||||
_controls pushBack [
|
||||
format ["[%1]", [DIK_F1] call CBA_fnc_localizeKey],
|
||||
localize "STR_A3_Spectator_Helper_Controls"
|
||||
];
|
||||
|
||||
// Too many controls in the UI, leave these out?
|
||||
// _controls pushBack [
|
||||
// format ["[%1]", [DIK_M] call CBA_fnc_localizeKey],
|
||||
// localize "str_usract_map"
|
||||
// ];
|
||||
// _controls pushBack [
|
||||
// format ["[%1]", [DIK_I] call CBA_fnc_localizeKey],
|
||||
// localize LSTRING(uiIcons)
|
||||
// ];
|
||||
// _controls pushBack [
|
||||
// format ["[%1]", [DIK_O] call CBA_fnc_localizeKey],
|
||||
// localize LSTRING(uiProjectiles)
|
||||
// ];
|
||||
|
||||
if (_cameraMode == MODE_FREE) then {
|
||||
_controls pushBack ["[LSHIFT]", localize "STR_A3_Spectator_Helper_Shift"];
|
||||
_controls pushBack ["[LALT]", localize LSTRING(camSlow)];
|
||||
};
|
||||
|
||||
if (count _controls > MAX_CONTROLS_HELP_ENTRIES) then {
|
||||
_controls resize MAX_CONTROLS_HELP_ENTRIES;
|
||||
};
|
||||
|
||||
private _help = CTRL_HELP;
|
||||
|
||||
_help ctrlEnable false;
|
||||
_help lnbSetColumnsPos [0, 0.45];
|
||||
lnbClear _help;
|
||||
|
||||
{
|
||||
_help lnbAddRow _x;
|
||||
_help lnbSetColor [[_forEachIndex, 0], [0.75,0.6,0,1]];
|
||||
} forEach _controls;
|
||||
|
||||
// Set height based on number of rows
|
||||
private _newH = (GVAR(uiHelpH) / MAX_CONTROLS_HELP_ENTRIES) * count _controls;
|
||||
private _newY = safezoneY + safezoneH - _newH;
|
||||
|
||||
(ctrlPosition _help) params ["_newX","","_newW"];
|
||||
|
||||
{
|
||||
_x ctrlSetPosition [_newX, _newY, _newW, _newH];
|
||||
_x ctrlCommit 0.15;
|
||||
} forEach [CTRL_HELP_BACK, _help];
|
162
addons/spectator/functions/fnc_ui_updateIconsToDraw.sqf
Normal file
162
addons/spectator/functions/fnc_ui_updateIconsToDraw.sqf
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, AACO, SilentSpike
|
||||
* Function used update the things to 3D draw
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Examples:
|
||||
* [] call ace_spectator_fnc_ui_updateIconsToDraw
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
private _iconsToDraw = [];
|
||||
private _entitiesToDraw = [];
|
||||
|
||||
{
|
||||
private _vehicle = vehicle _x;
|
||||
private _inVehicle = (_vehicle != _x);
|
||||
private _distanceToCameraSqr = GVAR(camera) distanceSqr _x;
|
||||
|
||||
if (_distanceToCameraSqr <= DISTANCE_ICONS_SQR && { !_inVehicle || { _x == effectiveCommander _vehicle } }) then {
|
||||
private _group = group _x;
|
||||
private _groupSide = side _group;
|
||||
private _groupName = groupId _group;
|
||||
private _groupLeader = leader _group;
|
||||
private _groupColor = [_groupSide] call BIS_fnc_sideColor;
|
||||
|
||||
// Calculate distance fade
|
||||
(_distanceToCameraSqr call {
|
||||
if (_this <= 250000) exitWith { // 500^2
|
||||
[1, 4, -2.5, 0.04]
|
||||
};
|
||||
if (_this <= 1000000) exitWith { // 1000^2
|
||||
[0.75, 3.5, -2.2, 0.035]
|
||||
};
|
||||
if (_this <= 2250000) exitWith { // 1500^2
|
||||
[0.5, 3, -1.9, 0.03]
|
||||
};
|
||||
if (_this <= 4000000) exitWith { // 2000^2
|
||||
[0.3, 2.5, -1.6, 0.025]
|
||||
};
|
||||
if (_this <= 6250000) exitWith { // 2500^2
|
||||
[0.2, 2, -1.3, 0.02]
|
||||
};
|
||||
[0.15, 1.5, -1, 0.015]
|
||||
}) params ["_fadeByDistance", "_sizeByDistance", "_heightByDistance", "_fontSizeByDistance"];
|
||||
|
||||
// Apply color fade
|
||||
_groupColor set [3, _fadeByDistance];
|
||||
|
||||
private _name = ([_x] call EFUNC(common,getName)) select [0, NAME_MAX_CHARACTERS];
|
||||
if !(isPlayer _x) then { _name = format ["%1: %2", localize "str_player_ai", _name]; };
|
||||
|
||||
if (_inVehicle) then {
|
||||
private _crewCount = (({alive _x} count (crew _vehicle)) - 1);
|
||||
if (_crewCount > 0) then {
|
||||
_name = format ["%1 (+%2)", _name, _crewCount];
|
||||
};
|
||||
};
|
||||
|
||||
// Show unit name only if camera is near enough
|
||||
if (_distanceToCameraSqr < DISTANCE_NAMES_SQR) then {
|
||||
// Unit name
|
||||
_iconsToDraw pushBack [_x, 2, [
|
||||
"",
|
||||
[1,1,1,1],
|
||||
[0,0,0],
|
||||
0,
|
||||
_heightByDistance,
|
||||
0,
|
||||
_name,
|
||||
2,
|
||||
_fontSizeByDistance,
|
||||
"PuristaMedium",
|
||||
"center"
|
||||
]];
|
||||
} else {
|
||||
if (_x == _groupLeader) then {
|
||||
// Group name
|
||||
_iconsToDraw pushBack [_x, 0, [
|
||||
"",
|
||||
[1,1,1,_fadeByDistance],
|
||||
[0,0,0],
|
||||
0,
|
||||
_heightByDistance,
|
||||
0,
|
||||
_groupName,
|
||||
2,
|
||||
_fontSizeByDistance,
|
||||
"PuristaMedium",
|
||||
"center"
|
||||
]];
|
||||
};
|
||||
};
|
||||
|
||||
if (_x == _groupLeader || { _inVehicle && { _x == effectiveCommander _vehicle } }) then {
|
||||
// Group icon
|
||||
_iconsToDraw pushBack [_x, 0, [
|
||||
[_group, true] call FUNC(getGroupIcon),
|
||||
_groupColor,
|
||||
[0,0,0],
|
||||
_sizeByDistance,
|
||||
_sizeByDistance,
|
||||
0,
|
||||
"",
|
||||
0,
|
||||
0.035,
|
||||
"PuristaMedium",
|
||||
"center"
|
||||
]];
|
||||
};
|
||||
|
||||
// Draw unit icon
|
||||
_iconsToDraw pushBack [_x, 1, [
|
||||
[ICON_UNIT, ICON_REVIVE] select (NEEDS_REVIVE(_x)),
|
||||
_groupColor,
|
||||
[0,0,0],
|
||||
_sizeByDistance,
|
||||
_sizeByDistance,
|
||||
0,
|
||||
"",
|
||||
0,
|
||||
0.035,
|
||||
"PuristaMedium",
|
||||
"center"
|
||||
]];
|
||||
};
|
||||
|
||||
// Track entities themselves for use with fired EH
|
||||
_entitiesToDraw pushBack _vehicle;
|
||||
|
||||
// Add fired EH for drawing and icon highlighting
|
||||
if (GETVAR(_vehicle,GVAR(firedEH),-1) == -1) then {
|
||||
SETVAR(_vehicle,GVAR(firedEH),_vehicle addEventHandler [ARR_2("Fired",{_this call FUNC(handleFired)})]);
|
||||
};
|
||||
|
||||
nil // Speed loop
|
||||
} count ([] call FUNC(getTargetEntities));
|
||||
|
||||
// Remove object locations that are now null
|
||||
{
|
||||
_x params ["_id", "_name", "", "_texture", "_pos"];
|
||||
|
||||
if ((_pos isEqualType objNull) && {isNull _pos}) then {
|
||||
[_id] call FUNC(removeLocation);
|
||||
} else {
|
||||
if ((GVAR(camera) distanceSqr _pos) < DISTANCE_NAMES_SQR) then {
|
||||
GVAR(locationsToDraw) pushBack [_pos, _name, _texture];
|
||||
};
|
||||
};
|
||||
|
||||
nil // Speed loop
|
||||
} count (GVAR(locationsList));
|
||||
|
||||
GVAR(iconsToDraw) = _iconsToDraw;
|
||||
GVAR(entitiesToDraw) = _entitiesToDraw;
|
222
addons/spectator/functions/fnc_ui_updateListEntities.sqf
Normal file
222
addons/spectator/functions/fnc_ui_updateListEntities.sqf
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, AACO, SilentSpike
|
||||
* Updates spectator UI list of units/groups
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [] call ace_spectator_fnc_ui_updateListEntities
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
private _newUnits = [];
|
||||
private _newGroups = [];
|
||||
// Always show the 4 main sides in this intuative order
|
||||
private _newSides = [str west, str east, str resistance, str civilian];
|
||||
private _newList = [
|
||||
[west, str west, [west] call BIS_fnc_sideName, [west] call BIS_fnc_sideColor, []],
|
||||
[east, str east, [east] call BIS_fnc_sideName, [east] call BIS_fnc_sideColor, []],
|
||||
[resistance, str resistance, [resistance] call BIS_fnc_sideName, [resistance] call BIS_fnc_sideColor, []],
|
||||
[civilian, str civilian, [civilian] call BIS_fnc_sideName, [civilian] call BIS_fnc_sideColor, []]
|
||||
];
|
||||
|
||||
// Go through entity groups and cache information (include dead entities)
|
||||
private _entities = [true] call FUNC(getTargetEntities);
|
||||
{
|
||||
// Add the group if new
|
||||
private _group = _x;
|
||||
if !(str _group in _newGroups) then {
|
||||
// Include the group if it contains valid entities
|
||||
private _entitiesGroup = units _group arrayIntersect _entities;
|
||||
|
||||
if !(_entitiesGroup isEqualTo []) then {
|
||||
// Cache the info of valid units in the group
|
||||
private _unitsInfo = [];
|
||||
{
|
||||
_newUnits pushBack ([_x] call BIS_fnc_objectVar);
|
||||
|
||||
private _name = ([_x] call EFUNC(common,getName)) select [0, NAME_MAX_CHARACTERS];
|
||||
if !(isPlayer _x) then { _name = format ["%1: %2", localize "str_player_ai", _name]; };
|
||||
|
||||
_unitsInfo pushBack [
|
||||
_x,
|
||||
alive _x,
|
||||
alive _x && { NEEDS_REVIVE(_x) },
|
||||
_name
|
||||
];
|
||||
nil // Speed loop
|
||||
} count _entitiesGroup;
|
||||
|
||||
// Cache the info of the group itself
|
||||
private _groupTexture = [_group] call FUNC(getGroupIcon);
|
||||
private _groupInfo = [_group, str _group, _groupTexture, groupID _group];
|
||||
|
||||
// Add the group to the correct side
|
||||
private _side = side _group;
|
||||
private _sideIndex = _newSides find (str _side);
|
||||
|
||||
// Add the side if new
|
||||
if (_sideIndex < 0) then {
|
||||
_newList pushBack [
|
||||
_side,
|
||||
str _side,
|
||||
[_side] call BIS_fnc_sideName,
|
||||
[_side] call BIS_fnc_sideColor,
|
||||
[]
|
||||
];
|
||||
|
||||
_sideIndex = _newSides pushBack (str _side);
|
||||
};
|
||||
|
||||
// Add it to the right index
|
||||
_newGroups pushBack (str _group);
|
||||
((_newList select _sideIndex) select 4) pushBack [_groupInfo, _unitsInfo];
|
||||
};
|
||||
};
|
||||
nil // Speed loop
|
||||
} count allGroups;
|
||||
|
||||
// Whether an update to the list is required (really only if something changed)
|
||||
if !(GVAR(curList) isEqualTo _newList) then {
|
||||
private _ctrl = CTRL_LIST;
|
||||
|
||||
// Remove groups/units that are no longer there
|
||||
for "_sideIndex" from ((_ctrl tvCount []) - 1) to 0 step -1 do {
|
||||
for "_groupIndex" from ((_ctrl tvCount [_sideIndex]) - 1) to 0 step -1 do {
|
||||
for "_unitIndex" from ((_ctrl tvCount [_sideIndex, _groupIndex]) - 1) to 0 step -1 do {
|
||||
private _lookup = _newUnits find (_ctrl tvData [_sideIndex, _groupIndex, _unitIndex]);
|
||||
if (_lookup < 0) then {
|
||||
_ctrl tvDelete [_sideIndex, _groupIndex, _unitIndex];
|
||||
} else {
|
||||
_newUnits deleteAt _lookup;
|
||||
};
|
||||
};
|
||||
private _lookup = _newGroups find (_ctrl tvData [_sideIndex, _groupIndex]);
|
||||
if (_lookup < 0) then {
|
||||
_ctrl tvDelete [_sideIndex, _groupIndex];
|
||||
} else {
|
||||
_newGroups deleteAt _lookup;
|
||||
};
|
||||
};
|
||||
private _lookup = _newSides find (_ctrl tvData [_sideIndex]);
|
||||
if (_lookup < 0) then {
|
||||
_ctrl tvDelete [_sideIndex];
|
||||
} else {
|
||||
_newSides deleteAt _lookup;
|
||||
};
|
||||
};
|
||||
|
||||
// Hash location lookups, note hashing assumes unique side/group/unit data
|
||||
private _sideDataToPathHash = [[], []];
|
||||
private _groupDataToPathHash = [[], []];
|
||||
private _unitDataToPathHash = [[], []];
|
||||
|
||||
for "_sideIndex" from 0 to ((_ctrl tvCount []) - 1) do {
|
||||
(_sideDataToPathHash select 0) pushBack (_ctrl tvData [_sideIndex]);
|
||||
(_sideDataToPathHash select 1) pushBack [_sideIndex];
|
||||
for "_groupIndex" from 0 to ((_ctrl tvCount [_sideIndex]) - 1) do {
|
||||
(_groupDataToPathHash select 0) pushBack (_ctrl tvData [_sideIndex, _groupIndex]);
|
||||
(_groupDataToPathHash select 1) pushBack [_sideIndex, _groupIndex];
|
||||
for "_unitIndex" from 0 to ((_ctrl tvCount [_sideIndex, _groupIndex]) - 1) do {
|
||||
(_unitDataToPathHash select 0) pushBack (_ctrl tvData [_sideIndex, _groupIndex, _unitIndex]);
|
||||
(_unitDataToPathHash select 1) pushBack [_sideIndex, _groupIndex, _unitIndex];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// Update/add the values
|
||||
{
|
||||
_x params ["_side", "_sideStr", "_sideTitle", "_sideColor", "_nestedGroupData"];
|
||||
|
||||
private _sideIndex = -1;
|
||||
private _lookup = (_sideDataToPathHash select 0) find _sideStr;
|
||||
if (_lookup < 0) then {
|
||||
_sideIndex = _ctrl tvAdd [[], _sideTitle];
|
||||
_ctrl tvSetData [[_sideIndex], _sideStr];
|
||||
_ctrl tvExpand [_sideIndex];
|
||||
} else {
|
||||
// pop data out of hash to improve later lookups
|
||||
(_sideDataToPathHash select 0) deleteAt _lookup;
|
||||
private _path = (_sideDataToPathHash select 1) deleteAt _lookup;
|
||||
_sideIndex = _path select 0;
|
||||
|
||||
_ctrl tvSetText [_path, _sideTitle];
|
||||
};
|
||||
|
||||
{
|
||||
_x params ["_groupInfo", "_nestedUnitData"];
|
||||
_groupInfo params ["_group", "_groupStr", "_groupTexture", "_groupId"];
|
||||
|
||||
private _groupIndex = -1;
|
||||
private _lookup = (_groupDataToPathHash select 0) find _groupStr;
|
||||
if (_lookup < 0) then {
|
||||
_groupIndex = _ctrl tvAdd [[_sideIndex], _groupId];
|
||||
_ctrl tvSetData [[_sideIndex, _groupIndex], _groupStr];
|
||||
_ctrl tvSetPicture [[_sideIndex, _groupIndex], _groupTexture];
|
||||
_ctrl tvSetPictureColor [[_sideIndex, _groupIndex], _sideColor];
|
||||
_ctrl tvSetTooltip [[_sideIndex, _groupIndex], _groupId];
|
||||
_ctrl tvExpand [_sideIndex, _groupIndex];
|
||||
} else {
|
||||
// pop data out of hash to improve later lookups
|
||||
(_groupDataToPathHash select 0) deleteAt _lookup;
|
||||
private _path = (_groupDataToPathHash select 1) deleteAt _lookup;
|
||||
_groupIndex = _path select 1;
|
||||
|
||||
_ctrl tvSetText [_path, _groupId];
|
||||
_ctrl tvSetPicture [_path, _groupTexture];
|
||||
_ctrl tvSetPictureColor [_path, _sideColor];
|
||||
_ctrl tvSetTooltip [_path, _groupId];
|
||||
};
|
||||
|
||||
{
|
||||
_x params ["_unit", "_isAlive", "_isIncapacitated", "_name"];
|
||||
|
||||
// Show full name in tooltip + whether medic + whether engineer
|
||||
private _tooltip = [[_unit] call EFUNC(common,getName)];
|
||||
if ([_unit] call EFUNC(common,isMedic)) then { _tooltip pushBack (localize "str_support_medic"); };
|
||||
if ([_unit] call EFUNC(common,isEngineer)) then { _tooltip pushBack (localize LSTRING(TooltipEngineer)); };
|
||||
_tooltip = _tooltip joinString " - ";
|
||||
|
||||
private _texture = [_isAlive, _isIncapacitated, _unit] call {
|
||||
params ["","","_unit"];
|
||||
if !(_this select 0) exitWith { ICON_DEAD };
|
||||
if (_this select 1) exitWith { ICON_REVIVE };
|
||||
[vehicle _unit] call EFUNC(common,getVehicleIcon)
|
||||
};
|
||||
|
||||
private _lookup = (_unitDataToPathHash select 0) find ([_unit] call BIS_fnc_objectVar);
|
||||
if (_lookup < 0) then {
|
||||
private _unitIndex = _ctrl tvAdd [[_sideIndex, _groupIndex], _name];
|
||||
_ctrl tvSetData [[_sideIndex, _groupIndex, _unitIndex], [_unit] call BIS_fnc_objectVar];
|
||||
_ctrl tvSetPicture [[_sideIndex, _groupIndex, _unitIndex], _texture];
|
||||
_ctrl tvSetPictureColor [[_sideIndex, _groupIndex, _unitIndex], _sideColor];
|
||||
_ctrl tvSetTooltip [[_sideIndex, _groupIndex, _unitIndex], _tooltip];
|
||||
} else {
|
||||
// pop data out of hash to improve later lookups
|
||||
(_unitDataToPathHash select 0) deleteAt _lookup;
|
||||
private _path = (_unitDataToPathHash select 1) deleteAt _lookup;
|
||||
_ctrl tvSetText [_path, _name];
|
||||
_ctrl tvSetPicture [_path, _texture];
|
||||
_ctrl tvSetPictureColor [_path, _sideColor];
|
||||
_ctrl tvSetTooltip [_path, _tooltip];
|
||||
};
|
||||
nil // Speed loop
|
||||
} count _nestedUnitData;
|
||||
nil // Speed loop
|
||||
} count _nestedGroupData;
|
||||
nil // Speed loop
|
||||
} count _newList;
|
||||
|
||||
// Store the new list as the current list
|
||||
GVAR(curList) = _newList;
|
||||
};
|
||||
|
||||
// Update focus if required
|
||||
[] call FUNC(ui_updateListFocus);
|
22
addons/spectator/functions/fnc_ui_updateListFocus.sqf
Normal file
22
addons/spectator/functions/fnc_ui_updateListFocus.sqf
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, AACO, SilentSpike
|
||||
* Function used to update the list current selection
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [] call ace_spectator_fnc_ui_updateListFocus
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
// Don't update list when in location mode or focus is a location
|
||||
if (!GVAR(camOnLocation) && {GVAR(uiListType) != LIST_LOCATIONS}) then {
|
||||
CTRL_LIST tvSetCurSel ([[GVAR(camTarget)] call BIS_fnc_objectVar] call FUNC(ui_getTreeDataIndex));
|
||||
};
|
69
addons/spectator/functions/fnc_ui_updateListLocations.sqf
Normal file
69
addons/spectator/functions/fnc_ui_updateListLocations.sqf
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, AACO, SilentSpike
|
||||
* Updates spectator UI list of locations
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [] call ace_spectator_fnc_ui_updateListLocations
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
private _newLocations = [];
|
||||
private _newList = GVAR(locationsList);
|
||||
|
||||
// Whether an update to the list is required (really only if something changed)
|
||||
if !(GVAR(curList) isEqualTo _newList) then {
|
||||
private _ctrl = CTRL_LIST;
|
||||
|
||||
// Remove locations that are no longer there
|
||||
for "_locationIndex" from ((_ctrl tvCount []) - 1) to 0 step -1 do {
|
||||
private _lookup = _newLocations find (_ctrl tvData [_locationIndex]);
|
||||
if (_lookup < 0) then {
|
||||
_ctrl tvDelete [_locationIndex];
|
||||
} else {
|
||||
_newLocations deleteAt _lookup;
|
||||
};
|
||||
};
|
||||
|
||||
// Hash location lookups, note hashing assumes unique location data
|
||||
private _locationDataToPathHash = [[], []];
|
||||
|
||||
for "_locationIndex" from 0 to ((_ctrl tvCount []) - 1) do {
|
||||
(_locationDataToPathHash select 0) pushBack (_ctrl tvData [_locationIndex]);
|
||||
(_locationDataToPathHash select 1) pushBack [_locationIndex];
|
||||
};
|
||||
|
||||
{
|
||||
_x params ["_id", "_name", "_description", "_texture"];
|
||||
|
||||
private _lookup = (_locationDataToPathHash select 0) find _id;
|
||||
if (_lookup < 0) then {
|
||||
private _locationIndex = _ctrl tvAdd [[], _name];
|
||||
_ctrl tvSetData [[_locationIndex], _id];
|
||||
_ctrl tvSetPicture [[_locationIndex], _texture];
|
||||
_ctrl tvSetPictureColor [[_locationIndex], [1,1,1,1]];
|
||||
_ctrl tvSetTooltip [[_locationIndex], _description];
|
||||
} else {
|
||||
// pop data out of hash to improve later lookups
|
||||
(_locationDataToPathHash select 0) deleteAt _lookup;
|
||||
private _path = (_locationDataToPathHash select 1) deleteAt _lookup;
|
||||
|
||||
_ctrl tvSetText [_path, _name];
|
||||
_ctrl tvSetPicture [_path, _texture];
|
||||
_ctrl tvSetPictureColor [_path, [1,1,1,1]];
|
||||
_ctrl tvSetTooltip [_path, _description];
|
||||
};
|
||||
|
||||
nil // Speed loop
|
||||
} count _newList;
|
||||
|
||||
GVAR(curList) = _newList;
|
||||
};
|
70
addons/spectator/functions/fnc_ui_updateWidget.sqf
Normal file
70
addons/spectator/functions/fnc_ui_updateWidget.sqf
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Author: Nelson Duarte, SilentSpike
|
||||
* Updates spectator UI unit info widget
|
||||
*
|
||||
* Arguments:
|
||||
* None
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Example:
|
||||
* [] call ace_spectator_fnc_ui_updateWidget
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
#define IMG_COMMANDER "a3\Ui_f\data\IGUI\Cfg\CommandBar\imageCommander_ca.paa"
|
||||
#define IMG_DRIVER "a3\Ui_f\data\IGUI\Cfg\CommandBar\imageDriver_ca.paa"
|
||||
#define IMG_GUNNER "a3\Ui_f\data\IGUI\Cfg\CommandBar\imageGunner_ca.paa"
|
||||
#define IMG_CARGO "a3\Ui_f\data\IGUI\Cfg\CommandBar\imageCommander_ca.paa"
|
||||
|
||||
// Hide if no target, or target is a location or widget is toggled off
|
||||
if (!GVAR(uiWidgetVisible) || {GVAR(camOnLocation)} || {isNull GVAR(camTarget)}) exitWith {CTRL_WIDGET ctrlShow false};
|
||||
|
||||
private _focus = GVAR(camTarget);
|
||||
|
||||
private _name = ([_focus] call EFUNC(common,getName)) select [0, NAME_MAX_CHARACTERS];
|
||||
if !(isPlayer _focus) then { _name = format ["%1: %2", localize "str_player_ai", _name]; };
|
||||
|
||||
private _unitTypePicture = [_focus] call EFUNC(common,getVehicleIcon);
|
||||
private _vehicleTypePicture = getText (configFile >> "CfgVehicles" >> typeOf vehicle _focus >> "Picture");
|
||||
private _insigniaTexture = ["GetGroupTexture", [group _focus]] call BIS_fnc_dynamicGroups;
|
||||
|
||||
private _weapon = currentWeapon _focus;
|
||||
private _weaponPicture = if (_weapon != "") then {
|
||||
getText (configFile >> "CfgWeapons" >> _weapon >> "Picture");
|
||||
} else {
|
||||
if (_focus != vehicle _focus) then {
|
||||
if (commander vehicle _focus == _focus) exitWith {IMG_COMMANDER};
|
||||
if (driver vehicle _focus == _focus) exitWith {IMG_DRIVER};
|
||||
if (gunner vehicle _focus == _focus) exitWith {IMG_GUNNER};
|
||||
IMG_CARGO
|
||||
} else {""};
|
||||
};
|
||||
|
||||
(getPlayerScores _focus) params [["_kills",0,[0]], ["_softKills",0,[0]], ["_armoredKills",0,[0]], ["_airKills",0,[0]], ["_deaths",0,[0]], ["_total",0,[0]]];
|
||||
|
||||
CTRL_WIDGET_NAME ctrlSetText _name;
|
||||
CTRL_WIDGET_AVATAR ctrlSetText _insigniaTexture;
|
||||
CTRL_WIDGET_KILLS ctrlSetText str _kills;
|
||||
CTRL_WIDGET_LAND ctrlSetText str _softKills;
|
||||
CTRL_WIDGET_ARMORED ctrlSetText str _armoredKills;
|
||||
CTRL_WIDGET_AIR ctrlSetText str _airKills;
|
||||
CTRL_WIDGET_DEATHS ctrlSetText str _deaths;
|
||||
CTRL_WIDGET_TOTAL ctrlSetText str _total;
|
||||
CTRL_WIDGET_WEAPON ctrlSetText _weaponPicture;
|
||||
|
||||
CTRL_WIDGET_UNIT ctrlSetText (["",_unitTypePicture] select (vehicle _focus == _focus));
|
||||
CTRL_WIDGET_UNIT ctrlShow (vehicle _focus == _focus);
|
||||
CTRL_WIDGET_VEHICLE ctrlSetText (["",_vehicleTypePicture] select (vehicle _focus != _focus));
|
||||
CTRL_WIDGET_VEHICLE ctrlShow (vehicle _focus != _focus);
|
||||
|
||||
CTRL_WIDGET_WEAPON ctrlShow (_weaponPicture != "");
|
||||
CTRL_WIDGET_WEAPON_BACK ctrlShow (_weaponPicture != "");
|
||||
|
||||
// Handle widget toggling
|
||||
if !(ctrlShown CTRL_WIDGET) then {
|
||||
CTRL_WIDGET ctrlShow true;
|
||||
};
|
@ -3,8 +3,10 @@
|
||||
* Adds or removes spectator camera modes from the selection available to the local player.
|
||||
* Possible camera modes are:
|
||||
* - 0: Free
|
||||
* - 1: Internal
|
||||
* - 2: External
|
||||
* - 1: First person
|
||||
* - 2: Follow
|
||||
*
|
||||
* Default selection is [0,1,2]
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Camera modes to add <ARRAY>
|
||||
@ -31,7 +33,7 @@ private ["_newModes","_currentModes"];
|
||||
_currentModes = GVAR(availableModes);
|
||||
|
||||
// Restrict additions to only possible values
|
||||
_newModes = _addModes arrayIntersect [0,1,2];
|
||||
_newModes = _addModes arrayIntersect ALL_MODES;
|
||||
_newModes append (_currentModes - _removeModes);
|
||||
|
||||
_newModes = _newModes arrayIntersect _newModes;
|
||||
@ -39,14 +41,19 @@ _newModes sort true;
|
||||
|
||||
// Can't become an empty array
|
||||
if (_newModes isEqualTo []) then {
|
||||
["Cannot remove all camera modes (%1)", QFUNC(updateCameraModes)] call BIS_fnc_error;
|
||||
WARNING("Cannot remove all spectator camera modes");
|
||||
} else {
|
||||
GVAR(availableModes) = _newModes;
|
||||
};
|
||||
|
||||
// Update camera in case of change
|
||||
if (GVAR(isSet)) then {
|
||||
[] call FUNC(transitionCamera);
|
||||
if !(isNil QGVAR(camera)) then {
|
||||
// If mode was free and no longer available, find a focus
|
||||
if (!(MODE_FREE in _newModes) && {GVAR(camMode) == MODE_FREE} && {isNull GVAR(camTarget) || GVAR(camOnLocation)}) then {
|
||||
[true] call FUNC(setFocus);
|
||||
};
|
||||
|
||||
[GVAR(camMode)] call FUNC(cam_setCameraMode);
|
||||
};
|
||||
|
||||
_newModes
|
||||
|
@ -1,7 +1,6 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Adds or removes sides from the selection available to spectate by the local player.
|
||||
* Note that the side filter setting is applied to the available sides dynamically.
|
||||
* Adds or removes sides from the selection available to spectate. Local effect.
|
||||
*
|
||||
* Default selection is [west,east,resistance,civilian]
|
||||
*
|
||||
@ -10,10 +9,10 @@
|
||||
* 1: Sides to remove <ARRAY>
|
||||
*
|
||||
* Return Value:
|
||||
* Spectatable sides <ARRAY>
|
||||
* Sides available <ARRAY>
|
||||
*
|
||||
* Example:
|
||||
* [[west], [east,civilian]] call ace_spectator_fnc_updateSpectatableSides
|
||||
* [[west], [east,civilian]] call ace_spectator_fnc_updateSides
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
@ -1,69 +1,40 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Adds units to spectator whitelist/blacklist and refreshes the filter units
|
||||
* Adds and removed units from the spectator list. Local effect.
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Units to add to the whitelist <ARRAY>
|
||||
* 1: Use blacklist <BOOL> (default: false)
|
||||
* 0: Units to show in the list <ARRAY>
|
||||
* 1: Units to hide in the list <ARRAY>
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
*
|
||||
* Example:
|
||||
* [allUnits,true] call ace_spectator_fnc_updateUnits
|
||||
* [allPlayers, [player]] call ace_spectator_fnc_updateUnits
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params [["_newUnits",[],[[]]],["_blacklist",false,[false]]];
|
||||
|
||||
// Function only matters on player clients
|
||||
if (!hasInterface) exitWith {};
|
||||
|
||||
// If adding to a list we can exit here, since it won't show up until the UI refreshes anyway
|
||||
if !(_newUnits isEqualTo []) exitWith {
|
||||
if (_blacklist) then {
|
||||
GVAR(unitWhitelist) = GVAR(unitWhitelist) - _newUnits;
|
||||
GVAR(unitBlacklist) append _newUnits;
|
||||
} else {
|
||||
GVAR(unitBlacklist) = GVAR(unitBlacklist) - _newUnits;
|
||||
GVAR(unitWhitelist) append _newUnits;
|
||||
params [["_addUnits",[],[[]]], ["_removeUnits",[],[[], true]]];
|
||||
|
||||
// Deprecated parameter (remember to remove bool from params when removed)
|
||||
if (_removeUnits isEqualType true) then {
|
||||
ACE_DEPRECATED("Boolean parameter","3.12.0","array (see function header or doc)");
|
||||
if (_removeUnits) then {
|
||||
_removeUnits = _addUnits;
|
||||
_addUnits = [];
|
||||
};
|
||||
};
|
||||
|
||||
// Unit setting filter
|
||||
private _newUnits = [[],allPlayers,playableUnits,allUnits] select GVAR(filterUnits);
|
||||
// Add to the whitelist and prevent list overlap
|
||||
GVAR(unitBlacklist) = GVAR(unitBlacklist) - _addUnits;
|
||||
GVAR(unitWhitelist) append _addUnits;
|
||||
|
||||
// Side setting filter
|
||||
private _sideFilter = [
|
||||
{_x == (side group player)},
|
||||
{(_x getFriend (side group player)) >= 0.6},
|
||||
{(_x getFriend (side group player)) < 0.6},
|
||||
{true}
|
||||
] select GVAR(filterSides);
|
||||
|
||||
private _filteredSides = GVAR(availableSides) select _sideFilter;
|
||||
|
||||
// Filter units and append to list
|
||||
private _filteredUnits = (_newUnits - GVAR(unitBlacklist)) select {
|
||||
(alive _x) &&
|
||||
{(_x isKindOf "CAManBase")} &&
|
||||
{(side group _x) in _filteredSides} && // Side filter
|
||||
{simulationEnabled _x} &&
|
||||
{!(_x getVariable [QGVAR(isStaged), false])} // Who watches the watchmen?
|
||||
};
|
||||
_filteredUnits append GVAR(unitWhitelist);
|
||||
|
||||
// Cache icons and colour for drawing
|
||||
private _filteredGroups = [];
|
||||
{
|
||||
// Intentionally re-applied to units in case their status changes
|
||||
[_x] call FUNC(cacheUnitInfo);
|
||||
_filteredGroups pushBackUnique (group _x);
|
||||
} forEach _filteredUnits;
|
||||
|
||||
// Replace previous lists entirely (removes any no longer valid)
|
||||
GVAR(groupList) = _filteredGroups;
|
||||
GVAR(unitList) = _filteredUnits arrayIntersect _filteredUnits;
|
||||
// Blacklist overrides the whitelist
|
||||
GVAR(unitWhitelist) = GVAR(unitWhitelist) - _removeUnits;
|
||||
GVAR(unitBlacklist) append _removeUnits;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Adds or removes spectator vision modes from the selection available to the local player.
|
||||
* The default selection is [-2,-1,0,1].
|
||||
*
|
||||
* Possible vision modes are:
|
||||
* - -2: Normal
|
||||
* - -1: Night vision
|
||||
@ -14,6 +14,8 @@
|
||||
* - 6: White Hot / Darker Red Cold
|
||||
* - 7: Thermal (Shade of Red and Green, Bodies are white)
|
||||
*
|
||||
* Default selection is [-2,-1,0,1]
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Vision modes to add <ARRAY>
|
||||
* 1: Vision modes to remove <ARRAY>
|
||||
@ -47,14 +49,14 @@ _newModes sort true;
|
||||
|
||||
// Can't become an empty array
|
||||
if (_newModes isEqualTo []) then {
|
||||
["Cannot remove all vision modes (%1)", QFUNC(updateVisionModes)] call BIS_fnc_error;
|
||||
WARNING("Cannot remove all spectator vision modes");
|
||||
} else {
|
||||
GVAR(availableVisions) = _newModes;
|
||||
};
|
||||
|
||||
// Update camera in case of change
|
||||
if (GVAR(isSet)) then {
|
||||
[] call FUNC(transitionCamera);
|
||||
if !(isNil QGVAR(camera)) then {
|
||||
[GVAR(camVision)] call FUNC(cam_setVisionMode);
|
||||
};
|
||||
|
||||
_newModes
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user