feat(alarm state): refactor to separe alarm state from radar state. Kown issue: alarm state is not correctly mantained

This commit is contained in:
MarcoJayUsai 2025-03-24 18:42:04 +01:00
parent f7e9fc5cbc
commit 1622d663bb
15 changed files with 174 additions and 253 deletions

View File

@ -48,9 +48,9 @@ namespace ROE {
namespace ALARM_STATE {
enum ALARM_STATEs {
AUTO = 0,
AUTO = 2,
GREEN = 1,
RED = 2,
RED = 0,
};
}

View File

@ -8,6 +8,7 @@ namespace DataIndex {
category,
alive,
alarmState,
radarState,
human,
controlled,
coalition,

View File

@ -98,7 +98,7 @@ public:
virtual void setTargetID(unsigned int newValue) { updateValue(targetID, newValue, DataIndex::targetID); }
virtual void setTargetPosition(Coords newValue) { updateValue(targetPosition, newValue, DataIndex::targetPosition); }
virtual void setROE(unsigned char newValue, bool force = false);
virtual void commandAlarmState(unsigned char newValue, bool force = false);
virtual void setAlarmState(unsigned char newValue, bool force = false);
virtual void setReactionToThreat(unsigned char newValue, bool force = false);
virtual void setEmissionsCountermeasures(unsigned char newValue, bool force = false);
virtual void setTACAN(DataTypes::TACAN newValue, bool force = false);
@ -126,12 +126,12 @@ public:
virtual void setTargetingRange(double newValue) { updateValue(targetingRange, newValue, DataIndex::targetingRange); }
virtual void setAimMethodRange(double newValue) { updateValue(aimMethodRange, newValue, DataIndex::aimMethodRange); }
virtual void setAcquisitionRange(double newValue) { updateValue(acquisitionRange, newValue, DataIndex::acquisitionRange); }
virtual void setAlarmState(string newValue) { updateValue(alarmState, newValue, DataIndex::alarmState); }
virtual void setRadarState(bool newValue) { updateValue(radarState, newValue, DataIndex::radarState); }
/********** Getters **********/
virtual string getCategory() { return category; };
virtual bool getAlive() { return alive; }
virtual string getAlarmState() { return alarmState; }
virtual unsigned char getAlarmState() { return alarmState; }
virtual bool getHuman() { return human; }
virtual bool getControlled() { return controlled; }
virtual unsigned char getCoalition() { return coalition; }
@ -190,6 +190,7 @@ public:
virtual double getTargetingRange() { return targetingRange; }
virtual double getAimMethodRange() { return aimMethodRange; }
virtual double getAcquisitionRange() { return acquisitionRange; }
virtual bool getRadarState() { return radarState; }
protected:
unsigned int ID;
@ -205,7 +206,8 @@ protected:
string callsign = "";
string groupName = "";
unsigned char state = State::NONE;
string alarmState = "";
unsigned char alarmState = ALARM_STATE::AUTO;
bool radarState = false;
string task = "";
bool hasTask = false;
Coords position = Coords(NULL);

View File

@ -609,7 +609,7 @@ string GroundUnit::aimAtPoint(Coords aimTarget) {
Geodesic::WGS84().Direct(position.lat, position.lng, bearing1, r, lat, lng);
taskString = +"Barrel elevation: " + to_string((int) round(barrelElevation)) + "m, bearing: " + to_string((int) round(bearing1)) + "deg";
log(unitName + "(" + name + ")" + " shooting with aim at point method. Barrel elevation: " + to_string(barrelElevation) + "m, bearing: " + to_string(bearing1) + "°");
log(unitName + "(" + name + ")" + " shooting with aim at point method. Barrel elevation: " + to_string(barrelElevation) + "m, bearing: " + to_string(bearing1) + "<EFBFBD>");
std::ostringstream taskSS;
taskSS.precision(10);

View File

@ -406,17 +406,17 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") ROE to " + to_string(ROE), true);
}
}
else if (key.compare("commandAlarmState") == 0)
else if (key.compare("setAlarmState") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unsigned char alarmState = value[L"alarmState"].as_integer();
unit->commandAlarmState(alarmState);
unit->setAlarmState(alarmState);
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") alarm state to " + to_string(alarmState), true);
} else {
log("Error while setting commandAlarmState. Unit does not exist.");
log("Error while setting setAlarmState. Unit does not exist.");
}
}
/************************/

