`;
+ var el = document.createElement("div");
+ el.classList.add("ol-ellipsed");
+ el.innerText = option;
+ this.#value.appendChild(el);
this.#index = idx;
this.#close();
this.#callback(option);
diff --git a/client/src/controls/slider.ts b/client/src/controls/slider.ts
index 7fab7782..e8070d2e 100644
--- a/client/src/controls/slider.ts
+++ b/client/src/controls/slider.ts
@@ -88,7 +88,7 @@ export class Slider {
#onValue() {
if (this.#valueText != null && this.#slider != null)
- this.#valueText.innerHTML = this.#minValue + Math.round(parseFloat(this.#slider.value) / parseFloat(this.#slider.max) * (this.#maxValue - this.#minValue)) + this.#unit
+ this.#valueText.innerText = this.#minValue + Math.round(parseFloat(this.#slider.value) / parseFloat(this.#slider.max) * (this.#maxValue - this.#minValue)) + this.#unit
this.setActive(true);
}
diff --git a/client/src/controls/unitcontextmenu.ts b/client/src/controls/unitcontextmenu.ts
index 86250e6d..4acbaf3e 100644
--- a/client/src/controls/unitcontextmenu.ts
+++ b/client/src/controls/unitcontextmenu.ts
@@ -40,11 +40,16 @@ export class UnitContextMenu extends ContextMenu {
this.#customFormationCallback = callback;
}
- setOptions(options: { [key: string]: string }, callback: CallableFunction) {
- this.getContainer()?.replaceChildren(...Object.keys(options).map((option: string, idx: number) => {
+ setOptions(options: { [key: string]: {text: string, tooltip: string }}, callback: CallableFunction) {
+ this.getContainer()?.replaceChildren(...Object.keys(options).map((key: string, idx: number) => {
+ const option = options[key];
var button = document.createElement("button");
- button.innerHTML = options[option];
- button.addEventListener("click", () => callback(option));
+ var el = document.createElement("div");
+ el.title = option.tooltip;
+ el.innerText = option.text;
+ el.id = key;
+ button.addEventListener("click", () => callback(key));
+ button.appendChild(el);
return (button);
}));
}
diff --git a/client/src/index.ts b/client/src/index.ts
index 16d9a8b2..c2f8a1b6 100644
--- a/client/src/index.ts
+++ b/client/src/index.ts
@@ -140,28 +140,14 @@ function setupEvents() {
case "Space":
setPaused(!getPaused());
break;
- case "KeyW":
- case "KeyA":
- case "KeyS":
- case "KeyD":
- case "ArrowLeft":
- case "ArrowRight":
- case "ArrowUp":
- case "ArrowDown":
+ case "KeyW": case "KeyA": case "KeyS": case "KeyD":
+ case "ArrowLeft": case "ArrowRight": case "ArrowUp": case "ArrowDown":
getMap().handleMapPanning(ev);
break;
- case "Digit1":
- case "Digit2":
- case "Digit3":
- case "Digit4":
- case "Digit5":
- case "Digit6":
- case "Digit7":
- case "Digit8":
- case "Digit9":
+ case "Digit1": case "Digit2": case "Digit3": case "Digit4": case "Digit5": case "Digit6": case "Digit7": case "Digit8": case "Digit9":
// Using the substring because the key will be invalid when pressing the Shift key
if (ev.ctrlKey && ev.shiftKey)
- getUnitsManager().selectedUnitsAddToHotgroup(parseInt(ev.code.substring(5)));
+ getUnitsManager().selectedUnitsAddToHotgroup(parseInt(ev.code.substring(5)));
else if (ev.ctrlKey && !ev.shiftKey)
getUnitsManager().selectedUnitsSetHotgroup(parseInt(ev.code.substring(5)));
else
@@ -176,14 +162,7 @@ function setupEvents() {
return;
}
switch (ev.code) {
- case "KeyW":
- case "KeyA":
- case "KeyS":
- case "KeyD":
- case "ArrowLeft":
- case "ArrowRight":
- case "ArrowUp":
- case "ArrowDown":
+ case "KeyW": case "KeyA": case "KeyS": case "KeyD": case "ArrowLeft": case "ArrowRight": case "ArrowUp": case "ArrowDown":
getMap().handleMapPanning(ev);
break;
}
@@ -201,8 +180,8 @@ function setupEvents() {
document.addEventListener("tryConnection", () => {
const form = document.querySelector("#splash-content")?.querySelector("#authentication-form");
- const username = ( (form?.querySelector("#username"))).value;
- const password = ( (form?.querySelector("#password"))).value;
+ const username = ((form?.querySelector("#username"))).value;
+ const password = ((form?.querySelector("#password"))).value;
setCredentials(username, btoa("admin" + ":" + password));
/* Start periodically requesting updates */
diff --git a/client/src/map/custommarker.ts b/client/src/map/custommarker.ts
index 41d79c14..a6ca5998 100644
--- a/client/src/map/custommarker.ts
+++ b/client/src/map/custommarker.ts
@@ -1,4 +1,4 @@
-import { Map, Marker } from "leaflet";
+import { DivIcon, Map, Marker } from "leaflet";
import { MarkerOptions } from "leaflet";
import { LatLngExpression } from "leaflet";
@@ -8,6 +8,7 @@ export class CustomMarker extends Marker {
}
onAdd(map: Map): this {
+ this.setIcon(new DivIcon()); // Default empty icon
super.onAdd(map);
this.createIcon();
return this;
diff --git a/client/src/map/map.ts b/client/src/map/map.ts
index a36ae834..477b8640 100644
--- a/client/src/map/map.ts
+++ b/client/src/map/map.ts
@@ -22,6 +22,7 @@ require("../../public/javascripts/leaflet.nauticscale.js")
export const IDLE = "IDLE";
export const MOVE_UNIT = "MOVE_UNIT";
export const visibilityControls: string[] = ["human", "dcs", "aircraft", "groundunit-sam", "groundunit-other", "navyunit", "airbase"];
+export const visibilityControlsTootlips: string[] = ["Toggle human players visibility", "Toggle DCS controlled units visibility", "Toggle aircrafts visibility", "Toggle SAM units visibility", "Toggle ground units (not SAM) visibility", "Toggle navy units visibility", "Toggle airbases visibility"];
export class Map extends L.Map {
#state: string;
@@ -116,7 +117,7 @@ export class Map extends L.Map {
/* Option buttons */
this.#optionButtons["visibility"] = visibilityControls.map((option: string, index: number) => {
- return this.#createOptionButton(option, `visibility/${option.toLowerCase()}.svg`, "", "toggleUnitVisibility", `{"type": "${option}"}`);
+ return this.#createOptionButton(option, `visibility/${option.toLowerCase()}.svg`, visibilityControlsTootlips[index], "toggleUnitVisibility", `{"type": "${option}"}`);
});
document.querySelector("#unit-visibility-control")?.append(...this.#optionButtons["visibility"]);
}
@@ -194,7 +195,7 @@ export class Map extends L.Map {
})
this.#destinationPreviewMarkers = [];
- if (getUnitsManager().getSelectedUnits({ excludeHumans: true }).length < 20) {
+ if (getUnitsManager().getSelectedUnits({ excludeHumans: true }).length > 1 && getUnitsManager().getSelectedUnits({ excludeHumans: true }).length < 20) {
/* Create the unit destination preview markers */
this.#destinationPreviewMarkers = getUnitsManager().getSelectedUnits({ excludeHumans: true }).map((unit: Unit) => {
var marker = new DestinationPreviewMarker(this.getMouseCoordinates());
@@ -425,6 +426,9 @@ export class Map extends L.Map {
getUnitsManager().selectedUnitsClearDestinations();
}
getUnitsManager().selectedUnitsAddDestination(this.#computeDestinationRotation && this.#destinationRotationCenter != null ? this.#destinationRotationCenter : e.latlng, !e.originalEvent.shiftKey, this.#destinationGroupRotation)
+ this.#destinationGroupRotation = 0;
+ this.#destinationRotationCenter = null;
+ this.#computeDestinationRotation = false;
}
}
@@ -440,18 +444,18 @@ export class Map extends L.Map {
#onMouseDown(e: any) {
this.hideAllContextMenus();
- if (this.#state == MOVE_UNIT && e.originalEvent.button == 2) {
- this.#computeDestinationRotation = true;
- this.#destinationRotationCenter = this.getMouseCoordinates();
+ if (this.#state == MOVE_UNIT) {
+ this.#destinationGroupRotation = 0;
+ this.#destinationRotationCenter = null;
+ this.#computeDestinationRotation = false;
+ if (e.originalEvent.button == 2) {
+ this.#computeDestinationRotation = true;
+ this.#destinationRotationCenter = this.getMouseCoordinates();
+ }
}
}
#onMouseUp(e: any) {
- if (this.#state == MOVE_UNIT) {
- this.#computeDestinationRotation = false;
- this.#destinationRotationCenter = null;
- this.#destinationGroupRotation = 0;
- }
}
#onMouseMove(e: any) {
diff --git a/client/src/panels/hotgrouppanel.ts b/client/src/panels/hotgrouppanel.ts
index 8431c2ab..f0abdb85 100644
--- a/client/src/panels/hotgrouppanel.ts
+++ b/client/src/panels/hotgrouppanel.ts
@@ -18,14 +18,24 @@ export class HotgroupPanel extends Panel {
}
addHotgroup(hotgroup: number) {
- const hotgroupHtml = `
-
${hotgroup}
-
- x${getUnitsManager().getUnitsByHotgroup(hotgroup).length}`
+ // Hotgroup number
+ var hotgroupDiv = document.createElement("div");
+ hotgroupDiv.classList.add("unit-hotgroup");
+ var idDiv = document.createElement("div");
+ idDiv.classList.add("unit-hotgroup-id");
+ idDiv.innerText = String(hotgroup);
+ hotgroupDiv.appendChild(idDiv);
+
+ // Hotgroup unit count
+ var countDiv = document.createElement("div");
+ countDiv.innerText = `x${getUnitsManager().getUnitsByHotgroup(hotgroup).length}`;
+
var el = document.createElement("div");
+ el.appendChild(hotgroupDiv);
+ el.appendChild(countDiv);
el.classList.add("hotgroup-selector");
- el.innerHTML = hotgroupHtml;
el.toggleAttribute(`data-hotgroup-${hotgroup}`, true)
+
this.getElement().appendChild(el);
el.addEventListener("click", () => {
diff --git a/client/src/panels/unitcontrolpanel.ts b/client/src/panels/unitcontrolpanel.ts
index 7b1967d4..ea90161d 100644
--- a/client/src/panels/unitcontrolpanel.ts
+++ b/client/src/panels/unitcontrolpanel.ts
@@ -1,3 +1,4 @@
+import { SVGInjector } from "@tanem/svg-injector";
import { getUnitsManager } from "..";
import { Dropdown } from "../controls/dropdown";
import { Slider } from "../controls/slider";
@@ -346,7 +347,10 @@ export class UnitControlPanel extends Panel {
var button = document.createElement("button");
button.title = title;
button.value = value;
- button.innerHTML = ``
+ var img = document.createElement("img");
+ img.src = `/resources/theme/images/buttons/${url}`;
+ img.onload = () => SVGInjector(img);
+ button.appendChild(img);
button.addEventListener("click", callback);
return button;
}
diff --git a/client/src/units/unit.ts b/client/src/units/unit.ts
index 3338c095..d54034a7 100644
--- a/client/src/units/unit.ts
+++ b/client/src/units/unit.ts
@@ -6,6 +6,7 @@ import { aircraftDatabase } from './aircraftdatabase';
import { groundUnitsDatabase } from './groundunitsdatabase';
import { CustomMarker } from '../map/custommarker';
import { SVGInjector } from '@tanem/svg-injector';
+import { UnitDatabase } from './unitdatabase';
var pathIcon = new Icon({
iconUrl: '/resources/theme/images/markers/marker-icon.png',
@@ -124,17 +125,23 @@ export class Unit extends CustomMarker {
return "";
}
- getActiveMarkerElements() {
- // Default values
+ getDatabase(): UnitDatabase | null {
+ // Overloaded by child classes
+ return null;
+ }
+
+ getIconOptions(): UnitIconOptions {
+ // Default values, overloaded by child classes if needed
return {
- state: false,
- vvi: false,
- hotgroup: false,
- unitIcon: true,
- shortLabel: false,
- fuel: false,
- ammo: false,
- summary: false
+ showState: false,
+ showVvi: false,
+ showHotgroup: false,
+ showUnitIcon: true,
+ showShortLabel: false,
+ showFuel: false,
+ showAmmo: false,
+ showSummary: false,
+ rotateToHeading: false
}
}
@@ -165,6 +172,7 @@ export class Unit extends CustomMarker {
setHotgroup(hotgroup: number | null) {
this.#hotgroup = hotgroup;
+ this.#updateMarker();
}
getHotgroup() {
@@ -172,7 +180,7 @@ export class Unit extends CustomMarker {
}
setHighlighted(highlighted: boolean) {
- if (this.#highlighted != highlighted) {
+ if (this.getSelectable() && this.#highlighted != highlighted) {
this.getElement()?.querySelector(`[data-object|="unit"]`)?.toggleAttribute("data-is-highlighted", highlighted);
this.#highlighted = highlighted;
this.getGroupMembers().forEach((unit: Unit) => unit.setHighlighted(highlighted));
@@ -297,19 +305,13 @@ export class Unit extends CustomMarker {
this.setIcon(icon);
var el = document.createElement("div");
+ el.classList.add("unit");
el.setAttribute("data-object", `unit-${this.getMarkerCategory()}`);
el.setAttribute("data-coalition", this.getMissionData().coalition);
- // Generate and append elements depending on active options
- // State icon
- if (this.getActiveMarkerElements().state){
- var state = document.createElement("div");
- state.classList.add("unit-state");
- el.appendChild(state);
- }
-
+ // Generate and append elements depending on active options
// Velocity vector
- if (this.getActiveMarkerElements().vvi) {
+ if (this.getIconOptions().showVvi) {
var vvi = document.createElement("div");
vvi.classList.add("unit-vvi");
vvi.toggleAttribute("data-rotate-to-heading");
@@ -317,7 +319,7 @@ export class Unit extends CustomMarker {
}
// Hotgroup indicator
- if (this.getActiveMarkerElements().hotgroup) {
+ if (this.getIconOptions().showHotgroup) {
var hotgroup = document.createElement("div");
hotgroup.classList.add("unit-hotgroup");
var hotgroupId = document.createElement("div");
@@ -327,26 +329,34 @@ export class Unit extends CustomMarker {
}
// Main icon
- if (this.getActiveMarkerElements().unitIcon) {
+ if (this.getIconOptions().showUnitIcon) {
var unitIcon = document.createElement("div");
unitIcon.classList.add("unit-icon");
var img = document.createElement("img");
img.src = `/resources/theme/images/units/${this.getMarkerCategory()}.svg`;
img.onload = () => SVGInjector(img);
unitIcon.appendChild(img);
+ unitIcon.toggleAttribute("data-rotate-to-heading", this.getIconOptions().rotateToHeading);
el.append(unitIcon);
}
+ // State icon
+ if (this.getIconOptions().showState){
+ var state = document.createElement("div");
+ state.classList.add("unit-state");
+ el.appendChild(state);
+ }
+
// Short label
- if (this.getActiveMarkerElements().shortLabel) {
+ if (this.getIconOptions().showShortLabel) {
var shortLabel = document.createElement("div");
shortLabel.classList.add("unit-short-label");
- shortLabel.innerText = aircraftDatabase.getByName(this.getBaseData().name)?.shortLabel || ""; //TODO: fix, use correct database
+ shortLabel.innerText = this.getDatabase()?.getByName(this.getBaseData().name)?.shortLabel || "";
el.append(shortLabel);
}
// Fuel indicator
- if (this.getActiveMarkerElements().fuel) {
+ if (this.getIconOptions().showFuel) {
var fuelIndicator = document.createElement("div");
fuelIndicator.classList.add("unit-fuel");
var fuelLevel = document.createElement("div");
@@ -356,7 +366,7 @@ export class Unit extends CustomMarker {
}
// Ammo indicator
- if (this.getActiveMarkerElements().ammo){
+ if (this.getIconOptions().showAmmo){
var ammoIndicator = document.createElement("div");
ammoIndicator.classList.add("unit-ammo");
for (let i = 0; i <= 3; i++)
@@ -365,7 +375,7 @@ export class Unit extends CustomMarker {
}
// Unit summary
- if (this.getActiveMarkerElements().summary) {
+ if (this.getIconOptions().showSummary) {
var summary = document.createElement("div");
summary.classList.add("unit-summary");
var callsign = document.createElement("div");
@@ -544,18 +554,18 @@ export class Unit extends CustomMarker {
}
#onContextMenu(e: any) {
- var options: { [key: string]: string } = {};
+ var options: {[key: string]: {text: string, tooltip: string}} = {};
- options["Center"] = `
Center map
`;
+ options["center-map"] = {text: "Center map", tooltip: "Center the map on the unit and follow it"};
if (getUnitsManager().getSelectedUnits().length > 0 && !(getUnitsManager().getSelectedUnits().length == 1 && (getUnitsManager().getSelectedUnits().includes(this)))) {
- options['Attack'] = `
Attack
`;
+ options["attack"] = {text: "Attack", tooltip: "Attack the unit using A/A or A/G weapons"};
if (getUnitsManager().getSelectedUnitsType() === "Aircraft")
- options['Follow'] = `
Follow
`;
+ options["follow"] = {text: "Follow", tooltip: "Follow the unit at a user defined distance and position"};;
}
else if ((getUnitsManager().getSelectedUnits().length > 0 && (getUnitsManager().getSelectedUnits().includes(this))) || getUnitsManager().getSelectedUnits().length == 0) {
if (this.getBaseData().category == "Aircraft") {
- options["Refuel"] = `
Refuel
`; // TODO Add some way of knowing which aircraft can AAR
+ options["refuel"] = {text: "AAR Refuel", tooltip: "Refuel unit at the nearest AAR Tanker. If no tanker is available the unit will RTB."}; // TODO Add some way of knowing which aircraft can AAR
}
}
@@ -569,28 +579,28 @@ export class Unit extends CustomMarker {
}
#executeAction(e: any, action: string) {
- if (action === "Center")
+ if (action === "center-map")
getMap().centerOnUnit(this.ID);
- if (action === "Attack")
+ if (action === "attack")
getUnitsManager().selectedUnitsAttackUnit(this.ID);
- else if (action === "Refuel")
+ else if (action === "refuel")
getUnitsManager().selectedUnitsRefuel();
- else if (action === "Follow")
+ else if (action === "follow")
this.#showFollowOptions(e);
}
#showFollowOptions(e: any) {
- var options: { [key: string]: string } = {};
+ var options: {[key: string]: {text: string, tooltip: string}} = {};
options = {
- 'Trail': `
Trail
`,
- 'Echelon (LH)': `
Echelon (left)
`,
- 'Echelon (RH)': `
Echelon (right)
`,
- 'Line abreast (LH)': `
Line abreast (left)
`,
- 'Line abreast (RH)': `
Line abreast (right)
`,
- 'Front': `
In front
`,
- 'Diamond': `
Diamond
`,
- 'Custom': `
Custom
`
+ 'trail': {text: "Trail", tooltip: "Follow unit in trail formation"},
+ 'echelon-lh': {text: "Echelon (LH)", tooltip: "Follow unit in echelon left formation"},
+ 'echelon-rh': {text: "Echelon (RH)", tooltip: "Follow unit in echelon right formation"},
+ 'line-abreast-lh': {text: "Line abreast (LH)", tooltip: "Follow unit in line abreast left formation"},
+ 'line-abreast-rh': {text: "Line abreast (RH)", tooltip: "Follow unit in line abreast right formation"},
+ 'front': {text: "Front", tooltip: "Fly in front of unit"},
+ 'diamond': {text: "Diamond", tooltip: "Follow unit in diamond formation"},
+ 'custom': {text: "Custom", tooltip: "Set a custom formation position"},
}
getMap().getUnitContextMenu().setOptions(options, (option: string) => {
@@ -601,7 +611,7 @@ export class Unit extends CustomMarker {
}
#applyFollowOptions(action: string) {
- if (action === "Custom") {
+ if (action === "custom") {
document.getElementById("custom-formation-dialog")?.classList.remove("hide");
getMap().getUnitContextMenu().setCustomFormationCallback((offset: { x: number, y: number, z: number }) => {
getUnitsManager().selectedUnitsFollowUnit(this.ID, offset);
@@ -657,18 +667,18 @@ export class Unit extends CustomMarker {
element.querySelector(".unit")?.toggleAttribute("data-is-dead", !this.getBaseData().alive);
/* Set current unit state */
- if (this.getMissionData().flags.Human) // Unit is human
+ if (this.getMissionData().flags.Human) // Unit is human
element.querySelector(".unit")?.setAttribute("data-state", "human");
- else if (!this.getBaseData().AI) // Unit is under DCS control (not Olympus)
+ else if (!this.getBaseData().AI) // Unit is under DCS control (not Olympus)
element.querySelector(".unit")?.setAttribute("data-state", "dcs");
- else // Unit is under Olympus control
+ else // Unit is under Olympus control
element.querySelector(".unit")?.setAttribute("data-state", this.getTaskData().currentState.toLowerCase());
/* Set altitude and speed */
if (element.querySelector(".unit-altitude"))
(element.querySelector(".unit-altitude")).innerText = "FL" + String(Math.floor(this.getFlightData().altitude / 0.3048 / 100));
if (element.querySelector(".unit-speed"))
- (element.querySelector(".unit-speed")).innerHTML = String(Math.floor(this.getFlightData().speed * 1.94384));
+ (element.querySelector(".unit-speed")).innerText = String(Math.floor(this.getFlightData().speed * 1.94384));
/* Rotate elements according to heading */
element.querySelectorAll("[data-rotate-to-heading]").forEach(el => {
@@ -791,16 +801,17 @@ export class Unit extends CustomMarker {
}
export class AirUnit extends Unit {
- getActiveMarkerElements() {
+ getIconOptions() {
return {
- state: true,
- vvi: true,
- hotgroup: true,
- unitIcon: true,
- shortLabel: true,
- fuel: true,
- ammo: true,
- summary: true
+ showState: true,
+ showVvi: true,
+ showHotgroup: true,
+ showUnitIcon: true,
+ showShortLabel: true,
+ showFuel: true,
+ showAmmo: true,
+ showSummary: true,
+ rotateToHeading: false
};
}
}
@@ -813,6 +824,10 @@ export class Aircraft extends AirUnit {
getMarkerCategory() {
return "aircraft";
}
+
+ getDatabase(): UnitDatabase | null {
+ return aircraftDatabase;
+ }
}
export class Helicopter extends AirUnit {
@@ -830,16 +845,17 @@ export class GroundUnit extends Unit {
super(ID, data);
}
- getActiveMarkerElements() {
+ getIconOptions() {
return {
- state: true,
- vvi: false,
- hotgroup: true,
- unitIcon: true,
- shortLabel: true,
- fuel: false,
- ammo: false,
- summary: false
+ showState: true,
+ showVvi: false,
+ showHotgroup: true,
+ showUnitIcon: true,
+ showShortLabel: true,
+ showFuel: false,
+ showAmmo: false,
+ showSummary: false,
+ rotateToHeading: false
};
}
@@ -849,6 +865,10 @@ export class GroundUnit extends Unit {
var markerCategory = (role === "SAM") ? "groundunit-sam" : "groundunit-other";
return markerCategory;
}
+
+ getDatabase(): UnitDatabase | null {
+ return groundUnitsDatabase;
+ }
}
export class NavyUnit extends Unit {
@@ -856,16 +876,17 @@ export class NavyUnit extends Unit {
super(ID, data);
}
- getActiveMarkerElements() {
+ getIconOptions() {
return {
- state: true,
- vvi: false,
- hotgroup: true,
- unitIcon: true,
- shortLabel: true,
- fuel: false,
- ammo: false,
- summary: false
+ showState: true,
+ showVvi: false,
+ showHotgroup: true,
+ showUnitIcon: true,
+ showShortLabel: true,
+ showFuel: false,
+ showAmmo: false,
+ showSummary: false,
+ rotateToHeading: false
};
}
@@ -879,6 +900,20 @@ export class Weapon extends Unit {
super(ID, data);
this.setSelectable(false);
}
+
+ getIconOptions() {
+ return {
+ showState: false,
+ showVvi: false,
+ showHotgroup: false,
+ showUnitIcon: true,
+ showShortLabel: false,
+ showFuel: false,
+ showAmmo: false,
+ showSummary: false,
+ rotateToHeading: true
+ };
+ }
}
export class Missile extends Weapon {
diff --git a/client/src/units/unitdatabase.ts b/client/src/units/unitdatabase.ts
index 9bfd0095..90d87863 100644
--- a/client/src/units/unitdatabase.ts
+++ b/client/src/units/unitdatabase.ts
@@ -1,21 +1,16 @@
export class UnitDatabase {
- blueprints: {[key: string]: UnitBlueprint} = {};
+ blueprints: { [key: string]: UnitBlueprint } = {};
- constructor()
- {
+ constructor() {
}
/* Returns a list of all possible roles in a database */
- getRoles()
- {
+ getRoles() {
var roles: string[] = [];
- for (let unit in this.blueprints)
- {
- for (let loadout of this.blueprints[unit].loadouts)
- {
- for (let role of loadout.roles)
- {
+ for (let unit in this.blueprints) {
+ for (let loadout of this.blueprints[unit].loadouts) {
+ for (let role of loadout.roles) {
if (role !== "" && !roles.includes(role))
roles.push(role);
}
@@ -25,18 +20,15 @@ export class UnitDatabase {
}
/* Gets a specific blueprint by name */
- getByName(name: string)
- {
+ 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)
- {
+ getByLabel(label: string) {
+ for (let unit in this.blueprints) {
if (this.blueprints[unit].label === label)
return this.blueprints[unit];
}
@@ -44,15 +36,11 @@ export class UnitDatabase {
}
/* Get all blueprints by role */
- getByRole(role: string)
- {
+ getByRole(role: string) {
var units = [];
- for (let unit in this.blueprints)
- {
- for (let loadout of this.blueprints[unit].loadouts)
- {
- if (loadout.roles.includes(role) || loadout.roles.includes(role.toLowerCase()))
- {
+ for (let unit in this.blueprints) {
+ for (let loadout of this.blueprints[unit].loadouts) {
+ if (loadout.roles.includes(role) || loadout.roles.includes(role.toLowerCase())) {
units.push(this.blueprints[unit])
break;
}
@@ -62,13 +50,10 @@ export class UnitDatabase {
}
/* Get the names of all the loadouts for a specific unit and for a specific role */
- getLoadoutNamesByRole(name: string, role: string)
- {
+ getLoadoutNamesByRole(name: string, role: string) {
var loadouts = [];
- for (let loadout of this.blueprints[name].loadouts)
- {
- if (loadout.roles.includes(role) || loadout.roles.includes(""))
- {
+ for (let loadout of this.blueprints[name].loadouts) {
+ if (loadout.roles.includes(role) || loadout.roles.includes("")) {
loadouts.push(loadout.name)
}
}
@@ -76,10 +61,8 @@ export class UnitDatabase {
}
/* Get the loadout content from the unit name and loadout name */
- getLoadoutByName(name: string, loadoutName: string)
- {
- for (let loadout of this.blueprints[name].loadouts)
- {
+ getLoadoutByName(name: string, loadoutName: string) {
+ for (let loadout of this.blueprints[name].loadouts) {
if (loadout.name === loadoutName)
return loadout;
}
diff --git a/client/src/units/unitsmanager.ts b/client/src/units/unitsmanager.ts
index 07964d7a..07f5ac9c 100644
--- a/client/src/units/unitsmanager.ts
+++ b/client/src/units/unitsmanager.ts
@@ -47,7 +47,7 @@ export class UnitsManager {
}
getUnitsByHotgroup(hotgroup: number) {
- return Object.values(this.#units).filter((unit: Unit) => {return unit.getBaseData().alive && unit.getHotgroup() == hotgroup});
+ return Object.values(this.#units).filter((unit: Unit) => { return unit.getBaseData().alive && unit.getHotgroup() == hotgroup });
}
addUnit(ID: number, data: UnitData) {
@@ -88,10 +88,8 @@ export class UnitsManager {
});
}
- setHiddenType(key: string, value: boolean)
- {
- if (value)
- {
+ setHiddenType(key: string, value: boolean) {
+ if (value) {
if (this.#hiddenTypes.includes(key))
delete this.#hiddenTypes[this.#hiddenTypes.indexOf(key)];
}
@@ -100,8 +98,7 @@ export class UnitsManager {
Object.values(this.getUnits()).forEach((unit: Unit) => unit.updateVisibility());
}
- getHiddenTypes()
- {
+ getHiddenTypes() {
return this.#hiddenTypes;
}
@@ -123,7 +120,7 @@ export class UnitsManager {
}
}
- getSelectedUnits(options?: {excludeHumans?: boolean}) {
+ getSelectedUnits(options?: { excludeHumans?: boolean }) {
var selectedUnits = [];
for (let ID in this.#units) {
if (this.#units[ID].getSelected()) {
@@ -132,7 +129,7 @@ export class UnitsManager {
}
if (options) {
if (options.excludeHumans)
- selectedUnits = selectedUnits.filter((unit: Unit) => {return !unit.getMissionData().flags.Human});
+ selectedUnits = selectedUnits.filter((unit: Unit) => { return !unit.getMissionData().flags.Human });
}
return selectedUnits;
}
@@ -190,14 +187,14 @@ export class UnitsManager {
/*********************** Actions on selected units ************************/
selectedUnitsAddDestination(latlng: L.LatLng, mantainRelativePosition: boolean, rotation: number) {
- var selectedUnits = this.getSelectedUnits({excludeHumans: true});
+ var selectedUnits = this.getSelectedUnits({ excludeHumans: true });
/* Compute the destination for each unit. If mantainRelativePosition is true, compute the destination so to hold the relative distances */
- var unitDestinations: {[key: number]: LatLng} = {};
+ var unitDestinations: { [key: number]: LatLng } = {};
if (mantainRelativePosition)
unitDestinations = this.selectedUnitsComputeGroupDestination(latlng, rotation);
else
- selectedUnits.forEach((unit: Unit) => {unitDestinations[unit.ID] = latlng});
+ selectedUnits.forEach((unit: Unit) => { unitDestinations[unit.ID] = latlng });
for (let idx in selectedUnits) {
const unit = selectedUnits[idx];
@@ -206,7 +203,7 @@ export class UnitsManager {
const leader = this.getUnitByID(unit.getFormationData().leaderID)
if (leader && leader.getSelected())
leader.addDestination(latlng);
- else
+ else
unit.addDestination(latlng);
}
else {
@@ -219,7 +216,7 @@ export class UnitsManager {
}
selectedUnitsClearDestinations() {
- var selectedUnits = this.getSelectedUnits({excludeHumans: true});
+ var selectedUnits = this.getSelectedUnits({ excludeHumans: true });
for (let idx in selectedUnits) {
const unit = selectedUnits[idx];
if (unit.getTaskData().currentState === "Follow") {
@@ -235,7 +232,7 @@ export class UnitsManager {
}
selectedUnitsLandAt(latlng: LatLng) {
- var selectedUnits = this.getSelectedUnits({excludeHumans: true});
+ var selectedUnits = this.getSelectedUnits({ excludeHumans: true });
for (let idx in selectedUnits) {
selectedUnits[idx].landAt(latlng);
}
@@ -243,21 +240,21 @@ export class UnitsManager {
}
selectedUnitsChangeSpeed(speedChange: string) {
- var selectedUnits = this.getSelectedUnits({excludeHumans: true});
+ var selectedUnits = this.getSelectedUnits({ excludeHumans: true });
for (let idx in selectedUnits) {
selectedUnits[idx].changeSpeed(speedChange);
}
}
selectedUnitsChangeAltitude(altitudeChange: string) {
- var selectedUnits = this.getSelectedUnits({excludeHumans: true});
+ var selectedUnits = this.getSelectedUnits({ excludeHumans: true });
for (let idx in selectedUnits) {
selectedUnits[idx].changeAltitude(altitudeChange);
}
}
selectedUnitsSetSpeed(speed: number) {
- var selectedUnits = this.getSelectedUnits({excludeHumans: true});
+ var selectedUnits = this.getSelectedUnits({ excludeHumans: true });
for (let idx in selectedUnits) {
selectedUnits[idx].setSpeed(speed);
}
@@ -265,7 +262,7 @@ export class UnitsManager {
}
selectedUnitsSetAltitude(altitude: number) {
- var selectedUnits = this.getSelectedUnits({excludeHumans: true});
+ var selectedUnits = this.getSelectedUnits({ excludeHumans: true });
for (let idx in selectedUnits) {
selectedUnits[idx].setAltitude(altitude);
}
@@ -273,7 +270,7 @@ export class UnitsManager {
}
selectedUnitsSetROE(ROE: string) {
- var selectedUnits = this.getSelectedUnits({excludeHumans: true});
+ var selectedUnits = this.getSelectedUnits({ excludeHumans: true });
for (let idx in selectedUnits) {
selectedUnits[idx].setROE(ROE);
}
@@ -281,7 +278,7 @@ export class UnitsManager {
}
selectedUnitsSetReactionToThreat(reactionToThreat: string) {
- var selectedUnits = this.getSelectedUnits({excludeHumans: true});
+ var selectedUnits = this.getSelectedUnits({ excludeHumans: true });
for (let idx in selectedUnits) {
selectedUnits[idx].setReactionToThreat(reactionToThreat);
}
@@ -289,7 +286,7 @@ export class UnitsManager {
}
selectedUnitsSetEmissionsCountermeasures(emissionCountermeasure: string) {
- var selectedUnits = this.getSelectedUnits({excludeHumans: true});
+ var selectedUnits = this.getSelectedUnits({ excludeHumans: true });
for (let idx in selectedUnits) {
selectedUnits[idx].setEmissionsCountermeasures(emissionCountermeasure);
}
@@ -298,7 +295,7 @@ export class UnitsManager {
selectedUnitsAttackUnit(ID: number) {
- var selectedUnits = this.getSelectedUnits({excludeHumans: true});
+ var selectedUnits = this.getSelectedUnits({ excludeHumans: true });
for (let idx in selectedUnits) {
selectedUnits[idx].attackUnit(ID);
}
@@ -314,7 +311,7 @@ export class UnitsManager {
}
selectedUnitsRefuel() {
- var selectedUnits = this.getSelectedUnits({excludeHumans: true});
+ var selectedUnits = this.getSelectedUnits({ excludeHumans: true });
for (let idx in selectedUnits) {
selectedUnits[idx].refuel();
}
@@ -328,15 +325,15 @@ export class UnitsManager {
// Y: top-bottom, positive top
// Z: left-right, positive right
offset = { "x": 0, "y": 0, "z": 0 };
- if (formation === "Trail") { offset.x = -50; offset.y = -30; offset.z = 0; }
- else if (formation === "Echelon (LH)") { offset.x = -50; offset.y = -10; offset.z = -50; }
- else if (formation === "Echelon (RH)") { offset.x = -50; offset.y = -10; offset.z = 50; }
- else if (formation === "Line abreast (RH)") { offset.x = 0; offset.y = 0; offset.z = 50; }
- else if (formation === "Line abreast (LH)") { offset.x = 0; offset.y = 0; offset.z = -50; }
- else if (formation === "Front") { offset.x = 100; offset.y = 0; offset.z = 0; }
+ if (formation === "trail") { offset.x = -50; offset.y = -30; offset.z = 0; }
+ else if (formation === "echelon-lh") { offset.x = -50; offset.y = -10; offset.z = -50; }
+ else if (formation === "echelon-rh") { offset.x = -50; offset.y = -10; offset.z = 50; }
+ else if (formation === "line-abreast-rh") { offset.x = 0; offset.y = 0; offset.z = 50; }
+ else if (formation === "line-abreast-lh") { offset.x = 0; offset.y = 0; offset.z = -50; }
+ else if (formation === "front") { offset.x = 100; offset.y = 0; offset.z = 0; }
else offset = undefined;
}
- var selectedUnits = this.getSelectedUnits({excludeHumans: true});
+ var selectedUnits = this.getSelectedUnits({ excludeHumans: true });
var count = 1;
var xr = 0; var yr = 1; var zr = -1;
var layer = 1;
@@ -347,7 +344,7 @@ export class UnitsManager {
unit.followUnit(ID, { "x": offset.x * count, "y": offset.y * count, "z": offset.z * count });
else {
/* More complex formations with variable offsets */
- if (formation === "Diamond") {
+ if (formation === "diamond") {
var xl = xr * Math.cos(Math.PI / 4) - yr * Math.sin(Math.PI / 4);
var yl = xr * Math.sin(Math.PI / 4) + yr * Math.cos(Math.PI / 4);
unit.followUnit(ID, { "x": -yl * 50, "y": zr * 10, "z": xl * 50 });
@@ -364,14 +361,12 @@ export class UnitsManager {
this.#showActionMessage(selectedUnits, `following unit ${this.getUnitByID(ID)?.getBaseData().unitName}`);
}
- selectedUnitsSetHotgroup(hotgroup: number)
- {
+ selectedUnitsSetHotgroup(hotgroup: number) {
this.getUnitsByHotgroup(hotgroup).forEach((unit: Unit) => unit.setHotgroup(null));
this.selectedUnitsAddToHotgroup(hotgroup);
}
- selectedUnitsAddToHotgroup(hotgroup: number)
- {
+ selectedUnitsAddToHotgroup(hotgroup: number) {
var selectedUnits = this.getSelectedUnits();
for (let idx in selectedUnits) {
selectedUnits[idx].setHotgroup(hotgroup);
@@ -380,11 +375,10 @@ export class UnitsManager {
getHotgroupPanel().refreshHotgroups();
}
- selectedUnitsComputeGroupDestination(latlng: LatLng, rotation: number)
- {
- var selectedUnits = this.getSelectedUnits({excludeHumans: true});
+ selectedUnitsComputeGroupDestination(latlng: LatLng, rotation: number) {
+ var selectedUnits = this.getSelectedUnits({ excludeHumans: true });
/* Compute the center of the group */
- var center = {x: 0, y: 0};
+ var center = { x: 0, y: 0 };
selectedUnits.forEach((unit: Unit) => {
var mercator = latLngToMercator(unit.getFlightData().latitude, unit.getFlightData().longitude);
center.x += mercator.x / selectedUnits.length;
@@ -392,20 +386,19 @@ export class UnitsManager {
});
/* Compute the distances from the center of the group */
-
- var unitDestinations: {[key: number]: LatLng} = {};
+ var unitDestinations: { [key: number]: LatLng } = {};
selectedUnits.forEach((unit: Unit) => {
var mercator = latLngToMercator(unit.getFlightData().latitude, unit.getFlightData().longitude);
- var distancesFromCenter = {dx: mercator.x - center.x, dy: mercator.y - center.y};
+ var distancesFromCenter = { dx: mercator.x - center.x, dy: mercator.y - center.y };
/* Rotate the distance according to the group rotation */
- var rotatedDistancesFromCenter: {dx: number, dy: number} = {dx: 0, dy: 0};
+ var rotatedDistancesFromCenter: { dx: number, dy: number } = { dx: 0, dy: 0 };
rotatedDistancesFromCenter.dx = distancesFromCenter.dx * Math.cos(deg2rad(rotation)) - distancesFromCenter.dy * Math.sin(deg2rad(rotation));
rotatedDistancesFromCenter.dy = distancesFromCenter.dx * Math.sin(deg2rad(rotation)) + distancesFromCenter.dy * Math.cos(deg2rad(rotation));
/* Compute the final position of the unit */
var destMercator = latLngToMercator(latlng.lat, latlng.lng); // Convert destination point to mercator
- var unitMercator = {x: destMercator.x + rotatedDistancesFromCenter.dx, y: destMercator.y + rotatedDistancesFromCenter.dy}; // Compute final position of this unit in mercator coordinates
+ var unitMercator = { x: destMercator.x + rotatedDistancesFromCenter.dx, y: destMercator.y + rotatedDistancesFromCenter.dy }; // Compute final position of this unit in mercator coordinates
var unitLatLng = mercatorToLatLng(unitMercator.x, unitMercator.y);
unitDestinations[unit.ID] = new LatLng(unitLatLng.lat, unitLatLng.lng);
});
diff --git a/scripts/OlympusCommand.lua b/scripts/OlympusCommand.lua
index 68adfc0f..bd61f8d2 100644
--- a/scripts/OlympusCommand.lua
+++ b/scripts/OlympusCommand.lua
@@ -524,6 +524,7 @@ function Olympus.setMissionData(arg, time)
bullseyes[i] = {}
bullseyes[i]["latitude"] = bullseyeLatitude
bullseyes[i]["longitude"] = bullseyeLongitude
+ bullseyes[i]["coalition"] = Olympus.getCoalitionByCoalitionID(i)
end
-- Units tactical data
@@ -589,14 +590,7 @@ function Olympus.setMissionData(arg, time)
local info = {}
local latitude, longitude, altitude = coord.LOtoLL(Airbase.getPoint(base[i]))
info["callsign"] = Airbase.getCallsign(base[i])
- local coalitionID = Airbase.getCoalition(base[i])
- if coalitionID == 0 then
- info["coalition"] = "neutral"
- elseif coalitionID == 1 then
- info["coalition"] = "red"
- else
- info["coalition"] = "blue"
- end
+ info["coalition"] = Olympus.getCoalitionByCoalitionID(Airbase.getCoalition(base[i]))
info["latitude"] = latitude
info["longitude"] = longitude
if Airbase.getUnit(base[i]) then