mirror of
https://github.com/acemod/ACE3.git
synced 2024-08-30 18:23:18 +00:00
commit
e3cda8ee0e
1
addons/spectator/$PBOPREFIX$
Normal file
1
addons/spectator/$PBOPREFIX$
Normal file
@ -0,0 +1 @@
|
||||
z\ace\addons\spectator
|
22
addons/spectator/ACE_Settings.hpp
Normal file
22
addons/spectator/ACE_Settings.hpp
Normal file
@ -0,0 +1,22 @@
|
||||
class ACE_Settings {
|
||||
class GVAR(filterUnits) {
|
||||
typeName = "SCALAR";
|
||||
value = 2;
|
||||
values[] = {CSTRING(units_none), CSTRING(units_players), CSTRING(units_playable), CSTRING(units_all)};
|
||||
};
|
||||
class GVAR(filterSides) {
|
||||
typeName = "SCALAR";
|
||||
value = 0;
|
||||
values[] = {CSTRING(sides_player), CSTRING(sides_friendly), CSTRING(sides_hostile), CSTRING(sides_all)};
|
||||
};
|
||||
class GVAR(restrictModes) {
|
||||
typeName = "SCALAR";
|
||||
value = 0;
|
||||
values[] = {CSTRING(modes_all), CSTRING(modes_unit), CSTRING(modes_free), CSTRING(modes_internal), CSTRING(modes_external)};
|
||||
};
|
||||
class GVAR(restrictVisions) {
|
||||
typeName = "SCALAR";
|
||||
value = 0;
|
||||
values[] = {CSTRING(modes_all), CSTRING(visions_nv), CSTRING(visions_ti), "$STR_Special_None"};
|
||||
};
|
||||
};
|
11
addons/spectator/CfgEventHandlers.hpp
Normal file
11
addons/spectator/CfgEventHandlers.hpp
Normal file
@ -0,0 +1,11 @@
|
||||
class Extended_PreInit_EventHandlers {
|
||||
class ADDON {
|
||||
init = QUOTE(call COMPILE_FILE(XEH_preInit));
|
||||
};
|
||||
};
|
||||
|
||||
class Extended_PostInit_EventHandlers {
|
||||
class ADDON {
|
||||
init = QUOTE(call COMPILE_FILE(XEH_postInit));
|
||||
};
|
||||
};
|
117
addons/spectator/CfgVehicles.hpp
Normal file
117
addons/spectator/CfgVehicles.hpp
Normal file
@ -0,0 +1,117 @@
|
||||
class CfgVehicles {
|
||||
class ACE_Module;
|
||||
class GVAR(moduleSettings): ACE_Module {
|
||||
scope = 2;
|
||||
displayName = CSTRING(Settings_DisplayName);
|
||||
icon = PATHTOF(UI\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 cameraModes {
|
||||
displayName = CSTRING(modes_DisplayName);
|
||||
description = CSTRING(modes_Description);
|
||||
typeName = "NUMBER";
|
||||
class values {
|
||||
class all {
|
||||
name = CSTRING(modes_all);
|
||||
value = 0;
|
||||
default = 1;
|
||||
};
|
||||
class unit {
|
||||
name = CSTRING(modes_unit);
|
||||
value = 1;
|
||||
};
|
||||
class free {
|
||||
name = CSTRING(modes_free);
|
||||
value = 2;
|
||||
};
|
||||
class internal {
|
||||
name = CSTRING(modes_internal);
|
||||
value = 3;
|
||||
};
|
||||
class external {
|
||||
name = CSTRING(modes_external);
|
||||
value = 4;
|
||||
};
|
||||
};
|
||||
};
|
||||
class visionModes {
|
||||
displayName = CSTRING(visions_DisplayName);
|
||||
description = CSTRING(visions_Description);
|
||||
typeName = "NUMBER";
|
||||
class values {
|
||||
class all {
|
||||
name = CSTRING(modes_all);
|
||||
value = 0;
|
||||
default = 1;
|
||||
};
|
||||
class nv {
|
||||
name = CSTRING(visions_nv);
|
||||
value = 1;
|
||||
};
|
||||
class ti {
|
||||
name = CSTRING(visions_ti);
|
||||
value = 2;
|
||||
};
|
||||
class none {
|
||||
name = "$STR_Special_None";
|
||||
value = 3;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
class ModuleDescription {
|
||||
description = CSTRING(Settings_Description);
|
||||
};
|
||||
};
|
||||
};
|
14
addons/spectator/README.md
Normal file
14
addons/spectator/README.md
Normal file
@ -0,0 +1,14 @@
|
||||
ace_spectator
|
||||
=======
|
||||
|
||||
A flexible spectator framework for mission makers to use.
|
||||
|
||||
Includes a public API for integration into custom respawn frameworks and a template for use with the vanilla respawn framework.
|
||||
|
||||
For more information, see: http://ace3mod.com/wiki/feature/spectator.html
|
||||
|
||||
## Maintainers
|
||||
|
||||
The people responsible for merging changes to this component or answering potential questions.
|
||||
|
||||
- [SilentSpike](https://github.com/SilentSpike)
|
BIN
addons/spectator/UI/Icon_Module_Spectator_ca.paa
Normal file
BIN
addons/spectator/UI/Icon_Module_Spectator_ca.paa
Normal file
Binary file not shown.
255
addons/spectator/UI/interface.hpp
Normal file
255
addons/spectator/UI/interface.hpp
Normal file
@ -0,0 +1,255 @@
|
||||
// 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;
|
||||
onTreeDblClick = QUOTE([ARR_2('onTreeDblClick',_this)] call FUNC(handleInterface));
|
||||
onTreeSelChanged = QUOTE([ARR_2('onTreeSelChanged',_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));
|
||||
};
|
||||
};
|
||||
};
|
10
addons/spectator/XEH_postInit.sqf
Normal file
10
addons/spectator/XEH_postInit.sqf
Normal file
@ -0,0 +1,10 @@
|
||||
#include "script_component.hpp"
|
||||
//#include "initKeybinds.sqf";
|
||||
|
||||
// Add interaction menu exception
|
||||
["isNotSpectating", {!(GETVAR((_this select 0),GVAR(isStaged),false))}] call EFUNC(common,addCanInteractWithCondition);
|
||||
|
||||
["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 EFUNC(common,addEventHandler);
|
59
addons/spectator/XEH_preInit.sqf
Normal file
59
addons/spectator/XEH_preInit.sqf
Normal file
@ -0,0 +1,59 @@
|
||||
#include "script_component.hpp"
|
||||
|
||||
ADDON = false;
|
||||
|
||||
PREP(cacheUnitInfo);
|
||||
PREP(cycleCamera);
|
||||
PREP(handleCamera);
|
||||
PREP(handleCompass);
|
||||
PREP(handleIcons);
|
||||
PREP(handleInterface);
|
||||
PREP(handleMap);
|
||||
PREP(handleMouse);
|
||||
PREP(handleToolbar);
|
||||
PREP(handleUnits);
|
||||
PREP(interrupt);
|
||||
PREP(moduleSpectatorSettings);
|
||||
PREP(respawnTemplate);
|
||||
PREP(setCameraAttributes);
|
||||
PREP(setSpectator);
|
||||
PREP(stageSpectator);
|
||||
PREP(transitionCamera);
|
||||
PREP(toggleInterface);
|
||||
PREP(updateCameraModes);
|
||||
PREP(updateSpectatableSides);
|
||||
PREP(updateUnits);
|
||||
PREP(updateVisionModes);
|
||||
|
||||
// Permanent variables
|
||||
GVAR(availableModes) = [0,1,2];
|
||||
GVAR(availableSides) = [west,east,resistance,civilian];
|
||||
GVAR(availableVisions) = [-2,-1,0,1];
|
||||
|
||||
GVAR(camAgent) = objNull;
|
||||
GVAR(camMode) = 0;
|
||||
GVAR(camPan) = 0;
|
||||
GVAR(camPos) = ATLtoASL [worldSize * 0.5, worldSize * 0.5, 20];
|
||||
GVAR(camSpeed) = 2.5;
|
||||
GVAR(camTilt) = -10;
|
||||
GVAR(camUnit) = objNull;
|
||||
GVAR(camVision) = -2;
|
||||
GVAR(camZoom) = 1.25;
|
||||
|
||||
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(unitBlacklist) = [];
|
||||
GVAR(unitWhitelist) = [];
|
||||
GVAR(groupList) = [];
|
||||
|
||||
ADDON = true;
|
25
addons/spectator/config.cpp
Normal file
25
addons/spectator/config.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include "script_component.hpp"
|
||||
|
||||
class CfgPatches {
|
||||
class ADDON {
|
||||
units[] = {};
|
||||
weapons[] = {};
|
||||
requiredVersion = REQUIRED_VERSION;
|
||||
requiredAddons[] = {"ace_common"};
|
||||
author[] = {"F3 Project","Head","SilentSpike","voiper"};
|
||||
authorUrl = "https://github.com/acemod";
|
||||
VERSION_CONFIG;
|
||||
};
|
||||
};
|
||||
|
||||
#include "ACE_Settings.hpp"
|
||||
#include "CfgEventHandlers.hpp"
|
||||
#include "CfgVehicles.hpp"
|
||||
#include "ui\interface.hpp"
|
||||
|
||||
class CfgRespawnTemplates {
|
||||
class ADDON {
|
||||
onPlayerKilled = QFUNC(respawnTemplate);
|
||||
onPlayerRespawn = QFUNC(respawnTemplate);
|
||||
};
|
||||
};
|
38
addons/spectator/functions/fnc_cacheUnitInfo.sqf
Normal file
38
addons/spectator/functions/fnc_cacheUnitInfo.sqf
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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);
|
58
addons/spectator/functions/fnc_cycleCamera.sqf
Normal file
58
addons/spectator/functions/fnc_cycleCamera.sqf
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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);
|
48
addons/spectator/functions/fnc_handleCamera.sqf
Normal file
48
addons/spectator/functions/fnc_handleCamera.sqf
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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","_oldPos","_altMod","_zoomMod","_mX","_mY","_mZ","_pan","_x","_y","_z"];
|
||||
|
||||
_camera = GVAR(camera);
|
||||
_oldPos = getPosASL _camera;
|
||||
|
||||
// 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;
|
||||
|
||||
_pan = (GVAR(camPan) + 360) % 360;
|
||||
_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 GVAR(camPan);
|
||||
[_camera, GVAR(camTilt), 0] call BIS_fnc_setPitchBank;
|
67
addons/spectator/functions/fnc_handleCompass.sqf
Normal file
67
addons/spectator/functions/fnc_handleCompass.sqf
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 = if (_heading < 90) then {
|
||||
[_SW, _WN, _NE, _ES]
|
||||
} else {
|
||||
if (_heading < 180) then {
|
||||
[_WN, _NE, _ES, _SW]
|
||||
} else {
|
||||
if (_heading < 270) then {
|
||||
[_NE, _ES, _SW, _WN]
|
||||
} else {
|
||||
[_ES, _SW, _WN, _NE]
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
{
|
||||
_x ctrlSetPosition (_positions select _forEachIndex);
|
||||
_x ctrlCommit 0;
|
||||
} forEach _sequence;
|
46
addons/spectator/functions/fnc_handleIcons.sqf
Normal file
46
addons/spectator/functions/fnc_handleIcons.sqf
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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(camera),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 [0,0,30], 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\map\markers\military\dot_CA.paa", _color, _x modelToWorldVisual [0,0,3], 0.7, 0.7, 0, _txt, 1, 0.02];
|
||||
false
|
||||
} count (_drawVehicles arrayIntersect GVAR(unitList));
|
493
addons/spectator/functions/fnc_handleInterface.sqf
Normal file
493
addons/spectator/functions/fnc_handleInterface.sqf
Normal file
@ -0,0 +1,493 @@
|
||||
/*
|
||||
* 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"];
|
||||
|
||||
// Always show interface and hide map upon opening
|
||||
[_display,nil,nil,!GVAR(showInterface),GVAR(showMap)] call FUNC(toggleInterface);
|
||||
|
||||
// Keep unit list and tree up to date
|
||||
[FUNC(handleUnits), 21, _display] call CBA_fnc_addPerFrameHandler;
|
||||
|
||||
// Handle 3D unit icons
|
||||
GVAR(iconHandler) = addMissionEventHandler ["Draw3D",FUNC(handleIcons)];
|
||||
|
||||
// Populate the help window
|
||||
private "_help";
|
||||
_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),"1"],
|
||||
[localize LSTRING(uiToggleHelp),"2"],
|
||||
[localize LSTRING(uiToggleTools),"3"],
|
||||
[localize LSTRING(uiToggleCompass),"4"],
|
||||
[localize LSTRING(uiToggleIcons),"5"],
|
||||
[localize LSTRING(uiToggleMap),"M"],
|
||||
[localize LSTRING(uiToggleInterface),"Backspace"],
|
||||
[localize LSTRING(freeCamControls),""],
|
||||
[localize LSTRING(freeCamForward),"W"],
|
||||
[localize LSTRING(freeCamBackward),"S"],
|
||||
[localize LSTRING(freeCamLeft),"A"],
|
||||
[localize LSTRING(freeCamRight),"D"],
|
||||
[localize LSTRING(freeCamUp),"Q"],
|
||||
[localize LSTRING(freeCamDown),"Z"],
|
||||
[localize LSTRING(freeCamPan),"RMB (Hold)"],
|
||||
[localize LSTRING(freeCamDolly),"LMB (Hold)"],
|
||||
[localize LSTRING(freeCamBoost),"Shift (Hold)"],
|
||||
[localize LSTRING(freeCamFocus),"F"],
|
||||
[localize LSTRING(attributeControls),""],
|
||||
[localize LSTRING(nextCam),"Up Arrow"],
|
||||
[localize LSTRING(prevCam),"Down Arrow"],
|
||||
[localize LSTRING(nextUnit),"Right Arrow"],
|
||||
[localize LSTRING(prevUnit),"Left Arrow"],
|
||||
[localize LSTRING(nextVis),"N"],
|
||||
[localize LSTRING(prevVis),"Ctrl + N"],
|
||||
[localize LSTRING(adjZoom),"Scrollwheel"],
|
||||
[localize LSTRING(adjSpeed),"Ctrl + Scrollwheel"],
|
||||
[localize LSTRING(incZoom),"Num-/Num+"],
|
||||
[localize LSTRING(incSpeed),"Ctrl + Num-/Num+"],
|
||||
[localize LSTRING(reZoom),"Alt + Num-"],
|
||||
[localize LSTRING(reSpeed),"Alt + Num+"]
|
||||
];
|
||||
|
||||
// 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 EFUNC(common,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];
|
||||
GVAR(treeSel) = objNull;
|
||||
};
|
||||
// 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 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);
|
||||
};
|
||||
};
|
||||
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 ((isServer || {serverCommandAvailable "#kick"}) && {_dik in (actionKeys "Chat" + actionKeys "PrevChannel" + actionKeys "NextChannel")}) exitWith {
|
||||
false
|
||||
};
|
||||
|
||||
// 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 33: { // F
|
||||
private ["_sel","_vector"];
|
||||
_sel = GVAR(treeSel);
|
||||
if ((GVAR(camMode) == 0) && {!isNull _sel} && {_sel in GVAR(unitList)}) then {
|
||||
_vector = (positionCameraToWorld [0,0,0]) vectorDiff (positionCameraToWorld [0,0,25]);
|
||||
[nil,nil,nil,(getPosATL _sel) vectorAdd _vector] call FUNC(setCameraAttributes);
|
||||
};
|
||||
};
|
||||
case 44: { // Z
|
||||
GVAR(camBoom) = -0.5 * GVAR(camSpeed) * ([1, 2] select _shift);
|
||||
};
|
||||
case 49: { // N
|
||||
if (GVAR(camMode) == 0) 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
|
||||
// Freecam attachment here, if in external then set cam pos and attach
|
||||
};
|
||||
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, 2.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 "ontreeselchanged": {
|
||||
_args params ["_tree","_sel"];
|
||||
|
||||
if (count _sel == 3) then {
|
||||
GVAR(treeSel) = objectFromNetId (_tree tvData _sel);
|
||||
} else {
|
||||
GVAR(treeSel) = objNull;
|
||||
};
|
||||
};
|
||||
case "onunitsupdate": {
|
||||
_args params ["_tree"];
|
||||
private ["_cachedUnits","_cachedGrps","_cachedSides","_s","_g","_grp","_u","_unit","_side"];
|
||||
|
||||
// Cache existing group and side nodes and cull removed data
|
||||
_cachedUnits = [];
|
||||
_cachedGrps = [];
|
||||
_cachedSides = [];
|
||||
for "_s" from 0 to ((_tree tvCount []) - 1) do {
|
||||
for "_g" from 0 to ((_tree tvCount [_s]) - 1) do {
|
||||
_grp = groupFromNetID (_tree tvData [_s,_g]);
|
||||
|
||||
if (_grp in GVAR(groupList)) then {
|
||||
_cachedGrps pushBack _grp;
|
||||
_cachedGrps pushBack _g;
|
||||
|
||||
for "_u" from 0 to ((_tree tvCount [_s,_g])) do {
|
||||
_unit = objectFromNetId (_tree tvData [_s,_g,_u]);
|
||||
|
||||
if (_unit in GVAR(unitList)) then {
|
||||
_cachedUnits pushBack _unit;
|
||||
} else {
|
||||
_tree tvDelete [_s,_g,_u];
|
||||
};
|
||||
};
|
||||
} else {
|
||||
_tree tvDelete [_s,_g];
|
||||
};
|
||||
};
|
||||
|
||||
if ((_tree tvCount [_s]) > 0) then {
|
||||
_cachedSides pushBack (_tree tvText [_s]);
|
||||
_cachedSides pushBack _s;
|
||||
} else {
|
||||
_tree tvDelete [_s];
|
||||
};
|
||||
};
|
||||
|
||||
// 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": {
|
||||
private "_dlg";
|
||||
|
||||
createDialog (["RscDisplayInterrupt", "RscDisplayMPInterrupt"] select isMultiplayer);
|
||||
|
||||
disableSerialization;
|
||||
_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 (findDisplay 49)) exitWith {};
|
||||
|
||||
// If still a spectator then re-enter the interface
|
||||
[QGVAR(escape),false] call FUNC(interrupt);
|
||||
|
||||
[_this select 1] call CBA_fnc_removePerFrameHandler;
|
||||
},0] 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 EFUNC(common,waitAndExecute);
|
||||
|
||||
true
|
||||
};
|
||||
};
|
47
addons/spectator/functions/fnc_handleMap.sqf
Normal file
47
addons/spectator/functions/fnc_handleMap.sqf
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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 ["_cachedVehicles","_unit","_color","_icon","_txt"];
|
||||
|
||||
if (GVAR(camMode) == 0) then {
|
||||
_map drawIcon ["\A3\UI_F\Data\GUI\Rsc\RscDisplayMissionEditor\iconcamera_ca.paa",[0,0,0,1],GVAR(camera),20,20,GVAR(camPan)];
|
||||
};
|
||||
|
||||
_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.03];
|
||||
};
|
||||
false
|
||||
} count GVAR(unitList);
|
46
addons/spectator/functions/fnc_handleMouse.sqf
Normal file
46
addons/spectator/functions/fnc_handleMouse.sqf
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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];
|
54
addons/spectator/functions/fnc_handleToolbar.sqf
Normal file
54
addons/spectator/functions/fnc_handleToolbar.sqf
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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(camMode) == 0) then {
|
||||
_vision = if (GVAR(camVision) >= 0) then {localize LSTRING(VisionThermal)} else { [localize LSTRING(VisionNight), localize LSTRING(VisionNormal)] select (GVAR(camVision) < -1) };
|
||||
_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;
|
40
addons/spectator/functions/fnc_handleUnits.sqf
Normal file
40
addons/spectator/functions/fnc_handleUnits.sqf
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 EFUNC(common,waitAndExecute);
|
||||
};
|
44
addons/spectator/functions/fnc_interrupt.sqf
Normal file
44
addons/spectator/functions/fnc_interrupt.sqf
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Interrupts the spectator interface for external systems
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Reason <STRING>
|
||||
* 1: Interrupting <BOOL>
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
*
|
||||
* Example:
|
||||
* ["mySystem"] call ace_spectator_fnc_interrupt
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
#include "script_component.hpp"
|
||||
|
||||
params [["_reason", "", [""]], ["_interrupt", true, [true]]];
|
||||
|
||||
// Nothing to do when spectator is closed
|
||||
if !(GVAR(isSet)) exitWith {};
|
||||
|
||||
if (_reason == "") exitWith { ERROR("Invalid Reason"); };
|
||||
if (_interrupt) then {
|
||||
GVAR(interrupts) pushBack _reason;
|
||||
} else {
|
||||
GVAR(interrupts) = GVAR(interrupts) - [_reason];
|
||||
};
|
||||
|
||||
if (GVAR(interrupts) isEqualTo []) then {
|
||||
if (isNull (findDisplay 12249)) then {
|
||||
createDialog QGVAR(interface);
|
||||
[] call FUNC(transitionCamera);
|
||||
};
|
||||
} else {
|
||||
if !(isNull (findDisplay 12249)) then {
|
||||
while {dialog} do {
|
||||
closeDialog 0;
|
||||
};
|
||||
|
||||
(findDisplay 12249) closeDisplay 0;
|
||||
};
|
||||
};
|
25
addons/spectator/functions/fnc_moduleSpectatorSettings.sqf
Normal file
25
addons/spectator/functions/fnc_moduleSpectatorSettings.sqf
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Read spectator settings from module
|
||||
*
|
||||
* Arguments:
|
||||
* 0: The module logic <LOGIC>
|
||||
* 1: units <ARRAY>
|
||||
* 2: activated <BOOL>
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
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(restrictModes), "cameraModes"] call EFUNC(common,readSettingFromModule);
|
||||
[_logic, QGVAR(restrictVisions), "visionModes"] call EFUNC(common,readSettingFromModule);
|
44
addons/spectator/functions/fnc_respawnTemplate.sqf
Normal file
44
addons/spectator/functions/fnc_respawnTemplate.sqf
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* The ace_spectator respawn template, handles killed + respawn
|
||||
* Can be used via BI's respawn framework, see:
|
||||
* https://community.bistudio.com/wiki/Arma_3_Respawn
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Corpse/New Unit <OBJECT>
|
||||
* 1: Killer/Old Unit <OBJECT>
|
||||
* 2: Respawn Type <NUMBER>
|
||||
* 3: Respawn Delay <NUMBER>
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
*
|
||||
* Public: No
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params [["_unit",objNull,[objNull]], ["_killer",objNull,[objNull]], ["_respawn",0,[0]], ["_respawnDelay",0,[0]]];
|
||||
private ["_vision","_pos"];
|
||||
|
||||
// End mission when all are dead with respawn type "None"
|
||||
if ((_respawn == 0) && {{alive _x} count allPlayers <= 0}) exitWith {
|
||||
[["endDeath",false],"BIS_fnc_endMission"] call EFUNC(common,execRemoteFnc);
|
||||
};
|
||||
|
||||
if (isNull _killer) then {_killer = _unit};
|
||||
_vision = [-2,-1] select (sunOrMoon < 1);
|
||||
_pos = (getPosATL _unit) vectorAdd [0,0,5];
|
||||
|
||||
if (alive _unit) then {
|
||||
if (_respawn == 1) then {
|
||||
[_unit,QGVAR(isSeagull)] call EFUNC(common,hideUnit);
|
||||
[2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes);
|
||||
[true] call FUNC(setSpectator);
|
||||
} else {
|
||||
[false] call FUNC(setSpectator);
|
||||
};
|
||||
} else {
|
||||
[2,_killer,_vision,_pos,getDir _unit] call FUNC(setCameraAttributes);
|
||||
[true] call FUNC(setSpectator);
|
||||
};
|
67
addons/spectator/functions/fnc_setCameraAttributes.sqf
Normal file
67
addons/spectator/functions/fnc_setCameraAttributes.sqf
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Sets the spectator camera attributes as desired
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Camera mode <NUMBER> <OPTIONAL>
|
||||
* - 0: Free
|
||||
* - 1: Internal
|
||||
* - 2: External
|
||||
* 1: Camera unit (objNull for random) <OBJECT> <OPTIONAL>
|
||||
* 2: Camera vision <NUMBER> <OPTIONAL>
|
||||
* - -2: Normal
|
||||
* - -1: Night vision
|
||||
* - 0: Thermal white hot
|
||||
* - 1: Thermal black hot
|
||||
* 3: Camera position (ATL) <ARRAY> <OPTIONAL>
|
||||
* 4: Camera pan (0 - 360) <NUMBER> <OPTIONAL>
|
||||
* 5: Camera tilt (-90 - 90) <NUMBER> <OPTIONAL>
|
||||
* 6: Camera zoom (0.01 - 2) <NUMBER> <OPTIONAL>
|
||||
* 7: Camera speed in m/s (0.05 - 10) <NUMBER> <OPTIONAL>
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
*
|
||||
* Example:
|
||||
* [1, objNull] call ace_spectator_fnc_setCameraAttributes
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
#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]]
|
||||
];
|
||||
|
||||
// Normalize input
|
||||
if !(_mode in GVAR(availableModes)) then {
|
||||
_mode = GVAR(availableModes) select ((GVAR(availableModes) find GVAR(camMode)) max 0);
|
||||
};
|
||||
|
||||
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 (isNil QGVAR(camera)) then {
|
||||
GVAR(camMode) = _mode;
|
||||
GVAR(camPos) = (ATLtoASL _position);
|
||||
} else {
|
||||
[_mode,_unit,_vision] call FUNC(transitionCamera);
|
||||
GVAR(camera) setPosATL _position;
|
||||
};
|
126
addons/spectator/functions/fnc_setSpectator.sqf
Normal file
126
addons/spectator/functions/fnc_setSpectator.sqf
Normal file
@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Sets local client to the given spectator state (virtually)
|
||||
* To physically handle a spectator see ace_spectator_fnc_stageSpectator
|
||||
*
|
||||
* Client will be able to communicate in ACRE/TFAR as appropriate
|
||||
* The spectator interface will be opened/closed
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Spectator state of local client <BOOL> <OPTIONAL>
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
*
|
||||
* Example:
|
||||
* [true] call ace_spectator_fnc_setSpectator
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params [["_set",true,[true]]];
|
||||
|
||||
// Only clients can be spectators
|
||||
if !(hasInterface) exitWith {};
|
||||
|
||||
// Exit if no change
|
||||
if (_set isEqualTo GVAR(isSet)) exitwith {};
|
||||
|
||||
// Handle common addon audio
|
||||
if (["ace_hearing"] call EFUNC(common,isModLoaded)) then {EGVAR(hearing,disableVolumeUpdate) = _set};
|
||||
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 display variables
|
||||
GVAR(ctrlKey) = false;
|
||||
GVAR(heldKeys) = [];
|
||||
GVAR(heldKeys) resize 255;
|
||||
GVAR(mouse) = [false,false];
|
||||
GVAR(mousePos) = [0.5,0.5];
|
||||
GVAR(treeSel) = objNull;
|
||||
|
||||
// Update units before opening to support pre-set camera unit
|
||||
[] call FUNC(updateUnits);
|
||||
|
||||
// Initalize the camera view
|
||||
GVAR(camera) = "Camera" camCreate (ASLtoATL GVAR(camPos));
|
||||
[] call FUNC(transitionCamera);
|
||||
|
||||
// Close map and clear radio
|
||||
openMap [false,false];
|
||||
clearRadio;
|
||||
|
||||
// Disable BI damage effects
|
||||
BIS_fnc_feedback_allowPP = false;
|
||||
|
||||
// Close any open dialogs
|
||||
while {dialog} do {
|
||||
closeDialog 0;
|
||||
};
|
||||
|
||||
// Create the display
|
||||
(findDisplay 46) createDisplay QGVAR(interface);
|
||||
|
||||
// Cache and disable nametag settings
|
||||
if (["ace_nametags"] call EFUNC(common,isModLoaded)) then {
|
||||
GVAR(nametagSettingCache) = [EGVAR(nametags,showPlayerNames), EGVAR(nametags,showNamesForAI)];
|
||||
EGVAR(nametags,showPlayerNames) = 0;
|
||||
EGVAR(nametags,showNamesForAI) = false;
|
||||
};
|
||||
} else {
|
||||
// Close any open dialogs (could be interrupts)
|
||||
while {dialog} do {
|
||||
closeDialog 0;
|
||||
};
|
||||
|
||||
// Kill the display
|
||||
(findDisplay 12249) closeDisplay 0;
|
||||
|
||||
// Terminate camera
|
||||
GVAR(camera) cameraEffect ["terminate", "back"];
|
||||
camDestroy GVAR(camera);
|
||||
|
||||
clearRadio;
|
||||
|
||||
// Return to player view
|
||||
player switchCamera "internal";
|
||||
|
||||
// Enable BI damage effects
|
||||
BIS_fnc_feedback_allowPP = true;
|
||||
|
||||
// Cleanup camera variables
|
||||
GVAR(camera) = nil;
|
||||
GVAR(camBoom) = nil;
|
||||
GVAR(camDolly) = nil;
|
||||
GVAR(camGun) = nil;
|
||||
|
||||
// Cleanup display variables
|
||||
GVAR(ctrlKey) = nil;
|
||||
GVAR(heldKeys) = nil;
|
||||
GVAR(mouse) = nil;
|
||||
GVAR(mousePos) = nil;
|
||||
GVAR(treeSel) = nil;
|
||||
|
||||
// Reset nametag settings
|
||||
if (["ace_nametags"] call EFUNC(common,isModLoaded)) then {
|
||||
EGVAR(nametags,showPlayerNames) = GVAR(nametagSettingCache) select 0;
|
||||
EGVAR(nametags,showNamesForAI) = GVAR(nametagSettingCache) select 1;
|
||||
GVAR(nametagSettingCache) = nil;
|
||||
};
|
||||
};
|
||||
|
||||
// Reset interruptions
|
||||
GVAR(interrupts) = [];
|
||||
|
||||
// Mark spectator state for reference
|
||||
GVAR(isSet) = _set;
|
||||
|
||||
["spectatorSet",[_set]] call EFUNC(common,localEvent);
|
68
addons/spectator/functions/fnc_stageSpectator.sqf
Normal file
68
addons/spectator/functions/fnc_stageSpectator.sqf
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Sets target unit to the given spectator state (physically)
|
||||
* To virtually handle a spectator see ace_spectator_fnc_setSpectator
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Unit to put into spectator stage <OBJECT> <OPTIONAL>
|
||||
* 1: Spectator stage <BOOL> <OPTIONAL>
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
*
|
||||
* Example:
|
||||
* [player, false] call ace_spectator_fnc_stageSpectator
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params [["_unit",player,[objNull]], ["_set",true,[true]]];
|
||||
|
||||
// No change, no service (but allow spectators to be reset)
|
||||
if !(_set || (GETVAR(_unit,GVAR(isStaged),false))) exitWith {};
|
||||
|
||||
if !(local _unit) exitwith {
|
||||
[[_unit, _set], QFUNC(stageSpectator), _unit] call EFUNC(common,execRemoteFnc);
|
||||
};
|
||||
|
||||
// Prevent unit falling into water
|
||||
_unit enableSimulation !_set;
|
||||
|
||||
// Move to/from group as appropriate
|
||||
[_unit, _set, QGVAR(isStaged), side group _unit] call EFUNC(common,switchToGroupSide);
|
||||
|
||||
if (_set) then {
|
||||
// Position should only be saved on first entry
|
||||
if !(GETVAR(_unit,GVAR(isStaged),false)) then {
|
||||
GVAR(oldPos) = getPosATL _unit;
|
||||
};
|
||||
|
||||
// Ghosts can't talk
|
||||
[_unit, QGVAR(isStaged)] call EFUNC(common,hideUnit);
|
||||
[_unit, QGVAR(isStaged)] call EFUNC(common,muteUnit);
|
||||
|
||||
_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);
|
||||
};
|
||||
|
||||
// Spectators ignore damage (vanilla and ace_medical)
|
||||
_unit allowDamage !_set;
|
||||
_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];
|
||||
|
||||
["spectatorStaged",[_set]] call EFUNC(common,localEvent);
|
||||
};
|
82
addons/spectator/functions/fnc_toggleInterface.sqf
Normal file
82
addons/spectator/functions/fnc_toggleInterface.sqf
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Correctly handles toggling of spectator interface elements for clean UX
|
||||
*
|
||||
* Arguments:
|
||||
* 0: 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:
|
||||
* [_dsiplay, 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(camera)] 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;
|
||||
};
|
111
addons/spectator/functions/fnc_transitionCamera.sqf
Normal file
111
addons/spectator/functions/fnc_transitionCamera.sqf
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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;
|
||||
};
|
||||
|
||||
if (_newMode == 0) then { // Free
|
||||
// Preserve camUnit value for consistency when manually changing view
|
||||
GVAR(camera) cameraEffect ["internal", "back"];
|
||||
showCinemaBorder false;
|
||||
cameraEffectEnableHUD true;
|
||||
|
||||
// Apply the camera zoom
|
||||
GVAR(camera) camSetFov -(linearConversion [0.01,2,GVAR(camZoom),-2,-0.01,true]);
|
||||
GVAR(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";
|
||||
clearRadio;
|
||||
|
||||
// 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 only applies to free cam
|
||||
if (_newVision < 0) then {
|
||||
false setCamUseTi 0;
|
||||
camUseNVG (_newVision >= -1);
|
||||
} else {
|
||||
true setCamUseTi _newVision;
|
||||
};
|
||||
GVAR(camVision) = _newVision;
|
||||
|
||||
// Handle camera movement
|
||||
if (isNil QGVAR(camHandler)) then { GVAR(camHandler) = [FUNC(handleCamera), 0] call CBA_fnc_addPerFrameHandler; };
|
||||
} else {
|
||||
// When null unit is given choose random
|
||||
if (isNull _newUnit) then {
|
||||
_newUnit = GVAR(unitList) select floor(random(count GVAR(unitList)));
|
||||
};
|
||||
|
||||
if (_newMode == 1) then { // Internal
|
||||
// Handle gun cam
|
||||
if (GVAR(camGun)) then {
|
||||
_newUnit switchCamera "gunner";
|
||||
} else {
|
||||
_newUnit switchCamera "internal";
|
||||
};
|
||||
} else { // External
|
||||
_newUnit switchCamera "external";
|
||||
};
|
||||
|
||||
// Clear radio if group changed
|
||||
if (group _newUnit != group GVAR(camUnit)) then {
|
||||
clearRadio;
|
||||
};
|
||||
|
||||
GVAR(camUnit) = _newUnit;
|
||||
|
||||
// Terminate camera view
|
||||
GVAR(camera) cameraEffect ["terminate", "back"];
|
||||
GVAR(camHandler) = nil;
|
||||
cameraEffectEnableHUD true;
|
||||
};
|
||||
|
||||
GVAR(camMode) = _newMode;
|
48
addons/spectator/functions/fnc_updateCameraModes.sqf
Normal file
48
addons/spectator/functions/fnc_updateCameraModes.sqf
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Adds or removes spectator camera modes from the selection available to the local player.
|
||||
* Possible camera modes are:
|
||||
* - 0: Free
|
||||
* - 1: Internal
|
||||
* - 2: External
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Camera modes to add <ARRAY>
|
||||
* 1: Camera modes to remove <ARRAY>
|
||||
*
|
||||
* Return Value:
|
||||
* Available camera modes <ARRAY>
|
||||
*
|
||||
* Example:
|
||||
* [[0], [1,2]] call ace_spectator_fnc_updateCameraModes
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params [["_addModes",[],[[]]], ["_removeModes",[],[[]]]];
|
||||
private ["_newModes","_currentModes"];
|
||||
|
||||
_currentModes = GVAR(availableModes);
|
||||
|
||||
// Restrict additions to only possible values
|
||||
_newModes = _addModes arrayIntersect [0,1,2];
|
||||
_newModes append (_currentModes - _removeModes);
|
||||
|
||||
_newModes = _newModes arrayIntersect _newModes;
|
||||
_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;
|
||||
} else {
|
||||
GVAR(availableModes) = _newModes;
|
||||
};
|
||||
|
||||
// Update camera in case of change
|
||||
if !(isNil QGVAR(camera)) then {
|
||||
[] call FUNC(transitionCamera);
|
||||
};
|
||||
|
||||
_newModes
|
33
addons/spectator/functions/fnc_updateSpectatableSides.sqf
Normal file
33
addons/spectator/functions/fnc_updateSpectatableSides.sqf
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Default selection is [west,east,resistance,civilian]
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Sides to add <ARRAY>
|
||||
* 1: Sides to remove <ARRAY>
|
||||
*
|
||||
* Return Value:
|
||||
* Spectatable sides <ARRAY>
|
||||
*
|
||||
* Example:
|
||||
* [[west], [east,civilian]] call ace_spectator_fnc_updateSpectatableSides
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params [["_addSides",[],[[]]], ["_removeSides",[],[[]]]];
|
||||
|
||||
// Add and remove sides
|
||||
_addSides append (GVAR(availableSides) - _removeSides);
|
||||
|
||||
// Only need array of unique sides
|
||||
_addSides = _addSides arrayIntersect _addSides;
|
||||
|
||||
GVAR(availableSides) = _addSides;
|
||||
|
||||
_addSides
|
75
addons/spectator/functions/fnc_updateUnits.sqf
Normal file
75
addons/spectator/functions/fnc_updateUnits.sqf
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Author: SilentSpike
|
||||
* Adds units to spectator whitelist/blacklist and refreshes the filter units
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Units to add to the whitelist <ARRAY>
|
||||
* 1: Use blacklist <BOOL> <OPTIONAL>
|
||||
*
|
||||
* Return Value:
|
||||
* None <NIL>
|
||||
*
|
||||
* Example:
|
||||
* [allUnits,true] 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;
|
||||
};
|
||||
};
|
||||
|
||||
private ["_sides","_cond","_filteredUnits","_filteredGroups"];
|
||||
|
||||
// Unit setting filter
|
||||
_newUnits = [[],allPlayers,playableUnits,allUnits] select GVAR(filterUnits);
|
||||
|
||||
// Side setting filter
|
||||
_sides = [];
|
||||
_cond = [{_this == (side group player)},{(_this getFriend (side group player)) >= 0.6},{(_this getFriend (side group player)) < 0.6},{true}] select GVAR(filterSides);
|
||||
{
|
||||
if (_x call _cond) then {
|
||||
_sides pushBack _x;
|
||||
};
|
||||
} forEach GVAR(availableSides);
|
||||
|
||||
// Filter units and append to list
|
||||
_filteredUnits = [];
|
||||
{
|
||||
if (
|
||||
(alive _x) &&
|
||||
{(_x isKindOf "CAManBase")} &&
|
||||
{(side group _x) in _sides} && // Side filter
|
||||
{simulationEnabled _x} &&
|
||||
{!(_x getVariable [QGVAR(isStaged), false])} // Who watches the watchmen?
|
||||
) then {
|
||||
_filteredUnits pushBack _x;
|
||||
};
|
||||
} forEach (_newUnits - GVAR(unitBlacklist));
|
||||
_filteredUnits append GVAR(unitWhitelist);
|
||||
|
||||
// Cache icons and colour for drawing
|
||||
_filteredGroups = [];
|
||||
{
|
||||
// Intentionally re-applied to units in case their status changes
|
||||
[_x] call FUNC(cacheUnitInfo);
|
||||
_filteredGroups pushBack (group _x);
|
||||
} forEach _filteredUnits;
|
||||
|
||||
// Replace previous lists entirely (removes any no longer valid)
|
||||
GVAR(unitList) = _filteredUnits arrayIntersect _filteredUnits;
|
||||
GVAR(groupList) = _filteredGroups arrayIntersect _filteredGroups;
|
56
addons/spectator/functions/fnc_updateVisionModes.sqf
Normal file
56
addons/spectator/functions/fnc_updateVisionModes.sqf
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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
|
||||
* - 0: White hot
|
||||
* - 1: Black hot
|
||||
* - 2: Light Green Hot / Darker Green cold
|
||||
* - 3: Black Hot / Darker Green cold
|
||||
* - 4: Light Red Hot / Darker Red Cold
|
||||
* - 5: Black Hot / Darker Red Cold
|
||||
* - 6: White Hot / Darker Red Cold
|
||||
* - 7: Thermal (Shade of Red and Green, Bodies are white)
|
||||
*
|
||||
* Arguments:
|
||||
* 0: Vision modes to add <ARRAY>
|
||||
* 1: Vision modes to remove <ARRAY>
|
||||
*
|
||||
* Return Value:
|
||||
* Available vision modes <ARRAY>
|
||||
*
|
||||
* Example:
|
||||
* [[0], [1,2]] call ace_spectator_fnc_updateVisionModes
|
||||
*
|
||||
* Public: Yes
|
||||
*/
|
||||
|
||||
#include "script_component.hpp"
|
||||
|
||||
params [["_addModes",[],[[]]], ["_removeModes",[],[[]]]];
|
||||
private ["_newModes","_currentModes"];
|
||||
|
||||
_currentModes = GVAR(availableVisions);
|
||||
|
||||
// Restrict additions to only possible values
|
||||
_newModes = _addModes arrayIntersect [-2,-1,0,1,2,3,4,5,6,7];
|
||||
_newModes append (_currentModes - _removeModes);
|
||||
|
||||
_newModes = _newModes arrayIntersect _newModes;
|
||||
_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;
|
||||
} else {
|
||||
GVAR(availableVisions) = _newModes;
|
||||
};
|
||||
|
||||
// Update camera in case of change
|
||||
if !(isNil QGVAR(camera)) then {
|
||||
[] call FUNC(transitionCamera);
|
||||
};
|
||||
|
||||
_newModes
|
1
addons/spectator/functions/script_component.hpp
Normal file
1
addons/spectator/functions/script_component.hpp
Normal file
@ -0,0 +1 @@
|
||||
#include "\z\ace\addons\spectator\script_component.hpp"
|
57
addons/spectator/script_component.hpp
Normal file
57
addons/spectator/script_component.hpp
Normal file
@ -0,0 +1,57 @@
|
||||
#define COMPONENT spectator
|
||||
#include "\z\ace\addons\main\script_mod.hpp"
|
||||
|
||||
#ifdef DEBUG_ENABLED_SPECTATOR
|
||||
#define DEBUG_MODE_FULL
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_SETTINGS_SPECTATOR
|
||||
#define DEBUG_SETTINGS DEBUG_SETTINGS_SPECTATOR
|
||||
#endif
|
||||
|
||||
#include "\z\ace\addons\main\script_macros.hpp"
|
||||
|
||||
// UI grid
|
||||
#define SIZEX ((safezoneW / safezoneH) min 1.2)
|
||||
#define SIZEY (SIZEX / 1.2)
|
||||
#define W_PART(num) (num * (SIZEX / 40))
|
||||
#define H_PART(num) (num * (SIZEY / 25))
|
||||
#define X_PART(num) (W_PART(num) + (safezoneX + (safezoneW - SIZEX)/2))
|
||||
#define Y_PART(num) (H_PART(num) + (safezoneY + (safezoneH - SIZEY)/2))
|
||||
|
||||
// UI tools
|
||||
#define TOOL_H H_PART(1)
|
||||
#define TOOL_W W_PART(5)
|
||||
#define MARGIN TOOL_W * 0.05
|
||||
|
||||
// UI compass
|
||||
#define COMPASS_W (TOOL_W * 4)
|
||||
#define COMPASS_X (safeZoneX + safeZoneW * 0.5 - COMPASS_W * 0.5)
|
||||
|
||||
// UI IDCs
|
||||
#define IDC_COMP 4490
|
||||
#define IDC_COMP_0 5000
|
||||
#define IDC_COMP_90 5090
|
||||
#define IDC_COMP_180 5180
|
||||
#define IDC_COMP_270 5270
|
||||
|
||||
#define IDC_HELP 7631
|
||||
#define IDC_HELP_LIST 7622
|
||||
|
||||
#define IDC_MAP 6791
|
||||
|
||||
#define IDC_TOOL 3000
|
||||
#define IDC_TOOL_CLOCK 3003
|
||||
#define IDC_TOOL_FOV 3005
|
||||
#define IDC_TOOL_NAME 3001
|
||||
#define IDC_TOOL_SPEED 3006
|
||||
#define IDC_TOOL_VIEW 3002
|
||||
#define IDC_TOOL_VISION 3004
|
||||
|
||||
#define IDC_UNIT 6002
|
||||
#define IDC_UNIT_TREE 6005
|
||||
|
||||
// UI colours
|
||||
#define COL_BACK 0.1,0.1,0.1,0.7
|
||||
#define COL_FORE 1,1,1,1
|
||||
#define COL_FORE_D 0.1,0.1,0.1,0.8
|
271
addons/spectator/stringtable.xml
Normal file
271
addons/spectator/stringtable.xml
Normal file
@ -0,0 +1,271 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project name="ACE">
|
||||
<Package name="Spectator">
|
||||
<Key ID="STR_ACE_Spectator_Settings_DisplayName">
|
||||
<English>Spectator Settings</English>
|
||||
<Polish>Ustawienia obserwatora</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_Settings_Descripton">
|
||||
<English>Configure how the spectator system will operate by default.</English>
|
||||
<Polish>Skonfiguruj domyślne ustawienia obserwatora.</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_units_DisplayName">
|
||||
<English>Unit filter</English>
|
||||
<Polish>Filtr jednostek</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_units_Description">
|
||||
<English>Method of filtering spectatable units.</English>
|
||||
<Polish>Wybierz jednostki, jakie będzie można obserwować po uruchomeniu obserwatora.</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_units_none">
|
||||
<English>No units</English>
|
||||
<Polish>Brak jednostek</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_units_players">
|
||||
<English>Only players</English>
|
||||
<Polish>Tylko gracze</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_units_playable">
|
||||
<English>Playable Units</English>
|
||||
<Polish>Grywalne jednostki</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_units_all">
|
||||
<English>All units</English>
|
||||
<Polish>Wszystkie jednostki</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_sides_DisplayName">
|
||||
<English>Side filter</English>
|
||||
<Polish>Filtr stron</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_sides_Description">
|
||||
<English>Method of filtering spectatable sides.</English>
|
||||
<Polish>Wybierz strony, jakie będzie można obserwować po uruchomeniu obserwatora.</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_sides_player">
|
||||
<English>Player side</English>
|
||||
<Polish>Strona gracza</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_sides_friendly">
|
||||
<English>Friendly sides</English>
|
||||
<Polish>Strony sojusznicze</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_sides_hostile">
|
||||
<English>Hostile sides</English>
|
||||
<Polish>Strony wrogie</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_sides_all">
|
||||
<English>All sides</English>
|
||||
<Polish>Wszystkie strony</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_modes_DisplayName">
|
||||
<English>Camera modes</English>
|
||||
<Polish>Tryby kamery</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_modes_Description">
|
||||
<English>Camera modes that can be used.</English>
|
||||
<Polish>Tryby kamery, jakie mogą być używane.</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_modes_all">
|
||||
<English>All</English>
|
||||
<Polish>Wszystkie</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_modes_free">
|
||||
<English>Free only</English>
|
||||
<Polish>Tylko wolna</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_modes_internal">
|
||||
<English>Internal only</English>
|
||||
<Polish>Tylko wewnętrzna</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_modes_external">
|
||||
<English>External only</English>
|
||||
<Polish>Tylko zewnętrzna</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_modes_unit">
|
||||
<English>Internal and external</English>
|
||||
<Polish>Wewnętrzna i zewnętrzna</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_visions_DisplayName">
|
||||
<English>Vision modes</English>
|
||||
<Polish>Tryby wizji</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_visions_Description">
|
||||
<English>Vision modes that can be used.</English>
|
||||
<Polish>Tryby wizji, jakie mogą być używane.</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_visions_nv">
|
||||
<English>Night vision</English>
|
||||
<Polish>Noktowizja</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_visions_ti">
|
||||
<English>Thermal imaging</English>
|
||||
<Polish>Termowizja</Polish>
|
||||
</Key>
|
||||
<!-- Interface strings -->
|
||||
<Key ID="STR_ACE_Spectator_UnitTitle">
|
||||
<English>Spectator Units</English>
|
||||
<Polish>Jednostki obserwatora</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_HelpTitle">
|
||||
<English>Spectator Controls</English>
|
||||
<Polish>Sterowanie obserwatorem</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_ViewFree">
|
||||
<English>Free</English>
|
||||
<Polish>Wolna</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_ViewInternal">
|
||||
<English>Internal</English>
|
||||
<Polish>Wewnętrzna</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_ViewExternal">
|
||||
<English>External</English>
|
||||
<Polish>Zewnętrzna</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_VisionNormal">
|
||||
<English>Normal</English>
|
||||
<Polish>Normalna</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_VisionNight">
|
||||
<English>Night</English>
|
||||
<Polish>Noc</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_VisionThermal">
|
||||
<English>Thermal</English>
|
||||
<Polish>Termo</Polish>
|
||||
</Key>
|
||||
<!-- Controls -->
|
||||
<Key ID="STR_ACE_Spectator_freeCamControls">
|
||||
<English>Free Camera</English>
|
||||
<Polish>Kamera swobodna</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_freeCamForward">
|
||||
<English>Camera Forward</English>
|
||||
<Polish>Kamera naprzód</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_freeCamBackward">
|
||||
<English>Camera Backward</English>
|
||||
<Polish>Kamera w tył</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_freeCamLeft">
|
||||
<English>Camera Left</English>
|
||||
<Polish>Kamera w lewo</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_freeCamRight">
|
||||
<English>Camera Right</English>
|
||||
<Polish>Kamera w prawo</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_freeCamUp">
|
||||
<English>Camera Up</English>
|
||||
<Polish>Kamera w górę</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_freeCamDown">
|
||||
<English>Camera Down</English>
|
||||
<Polish>Kamera w dół</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_freeCamPan">
|
||||
<English>Pan Camera</English>
|
||||
<Polish>Panoramowanie</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_freeCamDolly">
|
||||
<English>Dolly Camera</English>
|
||||
<Polish>Płynna kamera</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_freeCamLock">
|
||||
<English>Lock Camera to Target</English>
|
||||
<Polish>Zablokuj kamerę na celu</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_freeCamBoost">
|
||||
<English>Speed Boost</English>
|
||||
<Polish>Przyśpieszenie kamery</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_freeCamFocus">
|
||||
<English>Focus on Unit</English>
|
||||
<Polish>Skup na jednostce</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_uiControls">
|
||||
<English>Interface</English>
|
||||
<Polish>Interfejs</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_uiToggleInterface">
|
||||
<English>Toggle Interface</English>
|
||||
<Polish>Przełącz interfejs</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_uiToggleIcons">
|
||||
<English>Toggle Unit Icons</English>
|
||||
<Polish>Przełącz ikony jednostek</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_uiToggleUnits">
|
||||
<English>Toggle Unit List</English>
|
||||
<Polish>Przełącz listę jednostek</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_uiToggleTools">
|
||||
<English>Toggle Toolbar</English>
|
||||
<Polish>Przełącz pasek narzędzi</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_uiToggleCompass">
|
||||
<English>Toggle Compass</English>
|
||||
<Polish>Przełącz kompas</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_uiToggleMap">
|
||||
<English>Toggle Map</English>
|
||||
<Polish>Przełącz mapę</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_uiToggleHelp">
|
||||
<English>Toggle Help</English>
|
||||
<Polish>Przełącz pomoc</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_attributeControls">
|
||||
<English>Camera Attributes</English>
|
||||
<Polish>Atrybuty kamery</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_nextCam">
|
||||
<English>Next Camera</English>
|
||||
<Polish>Następna kamera</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_prevCam">
|
||||
<English>Previous Camera</English>
|
||||
<Polish>Poprzednia kamera</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_nextUnit">
|
||||
<English>Next Unit</English>
|
||||
<Polish>Następna jednostka</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_prevUnit">
|
||||
<English>Previous Unit</English>
|
||||
<Polish>Poprzednia jednostka</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_nextVis">
|
||||
<English>Next Vision Mode</English>
|
||||
<Polish>Następny tryb wizji</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_prevVis">
|
||||
<English>Previous Vision Mode</English>
|
||||
<Polish>Poprzedni tryb wizji</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_adjZoom">
|
||||
<English>Adjust Zoom</English>
|
||||
<Polish>Reguluj zoom</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_adjSpeed">
|
||||
<English>Adjust Speed</English>
|
||||
<Polish>Reguluj prędkość</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_incZoom">
|
||||
<English>Increment Zoom</English>
|
||||
<Polish>Reguluj zoom (krok)</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_incSpeed">
|
||||
<English>Increment Speed</English>
|
||||
<Polish>Reguluj prędkość (krok)</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_reZoom">
|
||||
<English>Reset Zoom</English>
|
||||
<Polish>Resetuj zoom</Polish>
|
||||
</Key>
|
||||
<Key ID="STR_ACE_Spectator_reSpeed">
|
||||
<English>Reset Speed</English>
|
||||
<Polish>Resetuj prędkość</Polish>
|
||||
</Key>
|
||||
</Package>
|
||||
</Project>
|
Loading…
Reference in New Issue
Block a user