Splitted weapons and units managers

This commit is contained in:
Pax1601
2023-07-27 16:27:59 +02:00
parent 875f3ebe68
commit 0150ae9df1
38 changed files with 5616 additions and 4883 deletions

View File

@@ -1,6 +1,6 @@
import { LatLng } from "leaflet"
interface UnitIconOptions {
interface ObjectIconOptions {
showState: boolean,
showVvi: boolean,
showHotgroup: boolean,

View File

@@ -1,7 +1,7 @@
import { Dropdown } from "../controls/dropdown";
import { zeroAppend } from "../other/utils";
import { ATC } from "./atc";
import { Unit } from "../units/unit";
import { Unit } from "../unit/unit";
import { getMissionHandler, getUnitsManager } from "..";
import Sortable from "sortablejs";
import { FlightInterface } from "./atc";

View File

@@ -1,6 +1,6 @@
import { getUnitsManager } from "..";
import { Panel } from "../panels/panel";
import { Unit } from "../units/unit";
import { Unit } from "../unit/unit";
export class UnitDataTable extends Panel {
constructor(id: string) {

View File

@@ -6,7 +6,7 @@ import { ContextMenu } from "./contextmenu";
import { Dropdown } from "./dropdown";
import { Slider } from "./slider";
import { Switch } from "./switch";
import { groundUnitDatabase } from "../units/groundunitdatabase";
import { groundUnitDatabase } from "../unit/groundunitdatabase";
import { createCheckboxOption, getCheckboxOptions } from "../other/utils";
export class CoalitionAreaContextMenu extends ContextMenu {

View File

@@ -1,16 +1,16 @@
import { LatLng } from "leaflet";
import { getActiveCoalition, getMap, getMissionHandler, getUnitsManager, setActiveCoalition } from "..";
import { spawnExplosion, spawnSmoke } from "../server/server";
import { aircraftDatabase } from "../units/aircraftdatabase";
import { groundUnitDatabase } from "../units/groundunitdatabase";
import { helicopterDatabase } from "../units/helicopterdatabase";
import { aircraftDatabase } from "../unit/aircraftdatabase";
import { groundUnitDatabase } from "../unit/groundunitdatabase";
import { helicopterDatabase } from "../unit/helicopterdatabase";
import { ContextMenu } from "./contextmenu";
import { Dropdown } from "./dropdown";
import { Switch } from "./switch";
import { Slider } from "./slider";
import { ftToM } from "../other/utils";
import { GAME_MASTER } from "../constants/constants";
import { navyUnitDatabase } from "../units/navyunitdatabase";
import { navyUnitDatabase } from "../unit/navyunitdatabase";
import { CoalitionArea } from "../map/coalitionarea";
export class MapContextMenu extends ContextMenu {

View File

@@ -1,5 +1,5 @@
import { Map } from "./map/map"
import { UnitsManager } from "./units/unitsmanager";
import { UnitsManager } from "./unit/unitsmanager";
import { UnitInfoPanel } from "./panels/unitinfopanel";
import { ConnectionStatusPanel } from "./panels/connectionstatuspanel";
import { MissionHandler } from "./mission/missionhandler";
@@ -18,10 +18,12 @@ import { HotgroupPanel } from "./panels/hotgrouppanel";
import { SVGInjector } from "@tanem/svg-injector";
import { BLUE_COMMANDER, GAME_MASTER, RED_COMMANDER } from "./constants/constants";
import { ServerStatusPanel } from "./panels/serverstatuspanel";
import { WeaponsManager } from "./weapon/weaponsmanager";
var map: Map;
var unitsManager: UnitsManager;
var weaponsManager: WeaponsManager;
var missionHandler: MissionHandler;
var aic: AIC;
@@ -48,6 +50,7 @@ function setup() {
/* Initialize base functionalitites */
unitsManager = new UnitsManager();
weaponsManager = new WeaponsManager();
map = new Map('map-container');
missionHandler = new MissionHandler();
@@ -222,6 +225,11 @@ export function getUnitsManager() {
return unitsManager;
}
export function getWeaponsManager() {
return weaponsManager;
}
export function getMissionHandler() {
return missionHandler;
}

View File

@@ -6,7 +6,7 @@ import { UnitContextMenu } from "../controls/unitcontextmenu";
import { AirbaseContextMenu } from "../controls/airbasecontextmenu";
import { Dropdown } from "../controls/dropdown";
import { Airbase } from "../mission/airbase";
import { Unit } from "../units/unit";
import { Unit } from "../unit/unit";
import { bearing, createCheckboxOption } from "../other/utils";
import { DestinationPreviewMarker } from "./destinationpreviewmarker";
import { TemporaryUnitMarker } from "./temporaryunitmarker";

View File

@@ -5,11 +5,11 @@ import { Bullseye } from "./bullseye";
import { BLUE_COMMANDER, GAME_MASTER, RED_COMMANDER } from "../constants/constants";
import { setCommandModeOptions } from "../server/server";
import { Dropdown } from "../controls/dropdown";
import { groundUnitDatabase } from "../units/groundunitdatabase";
import { groundUnitDatabase } from "../unit/groundunitdatabase";
import { createCheckboxOption, getCheckboxOptions } from "../other/utils";
import { aircraftDatabase } from "../units/aircraftdatabase";
import { helicopterDatabase } from "../units/helicopterdatabase";
import { navyUnitDatabase } from "../units/navyunitdatabase";
import { aircraftDatabase } from "../unit/aircraftdatabase";
import { helicopterDatabase } from "../unit/helicopterdatabase";
import { navyUnitDatabase } from "../unit/navyunitdatabase";
export class MissionHandler {
#bullseyes: { [name: string]: Bullseye } = {};

View File

@@ -1,9 +1,9 @@
import { LatLng, Point, Polygon } from "leaflet";
import * as turf from "@turf/turf";
import { UnitDatabase } from "../units/unitdatabase";
import { aircraftDatabase } from "../units/aircraftdatabase";
import { helicopterDatabase } from "../units/helicopterdatabase";
import { groundUnitDatabase } from "../units/groundunitdatabase";
import { UnitDatabase } from "../unit/unitdatabase";
import { aircraftDatabase } from "../unit/aircraftdatabase";
import { helicopterDatabase } from "../unit/helicopterdatabase";
import { groundUnitDatabase } from "../unit/groundunitdatabase";
import { Buffer } from "buffer";
import { ROEs, emissionsCountermeasures, reactionsToThreat, states } from "../constants/constants";
import { Dropdown } from "../controls/dropdown";

View File

@@ -1,5 +1,5 @@
import { getUnitsManager } from "..";
import { Unit } from "../units/unit";
import { Unit } from "../unit/unit";
import { Panel } from "./panel";
export class HotgroupPanel extends Panel {

View File

@@ -1,7 +1,7 @@
import { Icon, LatLng, Marker, Polyline } from "leaflet";
import { getMap, getMissionHandler, getUnitsManager } from "..";
import { distance, bearing, zeroAppend, mToNm, nmToFt } from "../other/utils";
import { Unit } from "../units/unit";
import { Unit } from "../unit/unit";
import { Panel } from "./panel";
import formatcoords from "formatcoords";

View File

@@ -2,8 +2,8 @@ import { SVGInjector } from "@tanem/svg-injector";
import { getUnitsManager } from "..";
import { Dropdown } from "../controls/dropdown";
import { Slider } from "../controls/slider";
import { aircraftDatabase } from "../units/aircraftdatabase";
import { Unit } from "../units/unit";
import { aircraftDatabase } from "../unit/aircraftdatabase";
import { Unit } from "../unit/unit";
import { Panel } from "./panel";
import { Switch } from "../controls/switch";
import { ROEDescriptions, ROEs, altitudeIncrements, emissionsCountermeasures, emissionsCountermeasuresDescriptions, maxAltitudeValues, maxSpeedValues, minAltitudeValues, minSpeedValues, reactionsToThreat, reactionsToThreatDescriptions, speedIncrements } from "../constants/constants";

View File

@@ -1,8 +1,8 @@
import { getUnitsManager } from "..";
import { Ammo } from "../@types/unit";
import { ConvertDDToDMS, rad2deg } from "../other/utils";
import { aircraftDatabase } from "../units/aircraftdatabase";
import { Unit } from "../units/unit";
import { aircraftDatabase } from "../unit/aircraftdatabase";
import { Unit } from "../unit/unit";
import { Panel } from "./panel";
export class UnitInfoPanel extends Panel {

View File

@@ -1,5 +1,5 @@
import { LatLng } from 'leaflet';
import { getConnectionStatusPanel, getInfoPopup, getLogPanel, getMissionHandler, getServerStatusPanel, getUnitDataTable, getUnitsManager, setLoginStatus } from '..';
import { getConnectionStatusPanel, getInfoPopup, getLogPanel, getMissionHandler, getServerStatusPanel, getUnitsManager, getWeaponsManager, setLoginStatus } from '..';
import { GeneralSettings, Radio, TACAN } from '../@types/unit';
import { ROEs, emissionsCountermeasures, reactionsToThreat } from '../constants/constants';
@@ -9,6 +9,7 @@ var paused: boolean = false;
var REST_ADDRESS = "http://localhost:30000/olympus";
var DEMO_ADDRESS = window.location.href + "demo";
const UNITS_URI = "units";
const WEAPONS_URI = "weapons";
const LOGS_URI = "logs";
const AIRBASES_URI = "airbases";
const BULLSEYE_URI = "bullseyes";
@@ -128,6 +129,10 @@ export function getUnits(callback: CallableFunction, refresh: boolean = false) {
GET(callback, UNITS_URI, { time: refresh ? 0 : lastUpdateTimes[UNITS_URI] }, 'arraybuffer');
}
export function getWeapons(callback: CallableFunction, refresh: boolean = false) {
GET(callback, WEAPONS_URI, { time: refresh ? 0 : lastUpdateTimes[WEAPONS_URI] }, 'arraybuffer');
}
export function addDestination(ID: number, path: any) {
var command = { "ID": ID, "path": path }
var data = { "setPath": command }
@@ -383,6 +388,15 @@ export function startUpdate() {
}
}, 250);
window.setInterval(() => {
if (!getPaused()) {
getWeapons((buffer: ArrayBuffer) => {
var time = getWeaponsManager()?.update(buffer);
return time;
}, false);
}
}, 250);
window.setInterval(() => {
if (!getPaused()) {
getUnits((buffer: ArrayBuffer) => {
@@ -394,14 +408,6 @@ export function startUpdate() {
}, 5000);
}
export function requestUpdate() {
/* Main update rate = 250ms is minimum time, equal to server update time. */
if (!getPaused()) {
getUnits((buffer: ArrayBuffer) => { return getUnitsManager()?.update(buffer); }, false);
}
window.setTimeout(() => requestUpdate(), getConnected() ? 250 : 1000);
}
export function checkSessionHash(newSessionHash: string) {
if (sessionHash != null) {
if (newSessionHash != sessionHash)

View File

@@ -7,8 +7,8 @@ import { SVGInjector } from '@tanem/svg-injector';
import { UnitDatabase } from './unitdatabase';
import { TargetMarker } from '../map/targetmarker';
import { BOMBING, CARPET_BOMBING, DLINK, DataIndexes, FIRE_AT_AREA, GAME_MASTER, HIDE_GROUP_MEMBERS, IDLE, IRST, MOVE_UNIT, OPTIC, RADAR, ROEs, RWR, SHOW_CONTACT_LINES, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, VISUAL, emissionsCountermeasures, reactionsToThreat, states } from '../constants/constants';
import { Ammo, Contact, GeneralSettings, Offset, Radio, TACAN, UnitIconOptions } from '../@types/unit';
import { DataExtractor } from './dataextractor';
import { Ammo, Contact, GeneralSettings, Offset, Radio, TACAN, ObjectIconOptions } from '../@types/unit';
import { DataExtractor } from '../server/dataextractor';
import { groundUnitDatabase } from './groundunitdatabase';
import { navyUnitDatabase } from './navyunitdatabase';
@@ -135,8 +135,6 @@ export class Unit extends CustomMarker {
if (type === "GroundUnit") return GroundUnit;
if (type === "Aircraft") return Aircraft;
if (type === "Helicopter") return Helicopter;
if (type === "Missile") return Missile;
if (type === "Bomb") return Bomb;
if (type === "NavyUnit") return NavyUnit;
}
@@ -297,7 +295,7 @@ export class Unit extends CustomMarker {
return getUnitDatabaseByCategory(this.getMarkerCategory());
}
getIconOptions(): UnitIconOptions {
getIconOptions(): ObjectIconOptions {
// Default values, overloaded by child classes if needed
return {
showState: false,
@@ -976,7 +974,7 @@ export class Unit extends CustomMarker {
if (getMap().getVisibilityOptions()[SHOW_CONTACT_LINES]) {
for (let index in this.#contacts) {
var contactData = this.#contacts[index];
var contact = getUnitsManager().getUnitByID(contactData.ID)
var contact = getUnitsManager().getUnitByID(contactData.ID);
if (contact != null && contact.getAlive()) {
var startLatLng = new LatLng(this.#position.lat, this.#position.lng);
var endLatLng: LatLng;
@@ -1149,74 +1147,3 @@ export class NavyUnit extends Unit {
return blueprint?.type? blueprint.type: "";
}
}
export class Weapon extends Unit {
constructor(ID: number) {
super(ID);
this.setSelectable(false);
}
}
export class Missile extends Weapon {
constructor(ID: number) {
super(ID);
}
getCategory() {
return "Missile";
}
getMarkerCategory() {
if (this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC))
return "missile";
else
return "aircraft";
}
getIconOptions() {
return {
showState: false,
showVvi: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
showHotgroup: false,
showUnitIcon: (this.belongsToCommandedCoalition() || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))),
showShortLabel: false,
showFuel: false,
showAmmo: false,
showSummary: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
showCallsign: false,
rotateToHeading: this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC)
};
}
}
export class Bomb extends Weapon {
constructor(ID: number) {
super(ID);
}
getCategory() {
return "Bomb";
}
getMarkerCategory() {
if (this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC))
return "bomb";
else
return "aircraft";
}
getIconOptions() {
return {
showState: false,
showVvi: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
showHotgroup: false,
showUnitIcon: (this.belongsToCommandedCoalition() || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))),
showShortLabel: false,
showFuel: false,
showAmmo: false,
showSummary: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
showCallsign: false,
rotateToHeading: this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC)
};
}
}

View File

@@ -6,9 +6,9 @@ import { bearingAndDistanceToLatLng, deg2rad, keyEventWasInInput, latLngToMercat
import { CoalitionArea } from "../map/coalitionarea";
import { groundUnitDatabase } from "./groundunitdatabase";
import { DataIndexes, GAME_MASTER, IADSDensities, IDLE, MOVE_UNIT, NONE } from "../constants/constants";
import { DataExtractor } from "./dataextractor";
import { DataExtractor } from "../server/dataextractor";
import { Contact } from "../@types/unit";
import { citiesDatabase } from "./citiesdatabase";
import { citiesDatabase } from "./citiesDatabase";
import { aircraftDatabase } from "./aircraftdatabase";
import { helicopterDatabase } from "./helicopterdatabase";
import { navyUnitDatabase } from "./navyunitdatabase";
@@ -73,10 +73,6 @@ export class UnitsManager {
}
}
removeUnit(ID: number) {
}
update(buffer: ArrayBuffer) {
var dataExtractor = new DataExtractor(buffer);
var updateTime = Number(dataExtractor.extractUInt64());

323
client/src/weapon/weapon.ts Normal file
View File

@@ -0,0 +1,323 @@
import { LatLng, DivIcon, Map } from 'leaflet';
import { getMap, getMissionHandler, getUnitsManager } from '..';
import { enumToCoalition, mToFt, msToKnots, rad2deg } from '../other/utils';
import { CustomMarker } from '../map/custommarker';
import { SVGInjector } from '@tanem/svg-injector';
import { DLINK, DataIndexes, GAME_MASTER, IRST, OPTIC, RADAR, VISUAL } from '../constants/constants';
import { ObjectIconOptions } from '../@types/unit';
import { DataExtractor } from '../server/dataextractor';
export class Weapon extends CustomMarker {
ID: number;
#alive: boolean = false;
#coalition: string = "neutral";
#name: string = "";
#position: LatLng = new LatLng(0, 0, 0);
#speed: number = 0;
#heading: number = 0;
#hidden: boolean = false;
#detectionMethods: number[] = [];
getAlive() {return this.#alive};
getCoalition() {return this.#coalition};
getName() {return this.#name};
getPosition() {return this.#position};
getSpeed() {return this.#speed};
getHeading() {return this.#heading};
static getConstructor(type: string) {
if (type === "Missile") return Missile;
if (type === "Bomb") return Bomb;
}
constructor(ID: number) {
super(new LatLng(0, 0), { riseOnHover: true, keyboard: false });
this.ID = ID;
/* Deselect units if they are hidden */
document.addEventListener("toggleCoalitionVisibility", (ev: CustomEventInit) => {
window.setTimeout(() => { !this.getHidden() }, 300);
});
document.addEventListener("toggleUnitVisibility", (ev: CustomEventInit) => {
window.setTimeout(() => { !this.getHidden() }, 300);
});
document.addEventListener("mapVisibilityOptionsChanged", (ev: CustomEventInit) => {
this.#updateMarker();
});
}
getCategory() {
// Overloaded by child classes
return "";
}
/********************** Unit data *************************/
setData(dataExtractor: DataExtractor) {
var updateMarker = !getMap().hasLayer(this);
var datumIndex = 0;
while (datumIndex != DataIndexes.endOfData) {
datumIndex = dataExtractor.extractUInt8();
switch (datumIndex) {
case DataIndexes.category: dataExtractor.extractString(); break;
case DataIndexes.alive: this.setAlive(dataExtractor.extractBool()); updateMarker = true; break;
case DataIndexes.coalition: this.#coalition = enumToCoalition(dataExtractor.extractUInt8()); break;
case DataIndexes.name: this.#name = dataExtractor.extractString(); break;
case DataIndexes.position: this.#position = dataExtractor.extractLatLng(); updateMarker = true; break;
case DataIndexes.speed: this.#speed = dataExtractor.extractFloat64(); updateMarker = true; break;
case DataIndexes.heading: this.#heading = dataExtractor.extractFloat64(); updateMarker = true; break;
}
}
if (updateMarker)
this.#updateMarker();
}
getData() {
return {
category: this.getCategory(),
ID: this.ID,
alive: this.#alive,
coalition: this.#coalition,
name: this.#name,
position: this.#position,
speed: this.#speed,
heading: this.#heading
}
}
getMarkerCategory(): string {
return "";
}
getIconOptions(): ObjectIconOptions {
// Default values, overloaded by child classes if needed
return {
showState: false,
showVvi: false,
showHotgroup: false,
showUnitIcon: true,
showShortLabel: false,
showFuel: false,
showAmmo: false,
showSummary: true,
showCallsign: true,
rotateToHeading: false
}
}
setAlive(newAlive: boolean) {
this.#alive = newAlive;
}
belongsToCommandedCoalition() {
if (getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER && getMissionHandler().getCommandedCoalition() !== this.#coalition)
return false;
return true;
}
getType() {
return "";
}
/********************** Icon *************************/
createIcon(): void {
/* Set the icon */
var icon = new DivIcon({
className: 'leaflet-unit-icon',
iconAnchor: [25, 25],
iconSize: [50, 50],
});
this.setIcon(icon);
var el = document.createElement("div");
el.classList.add("unit");
el.setAttribute("data-object", `unit-${this.getMarkerCategory()}`);
el.setAttribute("data-coalition", this.#coalition);
// Generate and append elements depending on active options
// Velocity vector
if (this.getIconOptions().showVvi) {
var vvi = document.createElement("div");
vvi.classList.add("unit-vvi");
vvi.toggleAttribute("data-rotate-to-heading");
el.append(vvi);
}
// Main icon
if (this.getIconOptions().showUnitIcon) {
var unitIcon = document.createElement("div");
unitIcon.classList.add("unit-icon");
var img = document.createElement("img");
img.src = `/resources/theme/images/units/${this.getMarkerCategory()}.svg`;
img.onload = () => SVGInjector(img);
unitIcon.appendChild(img);
unitIcon.toggleAttribute("data-rotate-to-heading", this.getIconOptions().rotateToHeading);
el.append(unitIcon);
}
this.getElement()?.appendChild(el);
}
/********************** Visibility *************************/
updateVisibility() {
const hiddenUnits = getUnitsManager().getHiddenTypes();
var hidden = (hiddenUnits.includes(this.getMarkerCategory())) ||
(hiddenUnits.includes(this.#coalition)) ||
(!this.belongsToCommandedCoalition() && this.#detectionMethods.length == 0);
this.setHidden(hidden || !this.#alive);
}
setHidden(hidden: boolean) {
this.#hidden = hidden;
/* Add the marker if not present */
if (!getMap().hasLayer(this) && !this.getHidden()) {
if (getMap().isZooming())
this.once("zoomend", () => {this.addTo(getMap())})
else
this.addTo(getMap());
}
/* Hide the marker if necessary*/
if (getMap().hasLayer(this) && this.getHidden()) {
getMap().removeLayer(this);
}
}
getHidden() {
return this.#hidden;
}
setDetectionMethods(newDetectionMethods: number[]) {
if (!this.belongsToCommandedCoalition()) {
/* Check if the detection methods of this unit have changed */
if (this.#detectionMethods.length !== newDetectionMethods.length || this.getDetectionMethods().some(value => !newDetectionMethods.includes(value))) {
/* Force a redraw of the unit to reflect the new status of the detection methods */
this.setHidden(true);
this.#detectionMethods = newDetectionMethods;
this.updateVisibility();
}
}
}
getDetectionMethods() {
return this.#detectionMethods;
}
/***********************************************/
onAdd(map: Map): this {
super.onAdd(map);
/* If this is the first time adding this unit to the map, remove the temporary marker */
getMap().removeTemporaryMarker(new LatLng(this.#position.lat, this.#position.lng));
return this;
}
#updateMarker() {
this.updateVisibility();
/* Draw the marker */
if (!this.getHidden()) {
if (this.getLatLng().lat !== this.#position.lat || this.getLatLng().lng !== this.#position.lng) {
this.setLatLng(new LatLng(this.#position.lat, this.#position.lng));
}
var element = this.getElement();
if (element != null) {
/* Draw the velocity vector */
element.querySelector(".unit-vvi")?.setAttribute("style", `height: ${15 + this.#speed / 5}px;`);
/* Set dead/alive flag */
element.querySelector(".unit")?.toggleAttribute("data-is-dead", !this.#alive);
/* Set altitude and speed */
if (element.querySelector(".unit-altitude"))
(<HTMLElement>element.querySelector(".unit-altitude")).innerText = "FL" + String(Math.floor(mToFt(this.#position.alt as number) / 100));
if (element.querySelector(".unit-speed"))
(<HTMLElement>element.querySelector(".unit-speed")).innerText = String(Math.floor(msToKnots(this.#speed))) + "GS";
/* Rotate elements according to heading */
element.querySelectorAll("[data-rotate-to-heading]").forEach(el => {
const headingDeg = rad2deg(this.#heading);
let currentStyle = el.getAttribute("style") || "";
el.setAttribute("style", currentStyle + `transform:rotate(${headingDeg}deg);`);
});
}
/* Set vertical offset for altitude stacking */
var pos = getMap().latLngToLayerPoint(this.getLatLng()).round();
this.setZIndexOffset(1000 + Math.floor(this.#position.alt as number) - pos.y);
}
}
}
export class Missile extends Weapon {
constructor(ID: number) {
super(ID);
}
getCategory() {
return "Missile";
}
getMarkerCategory() {
if (this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC))
return "missile";
else
return "aircraft";
}
getIconOptions() {
return {
showState: false,
showVvi: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
showHotgroup: false,
showUnitIcon: (this.belongsToCommandedCoalition() || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))),
showShortLabel: false,
showFuel: false,
showAmmo: false,
showSummary: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
showCallsign: false,
rotateToHeading: this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC)
};
}
}
export class Bomb extends Weapon {
constructor(ID: number) {
super(ID);
}
getCategory() {
return "Bomb";
}
getMarkerCategory() {
if (this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC))
return "bomb";
else
return "aircraft";
}
getIconOptions() {
return {
showState: false,
showVvi: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
showHotgroup: false,
showUnitIcon: (this.belongsToCommandedCoalition() || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))),
showShortLabel: false,
showFuel: false,
showAmmo: false,
showSummary: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
showCallsign: false,
rotateToHeading: this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC)
};
}
}

View File

@@ -0,0 +1,84 @@
import { getMissionHandler, getUnitsManager } from "..";
import { Weapon } from "./weapon";
import { DataIndexes, GAME_MASTER } from "../constants/constants";
import { DataExtractor } from "../server/dataextractor";
import { Contact } from "../@types/unit";
export class WeaponsManager {
#weapons: { [ID: number]: Weapon };
#requestDetectionUpdate: boolean = false;
constructor() {
this.#weapons = {};
document.addEventListener("commandModeOptionsChanged", () => {Object.values(this.#weapons).forEach((weapon: Weapon) => weapon.updateVisibility())});
document.addEventListener('contactsUpdated', (e: CustomEvent) => {this.#requestDetectionUpdate = true});
}
getWeapons() {
return this.#weapons;
}
getWeaponByID(ID: number) {
if (ID in this.#weapons)
return this.#weapons[ID];
else
return null;
}
addWeapon(ID: number, category: string) {
if (category){
/* The name of the weapon category is exactly the same as the constructor name */
var constructor = Weapon.getConstructor(category);
if (constructor != undefined) {
this.#weapons[ID] = new constructor(ID);
}
}
}
update(buffer: ArrayBuffer) {
var dataExtractor = new DataExtractor(buffer);
var updateTime = Number(dataExtractor.extractUInt64());
var requestRefresh = false;
while (dataExtractor.getSeekPosition() < buffer.byteLength) {
const ID = dataExtractor.extractUInt32();
if (!(ID in this.#weapons)) {
const datumIndex = dataExtractor.extractUInt8();
if (datumIndex == DataIndexes.category) {
const category = dataExtractor.extractString();
this.addWeapon(ID, category);
}
else {
requestRefresh = true;
}
}
this.#weapons[ID]?.setData(dataExtractor);
}
if (this.#requestDetectionUpdate && getMissionHandler().getCommandModeOptions().commandMode != GAME_MASTER) {
for (let ID in this.#weapons) {
var weapon = this.#weapons[ID];
if (!weapon.belongsToCommandedCoalition())
weapon.setDetectionMethods(this.getWeaponDetectedMethods(weapon));
}
this.#requestDetectionUpdate = false;
}
return updateTime;
}
getWeaponDetectedMethods(weapon: Weapon) {
var detectionMethods: number[] = [];
var units = getUnitsManager().getUnits();
for (let idx in units) {
if (units[idx].getAlive() && units[idx].getIsLeader() && units[idx].getCoalition() !== "neutral" && units[idx].getCoalition() != weapon.getCoalition())
{
units[idx].getContacts().forEach((contact: Contact) => {
if (contact.ID == weapon.ID && !detectionMethods.includes(contact.detectionMethod))
detectionMethods.push(contact.detectionMethod);
});
}
}
return detectionMethods;
}
}