mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Merge branch '111-measurebox-shows-000-when-measuring-north-should-read-360' of https://github.com/Pax1601/DCSOlympus into 111-measurebox-shows-000-when-measuring-north-should-read-360
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { LatLng } from "leaflet";
|
||||
import { getActiveCoalition, setActiveCoalition } from "..";
|
||||
import { spawnAircraft, spawnGroundUnit } from "../server/server";
|
||||
import { spawnAircraft, spawnGroundUnit, spawnSmoke } from "../server/server";
|
||||
import { aircraftDatabase } from "../units/aircraftdatabase";
|
||||
import { groundUnitsDatabase } from "../units/groundunitsdatabase";
|
||||
import { ContextMenu } from "./contextmenu";
|
||||
@@ -21,7 +21,7 @@ export class MapContextMenu extends ContextMenu {
|
||||
#aircraftLoadoutDropdown: Dropdown;
|
||||
#groundUnitRoleDropdown: Dropdown;
|
||||
#groundUnitTypeDropdown: Dropdown;
|
||||
#spawnOptions: SpawnOptions = {role: "", type: "", latlng: new LatLng(0, 0), loadout: null, coalition: "blue", airbaseName: null};
|
||||
#spawnOptions: SpawnOptions = { role: "", type: "", latlng: new LatLng(0, 0), loadout: null, coalition: "blue", airbaseName: null };
|
||||
|
||||
constructor(id: string) {
|
||||
super(id);
|
||||
@@ -35,33 +35,38 @@ export class MapContextMenu extends ContextMenu {
|
||||
|
||||
document.addEventListener("contextMenuShow", (e: any) => {
|
||||
this.showSubMenu(e.detail.type);
|
||||
})
|
||||
});
|
||||
|
||||
document.addEventListener("contextMenuDeployAircraft", () => {
|
||||
this.hide();
|
||||
this.#spawnOptions.coalition = getActiveCoalition();
|
||||
if (this.#spawnOptions)
|
||||
spawnAircraft(this.#spawnOptions);
|
||||
})
|
||||
});
|
||||
|
||||
document.addEventListener("contextMenuDeployGroundUnit", () => {
|
||||
this.hide();
|
||||
this.#spawnOptions.coalition = getActiveCoalition();
|
||||
if (this.#spawnOptions)
|
||||
spawnGroundUnit(this.#spawnOptions);
|
||||
})
|
||||
});
|
||||
|
||||
document.addEventListener("contextMenuDeploySmoke", (e: any) => {
|
||||
this.hide();
|
||||
spawnSmoke(e.detail.color, this.getLatLng());
|
||||
});
|
||||
|
||||
this.hide();
|
||||
}
|
||||
|
||||
show(x: number, y: number, latlng: LatLng) {
|
||||
this.#spawnOptions = {role: "", type: "", latlng: new LatLng(0, 0), loadout: null, coalition: "blue", airbaseName: null};
|
||||
this.#spawnOptions.airbaseName = null;
|
||||
super.show(x, y, latlng);
|
||||
this.#spawnOptions.latlng = latlng;
|
||||
this.showUpperBar();
|
||||
}
|
||||
|
||||
showSubMenu(type: string){
|
||||
showSubMenu(type: string) {
|
||||
this.getContainer()?.querySelector("#aircraft-spawn-menu")?.classList.toggle("hide", type !== "aircraft");
|
||||
this.getContainer()?.querySelector("#aircraft-spawn-button")?.classList.toggle("is-open", type === "aircraft");
|
||||
this.getContainer()?.querySelector("#ground-unit-spawn-menu")?.classList.toggle("hide", type !== "ground-unit");
|
||||
@@ -84,31 +89,28 @@ export class MapContextMenu extends ContextMenu {
|
||||
this.getContainer()?.querySelector("#upper-bar")?.classList.toggle("hide", true);
|
||||
}
|
||||
|
||||
setAirbaseName(airbaseName: string)
|
||||
{
|
||||
setAirbaseName(airbaseName: string) {
|
||||
this.#spawnOptions.airbaseName = airbaseName;
|
||||
}
|
||||
|
||||
setLatLng(latlng: LatLng)
|
||||
{
|
||||
setLatLng(latlng: LatLng) {
|
||||
this.#spawnOptions.latlng = latlng;
|
||||
}
|
||||
|
||||
#onSwitch(e: any) {
|
||||
if (this.getContainer() != null) {
|
||||
if (e.srcElement.checked)
|
||||
if (e.srcElement.checked)
|
||||
setActiveCoalition("red");
|
||||
else
|
||||
else
|
||||
setActiveCoalition("blue");
|
||||
}
|
||||
}
|
||||
|
||||
/********* Aircraft spawn menu *********/
|
||||
#setAircraftRole(role: string)
|
||||
{
|
||||
#setAircraftRole(role: string) {
|
||||
this.#spawnOptions.role = role;
|
||||
this.#resetAircraftRole();
|
||||
this.#aircraftTypeDropdown.setOptions(aircraftDatabase.getLabelsByRole(role));
|
||||
this.#resetAircraftType();
|
||||
this.#aircraftTypeDropdown.setOptions(aircraftDatabase.getByRole(role).map((blueprint) => { return blueprint.label }));
|
||||
this.#aircraftTypeDropdown.selectValue(0);
|
||||
this.clip();
|
||||
}
|
||||
@@ -122,20 +124,18 @@ export class MapContextMenu extends ContextMenu {
|
||||
this.clip();
|
||||
}
|
||||
|
||||
#setAircraftType(label: string)
|
||||
{
|
||||
#setAircraftType(label: string) {
|
||||
this.#resetAircraftType();
|
||||
var type = aircraftDatabase.getNameByLabel(label);
|
||||
if (type != null)
|
||||
{
|
||||
var type = aircraftDatabase.getByLabel(label)?.name || null;
|
||||
if (type != null) {
|
||||
this.#spawnOptions.type = type;
|
||||
this.#aircraftLoadoutDropdown.setOptions(aircraftDatabase.getLoadoutNamesByRole(type, this.#spawnOptions.role));
|
||||
this.#aircraftLoadoutDropdown.selectValue(0);
|
||||
var image = (<HTMLImageElement>this.getContainer()?.querySelector("#unit-image"));
|
||||
image.src = `images/units/${aircraftDatabase.getByLabel(label)?.filename}`;
|
||||
image.classList.toggle("hide", false);
|
||||
image.classList.toggle("hide", false);
|
||||
}
|
||||
|
||||
|
||||
this.clip();
|
||||
}
|
||||
|
||||
@@ -147,15 +147,13 @@ export class MapContextMenu extends ContextMenu {
|
||||
this.clip();
|
||||
}
|
||||
|
||||
#setAircraftLoadout(loadoutName: string)
|
||||
{
|
||||
var loadout = aircraftDatabase.getLoadoutsByName(this.#spawnOptions.type, loadoutName);
|
||||
if (loadout)
|
||||
{
|
||||
#setAircraftLoadout(loadoutName: string) {
|
||||
var loadout = aircraftDatabase.getLoadoutByName(this.#spawnOptions.type, loadoutName);
|
||||
if (loadout) {
|
||||
this.#spawnOptions.loadout = loadout.code;
|
||||
(<HTMLButtonElement>this.getContainer()?.querySelector("#aircraft-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = false;
|
||||
var items = loadout.items.map((item: any) => {return `${item.quantity}x ${item.name}`;});
|
||||
items.length == 0? items.push("Empty loadout"): "";
|
||||
var items = loadout.items.map((item: any) => { return `${item.quantity}x ${item.name}`; });
|
||||
items.length == 0 ? items.push("Empty loadout") : "";
|
||||
(<HTMLButtonElement>this.getContainer()?.querySelector("#loadout-list")).replaceChildren(
|
||||
...items.map((item: any) => {
|
||||
var div = document.createElement('div');
|
||||
@@ -168,11 +166,10 @@ export class MapContextMenu extends ContextMenu {
|
||||
}
|
||||
|
||||
/********* Ground unit spawn menu *********/
|
||||
#setGroundUnitRole(role: string)
|
||||
{
|
||||
#setGroundUnitRole(role: string) {
|
||||
this.#spawnOptions.role = role;
|
||||
this.#resetGroundUnitRole();
|
||||
this.#groundUnitTypeDropdown.setOptions(groundUnitsDatabase.getLabelsByRole(role));
|
||||
this.#resetGroundUnitType();
|
||||
this.#groundUnitTypeDropdown.setOptions(groundUnitsDatabase.getByRole(role).map((blueprint) => { return blueprint.label }));
|
||||
this.#groundUnitTypeDropdown.selectValue(0);
|
||||
this.clip();
|
||||
}
|
||||
@@ -186,12 +183,10 @@ export class MapContextMenu extends ContextMenu {
|
||||
this.clip();
|
||||
}
|
||||
|
||||
#setGroundUnitType(label: string)
|
||||
{
|
||||
#setGroundUnitType(label: string) {
|
||||
this.#resetGroundUnitType();
|
||||
var type = groundUnitsDatabase.getNameByLabel(label);
|
||||
if (type != null)
|
||||
{
|
||||
var type = groundUnitsDatabase.getByLabel(label)?.name || null;
|
||||
if (type != null) {
|
||||
this.#spawnOptions.type = type;
|
||||
(<HTMLButtonElement>this.getContainer()?.querySelector("#ground-unit-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = false;
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ export class Slider {
|
||||
{
|
||||
this.#value = newValue;
|
||||
if (this.#slider != null)
|
||||
this.#slider.value = String((newValue - this.#minValue) / (this.#maxValue - this.#minValue) * 100);
|
||||
this.#slider.value = String((newValue - this.#minValue) / (this.#maxValue - this.#minValue) * parseFloat(this.#slider.max));
|
||||
this.#onValue()
|
||||
}
|
||||
}
|
||||
@@ -120,7 +120,7 @@ export class Slider {
|
||||
this.#dragged = false;
|
||||
if (this.#slider != null)
|
||||
{
|
||||
this.#value = this.#minValue + parseFloat(this.#slider.value) / 100 * (this.#maxValue - this.#minValue);
|
||||
this.#value = this.#minValue + parseFloat(this.#slider.value) / parseFloat(this.#slider.max) * (this.#maxValue - this.#minValue);
|
||||
this.#callback(this.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { AIC } from "./aic/aic";
|
||||
import { ATC } from "./atc/atc";
|
||||
import { FeatureSwitches } from "./featureswitches";
|
||||
import { LogPanel } from "./panels/logpanel";
|
||||
import { getAirbases, getBullseye as getBullseyes, getMission, getUnits, toggleDemoEnabled } from "./server/server";
|
||||
import { getAirbases, getBullseye as getBullseyes, getConfig, getMission, getUnits, setAddress, toggleDemoEnabled } from "./server/server";
|
||||
import { UnitDataTable } from "./units/unitdatatable";
|
||||
|
||||
var map: Map;
|
||||
@@ -69,16 +69,33 @@ function setup() {
|
||||
/* Setup event handlers */
|
||||
setupEvents();
|
||||
|
||||
/* On the first connection, force request of full data */
|
||||
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
|
||||
getBullseyes((data: BullseyesData) => getMissionData()?.update(data));
|
||||
getMission((data: any) => {getMissionData()?.update(data)});
|
||||
getUnits((data: UnitsData) => getUnitsManager()?.update(data), true /* Does a full refresh */);
|
||||
|
||||
/* Start periodically requesting updates */
|
||||
startPeriodicUpdate();
|
||||
getConfig(readConfig)
|
||||
}
|
||||
|
||||
function readConfig(config: any)
|
||||
{
|
||||
if (config && config["server"] != undefined && config["server"]["address"] != undefined && config["server"]["port"] != undefined)
|
||||
{
|
||||
const address = config["server"]["address"];
|
||||
const port = config["server"]["port"];
|
||||
if ((typeof address === 'string' || address instanceof String) && typeof port == 'number')
|
||||
{
|
||||
setAddress(window.location.hostname, <number>port);
|
||||
}
|
||||
|
||||
/* On the first connection, force request of full data */
|
||||
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
|
||||
getBullseyes((data: BullseyesData) => getMissionData()?.update(data));
|
||||
getMission((data: any) => {getMissionData()?.update(data)});
|
||||
getUnits((data: UnitsData) => getUnitsManager()?.update(data), true /* Does a full refresh */);
|
||||
|
||||
/* Start periodically requesting updates */
|
||||
startPeriodicUpdate();
|
||||
}
|
||||
else {
|
||||
throw new Error('Could not read configuration file!');
|
||||
}
|
||||
}
|
||||
|
||||
function startPeriodicUpdate() {
|
||||
requestUpdate();
|
||||
@@ -124,13 +141,16 @@ function checkSessionHash(newSessionHash: string) {
|
||||
function setupEvents() {
|
||||
/* Generic clicks */
|
||||
document.addEventListener("click", (ev) => {
|
||||
if (ev instanceof PointerEvent && ev.target instanceof HTMLElement) {
|
||||
if (ev instanceof MouseEvent && ev.target instanceof HTMLElement) {
|
||||
|
||||
const target = ev.target;
|
||||
|
||||
if (target.classList.contains("olympus-dialog-close")) {
|
||||
target.closest("div.olympus-dialog")?.classList.add("hide");
|
||||
}
|
||||
|
||||
const triggerElement = target.closest("[data-on-click]");
|
||||
|
||||
if (triggerElement instanceof HTMLElement) {
|
||||
const eventName: string = triggerElement.dataset.onClick || "";
|
||||
let params = JSON.parse(triggerElement.dataset.onClickParams || "{}");
|
||||
@@ -184,15 +204,6 @@ function setupEvents() {
|
||||
}
|
||||
//*/
|
||||
|
||||
document.addEventListener("toggleCoalitionVisibility", (ev: CustomEventInit) => {
|
||||
ev.detail._element.classList.toggle("off");
|
||||
document.body.toggleAttribute("data-hide-" + ev.detail.coalition);
|
||||
});
|
||||
|
||||
document.addEventListener("toggleUnitVisibility", (ev: CustomEventInit) => {
|
||||
document.body.toggleAttribute("data-hide-" + ev.detail.category);
|
||||
});
|
||||
|
||||
document.addEventListener( "closeDialog", (ev: CustomEventInit) => {
|
||||
ev.detail._element.closest( ".ol-dialog" ).classList.add( "hide" );
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ import { UnitContextMenu } from "../controls/unitcontextmenu";
|
||||
import { AirbaseContextMenu } from "../controls/airbasecontextmenu";
|
||||
import { Dropdown } from "../controls/dropdown";
|
||||
import { Airbase } from "../missionhandler/airbase";
|
||||
import { Unit } from "../units/unit";
|
||||
|
||||
export const IDLE = "IDLE";
|
||||
export const MOVE_UNIT = "MOVE_UNIT";
|
||||
@@ -45,6 +46,17 @@ export class Map extends L.Map {
|
||||
this.on('mouseup', (e: any) => this.#onMouseUp(e));
|
||||
this.on('mousemove', (e: any) => this.#onMouseMove(e));
|
||||
|
||||
document.addEventListener("toggleCoalitionVisibility", (ev: CustomEventInit) => {
|
||||
ev.detail._element.classList.toggle("off");
|
||||
document.body.toggleAttribute("data-hide-" + ev.detail.coalition);
|
||||
Object.values(getUnitsManager().getUnits()).forEach((unit: Unit) => unit.updateVisibility());
|
||||
});
|
||||
|
||||
document.addEventListener("toggleUnitVisibility", (ev: CustomEventInit) => {
|
||||
document.body.toggleAttribute("data-hide-" + ev.detail.category);
|
||||
Object.values(getUnitsManager().getUnits()).forEach((unit: Unit) => unit.updateVisibility());
|
||||
});
|
||||
|
||||
this.#mapSourceDropdown = new Dropdown("map-type", (layerName: string) => this.setLayer(layerName), this.getLayers())
|
||||
}
|
||||
|
||||
@@ -228,6 +240,7 @@ export class Map extends L.Map {
|
||||
|
||||
#onMouseDown(e: any)
|
||||
{
|
||||
this.hideAllContextMenus();
|
||||
if ((e.originalEvent.which == 1) && (e.originalEvent.button == 0))
|
||||
this.dragging.disable();
|
||||
}
|
||||
|
||||
@@ -26,6 +26,27 @@ export function ConvertDDToDMS(D: number, lng: boolean) {
|
||||
}
|
||||
|
||||
|
||||
export function dataPointMap( container:HTMLElement, data:any) {
|
||||
|
||||
Object.keys( data ).forEach( ( key ) => {
|
||||
|
||||
const val = "" + data[ key ]; // Ensure a string
|
||||
|
||||
container.querySelectorAll( `[data-point="${key}"]`).forEach( el => {
|
||||
|
||||
// We could probably have options here
|
||||
if ( el instanceof HTMLInputElement ) {
|
||||
el.value = val;
|
||||
} else if ( el instanceof HTMLElement ) {
|
||||
el.innerText = val;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
export function deg2rad(deg: number) {
|
||||
var pi = Math.PI;
|
||||
return deg * (pi / 180);
|
||||
|
||||
@@ -1,25 +1,30 @@
|
||||
import { getUnitsManager } from "..";
|
||||
import { Slider } from "../controls/slider";
|
||||
import { dataPointMap } from "../other/utils";
|
||||
import { aircraftDatabase } from "../units/aircraftdatabase";
|
||||
import { groundUnitsDatabase } from "../units/groundunitsdatabase";
|
||||
import { Aircraft, GroundUnit, Unit } from "../units/unit";
|
||||
import { UnitsManager } from "../units/unitsmanager";
|
||||
import { UnitDatabase } from "../units/unitdatabase";
|
||||
import { Panel } from "./panel";
|
||||
|
||||
const ROEs: string[] = ["Free", "Designated free", "Designated", "Return", "Hold"];
|
||||
const reactionsToThreat: string[] = [ "None", "Passive", "Evade", "Escape", "Abort"];
|
||||
const minSpeedValues: {[key: string]: number} = {Aircraft: 100, Helicopter: 0, NavyUnit: 0, GroundUnit: 0};
|
||||
const maxSpeedValues: {[key: string]: number} = {Aircraft: 800, Helicopter: 300, NavyUnit: 60, GroundUnit: 60};
|
||||
const speedIncrements: {[key: string]: number} = {Aircraft: 25, Helicopter: 10, NavyUnit: 5, GroundUnit: 5};
|
||||
const minAltitudeValues: {[key: string]: number} = {Aircraft: 0, Helicopter: 0};
|
||||
const maxAltitudeValues: {[key: string]: number} = {Aircraft: 50000, Helicopter: 10000};
|
||||
const altitudeIncrements: {[key: string]: number} = {Aircraft: 2500, Helicopter: 1000};
|
||||
// const ROEs: string[] = ["Free", "Designated free", "Designated", "Return", "Hold"]; // Full list
|
||||
// const reactionsToThreat: string[] = ["None", "Passive", "Evade", "Escape", "Abort"]; // Full list
|
||||
|
||||
const ROEs: string[] = [ "Hold", "Return", "Designated", "Free" ];
|
||||
const reactionsToThreat: string[] = [ "None", "Passive", "Evade" ];
|
||||
|
||||
const minSpeedValues: { [key: string]: number } = { Aircraft: 100, Helicopter: 0, NavyUnit: 0, GroundUnit: 0 };
|
||||
const maxSpeedValues: { [key: string]: number } = { Aircraft: 800, Helicopter: 300, NavyUnit: 60, GroundUnit: 60 };
|
||||
const speedIncrements: { [key: string]: number } = { Aircraft: 25, Helicopter: 10, NavyUnit: 5, GroundUnit: 5 };
|
||||
const minAltitudeValues: { [key: string]: number } = { Aircraft: 0, Helicopter: 0 };
|
||||
const maxAltitudeValues: { [key: string]: number } = { Aircraft: 50000, Helicopter: 10000 };
|
||||
const altitudeIncrements: { [key: string]: number } = { Aircraft: 2500, Helicopter: 1000 };
|
||||
|
||||
export class UnitControlPanel extends Panel {
|
||||
#altitudeSlider: Slider;
|
||||
#airspeedSlider: Slider;
|
||||
#optionButtons: {[key: string]: HTMLButtonElement[]} = {}
|
||||
|
||||
#optionButtons: { [key: string]: HTMLButtonElement[] } = {}
|
||||
|
||||
constructor(ID: string) {
|
||||
super(ID);
|
||||
|
||||
@@ -28,51 +33,68 @@ export class UnitControlPanel extends Panel {
|
||||
this.#airspeedSlider = new Slider("airspeed-slider", 0, 100, "kts", (value: number) => getUnitsManager().selectedUnitsSetSpeed(value / 1.94384));
|
||||
|
||||
/* Option buttons */
|
||||
this.#optionButtons["ROE"] = ROEs.map((option: string, index:number) => {
|
||||
this.#optionButtons["ROE"] = ROEs.map((option: string, index: number) => {
|
||||
var button = document.createElement("button");
|
||||
button.title = option;
|
||||
button.value = option;
|
||||
button.addEventListener("click", () => {getUnitsManager().selectedUnitsSetROE(button.title);});
|
||||
button.addEventListener("click", () => { getUnitsManager().selectedUnitsSetROE(button.title); });
|
||||
return button;
|
||||
});
|
||||
|
||||
this.#optionButtons["reactionToThreat"] = reactionsToThreat.map((option: string, index:number) => {
|
||||
this.#optionButtons["reactionToThreat"] = reactionsToThreat.map((option: string, index: number) => {
|
||||
var button = document.createElement("button");
|
||||
button.title = option;
|
||||
button.value = option;
|
||||
button.addEventListener("click", () => {getUnitsManager().selectedUnitsSetReactionToThreat(button.title);});
|
||||
button.addEventListener("click", () => { getUnitsManager().selectedUnitsSetReactionToThreat(button.title); });
|
||||
return button;
|
||||
});
|
||||
|
||||
this.getElement().querySelector("#roe-buttons-container")?.append(...this.#optionButtons["ROE"]);
|
||||
this.getElement().querySelector("#reaction-to-threat-buttons-container")?.append(...this.#optionButtons["reactionToThreat"]);
|
||||
|
||||
document.addEventListener("unitUpdated", (e: CustomEvent<Unit>) => {if (e.detail.getSelected()) this.update()});
|
||||
document.addEventListener("unitsSelection", (e: CustomEvent<Unit[]>) => {this.show(); this.update()});
|
||||
document.addEventListener("clearSelection", () => {this.hide()});
|
||||
document.addEventListener("unitUpdated", (e: CustomEvent<Unit>) => { if (e.detail.getSelected()) this.update() });
|
||||
document.addEventListener("unitsSelection", (e: CustomEvent<Unit[]>) => { this.show(); this.update() });
|
||||
document.addEventListener("clearSelection", () => { this.hide() });
|
||||
|
||||
this.hide();
|
||||
}
|
||||
|
||||
update() {
|
||||
var units = getUnitsManager().getSelectedUnits();
|
||||
if (this.getElement() != null && units.length > 0)
|
||||
{
|
||||
if (this.getElement() != null && units.length > 0) {
|
||||
this.#showFlightControlSliders(units);
|
||||
this.getElement().querySelector("#selected-units-container")?.replaceChildren(...units.map((unit: Unit) =>
|
||||
{
|
||||
var button = document.createElement("button");
|
||||
button.innerText = unit.getBaseData().unitName;
|
||||
|
||||
if (unit instanceof Aircraft)
|
||||
button.setAttribute( "data-short-label", aircraftDatabase.getShortLabelByName(unit.getBaseData().name));
|
||||
else if (unit instanceof GroundUnit)
|
||||
button.setAttribute( "data-short-label", groundUnitsDatabase.getShortLabelByName(unit.getBaseData().name));
|
||||
else
|
||||
button.setAttribute( "data-short-label", "");
|
||||
|
||||
button.setAttribute( "data-coalition", unit.getMissionData().coalition );
|
||||
button.classList.add( "pill", "highlight-coalition" )
|
||||
this.getElement().querySelector("#selected-units-container")?.replaceChildren(...units.map((unit: Unit, index: number) => {
|
||||
let database: UnitDatabase | null;
|
||||
if (unit instanceof Aircraft)
|
||||
database = aircraftDatabase;
|
||||
else if (unit instanceof GroundUnit)
|
||||
database = groundUnitsDatabase;
|
||||
else
|
||||
database = null; // TODO add databases for other unit types
|
||||
|
||||
if (index === 0) {
|
||||
this.getElement().querySelectorAll(`[data-object|="unit"]`).forEach(marker => {
|
||||
|
||||
marker.setAttribute("data-coalition", unit.getMissionData().coalition);
|
||||
|
||||
dataPointMap( this.getElement(), {
|
||||
"shortLabel" : database?.getByName(unit.getBaseData().name)?.shortLabel,
|
||||
"unitName": unit.getBaseData().unitName
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
var button = document.createElement("button");
|
||||
var callsign = unit.getBaseData().unitName || "";
|
||||
|
||||
button.innerText = unit.getBaseData().unitName;
|
||||
button.setAttribute("data-short-label", database?.getByName(unit.getBaseData().name)?.shortLabel || "");
|
||||
button.setAttribute("data-callsign", callsign);
|
||||
|
||||
button.setAttribute("data-coalition", unit.getMissionData().coalition);
|
||||
button.classList.add("pill", "highlight-coalition")
|
||||
|
||||
button.addEventListener("click", () => getUnitsManager().selectUnit(unit.ID, true));
|
||||
return (button);
|
||||
@@ -80,25 +102,33 @@ export class UnitControlPanel extends Panel {
|
||||
|
||||
this.#optionButtons["ROE"].forEach((button: HTMLButtonElement) => {
|
||||
button.classList.toggle("selected", units.every((unit: Unit) => unit.getOptionsData().ROE === button.value))
|
||||
});
|
||||
});
|
||||
|
||||
this.#optionButtons["reactionToThreat"].forEach((button: HTMLButtonElement) => {
|
||||
button.classList.toggle("selected", units.every((unit: Unit) => unit.getOptionsData().reactionToThreat === button.value))
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#showFlightControlSliders(units: Unit[])
|
||||
{
|
||||
this.#airspeedSlider.show();
|
||||
this.#altitudeSlider.show();
|
||||
if (getUnitsManager().getSelectedUnitsType() !== undefined)
|
||||
this.#airspeedSlider.show()
|
||||
else
|
||||
this.#airspeedSlider.hide();
|
||||
|
||||
if (getUnitsManager().getSelectedUnitsType() === "Aircraft" || getUnitsManager().getSelectedUnitsType() === "Helicopter")
|
||||
this.#altitudeSlider.show()
|
||||
else
|
||||
this.#altitudeSlider.hide();
|
||||
|
||||
this.getElement().querySelector(`#categories-tooltip`)?.classList.toggle("hide", getUnitsManager().getSelectedUnitsType() !== undefined);
|
||||
|
||||
var unitsType = getUnitsManager().getSelectedUnitsType();
|
||||
var targetAltitude = getUnitsManager().getSelectedUnitsTargetAltitude();
|
||||
var targetSpeed = getUnitsManager().getSelectedUnitsTargetSpeed();
|
||||
|
||||
if (unitsType != undefined)
|
||||
{
|
||||
if (unitsType != undefined) {
|
||||
if (["GroundUnit", "NavyUnit"].includes(unitsType))
|
||||
this.#altitudeSlider.hide()
|
||||
|
||||
|
||||
@@ -1,34 +1,44 @@
|
||||
import { getUnitsManager } from "..";
|
||||
import { ConvertDDToDMS, rad2deg } from "../other/utils";
|
||||
import { aircraftDatabase } from "../units/aircraftdatabase";
|
||||
import { Unit } from "../units/unit";
|
||||
import { Panel } from "./panel";
|
||||
|
||||
export class UnitInfoPanel extends Panel {
|
||||
#unitName: HTMLElement;
|
||||
#groupName: HTMLElement;
|
||||
#name: HTMLElement;
|
||||
#heading: HTMLElement;
|
||||
#altitude: HTMLElement;
|
||||
#currentTask: HTMLElement;
|
||||
#fuelBar: HTMLElement;
|
||||
#fuelPercentage: HTMLElement;
|
||||
#groundSpeed: HTMLElement;
|
||||
#fuel: HTMLElement;
|
||||
#groupName: HTMLElement;
|
||||
#heading: HTMLElement;
|
||||
#name: HTMLElement;
|
||||
#latitude: HTMLElement;
|
||||
#longitude: HTMLElement;
|
||||
#currentTask: HTMLElement;
|
||||
#loadoutContainer: HTMLElement;
|
||||
#silhouette: HTMLElement;
|
||||
#unitControl: HTMLElement;
|
||||
#unitLabel: HTMLElement;
|
||||
#unitName: HTMLElement;
|
||||
|
||||
constructor(ID: string) {
|
||||
super(ID);
|
||||
|
||||
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.#currentTask = <HTMLElement>(this.getElement().querySelector("#current-task"));
|
||||
this.#altitude = <HTMLElement>(this.getElement().querySelector("#altitude"));
|
||||
this.#currentTask = <HTMLElement>(this.getElement().querySelector("#current-task"));
|
||||
this.#groundSpeed = <HTMLElement>(this.getElement().querySelector("#ground-speed"));
|
||||
this.#fuelBar = <HTMLElement>(this.getElement().querySelector("#fuel-bar"));
|
||||
this.#fuelPercentage = <HTMLElement>(this.getElement().querySelector("#fuel-percentage"));
|
||||
this.#groupName = <HTMLElement>(this.getElement().querySelector("#group-name"));
|
||||
this.#heading = <HTMLElement>(this.getElement().querySelector("#heading"));
|
||||
this.#name = <HTMLElement>(this.getElement().querySelector("#name"));
|
||||
this.#latitude = <HTMLElement>(this.getElement().querySelector("#latitude"));
|
||||
this.#loadoutContainer = <HTMLElement>(this.getElement().querySelector("#loadout-container"));
|
||||
this.#longitude = <HTMLElement>(this.getElement().querySelector("#longitude"));
|
||||
this.#silhouette = <HTMLElement>(this.getElement().querySelector("#loadout-silhouette"));
|
||||
this.#unitControl = <HTMLElement>(this.getElement().querySelector("#unit-control"));
|
||||
this.#unitLabel = <HTMLElement>(this.getElement().querySelector("#unit-label"));
|
||||
this.#unitName = <HTMLElement>(this.getElement().querySelector("#unit-name"));
|
||||
|
||||
document.addEventListener("unitsSelection", (e: CustomEvent<Unit[]>) => this.#onUnitsSelection(e.detail));
|
||||
document.addEventListener("unitsDeselection", (e: CustomEvent<Unit[]>) => this.#onUnitsDeselection(e.detail));
|
||||
@@ -40,29 +50,53 @@ export class UnitInfoPanel extends Panel {
|
||||
|
||||
#onUnitUpdate(unit: Unit) {
|
||||
if (this.getElement() != null && this.getVisible() && unit.getSelected()) {
|
||||
|
||||
const baseData = unit.getBaseData();
|
||||
|
||||
/* Set the unit info */
|
||||
this.#unitName.innerText = unit.getBaseData().unitName;
|
||||
this.#groupName.innerText = unit.getBaseData().groupName;
|
||||
this.#name.innerText = unit.getBaseData().name;
|
||||
this.#unitLabel.innerText = aircraftDatabase.getByName(baseData.name)?.label || "";
|
||||
this.#unitName.innerText = baseData.unitName;
|
||||
this.#unitControl.innerText = ( ( baseData.AI ) ? "AI" : "Human" ) + " controlled";
|
||||
// this.#groupName.innerText = baseData.groupName;
|
||||
//this.#name.innerText = baseData.name;
|
||||
//this.#heading.innerText = String(Math.floor(rad2deg(unit.getFlightData().heading)) + " °");
|
||||
//this.#altitude.innerText = String(Math.floor(unit.getFlightData().altitude / 0.3048) + " ft");
|
||||
//this.#groundSpeed.innerText = String(Math.floor(unit.getFlightData().speed * 1.94384) + " kts");
|
||||
//this.#fuel.innerText = String(unit.getMissionData().fuel + "%");
|
||||
this.#fuelBar.style.width = String(unit.getMissionData().fuel + "%");
|
||||
this.#fuelPercentage.dataset.percentage = "" + unit.getMissionData().fuel;
|
||||
//this.#latitude.innerText = ConvertDDToDMS(unit.getFlightData().latitude, false);
|
||||
//this.#longitude.innerText = ConvertDDToDMS(unit.getFlightData().longitude, true);
|
||||
this.#currentTask.dataset.currentTask = unit.getTaskData().currentTask !== ""? unit.getTaskData().currentTask: "No task";
|
||||
this.#currentTask.dataset.coalition = unit.getMissionData().coalition;
|
||||
|
||||
this.#silhouette.setAttribute( "style", `--loadout-background-image:url('/images/units/${aircraftDatabase.getByName( baseData.name )?.filename}');` );;
|
||||
|
||||
/* Add the loadout elements */
|
||||
this.#loadoutContainer.replaceChildren(...Object.values(unit.getMissionData().ammo).map(
|
||||
(ammo: any) => {
|
||||
var el = document.createElement("div");
|
||||
el.classList.add("pill", "loadout-item");
|
||||
el.dataset.loadoutQty = ammo.count;
|
||||
el.dataset.loadoutItem = ammo.desc.displayName;
|
||||
return el;
|
||||
const items = <HTMLElement>this.#loadoutContainer.querySelector( "#loadout-items" );
|
||||
|
||||
|
||||
if ( items ) {
|
||||
|
||||
const ammo = Object.values( unit.getMissionData().ammo );
|
||||
|
||||
if ( ammo.length > 0 ) {
|
||||
|
||||
items.replaceChildren(...Object.values(unit.getMissionData().ammo).map(
|
||||
(ammo: any) => {
|
||||
var el = document.createElement("div");
|
||||
el.dataset.qty = ammo.count;
|
||||
el.dataset.item = ammo.desc.displayName;
|
||||
return el;
|
||||
}
|
||||
));
|
||||
|
||||
} else {
|
||||
|
||||
items.innerText = "No loadout";
|
||||
|
||||
}
|
||||
))
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,8 @@ import * as L from 'leaflet'
|
||||
import { setConnected } from '..';
|
||||
import { SpawnOptions } from '../controls/mapcontextmenu';
|
||||
|
||||
/* Edit here to change server address */
|
||||
const REST_ADDRESS = "http://localhost:30000/olympus";
|
||||
const DEMO_ADDRESS = "http://localhost:3000/demo";
|
||||
var REST_ADDRESS = "http://localhost:30000/olympus";
|
||||
var DEMO_ADDRESS = window.location.href + "demo";
|
||||
const UNITS_URI = "units";
|
||||
const LOGS_URI = "logs";
|
||||
const AIRBASES_URI = "airbases";
|
||||
@@ -24,9 +23,14 @@ export function GET(callback: CallableFunction, uri: string){
|
||||
xmlHttp.open("GET", `${demoEnabled? DEMO_ADDRESS: REST_ADDRESS}/${uri}`, true);
|
||||
xmlHttp.onload = function (e) {
|
||||
var data = JSON.parse(xmlHttp.responseText);
|
||||
callback(data);
|
||||
lastUpdateTime = parseInt(data.time);
|
||||
setConnected(true);
|
||||
if (parseInt(data.time) > lastUpdateTime)
|
||||
{
|
||||
callback(data);
|
||||
lastUpdateTime = parseInt(data.time);
|
||||
if (isNaN(lastUpdateTime))
|
||||
lastUpdateTime = 0;
|
||||
setConnected(true);
|
||||
}
|
||||
};
|
||||
xmlHttp.onerror = function () {
|
||||
console.error("An error occurred during the XMLHttpRequest");
|
||||
@@ -45,6 +49,24 @@ export function POST(request: object, callback: CallableFunction){
|
||||
xhr.send(JSON.stringify(request));
|
||||
}
|
||||
|
||||
export function getConfig(callback: CallableFunction) {
|
||||
var xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.open("GET", window.location.href + "config", true);
|
||||
xmlHttp.onload = function (e) {
|
||||
var data = JSON.parse(xmlHttp.responseText);
|
||||
callback(data);
|
||||
};
|
||||
xmlHttp.onerror = function () {
|
||||
console.error("An error occurred during the XMLHttpRequest, could not retrieve configuration file");
|
||||
};
|
||||
xmlHttp.send(null);
|
||||
}
|
||||
|
||||
export function setAddress(address: string, port: number) {
|
||||
REST_ADDRESS = `http://${address}:${port}/olympus`
|
||||
console.log(`Setting REST address to ${REST_ADDRESS}`)
|
||||
}
|
||||
|
||||
export function getAirbases(callback: CallableFunction) {
|
||||
GET(callback, AIRBASES_URI);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { UnitDatabase } from "./unitdatabase"
|
||||
export class AircraftDatabase extends UnitDatabase {
|
||||
constructor() {
|
||||
super();
|
||||
this.units = {
|
||||
this.blueprints = {
|
||||
|
||||
"A-10C": {
|
||||
"name": "A-10C",
|
||||
|
||||
@@ -3,7 +3,7 @@ import { UnitDatabase } from "./unitdatabase"
|
||||
export class GroundUnitsDatabase extends UnitDatabase {
|
||||
constructor() {
|
||||
super();
|
||||
this.units = {
|
||||
this.blueprints = {
|
||||
"2B11 mortar": {
|
||||
"name": "2B11 mortar",
|
||||
"label": "2B11 mortar",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Marker, LatLng, Polyline, Icon, DivIcon } from 'leaflet';
|
||||
import { getMap, getUnitsManager } from '..';
|
||||
import { rad2deg } from '../other/utils';
|
||||
import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, landAt, setAltitude, setReactionToThreat, setROE, setSpeed } from '../server/server';
|
||||
import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, getUnits, landAt, setAltitude, setReactionToThreat, setROE, setSpeed } from '../server/server';
|
||||
import { aircraftDatabase } from './aircraftdatabase';
|
||||
import { groundUnitsDatabase } from './groundunitsdatabase';
|
||||
|
||||
@@ -79,7 +79,7 @@ export class Unit extends Marker {
|
||||
if (type === "NavyUnit") return NavyUnit;
|
||||
}
|
||||
|
||||
constructor(ID: number, data: UpdateData, html: string) {
|
||||
constructor(ID: number, data: UpdateData) {
|
||||
super(new LatLng(0, 0), { riseOnHover: true });
|
||||
|
||||
this.ID = ID;
|
||||
@@ -89,19 +89,12 @@ export class Unit extends Marker {
|
||||
this.on('click', (e) => this.#onClick(e));
|
||||
this.on('dblclick', (e) => this.#onDoubleClick(e));
|
||||
this.on('contextmenu', (e) => this.#onContextMenu(e));
|
||||
|
||||
var icon = new DivIcon({
|
||||
html: html,
|
||||
className: 'leaflet-unit-marker',
|
||||
iconAnchor: [0, 0]
|
||||
});
|
||||
this.setIcon(icon);
|
||||
|
||||
|
||||
this.#pathPolyline = new Polyline([], { color: '#2d3e50', weight: 3, opacity: 0.5, smoothFactor: 1 });
|
||||
this.#pathPolyline.addTo(getMap());
|
||||
this.#targetsPolylines = [];
|
||||
|
||||
// Deselect units if they are hidden
|
||||
/* Deselect units if they are hidden */
|
||||
document.addEventListener("toggleCoalitionVisibility", (ev: CustomEventInit) => {
|
||||
setTimeout(() => {this.setSelected(this.getSelected() && !this.getHidden())}, 300);
|
||||
});
|
||||
@@ -110,7 +103,31 @@ export class Unit extends Marker {
|
||||
setTimeout(() => {this.setSelected(this.getSelected() && !this.getHidden())}, 300);
|
||||
});
|
||||
|
||||
/* Set the unit data */
|
||||
this.setData(data);
|
||||
|
||||
/* Set the icon */
|
||||
var icon = new DivIcon({
|
||||
html: this.getMarkerHTML(),
|
||||
className: 'leaflet-unit-marker',
|
||||
iconAnchor: [0, 0]
|
||||
});
|
||||
this.setIcon(icon);
|
||||
|
||||
}
|
||||
|
||||
getMarkerHTML() {
|
||||
return `<div class="unit" data-object="unit-${this.getMarkerCategory()}" data-coalition="${this.getMissionData().coalition}">
|
||||
<div class="unit-selected-spotlight"></div>
|
||||
<div class="unit-marker"></div>
|
||||
<div class="unit-short-label"></div>
|
||||
</div>`
|
||||
}
|
||||
|
||||
getMarkerCategory()
|
||||
{
|
||||
// Overloaded by child classes
|
||||
return "";
|
||||
}
|
||||
|
||||
setData(data: UpdateData) {
|
||||
@@ -118,6 +135,7 @@ export class Unit extends Marker {
|
||||
var updateMarker = false;
|
||||
|
||||
if ((data.flightData.latitude != undefined && data.flightData.longitude != undefined && (this.getFlightData().latitude != data.flightData.latitude || this.getFlightData().longitude != data.flightData.longitude))
|
||||
|| (data.flightData.heading != undefined && this.getFlightData().heading != data.flightData.heading)
|
||||
|| (data.baseData.alive != undefined && this.getBaseData().alive != data.baseData.alive)
|
||||
|| this.#forceUpdate || !getMap().hasLayer(this))
|
||||
updateMarker = true;
|
||||
@@ -253,13 +271,30 @@ export class Unit extends Marker {
|
||||
this.getTaskData().activePath = undefined;
|
||||
}
|
||||
|
||||
updateVisibility()
|
||||
{
|
||||
this.setHidden( document.body.getAttribute(`data-hide-${this.getMissionData().coalition}`) != null ||
|
||||
document.body.getAttribute(`data-hide-${this.getMarkerCategory()}`) != null ||
|
||||
!this.getBaseData().alive)
|
||||
}
|
||||
|
||||
setHidden(hidden: boolean)
|
||||
{
|
||||
this.#hidden = hidden;
|
||||
this.#hidden = hidden;
|
||||
|
||||
/* Add the marker if not present */
|
||||
if (!getMap().hasLayer(this) && !this.getHidden()) {
|
||||
this.addTo(getMap());
|
||||
}
|
||||
|
||||
/* Hide the marker if necessary*/
|
||||
if (getMap().hasLayer(this) && this.getHidden()) {
|
||||
getMap().removeLayer(this);
|
||||
}
|
||||
}
|
||||
|
||||
getHidden() {
|
||||
return (<HTMLElement>this.getElement()?.querySelector(`.unit`))?.offsetParent === null;
|
||||
return this.#hidden;
|
||||
}
|
||||
|
||||
getLeader() {
|
||||
@@ -282,10 +317,6 @@ export class Unit extends Marker {
|
||||
return wingmen;
|
||||
}
|
||||
|
||||
forceUpdate() {
|
||||
this.#forceUpdate = true;
|
||||
}
|
||||
|
||||
attackUnit(targetID: number) {
|
||||
/* Call DCS attackUnit function */
|
||||
if (this.ID != targetID) {
|
||||
@@ -355,11 +386,14 @@ export class Unit extends Marker {
|
||||
var options = [
|
||||
'Attack'
|
||||
]
|
||||
getMap().showUnitContextMenu(e);
|
||||
getMap().getUnitContextMenu().setOptions(options, (option: string) => {
|
||||
getMap().hideUnitContextMenu();
|
||||
this.#executeAction(option);
|
||||
});
|
||||
if (getUnitsManager().getSelectedUnits().length > 0 && !(getUnitsManager().getSelectedUnits().includes(this)))
|
||||
{
|
||||
getMap().showUnitContextMenu(e);
|
||||
getMap().getUnitContextMenu().setOptions(options, (option: string) => {
|
||||
getMap().hideUnitContextMenu();
|
||||
this.#executeAction(option);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#executeAction(action: string) {
|
||||
@@ -368,21 +402,13 @@ export class Unit extends Marker {
|
||||
}
|
||||
|
||||
#updateMarker() {
|
||||
/* Add the marker if not present */
|
||||
if (!getMap().hasLayer(this) && !this.getHidden()) {
|
||||
this.addTo(getMap());
|
||||
}
|
||||
this.updateVisibility();
|
||||
|
||||
/* Hide the marker if necessary*/
|
||||
if (getMap().hasLayer(this) && this.getHidden()) {
|
||||
getMap().removeLayer(this);
|
||||
}
|
||||
else {
|
||||
if (!this.getHidden()) {
|
||||
|
||||
this.setLatLng(new LatLng(this.getFlightData().latitude, this.getFlightData().longitude));
|
||||
var element = this.getElement();
|
||||
if (element != null) {
|
||||
|
||||
element.querySelector(".unit-vvi")?.setAttribute("style", `height: ${15 + this.getFlightData().speed / 5}px;`);
|
||||
element.querySelector(".unit")?.setAttribute("data-pilot", this.getMissionData().flags.human? "human": "ai");
|
||||
|
||||
@@ -401,9 +427,8 @@ export class Unit extends Marker {
|
||||
|
||||
}
|
||||
|
||||
const headingDeg = rad2deg( this.getFlightData().heading );
|
||||
|
||||
element.querySelectorAll( "[data-rotate-to-heading]" ).forEach( el => {
|
||||
const headingDeg = rad2deg( this.getFlightData().heading );
|
||||
let currentStyle = el.getAttribute( "style" ) || "";
|
||||
el.setAttribute( "style", currentStyle + `transform:rotate(${headingDeg}deg);` );
|
||||
});
|
||||
@@ -494,93 +519,120 @@ export class AirUnit extends Unit {
|
||||
|
||||
export class Aircraft extends AirUnit {
|
||||
constructor(ID: number, data: UnitData) {
|
||||
super(ID, data,
|
||||
`<div class="unit" data-object="unit-air-aircraft" data-status="" data-coalition="${data.missionData.coalition}">
|
||||
<div class="unit-selected-spotlight"></div>
|
||||
<div class="unit-marker-border"></div>
|
||||
<div class="unit-status"></div>
|
||||
<div class="unit-vvi" data-rotate-to-heading></div>
|
||||
<div class="unit-hotgroup">
|
||||
<div class="unit-hotgroup-id"></div>
|
||||
</div>
|
||||
<div class="unit-marker"></div>
|
||||
<div class="unit-short-label">${aircraftDatabase.getShortLabelByName(data.baseData.name)}</div>
|
||||
<div class="unit-fuel">
|
||||
<div class="unit-fuel-level" style="width:100%;"></div>
|
||||
</div>
|
||||
<div class="unit-ammo">
|
||||
<div class="unit-ammo-fox-1"></div>
|
||||
<div class="unit-ammo-fox-2"></div>
|
||||
<div class="unit-ammo-fox-3"></div>
|
||||
<div class="unit-ammo-other"></div>
|
||||
</div>
|
||||
<div class="unit-summary">
|
||||
<div class="unit-callsign">${data.baseData.unitName}</div>
|
||||
<div class="unit-altitude"></div>
|
||||
<div class="unit-speed"></div>
|
||||
</div>
|
||||
</div>`);
|
||||
super(ID, data);
|
||||
}
|
||||
|
||||
getMarkerHTML()
|
||||
{
|
||||
return `<div class="unit" data-object="unit-aircraft" data-status="" data-coalition="${this.getMissionData().coalition}">
|
||||
<div class="unit-selected-spotlight"></div>
|
||||
<div class="unit-marker-border"></div>
|
||||
<div class="unit-status"></div>
|
||||
<div class="unit-vvi" data-rotate-to-heading></div>
|
||||
<div class="unit-hotgroup">
|
||||
<div class="unit-hotgroup-id"></div>
|
||||
</div>
|
||||
<div class="unit-marker"></div>
|
||||
<div class="unit-short-label">${aircraftDatabase.getByName(this.getBaseData().name)?.shortLabel || ""}</div>
|
||||
<div class="unit-fuel">
|
||||
<div class="unit-fuel-level" style="width:100%;"></div>
|
||||
</div>
|
||||
<div class="unit-ammo">
|
||||
<div class="unit-ammo-fox-1"></div>
|
||||
<div class="unit-ammo-fox-2"></div>
|
||||
<div class="unit-ammo-fox-3"></div>
|
||||
<div class="unit-ammo-other"></div>
|
||||
</div>
|
||||
<div class="unit-summary">
|
||||
<div class="unit-callsign">${this.getBaseData().unitName}</div>
|
||||
<div class="unit-altitude"></div>
|
||||
<div class="unit-speed"></div>
|
||||
</div>
|
||||
</div>`
|
||||
}
|
||||
|
||||
getMarkerCategory()
|
||||
{
|
||||
return "aircraft";
|
||||
}
|
||||
}
|
||||
|
||||
export class Helicopter extends AirUnit {
|
||||
constructor(ID: number, data: UnitData) {
|
||||
super(ID, data,
|
||||
``);
|
||||
super(ID, data);
|
||||
}
|
||||
|
||||
getVisibilityCategory()
|
||||
{
|
||||
return "helicopter";
|
||||
}
|
||||
}
|
||||
|
||||
export class GroundUnit extends Unit {
|
||||
constructor(ID: number, data: UnitData) {
|
||||
// TODO this is very messy
|
||||
var role = groundUnitsDatabase.getByName(data.baseData.name)?.loadouts[0].roles[0];
|
||||
if (role == undefined)
|
||||
role = "U";
|
||||
var roleType = (role === "SAM") ? "sam" : "mi";
|
||||
super(ID, data);
|
||||
}
|
||||
|
||||
super(ID, data, `
|
||||
<div class="unit" data-object="unit-ground-${roleType}" data-coalition="${data.missionData.coalition}">
|
||||
<div class="unit-selected-spotlight"></div>
|
||||
<div class="unit-marker"></div>
|
||||
<div class="unit-short-label">${role?.substring(0, 1).toUpperCase()}</div>
|
||||
</div>
|
||||
`);
|
||||
getMarkerHTML() {
|
||||
var role = groundUnitsDatabase.getByName(this.getBaseData().name)?.loadouts[0].roles[0];
|
||||
return `<div class="unit" data-object="unit-${this.getMarkerCategory()}" data-coalition="${this.getMissionData().coalition}">
|
||||
<div class="unit-selected-spotlight"></div>
|
||||
<div class="unit-marker"></div>
|
||||
<div class="unit-short-label">${role?.substring(0, 1)?.toUpperCase() || ""}</div>
|
||||
</div>`
|
||||
}
|
||||
|
||||
getMarkerCategory()
|
||||
{
|
||||
// TODO this is very messy
|
||||
var role = groundUnitsDatabase.getByName(this.getBaseData().name)?.loadouts[0].roles[0];
|
||||
var markerCategory = (role === "SAM") ? "sam" : "groundunit";
|
||||
return markerCategory;
|
||||
}
|
||||
}
|
||||
|
||||
export class NavyUnit extends Unit {
|
||||
constructor(ID: number, data: UnitData) {
|
||||
super(ID, data, `
|
||||
<div class="unit" data-object="unit-naval" data-coalition="${data.missionData.coalition}">
|
||||
<div class="unit-selected-spotlight"></div>
|
||||
<div class="unit-marker"></div>
|
||||
<div class="unit-short-label">N</div>
|
||||
</div>
|
||||
`);
|
||||
super(ID, data);
|
||||
}
|
||||
|
||||
getMarkerCategory() {
|
||||
return "navyunit";
|
||||
}
|
||||
}
|
||||
|
||||
export class Weapon extends Unit {
|
||||
constructor(ID: number, data: UnitData, html: string) {
|
||||
super(ID, data, html);
|
||||
constructor(ID: number, data: UnitData) {
|
||||
super(ID, data);
|
||||
this.setSelectable(false);
|
||||
}
|
||||
|
||||
getMarkerHTML(): string {
|
||||
return `<div class="unit" data-object="unit-${this.getMarkerCategory()}" data-coalition="${this.getMissionData().coalition}">
|
||||
<div class="unit-selected-spotlight"></div>
|
||||
<div class="unit-marker" data-rotate-to-heading></div>
|
||||
<div class="unit-short-label"></div>
|
||||
</div>`
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class Missile extends Weapon {
|
||||
constructor(ID: number, data: UnitData) {
|
||||
super(ID, data, `
|
||||
<div class="unit" data-object="unit-weapon-missile" data-coalition="${data.missionData.coalition}">
|
||||
<div class="unit-selected-spotlight"></div>
|
||||
<div class="unit-marker" data-rotate-to-heading></div>
|
||||
<div class="unit-short-label"></div>
|
||||
</div>
|
||||
`);
|
||||
super(ID, data);
|
||||
}
|
||||
|
||||
getMarkerCategory() {
|
||||
return "missile";
|
||||
}
|
||||
}
|
||||
|
||||
export class Bomb extends Weapon {
|
||||
constructor(ID: number, data: UnitData) {
|
||||
super(ID, data, "");
|
||||
super(ID, data);
|
||||
}
|
||||
|
||||
getMarkerCategory() {
|
||||
return "bomb";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,18 @@
|
||||
export class UnitDatabase {
|
||||
units: {[key: string]: UnitBlueprint} = {};
|
||||
blueprints: {[key: string]: UnitBlueprint} = {};
|
||||
|
||||
constructor()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
getByName(name: string)
|
||||
{
|
||||
if (name in this.units)
|
||||
return this.units[name];
|
||||
return null;
|
||||
}
|
||||
|
||||
getByLabel(label: string)
|
||||
{
|
||||
for (let unit in this.units)
|
||||
{
|
||||
if (this.units[unit].label === label)
|
||||
return this.units[unit];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Returns a list of all possible roles in a database */
|
||||
getRoles()
|
||||
{
|
||||
var roles: string[] = [];
|
||||
for (let unit in this.units)
|
||||
for (let unit in this.blueprints)
|
||||
{
|
||||
for (let loadout of this.units[unit].loadouts)
|
||||
for (let loadout of this.blueprints[unit].loadouts)
|
||||
{
|
||||
for (let role of loadout.roles)
|
||||
{
|
||||
@@ -40,16 +24,36 @@ export class UnitDatabase {
|
||||
return roles;
|
||||
}
|
||||
|
||||
getLabelsByRole(role: string)
|
||||
/* Gets a specific blueprint by name */
|
||||
getByName(name: string)
|
||||
{
|
||||
if (name in this.blueprints)
|
||||
return this.blueprints[name];
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Gets a specific blueprint by label */
|
||||
getByLabel(label: string)
|
||||
{
|
||||
for (let unit in this.blueprints)
|
||||
{
|
||||
if (this.blueprints[unit].label === label)
|
||||
return this.blueprints[unit];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Get all blueprints by role */
|
||||
getByRole(role: string)
|
||||
{
|
||||
var units = [];
|
||||
for (let unit in this.units)
|
||||
for (let unit in this.blueprints)
|
||||
{
|
||||
for (let loadout of this.units[unit].loadouts)
|
||||
for (let loadout of this.blueprints[unit].loadouts)
|
||||
{
|
||||
if (loadout.roles.includes(role) || loadout.roles.includes(role.toLowerCase()))
|
||||
{
|
||||
units.push(this.units[unit].label)
|
||||
units.push(this.blueprints[unit])
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -57,10 +61,11 @@ export class UnitDatabase {
|
||||
return units;
|
||||
}
|
||||
|
||||
getLoadoutNamesByRole(unit: string, role: string)
|
||||
/* Get the names of all the loadouts for a specific unit and for a specific role */
|
||||
getLoadoutNamesByRole(name: string, role: string)
|
||||
{
|
||||
var loadouts = [];
|
||||
for (let loadout of this.units[unit].loadouts)
|
||||
for (let loadout of this.blueprints[name].loadouts)
|
||||
{
|
||||
if (loadout.roles.includes(role) || loadout.roles.includes(""))
|
||||
{
|
||||
@@ -70,37 +75,14 @@ export class UnitDatabase {
|
||||
return loadouts;
|
||||
}
|
||||
|
||||
getLoadoutsByName(unit: string, loadoutName: string)
|
||||
/* Get the loadout content from the unit name and loadout name */
|
||||
getLoadoutByName(name: string, loadoutName: string)
|
||||
{
|
||||
for (let loadout of this.units[unit].loadouts)
|
||||
for (let loadout of this.blueprints[name].loadouts)
|
||||
{
|
||||
if (loadout.name === loadoutName)
|
||||
{
|
||||
return loadout;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
getNameByLabel(label: string)
|
||||
{
|
||||
for (let name in this.units)
|
||||
{
|
||||
if (this.units[name].label === label)
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
getLabelByName(name: string)
|
||||
{
|
||||
return this.units[name] === undefined? name: this.units[name].label;
|
||||
}
|
||||
|
||||
getShortLabelByName(name: string)
|
||||
{
|
||||
return this.units[name] === undefined? "U": this.units[name].shortLabel;
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ export class UnitsManager {
|
||||
#units: { [ID: number]: Unit };
|
||||
#copiedUnits: Unit[];
|
||||
#selectionEventDisabled: boolean = false;
|
||||
#pasteDisabled: boolean = false;
|
||||
|
||||
constructor() {
|
||||
this.#units = {};
|
||||
@@ -330,10 +331,15 @@ export class UnitsManager {
|
||||
|
||||
pasteUnits()
|
||||
{
|
||||
for (let idx in this.#copiedUnits)
|
||||
if (!this.#pasteDisabled)
|
||||
{
|
||||
var unit = this.#copiedUnits[idx];
|
||||
cloneUnit(unit.ID, getMap().getMouseCoordinates());
|
||||
for (let idx in this.#copiedUnits)
|
||||
{
|
||||
var unit = this.#copiedUnits[idx];
|
||||
cloneUnit(unit.ID, getMap().getMouseCoordinates());
|
||||
}
|
||||
this.#pasteDisabled = true;
|
||||
setTimeout(() => this.#pasteDisabled = false, 250);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user