mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
feat(alarm state): added unit control panel buttons (WIP)
This commit is contained in:
parent
18960ca51e
commit
2a00bab149
@ -96,13 +96,8 @@ export const states: string[] = [
|
||||
UnitState.LAND_AT_POINT,
|
||||
];
|
||||
|
||||
export enum RADAR_STATES {
|
||||
RED = 'red',
|
||||
GREEN = 'green',
|
||||
AUTO = 'auto'
|
||||
}
|
||||
|
||||
export const ROEs: string[] = ["free", "designated", "", "return", "hold"];
|
||||
export const alarmStates: string[] = ["green", "auto", "red"];
|
||||
export const reactionsToThreat: string[] = ["none", "manoeuvre", "passive", "evade"];
|
||||
export const emissionsCountermeasures: string[] = ["silent", "attack", "defend", "free"];
|
||||
|
||||
|
||||
@ -213,6 +213,7 @@ export interface UnitData {
|
||||
markerCategory: string;
|
||||
ID: number;
|
||||
alive: boolean;
|
||||
alarmState: AlarmState | undefined;
|
||||
human: boolean;
|
||||
controlled: boolean;
|
||||
coalition: string;
|
||||
@ -395,4 +396,10 @@ export interface Drawing {
|
||||
hiddenOnPlanner?: boolean;
|
||||
file?: string;
|
||||
scale?: number;
|
||||
}
|
||||
|
||||
export enum AlarmState {
|
||||
AUTO = 'auto',
|
||||
GREEN = 'green',
|
||||
RED = 'red'
|
||||
}
|
||||
@ -631,12 +631,12 @@
|
||||
left: 35px;
|
||||
bottom: 8px;
|
||||
}
|
||||
.unit[data-radar-state="GREEN"] .unit-radar-state {
|
||||
.unit[data-radar-state="green"] .unit-radar-state {
|
||||
border: 1px solid white;
|
||||
background: rgb(0, 226, 0);
|
||||
}
|
||||
|
||||
.unit[data-radar-state="RED"] .unit-radar-state {
|
||||
.unit[data-radar-state="red"] .unit-radar-state {
|
||||
border: 1px solid white;
|
||||
background: red;
|
||||
}
|
||||
|
||||
@ -547,7 +547,7 @@ export function roundToNearestFive(number) {
|
||||
return Math.round(number / 5) * 5;
|
||||
}
|
||||
|
||||
export function toDCSFormationOffset(offset: {x: number, y: number, z: number}) {
|
||||
export function toDCSFormationOffset(offset: { x: number, y: number, z: number }) {
|
||||
// X: front-rear, positive front
|
||||
// Y: top-bottom, positive top
|
||||
// Z: left-right, positive right
|
||||
@ -555,7 +555,7 @@ export function toDCSFormationOffset(offset: {x: number, y: number, z: number})
|
||||
return { x: -offset.y, y: offset.z, z: offset.x };
|
||||
}
|
||||
|
||||
export function fromDCSFormationOffset(offset: {x: number, y: number, z: number}) {
|
||||
export function fromDCSFormationOffset(offset: { x: number, y: number, z: number }) {
|
||||
return { x: offset.z, y: -offset.x, z: offset.y };
|
||||
}
|
||||
|
||||
@ -649,10 +649,10 @@ export function normalizeAngle(angle: number): number {
|
||||
}
|
||||
|
||||
export function decimalToRGBA(decimal: number): string {
|
||||
const r = (decimal >>> 24) & 0xff;
|
||||
const g = (decimal >>> 16) & 0xff;
|
||||
const b = (decimal >>> 8) & 0xff;
|
||||
const a = (decimal & 0xff) / 255;
|
||||
const r = (decimal >>> 24) & 0xff;
|
||||
const g = (decimal >>> 16) & 0xff;
|
||||
const b = (decimal >>> 8) & 0xff;
|
||||
const a = (decimal & 0xff) / 255;
|
||||
|
||||
return `rgba(${r}, ${g}, ${b}, ${a.toFixed(2)})`;
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import { OlButtonGroup, OlButtonGroupItem } from "../components/olbuttongroup";
|
||||
import { OlCheckbox } from "../components/olcheckbox";
|
||||
import {
|
||||
ROEs,
|
||||
alarmStates,
|
||||
altitudeIncrements,
|
||||
emissionsCountermeasures,
|
||||
maxAltitudeValues,
|
||||
@ -53,7 +54,7 @@ import { OlSearchBar } from "../components/olsearchbar";
|
||||
import { OlDropdown, OlDropdownItem } from "../components/oldropdown";
|
||||
import { FaRadio, FaVolumeHigh } from "react-icons/fa6";
|
||||
import { OlNumberInput } from "../components/olnumberinput";
|
||||
import { GeneralSettings, Radio, TACAN } from "../../interfaces";
|
||||
import { AlarmState, GeneralSettings, Radio, TACAN } from "../../interfaces";
|
||||
import { OlStringInput } from "../components/olstringinput";
|
||||
import { OlFrequencyInput } from "../components/olfrequencyinput";
|
||||
import { UnitSink } from "../../audio/unitsink";
|
||||
@ -85,6 +86,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
|
||||
radio: undefined as undefined | Radio,
|
||||
TACAN: undefined as undefined | TACAN,
|
||||
generalSettings: undefined as undefined | GeneralSettings,
|
||||
alarmState: undefined as undefined | AlarmState
|
||||
};
|
||||
}
|
||||
|
||||
@ -165,6 +167,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
|
||||
onOff: (unit: Unit) => unit.getOnOff(),
|
||||
radio: (unit: Unit) => unit.getRadio(),
|
||||
TACAN: (unit: Unit) => unit.getTACAN(),
|
||||
alarmState: (unit: Unit) => unit.getAlarmState(),
|
||||
generalSettings: (unit: Unit) => unit.getGeneralSettings(),
|
||||
isAudioSink: (unit: Unit) => {
|
||||
return (
|
||||
@ -818,6 +821,82 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
|
||||
</div>
|
||||
)}
|
||||
{/* ============== Rules of Engagement END ============== */}
|
||||
|
||||
{/* ============== Alarm state selector START ============== */}
|
||||
{selectedUnitsData.alarmState &&
|
||||
<div className="flex flex-col gap-2">
|
||||
<span
|
||||
className={`
|
||||
my-auto font-normal
|
||||
dark:text-white
|
||||
`}
|
||||
>
|
||||
Alarm State
|
||||
</span>
|
||||
<OlButtonGroup
|
||||
tooltip={() => (
|
||||
<OlExpandingTooltip
|
||||
title="Alarm State"
|
||||
content={
|
||||
<div className="flex flex-col gap-2">
|
||||
<div>Sets the alarm state of the unit, in order:</div>
|
||||
<div className="flex flex-col gap-2 px-2">
|
||||
<div className="flex content-center gap-2">
|
||||
{" "}
|
||||
<FontAwesomeIcon icon={olButtonsRoeReturn} className={`
|
||||
my-auto min-w-8 text-white
|
||||
`} /> Green: The unit will not engage with its sensors in any circumstances. The unit will be able to move.
|
||||
</div>
|
||||
<div className="flex content-center gap-2">
|
||||
{" "}
|
||||
<FontAwesomeIcon icon={olButtonsRoeDesignated} className={`
|
||||
my-auto min-w-8 text-white
|
||||
`} />{" "}
|
||||
<div>
|
||||
{" "}
|
||||
Auto: The unit will use its sensors to engage based on its ROE.
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex content-center gap-2">
|
||||
{" "}
|
||||
<FontAwesomeIcon icon={olButtonsRoeHold} className={`
|
||||
my-auto min-w-8 text-white
|
||||
`} /> Red: The unit will be actively searching for target with its sensors. For some units, this will deploy
|
||||
the radar and make the unit not able to move.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
tooltipRelativeToParent={true}
|
||||
>
|
||||
{[olButtonsRoeHold, olButtonsRoeReturn, olButtonsRoeDesignated].map((icon, idx) => {
|
||||
return (
|
||||
<OlButtonGroupItem
|
||||
key={idx}
|
||||
onClick={() => {
|
||||
// TODO: set alarm state
|
||||
// getApp()
|
||||
// .getUnitsManager()
|
||||
// .setROE(ROEs[convertROE(idx)], null, () =>
|
||||
// setForcedUnitsData({
|
||||
// ...forcedUnitsData,
|
||||
// ROE: ROEs[convertROE(idx)],
|
||||
// })
|
||||
// );
|
||||
}}
|
||||
active={selectedUnitsData.alarmState === alarmStates[idx]}
|
||||
icon={icon}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</OlButtonGroup>
|
||||
</div>
|
||||
}
|
||||
{/* ============== Alarm state selector END ============== */}
|
||||
|
||||
|
||||
{selectedCategories.every((category) => {
|
||||
return ["Aircraft", "Helicopter"].includes(category);
|
||||
}) && (
|
||||
|
||||
@ -51,7 +51,7 @@ import {
|
||||
} from "../constants/constants";
|
||||
import { DataExtractor } from "../server/dataextractor";
|
||||
import { Weapon } from "../weapon/weapon";
|
||||
import { Ammo, Contact, GeneralSettings, LoadoutBlueprint, ObjectIconOptions, Offset, Radio, TACAN, UnitBlueprint, UnitData } from "../interfaces";
|
||||
import { AlarmState, Ammo, Contact, GeneralSettings, LoadoutBlueprint, ObjectIconOptions, Offset, Radio, TACAN, UnitBlueprint, UnitData } from "../interfaces";
|
||||
import { RangeCircle } from "../map/rangecircle";
|
||||
import { Group } from "./group";
|
||||
import { ContextActionSet } from "./contextactionset";
|
||||
@ -83,7 +83,7 @@ export abstract class Unit extends CustomMarker {
|
||||
|
||||
/* Data controlled directly by the backend. No setters are provided to avoid misalignments */
|
||||
#alive: boolean = false;
|
||||
#radarState: string = '';
|
||||
#alarmState: AlarmState | undefined = undefined;
|
||||
#human: boolean = false;
|
||||
#controlled: boolean = false;
|
||||
#coalition: string = "neutral";
|
||||
@ -333,6 +333,9 @@ export abstract class Unit extends CustomMarker {
|
||||
getRaceTrackBearing() {
|
||||
return this.#racetrackBearing;
|
||||
}
|
||||
getAlarmState() {
|
||||
return this.#alarmState;
|
||||
}
|
||||
|
||||
static getConstructor(type: string) {
|
||||
if (type === "GroundUnit") return GroundUnit;
|
||||
@ -490,7 +493,19 @@ export abstract class Unit extends CustomMarker {
|
||||
updateMarker = true;
|
||||
break;
|
||||
case DataIndexes.radarState:
|
||||
this.setRadarState(dataExtractor.extractString());
|
||||
let stringAlarmState = dataExtractor.extractString();
|
||||
switch (stringAlarmState) {
|
||||
case 'RED':
|
||||
this.setRadarState(AlarmState.RED);
|
||||
break;
|
||||
case 'GREEN':
|
||||
this.setRadarState(AlarmState.GREEN);
|
||||
break;
|
||||
case '':
|
||||
this.setRadarState(AlarmState.AUTO);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
updateMarker = true;
|
||||
break;
|
||||
case DataIndexes.human:
|
||||
@ -755,6 +770,7 @@ export abstract class Unit extends CustomMarker {
|
||||
racetrackLength: this.#racetrackLength,
|
||||
racetrackAnchor: this.#racetrackAnchor,
|
||||
racetrackBearing: this.#racetrackBearing,
|
||||
alarmState: this.#alarmState
|
||||
};
|
||||
}
|
||||
|
||||
@ -769,11 +785,11 @@ export abstract class Unit extends CustomMarker {
|
||||
}
|
||||
}
|
||||
|
||||
setRadarState(newRadarState: string) {
|
||||
if (newRadarState != this.#radarState) {
|
||||
this.#radarState = newRadarState;
|
||||
setRadarState(newRadarState: AlarmState) {
|
||||
if (newRadarState != this.#alarmState) {
|
||||
this.#alarmState = newRadarState;
|
||||
// TODO: check if an event is needed -- surely yes to update the UI
|
||||
console.log('----radar state updated: ', this.#radarState);
|
||||
console.log('----radar state updated: ', this.#alarmState);
|
||||
this.#updateMarker();
|
||||
}
|
||||
}
|
||||
@ -1053,7 +1069,7 @@ export abstract class Unit extends CustomMarker {
|
||||
}
|
||||
|
||||
/* Radar state indicator */
|
||||
if (this.#radarState !== '') {
|
||||
if (this.#alarmState) {
|
||||
var radarStateIcon = document.createElement("div");
|
||||
radarStateIcon.classList.add("unit-radar-state");
|
||||
el.append(radarStateIcon);
|
||||
@ -1587,7 +1603,7 @@ export abstract class Unit extends CustomMarker {
|
||||
element.querySelector(".unit")?.toggleAttribute("data-is-dead", !this.#alive);
|
||||
|
||||
/* Set RED/GREEN state*/
|
||||
if (this.#radarState !== '') element.querySelector(".unit")?.setAttribute("data-radar-state", this.#radarState);
|
||||
if (this.#alarmState) element.querySelector(".unit")?.setAttribute("data-radar-state", this.#alarmState);
|
||||
|
||||
/* Set current unit state */
|
||||
if (this.#human) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user