View File

@ -18,7 +18,7 @@ extern UnitsManager* unitsManager;
Unit::Unit(json::value json, unsigned int ID) :
ID(ID)
{
log("Creating unit with ID: " + to_string(ID));
// log("Creating unit with ID: " + to_string(ID));
}
Unit::~Unit()
@ -83,8 +83,8 @@ void Unit::update(json::value json, double dt)
if (json.has_boolean_field(L"isAlive"))
setAlive(json[L"isAlive"].as_bool());
if (json.has_string_field(L"alarmState")) {
setAlarmState(to_string(json[L"alarmState"]));
if (json.has_boolean_field(L"radarState")) {
setRadarState(json[L"radarState"].as_bool());
}
if (json.has_boolean_field(L"isHuman"))
@ -154,7 +154,7 @@ void Unit::update(json::value json, double dt)
void Unit::setDefaults(bool force)
{
setAlarmState(ALARM_STATE::AUTO, force);
}
void Unit::runAILoop() {
@ -256,7 +256,8 @@ void Unit::getData(stringstream& ss, unsigned long long time)
switch (datumIndex) {
case DataIndex::category: appendString(ss, datumIndex, category); break;
case DataIndex::alive: appendNumeric(ss, datumIndex, alive); break;
case DataIndex::alarmState: appendString(ss, datumIndex, alarmState); break;
case DataIndex::alarmState: appendNumeric(ss, datumIndex, alarmState); break;
case DataIndex::radarState: appendNumeric(ss, datumIndex, radarState); break;
case DataIndex::human: appendNumeric(ss, datumIndex, human); break;
case DataIndex::controlled: appendNumeric(ss, datumIndex, controlled); break;
case DataIndex::coalition: appendNumeric(ss, datumIndex, coalition); break;
@ -473,7 +474,7 @@ void Unit::setROE(unsigned char newROE, bool force)
}
}
void Unit::commandAlarmState(unsigned char newAlarmState, bool force)
void Unit::setAlarmState(unsigned char newAlarmState, bool force)
{
Command* command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::ALARM_STATE, static_cast<unsigned int>(newAlarmState)));
scheduler->appendCommand(command);

View File

