import { LatLng, LatLngBounds } from "leaflet"; import { getInfoPopup, getMap, getUnitDataTable } from ".."; import { Unit } from "./unit"; import { cloneUnit } from "../server/server"; import { IDLE, MOVE_UNIT } from "../map/map"; import { keyEventWasInInput } from "../other/utils"; export class UnitsManager { #units: { [ID: number]: Unit }; #copiedUnits: Unit[]; #selectionEventDisabled: boolean = false; #pasteDisabled: boolean = false; constructor() { this.#units = {}; this.#copiedUnits = []; document.addEventListener('copy', () => this.copyUnits()); document.addEventListener('paste', () => this.pasteUnits()); document.addEventListener('unitSelection', (e: CustomEvent) => this.#onUnitSelection(e.detail)); document.addEventListener('unitDeselection', (e: CustomEvent) => this.#onUnitDeselection(e.detail)); document.addEventListener('keydown', (event) => this.#onKeyDown(event)); document.addEventListener('deleteSelectedUnits', () => this.selectedUnitsDelete() ) } getUnits() { return this.#units; } getUnitByID(ID: number) { if (ID in this.#units) return this.#units[ID]; else return null; } addUnit(ID: number, data: UnitData) { /* The name of the unit category is exactly the same as the constructor name */ var constructor = Unit.getConstructor(data.baseData.category); if (constructor != undefined) { this.#units[ID] = new constructor(ID, data); } } removeUnit(ID: number) { } update(data: UnitsData) { Object.keys(data.units) .filter((ID: string) => !(ID in this.#units)) .reduce((timeout: number, ID: string) => { setTimeout(() => { if (!(ID in this.#units)) this.addUnit(parseInt(ID), data.units[ID]); this.#units[parseInt(ID)]?.setData(data.units[ID]); }, timeout); return timeout + 10; }, 10); Object.keys(data.units) .filter((ID: string) => ID in this.#units) .forEach((ID: string) => this.#units[parseInt(ID)]?.setData(data.units[ID])); } selectUnit(ID: number, deselectAllUnits: boolean = true) { if (deselectAllUnits) this.getSelectedUnits().filter((unit: Unit) => unit.ID !== ID ).forEach((unit: Unit) => unit.setSelected(false)); this.#units[ID]?.setSelected(true); } selectFromBounds(bounds: LatLngBounds) { this.deselectAllUnits(); for (let ID in this.#units) { if (this.#units[ID].getHidden() == false) { var latlng = new LatLng(this.#units[ID].getFlightData().latitude, this.#units[ID].getFlightData().longitude); if (bounds.contains(latlng)) { this.#units[ID].setSelected(true); } } } } getSelectedUnits() { var selectedUnits = []; for (let ID in this.#units) { if (this.#units[ID].getSelected()) { selectedUnits.push(this.#units[ID]); } } return selectedUnits; } deselectAllUnits() { for (let ID in this.#units) { this.#units[ID].setSelected(false); } } getSelectedLeaders() { var leaders: Unit[] = []; for (let idx in this.getSelectedUnits()) { var unit = this.getSelectedUnits()[idx]; if (unit.getFormationData().isLeader) leaders.push(unit); else if (unit.getFormationData().isWingman) { var leader = unit.getLeader(); if (leader && !leaders.includes(leader)) leaders.push(leader); } } return leaders; } getSelectedSingletons() { var singletons: Unit[] = []; for (let idx in this.getSelectedUnits()) { var unit = this.getSelectedUnits()[idx]; if (!unit.getFormationData().isLeader && !unit.getFormationData().isWingman) singletons.push(unit); } return singletons; } getSelectedUnitsType () { if (this.getSelectedUnits().length == 0) return undefined; return this.getSelectedUnits().map((unit: Unit) => { return unit.constructor.name })?.reduce((a: any, b: any) => { return a == b? a: undefined }); }; getSelectedUnitsTargetSpeed () { if (this.getSelectedUnits().length == 0) return undefined; return this.getSelectedUnits().map((unit: Unit) => { return unit.getTaskData().targetSpeed })?.reduce((a: any, b: any) => { return a == b? a: undefined }); }; getSelectedUnitsTargetAltitude () { if (this.getSelectedUnits().length == 0) return undefined; return this.getSelectedUnits().map((unit: Unit) => { return unit.getTaskData().targetAltitude })?.reduce((a: any, b: any) => { return a == b? a: undefined }); }; getSelectedUnitsCoalition () { if (this.getSelectedUnits().length == 0) return undefined; return this.getSelectedUnits().map((unit: Unit) => { return unit.getMissionData().coalition })?.reduce((a: any, b: any) => { return a == b? a: undefined }); }; selectedUnitsAddDestination(latlng: L.LatLng) { var selectedUnits = this.getSelectedUnits(); for (let idx in selectedUnits) { var commandedUnit = selectedUnits[idx]; commandedUnit.addDestination(latlng); } this.#showActionMessage(selectedUnits, " new destination added"); } selectedUnitsClearDestinations() { var selectedUnits = this.getSelectedUnits(); for (let idx in selectedUnits) { var commandedUnit = selectedUnits[idx]; commandedUnit.clearDestinations(); } } selectedUnitsLandAt(latlng: LatLng) { var selectedUnits = this.getSelectedUnits(); for (let idx in selectedUnits) { selectedUnits[idx].landAt(latlng); } this.#showActionMessage(selectedUnits, " landing"); } selectedUnitsChangeSpeed(speedChange: string) { var selectedUnits = this.getSelectedUnits(); for (let idx in selectedUnits) { selectedUnits[idx].changeSpeed(speedChange); } } selectedUnitsChangeAltitude(altitudeChange: string) { var selectedUnits = this.getSelectedUnits(); for (let idx in selectedUnits) { selectedUnits[idx].changeAltitude(altitudeChange); } } selectedUnitsSetSpeed(speed: number) { var selectedUnits = this.getSelectedUnits(); for (let idx in selectedUnits) { selectedUnits[idx].setSpeed(speed); } this.#showActionMessage(selectedUnits, `setting speed to ${speed * 1.94384} kts`); } selectedUnitsSetAltitude(altitude: number) { var selectedUnits = this.getSelectedUnits(); for (let idx in selectedUnits) { selectedUnits[idx].setAltitude(altitude); } this.#showActionMessage(selectedUnits, `setting altitude to ${altitude / 0.3048} ft`); } selectedUnitsSetROE(ROE: string) { var selectedUnits = this.getSelectedUnits(); for (let idx in selectedUnits) { selectedUnits[idx].setROE(ROE); } this.#showActionMessage(selectedUnits, `ROE set to ${ROE}`); } selectedUnitsSetReactionToThreat(reactionToThreat: string) { var selectedUnits = this.getSelectedUnits(); for (let idx in selectedUnits) { selectedUnits[idx].setReactionToThreat(reactionToThreat); } this.#showActionMessage(selectedUnits, `reaction to threat set to ${reactionToThreat}`); } selectedUnitsAttackUnit(ID: number) { var selectedUnits = this.getSelectedUnits(); for (let idx in selectedUnits) { selectedUnits[idx].attackUnit(ID); } this.#showActionMessage(selectedUnits, `attacking unit ${this.getUnitByID(ID)?.getBaseData().unitName}`); } selectedUnitsDelete() { var selectedUnits = this.getSelectedUnits(); for (let idx in selectedUnits) { selectedUnits[idx].delete(); } this.#showActionMessage(selectedUnits, `deleted`); } selectedUnitsRefuel() { var selectedUnits = this.getSelectedUnits(); for (let idx in selectedUnits) { selectedUnits[idx].refuel(); } this.#showActionMessage(selectedUnits, `sent to nearest tanker`); } selectedUnitsFollowUnit(ID: number, offset: {"x": number, "y": number, "z": number}) { var selectedUnits = this.getSelectedUnits(); var count = 1; for (let idx in selectedUnits) { var commandedUnit = selectedUnits[idx]; commandedUnit.followUnit(ID, {"x": offset.x * count, "y": offset.y * count, "z": offset.z * count} ); count++; } this.#showActionMessage(selectedUnits, `following unit ${this.getUnitByID(ID)?.getBaseData().unitName}`); } copyUnits() { this.#copiedUnits = this.getSelectedUnits(); this.#showActionMessage(this.#copiedUnits, `copied`); } pasteUnits() { if (!this.#pasteDisabled) { for (let idx in this.#copiedUnits) { var unit = this.#copiedUnits[idx]; cloneUnit(unit.ID, getMap().getMouseCoordinates()); this.#showActionMessage(this.#copiedUnits, `pasted`); } this.#pasteDisabled = true; setTimeout(() => this.#pasteDisabled = false, 250); } } #onKeyDown(event: KeyboardEvent) { if ( !keyEventWasInInput( event ) && event.key === "Delete") { this.selectedUnitsDelete(); } } #onUnitSelection(unit: Unit) { if (this.getSelectedUnits().length > 0) { getMap().setState(MOVE_UNIT); /* Disable the firing of the selection event for a certain amount of time. This avoids firing many events if many units are selected */ if (!this.#selectionEventDisabled) { setTimeout(() => { document.dispatchEvent(new CustomEvent("unitsSelection", {detail: this.getSelectedUnits()})); this.#selectionEventDisabled = false; }, 100); this.#selectionEventDisabled = true; } } else { getMap().setState(IDLE); document.dispatchEvent(new CustomEvent("clearSelection")); } } #onUnitDeselection(unit: Unit) { if (this.getSelectedUnits().length == 0) { getMap().setState(IDLE); document.dispatchEvent(new CustomEvent("clearSelection")); } else document.dispatchEvent(new CustomEvent("unitsDeselection", {detail: this.getSelectedUnits()})); } #showActionMessage(units: Unit[], message: string) { if (units.length == 1) getInfoPopup().setText(`${units[0].getBaseData().unitName} ${message}`); else getInfoPopup().setText(`${units[0].getBaseData().unitName} and ${units.length - 1} other units ${message}`); } }