Added logs on client

Airplanes are now shown with silhouettes
This commit is contained in:
Pax1601
2023-02-20 18:17:54 +01:00
parent ef1785365c
commit abf5f40020
49 changed files with 672 additions and 489 deletions

View File

@@ -6,12 +6,11 @@ import { UnitInfoPanel } from "./panels/unitinfopanel";
import { SelectionScroll } from "./controls/selectionscroll";
import { Dropdown } from "./controls/dropdown";
import { ConnectionStatusPanel } from "./panels/connectionstatuspanel";
import { Button } from "./controls/button";
import { MissionData } from "./missiondata/missiondata";
import { UnitControlPanel } from "./panels/unitcontrolpanel";
import { MouseInfoPanel } from "./panels/mouseInfoPanel";
import { Slider } from "./controls/slider";
import { VisibilityControlPanel } from "./panels/visibilitycontrolpanel";
import { LogPanel } from "./panels/logpanel";
/* TODO: should this be a class? */
var map: Map;
@@ -26,18 +25,10 @@ var connectionStatusPanel: ConnectionStatusPanel;
var unitControlPanel: UnitControlPanel;
var mouseInfoPanel: MouseInfoPanel;
var visibilityControlPanel: VisibilityControlPanel;
var logPanel: LogPanel;
var scenarioDropdown: Dropdown;
var mapSourceDropdown: Dropdown;
var slowButton: Button;
var fastButton: Button;
var climbButton: Button;
var descendButton: Button;
var altitudeSlider: Slider;
var airspeedSlider: Slider;
var connected: boolean;
var activeCoalition: string;
@@ -45,6 +36,7 @@ function setup() {
/* Initialize */
map = new Map('map-container');
unitsManager = new UnitsManager();
missionData = new MissionData();
selectionWheel = new SelectionWheel("selection-wheel");
selectionScroll = new SelectionScroll("selection-scroll");
@@ -54,22 +46,10 @@ function setup() {
connectionStatusPanel = new ConnectionStatusPanel("connection-status-panel");
mouseInfoPanel = new MouseInfoPanel("mouse-info-panel");
visibilityControlPanel = new VisibilityControlPanel("visibility-control-panel");
logPanel = new LogPanel("log-panel");
scenarioDropdown = new Dropdown("scenario-dropdown", ["Caucasus", "Syria", "Marianas", "Nevada", "South Atlantic", "The channel"], () => { });
mapSourceDropdown = new Dropdown("map-source-dropdown", map.getLayers(), (option: string) => map.setLayer(option));
missionData = new MissionData();
/* Unit control buttons */
slowButton = new Button("slow-button", ["images/buttons/slow.svg"], () => { getUnitsManager().selectedUnitsChangeSpeed("slow"); });
fastButton = new Button("fast-button", ["images/buttons/fast.svg"], () => { getUnitsManager().selectedUnitsChangeSpeed("fast"); });
climbButton = new Button("climb-button", ["images/buttons/climb.svg"], () => { getUnitsManager().selectedUnitsChangeAltitude("climb"); });
descendButton = new Button("descend-button", ["images/buttons/descend.svg"], () => { getUnitsManager().selectedUnitsChangeAltitude("descend"); });
/* Unit control sliders */
altitudeSlider = new Slider("altitude-slider", 0, 100, "ft", (value: number) => getUnitsManager().selectedUnitsSetAltitude(value * 0.3048));
airspeedSlider = new Slider("airspeed-slider", 0, 100, "kts", (value: number) => getUnitsManager().selectedUnitsSetSpeed(value / 1.94384));
/* Default values */
activeCoalition = "blue";
connected = false;
@@ -87,6 +67,7 @@ function requestUpdate() {
export function update(data: JSON) {
unitsManager.update(data);
missionData.update(data);
logPanel.update(data);
}
export function getMap() {
@@ -137,8 +118,4 @@ export function getConnected() {
return connected;
}
export function getUnitControlSliders() {
return {altitude: altitudeSlider, airspeed: airspeedSlider}
}
window.onload = setup;

View File

@@ -2,7 +2,7 @@ import * as L from "leaflet"
import { getSelectionWheel, getSelectionScroll, getUnitsManager, getActiveCoalition, getMouseInfoPanel } from "..";
import { spawnAircraft, spawnGroundUnit, spawnSmoke } from "../dcs/dcs";
import { bearing, distance, zeroAppend } from "../other/utils";
import { aircraftDatabase, getAircraftLabelsByRole, getLoadoutsByName, getLoadoutNamesByRole } from "../units/aircraftDatabase";
import { aircraftDatabase, getAircraftLabelsByRole, getLoadoutsByName, getLoadoutNamesByRole, getAircraftNameByLabel } from "../units/aircraftDatabase";
import { unitTypes } from "../units/unitTypes";
import { BoxSelect } from "./boxselect";
@@ -46,7 +46,7 @@ export class Map extends L.Map {
this.#measureIcon = new L.Icon({ iconUrl: 'images/pin.png', iconAnchor: [16, 32]});
this.#measureMarker = new L.Marker([0, 0], {icon: this.#measureIcon, interactive: false});
this.#measureLineDiv = document.createElement("div");
this.#measureLineDiv.classList.add("measure-box");
this.#measureLineDiv.classList.add("ol-measure-box");
this.#measureLineDiv.style.display = 'none';
document.body.appendChild(this.#measureLineDiv);
@@ -324,10 +324,12 @@ export class Map extends L.Map {
this.hideSelectionWheel();
this.hideSelectionScroll();
var options = getAircraftLabelsByRole(role);
this.showSelectionScroll(e, "Select aircraft", options, (unitType: string) => {
this.showSelectionScroll(e, "Select aircraft", options, (label: string) => {
this.hideSelectionWheel();
this.hideSelectionScroll();
this.#unitSelectPayload(e, unitType, role);
var name = getAircraftNameByLabel(label);
if (name != null)
this.#unitSelectPayload(e, name, role);
}, true);
}

View File

@@ -1,24 +1,22 @@
export class ConnectionStatusPanel {
#element: HTMLElement
import { Panel } from "./panel";
export class ConnectionStatusPanel extends Panel {
constructor(ID: string) {
this.#element = <HTMLElement>document.getElementById(ID);
super(ID);
}
update(connected: boolean) {
if (this.#element != null) {
var div = this.#element.querySelector("#status-string");
if (div != null) {
if (connected) {
div.innerHTML = "Connected";
div.classList.add("ol-status-connected");
div.classList.remove("ol-status-disconnected");
}
else {
div.innerHTML = "Disconnected";
div.classList.add("ol-status-disconnected");
div.classList.remove("ol-status-connected");
}
var div = this.getElement().querySelector("#status-string");
if (div != null) {
if (connected) {
div.innerHTML = "Connected";
div.classList.add("ol-status-connected");
div.classList.remove("ol-status-disconnected");
}
else {
div.innerHTML = "Disconnected";
div.classList.add("ol-status-disconnected");
div.classList.remove("ol-status-connected");
}
}
}

View File

@@ -0,0 +1,28 @@
import { Panel } from "./panel";
export class LogPanel extends Panel
{
#logs: String[];
constructor(ID: string)
{
super(ID);
this.#logs = [];
}
update(data: any)
{
var logs = data["logs"];
for (let idx in logs)
{
if (parseInt(idx) >= this.#logs.length) {
this.#logs.push(logs[idx]);
var el = document.createElement("div");
el.innerHTML = logs[idx];
el.classList.add("js-log-element", "ol-log-element");
this.getElement().appendChild(el);
this.getElement().scrollTop = this.getElement().scrollHeight;
}
}
}
}

View File

@@ -1,28 +1,11 @@
import { LatLng } from "leaflet";
import { getMissionData } from "..";
import { distance, bearing, zeroPad, zeroAppend } from "../other/utils";
import { Unit } from "../units/unit";
export class MouseInfoPanel {
#element: HTMLElement
#display: string;
import { Panel } from "./panel";
export class MouseInfoPanel extends Panel {
constructor(ID: string) {
this.#element = <HTMLElement>document.getElementById(ID);
this.#display = '';
if (this.#element != null) {
this.#display = this.#element.style.display;
var el = <HTMLElement>this.#element.querySelector(`#measure-position`);
this.show();
}
}
show() {
this.#element.style.display = this.#display;
}
hide() {
this.#element.style.display = "none";
super(ID);
}
update(mousePosition: LatLng, measurePosition: LatLng | null, unitPosition: LatLng | null) {
@@ -31,7 +14,7 @@ export class MouseInfoPanel {
{
var dist = distance(bullseyes[idx].lat, bullseyes[idx].lng, mousePosition.lat, mousePosition.lng);
var bear = bearing(bullseyes[idx].lat, bullseyes[idx].lng, mousePosition.lat, mousePosition.lng);
var el = <HTMLElement>this.#element.querySelector(`#bullseye-${idx}`);
var el = <HTMLElement>this.getElement().querySelector(`#bullseye-${idx}`);
if (el != null)
el.innerHTML = `${zeroAppend(Math.floor(bear), 3)}° / ${zeroAppend(Math.floor(dist*0.000539957), 3)} NM`
}
@@ -39,16 +22,16 @@ export class MouseInfoPanel {
if (measurePosition) {
var dist = distance(measurePosition.lat, measurePosition.lng, mousePosition.lat, mousePosition.lng);
var bear = bearing(measurePosition.lat, measurePosition.lng, mousePosition.lat, mousePosition.lng);
var el = <HTMLElement>this.#element.querySelector(`#measure-position`);
var el = <HTMLElement>this.getElement().querySelector(`#measure-position`);
if (el != null)
{
el.innerHTML = `${zeroAppend(Math.floor(bear), 3)}° / ${zeroAppend(Math.floor(dist*0.000539957), 3)} NM`
if (el.parentElement != null)
el.parentElement.style.display = 'flex'; //TODO: don't like that its hardcoded
el.parentElement.style.display = 'flex'; //TODO: don't like that it's hardcoded
}
}
else {
var el = <HTMLElement>this.#element.querySelector(`#measure-position`);
var el = <HTMLElement>this.getElement().querySelector(`#measure-position`);
if (el != null && el.parentElement != null)
el.parentElement.style.display = 'none';
}
@@ -56,7 +39,7 @@ export class MouseInfoPanel {
if (unitPosition) {
var dist = distance(unitPosition.lat, unitPosition.lng, mousePosition.lat, mousePosition.lng);
var bear = bearing(unitPosition.lat, unitPosition.lng, mousePosition.lat, mousePosition.lng);
var el = <HTMLElement>this.#element.querySelector(`#unit-position`);
var el = <HTMLElement>this.getElement().querySelector(`#unit-position`);
if (el != null)
{
el.innerHTML = `${zeroAppend(Math.floor(bear), 3)}° / ${zeroAppend(Math.floor(dist*0.000539957), 3)} NM`
@@ -65,7 +48,7 @@ export class MouseInfoPanel {
}
}
else {
var el = <HTMLElement>this.#element.querySelector(`#unit-position`);
var el = <HTMLElement>this.getElement().querySelector(`#unit-position`);
if (el != null && el.parentElement != null)
el.parentElement.style.display = 'none';
}

View File

@@ -0,0 +1,22 @@
export class Panel {
#element: HTMLElement
#display: string;
constructor(ID: string) {
this.#element = <HTMLElement>document.getElementById(ID);
this.#display = '';
this.#display = this.#element.style.display;
}
show() {
this.#element.style.display = this.#display;
}
hide() {
this.#element.style.display = "none";
}
getElement() {
return this.#element;
}
}

View File

@@ -1,159 +1,155 @@
import { imageOverlay } from "leaflet";
import { getUnitControlSliders, getUnitsManager } from "..";
import { ConvertDDToDMS, rad2deg } from "../other/utils";
import { getUnitsManager } from "..";
import { Slider } from "../controls/slider";
import { Aircraft, AirUnit, GroundUnit, Helicopter, NavyUnit, Unit } from "../units/unit";
import { Panel } from "./panel";
export class UnitControlPanel {
#element: HTMLElement
#display: string;
interface Button {
id: string,
value: string,
element: null | HTMLElement
}
export class UnitControlPanel extends Panel {
#altitudeSlider: Slider;
#airspeedSlider: Slider;
#formationCreationContainer: HTMLElement;
#ROEButtonsContainer: HTMLElement;
#reactionToThreatButtonsContainer: HTMLElement;
#selectedUnitsContainer: HTMLElement;
#ROEButtons: Button[] = [
{id: "#free", value: "Free", element: null},
{id: "#designated-free", value: "Designated free", element: null},
{id: "#designated", value: "Designated", element: null},
{id: "#return", value: "Return", element: null},
{id: "#hold", value: "Hold", element: null}
]
#reactionToThreatButtons: Button[] = [
{id: "#none", value: "None", element: null},
{id: "#passive", value: "Passive", element: null},
{id: "#evade", value: "Evade", element: null},
{id: "#escape", value: "Escape", element: null},
{id: "#abort", value: "Abort", element: null}
]
constructor(ID: string) {
this.#element = <HTMLElement>document.getElementById(ID);
this.#display = '';
if (this.#element != null) {
this.#display = this.#element.style.display;
var formationCreationContainer = <HTMLElement>(this.#element.querySelector("#formation-creation-container"));
if (formationCreationContainer != null)
{
var createButton = <HTMLElement>formationCreationContainer.querySelector("#create-formation");
createButton?.addEventListener("click", () => getUnitsManager().selectedUnitsCreateFormation());
super(ID);
var undoButton = <HTMLElement>formationCreationContainer.querySelector("#undo-formation");
undoButton?.addEventListener("click", () => getUnitsManager().selectedUnitsUndoFormation());
}
var ROEButtonsContainer = <HTMLElement>(this.#element.querySelector("#roe-buttons-container"));
if (ROEButtonsContainer != null)
{
(<HTMLElement>ROEButtonsContainer.querySelector("#free"))?.addEventListener("click", () => getUnitsManager().selectedUnitsSetROE("Free"));
(<HTMLElement>ROEButtonsContainer.querySelector("#designated-free"))?.addEventListener("click", () => getUnitsManager().selectedUnitsSetROE("Designated free"));
(<HTMLElement>ROEButtonsContainer.querySelector("#designated"))?.addEventListener("click", () => getUnitsManager().selectedUnitsSetROE("Designated"));
(<HTMLElement>ROEButtonsContainer.querySelector("#return"))?.addEventListener("click", () => getUnitsManager().selectedUnitsSetROE("Return"));
(<HTMLElement>ROEButtonsContainer.querySelector("#hold"))?.addEventListener("click", () => getUnitsManager().selectedUnitsSetROE("Hold"));
}
/* Selected units container */
this.#selectedUnitsContainer = <HTMLElement>(this.getElement().querySelector("#selected-units-container"));
var reactionToThreatButtonsContainer = <HTMLElement>(this.#element.querySelector("#reaction-to-threat-buttons-container"));
if (reactionToThreatButtonsContainer != null)
{
(<HTMLElement>reactionToThreatButtonsContainer.querySelector("#none"))?.addEventListener("click", () => getUnitsManager().selectedUnitsSetReactionToThreat("None"));
(<HTMLElement>reactionToThreatButtonsContainer.querySelector("#passive"))?.addEventListener("click", () => getUnitsManager().selectedUnitsSetReactionToThreat("Passive"));
(<HTMLElement>reactionToThreatButtonsContainer.querySelector("#evade"))?.addEventListener("click", () => getUnitsManager().selectedUnitsSetReactionToThreat("Evade"));
(<HTMLElement>reactionToThreatButtonsContainer.querySelector("#escape"))?.addEventListener("click", () => getUnitsManager().selectedUnitsSetReactionToThreat("Escape"));
(<HTMLElement>reactionToThreatButtonsContainer.querySelector("#abort"))?.addEventListener("click", () => getUnitsManager().selectedUnitsSetReactionToThreat("Abort"));
}
this.hide();
/* Unit control sliders */
this.#altitudeSlider = new Slider("altitude-slider", 0, 100, "ft", (value: number) => getUnitsManager().selectedUnitsSetAltitude(value * 0.3048));
this.#airspeedSlider = new Slider("airspeed-slider", 0, 100, "kts", (value: number) => getUnitsManager().selectedUnitsSetSpeed(value / 1.94384));
/* Formation control buttons */
this.#formationCreationContainer = <HTMLElement>(this.getElement().querySelector("#formation-creation-container"));
//var createButton = <HTMLElement>this.#formationCreationContainer.querySelector("#create-formation");
//createButton?.addEventListener("click", () => getUnitsManager().selectedUnitsCreateFormation());
//var undoButton = <HTMLElement>this.#formationCreationContainer.querySelector("#undo-formation");
//undoButton?.addEventListener("click", () => getUnitsManager().selectedUnitsUndoFormation());
/* ROE buttons */
this.#ROEButtonsContainer = <HTMLElement>(this.getElement().querySelector("#roe-buttons-container"));
for (let button of this.#ROEButtons)
{
button.element = <HTMLElement>(this.#ROEButtonsContainer.querySelector(button.id));
button.element?.addEventListener("click", () => getUnitsManager().selectedUnitsSetROE(button.value));
}
/* Reaction to threat buttons */
this.#reactionToThreatButtonsContainer = <HTMLElement>(this.getElement().querySelector("#reaction-to-threat-buttons-container"));
for (let button of this.#reactionToThreatButtons)
{
button.element = <HTMLElement>(this.#reactionToThreatButtonsContainer.querySelector(button.id));
button.element?.addEventListener("click", () => getUnitsManager().selectedUnitsSetReactionToThreat(button.value));
}
}
show() {
this.#element.style.display = this.#display;
}
hide() {
this.#element.style.display = "none";
this.hide();
}
update(units: Unit[]) {
if (this.#element != null)
if (this.getElement() != null)
{
var selectedUnitsContainer = <HTMLElement>(this.#element.querySelector("#selected-units-container"));
var formationCreationContainer = <HTMLElement>(this.#element.querySelector("#formation-creation-container"));
if (selectedUnitsContainer != null && formationCreationContainer != null)
{
this.#addUnitsButtons(units, selectedUnitsContainer);
this.#showFlightControlSliders(units);
this.#showFormationButtons(units, formationCreationContainer);
}
//this.#addUnitsButtons(units);
//this.#showFormationButtons(units);
this.#showFlightControlSliders(units);
var ROEButtonsContainer = <HTMLElement>(this.#element.querySelector("#roe-buttons-container"));
if (ROEButtonsContainer != null)
{
(<HTMLElement>ROEButtonsContainer.querySelector("#free"))?.classList.toggle("white", this.#getROE(units) === "Free");
(<HTMLElement>ROEButtonsContainer.querySelector("#designated-free"))?.classList.toggle("white", this.#getROE(units) === "Designated free");
(<HTMLElement>ROEButtonsContainer.querySelector("#designated"))?.classList.toggle("white", this.#getROE(units) === "Designated");
(<HTMLElement>ROEButtonsContainer.querySelector("#return"))?.classList.toggle("white", this.#getROE(units) === "Return");
(<HTMLElement>ROEButtonsContainer.querySelector("#hold"))?.classList.toggle("white", this.#getROE(units) === "Hold");
}
var reactionToThreatButtonsContainer = <HTMLElement>(this.#element.querySelector("#reaction-to-threat-buttons-container"));
if (reactionToThreatButtonsContainer != null)
{
(<HTMLElement>reactionToThreatButtonsContainer.querySelector("#none"))?.classList.toggle("white", this.#getReactionToThreat(units) === "None");
(<HTMLElement>reactionToThreatButtonsContainer.querySelector("#passive"))?.classList.toggle("white", this.#getReactionToThreat(units) === "Passive");
(<HTMLElement>reactionToThreatButtonsContainer.querySelector("#evade"))?.classList.toggle("white", this.#getReactionToThreat(units) === "Evade");
(<HTMLElement>reactionToThreatButtonsContainer.querySelector("#escape"))?.classList.toggle("white", this.#getReactionToThreat(units) === "Escape");
(<HTMLElement>reactionToThreatButtonsContainer.querySelector("#abort"))?.classList.toggle("white", this.#getReactionToThreat(units) === "Abort");
}
for (let button of this.#ROEButtons)
button.element?.classList.toggle("white", this.#getROE(units) === button.value);
for (let button of this.#reactionToThreatButtons)
button.element?.classList.toggle("white", this.#getReactionToThreat(units) === button.value);
}
}
#showFlightControlSliders(units: Unit[])
{
var sliders = getUnitControlSliders();
sliders.airspeed.show();
sliders.altitude.show();
this.#airspeedSlider.show();
this.#altitudeSlider.show();
if (this.#checkAllUnitsAircraft(units))
{
sliders.airspeed.setMinMax(100, 600);
sliders.altitude.setMinMax(0, 50000);
this.#airspeedSlider.setMinMax(100, 600);
this.#altitudeSlider.setMinMax(0, 50000);
}
else if (this.#checkAllUnitsHelicopter(units))
{
sliders.airspeed.setMinMax(0, 200);
sliders.altitude.setMinMax(0, 10000);
this.#airspeedSlider.setMinMax(0, 200);
this.#altitudeSlider.setMinMax(0, 10000);
}
else if (this.#checkAllUnitsGroundUnit(units))
{
sliders.airspeed.setMinMax(0, 60);
sliders.altitude.hide();
this.#airspeedSlider.setMinMax(0, 60);
this.#altitudeSlider.hide();
}
else if (this.#checkAllUnitsNavyUnit(units))
{
sliders.airspeed.setMinMax(0, 60);
sliders.altitude.hide();
this.#airspeedSlider.setMinMax(0, 60);
this.#altitudeSlider.hide();
}
else {
sliders.airspeed.hide();
sliders.altitude.hide();
this.#airspeedSlider.hide();
this.#altitudeSlider.hide();
}
var targetSpeed = this.#getTargetAirspeed(units);
if (targetSpeed != null)
{
sliders.airspeed.setActive(true);
sliders.airspeed.setValue(targetSpeed * 1.94384);
this.#airspeedSlider.setActive(true);
this.#airspeedSlider.setValue(targetSpeed * 1.94384);
}
else
{
sliders.airspeed.setActive(false);
this.#airspeedSlider.setActive(false);
}
var targetAltitude = this.#getTargetAltitude(units);
if (targetAltitude != null)
{
sliders.altitude.setActive(true);
sliders.altitude.setValue(targetAltitude / 0.3048);
this.#altitudeSlider.setActive(true);
this.#altitudeSlider.setValue(targetAltitude / 0.3048);
}
else
{
sliders.altitude.setActive(false);
this.#altitudeSlider.setActive(false);
}
}
#addUnitsButtons(units: Unit[], selectedUnitsContainer: HTMLElement)
#addUnitsButtons(units: Unit[])
{
/* Remove any pre-existing unit button */
var elements = selectedUnitsContainer.getElementsByClassName("js-unit-container");
var elements = this.#selectedUnitsContainer.getElementsByClassName("js-unit-container");
while (elements.length > 0)
selectedUnitsContainer.removeChild(elements[0])
this.#selectedUnitsContainer.removeChild(elements[0])
/* Create all the units buttons */
for (let unit of units)
{
this.#addUnitButton(unit, selectedUnitsContainer);
this.#addUnitButton(unit, this.#selectedUnitsContainer);
if (unit.isLeader)
for (let wingman of unit.getWingmen())
this.#addUnitButton(wingman, selectedUnitsContainer);
this.#addUnitButton(wingman, this.#selectedUnitsContainer);
}
}
@@ -163,7 +159,7 @@ export class UnitControlPanel {
/* Unit name (actually type, but DCS calls it name for some reason) */
var nameDiv = document.createElement("div");
nameDiv.classList.add("rounded-container-small");
nameDiv.classList.add("ol-rounded-container-small");
if (unit.name.length >= 7)
nameDiv.innerHTML = `${unit.name.substring(0, 4)} ...`;
else
@@ -193,36 +189,27 @@ export class UnitControlPanel {
if ((unit instanceof AirUnit))
el.append(icon);
el.classList.add("rounded-container", "js-unit-container");
el.classList.add("ol-rounded-container", "js-unit-container");
if (!unit.getSelected())
el.classList.add("not-selected")
/* Set background color */
if (unit.coalitionID == 1)
{
el.classList.add("red");
icon.classList.add("red");
}
else if (unit.coalitionID == 2)
{
el.classList.add("blue");
icon.classList.add("blue");
}
else
{
el.classList.add("neutral");
icon.classList.add("neutral");
}
el.classList.toggle("red", unit.coalitionID == 1);
icon.classList.toggle("red", unit.coalitionID == 1);
el.classList.toggle("blue", unit.coalitionID == 2);
icon.classList.toggle("blue", unit.coalitionID == 2);
el.classList.toggle("neutral", unit.coalitionID == 0);
icon.classList.toggle("neutral", unit.coalitionID == 0);
el.addEventListener("click", () => getUnitsManager().selectUnit(unit.ID));
container.appendChild(el);
}
#showFormationButtons(units: Unit[], formationCreationContainer: HTMLElement)
#showFormationButtons(units: Unit[])
{
var createButton = <HTMLElement>formationCreationContainer.querySelector("#create-formation");
var undoButton = <HTMLElement>formationCreationContainer.querySelector("#undo-formation");
var createButton = <HTMLElement>this.#formationCreationContainer.querySelector("#create-formation");
var undoButton = <HTMLElement>this.#formationCreationContainer.querySelector("#undo-formation");
if (createButton && undoButton && this.#checkAllUnitsAir(units))
{
if (!this.#checkUnitsAlreadyInFormation(units))

View File

@@ -1,62 +1,75 @@
import { ConvertDDToDMS, rad2deg } from "../other/utils";
import { Unit } from "../units/unit";
import { Panel } from "./panel";
export class UnitInfoPanel {
#element: HTMLElement
#display: string;
export class UnitInfoPanel extends Panel {
#unitName: HTMLElement;
#groupName: HTMLElement;
#name: HTMLElement;
#heading: HTMLElement;
#altitude: HTMLElement;
#groundSpeed: HTMLElement;
#fuel: HTMLElement;
#latitude: HTMLElement;
#longitude: HTMLElement;
#task: HTMLElement;
#loadoutContainer: HTMLElement;
constructor(ID: string) {
this.#element = <HTMLElement>document.getElementById(ID);
this.#display = '';
if (this.#element != null) {
this.#display = this.#element.style.display;
this.hide();
}
}
super(ID);
show() {
this.#element.style.display = this.#display;
}
this.#unitName = <HTMLElement>(this.getElement().querySelector("#unit-name"));
this.#groupName= <HTMLElement>(this.getElement().querySelector("#group-name"));
this.#name = <HTMLElement>(this.getElement().querySelector("#name"));
this.#heading = <HTMLElement>(this.getElement().querySelector("#heading"));
this.#altitude = <HTMLElement>(this.getElement().querySelector("#altitude"));
this.#groundSpeed = <HTMLElement>(this.getElement().querySelector("#ground-speed"));
this.#fuel = <HTMLElement>(this.getElement().querySelector("#fuel"));
this.#latitude = <HTMLElement>(this.getElement().querySelector("#latitude"));
this.#longitude = <HTMLElement>(this.getElement().querySelector("#longitude"));
this.#task = <HTMLElement>(this.getElement().querySelector("#task"));
this.#loadoutContainer = <HTMLElement>(this.getElement().querySelector("#loadout-container"));
hide() {
this.#element.style.display = "none";
this.hide();
}
update(unit: Unit) {
if (this.#element != null) {
var els = this.#element.getElementsByClassName("js-loadout-element");
while (els.length > 0)
this.#element.querySelector("#loadout-container")?.removeChild(els[0]);
for (let index in unit.ammo) {
var ammo = unit.ammo[index];
var displayName = ammo.desc.displayName;
var amount = ammo.count;
var el = document.createElement("div")
el.classList.add("js-loadout-element", "rectangular-container-dark")
el.innerHTML = amount + "x" + displayName;
this.#element.querySelector("#loadout-container")?.appendChild(el);
}
if (this.getElement() != null) {
/* Set the unit info */
this.#unitName.innerHTML = unit.unitName;
this.#groupName.innerHTML = unit.groupName;
this.#name.innerHTML = unit.name;
this.#heading.innerHTML = String(Math.floor(rad2deg(unit.heading)) + " °");
this.#altitude.innerHTML = String(Math.floor(unit.altitude / 0.3048) + " ft");
this.#groundSpeed.innerHTML = String(Math.floor(unit.speed * 1.94384) + " kts");
this.#fuel.innerHTML = String(unit.fuel + "%");
this.#latitude.innerHTML = ConvertDDToDMS(unit.latitude, false);
this.#longitude.innerHTML = ConvertDDToDMS(unit.longitude, true);
this.#task.innerHTML = unit.currentTask !== ""? unit.currentTask: "No task";
this.#element.querySelector("#unit-name")!.innerHTML = unit.unitName;
this.#element.querySelector("#group-name")!.innerHTML = unit.groupName;
this.#element.querySelector("#name")!.innerHTML = unit.name;
this.#element.querySelector("#heading")!.innerHTML = String(Math.floor(rad2deg(unit.heading)) + " °");
this.#element.querySelector("#altitude")!.innerHTML = String(Math.floor(unit.altitude / 0.3048) + " ft");
this.#element.querySelector("#ground-speed")!.innerHTML = String(Math.floor(unit.speed * 1.94384) + " kts");
this.#element.querySelector("#fuel")!.innerHTML = String(unit.fuel + "%");
this.#element.querySelector("#latitude")!.innerHTML = ConvertDDToDMS(unit.latitude, false);
this.#element.querySelector("#longitude")!.innerHTML = ConvertDDToDMS(unit.longitude, true);
this.#element.querySelector("#task")!.innerHTML = unit.currentTask !== ""? unit.currentTask: "Not controlled";
this.#element.querySelector("#task")!.classList.remove("red", "blue", "neutral");
if (unit.coalitionID == 1)
this.#element.querySelector("#task")!.classList.add("red");
else if (unit.coalitionID == 2)
this.#element.querySelector("#task")!.classList.add("blue");
else
this.#element.querySelector("#task")!.classList.add("neutral");
/* Set the class of the task container */
this.#task.classList.toggle("red", unit.coalitionID == 1);
this.#task.classList.toggle("blue", unit.coalitionID == 2);
this.#task.classList.toggle("neutral", unit.coalitionID == 0);
/* Add the loadout elements */
var els = this.getElement().getElementsByClassName("js-loadout-element");
while (els.length > 0)
this.#loadoutContainer.removeChild(els[0]);
for (let index in unit.ammo)
this.#addLoadoutElement(unit, index);
}
}
#addLoadoutElement(unit: Unit, index: string)
{
var ammo = unit.ammo[index];
var displayName = ammo.desc.displayName;
var amount = ammo.count;
var el = document.createElement("div")
el.classList.add("js-loadout-element", "ol-rectangular-container-dark")
el.innerHTML = amount + "x" + displayName;
this.#loadoutContainer.appendChild(el);
}
}

View File

@@ -33,7 +33,7 @@ export function getLoadoutNamesByRole(aircraft: string, role: string)
export function getLoadoutsByName(aircraft: string, loadoutName: string)
{
//@ts-ignore
//@ts-ignore TODO
for (let loadout of aircraftDatabase[aircraft]["loadouts"])
{
if (loadout["name"] === loadoutName)
@@ -44,7 +44,21 @@ export function getLoadoutsByName(aircraft: string, loadoutName: string)
return null;
}
export function getUnitLabel(name: string)
export function getAircraftNameByLabel(label: string)
{
for (let name in aircraftDatabase)
{
//@ts-ignore TODO
if (aircraftDatabase[name]["label"] === label)
{
return name;
}
}
return null;
}
export function getAircraftLabelByName(name: string)
{
//@ts-ignore TODO
return aircraftDatabase[name] === undefined? name: aircraftDatabase[name].label;
@@ -1239,4 +1253,165 @@ export var aircraftDatabase = {
}
]
},
}
}
export function getAircrafImage(name: string)
{
var results = []
for (let imageName of imageNames) {
var score = similarity(imageName, name);
results.push({score: score, imageName: imageName});
}
var bestResult = null;
for (let result of results)
{
if (bestResult == null)
bestResult = result;
else {
if (result.score > bestResult.score)
bestResult = result;
}
}
return bestResult?.imageName + ".png";
}
function similarity(s1: string, s2: string) {
var longer = s1;
var shorter = s2;
if (s1.length < s2.length) {
longer = s2;
shorter = s1;
}
var longerLength = longer.length;
if (longerLength == 0) {
return 1.0;
}
return (longerLength - editDistance(longer, shorter)) / longerLength;
}
function editDistance(s1: string, s2: string) {
s1 = s1.toLowerCase();
s2 = s2.toLowerCase();
var costs = new Array();
for (var i = 0; i <= s1.length; i++) {
var lastValue = i;
for (var j = 0; j <= s2.length; j++) {
if (i == 0)
costs[j] = j;
else {
if (j > 0) {
var newValue = costs[j - 1];
if (s1.charAt(i - 1) != s2.charAt(j - 1))
newValue = Math.min(Math.min(newValue, lastValue),
costs[j]) + 1;
costs[j - 1] = lastValue;
lastValue = newValue;
}
}
}
if (i > 0)
costs[s2.length] = lastValue;
}
return costs[s2.length];
}
var imageNames = [
'a-10',
'a-20',
'a-29',
'a-4',
'a-400',
'a-50',
'a-6',
'ah-1',
'ah-64',
'an-26',
'av8bna',
'b-1',
'b-17',
'b-2',
'b-52',
'b707',
'bf109',
'bomb',
'c-101',
'c-130',
'c-17',
'c-5',
'ch-47',
'ch-53',
'christeneagleii',
'e-2',
'e-3',
'eurofighter',
'f-111',
'f-117',
'f-14',
'f-15',
'f-16',
'f-18',
'f-22',
'f-35',
'f-4',
'f-5',
'f-86',
'fw190',
'general1',
'gripen',
'h-6',
'hawk',
'helicopter1',
'i-16',
'il-76',
'j-10',
'j-20',
'j-7',
'jf-17',
'ju-88',
'ka-27',
'ka-50',
'kc-10',
'kc-135',
'l-159',
'l-39',
'm2000',
'mi-24',
'mi-26',
'mi-28',
'mi-8',
'mig-15',
'mig-19',
'mig-21',
'mig-23',
'mig-25',
'mig-29',
'mosquito',
'multiengine',
'oh-58',
'p-47',
'p-51',
'rafale',
'rq-1',
'rq-4',
's-3',
'sa-342',
'spitfire',
'su-17',
'su-24',
'su-25',
'su-27',
'su-34',
'su-57',
'tornado',
'tu-160',
'tu-22',
'tu-95',
'u-28',
'uh-1',
'uh-60',
'viggen',
'yak-40',
'yak-52'
]

View File

@@ -205,72 +205,3 @@ unitTypes.vehicles.Unarmed = [
"ZIL-131 KUNG",
"ZIL-4331"
]
/* AIRPLANES */
unitTypes.air = {}
unitTypes.air.CAP = [
"F-4E",
"F/A-18C",
"MiG-29S",
"F-14A",
"Su-27",
"MiG-23MLD",
"Su-33",
"MiG-25RBT",
"Su-30",
"MiG-31",
"Mirage 2000-5",
"F-15C",
"F-5E",
"F-16C bl.52d",
]
unitTypes.air.CAS = [
"Tornado IDS",
"F-4E",
"F/A-18C",
"MiG-27K",
"A-10C",
"Su-25",
"Su-34",
"Su-17M4",
"F-15E",
]
unitTypes.air.strike = [
"Tu-22M3",
"B-52H",
"F-111F",
"Tu-95MS",
"Su-24M",
"Tu-160",
"F-117A",
"B-1B",
"Tu-142",
]
unitTypes.air.tanker = [
"S-3B Tanker",
"KC-135",
"IL-78M",
]
unitTypes.air.awacs = [
"A-50",
"E-3A",
"E-2D",
]
unitTypes.air.drone = [
"MQ-1A Predator",
"MQ-9 Reaper",
]
unitTypes.air.transport = [
"C-130",
"An-26B",
"An-30M",
"C-17A",
"IL-76MD",
]

View File

@@ -1,6 +1,6 @@
import * as L from 'leaflet'
import { getMap } from '..'
import { getUnitLabel } from './aircraftDatabase'
import { getAircrafImage, getAircraftLabelByName } from './aircraftDatabase'
import { AirUnit, GroundUnit, NavyUnit, Weapon } from './unit'
export interface MarkerOptions {
@@ -30,7 +30,7 @@ export class UnitMarker extends L.Marker {
constructor(options: MarkerOptions) {
super(new L.LatLng(0, 0), { riseOnHover: true });
this.#unitName = options.unitName;
this.#name = getUnitLabel(options.name);
this.#name = getAircraftLabelByName(options.name);
this.#human = options.human;
this.#AI = options.AI;
@@ -45,20 +45,21 @@ export class UnitMarker extends L.Marker {
coalition = "neutral"
var icon = new L.DivIcon({
html: `<table class="unit-marker-container" id="container">
html: `<table class="ol-unit-marker-container" id="container">
<tr>
<td>
<div class="${coalition}" id="background"></div>
<div class="${coalition}" id="ring"></div>
<div class="unit-marker-icon" id="icon"><img class="${coalition} unit-marker-image" src="${img}"></div>
<div class="unit-marker-unitName" id="unitName">${this.#unitName}</div>
<div class="unit-marker-altitude" id="altitude"></div>
<div class="unit-marker-speed" id="speed"></div>
<div class="unit-marker-name" id="name">${this.#name}</div>
<div class="ol-unit-marker-icon" id="icon"><img class="${coalition} ol-unit-marker-image" src="${img}"></div>
<div class="ol-unit-marker-unitName" id="unitName">${this.#unitName}</div>
<div class="ol-unit-marker-altitude" id="altitude"></div>
<div class="ol-unit-marker-speed" id="speed"></div>
<div class="ol-unit-marker-name" id="name">${this.#name}</div>
</td>
</tr>
</table>`,
className: 'unit-marker'
className: 'ol-unit-marker',
iconAnchor: [30, 30]
});
this.setIcon(icon);
}
@@ -109,16 +110,16 @@ export class UnitMarker extends L.Marker {
if (!this.#alive)
{
this.getElement()?.querySelector("#icon")?.classList.add("unit-marker-dead");
this.getElement()?.querySelector("#icon")?.classList.add("ol-unit-marker-dead");
}
}
}
setSelected(selected: boolean) {
this.#selected = selected;
this.getElement()?.querySelector("#icon")?.classList.remove("unit-marker-hovered");
this.getElement()?.querySelector("#ring")?.classList.toggle("unit-marker-selected", selected);
this.getElement()?.querySelector("#background")?.classList.toggle("unit-marker-selected", selected);
this.getElement()?.querySelector("#icon")?.classList.remove("ol-unit-marker-hovered");
this.getElement()?.querySelector("#ring")?.classList.toggle("ol-unit-marker-selected", selected);
this.getElement()?.querySelector("#background")?.classList.toggle("ol-unit-marker-selected", selected);
}
getSelected() {
@@ -126,7 +127,11 @@ export class UnitMarker extends L.Marker {
}
setHovered(hovered: boolean) {
this.getElement()?.querySelector("#icon")?.classList.toggle("unit-marker-hovered", hovered && this.#alive);
this.getElement()?.querySelector("#icon")?.classList.toggle("ol-unit-marker-hovered", hovered && this.#alive);
}
getName() {
return this.#name;
}
getHuman() {
@@ -166,19 +171,22 @@ export class AirUnitMarker extends UnitMarker {
else
return "minimal";
}
}
export class AircraftMarker extends AirUnitMarker {
getUnitImage()
{
return new Image().src = "images/units/" + getAircrafImage(this.getName());
}
}
export class HelicopterMarker extends AirUnitMarker {
getUnitImage()
{
return new Image().src = "images/units/airUnit.png"
}
}
export class AircraftMarker extends AirUnitMarker {
}
export class HelicopterMarker extends AirUnitMarker {
}
export class GroundUnitMarker extends UnitMarker {
/* Are user driven units recognized as human? */
getVisibility() {