Added unit marker to database and implemented better grouping

This commit is contained in:
Pax1601
2023-11-14 17:43:24 +01:00
parent e3423ea9a3
commit 25e2c50438
20 changed files with 785 additions and 423 deletions

View File

@@ -273,4 +273,6 @@ export const MGRS_PRECISION_10M = 5;
export const MGRS_PRECISION_1M = 6;
export const DELETE_CYCLE_TIME = 0.05;
export const DELETE_SLOW_THRESHOLD = 50;
export const DELETE_SLOW_THRESHOLD = 50;
export const GROUPING_ZOOM_TRANSITION = 13;

View File

@@ -231,6 +231,7 @@ export interface UnitBlueprint {
canAAA?: boolean;
indirectFire?: boolean;
markerFile?: string;
unitWhenGrouped?: string;
}
export interface UnitSpawnOptions {

View File

@@ -68,6 +68,7 @@ export class Map extends L.Map {
#temporaryMarkers: TemporaryUnitMarker[] = [];
#selecting: boolean = false;
#isZooming: boolean = false;
#previousZoom: number = 0;
#destinationGroupRotation: number = 0;
#computeDestinationRotation: boolean = false;
@@ -501,6 +502,10 @@ export class Map extends L.Map {
return this.#visibilityOptions;
}
getPreviousZoom() {
return this.#previousZoom;
}
/* Event handlers */
#onClick(e: any) {
if (!this.#preventLeftClick) {
@@ -701,6 +706,7 @@ export class Map extends L.Map {
}
#onZoomStart(e: any) {
this.#previousZoom = this.getZoom();
if (this.#centerUnit != null)
this.#panToUnit(this.#centerUnit);
this.#isZooming = true;

View File

@@ -5,7 +5,7 @@ import { CustomMarker } from '../map/markers/custommarker';
import { SVGInjector } from '@tanem/svg-injector';
import { UnitDatabase } from './databases/unitdatabase';
import { TargetMarker } from '../map/markers/targetmarker';
import { DLINK, DataIndexes, GAME_MASTER, HIDE_GROUP_MEMBERS, IDLE, IRST, MOVE_UNIT, OPTIC, RADAR, ROEs, RWR, SHOW_UNIT_CONTACTS, SHOW_UNITS_ENGAGEMENT_RINGS, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, VISUAL, emissionsCountermeasures, reactionsToThreat, states, SHOW_UNITS_ACQUISITION_RINGS, HIDE_UNITS_SHORT_RANGE_RINGS, FILL_SELECTED_RING } from '../constants/constants';
import { DLINK, DataIndexes, GAME_MASTER, HIDE_GROUP_MEMBERS, IDLE, IRST, MOVE_UNIT, OPTIC, RADAR, ROEs, RWR, SHOW_UNIT_CONTACTS, SHOW_UNITS_ENGAGEMENT_RINGS, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, VISUAL, emissionsCountermeasures, reactionsToThreat, states, SHOW_UNITS_ACQUISITION_RINGS, HIDE_UNITS_SHORT_RANGE_RINGS, FILL_SELECTED_RING, GROUPING_ZOOM_TRANSITION } from '../constants/constants';
import { DataExtractor } from '../server/dataextractor';
import { groundUnitDatabase } from './databases/groundunitdatabase';
import { navyUnitDatabase } from './databases/navyunitdatabase';
@@ -21,12 +21,11 @@ var pathIcon = new Icon({
/**
* Unit class which controls unit behaviour
*
* Just about everything is a unit - even missiles!
*/
export class Unit extends CustomMarker {
export abstract class Unit extends CustomMarker {
ID: number;
/* Data controlled directly by the backend. No setters are provided to avoid misalignments */
#alive: boolean = false;
#human: boolean = false;
#controlled: boolean = false;
@@ -90,6 +89,7 @@ export class Unit extends CustomMarker {
#shotsIntensity: number = 2;
#health: number = 100;
/* Other members used to draw the unit, mostly ancillary stuff like targets, ranges and so on */
#selectable: boolean;
#selected: boolean = false;
#hidden: boolean = false;
@@ -107,6 +107,7 @@ export class Unit extends CustomMarker {
#hotgroup: number | null = null;
#detectionMethods: number[] = [];
/* Getters for backend driven data */
getAlive() { return this.#alive };
getHuman() { return this.#human };
getControlled() { return this.#controlled };
@@ -171,6 +172,7 @@ export class Unit extends CustomMarker {
this.#engagementCircle = new RangeCircle(this.getPosition(), { radius: 0, weight: 4, opacity: 1, fillOpacity: 0, dashArray: "4 8", interactive: false, bubblingMouseEvents: false });
this.#acquisitionCircle = new RangeCircle(this.getPosition(), { radius: 0, weight: 2, opacity: 1, fillOpacity: 0, dashArray: "8 12", interactive: false, bubblingMouseEvents: false });
/* Leaflet events listeners */
this.on('click', (e) => this.#onClick(e));
this.on('dblclick', (e) => this.#onDoubleClick(e));
this.on('contextmenu', (e) => this.#onContextMenu(e));
@@ -184,7 +186,7 @@ export class Unit extends CustomMarker {
this.setHighlighted(false);
document.dispatchEvent(new CustomEvent("unitMouseout", { detail: this }));
});
getApp().getMap().on("zoomend", () => { this.#onZoom(); })
getApp().getMap().on("zoomend", (e: any) => { this.#onZoom(e); })
/* Deselect units if they are hidden */
document.addEventListener("toggleCoalitionVisibility", (ev: CustomEventInit) => {
@@ -195,6 +197,7 @@ export class Unit extends CustomMarker {
window.setTimeout(() => { this.setSelected(this.getSelected() && !this.getHidden()) }, 300);
});
/* Update the marker when the visibility options change */
document.addEventListener("mapVisibilityOptionsChanged", (ev: CustomEventInit) => {
this.#updateMarker();
@@ -209,13 +212,33 @@ export class Unit extends CustomMarker {
});
}
getCategory() {
// Overloaded by child classes
return "";
}
/********************** Abstract methods *************************/
/** Get the unit category string
*
* @returns string The unit category
*/
abstract getCategory(): string;
/** Get the icon options
* Used to configure how the marker appears on the map
*
* @returns ObjectIconOptions
*/
abstract getIconOptions(): ObjectIconOptions;
/** Get the actions that this unit can perform
*
* @returns Object containing the available actions
*/
abstract getActions(): {[key: string]: { text: string, tooltip: string, type: string}};
/********************** Unit data *************************/
/** This function is called by the units manager to update all the data coming from the backend. It reads the binary raw data using a DataExtractor
*
* @param dataExtractor The DataExtractor object pointing to the binary buffer which contains the raw data coming from the backend
*/
setData(dataExtractor: DataExtractor) {
/* This variable controls if the marker must be updated. This is not always true since not all variables have an effect on the marker*/
var updateMarker = !getApp().getMap().hasLayer(this);
var datumIndex = 0;
@@ -226,7 +249,7 @@ export class Unit extends CustomMarker {
case DataIndexes.alive: this.setAlive(dataExtractor.extractBool()); updateMarker = true; break;
case DataIndexes.human: this.#human = dataExtractor.extractBool(); break;
case DataIndexes.controlled: this.#controlled = dataExtractor.extractBool(); updateMarker = true; break;
case DataIndexes.coalition: let newCoalition = enumToCoalition(dataExtractor.extractUInt8()); updateMarker = true; if (newCoalition != this.#coalition) this.#clearRanges(); this.#coalition = newCoalition; break;
case DataIndexes.coalition: let newCoalition = enumToCoalition(dataExtractor.extractUInt8()); updateMarker = true; if (newCoalition != this.#coalition) this.#clearRanges(); this.#coalition = newCoalition; break; // If the coalition has changed, redraw the range circles to update the colour
case DataIndexes.country: this.#country = dataExtractor.extractUInt8(); break;
case DataIndexes.name: this.#name = dataExtractor.extractString(); break;
case DataIndexes.unitName: this.#unitName = dataExtractor.extractString(); break;
@@ -269,25 +292,18 @@ export class Unit extends CustomMarker {
}
}
/* Dead units can't be selected */
/* Dead and hidden units can't be selected */
this.setSelected(this.getSelected() && this.#alive && !this.getHidden())
/* Update the marker if required */
if (updateMarker)
this.#updateMarker();
/* If the unit is selected or if the view is centered on this unit, sent the update signal so that other elements like the UnitControlPanel can be updated. */
if (this.getSelected() || getApp().getMap().getCenterUnit() === this)
document.dispatchEvent(new CustomEvent("unitUpdated", { detail: this }));
}
drawLines() {
/* Leaflet does not like it when you change coordinates when the map is zooming */
if (!getApp().getMap().isZooming()) {
this.#drawPath();
this.#drawContacts();
this.#drawTarget();
}
}
/** Get unit data collated into an object
*
* @returns object populated by unit information which can also be retrieved using getters
@@ -358,28 +374,6 @@ export class Unit extends CustomMarker {
return getUnitDatabaseByCategory(this.getMarkerCategory());
}
/** Get the icon options
* Used to configure how the marker appears on the map
*
* @returns ObjectIconOptions
*/
getIconOptions(): ObjectIconOptions {
// Default values, overloaded by child classes if needed
return {
showState: false,
showVvi: false,
showHealth: true,
showHotgroup: false,
showUnitIcon: true,
showShortLabel: false,
showFuel: false,
showAmmo: false,
showSummary: true,
showCallsign: true,
rotateToHeading: false
}
}
/** Set the unit as alive or dead
*
* @param newAlive (boolean) true = alive, false = dead
@@ -395,16 +389,11 @@ export class Unit extends CustomMarker {
* @param selected (boolean)
*/
setSelected(selected: boolean) {
/* Only alive units can be selected. Some units are not selectable (weapons) */
if ((this.#alive || !selected) && this.getSelectable() && this.getSelected() != selected && this.belongsToCommandedCoalition()) {
/* Only alive units can be selected that belong to the commanded coalition can be selected */
if ((this.#alive || !selected) && this.belongsToCommandedCoalition() && this.getSelected() != selected) {
this.#selected = selected;
/* Circles don't like to be updated when the map is zooming */
if (!getApp().getMap().isZooming())
this.#drawRanges();
else
this.once("zoomend", () => { this.#drawRanges(); })
/* If selected, update the marker to show the selected effects, else clear all the drawings that are only shown for selected units. */
if (selected) {
this.#updateMarker();
}
@@ -414,21 +403,27 @@ export class Unit extends CustomMarker {
this.#clearTarget();
}
this.getElement()?.querySelector(`.unit`)?.toggleAttribute("data-is-selected", selected);
if (this.getCategory() === "GroundUnit" && getApp().getMap().getZoom() < 13) {
if (this.#isLeader)
/* When the group leader is selected, if grouping is active, all the other group members are also selected */
if (this.getCategory() === "GroundUnit" && getApp().getMap().getZoom() < GROUPING_ZOOM_TRANSITION) {
if (this.#isLeader) {
/* Redraw the marker in case the leader unit was replaced by a group marker, like for SAM Sites */
this.#redrawMarker();
this.getGroupMembers().forEach((unit: Unit) => unit.setSelected(selected));
else
}
else {
this.#updateMarker();
}
}
// Trigger events after all (de-)selecting has been done
/* Activate the selection effects on the marker */
this.getElement()?.querySelector(`.unit`)?.toggleAttribute("data-is-selected", selected);
/* Trigger events after all (de-)selecting has been done */
if (selected) {
document.dispatchEvent(new CustomEvent("unitSelection", { detail: this }));
} else {
document.dispatchEvent(new CustomEvent("unitDeselection", { detail: this }));
}
}
}
@@ -440,22 +435,6 @@ export class Unit extends CustomMarker {
return this.#selected;
}
/** Set whether this unit is selectable
*
* @param selectable (boolean)
*/
setSelectable(selectable: boolean) {
this.#selectable = selectable;
}
/** Get whether this unit is selectable
*
* @returns boolean
*/
getSelectable() {
return this.#selectable;
}
/** Set the number of the hotgroup to which the unit belongs
*
* @param hotgroup (number)
@@ -478,9 +457,9 @@ export class Unit extends CustomMarker {
* @param highlighted (boolean)
*/
setHighlighted(highlighted: boolean) {
if (this.getSelectable() && this.#highlighted != highlighted) {
this.getElement()?.querySelector(`[data-object|="unit"]`)?.toggleAttribute("data-is-highlighted", highlighted);
if (this.#highlighted != highlighted) {
this.#highlighted = highlighted;
this.getElement()?.querySelector(`[data-object|="unit"]`)?.toggleAttribute("data-is-highlighted", highlighted);
this.getGroupMembers().forEach((unit: Unit) => unit.setHighlighted(highlighted));
}
}
@@ -517,10 +496,25 @@ export class Unit extends CustomMarker {
return this.getDatabase()?.getSpawnPointsByName(this.getName());
}
getDatabaseEntry() {
return this.getDatabase()?.getByName(this.#name);
}
drawLines() {
/* Leaflet does not like it when you change coordinates when the map is zooming */
if (!getApp().getMap().isZooming()) {
this.#drawPath();
this.#drawContacts();
this.#drawTarget();
}
}
checkRedraw() {
return false;
}
/********************** Icon *************************/
createIcon(): void {
const databaseEntry = this.getDatabase()?.getByName(this.#name);
/* Set the icon */
var icon = new DivIcon({
className: 'leaflet-unit-icon',
@@ -529,6 +523,7 @@ export class Unit extends CustomMarker {
});
this.setIcon(icon);
/* Create the base element */
var el = document.createElement("div");
el.classList.add("unit");
el.setAttribute("data-object", `unit-${this.getMarkerCategory()}`);
@@ -536,8 +531,8 @@ export class Unit extends CustomMarker {
var iconOptions = this.getIconOptions();
// Generate and append elements depending on active options
// Velocity vector
/* Generate and append elements depending on active options */
/* Velocity vector */
if (iconOptions.showVvi) {
var vvi = document.createElement("div");
vvi.classList.add("unit-vvi");
@@ -545,7 +540,7 @@ export class Unit extends CustomMarker {
el.append(vvi);
}
// Hotgroup indicator
/* Hotgroup indicator */
if (iconOptions.showHotgroup) {
var hotgroup = document.createElement("div");
hotgroup.classList.add("unit-hotgroup");
@@ -555,42 +550,42 @@ export class Unit extends CustomMarker {
el.append(hotgroup);
}
// Main icon
/* Main icon */
if (iconOptions.showUnitIcon) {
var unitIcon = document.createElement("div");
unitIcon.classList.add("unit-icon");
var img = document.createElement("img");
var marker;
/* If a unit does not belong to the commanded coalition or it is not visually detected, show it with the generic aircraft square */
if (this.belongsToCommandedCoalition() || this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)))
marker = databaseEntry?.markerFile ?? this.getMarkerCategory();
var marker;
if (this.belongsToCommandedCoalition() || this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)))
marker = this.getDatabaseEntry()?.markerFile ?? this.getMarkerCategory();
else
marker = "aircraft";
img.src = `/resources/theme/images/units/${marker}.svg`;
img.onload = () => SVGInjector(img);
unitIcon.appendChild(img);
unitIcon.toggleAttribute("data-rotate-to-heading", iconOptions.rotateToHeading);
el.append(unitIcon);
}
// State icon
/* State icon */
if (iconOptions.showState) {
var state = document.createElement("div");
state.classList.add("unit-state");
el.appendChild(state);
}
// Short label
/* Short label */
if (iconOptions.showShortLabel) {
var shortLabel = document.createElement("div");
shortLabel.classList.add("unit-short-label");
shortLabel.innerText = databaseEntry?.shortLabel || "";
shortLabel.innerText = this.getDatabaseEntry()?.shortLabel || "";
el.append(shortLabel);
}
// Fuel indicator
/* Fuel indicator */
if (iconOptions.showFuel) {
var fuelIndicator = document.createElement("div");
fuelIndicator.classList.add("unit-fuel");
@@ -600,7 +595,7 @@ export class Unit extends CustomMarker {
el.append(fuelIndicator);
}
// Health indicator
/* Health indicator */
if (iconOptions.showHealth) {
var healthIndicator = document.createElement("div");
healthIndicator.classList.add("unit-health");
@@ -610,7 +605,7 @@ export class Unit extends CustomMarker {
el.append(healthIndicator);
}
// Ammo indicator
/* Ammo indicator */
if (iconOptions.showAmmo) {
var ammoIndicator = document.createElement("div");
ammoIndicator.classList.add("unit-ammo");
@@ -619,7 +614,7 @@ export class Unit extends CustomMarker {
el.append(ammoIndicator);
}
// Unit summary
/* Unit summary */
if (iconOptions.showSummary) {
var summary = document.createElement("div");
summary.classList.add("unit-summary");
@@ -637,25 +632,29 @@ export class Unit extends CustomMarker {
}
this.getElement()?.appendChild(el);
/* Circles don't like to be updated when the map is zooming */
if (!getApp().getMap().isZooming())
this.#drawRanges();
else
this.once("zoomend", () => { this.#drawRanges(); })
}
/********************** Visibility *************************/
updateVisibility() {
const hiddenUnits = getApp().getMap().getHiddenTypes();
var hidden = ((this.#human && hiddenUnits.includes("human")) ||
(this.#controlled == false && hiddenUnits.includes("dcs")) ||
(hiddenUnits.includes(this.getMarkerCategory())) ||
(hiddenUnits.includes(this.#coalition)) ||
const hiddenTypes = getApp().getMap().getHiddenTypes();
var hidden = (
/* Hide the unit if it is a human and humans are hidden */
(this.#human && hiddenTypes.includes("human")) ||
/* Hide the unit if it is DCS controlled and DCS controlled units are hidden */
(this.#controlled == false && hiddenTypes.includes("dcs")) ||
/* Hide the unit if this specific category is hidden */
(hiddenTypes.includes(this.getMarkerCategory())) ||
/* Hide the unit if this coalition is hidden */
(hiddenTypes.includes(this.#coalition)) ||
/* Hide the unit if it does not belong to the commanded coalition and it is not detected by a method that can pinpoint its location (RWR does not count) */
(!this.belongsToCommandedCoalition() && (this.#detectionMethods.length == 0 || (this.#detectionMethods.length == 1 && this.#detectionMethods[0] === RWR))) ||
(getApp().getMap().getVisibilityOptions()[HIDE_GROUP_MEMBERS] && !this.#isLeader && this.getCategory() == "GroundUnit" && getApp().getMap().getZoom() < 13 && (this.belongsToCommandedCoalition() || (!this.belongsToCommandedCoalition() && this.#detectionMethods.length == 0)))) &&
!(this.getSelected());
/* Hide the unit if grouping is activated, the unit is not the group leader, it is not selected, and the zoom is higher than the grouping threshold */
(getApp().getMap().getVisibilityOptions()[HIDE_GROUP_MEMBERS] && !this.#isLeader && this.getCategory() == "GroundUnit" && getApp().getMap().getZoom() < GROUPING_ZOOM_TRANSITION &&
(this.belongsToCommandedCoalition() || (!this.belongsToCommandedCoalition() && this.#detectionMethods.length == 0)))) &&
!(this.getSelected()
);
/* Force dead units to be hidden */
this.setHidden(hidden || !this.#alive);
}
@@ -675,6 +674,7 @@ export class Unit extends CustomMarker {
getApp().getMap().removeLayer(this);
}
/* Draw the range circles if the unit is not hidden */
if (!this.getHidden()) {
/* Circles don't like to be updated when the map is zooming */
if (!getApp().getMap().isZooming())
@@ -714,7 +714,7 @@ export class Unit extends CustomMarker {
if (typeof (roles) === "string")
roles = [roles];
var loadouts = this.getDatabase()?.getByName(this.#name)?.loadouts;
var loadouts = this.getDatabaseEntry()?.loadouts;
if (loadouts) {
return loadouts.some((loadout: LoadoutBlueprint) => {
return (roles as string[]).some((role: string) => { return loadout.roles.includes(role) });
@@ -728,11 +728,11 @@ export class Unit extends CustomMarker {
}
canTargetPoint() {
return this.getDatabase()?.getByName(this.#name)?.canTargetPoint === true;
return this.getDatabaseEntry()?.canTargetPoint === true;
}
canRearm() {
return this.getDatabase()?.getByName(this.#name)?.canRearm === true;
return this.getDatabaseEntry()?.canRearm === true;
}
canLandAtPoint() {
@@ -740,11 +740,11 @@ export class Unit extends CustomMarker {
}
canAAA() {
return this.getDatabase()?.getByName(this.#name)?.canAAA === true;
return this.getDatabaseEntry()?.canAAA === true;
}
indirectFire() {
return this.getDatabase()?.getByName(this.#name)?.indirectFire === true;
return this.getDatabaseEntry()?.indirectFire === true;
}
isTanker() {
@@ -933,11 +933,6 @@ export class Unit extends CustomMarker {
}
/***********************************************/
getActions(): { [key: string]: { text: string, tooltip: string, type: string } } {
/* To be implemented by child classes */ // TODO make Unit an abstract class
return {};
}
executeAction(e: any, action: string) {
if (action === "center-map")
getApp().getMap().centerOnUnit(this.ID);
@@ -963,18 +958,15 @@ export class Unit extends CustomMarker {
/***********************************************/
#onClick(e: any) {
// Exit if we were waiting for a doubleclick
/* Exit if we were waiting for a doubleclick */
if (this.#waitingForDoubleClick) {
return;
}
// We'll wait for a doubleclick
/* We'll wait for a doubleclick */
this.#waitingForDoubleClick = true;
this.#doubleClickTimer = window.setTimeout(() => {
// Still waiting so no doubleclick; do the click action
/* Still waiting so no doubleclick; do the click action */
if (this.#waitingForDoubleClick) {
if (getApp().getMap().getState() === IDLE || getApp().getMap().getState() === MOVE_UNIT || e.originalEvent.ctrlKey) {
if (!e.originalEvent.ctrlKey)
@@ -984,17 +976,17 @@ export class Unit extends CustomMarker {
}
}
// No longer waiting for a doubleclick
/* No longer waiting for a doubleclick */
this.#waitingForDoubleClick = false;
}, 200);
}
#onDoubleClick(e: any) {
// Let single clicks work again
/* Let single clicks work again */
this.#waitingForDoubleClick = false;
clearTimeout(this.#doubleClickTimer);
// Select all matching units in the viewport
/* Select all matching units in the viewport */
const unitsManager = getApp().getUnitsManager();
Object.values(unitsManager.getUnits()).forEach((unit: Unit) => {
if (unit.getAlive() === true && unit.getName() === this.getName() && unit.isInViewport())
@@ -1226,6 +1218,11 @@ export class Unit extends CustomMarker {
if (hotgroupEl)
hotgroupEl.innerText = String(this.#hotgroup);
}
/* If the unit is a leader of a SAM Site, show the group as a SAM with the appropriate short label */
if (this.#isLeader) {
}
}
/* Set vertical offset for altitude stacking */
@@ -1234,6 +1231,11 @@ export class Unit extends CustomMarker {
}
}
#redrawMarker() {
this.removeFrom(getApp().getMap());
this.#updateMarker();
}
#drawPath() {
if (this.#activePath != undefined && getApp().getMap().getVisibilityOptions()[SHOW_UNIT_PATHS]) {
var points = [];
@@ -1446,12 +1448,21 @@ export class Unit extends CustomMarker {
this.#targetPositionPolyline.removeFrom(getApp().getMap());
}
#onZoom() {
#onZoom(e: any) {
if (this.checkRedraw()) {
this.#redrawMarker();
/* If the marker has been redrawn, reapply selection */
if (this.getSelected()) {
this.setSelected(false);
this.setSelected(true);
}
}
this.#updateMarker();
}
}
export class AirUnit extends Unit {
export abstract class AirUnit extends Unit {
getIconOptions() {
var belongsToCommandedCoalition = this.belongsToCommandedCoalition();
return {
@@ -1534,7 +1545,7 @@ export class GroundUnit extends Unit {
showHealth: true,
showHotgroup: belongsToCommandedCoalition,
showUnitIcon: (belongsToCommandedCoalition || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))),
showShortLabel: false,
showShortLabel: this.getDatabaseEntry()?.type === "SAM Site",
showFuel: false,
showAmmo: false,
showSummary: false,
@@ -1584,6 +1595,31 @@ export class GroundUnit extends Unit {
var blueprint = groundUnitDatabase.getByName(this.getName());
return blueprint?.type ? blueprint.type : "";
}
/* When a unit is a leader of a group, the map is zoomed out and grouping when zoomed out is enabled, check if the unit should be shown as a specific group. This is used to show a SAM battery instead of the group leader */
getDatabaseEntry() {
let unitWhenGrouped = null;
if (!this.getSelected() && this.getIsLeader() && getApp().getMap().getVisibilityOptions()[HIDE_GROUP_MEMBERS] && getApp().getMap().getZoom() < GROUPING_ZOOM_TRANSITION) {
unitWhenGrouped = this.getDatabase()?.getByName(this.getName())?.unitWhenGrouped ?? null;
let member = this.getGroupMembers().reduce((prev: Unit | null, unit: Unit, index: number) => {
if (unit.getDatabaseEntry()?.unitWhenGrouped != undefined)
return unit
return prev;
}, null);
unitWhenGrouped == member !== null ? member?.getDatabaseEntry()?.unitWhenGrouped : unitWhenGrouped;
}
if (unitWhenGrouped !== null)
return this.getDatabase()?.getByName(unitWhenGrouped);
else
return this.getDatabase()?.getByName(this.getName());
}
/* When we zoom past the grouping limit, grouping is enabled and the unit is a leader, we redraw the unit to apply any possible grouped marker */
checkRedraw(): boolean {
return (this.getIsLeader() && getApp().getMap().getVisibilityOptions()[HIDE_GROUP_MEMBERS] &&
(getApp().getMap().getZoom() >= GROUPING_ZOOM_TRANSITION && getApp().getMap().getPreviousZoom() < GROUPING_ZOOM_TRANSITION ||
getApp().getMap().getZoom() < GROUPING_ZOOM_TRANSITION && getApp().getMap().getPreviousZoom() >= GROUPING_ZOOM_TRANSITION))
}
}
export class NavyUnit extends Unit {