mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Added unit marker to database and implemented better grouping
This commit is contained in:
@@ -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;
|
||||
@@ -231,6 +231,7 @@ export interface UnitBlueprint {
|
||||
canAAA?: boolean;
|
||||
indirectFire?: boolean;
|
||||
markerFile?: string;
|
||||
unitWhenGrouped?: string;
|
||||
}
|
||||
|
||||
export interface UnitSpawnOptions {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user