mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Fixed conflicts, ordered maps.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { LatLng } from "leaflet";
|
||||
import { setActiveCoalition } from "..";
|
||||
import { getActiveCoalition, setActiveCoalition } from "..";
|
||||
|
||||
export class SelectionScroll {
|
||||
#container: HTMLElement | null;
|
||||
@@ -15,14 +15,17 @@ export class SelectionScroll {
|
||||
}
|
||||
}
|
||||
|
||||
show(x: number, y: number, options: any, callback: CallableFunction, showCoalition: boolean) {
|
||||
show(x: number, y: number, title: string, options: any, callback: CallableFunction, showCoalition: boolean) {
|
||||
/* Hide to remove buttons, if present */
|
||||
this.hide();
|
||||
|
||||
if (this.#container != null && options.length >= 1) {
|
||||
var titleDiv = this.#container.querySelector("#olympus-selection-scroll-top-bar")?.querySelector(".olympus-selection-scroll-title");
|
||||
if (titleDiv)
|
||||
titleDiv.innerHTML = title;
|
||||
this.#container.style.display = this.#display;
|
||||
this.#container.style.left = x - 110 + "px";
|
||||
this.#container.style.top = y - 110 + "px";
|
||||
this.#container.style.left = x - this.#container.offsetWidth / 2 + "px";
|
||||
this.#container.style.top = y - 20 + "px";
|
||||
var scroll = this.#container.querySelector(".olympus-selection-scroll");
|
||||
if (scroll != null)
|
||||
{
|
||||
@@ -40,6 +43,20 @@ export class SelectionScroll {
|
||||
scroll.appendChild(node);
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide the coalition switch if required */
|
||||
var switchContainer = <HTMLElement>this.#container.querySelector("#olympus-selection-scroll-top-bar")?.querySelector("#coalition-switch-container");
|
||||
if (showCoalition == false) {
|
||||
switchContainer.style.display = "none";
|
||||
document.documentElement.style.setProperty('--active-coalition-color', getComputedStyle(this.#container).getPropertyValue("--neutral-coalition-color"));
|
||||
}
|
||||
else {
|
||||
switchContainer.style.display = "block";
|
||||
if (getActiveCoalition() == "blue")
|
||||
document.documentElement.style.setProperty('--active-coalition-color', getComputedStyle(this.#container).getPropertyValue("--blue-coalition-color"));
|
||||
else
|
||||
document.documentElement.style.setProperty('--active-coalition-color', getComputedStyle(this.#container).getPropertyValue("--red-coalition-color"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
83
client/src/controls/slider.ts
Normal file
83
client/src/controls/slider.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
export class Slider {
|
||||
#container: HTMLElement | null;
|
||||
#callback: CallableFunction;
|
||||
#slider: HTMLInputElement | null = null;
|
||||
#value: HTMLElement | null = null;
|
||||
#minValue: number;
|
||||
#maxValue: number;
|
||||
#minValueDiv: HTMLElement | null = null;
|
||||
#maxValueDiv: HTMLElement | null = null;
|
||||
#unit: string;
|
||||
#display: string = "";
|
||||
|
||||
constructor(ID: string, minValue: number, maxValue: number, unit: string, callback: CallableFunction) {
|
||||
this.#container = document.getElementById(ID);
|
||||
this.#callback = callback;
|
||||
this.#minValue = minValue;
|
||||
this.#maxValue = maxValue;
|
||||
this.#unit = unit;
|
||||
if (this.#container != null) {
|
||||
this.#display = this.#container.style.display;
|
||||
this.#slider = <HTMLInputElement>this.#container.querySelector("input");
|
||||
if (this.#slider != null)
|
||||
{
|
||||
this.#slider.addEventListener("input", (e: any) => this.#onInput());
|
||||
this.#slider.addEventListener("mouseup", (e: any) => this.#onFinalize());
|
||||
}
|
||||
this.#value = <HTMLElement>this.#container.querySelector("#value");
|
||||
}
|
||||
}
|
||||
|
||||
#onValue()
|
||||
{
|
||||
if (this.#value != null && this.#slider != null)
|
||||
this.#value.innerHTML = this.#minValue + Math.round(parseFloat(this.#slider.value) / 100 * (this.#maxValue - this.#minValue)) + this.#unit
|
||||
this.setActive(true);
|
||||
}
|
||||
|
||||
#onInput()
|
||||
{
|
||||
this.#onValue();
|
||||
}
|
||||
|
||||
#onFinalize()
|
||||
{
|
||||
if (this.#slider != null)
|
||||
this.#callback(this.#minValue + parseFloat(this.#slider.value) / 100 * (this.#maxValue - this.#minValue));
|
||||
}
|
||||
|
||||
show()
|
||||
{
|
||||
if (this.#container != null)
|
||||
this.#container.style.display = this.#display;
|
||||
}
|
||||
|
||||
hide()
|
||||
{
|
||||
if (this.#container != null)
|
||||
this.#container.style.display = 'none';
|
||||
}
|
||||
|
||||
setActive(newActive: boolean)
|
||||
{
|
||||
if (this.#container)
|
||||
{
|
||||
this.#container.classList.toggle("active", newActive);
|
||||
if (!newActive && this.#value != null)
|
||||
this.#value.innerHTML = "Mixed values"
|
||||
}
|
||||
}
|
||||
|
||||
setMinMax(newMinValue: number, newMaxValue: number)
|
||||
{
|
||||
this.#minValue = newMinValue;
|
||||
this.#maxValue = newMaxValue;
|
||||
}
|
||||
|
||||
setValue(newValue: number)
|
||||
{
|
||||
if (this.#slider != null)
|
||||
this.#slider.value = String((newValue - this.#minValue) / (this.#maxValue - this.#minValue) * 100);
|
||||
this.#onValue()
|
||||
}
|
||||
}
|
||||
@@ -89,7 +89,7 @@ export function attackUnit(ID: number, targetID: number) {
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
console.log("Unit " + getUnitsManager().getUnitByID(ID).unitName + " attack " + getUnitsManager().getUnitByID(targetID).unitName);
|
||||
//console.log("Unit " + getUnitsManager().getUnitByID(ID).unitName + " attack " + getUnitsManager().getUnitByID(targetID).unitName);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -99,29 +99,45 @@ export function attackUnit(ID: number, targetID: number) {
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function cloneUnit(ID: number) {
|
||||
export function cloneUnit(ID: number, latlng: L.LatLng) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
console.log("Unit " + getUnitsManager().getUnitByID(ID).unitName + " cloned");
|
||||
//console.log("Unit " + getUnitsManager().getUnitByID(ID).unitName + " cloned");
|
||||
}
|
||||
};
|
||||
|
||||
var command = { "ID": ID };
|
||||
var command = { "ID": ID, "location": latlng };
|
||||
var data = { "cloneUnit": command }
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function landAt(ID: number, latlng: L.LatLng) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
//console.log("Unit " + getUnitsManager().getUnitByID(ID).unitName + " cloned");
|
||||
}
|
||||
};
|
||||
|
||||
var command = { "ID": ID, "location": latlng };
|
||||
var data = { "landAt": command }
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function changeSpeed(ID: number, speedChange: string) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
console.log(getUnitsManager().getUnitByID(ID).unitName + " speed change request: " + speedChange);
|
||||
//console.log(getUnitsManager().getUnitByID(ID).unitName + " speed change request: " + speedChange);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -131,18 +147,98 @@ export function changeSpeed(ID: number, speedChange: string) {
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function setSpeed(ID: number, speed: number) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
//console.log(getUnitsManager().getUnitByID(ID).unitName + " speed change request: " + speedChange);
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"ID": ID, "speed": speed}
|
||||
var data = {"setSpeed": command}
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function changeAltitude(ID: number, altitudeChange: string) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
console.log(getUnitsManager().getUnitByID(ID).unitName + " altitude change request: " + altitudeChange);
|
||||
//console.log(getUnitsManager().getUnitByID(ID).unitName + " altitude change request: " + altitudeChange);
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"ID": ID, "change": altitudeChange}
|
||||
var data = {"changeAltitude": command}
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function setAltitude(ID: number, altitude: number) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
//console.log(getUnitsManager().getUnitByID(ID).unitName + " speed change request: " + speedChange);
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"ID": ID, "altitude": altitude}
|
||||
var data = {"setAltitude": command}
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function createFormation(ID: number, isLeader: boolean, wingmenIDs: number[]) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
//console.log(getUnitsManager().getUnitByID(ID).unitName + " created formation with: " + wingmenIDs);
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"ID": ID, "wingmenIDs": wingmenIDs, "isLeader": isLeader}
|
||||
var data = {"setLeader": command}
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function setROE(ID: number, ROE: string) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
//console.log(getUnitsManager().getUnitByID(ID).unitName + " speed change request: " + speedChange);
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"ID": ID, "ROE": ROE}
|
||||
var data = {"setROE": command}
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function setReactionToThreat(ID: number, reactionToThreat: string) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
//console.log(getUnitsManager().getUnitByID(ID).unitName + " speed change request: " + speedChange);
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"ID": ID, "reactionToThreat": reactionToThreat}
|
||||
var data = {"setReactionToThreat": command}
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
@@ -8,19 +8,25 @@ 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";
|
||||
|
||||
/* TODO: should this be a class? */
|
||||
var map: Map;
|
||||
var selectionWheel: SelectionWheel;
|
||||
var selectionScroll: SelectionScroll;
|
||||
|
||||
var unitsManager: UnitsManager;
|
||||
var missionData: MissionData;
|
||||
|
||||
var unitInfoPanel: UnitInfoPanel;
|
||||
var activeCoalition: string;
|
||||
var connectionStatusPanel: ConnectionStatusPanel;
|
||||
var unitControlPanel: UnitControlPanel;
|
||||
var mouseInfoPanel: MouseInfoPanel;
|
||||
|
||||
var scenarioDropdown: Dropdown;
|
||||
var mapSourceDropdown: Dropdown;
|
||||
var connected: boolean;
|
||||
var connectionStatusPanel: ConnectionStatusPanel;
|
||||
var missionData: MissionData;
|
||||
|
||||
var slowButton: Button;
|
||||
var fastButton: Button;
|
||||
@@ -31,6 +37,12 @@ var aiVisibilityButton: Button;
|
||||
var weaponVisibilityButton: Button;
|
||||
var deadVisibilityButton: Button;
|
||||
|
||||
var altitudeSlider: Slider;
|
||||
var airspeedSlider: Slider;
|
||||
|
||||
var connected: boolean;
|
||||
var activeCoalition: string;
|
||||
|
||||
function setup() {
|
||||
/* Initialize */
|
||||
map = new Map('map-container');
|
||||
@@ -38,9 +50,11 @@ function setup() {
|
||||
selectionScroll = new SelectionScroll("selection-scroll");
|
||||
unitsManager = new UnitsManager();
|
||||
unitInfoPanel = new UnitInfoPanel("unit-info-panel");
|
||||
unitControlPanel = new UnitControlPanel("unit-control-panel");
|
||||
scenarioDropdown = new Dropdown("scenario-dropdown", ["Caucasus", "Marianas", "Nevada", "South Atlantic", "Syria", "The Channel"], () => { });
|
||||
mapSourceDropdown = new Dropdown("map-source-dropdown", map.getLayers(), (option: string) => map.setLayer(option));
|
||||
connectionStatusPanel = new ConnectionStatusPanel("connection-status-panel");
|
||||
mouseInfoPanel = new MouseInfoPanel("mouse-info-panel");
|
||||
missionData = new MissionData();
|
||||
|
||||
/* Unit control buttons */
|
||||
@@ -49,6 +63,10 @@ function setup() {
|
||||
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));
|
||||
|
||||
/* Visibility buttons */
|
||||
userVisibilityButton = new Button("user-visibility-button", ["images/buttons/user-full.svg", "images/buttons/user-partial.svg", "images/buttons/user-none.svg", "images/buttons/user-hidden.svg"], () => { });
|
||||
aiVisibilityButton = new Button("ai-visibility-button", ["images/buttons/ai-full.svg", "images/buttons/ai-partial.svg", "images/buttons/ai-none.svg", "images/buttons/ai-hidden.svg"], () => { });
|
||||
@@ -93,6 +111,10 @@ export function getMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
export function getMissionData() {
|
||||
return missionData;
|
||||
}
|
||||
|
||||
export function getSelectionWheel() {
|
||||
return selectionWheel;
|
||||
}
|
||||
@@ -109,6 +131,14 @@ export function getUnitInfoPanel() {
|
||||
return unitInfoPanel;
|
||||
}
|
||||
|
||||
export function getUnitControlPanel() {
|
||||
return unitControlPanel;
|
||||
}
|
||||
|
||||
export function getMouseInfoPanel() {
|
||||
return mouseInfoPanel;
|
||||
}
|
||||
|
||||
export function setActiveCoalition(newActiveCoalition: string) {
|
||||
activeCoalition = newActiveCoalition;
|
||||
}
|
||||
@@ -173,4 +203,12 @@ export function getVisibilitySettings() {
|
||||
return visibility;
|
||||
}
|
||||
|
||||
export function getVisibilityButtons() {
|
||||
return {user: userVisibilityButton, ai: aiVisibilityButton, weapon: weaponVisibilityButton, dead: deadVisibilityButton}
|
||||
}
|
||||
|
||||
export function getUnitControlSliders() {
|
||||
return {altitude: altitudeSlider, airspeed: airspeedSlider}
|
||||
}
|
||||
|
||||
window.onload = setup;
|
||||
@@ -45,7 +45,7 @@ export var BoxSelect = Handler.extend({
|
||||
},
|
||||
|
||||
_onMouseDown: function (e: any) {
|
||||
if (((e.which !== 3) && (e.button !== 2))) { return false; }
|
||||
if (((e.which !== 1) && (e.button !== 0))) { return false; }
|
||||
|
||||
// Clear the deferred resetState if it hasn't executed yet, otherwise it
|
||||
// will interrupt the interaction and orphan a box element in the container.
|
||||
@@ -107,7 +107,7 @@ export var BoxSelect = Handler.extend({
|
||||
},
|
||||
|
||||
_onMouseUp: function (e: any) {
|
||||
if ((e.which !== 3) && (e.button !== 2)) { return; }
|
||||
if ((e.which !== 1) && (e.button !== 0)) { return; }
|
||||
|
||||
this._finish();
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as L from "leaflet"
|
||||
import { getSelectionWheel, getSelectionScroll, getUnitsManager, getActiveCoalition } from "..";
|
||||
import { getSelectionWheel, getSelectionScroll, getUnitsManager, getActiveCoalition, getMouseInfoPanel } from "..";
|
||||
import { spawnAircraft, spawnGroundUnit, spawnSmoke } from "../dcs/dcs";
|
||||
import { bearing, distance, zeroAppend } from "../other/utils";
|
||||
import { payloadNames } from "../units/payloadNames";
|
||||
import { unitTypes } from "../units/unitTypes";
|
||||
import { BoxSelect } from "./boxselect";
|
||||
@@ -21,8 +22,14 @@ export interface SpawnEvent extends ClickEvent{
|
||||
export class Map extends L.Map {
|
||||
#state: string;
|
||||
#layer?: L.TileLayer;
|
||||
#preventRightClick: boolean = false;
|
||||
#rightClickTimer: number = 0;
|
||||
#preventLeftClick: boolean = false;
|
||||
#leftClickTimer: number = 0;
|
||||
#measurePoint: L.LatLng | null;
|
||||
#measureIcon: L.Icon;
|
||||
#measureMarker: L.Marker;
|
||||
#measureLine: L.Polyline = new L.Polyline([], { color: '#2d3e50', weight: 3, opacity: 0.5, smoothFactor: 1, interactive: false });
|
||||
#measureLineDiv: HTMLElement;
|
||||
#lastMousePosition: L.Point = new L.Point(0, 0);
|
||||
|
||||
constructor(ID: string) {
|
||||
/* Init the leaflet map */
|
||||
@@ -34,12 +41,25 @@ export class Map extends L.Map {
|
||||
|
||||
/* Init the state machine */
|
||||
this.#state = "IDLE";
|
||||
this.#measurePoint = null;
|
||||
|
||||
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.style.display = 'none';
|
||||
|
||||
document.body.appendChild(this.#measureLineDiv);
|
||||
|
||||
/* Register event handles */
|
||||
this.on("click", (e: any) => this.#onClick(e));
|
||||
this.on("dblclick", (e: any) => this.#onDoubleClick(e));
|
||||
this.on("contextmenu", (e: any) => this.#onContextMenu(e));
|
||||
this.on('selectionend', (e: any) => this.#onSelectionEnd(e));
|
||||
this.on('mousedown', (e: any) => this.#onMouseDown(e));
|
||||
this.on('mouseup', (e: any) => this.#onMouseUp(e));
|
||||
this.on('mousemove', (e: any) => this.#onMouseMove(e));
|
||||
this.on('zoom', (e: any) => this.#onZoom(e));
|
||||
}
|
||||
|
||||
setLayer(layerName: string) {
|
||||
@@ -124,63 +144,133 @@ export class Map extends L.Map {
|
||||
}
|
||||
|
||||
/* Selection scroll */
|
||||
showSelectionScroll(e: ClickEvent | SpawnEvent, options: any, callback: CallableFunction, showCoalition: boolean = false) {
|
||||
showSelectionScroll(e: ClickEvent | SpawnEvent, title: string, options: any, callback: CallableFunction, showCoalition: boolean = false) {
|
||||
var x = e.x;
|
||||
var y = e.y;
|
||||
getSelectionScroll().show(x, y, options, callback, showCoalition);
|
||||
getSelectionScroll().show(x, y, title, options, callback, showCoalition);
|
||||
}
|
||||
|
||||
hideSelectionScroll() {
|
||||
getSelectionScroll().hide();
|
||||
}
|
||||
|
||||
getMousePosition() {
|
||||
return this.#lastMousePosition;
|
||||
}
|
||||
|
||||
getMouseCoordinates() {
|
||||
return this.containerPointToLatLng(this.#lastMousePosition);
|
||||
}
|
||||
|
||||
/* Event handlers */
|
||||
#onClick(e: any) {
|
||||
this.hideSelectionWheel();
|
||||
this.hideSelectionScroll();
|
||||
if (this.#state === "IDLE") {
|
||||
|
||||
}
|
||||
else if (this.#state === "MOVE_UNIT") {
|
||||
if (!e.originalEvent.ctrlKey) {
|
||||
getUnitsManager().clearDestinations();
|
||||
if (!this.#preventLeftClick) {
|
||||
this.hideSelectionWheel();
|
||||
this.hideSelectionScroll();
|
||||
if (this.#state === "IDLE") {
|
||||
if (e.originalEvent.ctrlKey)
|
||||
if (!this.#measurePoint)
|
||||
{
|
||||
this.#measurePoint = e.latlng;
|
||||
this.#measureMarker.setLatLng(e.latlng);
|
||||
this.#measureMarker.addTo(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.#measurePoint = null;
|
||||
if (this.hasLayer(this.#measureMarker))
|
||||
this.removeLayer(this.#measureMarker);
|
||||
}
|
||||
}
|
||||
getUnitsManager().addDestination(e.latlng)
|
||||
}
|
||||
}
|
||||
|
||||
#onDoubleClick(e: any) {
|
||||
var spawnEvent: SpawnEvent = {x: e.originalEvent.x, y: e.originalEvent.y, latlng: e.latlng, airbaseName: null, coalitionID: null};
|
||||
if (this.#state == "IDLE") {
|
||||
var options = [
|
||||
{ "tooltip": "Spawn air unit", "src": "spawnAir.png", "callback": () => this.#aircraftSpawnMenu(spawnEvent) },
|
||||
{ "tooltip": "Spawn ground unit", "src": "spawnGround.png", "callback": () => this.#groundUnitSpawnMenu(spawnEvent) },
|
||||
{ "tooltip": "Smoke", "src": "spawnSmoke.png", "callback": () => this.#smokeSpawnMenu(spawnEvent) },
|
||||
//{ "tooltip": "Explosion", "src": "spawnExplosion.png", "callback": () => this.#explosionSpawnMenu(e) }
|
||||
]
|
||||
this.showSelectionScroll(spawnEvent, options, () => {}, true);
|
||||
}
|
||||
}
|
||||
|
||||
#onContextMenu(e: any) {
|
||||
this.#rightClickTimer = setTimeout(() => {
|
||||
if (!this.#preventRightClick) {
|
||||
else if (this.#state === "MOVE_UNIT") {
|
||||
this.setState("IDLE");
|
||||
getUnitsManager().deselectAllUnits();
|
||||
this.hideSelectionWheel();
|
||||
this.hideSelectionScroll();
|
||||
}
|
||||
this.#preventRightClick = false;
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
|
||||
#onDoubleClick(e: any) {
|
||||
|
||||
}
|
||||
|
||||
#onContextMenu(e: any) {
|
||||
this.hideSelectionWheel();
|
||||
this.hideSelectionScroll();
|
||||
if (this.#state === "IDLE") {
|
||||
var spawnEvent: SpawnEvent = {x: e.originalEvent.x, y: e.originalEvent.y, latlng: e.latlng, airbaseName: null, coalitionID: null};
|
||||
if (this.#state == "IDLE") {
|
||||
var options = [
|
||||
{ "tooltip": "Spawn air unit", "src": "spawnAir.png", "callback": () => this.#aircraftSpawnMenu(spawnEvent) },
|
||||
{ "tooltip": "Spawn ground unit", "src": "spawnGround.png", "callback": () => this.#groundUnitSpawnMenu(spawnEvent) },
|
||||
{ "tooltip": "Smoke", "src": "spawnSmoke.png", "callback": () => this.#smokeSpawnMenu(spawnEvent) },
|
||||
//{ "tooltip": "Explosion", "src": "spawnExplosion.png", "callback": () => this.#explosionSpawnMenu(e) }
|
||||
]
|
||||
this.showSelectionScroll(spawnEvent, "Action", options, () => {}, false);
|
||||
}
|
||||
}
|
||||
else if (this.#state === "MOVE_UNIT") {
|
||||
if (!e.originalEvent.ctrlKey) {
|
||||
getUnitsManager().selectedUnitsClearDestinations();
|
||||
}
|
||||
getUnitsManager().selectedUnitsAddDestination(e.latlng)
|
||||
}
|
||||
}
|
||||
|
||||
#onSelectionEnd(e: any)
|
||||
{
|
||||
clearTimeout(this.#rightClickTimer);
|
||||
this.#preventRightClick = true;
|
||||
clearTimeout(this.#leftClickTimer);
|
||||
this.#preventLeftClick = true;
|
||||
this.#leftClickTimer = setTimeout(() => {
|
||||
this.#preventLeftClick = false;
|
||||
}, 200);
|
||||
getUnitsManager().selectFromBounds(e.selectionBounds);
|
||||
}
|
||||
|
||||
#onMouseDown(e: any)
|
||||
{
|
||||
if ((e.originalEvent.which == 1) && (e.originalEvent.button == 0))
|
||||
{
|
||||
this.dragging.disable();
|
||||
}
|
||||
}
|
||||
|
||||
#onMouseUp(e: any)
|
||||
{
|
||||
if ((e.originalEvent.which == 1) && (e.originalEvent.button == 0))
|
||||
{
|
||||
this.dragging.enable();
|
||||
}
|
||||
}
|
||||
|
||||
#onMouseMove(e: any)
|
||||
{
|
||||
var selectedUnitPosition = null;
|
||||
var selectedUnits = getUnitsManager().getSelectedUnits();
|
||||
if (selectedUnits && selectedUnits.length == 1)
|
||||
{
|
||||
selectedUnitPosition = new L.LatLng(selectedUnits[0].latitude, selectedUnits[0].longitude);
|
||||
}
|
||||
getMouseInfoPanel().update(<L.LatLng>e.latlng, this.#measurePoint, selectedUnitPosition);
|
||||
|
||||
this.#lastMousePosition.x = e.originalEvent.x;
|
||||
this.#lastMousePosition.y = e.originalEvent.y;
|
||||
|
||||
if ( this.#measurePoint)
|
||||
this.#drawMeasureLine();
|
||||
else
|
||||
this.#hideMeasureLine();
|
||||
}
|
||||
|
||||
#onZoom(e: any)
|
||||
{
|
||||
if (this.#measurePoint)
|
||||
this.#drawMeasureLine();
|
||||
else
|
||||
this.#hideMeasureLine();
|
||||
}
|
||||
|
||||
/* Spawn from air base */
|
||||
spawnFromAirbase(e: SpawnEvent)
|
||||
{
|
||||
@@ -198,7 +288,7 @@ export class Map extends L.Map {
|
||||
{'coalition': true, 'tooltip': 'Radar', 'src': 'spawnRadar.png', 'callback': () => this.#selectGroundUnit(e, "Radar")},
|
||||
{'coalition': true, 'tooltip': 'Unarmed', 'src': 'spawnUnarmed.png', 'callback': () => this.#selectGroundUnit(e, "Unarmed")}
|
||||
]
|
||||
this.showSelectionScroll(e, options, () => {}, true);
|
||||
this.showSelectionScroll(e, "Spawn ground unit", options, () => {}, true);
|
||||
}
|
||||
|
||||
#smokeSpawnMenu(e: SpawnEvent) {
|
||||
@@ -211,7 +301,7 @@ export class Map extends L.Map {
|
||||
{'tooltip': 'Green smoke', 'src': 'spawnSmoke.png', 'callback': () => {this.hideSelectionWheel(); this.hideSelectionScroll(); spawnSmoke('green', e.latlng)}, 'tint': 'green'},
|
||||
{'tooltip': 'Orange smoke', 'src': 'spawnSmoke.png', 'callback': () => {this.hideSelectionWheel(); this.hideSelectionScroll(); spawnSmoke('orange', e.latlng)}, 'tint': 'orange'},
|
||||
]
|
||||
this.showSelectionScroll(e, options, () => {}, true);
|
||||
this.showSelectionScroll(e, "Spawn smoke", options, () => {}, false);
|
||||
}
|
||||
|
||||
#explosionSpawnMenu(e: SpawnEvent) {
|
||||
@@ -228,7 +318,10 @@ export class Map extends L.Map {
|
||||
{ 'coalition': true, 'tooltip': 'Drone', 'src': 'spawnDrone.png', 'callback': () => this.#selectAircraft(e, "drone") },
|
||||
{ 'coalition': true, 'tooltip': 'Transport', 'src': 'spawnTransport.png', 'callback': () => this.#selectAircraft(e, "transport") },
|
||||
]
|
||||
this.showSelectionScroll(e, options, () => {}, true);
|
||||
if (e.airbaseName != null)
|
||||
this.showSelectionScroll(e, "Spawn at " + e.airbaseName, options, () => {}, true);
|
||||
else
|
||||
this.showSelectionScroll(e, "Spawn air unit", options, () => {}, true);
|
||||
}
|
||||
|
||||
/* Show unit selection for air units */
|
||||
@@ -240,11 +333,11 @@ export class Map extends L.Map {
|
||||
options.sort();
|
||||
else
|
||||
options = [];
|
||||
this.showSelectionScroll(e, options, (unitType: string) => {
|
||||
this.showSelectionScroll(e, "Select aircraft", options, (unitType: string) => {
|
||||
this.hideSelectionWheel();
|
||||
this.hideSelectionScroll();
|
||||
this.#unitSelectPayload(e, unitType);
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
|
||||
/* Show weapon selection for air units */
|
||||
@@ -255,11 +348,11 @@ export class Map extends L.Map {
|
||||
options = payloadNames[unitType]
|
||||
if (options != undefined && options.length > 0) {
|
||||
options.sort();
|
||||
this.showSelectionScroll({x: e.x, y: e.y, latlng: e.latlng}, options, (payloadName: string) => {
|
||||
this.showSelectionScroll({x: e.x, y: e.y, latlng: e.latlng}, "Select loadout", options, (payloadName: string) => {
|
||||
this.hideSelectionWheel();
|
||||
this.hideSelectionScroll();
|
||||
spawnAircraft(unitType, e.latlng, getActiveCoalition(), payloadName, e.airbaseName);
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
else {
|
||||
spawnAircraft(unitType, e.latlng, getActiveCoalition());
|
||||
@@ -273,10 +366,49 @@ export class Map extends L.Map {
|
||||
this.hideSelectionScroll();
|
||||
var options = unitTypes.vehicles[group];
|
||||
options.sort();
|
||||
this.showSelectionScroll(e, options, (unitType: string) => {
|
||||
this.showSelectionScroll(e, "Select ground unit", options, (unitType: string) => {
|
||||
this.hideSelectionWheel();
|
||||
this.hideSelectionScroll();
|
||||
spawnGroundUnit(unitType, e.latlng, getActiveCoalition());
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
|
||||
#drawMeasureLine()
|
||||
{
|
||||
var mouseLatLng = this.containerPointToLatLng(this.#lastMousePosition);
|
||||
if (this.#measurePoint != null)
|
||||
{
|
||||
var points = [this.#measurePoint, mouseLatLng];
|
||||
this.#measureLine.setLatLngs(points);
|
||||
var dist = distance(this.#measurePoint.lat, this.#measurePoint.lng, mouseLatLng.lat, mouseLatLng.lng);
|
||||
var bear = bearing(this.#measurePoint.lat, this.#measurePoint.lng, mouseLatLng.lat, mouseLatLng.lng);
|
||||
var startXY = this.latLngToContainerPoint(this.#measurePoint);
|
||||
var dx = (this.#lastMousePosition.x - startXY.x);
|
||||
var dy = (this.#lastMousePosition.y - startXY.y);
|
||||
|
||||
var angle = Math.atan2(dy, dx);
|
||||
if (angle > Math.PI / 2)
|
||||
angle = angle - Math.PI;
|
||||
|
||||
if (angle < -Math.PI / 2)
|
||||
angle = angle + Math.PI;
|
||||
|
||||
this.#measureLineDiv.innerHTML = `${zeroAppend(Math.floor(bear), 3)}° / ${zeroAppend(Math.floor(dist*0.000539957), 3)} NM`
|
||||
this.#measureLineDiv.style.left = (this.#lastMousePosition.x + startXY.x) / 2 - this.#measureLineDiv.offsetWidth / 2 + "px";
|
||||
this.#measureLineDiv.style.top = (this.#lastMousePosition.y + startXY.y) / 2 - this.#measureLineDiv.offsetHeight / 2 + "px";
|
||||
this.#measureLineDiv.style.rotate = angle + "rad";
|
||||
this.#measureLineDiv.style.display = "";
|
||||
}
|
||||
|
||||
if (!this.hasLayer(this.#measureLine))
|
||||
this.#measureLine.addTo(this);
|
||||
}
|
||||
|
||||
#hideMeasureLine()
|
||||
{
|
||||
this.#measureLineDiv.style.display = "none";
|
||||
|
||||
if (this.hasLayer(this.#measureLine))
|
||||
this.removeLayer(this.#measureLine)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,41 +1,56 @@
|
||||
import { Marker, LatLng } from "leaflet";
|
||||
import { getMap } from "..";
|
||||
import { Marker, LatLng, Icon } from "leaflet";
|
||||
import { getMap, getUnitsManager } from "..";
|
||||
import { SpawnEvent } from "../map/map";
|
||||
import { AirbaseMarker } from "./airbasemarker";
|
||||
|
||||
var bullseyeIcons = [
|
||||
new Icon({ iconUrl: 'images/bullseye0.png', iconAnchor: [30, 30]}),
|
||||
new Icon({ iconUrl: 'images/bullseye1.png', iconAnchor: [30, 30]}),
|
||||
new Icon({ iconUrl: 'images/bullseye2.png', iconAnchor: [30, 30]})
|
||||
]
|
||||
|
||||
export class MissionData
|
||||
{
|
||||
//#bullseye : any; //TODO declare interface
|
||||
//#bullseyeMarker : Marker;
|
||||
#bullseyes : any; //TODO declare interface
|
||||
#bullseyeMarkers: any;
|
||||
#airbases : any; //TODO declare interface
|
||||
#airbasesMarkers: {[name: string]: AirbaseMarker};
|
||||
|
||||
constructor()
|
||||
{
|
||||
//this.#bullseye = undefined;
|
||||
//this.#bullseyeMarker = undefined;
|
||||
this.#bullseyes = undefined;
|
||||
this.#bullseyeMarkers = [
|
||||
new Marker([0, 0], {icon: bullseyeIcons[0]}).addTo(getMap()),
|
||||
new Marker([0, 0], {icon: bullseyeIcons[1]}).addTo(getMap()),
|
||||
new Marker([0, 0], {icon: bullseyeIcons[2]}).addTo(getMap())
|
||||
]
|
||||
this.#airbasesMarkers = {};
|
||||
}
|
||||
|
||||
update(data: any)
|
||||
{
|
||||
//this.#bullseye = data.missionData.bullseye;
|
||||
this.#bullseyes = data.bullseye;
|
||||
this.#airbases = data.airbases;
|
||||
//this.#drawBullseye();
|
||||
this.#drawAirbases();
|
||||
if (this.#bullseyes != null && this.#airbases != null)
|
||||
{
|
||||
this.#drawBullseye();
|
||||
this.#drawAirbases();
|
||||
}
|
||||
}
|
||||
|
||||
//#drawBullseye()
|
||||
//{
|
||||
// if (this.#bullseyeMarker === undefined)
|
||||
// {
|
||||
// this.#bullseyeMarker = new Marker([this.#bullseye.lat, this.#bullseye.lng]).addTo(map.getMap());
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// this.#bullseyeMarker.setLatLng(new LatLng(this.#bullseye.lat, this.#bullseye.lng));
|
||||
// }
|
||||
//}
|
||||
getBullseyes()
|
||||
{
|
||||
return this.#bullseyes;
|
||||
}
|
||||
|
||||
#drawBullseye()
|
||||
{
|
||||
for (let idx in this.#bullseyes)
|
||||
{
|
||||
var bullseye = this.#bullseyes[idx];
|
||||
this.#bullseyeMarkers[idx].setLatLng(new LatLng(bullseye.lat, bullseye.lng));
|
||||
}
|
||||
}
|
||||
|
||||
#drawAirbases()
|
||||
{
|
||||
@@ -48,7 +63,7 @@ export class MissionData
|
||||
position: new LatLng(airbase.lat, airbase.lng),
|
||||
name: airbase.callsign,
|
||||
src: "images/airbase.png"}).addTo(getMap());
|
||||
this.#airbasesMarkers[idx].on('click', (e) => this.#onAirbaseClick(e));
|
||||
this.#airbasesMarkers[idx].on('contextmenu', (e) => this.#onAirbaseClick(e));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -59,7 +74,25 @@ export class MissionData
|
||||
|
||||
#onAirbaseClick(e: any)
|
||||
{
|
||||
var spawnEvent: SpawnEvent = {x: e.originalEvent.x, y: e.originalEvent.y, latlng: e.latlng, airbaseName: e.sourceTarget.getName(), coalitionID: e.sourceTarget.getCoalitionID()};
|
||||
getMap().spawnFromAirbase(spawnEvent);
|
||||
var options = [];
|
||||
if (getUnitsManager().getSelectedUnits().length > 0)
|
||||
options = ["Spawn unit", "Land here"];
|
||||
else
|
||||
options = ["Spawn unit"];
|
||||
getMap().showSelectionScroll(e.originalEvent, e.sourceTarget.getName(), options, (option: string) => this.#onAirbaseOptionSelection(e, option), false);
|
||||
|
||||
}
|
||||
|
||||
#onAirbaseOptionSelection(e: any, option: string) {
|
||||
if (option === "Spawn unit") {
|
||||
var spawnEvent: SpawnEvent = {x: e.originalEvent.x, y: e.originalEvent.y, latlng: e.latlng, airbaseName: e.sourceTarget.getName(), coalitionID: e.sourceTarget.getCoalitionID()};
|
||||
getMap().spawnFromAirbase(spawnEvent);
|
||||
}
|
||||
else if (option === "Land here")
|
||||
{
|
||||
getMap().hideSelectionWheel();
|
||||
getMap().hideSelectionScroll();
|
||||
getUnitsManager().selectedUnitsLandAt(e.latlng);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ export function bearing(lat1: number, lon1: number, lat2: number, lon2: number)
|
||||
return brng;
|
||||
}
|
||||
|
||||
const zeroPad = function (num: number, places: number) {
|
||||
export const zeroPad = function (num: number, places: number) {
|
||||
var string = String(num);
|
||||
while (string.length < places) {
|
||||
string += "0";
|
||||
@@ -34,6 +34,14 @@ const zeroPad = function (num: number, places: number) {
|
||||
return string;
|
||||
}
|
||||
|
||||
export const zeroAppend = function (num: number, places: number) {
|
||||
var string = String(num);
|
||||
while (string.length < places) {
|
||||
string = "0" + string;
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
export function ConvertDDToDMS(D: number, lng: boolean) {
|
||||
var dir = D < 0 ? (lng ? "W" : "S") : lng ? "E" : "N";
|
||||
var deg = 0 | (D < 0 ? (D = -D) : D);
|
||||
|
||||
73
client/src/panels/mouseInfoPanel.ts
Normal file
73
client/src/panels/mouseInfoPanel.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
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;
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
update(mousePosition: LatLng, measurePosition: LatLng | null, unitPosition: LatLng | null) {
|
||||
var bullseyes = getMissionData().getBullseyes();
|
||||
for (let idx in bullseyes)
|
||||
{
|
||||
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}`);
|
||||
if (el != null)
|
||||
el.innerHTML = `${zeroAppend(Math.floor(bear), 3)}° / ${zeroAppend(Math.floor(dist*0.000539957), 3)} NM`
|
||||
}
|
||||
|
||||
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`);
|
||||
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
|
||||
}
|
||||
}
|
||||
else {
|
||||
var el = <HTMLElement>this.#element.querySelector(`#measure-position`);
|
||||
if (el != null && el.parentElement != null)
|
||||
el.parentElement.style.display = 'none';
|
||||
}
|
||||
|
||||
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`);
|
||||
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
|
||||
}
|
||||
}
|
||||
else {
|
||||
var el = <HTMLElement>this.#element.querySelector(`#unit-position`);
|
||||
if (el != null && el.parentElement != null)
|
||||
el.parentElement.style.display = 'none';
|
||||
}
|
||||
}
|
||||
}
|
||||
363
client/src/panels/unitcontrolpanel.ts
Normal file
363
client/src/panels/unitcontrolpanel.ts
Normal file
@@ -0,0 +1,363 @@
|
||||
import { imageOverlay } from "leaflet";
|
||||
import { getUnitControlSliders, getUnitsManager } from "..";
|
||||
import { ConvertDDToDMS, rad2deg } from "../other/utils";
|
||||
import { Aircraft, AirUnit, GroundUnit, Helicopter, NavyUnit, Unit } from "../units/unit";
|
||||
|
||||
export class UnitControlPanel {
|
||||
#element: HTMLElement
|
||||
#display: string;
|
||||
|
||||
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());
|
||||
|
||||
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"));
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
show() {
|
||||
this.#element.style.display = this.#display;
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.#element.style.display = "none";
|
||||
}
|
||||
|
||||
update(units: Unit[]) {
|
||||
if (this.#element != 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);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#showFlightControlSliders(units: Unit[])
|
||||
{
|
||||
var sliders = getUnitControlSliders();
|
||||
sliders.airspeed.show();
|
||||
sliders.altitude.show();
|
||||
|
||||
if (this.#checkAllUnitsAircraft(units))
|
||||
{
|
||||
sliders.airspeed.setMinMax(100, 600);
|
||||
sliders.altitude.setMinMax(0, 50000);
|
||||
}
|
||||
else if (this.#checkAllUnitsHelicopter(units))
|
||||
{
|
||||
sliders.airspeed.setMinMax(0, 200);
|
||||
sliders.altitude.setMinMax(0, 10000);
|
||||
}
|
||||
else if (this.#checkAllUnitsGroundUnit(units))
|
||||
{
|
||||
sliders.airspeed.setMinMax(0, 60);
|
||||
sliders.altitude.hide();
|
||||
}
|
||||
else if (this.#checkAllUnitsNavyUnit(units))
|
||||
{
|
||||
sliders.airspeed.setMinMax(0, 60);
|
||||
sliders.altitude.hide();
|
||||
}
|
||||
else {
|
||||
sliders.airspeed.hide();
|
||||
sliders.altitude.hide();
|
||||
}
|
||||
|
||||
var targetSpeed = this.#getTargetAirspeed(units);
|
||||
if (targetSpeed != null)
|
||||
{
|
||||
sliders.airspeed.setActive(true);
|
||||
sliders.airspeed.setValue(targetSpeed * 1.94384);
|
||||
}
|
||||
else
|
||||
{
|
||||
sliders.airspeed.setActive(false);
|
||||
}
|
||||
|
||||
var targetAltitude = this.#getTargetAltitude(units);
|
||||
if (targetAltitude != null)
|
||||
{
|
||||
sliders.altitude.setActive(true);
|
||||
sliders.altitude.setValue(targetAltitude / 0.3048);
|
||||
}
|
||||
else
|
||||
{
|
||||
sliders.altitude.setActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
#addUnitsButtons(units: Unit[], selectedUnitsContainer: HTMLElement)
|
||||
{
|
||||
/* Remove any pre-existing unit button */
|
||||
var elements = selectedUnitsContainer.getElementsByClassName("js-unit-container");
|
||||
while (elements.length > 0)
|
||||
selectedUnitsContainer.removeChild(elements[0])
|
||||
|
||||
/* Create all the units buttons */
|
||||
for (let unit of units)
|
||||
{
|
||||
this.#addUnitButton(unit, selectedUnitsContainer);
|
||||
if (unit.isLeader)
|
||||
for (let wingman of unit.getWingmen())
|
||||
this.#addUnitButton(wingman, selectedUnitsContainer);
|
||||
}
|
||||
}
|
||||
|
||||
#addUnitButton(unit: Unit, container: HTMLElement)
|
||||
{
|
||||
var el = document.createElement("div");
|
||||
|
||||
/* Unit name (actually type, but DCS calls it name for some reason) */
|
||||
var nameDiv = document.createElement("div");
|
||||
nameDiv.classList.add("rounded-container-small");
|
||||
if (unit.name.length >= 7)
|
||||
nameDiv.innerHTML = `${unit.name.substring(0, 4)} ...`;
|
||||
else
|
||||
nameDiv.innerHTML = `${unit.name}`;
|
||||
|
||||
/* Unit icon */
|
||||
var icon = document.createElement("img");
|
||||
if (unit.isLeader)
|
||||
icon.src = "images/icons/formation.png"
|
||||
else if (unit.isWingman)
|
||||
{
|
||||
var wingmen = unit.getLeader()?.getWingmen();
|
||||
if (wingmen && wingmen.lastIndexOf(unit) == wingmen.length - 1)
|
||||
icon.src = "images/icons/formation-end.svg"
|
||||
else
|
||||
icon.src = "images/icons/formation-middle.svg"
|
||||
}
|
||||
|
||||
else
|
||||
icon.src = "images/icons/singleton.png"
|
||||
|
||||
el.innerHTML = unit.unitName;
|
||||
|
||||
el.prepend(nameDiv);
|
||||
|
||||
/* Show the icon only for air units */
|
||||
if ((unit instanceof AirUnit))
|
||||
el.append(icon);
|
||||
|
||||
el.classList.add("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.addEventListener("click", () => getUnitsManager().selectUnit(unit.ID));
|
||||
container.appendChild(el);
|
||||
}
|
||||
|
||||
#showFormationButtons(units: Unit[], formationCreationContainer: HTMLElement)
|
||||
{
|
||||
var createButton = <HTMLElement>formationCreationContainer.querySelector("#create-formation");
|
||||
var undoButton = <HTMLElement>formationCreationContainer.querySelector("#undo-formation");
|
||||
if (createButton && undoButton && this.#checkAllUnitsAir(units))
|
||||
{
|
||||
if (!this.#checkUnitsAlreadyInFormation(units))
|
||||
{
|
||||
createButton.style.display = '';
|
||||
undoButton.style.display = 'none';
|
||||
}
|
||||
else if (this.#checkUnitsAlreadyInFormation(units) && this.#checkAllUnitsSameFormation(units))
|
||||
{
|
||||
createButton.style.display = 'none';
|
||||
undoButton.style.display = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
createButton.style.display = 'none';
|
||||
undoButton.style.display = 'none';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#checkAllUnitsAir(units: Unit[])
|
||||
{
|
||||
for (let unit of units)
|
||||
if (!(unit instanceof AirUnit))
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
#checkAllUnitsAircraft(units: Unit[])
|
||||
{
|
||||
for (let unit of units)
|
||||
if (!(unit instanceof Aircraft))
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
#checkAllUnitsHelicopter(units: Unit[])
|
||||
{
|
||||
for (let unit of units)
|
||||
if (!(unit instanceof Helicopter))
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
#checkAllUnitsGroundUnit(units: Unit[])
|
||||
{
|
||||
for (let unit of units)
|
||||
if (!(unit instanceof GroundUnit))
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
#checkAllUnitsNavyUnit(units: Unit[])
|
||||
{
|
||||
for (let unit of units)
|
||||
if (!(unit instanceof NavyUnit))
|
||||
return false
|
||||
return true
|
||||
}
|
||||
|
||||
#checkAllUnitsSameFormation(units: Unit[])
|
||||
{
|
||||
var leaderFound = false;
|
||||
for (let unit of units)
|
||||
{
|
||||
if (unit.isLeader)
|
||||
{
|
||||
if (leaderFound)
|
||||
return false
|
||||
else
|
||||
leaderFound = true;
|
||||
}
|
||||
if (!unit.isLeader)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
#checkUnitsAlreadyInFormation(units: Unit[])
|
||||
{
|
||||
for (let unit of units)
|
||||
if (unit.isLeader)
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
#getTargetAirspeed(units: Unit[])
|
||||
{
|
||||
var airspeed = null;
|
||||
for (let unit of units)
|
||||
{
|
||||
if (unit.targetSpeed != airspeed && airspeed != null)
|
||||
return null
|
||||
else
|
||||
airspeed = unit.targetSpeed;
|
||||
}
|
||||
return airspeed;
|
||||
}
|
||||
|
||||
#getTargetAltitude(units: Unit[])
|
||||
{
|
||||
var altitude = null;
|
||||
for (let unit of units)
|
||||
{
|
||||
if (unit.targetAltitude != altitude && altitude != null)
|
||||
return null
|
||||
else
|
||||
altitude = unit.targetAltitude;
|
||||
}
|
||||
return altitude;
|
||||
}
|
||||
|
||||
#getROE(units: Unit[])
|
||||
{
|
||||
var ROE = null;
|
||||
for (let unit of units)
|
||||
{
|
||||
if (unit.ROE !== ROE && ROE != null)
|
||||
return null
|
||||
else
|
||||
ROE = unit.ROE;
|
||||
}
|
||||
return ROE;
|
||||
}
|
||||
|
||||
#getReactionToThreat(units: Unit[])
|
||||
{
|
||||
var reactionToThreat = null;
|
||||
for (let unit of units)
|
||||
{
|
||||
if (unit.reactionToThreat !== reactionToThreat && reactionToThreat != null)
|
||||
return null
|
||||
else
|
||||
reactionToThreat = unit.reactionToThreat;
|
||||
}
|
||||
return reactionToThreat;
|
||||
}
|
||||
}
|
||||
@@ -48,6 +48,15 @@ export class UnitInfoPanel {
|
||||
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");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import { Marker, LatLng, Polyline, Icon } from 'leaflet';
|
||||
import { ConvertDDToDMS } from '../other/utils';
|
||||
import { getMap, getUnitsManager, getVisibilitySettings } from '..';
|
||||
import { UnitMarker, MarkerOptions, AircraftMarker, HelicopterMarker, GroundUnitMarker, NavyUnitMarker, WeaponMarker } from './unitmarker';
|
||||
import { addDestination, attackUnit, changeAltitude, changeSpeed } from '../dcs/dcs';
|
||||
import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, landAt, setAltitude, setReactionToThreat, setROE, setSpeed } from '../dcs/dcs';
|
||||
|
||||
var pathIcon = new Icon({
|
||||
iconUrl: 'images/marker-icon.png',
|
||||
@@ -12,9 +12,6 @@ var pathIcon = new Icon({
|
||||
|
||||
export class Unit {
|
||||
ID: number = -1;
|
||||
leader: boolean = false;
|
||||
wingman: boolean = false;
|
||||
wingmen: Unit[] = [];
|
||||
formation: string = "";
|
||||
name: string = "";
|
||||
unitName: string = "";
|
||||
@@ -33,7 +30,17 @@ export class Unit {
|
||||
activePath: any = null;
|
||||
ammo: any = null;
|
||||
targets: any = null;
|
||||
|
||||
hasTask: boolean = false;
|
||||
isLeader: boolean = false;
|
||||
isWingman: boolean = false;
|
||||
leaderID: number = 0;
|
||||
wingmen: Unit[] = [];
|
||||
wingmenIDs: number[] = [];
|
||||
targetSpeed: number = 0;
|
||||
targetAltitude: number = 0;
|
||||
ROE: string = "";
|
||||
reactionToThreat: string = "";
|
||||
|
||||
#selectable: boolean;
|
||||
#selected: boolean = false;
|
||||
#preventClick: boolean = false;
|
||||
@@ -61,42 +68,36 @@ export class Unit {
|
||||
this.#marker = marker;
|
||||
this.#marker.on('click', (e) => this.#onClick(e));
|
||||
this.#marker.on('dblclick', (e) => this.#onDoubleClick(e));
|
||||
this.#marker.on('contextmenu', (e) => this.#onContextMenu(e));
|
||||
|
||||
this.#pathPolyline = new Polyline([], { color: '#2d3e50', weight: 3, opacity: 0.5, smoothFactor: 1 });
|
||||
this.#pathPolyline.addTo(getMap());
|
||||
this.#targetsPolylines = [];
|
||||
}
|
||||
|
||||
update(response: JSON) {
|
||||
update(response: any) {
|
||||
for (let entry in response) {
|
||||
// @ts-ignore
|
||||
// @ts-ignore TODO handle better
|
||||
this[entry] = response[entry];
|
||||
}
|
||||
|
||||
// TODO handle better
|
||||
if (response['activePath'] == undefined)
|
||||
this.activePath = null
|
||||
|
||||
/* Dead units can't be selected */
|
||||
this.setSelected(this.getSelected() && this.alive)
|
||||
|
||||
this.#updateMarker();
|
||||
|
||||
this.#clearTargets();
|
||||
if (this.getSelected())
|
||||
if (this.getSelected() && this.activePath != null)
|
||||
{
|
||||
this.#drawPath();
|
||||
this.#drawTargets();
|
||||
}
|
||||
else
|
||||
this.#clearPath();
|
||||
|
||||
/*
|
||||
this.wingmen = [];
|
||||
if (response["wingmenIDs"] != null)
|
||||
{
|
||||
for (let ID of response["wingmenIDs"])
|
||||
{
|
||||
this.wingmen.push(unitsManager.getUnitByID(ID));
|
||||
}
|
||||
}
|
||||
*/
|
||||
this.#clearPath();
|
||||
}
|
||||
|
||||
setSelected(selected: boolean) {
|
||||
@@ -105,6 +106,7 @@ export class Unit {
|
||||
this.#selected = selected;
|
||||
this.#marker.setSelected(selected);
|
||||
getUnitsManager().onUnitSelection();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +142,28 @@ export class Unit {
|
||||
return false;
|
||||
}
|
||||
|
||||
getLeader() {
|
||||
return getUnitsManager().getUnitByID(this.leaderID);
|
||||
}
|
||||
|
||||
getFormation() {
|
||||
return [<Unit>this].concat(this.getWingmen())
|
||||
}
|
||||
|
||||
getWingmen() {
|
||||
var wingmen: Unit[] = [];
|
||||
if (this.wingmenIDs != null)
|
||||
{
|
||||
for (let ID of this.wingmenIDs)
|
||||
{
|
||||
var unit = getUnitsManager().getUnitByID(ID)
|
||||
if (unit)
|
||||
wingmen.push(unit);
|
||||
}
|
||||
}
|
||||
return wingmen;
|
||||
}
|
||||
|
||||
#onClick(e: any) {
|
||||
this.#timer = setTimeout(() => {
|
||||
if (!this.#preventClick) {
|
||||
@@ -157,22 +181,21 @@ export class Unit {
|
||||
#onDoubleClick(e: any) {
|
||||
clearTimeout(this.#timer);
|
||||
this.#preventClick = true;
|
||||
}
|
||||
|
||||
#onContextMenu(e: any) {
|
||||
var options = [
|
||||
'Attack',
|
||||
'Follow'
|
||||
]
|
||||
|
||||
//if (!this.leader && !this.wingman) {
|
||||
// options.push({ 'tooltip': 'Create formation', 'src': 'formation.png', 'callback': () => { getMap().hideSelectionWheel(); /*unitsManager.createFormation(this.ID);*/ } });
|
||||
//}
|
||||
|
||||
getMap().showSelectionScroll(e.originalEvent, options, (action: string) => this.#executeAction(action));
|
||||
getMap().showSelectionScroll(e.originalEvent, "Action: " + this.unitName, options, (action: string) => this.#executeAction(action));
|
||||
}
|
||||
|
||||
#executeAction(action: string) {
|
||||
getMap().hideSelectionScroll();
|
||||
if (action === "Attack")
|
||||
getUnitsManager().attackUnit(this.ID);
|
||||
getUnitsManager().selectedUnitsAttackUnit(this.ID);
|
||||
}
|
||||
|
||||
#updateMarker() {
|
||||
@@ -199,8 +222,8 @@ export class Unit {
|
||||
|
||||
#drawPath() {
|
||||
if (this.activePath != null) {
|
||||
var _points = [];
|
||||
_points.push(new LatLng(this.latitude, this.longitude));
|
||||
var points = [];
|
||||
points.push(new LatLng(this.latitude, this.longitude));
|
||||
|
||||
/* Add markers if missing */
|
||||
while (this.#pathMarkers.length < Object.keys(this.activePath).length) {
|
||||
@@ -218,8 +241,8 @@ export class Unit {
|
||||
for (let WP in this.activePath) {
|
||||
var destination = this.activePath[WP];
|
||||
this.#pathMarkers[parseInt(WP) - 1].setLatLng([destination.lat, destination.lng]);
|
||||
_points.push(new LatLng(destination.lat, destination.lng));
|
||||
this.#pathPolyline.setLatLngs(_points);
|
||||
points.push(new LatLng(destination.lat, destination.lng));
|
||||
this.#pathPolyline.setLatLngs(points);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -232,7 +255,6 @@ export class Unit {
|
||||
this.#pathPolyline.setLatLngs([]);
|
||||
}
|
||||
|
||||
|
||||
#drawTargets()
|
||||
{
|
||||
for (let typeIndex in this.targets)
|
||||
@@ -278,7 +300,6 @@ export class Unit {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
attackUnit(targetID: number) {
|
||||
/* Call DCS attackUnit function */
|
||||
if (this.ID != targetID) {
|
||||
@@ -289,7 +310,11 @@ export class Unit {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
landAt(latlng: LatLng)
|
||||
{
|
||||
landAt(this.ID, latlng);
|
||||
}
|
||||
|
||||
changeSpeed(speedChange: string)
|
||||
{
|
||||
changeSpeed(this.ID, speedChange);
|
||||
@@ -300,6 +325,26 @@ export class Unit {
|
||||
changeAltitude(this.ID, altitudeChange);
|
||||
}
|
||||
|
||||
setSpeed(speed: number)
|
||||
{
|
||||
setSpeed(this.ID, speed);
|
||||
}
|
||||
|
||||
setAltitude(altitude: number)
|
||||
{
|
||||
setAltitude(this.ID, altitude);
|
||||
}
|
||||
|
||||
setROE(ROE: string)
|
||||
{
|
||||
setROE(this.ID, ROE);
|
||||
}
|
||||
|
||||
setReactionToThreat(reactionToThreat: string)
|
||||
{
|
||||
setReactionToThreat(this.ID, reactionToThreat);
|
||||
}
|
||||
|
||||
/*
|
||||
setformation(formation)
|
||||
{
|
||||
@@ -318,25 +363,13 @@ export class Unit {
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
setLeader(wingmenIDs)
|
||||
{
|
||||
// TODO move in dedicated file
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
console.log(this.unitName + " created formation with: " + wingmenIDs);
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"ID": this.ID, "wingmenIDs": wingmenIDs}
|
||||
var data = {"setLeader": command}
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
*/
|
||||
|
||||
setLeader(isLeader: boolean, wingmenIDs: number[] = [])
|
||||
{
|
||||
setLeader(this.ID, isLeader, wingmenIDs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class AirUnit extends Unit {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { LatLng, LatLngBounds } from "leaflet";
|
||||
import { getMap, getUnitInfoPanel } from "..";
|
||||
import { getMap, getUnitControlPanel, getUnitInfoPanel } from "..";
|
||||
import { Unit, GroundUnit } from "./unit";
|
||||
import { cloneUnit } from "../dcs/dcs";
|
||||
|
||||
export class UnitsManager {
|
||||
#units: { [ID: number]: Unit };
|
||||
@@ -9,6 +10,24 @@ export class UnitsManager {
|
||||
constructor() {
|
||||
this.#units = {};
|
||||
this.#copiedUnits = [];
|
||||
|
||||
document.addEventListener('copy', () => this.copyUnits());
|
||||
document.addEventListener('paste', () => this.pasteUnits());
|
||||
}
|
||||
|
||||
#updateUnitControlPanel() {
|
||||
/* Update the unit control panel */
|
||||
if (this.getSelectedUnits().length > 0) {
|
||||
getUnitControlPanel().show();
|
||||
getUnitControlPanel().update(this.getSelectedLeaders().concat(this.getSelectedSingletons()));
|
||||
}
|
||||
else {
|
||||
getUnitControlPanel().hide();
|
||||
}
|
||||
}
|
||||
|
||||
getUnits() {
|
||||
return this.#units;
|
||||
}
|
||||
|
||||
addUnit(ID: number, data: any) {
|
||||
@@ -27,7 +46,10 @@ export class UnitsManager {
|
||||
}
|
||||
|
||||
getUnitByID(ID: number) {
|
||||
return this.#units[ID];
|
||||
if (ID in this.#units)
|
||||
return this.#units[ID];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
removeUnit(ID: number) {
|
||||
@@ -40,6 +62,13 @@ export class UnitsManager {
|
||||
}
|
||||
}
|
||||
|
||||
selectUnit(ID: number, deselectAllUnits: boolean = true)
|
||||
{
|
||||
if (deselectAllUnits)
|
||||
this.deselectAllUnits();
|
||||
this.#units[ID]?.setSelected(true);
|
||||
}
|
||||
|
||||
update(data: any) {
|
||||
for (let ID in data["units"]) {
|
||||
/* Create the unit if missing from the local array, then update the data. Drawing is handled by leaflet. */
|
||||
@@ -49,6 +78,7 @@ export class UnitsManager {
|
||||
this.#units[parseInt(ID)].update(data["units"][ID]);
|
||||
}
|
||||
|
||||
/* Update the unit info panel */
|
||||
if (this.getSelectedUnits().length == 1) {
|
||||
getUnitInfoPanel().show();
|
||||
getUnitInfoPanel().update(this.getSelectedUnits()[0]);
|
||||
@@ -67,6 +97,8 @@ export class UnitsManager {
|
||||
getMap().setState("IDLE");
|
||||
//unitControlPanel.setEnabled(false);
|
||||
}
|
||||
|
||||
this.#updateUnitControlPanel();
|
||||
}
|
||||
|
||||
selectFromBounds(bounds: LatLngBounds)
|
||||
@@ -92,7 +124,35 @@ export class UnitsManager {
|
||||
return selectedUnits;
|
||||
}
|
||||
|
||||
addDestination(latlng: L.LatLng) {
|
||||
getSelectedLeaders() {
|
||||
var leaders: Unit[] = [];
|
||||
for (let idx in this.getSelectedUnits())
|
||||
{
|
||||
var unit = this.getSelectedUnits()[idx];
|
||||
if (unit.isLeader)
|
||||
leaders.push(unit);
|
||||
else if (unit.isWingman)
|
||||
{
|
||||
var leader = unit.getLeader();
|
||||
if (leader && !leaders.includes(leader))
|
||||
leaders.push(leader);
|
||||
}
|
||||
}
|
||||
return leaders;
|
||||
}
|
||||
|
||||
getSelectedSingletons() {
|
||||
var singletons: Unit[] = [];
|
||||
for (let idx in this.getSelectedUnits())
|
||||
{
|
||||
var unit = this.getSelectedUnits()[idx];
|
||||
if (!unit.isLeader && !unit.isWingman)
|
||||
singletons.push(unit);
|
||||
}
|
||||
return singletons;
|
||||
}
|
||||
|
||||
selectedUnitsAddDestination(latlng: L.LatLng) {
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits) {
|
||||
var commandedUnit = selectedUnits[idx];
|
||||
@@ -104,7 +164,7 @@ export class UnitsManager {
|
||||
}
|
||||
}
|
||||
|
||||
clearDestinations() {
|
||||
selectedUnitsClearDestinations() {
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits) {
|
||||
var commandedUnit = selectedUnits[idx];
|
||||
@@ -116,6 +176,15 @@ export class UnitsManager {
|
||||
}
|
||||
}
|
||||
|
||||
selectedUnitsLandAt(latlng: LatLng)
|
||||
{
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits)
|
||||
{
|
||||
selectedUnits[idx].landAt(latlng);
|
||||
}
|
||||
}
|
||||
|
||||
selectedUnitsChangeSpeed(speedChange: string)
|
||||
{
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
@@ -123,6 +192,8 @@ export class UnitsManager {
|
||||
{
|
||||
selectedUnits[idx].changeSpeed(speedChange);
|
||||
}
|
||||
|
||||
setTimeout(() => this.#updateUnitControlPanel(), 300); // TODO find better method, may fail
|
||||
}
|
||||
|
||||
selectedUnitsChangeAltitude(altitudeChange: string)
|
||||
@@ -132,35 +203,66 @@ export class UnitsManager {
|
||||
{
|
||||
selectedUnits[idx].changeAltitude(altitudeChange);
|
||||
}
|
||||
|
||||
setTimeout(() => this.#updateUnitControlPanel(), 300); // TODO find better method, may fail
|
||||
}
|
||||
|
||||
// handleKeyEvent(e)
|
||||
// {
|
||||
// if (e.originalEvent.code === 'KeyC' && e.originalEvent.ctrlKey)
|
||||
// {
|
||||
// this.copyUnits();
|
||||
// }
|
||||
// else if (e.originalEvent.code === 'KeyV' && e.originalEvent.ctrlKey)
|
||||
// {
|
||||
// this.pasteUnits();
|
||||
// }
|
||||
// }
|
||||
selectedUnitsSetSpeed(speed: number)
|
||||
{
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits)
|
||||
{
|
||||
selectedUnits[idx].setSpeed(speed);
|
||||
}
|
||||
}
|
||||
|
||||
// copyUnits()
|
||||
// {
|
||||
// this.#copiedUnits = this.getSelectedUnits();
|
||||
// }
|
||||
selectedUnitsSetAltitude(altitude: number)
|
||||
{
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits)
|
||||
{
|
||||
selectedUnits[idx].setAltitude(altitude);
|
||||
}
|
||||
}
|
||||
|
||||
// pasteUnits()
|
||||
// {
|
||||
// for (let idx in this.#copiedUnits)
|
||||
// {
|
||||
// var unit = this.#copiedUnits[idx];
|
||||
// cloneUnit(unit.ID);
|
||||
// }
|
||||
// }
|
||||
selectedUnitsSetROE(ROE: string)
|
||||
{
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits)
|
||||
{
|
||||
selectedUnits[idx].setROE(ROE);
|
||||
}
|
||||
|
||||
attackUnit(ID: number) {
|
||||
setTimeout(() => this.#updateUnitControlPanel(), 300); // TODO find better method, may fail
|
||||
}
|
||||
|
||||
selectedUnitsSetReactionToThreat(reactionToThreat: string)
|
||||
{
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits)
|
||||
{
|
||||
selectedUnits[idx].setReactionToThreat(reactionToThreat);
|
||||
}
|
||||
|
||||
setTimeout(() => this.#updateUnitControlPanel(), 300); // TODO find better method, may fail
|
||||
}
|
||||
|
||||
|
||||
copyUnits()
|
||||
{
|
||||
this.#copiedUnits = this.getSelectedUnits();
|
||||
}
|
||||
|
||||
pasteUnits()
|
||||
{
|
||||
for (let idx in this.#copiedUnits)
|
||||
{
|
||||
var unit = this.#copiedUnits[idx];
|
||||
cloneUnit(unit.ID, getMap().getMouseCoordinates());
|
||||
}
|
||||
}
|
||||
|
||||
selectedUnitsAttackUnit(ID: number) {
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits) {
|
||||
/* If a unit is a wingman, send the command to its leader */
|
||||
@@ -173,59 +275,59 @@ export class UnitsManager {
|
||||
}
|
||||
}
|
||||
|
||||
// createFormation(ID)
|
||||
// {
|
||||
// var selectedUnits = this.getSelectedUnits();
|
||||
// var wingmenIDs = [];
|
||||
// for (let idx in selectedUnits)
|
||||
// {
|
||||
// if (selectedUnits[idx].wingman)
|
||||
// {
|
||||
// showMessage(selectedUnits[idx].unitName + " is already in a formation.");
|
||||
// return;
|
||||
// }
|
||||
// else if (selectedUnits[idx].leader)
|
||||
// {
|
||||
// showMessage(selectedUnits[idx].unitName + " is already in a formation.");
|
||||
// return;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// /* TODO
|
||||
// if (selectedUnits[idx].category !== this.getUnitByID(ID).category)
|
||||
// {
|
||||
// showMessage("All units must be of the same category to create a formation.");
|
||||
// }
|
||||
// */
|
||||
// if (selectedUnits[idx].ID != ID)
|
||||
// {
|
||||
// wingmenIDs.push(selectedUnits[idx].ID);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (wingmenIDs.length > 0)
|
||||
// {
|
||||
// this.getUnitByID(ID).setLeader(wingmenIDs);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// showMessage("At least 2 units must be selected to create a formation.");
|
||||
// }
|
||||
// }
|
||||
selectedUnitsCreateFormation(ID: number | null = null)
|
||||
{
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
if (selectedUnits.length >= 2)
|
||||
{
|
||||
if (ID == null)
|
||||
ID = selectedUnits[0].ID
|
||||
|
||||
var wingmenIDs = [];
|
||||
for (let idx in selectedUnits)
|
||||
{
|
||||
if (selectedUnits[idx].isWingman)
|
||||
{
|
||||
console.log(selectedUnits[idx].unitName + " is already in a formation.");
|
||||
return;
|
||||
}
|
||||
else if (selectedUnits[idx].isLeader)
|
||||
{
|
||||
console.log(selectedUnits[idx].unitName + " is already in a formation.");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO
|
||||
if (selectedUnits[idx].category !== this.getUnitByID(ID).category)
|
||||
{
|
||||
showMessage("All units must be of the same category to create a formation.");
|
||||
}
|
||||
*/
|
||||
if (selectedUnits[idx].ID != ID)
|
||||
{
|
||||
wingmenIDs.push(selectedUnits[idx].ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (wingmenIDs.length > 0)
|
||||
{
|
||||
this.getUnitByID(ID)?.setLeader(true, wingmenIDs);
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log("At least 2 units must be selected to create a formation.");
|
||||
}
|
||||
}
|
||||
setTimeout(() => this.#updateUnitControlPanel(), 300); // TODO find better method, may fail
|
||||
}
|
||||
|
||||
// getLeader(ID)
|
||||
// {
|
||||
// for (let idx in this.#units)
|
||||
// {
|
||||
// var unit = this.#units[idx];
|
||||
// if (unit.leader)
|
||||
// {
|
||||
// if (unit.wingmen.includes(this.getUnitByID(ID)))
|
||||
// {
|
||||
// return unit;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// showMessage("Error: no leader found for this unit")
|
||||
// }
|
||||
selectedUnitsUndoFormation(ID: number | null = null)
|
||||
{
|
||||
for (let leader of this.getSelectedLeaders())
|
||||
{
|
||||
leader.setLeader(false);
|
||||
}
|
||||
setTimeout(() => this.#updateUnitControlPanel(), 300); // TODO find better method, may fail
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user