@ -97,7 +97,6 @@ export const states: string[] = [
];
export const ROEs: string[] = ["free", "designated", "", "return", "hold"];
export const alarmStates: string[] = ["auto", "green", "red"];
export const reactionsToThreat: string[] = ["none", "manoeuvre", "passive", "evade"];
export const emissionsCountermeasures: string[] = ["silent", "attack", "defend", "free"];
@ -453,6 +452,7 @@ export enum DataIndexes {
category,
alive,
alarmState,
radarState,
human,
controlled,
coalition,

View File

@ -220,7 +220,7 @@ export interface UnitData {
markerCategory: string;
ID: number;
alive: boolean;
alarmState: AlarmState | undefined;
alarmState: AlarmState;
human: boolean;
controlled: boolean;
coalition: string;
@ -417,7 +417,7 @@ export interface Drawing {
}
export enum AlarmState {
AUTO = 'auto',
RED = 'red',
GREEN = 'green',
RED = 'red'
AUTO = 'auto'
}

View File

@ -660,7 +660,7 @@
}
/* Unit Radar State */
.unit-radar-state {
.unit-alarm-state {
height: 10px;
width: 10px;
position: absolute;
@ -670,12 +670,12 @@
left: 35px;
bottom: 8px;
}
.unit[data-radar-state="green"] .unit-radar-state {
.unit[data-alarm-state="green"] .unit-alarm-state {
border: 1px solid white;
background: rgb(0, 226, 0);
}
.unit[data-radar-state="red"] .unit-radar-state {
.unit[data-alarm-state="red"] .unit-alarm-state {
border: 1px solid white;
background: red;
}

View File

@ -1,7 +1,7 @@
import { Circle, LatLng, Polygon } from "leaflet";
import * as turf from "@turf/turf";
import { ROEs, emissionsCountermeasures, reactionsToThreat, states } from "../constants/constants";
import { DateAndTime } from "../interfaces";
import { AlarmState, DateAndTime } from "../interfaces";
import { Converter } from "usng";
import { MGRS } from "../types/types";
import { featureCollection } from "turf";
@ -275,6 +275,19 @@ export function enumToROE(ROE: number) {
else return ROEs[0];
}
export function enumToAlarmState(alarmState: number) {
switch (alarmState) {
case 0:
return AlarmState.RED;
case 1:
return AlarmState.GREEN;
case 2:
return AlarmState.AUTO;
default:
return AlarmState.AUTO;
}
}
export function convertROE(idx: number) {
let roe = 0;
if (idx === 0) roe = 4;

View File

@ -421,7 +421,7 @@ export class ServerManager {
setAlarmState(ID: number, alarmState: number, callback: CallableFunction = () => {}) {
var command = { ID: ID, alarmState: alarmState };
var data = { commandAlarmState: command };
var data = { setAlarmState: command };
this.PUT(data, callback);
}

View File

@ -132,7 +132,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
const [activeRadioSettings, setActiveRadioSettings] = useState(null as null | { radio: Radio; TACAN: TACAN });
const [activeAdvancedSettings, setActiveAdvancedSettings] = useState(null as null | GeneralSettings);
const [lastUpdateTime, setLastUpdateTime] = useState(0);
const [showScenicModes, setShowScenicModes] = useState(true);
const [showScenicModes, setShowScenicModes] = useState(false);
const [showEngagementSettings, setShowEngagementSettings] = useState(false);
const [barrelHeight, setBarrelHeight] = useState(0);
const [muzzleVelocity, setMuzzleVelocity] = useState(0);
@ -420,9 +420,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
<td className="flex gap-2 text-lg text-gray-200">
<FontAwesomeIcon icon={entry[1][0] as IconDefinition} />{" "}
<div
className={`
text-sm text-gray-400
`}
className={`text-sm text-gray-400`}
>
{entry[1][1] as string}
</div>
@ -802,9 +800,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
{" "}
<FontAwesomeIcon
icon={olButtonsRoeHold}
className={`
my-auto min-w-8 text-white
`}
className={`my-auto min-w-8 text-white`}
/>{" "}
Hold fire: The unit will not shoot in any circumstance
</div>
@ -812,9 +808,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
{" "}
<FontAwesomeIcon
icon={olButtonsRoeReturn}
className={`
my-auto min-w-8 text-white
`}
className={`my-auto min-w-8 text-white`}
/>{" "}
Return fire: The unit will not fire unless fired upon
</div>
@ -822,17 +816,13 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
{" "}
<FontAwesomeIcon
icon={olButtonsRoeDesignated}
className={`
my-auto min-w-8 text-white
`}
className={`my-auto min-w-8 text-white`}
/>{" "}
<div>
{" "}
Fire on target: The unit will not fire unless fired upon{" "}
<p
className={`
inline font-bold
`}
className={`inline font-bold`}
>
or
</p>{" "}
@ -843,9 +833,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
{" "}
<FontAwesomeIcon
icon={olButtonsRoeFree}
className={`
my-auto min-w-8 text-white
`}
className={`my-auto min-w-8 text-white`}
/>{" "}
Free: The unit will fire at any detected enemy in range
</div>
@ -853,25 +841,19 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
<div className="flex gap-4">
<div className="my-auto">
<FaExclamationCircle
className={`
animate-bounce text-xl
`}
className={`animate-bounce text-xl`}
/>
</div>
<div>
Currently, DCS blue and red ground units do not respect{" "}
<FontAwesomeIcon
icon={olButtonsRoeReturn}
className={`
my-auto text-white
`}
className={`my-auto text-white`}
/>{" "}
and{" "}
<FontAwesomeIcon
icon={olButtonsRoeDesignated}
className={`
my-auto text-white
`}
className={`my-auto text-white`}
/>{" "}
rules of engagement, so be careful, they may start shooting when you don't want them to. Use neutral units for finer
control.
@ -957,6 +939,18 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
tooltipRelativeToParent={true}
>
{[olButtonsRoeHold, olButtonsRoeReturn, olButtonsRoeDesignated].map((icon, idx) => {
const getAlarmStateByIdx = (idx) => {
switch (idx) {
case 0:
return AlarmState.AUTO;
case 1:
return AlarmState.GREEN;
case 2:
return AlarmState.RED;
}
}
return (
<OlButtonGroupItem
key={idx}
@ -966,11 +960,11 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
.setAlarmState(idx, null, () =>
setForcedUnitsData({
...forcedUnitsData,
alarmState: Object.values(AlarmState)[idx],
alarmState: getAlarmStateByIdx(idx),
})
);
}}
active={selectedUnitsData.alarmState === alarmStates[idx]}
active={selectedUnitsData.alarmState === getAlarmStateByIdx(idx)}
icon={icon}
/>
);
@ -1007,9 +1001,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
{" "}
<FontAwesomeIcon
icon={olButtonsThreatNone}
className={`
my-auto min-w-8 text-white
`}
className={`my-auto min-w-8 text-white`}
/>{" "}
No reaction: The unit will not react in any circumstance
</div>
@ -1017,9 +1009,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
{" "}
<FontAwesomeIcon
icon={olButtonsThreatPassive}
className={`
my-auto min-w-8 text-white
`}
className={`my-auto min-w-8 text-white`}
/>{" "}
Passive: The unit will use counter-measures, but will not alter its course
</div>
@ -1027,9 +1017,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
{" "}
<FontAwesomeIcon
icon={olButtonsThreatManoeuvre}
className={`
my-auto min-w-8 text-white
`}
className={`my-auto min-w-8 text-white`}
/>{" "}
Manouevre: The unit will try to evade the threat using manoeuvres, but no counter-measures
</div>
@ -1037,9 +1025,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
{" "}
<FontAwesomeIcon
icon={olButtonsThreatEvade}
className={`
my-auto min-w-8 text-white
`}
className={`my-auto min-w-8 text-white`}
/>{" "}
Full evasion: the unit will try to evade the threat both manoeuvering and using counter-measures
</div>
@ -1094,9 +1080,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
{" "}
<FontAwesomeIcon
icon={olButtonsEmissionsSilent}
className={`
my-auto min-w-8 text-white
`}
className={`my-auto min-w-8 text-white`}
/>{" "}
Radio silence: No radar or ECM will be used
</div>
@ -1104,9 +1088,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
{" "}
<FontAwesomeIcon
icon={olButtonsEmissionsDefend}
className={`
my-auto min-w-8 text-white
`}
className={`my-auto min-w-8 text-white`}
/>{" "}
Defensive: The unit will turn radar and ECM on only when threatened
</div>
@ -1114,9 +1096,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
{" "}
<FontAwesomeIcon
icon={olButtonsEmissionsAttack}
className={`
my-auto min-w-8 text-white
`}
className={`my-auto min-w-8 text-white`}
/>{" "}
Attack: The unit will use radar and ECM when engaging other units
</div>
@ -1124,9 +1104,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
{" "}
<FontAwesomeIcon
icon={olButtonsEmissionsFree}
className={`
my-auto min-w-8 text-white
`}
className={`my-auto min-w-8 text-white`}
/>{" "}
Free: the unit will use the radar and ECM all the time
</div>
@ -1347,9 +1325,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
<div className="flex gap-4">
<div className="my-auto">
<FaExclamationCircle
className={`
animate-bounce text-xl
`}
className={`animate-bounce text-xl`}
/>
</div>
<div>
@ -1529,9 +1505,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
{/* ============== Operate as toggle START ============== */}
{selectedUnits.every((unit) => unit.getCoalition() === "neutral") && (
<div
className={`
flex content-center justify-between
`}
className={`flex content-center justify-between`}
>
<span
className={`
@ -1573,17 +1547,13 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
>
<div className="flex align-center gap-2">
<div
className={`
my-auto
`}
className={`my-auto`}
>
Barrel height:{" "}
</div>
<OlNumberInput
decimalPlaces={1}
className={`
ml-auto
`}
className={`ml-auto`}
value={barrelHeight}
min={0}
max={100}
@ -1598,26 +1568,20 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
}}
></OlNumberInput>
<div
className={`
my-auto
`}
className={`my-auto`}
>
m
</div>
</div>
<div className="flex align-center gap-2">
<div
className={`
my-auto
`}
className={`my-auto`}
>
Muzzle velocity:{" "}
</div>
<OlNumberInput
decimalPlaces={0}
className={`
ml-auto
`}
className={`ml-auto`}
value={muzzleVelocity}
min={0}
max={10000}
@ -1632,26 +1596,20 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
}}
></OlNumberInput>
<div
className={`
my-auto
`}
className={`my-auto`}
>
m/s
</div>
</div>
<div className="flex align-center gap-2">
<div
className={`
my-auto
`}
className={`my-auto`}
>
Aim time:{" "}
</div>
<OlNumberInput
decimalPlaces={2}
className={`
ml-auto
`}
className={`ml-auto`}
value={aimTime}
min={0}
max={100}
@ -1666,25 +1624,19 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
}}
></OlNumberInput>
<div
className={`
my-auto
`}
className={`my-auto`}
>
s
</div>
</div>
<div className="flex align-center gap-2">
<div
className={`
my-auto
`}
className={`my-auto`}
>
Shots to fire:{" "}
</div>
<OlNumberInput
className={`
ml-auto
`}
className={`ml-auto`}
value={shotsToFire}
min={0}
max={100}
@ -1701,17 +1653,13 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
</div>
<div className="flex align-center gap-2">
<div
className={`
my-auto
`}
className={`my-auto`}
>
Shots base interval:{" "}
</div>
<OlNumberInput
decimalPlaces={2}
className={`
ml-auto
`}
className={`ml-auto`}
value={shotsBaseInterval}
min={0}
max={100}
@ -1726,26 +1674,20 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
}}
></OlNumberInput>
<div
className={`
my-auto
`}
className={`my-auto`}
>
s
</div>
</div>
<div className="flex align-center gap-2">
<div
className={`
my-auto
`}
className={`my-auto`}
>
Shots base scatter:{" "}
</div>
<OlNumberInput
decimalPlaces={2}
className={`
ml-auto
`}
className={`ml-auto`}
value={shotsBaseScatter}
min={0}
max={50}
@ -1760,25 +1702,19 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
}}
></OlNumberInput>
<div
className={`
my-auto
`}
className={`my-auto`}
>
deg
</div>
</div>
<div className="flex align-center gap-2">
<div
className={`
my-auto
`}
className={`my-auto`}
>
Engagement range:{" "}
</div>
<OlNumberInput
className={`
ml-auto
`}
className={`ml-auto`}
value={engagementRange}
min={0}
max={100000}
@ -1793,25 +1729,19 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
}}
></OlNumberInput>
<div
className={`
my-auto
`}
className={`my-auto`}
>
m
</div>
</div>
<div className="flex align-center gap-2">
<div
className={`
my-auto
`}
className={`my-auto`}
>
Targeting range:{" "}
</div>
<OlNumberInput
className={`
ml-auto
`}
className={`ml-auto`}
value={targetingRange}
min={0}
max={100000}
@ -1826,25 +1756,19 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
}}
></OlNumberInput>
<div
className={`
my-auto
`}
className={`my-auto`}
>
m
</div>
</div>
<div className="flex align-center gap-2">
<div
className={`
my-auto
`}
className={`my-auto`}
>
Aim method range:{" "}
</div>
<OlNumberInput
className={`
ml-auto
`}
className={`ml-auto`}
value={aimMethodRange}
min={0}
max={100000}
@ -1859,25 +1783,19 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
}}
></OlNumberInput>
<div
className={`
my-auto
`}
className={`my-auto`}
>
m
</div>
</div>
<div className="flex align-center gap-2">
<div
className={`
my-auto
`}
className={`my-auto`}
>
Acquisition range:{" "}
</div>
<OlNumberInput
className={`
ml-auto
`}
className={`ml-auto`}
value={acquisitionRange}
min={0}
max={100000}
@ -1892,9 +1810,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
}}
></OlNumberInput>
<div
className={`
my-auto
`}
className={`my-auto`}
>
m
</div>

View File

@ -18,6 +18,7 @@ import {
computeBearingRangeString,
adjustBrightness,
bearingAndDistanceToLatLng,
enumToAlarmState,
} from "../other/utils";
import { CustomMarker } from "../map/markers/custommarker";
import { SVGInjector } from "@tanem/svg-injector";
@ -84,7 +85,8 @@ export abstract class Unit extends CustomMarker {
/* Data controlled directly by the backend. No setters are provided to avoid misalignments */
#alive: boolean = false;
#alarmState: AlarmState | undefined = undefined;
#alarmState: AlarmState = AlarmState.AUTO;
#radarState: boolean | undefined = undefined;
#human: boolean = false;
#controlled: boolean = false;
#coalition: string = "neutral";
@ -352,6 +354,9 @@ export abstract class Unit extends CustomMarker {
getAlarmState() {
return this.#alarmState;
}
getRadarState() {
return this.#radarState;
}
getTimeToNextTasking() {
return this.#timeToNextTasking;
}
@ -541,6 +546,7 @@ export abstract class Unit extends CustomMarker {
var datumIndex = 0;
while (datumIndex != DataIndexes.endOfData) {
datumIndex = dataExtractor.extractUInt8();
switch (datumIndex) {
case DataIndexes.category:
dataExtractor.extractString();
@ -549,20 +555,8 @@ export abstract class Unit extends CustomMarker {
this.setAlive(dataExtractor.extractBool());
updateMarker = true;
break;
case DataIndexes.alarmState:
let stringAlarmState = dataExtractor.extractString();
switch (stringAlarmState) {
case 'RED':
this.setAlarmState(AlarmState.RED);
break;
case 'GREEN':
this.setAlarmState(AlarmState.GREEN);
break;
case '':
this.setAlarmState(AlarmState.AUTO);
default:
break;
}
case DataIndexes.radarState:
this.#radarState = dataExtractor.extractBool();
updateMarker = true;
break;
case DataIndexes.human:
@ -670,6 +664,9 @@ export abstract class Unit extends CustomMarker {
case DataIndexes.ROE:
this.#ROE = enumToROE(dataExtractor.extractUInt8());
break;
case DataIndexes.alarmState:
this.#alarmState = enumToAlarmState(dataExtractor.extractUInt8());
break;
case DataIndexes.reactionToThreat:
this.#reactionToThreat = enumToReactionToThreat(dataExtractor.extractUInt8());
break;
@ -890,10 +887,9 @@ export abstract class Unit extends CustomMarker {
}
}
setAlarmState(newAlarmState: AlarmState) {
if (newAlarmState != this.#alarmState) {
this.#alarmState = newAlarmState;
console.log('---- alarm state updated: ', this.#alarmState);
setRadarState(newRadarState: boolean) {
if (newRadarState != this.#radarState) {
this.#radarState = newRadarState;
this.#updateMarker();
}
}
@ -1436,7 +1432,7 @@ export abstract class Unit extends CustomMarker {
if (!this.#human) getApp().getServerManager().setROE(this.ID, ROE);
}
commandAlarmState(alarmState: number) {
setAlarmState(alarmState: number) {
if (!this.#human) getApp().getServerManager().setAlarmState(this.ID, alarmState);
}
@ -1755,7 +1751,7 @@ export abstract class Unit extends CustomMarker {
}
if (this.getHidden()) return; // We won't draw the marker if the unit is hidden
/* Draw the marker */
if (this.getLatLng().lat !== this.#position.lat || this.getLatLng().lng !== this.#position.lng) {
this.setLatLng(new LatLng(this.#position.lat, this.#position.lng));
@ -1777,8 +1773,9 @@ export abstract class Unit extends CustomMarker {
/* Set dead/alive flag */
element.querySelector(".unit")?.toggleAttribute("data-is-dead", !this.#alive);
/* Set RED/GREEN state*/
if (this.#alarmState) element.querySelector(".unit")?.setAttribute("data-radar-state", this.#alarmState);
/* Set radar state*/
// if (this.#radarState !== undefined) element.querySelector(".unit")?.setAttribute("data-radar-state", (this.#radarState === true ? 'on' : 'off'));
if (this.#alarmState !== AlarmState.AUTO) element.querySelector(".unit")?.setAttribute("data-alarm-state", (this.#alarmState === AlarmState.RED ? 'red' : 'green'));
/* Set current unit state */
if (this.#human) {
@ -1836,28 +1833,28 @@ export abstract class Unit extends CustomMarker {
if (hasFox3 != newHasFox3) element.querySelector(".unit")?.toggleAttribute("data-has-fox-3", newHasFox3);
if (hasOtherAmmo != newHasOtherAmmo) element.querySelector(".unit")?.toggleAttribute("data-has-other-ammo", newHasOtherAmmo);
/* Draw the hotgroup element */
element.querySelector(".unit")?.toggleAttribute("data-is-in-hotgroup", this.#hotgroup != null);
if (this.#hotgroup) {
const hotgroupEl = element.querySelector(".unit-hotgroup-id") as HTMLElement;
if (hotgroupEl) hotgroupEl.innerText = String(this.#hotgroup);
}
/* Draw the hotgroup element */
element.querySelector(".unit")?.toggleAttribute("data-is-in-hotgroup", this.#hotgroup != null);
if (this.#hotgroup) {
const hotgroupEl = element.querySelector(".unit-hotgroup-id") as HTMLElement;
if (hotgroupEl) hotgroupEl.innerText = String(this.#hotgroup);
}
/* Draw the cluster element */
element
.querySelector(".unit")
?.toggleAttribute(
"data-is-cluster-leader",
this.#isClusterLeader &&
this.#clusterUnits.length > 1 &&
getApp().getMap().getOptions().clusterGroundUnits &&
getApp().getMap().getZoom() < CLUSTERING_ZOOM_TRANSITION &&
!this.getSelected()
);
if (this.#isClusterLeader && this.#clusterUnits.length > 1) {
const clusterEl = element.querySelector(".unit-cluster-id") as HTMLElement;
if (clusterEl) clusterEl.innerText = String(this.#clusterUnits.length);
}
/* Draw the cluster element */
element
.querySelector(".unit")
?.toggleAttribute(
"data-is-cluster-leader",
this.#isClusterLeader &&
this.#clusterUnits.length > 1 &&
getApp().getMap().getOptions().clusterGroundUnits &&
getApp().getMap().getZoom() < CLUSTERING_ZOOM_TRANSITION &&
!this.getSelected()
);
if (this.#isClusterLeader && this.#clusterUnits.length > 1) {
const clusterEl = element.querySelector(".unit-cluster-id") as HTMLElement;
if (clusterEl) clusterEl.innerText = String(this.#clusterUnits.length);
}
/* Set bullseyes positions */
const bullseyes = getApp().getMissionManager().getBullseyes();

View File

@ -1,36 +1,14 @@
import { DomEvent, DomUtil, LatLng, LatLngBounds } from "leaflet";
import { getApp } from "../olympusapp";
import { AirUnit, GroundUnit, NavyUnit, Unit } from "./unit";
import {
areaContains,
bearingAndDistanceToLatLng,
deepCopyTable,
deg2rad,
getGroundElevation,
latLngToMercator,
mToFt,
mercatorToLatLng,
msToKnots,
} from "../other/utils";
import { CoalitionPolygon } from "../map/coalitionarea/coalitionpolygon";
import * as turf from "@turf/turf";
import { LatLng, LatLngBounds } from "leaflet";
import {
BLUE_COMMANDER,
DELETE_CYCLE_TIME,
DELETE_SLOW_THRESHOLD,
DataIndexes,
GAME_MASTER,
IADSDensities,
OlympusState,
RED_COMMANDER,
UnitControlSubState, alarmStates,
UnitControlSubState
} from "../constants/constants";
import { DataExtractor } from "../server/dataextractor";
import { citiesDatabase } from "./databases/citiesdatabase";
import { TemporaryUnitMarker } from "../map/markers/temporaryunitmarker";
import { AlarmState, Contact, GeneralSettings, Radio, TACAN, UnitBlueprint, UnitData, UnitSpawnTable } from "../interfaces";
import { Group } from "./group";
import { CoalitionCircle } from "../map/coalitionarea/coalitioncircle";
import { ContextActionSet } from "./contextactionset";
import {
AWACSReferenceChangedEvent,
CommandModeOptionsChangedEvent,
@ -46,11 +24,30 @@ import {
UnitsRefreshedEvent,
UnitsUpdatedEvent,
} from "../events";
import { UnitDatabase } from "./databases/unitdatabase";
import * as turf from "@turf/turf";
import { Contact, GeneralSettings, Radio, TACAN, UnitBlueprint, UnitData, UnitSpawnTable } from "../interfaces";
import { CoalitionCircle } from "../map/coalitionarea/coalitioncircle";
import { CoalitionPolygon } from "../map/coalitionarea/coalitionpolygon";
import { PathMarker } from "../map/markers/pathmarker";
import { TemporaryUnitMarker } from "../map/markers/temporaryunitmarker";
import { getApp } from "../olympusapp";
import {
areaContains,
bearingAndDistanceToLatLng,
deepCopyTable,
deg2rad,
getGroundElevation,
latLngToMercator,
mToFt,
mercatorToLatLng,
msToKnots,
} from "../other/utils";
import { DataExtractor } from "../server/dataextractor";
import { Coalition } from "../types/types";
import { ClusterMarker } from "../map/markers/clustermarker";
import { ContextActionSet } from "./contextactionset";
import { citiesDatabase } from "./databases/citiesdatabase";
import { UnitDatabase } from "./databases/unitdatabase";
import { Group } from "./group";
import { AirUnit, GroundUnit, NavyUnit, Unit } from "./unit";
/** The UnitsManager handles the creation, update, and control of units. Data is strictly updated by the server ONLY. This means that any interaction from the user will always and only
* result in a command to the server, executed by means of a REST PUT request. Any subsequent change in data will be reflected only when the new data is sent back by the server. This strategy allows
@ -787,7 +784,7 @@ export class UnitsManager {
let callback = (units) => {
onExecution();
units.forEach((unit: Unit) => unit.commandAlarmState(alarmState));
units.forEach((unit: Unit) => unit.setAlarmState(alarmState));
this.#showActionMessage(units, `Alarm State set to ${alarmState.toString()}`);
};

View File

@ -1263,16 +1263,10 @@ function Olympus.setUnitsData(arg, time)
table["isAlive"] = unit:isExist() and unit:isActive() and unit:getLife() >= 1
if unit:isActive() and unit:hasSensors(Unit.SensorType.RADAR) then
-- Olympus.log:info("Unit Has Sensor Radar " .. tostring(unit:hasSensors(Unit.SensorType.RADAR)));
table["alarmState"] = "AUTO"
if unit:getRadar() then
-- Olympus.log:info("alarmState: unit active and getRadar is true, setting RED.")
table["alarmState"] = "RED"
table["radarState"] = true
else
-- Olympus.log:info("alarmState: unit active and getRadar is false, setting GREEN.")
table["alarmState"] = "GREEN"
table["radarState"] = false
end
end