mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
361 lines
12 KiB
TypeScript
361 lines
12 KiB
TypeScript
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}`);
|
|
}
|
|
} |