Continued typescript conversion
3
.gitignore
vendored
@ -7,3 +7,6 @@ core.vcxproj.user
|
||||
.vscode
|
||||
*.user
|
||||
Output
|
||||
server
|
||||
/www/js
|
||||
/www/node_modules
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
:root {
|
||||
--blue: #2196F3aa;
|
||||
--red: #f32121aa;
|
||||
--dark: #202831AA;
|
||||
--normal: #2196F3aa;
|
||||
--highlight: #FFFFFFAA;
|
||||
--start_angle: 0deg;
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
BIN
www/img/buttons/rtb.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
www/img/buttons/tanker.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
@ -20,30 +20,9 @@
|
||||
integrity="sha256-o9N1jGDZrf5tS+Ft4gbIK7mYMipq9lqpVJ91xHSyKhg="
|
||||
crossorigin=""></script>
|
||||
|
||||
<script src="js/DCS/payloadNames.js"></script>
|
||||
<script src="js/DCS/DCSCommands.js"></script>
|
||||
|
||||
<script src="js/Panels/PanelButton.js"></script>
|
||||
<script src="js/Panels/SettingsPanel.js"></script>
|
||||
<script src="js/Panels/UnitInfoPanel.js"></script>
|
||||
<script src="js/Panels/UnitControlPanel.js"></script>
|
||||
<script src="js/Panels/FormationControlPanel.js"></script>
|
||||
<script src="js/Panels/ActionPanel.js"></script>
|
||||
<script type = "module" src="js/Units/UnitMarker.js"></script>
|
||||
<script type = "module" src="js/index.js"></script>
|
||||
|
||||
<script src="js/Units/unitTypes.js"></script>
|
||||
<script src="js/Units/Unit.js"></script>
|
||||
<script src="js/Units/UnitMarker.js"></script>
|
||||
<script src="js/Units/UnitsManager.js"></script>
|
||||
|
||||
<script src="js/Other/Utils.js"></script>
|
||||
<script src="js/Other/AirbaseMarker.js"></script>
|
||||
<script src="js/Other/MissionData.js"></script>
|
||||
|
||||
<script src="js/Map/Map.js"></script>
|
||||
<script src="js/Map/SelectionWheel.js"></script>
|
||||
<script src="js/Map/SelectionScroll.js"></script>
|
||||
|
||||
<script src="js/index.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<table id="content-table">
|
||||
@ -56,11 +35,10 @@
|
||||
<td id="map-container">
|
||||
<div id="map"></div>
|
||||
<div id="log"></div>
|
||||
<div class="action-panel" id="action-panel"></div>
|
||||
<div class="unit-info-panel" id="unit-info-panel"></div>
|
||||
<div class="unit-control-panel" id="unit-control-panel"></div>
|
||||
<div class="formation-control-panel" id="formation-control-panel"></div>
|
||||
<div id="snackbar">ASD</div>
|
||||
<div id="snackbar"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
class SelectionScroll
|
||||
{
|
||||
constructor(x, y, options, callback)
|
||||
{
|
||||
if (options.length > 1)
|
||||
{
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._options = options;
|
||||
|
||||
/* Create the container of the scroll */
|
||||
this._container = document.createElement("div");
|
||||
this._container.id = 'selection-scroll-container';
|
||||
this._container.style.left = this._x + "px";
|
||||
this._container.style.top = this._y + "px";
|
||||
document.getElementById("map-container").appendChild(this._container);
|
||||
|
||||
for (let optionID in this._options)
|
||||
{
|
||||
var node = document.createElement("div");
|
||||
node.classList.add("selection-scroll-element");
|
||||
node.appendChild(document.createTextNode(this._options[optionID]));
|
||||
this._container.appendChild(node);
|
||||
node.addEventListener('click', () => callback(this._options[optionID]))
|
||||
}
|
||||
|
||||
window.setTimeout(() => this._show(), 100);
|
||||
}
|
||||
}
|
||||
|
||||
remove()
|
||||
{
|
||||
document.getElementById("map-container").removeChild(this._container);
|
||||
}
|
||||
|
||||
_show()
|
||||
{
|
||||
this._container.style.width = 220 + "px";
|
||||
this._container.style.height = 220 + "px";
|
||||
this._container.style.left = this._x - 110 + "px";
|
||||
this._container.style.top = this._y - 110 + "px";
|
||||
}
|
||||
}
|
||||
@ -1,100 +0,0 @@
|
||||
class SelectionWheel
|
||||
{
|
||||
constructor(x, y, options)
|
||||
{
|
||||
if (options.length > 1)
|
||||
{
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._options = options;
|
||||
this._angularSize = 360 / this._options.length;
|
||||
|
||||
/* Create the container of the wheel */
|
||||
this._container = document.createElement("div");
|
||||
this._container.id = 'selection-wheel-container';
|
||||
this._container.style.left = this._x + "px";
|
||||
this._container.style.top = this._y + "px";
|
||||
document.getElementById("map-container").appendChild(this._container);
|
||||
|
||||
/* Create the wheel itself */
|
||||
this._wheel = document.createElement("div");
|
||||
this._wheel.id = 'selection-wheel';
|
||||
this._container.appendChild(this._wheel);
|
||||
|
||||
/* Create the buttons */
|
||||
this._buttons = [];
|
||||
for (let id in this._options)
|
||||
{
|
||||
var button = document.createElement("div");
|
||||
button.classList.add("selection-wheel-button");
|
||||
button.style.left = this._x - 25 + "px";
|
||||
button.style.top = this._y - 25 + "px";
|
||||
button.addEventListener('click', (e) => this._options[id].callback(e));
|
||||
this._container.appendChild(button);
|
||||
this._buttons.push(button);
|
||||
|
||||
var image = document.createElement("img");
|
||||
image.classList.add("selection-wheel-image");
|
||||
image.src = `img/buttons/${this._options[id].src}`
|
||||
image.title = this._options[id].tooltip;
|
||||
if ('tint' in this._options[id])
|
||||
{
|
||||
button.style.setProperty('background-color', this._options[id].tint);
|
||||
image.style.opacity = 0;
|
||||
}
|
||||
button.appendChild(image);
|
||||
}
|
||||
|
||||
/* Show the coalition switch if requested */
|
||||
this._switchLabel = document.createElement("label");
|
||||
this._switchLabel.classList.add("switch");
|
||||
this._switchLabel.innerHTML = `<input type="checkbox" id="coalition-switch"> <span class="slider round"></span>`
|
||||
this._container.appendChild(this._switchLabel);
|
||||
document.getElementById("coalition-switch").addEventListener('change', (e) => this._onSwitch(e))
|
||||
|
||||
if (map.getActiveCoalition() == "red")
|
||||
{
|
||||
document.getElementById("coalition-switch").checked = true;
|
||||
}
|
||||
|
||||
window.setTimeout(() => this._show(), 100);
|
||||
}
|
||||
}
|
||||
|
||||
remove()
|
||||
{
|
||||
this._container.removeChild(this._wheel);
|
||||
document.getElementById("map-container").removeChild(this._container);
|
||||
}
|
||||
|
||||
_show()
|
||||
{
|
||||
this._container.style.width = 220 + "px";
|
||||
this._container.style.height = 220 + "px";
|
||||
this._container.style.left = this._x - 110 + "px";
|
||||
this._container.style.top = this._y - 110 + "px";
|
||||
|
||||
var r = 80;
|
||||
for (let id in this._buttons)
|
||||
{
|
||||
var angle = parseInt(id) * this._angularSize;
|
||||
this._buttons[id].style.opacity = 1;
|
||||
this._buttons[id].style.left = this._x + r * Math.sin(deg2rad(angle)) - 25 + "px";
|
||||
this._buttons[id].style.top = this._y - r * Math.cos(deg2rad(angle)) - 25 + "px";
|
||||
}
|
||||
|
||||
this._switchLabel.style.opacity = 1;
|
||||
}
|
||||
|
||||
_onSwitch(e)
|
||||
{
|
||||
if (e.currentTarget.checked) {
|
||||
document.documentElement.style.setProperty('--normal', getComputedStyle(this._container).getPropertyValue("--red"));
|
||||
map.setActiveCoalition("red");
|
||||
} else {
|
||||
document.documentElement.style.setProperty('--normal', getComputedStyle(this._container).getPropertyValue("--blue"));
|
||||
map.setActiveCoalition("blue");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,67 +0,0 @@
|
||||
class MissionData
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
this._bullseye = undefined;
|
||||
this._bullseyeMarker = undefined;
|
||||
this._airbasesMarkers = {};
|
||||
}
|
||||
|
||||
update(data)
|
||||
{
|
||||
this._bullseye = data.missionData.bullseye;
|
||||
this._unitsData = data.missionData.unitsData;
|
||||
this._airbases = data.missionData.airbases;
|
||||
this._drawBullseye();
|
||||
this._drawAirbases();
|
||||
}
|
||||
|
||||
getUnitData(ID)
|
||||
{
|
||||
if (ID in this._unitsData)
|
||||
{
|
||||
return this._unitsData[ID];
|
||||
}
|
||||
else
|
||||
{
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
_drawBullseye()
|
||||
{
|
||||
if (this._bullseyeMarker === undefined)
|
||||
{
|
||||
this._bullseyeMarker = new L.Marker([this._bullseye.lat, this._bullseye.lng]).addTo(map.getMap());
|
||||
}
|
||||
else
|
||||
{
|
||||
this._bullseyeMarker.setLatLng(new L.LatLng(this._bullseye.lat, this._bullseye.lng));
|
||||
}
|
||||
}
|
||||
|
||||
_drawAirbases()
|
||||
{
|
||||
for (let idx in this._airbases)
|
||||
{
|
||||
var airbase = this._airbases[idx]
|
||||
if (this._airbasesMarkers[idx] === undefined)
|
||||
{
|
||||
this._airbasesMarkers[idx] = new L.Marker.AirbaseMarker(new L.LatLng(airbase.lat, airbase.lng), {name: airbase.callsign}).addTo(map.getMap());
|
||||
this._airbasesMarkers[idx].on('click', (e) => this._onAirbaseClick(e));
|
||||
}
|
||||
else
|
||||
{
|
||||
this._airbasesMarkers[idx].setCoalitionID(airbase.coalition);
|
||||
this._airbasesMarkers[idx].setLatLng(new L.LatLng(airbase.lat, airbase.lng));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_onAirbaseClick(e)
|
||||
{
|
||||
e.airbaseName = e.sourceTarget.options.name;
|
||||
e.coalitionID = e.sourceTarget.coalitionID;
|
||||
map.spawnFromAirbase(e);
|
||||
}
|
||||
}
|
||||
@ -1,30 +0,0 @@
|
||||
class ActionPanel
|
||||
{
|
||||
constructor(id)
|
||||
{
|
||||
this._panel = document.getElementById(id);
|
||||
|
||||
this._attackButton = new PanelButton(this._panel, "img/buttons/attack.png", "Attack unit");
|
||||
this._bombButton = new PanelButton(this._panel, "img/buttons/bomb.png", "Precision bombing");
|
||||
this._carpetButton = new PanelButton(this._panel, "img/buttons/carpet.png", "Carpet bombing");
|
||||
this._landButton = new PanelButton(this._panel, "img/buttons/land.png", "Land here");
|
||||
this._formationButton = new PanelButton(this._panel, "img/buttons/formation.png", "Create formation");
|
||||
|
||||
this._attackButton.addCallback(() => map.setState("ATTACK"));
|
||||
this._bombButton.addCallback(() => map.setState("BOMB"));
|
||||
this._carpetButton.addCallback(() => map.setState("CARPET_BOMB"));
|
||||
this._landButton.addCallback(() => map.setState("LAND"));
|
||||
this._formationButton.addCallback(() => map.setState("FORMATION"));
|
||||
|
||||
this.setEnabled(false);
|
||||
}
|
||||
|
||||
setEnabled(enabled)
|
||||
{
|
||||
this._attackButton.setEnabled(enabled);
|
||||
this._bombButton.setEnabled(false);
|
||||
this._carpetButton.setEnabled(false);
|
||||
this._landButton.setEnabled(false);
|
||||
this._formationButton.setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
@ -1,82 +0,0 @@
|
||||
class PanelButton
|
||||
{
|
||||
constructor(parent, icon, tooltip)
|
||||
{
|
||||
this._div = document.createElement("div");
|
||||
this.setIcon(icon, tooltip);
|
||||
this.setSlashed(false);
|
||||
|
||||
this._div.classList.add("panel-button");
|
||||
parent.appendChild(this._div);
|
||||
|
||||
this.setEnabled(true);
|
||||
|
||||
this._div.onclick = () => this._onClick();
|
||||
this._callbacks = [];
|
||||
}
|
||||
|
||||
setEnabled(enabled)
|
||||
{
|
||||
this._enabled = enabled;
|
||||
if (enabled)
|
||||
{
|
||||
this._div.classList.remove("panel-button-disabled");
|
||||
}
|
||||
else
|
||||
{
|
||||
this._div.classList.add("panel-button-disabled");
|
||||
}
|
||||
}
|
||||
|
||||
addCallback(callback)
|
||||
{
|
||||
this._callbacks.push(callback);
|
||||
}
|
||||
|
||||
clearCallbacks()
|
||||
{
|
||||
this._callbacks = [];
|
||||
}
|
||||
|
||||
setIcon(icon, tooltip)
|
||||
{
|
||||
if (icon.includes("png"))
|
||||
{
|
||||
this._baseIcon = `<img src="${icon}" title="${tooltip}">`;
|
||||
}
|
||||
else
|
||||
{
|
||||
this._baseIcon = `<i class="fa ${icon}" title="${tooltip}"></i>`;
|
||||
}
|
||||
this._div.innerHTML = this._baseIcon;
|
||||
}
|
||||
|
||||
setSubicon(subicon)
|
||||
{
|
||||
this._baseIcon = `<div style="display: flex;">${this._baseIcon}<i style="font-size: 10px;" class="fa ${subicon}"></i></div>`;
|
||||
this._div.innerHTML = this._baseIcon;
|
||||
}
|
||||
|
||||
setSlashed(slashed)
|
||||
{
|
||||
if (slashed)
|
||||
{
|
||||
this._div.innerHTML = `<div style="display: flex; justify-content: center;">${this._baseIcon}<i style="position:fixed;" class="fa fa-slash"></i></div>`;
|
||||
}
|
||||
else
|
||||
{
|
||||
this._div.innerHTML = this._baseIcon;
|
||||
}
|
||||
}
|
||||
|
||||
_onClick()
|
||||
{
|
||||
if (this._enabled)
|
||||
{
|
||||
for (let callback in this._callbacks)
|
||||
{
|
||||
this._callbacks[callback]();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,86 +0,0 @@
|
||||
class SettingsPanel
|
||||
{
|
||||
constructor(id)
|
||||
{
|
||||
this._panel = document.getElementById(id);
|
||||
|
||||
/* Create all buttons, disabled by default */
|
||||
this._humanIcon = "fa-user";
|
||||
this._AIIcon = "fa-desktop";
|
||||
this._weaponsIcon = "fa-bomb";
|
||||
this._labelsIcon = "fa-font";
|
||||
this._deadIcon = "fa-skull";
|
||||
|
||||
this._humanButton = new PanelButton(this._panel, this._humanIcon, "Player visibility");
|
||||
this._AIButton = new PanelButton(this._panel, this._AIIcon, "AI visibility");
|
||||
this._weaponsButton = new PanelButton(this._panel, this._weaponsIcon, "Weapons visibility");
|
||||
this._deadAliveButton = new PanelButton(this._panel, this._deadIcon, "Dead units visibility");
|
||||
|
||||
this._humanButton.addCallback(() => this._onHumanButton());
|
||||
this._AIButton.addCallback(() => this._onAIButton());
|
||||
this._weaponsButton.addCallback(() => this._onWeaponsButton());
|
||||
this._deadAliveButton.addCallback(() => this._cycleDeadAlive());
|
||||
|
||||
this._human = "labels";
|
||||
this._humanButton.setSubicon(this._labelsIcon);
|
||||
this._AI = "marker";
|
||||
this._weapons = "marker";
|
||||
this._deadAlive = "both";
|
||||
}
|
||||
|
||||
getSettings()
|
||||
{
|
||||
return {'human': this._human, 'AI': this._AI, 'weapons': this._weapons, 'deadAlive': this._deadAlive}
|
||||
}
|
||||
|
||||
_onHumanButton()
|
||||
{
|
||||
this._human = this._cycleVisibility(this._humanButton, this._human, this._humanIcon);
|
||||
}
|
||||
|
||||
_onAIButton()
|
||||
{
|
||||
this._AI = this._cycleVisibility(this._AIButton, this._AI, this._AIIcon);
|
||||
}
|
||||
|
||||
_onWeaponsButton()
|
||||
{
|
||||
this._weapons = this._cycleVisibility(this._weaponsButton, this._weapons, this._weaponsIcon);
|
||||
}
|
||||
|
||||
_cycleVisibility(button, variable, icon)
|
||||
{
|
||||
if (variable === "labels")
|
||||
{
|
||||
variable = "marker";
|
||||
button.setIcon(icon);
|
||||
button.setSlashed(false);
|
||||
}
|
||||
else if (variable === "marker")
|
||||
{
|
||||
variable = "none";
|
||||
button.setSlashed(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
variable = "labels";
|
||||
button.setSubicon(this._labelsIcon);
|
||||
button.setSlashed(false);
|
||||
}
|
||||
return variable;
|
||||
}
|
||||
|
||||
_cycleDeadAlive()
|
||||
{
|
||||
if (this._deadAlive === "both")
|
||||
{
|
||||
this._deadAlive = "alive";
|
||||
this._deadAliveButton.setSlashed(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
this._deadAlive = "both";
|
||||
this._deadAliveButton.setSlashed(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
class UnitControlPanel
|
||||
{
|
||||
constructor(id)
|
||||
{
|
||||
this._panel = document.getElementById(id);
|
||||
|
||||
/* Create all buttons, disabled by default */
|
||||
//this._moveButton = new PanelButton(this._panel, "fa-play");
|
||||
//this._stopButton = new PanelButton(this._panel, "fa-pause");
|
||||
this._slowButton = new PanelButton(this._panel, "fa-angle-right", "Decelerate");
|
||||
this._fastButton = new PanelButton(this._panel, "fa-angle-double-right", "Accelerate");
|
||||
this._descendButton = new PanelButton(this._panel, "fa-arrow-down", "Descend");
|
||||
this._climbButton = new PanelButton(this._panel, "fa-arrow-up", "Climb");
|
||||
//this._repeatButton = new PanelButton(this._panel, "fa-undo");
|
||||
|
||||
this.setEnabled(false);
|
||||
|
||||
//this._moveButton.addCallback(unitsManager.selectedUnitsMove);
|
||||
//this._stopButton.addCallback(() => unitsManager.selectedUnitsChangeSpeed('stop'));
|
||||
this._slowButton.addCallback(() => unitsManager.selectedUnitsChangeSpeed('slow'));
|
||||
this._fastButton.addCallback(() => unitsManager.selectedUnitsChangeSpeed('fast'));
|
||||
this._descendButton.addCallback(() => unitsManager.selectedUnitsChangeAltitude('descend'));
|
||||
this._climbButton.addCallback(() => unitsManager.selectedUnitsChangeAltitude('climb'));
|
||||
}
|
||||
|
||||
setEnabled(enabled)
|
||||
{
|
||||
//this._moveButton.setEnabled(true);
|
||||
//this._stopButton.setEnabled(true);
|
||||
this._slowButton.setEnabled(enabled);
|
||||
this._fastButton.setEnabled(enabled);
|
||||
this._descendButton.setEnabled(enabled);
|
||||
this._climbButton.setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
1524
www/package-lock.json
generated
Normal file
24
www/package.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "olympus",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "npm run build && npm run dev",
|
||||
"build": "npm run clean && npm run mkdir && npm run build:html && npm run build:css && npm run build:js",
|
||||
"dev": "webpack-dev-server --inline --hot --content-base build --history-api-fallback"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@types/leaflet": "^1.9.0",
|
||||
"express": "^4.18.2",
|
||||
"leaflet": "^1.9.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.15",
|
||||
"@types/node": "^18.11.18",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.9.4"
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,6 @@
|
||||
function spawnSmoke(color, latlng)
|
||||
import { ConvertDDToDMS } from 'Other/Utils.js'
|
||||
|
||||
export function spawnSmoke(color, latlng)
|
||||
{
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
@ -15,7 +17,7 @@ function spawnSmoke(color, latlng)
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
function spawnGroundUnit(type, latlng, coalition)
|
||||
export function spawnGroundUnit(type, latlng, coalition)
|
||||
{
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
@ -32,7 +34,7 @@ function spawnGroundUnit(type, latlng, coalition)
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
function spawnAircraft(type, latlng, coalition, payloadName = "", airbaseName = "")
|
||||
export function spawnAircraft(type, latlng, coalition, payloadName = "", airbaseName = "")
|
||||
{
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
@ -49,7 +51,7 @@ function spawnAircraft(type, latlng, coalition, payloadName = "", airbaseName =
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
function attackUnit(ID, targetID)
|
||||
export function attackUnit(ID, targetID)
|
||||
{
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
@ -66,7 +68,7 @@ function attackUnit(ID, targetID)
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
function cloneUnit(ID)
|
||||
export function cloneUnit(ID)
|
||||
{
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
1
www/src/DCS/payloadNames.ts
Normal file
@ -1,88 +1,106 @@
|
||||
class Map
|
||||
import { map, tileLayer } from 'leaflet'
|
||||
import { SelectionWheel } from './SelectionWheel.js';
|
||||
import { SelectionScroll } from './SelectionScroll.js';
|
||||
import { spawnAircraft, spawnGroundUnit, spawnSmoke } from '../DCS/DCSCommands.js';
|
||||
import { payloadNames } from '../DCS/payloadNames.js';
|
||||
|
||||
export class Map
|
||||
{
|
||||
#state : string;
|
||||
#map : any; // TODO Fix, has same name of global variable
|
||||
#selectionWheel : SelectionWheel;
|
||||
#selectionScroll: SelectionScroll;
|
||||
#activeCoalition: string;
|
||||
|
||||
constructor()
|
||||
{
|
||||
this._state = "IDLE";
|
||||
this.#state = "IDLE";
|
||||
|
||||
this._map = L.map('map', {doubleClickZoom: false}).setView([37.23, -115.8], 12);
|
||||
this.#map = map('map', {doubleClickZoom: false}).setView([37.23, -115.8], 12);
|
||||
|
||||
L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
|
||||
tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
|
||||
attribution: 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
|
||||
}).addTo(this._map);
|
||||
}).addTo(this.#map);
|
||||
|
||||
// Register event handles
|
||||
this._map.on('contextmenu', (e) => this._onContextMenu(e));
|
||||
this._map.on('click', (e) => this._onClick(e));
|
||||
this._map.on('dblclick', (e) => this._onDoubleClick(e));
|
||||
this._map.on('movestart', () => {this.removeSelectionWheel(); this.removeSelectionScroll();});
|
||||
this._map.on('zoomstart', () => {this.removeSelectionWheel(); this.removeSelectionScroll();});
|
||||
this._map.on('selectionend', (e) => unitsManager.selectFromBounds(e.selectionBounds));
|
||||
this._map.on('keyup', (e) => unitsManager.handleKeyEvent(e));
|
||||
this.#map.on('contextmenu', (e) => this.#onContextMenu(e));
|
||||
this.#map.on('click', (e) => this.#onClick(e));
|
||||
this.#map.on('dblclick', (e) => this.#onDoubleClick(e));
|
||||
this.#map.on('movestart', () => {this.removeSelectionWheel(); this.removeSelectionScroll();});
|
||||
this.#map.on('zoomstart', () => {this.removeSelectionWheel(); this.removeSelectionScroll();});
|
||||
this.#map.on('selectionend', (e) => unitsManager.selectFromBounds(e.selectionBounds));
|
||||
this.#map.on('keyup', (e) => unitsManager.handleKeyEvent(e));
|
||||
|
||||
this._map._container.classList.add("action-cursor");
|
||||
this.#map._container.classList.add("action-cursor");
|
||||
|
||||
this.setState("IDLE");
|
||||
|
||||
this._selectionWheel = undefined;
|
||||
this._selectionScroll = undefined;
|
||||
this.#selectionWheel = undefined;
|
||||
this.#selectionScroll = undefined;
|
||||
|
||||
/* Edit the default zoom box effect to use it as a multiple units selection */
|
||||
L.Map.BoxZoom.prototype._onMouseUp = function (e) {
|
||||
// TODO
|
||||
/* Edit the default zoom box effect to use it as a multiple units selection
|
||||
Map.BoxZoom.prototype._onMouseUp = function (e) {
|
||||
if ((e.which !== 1) && (e.button !== 1)) { return; }
|
||||
|
||||
this._finish();
|
||||
this.#finish();
|
||||
|
||||
if (!this._moved) { return; }
|
||||
if (!this.#moved) { return; }
|
||||
// Postpone to next JS tick so internal click event handling
|
||||
// still see it as "moved".
|
||||
setTimeout(L.bind(this._resetState, this), 0);
|
||||
setTimeout(L.bind(this.#resetState, this), 0);
|
||||
var bounds = new L.LatLngBounds(
|
||||
this._map.containerPointToLatLng(this._startPoint),
|
||||
this._map.containerPointToLatLng(this._point));
|
||||
this.#map.containerPointToLatLng(this.#startPoint),
|
||||
this.#map.containerPointToLatLng(this.#point));
|
||||
|
||||
this._map.fire('selectionend', {selectionBounds: bounds});
|
||||
this.#map.fire('selectionend', {selectionBounds: bounds});
|
||||
}
|
||||
*/
|
||||
|
||||
this._activeCoalition = "blue";
|
||||
this.#activeCoalition = "blue";
|
||||
}
|
||||
|
||||
getMap()
|
||||
{
|
||||
return this._map;
|
||||
return this.#map;
|
||||
}
|
||||
|
||||
/* State machine */
|
||||
setState(newState)
|
||||
{
|
||||
this._state = newState;
|
||||
this.#state = newState;
|
||||
|
||||
var cursorElements = document.getElementsByClassName("action-cursor");
|
||||
for (let item of cursorElements)
|
||||
for (let idx in cursorElements)
|
||||
{
|
||||
var item = cursorElements[idx];
|
||||
item.classList.remove("move-cursor-enabled", "attack-cursor-enabled", "formation-cursor-enabled");
|
||||
}
|
||||
if (this._state === "IDLE")
|
||||
if (this.#state === "IDLE")
|
||||
{
|
||||
|
||||
}
|
||||
else if (this._state === "MOVE_UNIT")
|
||||
else if (this.#state === "MOVE_UNIT")
|
||||
{
|
||||
for (let item of cursorElements)
|
||||
for (let idx in cursorElements)
|
||||
{
|
||||
var item = cursorElements[idx];
|
||||
item.classList.add("move-cursor-enabled");
|
||||
}
|
||||
}
|
||||
else if (this._state === "ATTACK")
|
||||
else if (this.#state === "ATTACK")
|
||||
{
|
||||
for (let item of cursorElements)
|
||||
for (let idx in cursorElements)
|
||||
{
|
||||
var item = cursorElements[idx];
|
||||
item.classList.add("attack-cursor-enabled");
|
||||
}
|
||||
}
|
||||
else if (this._state === "FORMATION")
|
||||
else if (this.#state === "FORMATION")
|
||||
{
|
||||
for (let item of cursorElements)
|
||||
for (let idx in cursorElements)
|
||||
{
|
||||
var item = cursorElements[idx];
|
||||
item.classList.add("formation-cursor-enabled");
|
||||
}
|
||||
}
|
||||
@ -90,23 +108,23 @@ class Map
|
||||
|
||||
getState()
|
||||
{
|
||||
return this._state;
|
||||
return this.#state;
|
||||
}
|
||||
|
||||
/* Set the active coalition (for persistency) */
|
||||
setActiveCoalition(coalition)
|
||||
{
|
||||
this._activeCoalition = coalition;
|
||||
this.#activeCoalition = coalition;
|
||||
}
|
||||
|
||||
getActiveCoalition()
|
||||
{
|
||||
return this._activeCoalition;
|
||||
return this.#activeCoalition;
|
||||
}
|
||||
|
||||
/* Event handlers */
|
||||
// Right click
|
||||
_onContextMenu(e)
|
||||
#onContextMenu(e)
|
||||
{
|
||||
this.setState("IDLE");
|
||||
unitsManager.deselectAllUnits();
|
||||
@ -114,15 +132,15 @@ class Map
|
||||
this.removeSelectionScroll();
|
||||
}
|
||||
|
||||
_onClick(e)
|
||||
#onClick(e)
|
||||
{
|
||||
this.removeSelectionWheel();
|
||||
this.removeSelectionScroll();
|
||||
if (this._state === "IDLE")
|
||||
if (this.#state === "IDLE")
|
||||
{
|
||||
|
||||
}
|
||||
else if (this._state === "MOVE_UNIT")
|
||||
else if (this.#state === "MOVE_UNIT")
|
||||
{
|
||||
if (!e.originalEvent.ctrlKey)
|
||||
{
|
||||
@ -132,81 +150,84 @@ class Map
|
||||
}
|
||||
}
|
||||
|
||||
_onDoubleClick(e)
|
||||
#onDoubleClick(e)
|
||||
{
|
||||
if (this._state == 'IDLE')
|
||||
if (this.#state == 'IDLE')
|
||||
{
|
||||
var options = [
|
||||
{'tooltip': 'Air unit', 'src': 'spawnAir.png', 'callback': () => this._aircraftSpawnMenu(e)},
|
||||
{'tooltip': 'Ground unit', 'src': 'spawnGround.png', 'callback': () => this._groundUnitSpawnMenu(e)},
|
||||
{'tooltip': 'Smoke', 'src': 'spawnSmoke.png', 'callback': () => this._smokeSpawnMenu(e)},
|
||||
{'tooltip': 'Explosion', 'src': 'spawnExplosion.png', 'callback': () => this._explosionSpawnMenu(e)}
|
||||
{'tooltip': 'Air unit', 'src': 'spawnAir.png', 'callback': () => this.#aircraftSpawnMenu(e)},
|
||||
{'tooltip': 'Ground unit', 'src': 'spawnGround.png', 'callback': () => this.#groundUnitSpawnMenu(e)},
|
||||
{'tooltip': 'Smoke', 'src': 'spawnSmoke.png', 'callback': () => this.#smokeSpawnMenu(e)},
|
||||
{'tooltip': 'Explosion', 'src': 'spawnExplosion.png', 'callback': () => this.#explosionSpawnMenu(e)}
|
||||
]
|
||||
this._selectionWheel = new SelectionWheel(e.originalEvent.x, e.originalEvent.y, options);
|
||||
this.showSelectionWheel(e, options, true);
|
||||
}
|
||||
}
|
||||
|
||||
showSelectionWheel(e, options, coalition)
|
||||
{
|
||||
this.removeSelectionWheel();
|
||||
this.removeSelectionScroll();
|
||||
this.#selectionWheel = new SelectionWheel(e.originalEvent.x, e.originalEvent.y, options, coalition);
|
||||
}
|
||||
|
||||
/* Selection wheel and selection scroll functions */
|
||||
removeSelectionWheel()
|
||||
{
|
||||
if (this._selectionWheel !== undefined)
|
||||
if (this.#selectionWheel !== undefined)
|
||||
{
|
||||
this._selectionWheel.remove();
|
||||
this._selectionWheel = undefined;
|
||||
this.#selectionWheel.remove();
|
||||
this.#selectionWheel = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
removeSelectionScroll()
|
||||
{
|
||||
if (this._selectionScroll !== undefined)
|
||||
if (this.#selectionScroll !== undefined)
|
||||
{
|
||||
this._selectionScroll.remove();
|
||||
this._selectionScroll = undefined;
|
||||
this.#selectionScroll.remove();
|
||||
this.#selectionScroll = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/* Show unit selection for air units */
|
||||
spawnFromAirbase(e)
|
||||
{
|
||||
this._selectAircraft(e);
|
||||
this.#selectAircraft(e, undefined);
|
||||
}
|
||||
|
||||
/* Spawn a new ground unit selection wheel */
|
||||
_aircraftSpawnMenu(e)
|
||||
#aircraftSpawnMenu(e)
|
||||
{
|
||||
this.removeSelectionWheel();
|
||||
this.removeSelectionScroll();
|
||||
var options = [
|
||||
{'coalition': true, 'tooltip': 'CAP', 'src': 'spawnCAP.png', 'callback': () => this._selectAircraft(e, "CAP")},
|
||||
{'coalition': true, 'tooltip': 'CAS', 'src': 'spawnCAS.png', 'callback': () => this._selectAircraft(e, "CAS")},
|
||||
{'coalition': true, 'tooltip': 'Tanker', 'src': 'spawnTanker.png', 'callback': () => this._selectAircraft(e, "tanker")},
|
||||
{'coalition': true, 'tooltip': 'AWACS', 'src': 'spawnAWACS.png', 'callback': () => this._selectAircraft(e, "awacs")},
|
||||
{'coalition': true, 'tooltip': 'Strike', 'src': 'spawnStrike.png', 'callback': () => this._selectAircraft(e, "strike")},
|
||||
{'coalition': true, 'tooltip': 'Drone', 'src': 'spawnDrone.png', 'callback': () => this._selectAircraft(e, "drone")},
|
||||
{'coalition': true, 'tooltip': 'Transport', 'src': 'spawnTransport.png','callback': () => this._selectAircraft(e, "transport")},
|
||||
{'coalition': true, 'tooltip': 'CAP', 'src': 'spawnCAP.png', 'callback': () => this.#selectAircraft(e, "CAP")},
|
||||
{'coalition': true, 'tooltip': 'CAS', 'src': 'spawnCAS.png', 'callback': () => this.#selectAircraft(e, "CAS")},
|
||||
{'coalition': true, 'tooltip': 'Tanker', 'src': 'spawnTanker.png', 'callback': () => this.#selectAircraft(e, "tanker")},
|
||||
{'coalition': true, 'tooltip': 'AWACS', 'src': 'spawnAWACS.png', 'callback': () => this.#selectAircraft(e, "awacs")},
|
||||
{'coalition': true, 'tooltip': 'Strike', 'src': 'spawnStrike.png', 'callback': () => this.#selectAircraft(e, "strike")},
|
||||
{'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._selectionWheel = new SelectionWheel(e.originalEvent.x, e.originalEvent.y, options);
|
||||
this.showSelectionWheel(e, options, true);
|
||||
}
|
||||
|
||||
/* Spawn a new ground unit selection wheel */
|
||||
_groundUnitSpawnMenu(e)
|
||||
#groundUnitSpawnMenu(e)
|
||||
{
|
||||
this.removeSelectionWheel();
|
||||
this.removeSelectionScroll();
|
||||
var options = [
|
||||
{'coalition': true, 'tooltip': 'Howitzer', 'src': 'spawnHowitzer.png', 'callback': () => this._selectGroundUnit(e, "Howitzers")},
|
||||
{'coalition': true, 'tooltip': 'SAM', 'src': 'spawnSAM.png', 'callback': () => this._selectGroundUnit(e, "SAM")},
|
||||
{'coalition': true, 'tooltip': 'IFV', 'src': 'spawnIFV.png', 'callback': () => this._selectGroundUnit(e, "IFV")},
|
||||
{'coalition': true, 'tooltip': 'Tank', 'src': 'spawnTank.png', 'callback': () => this._selectGroundUnit(e, "Tanks")},
|
||||
{'coalition': true, 'tooltip': 'MLRS', 'src': 'spawnMLRS.png', 'callback': () => this._selectGroundUnit(e, "MLRS")},
|
||||
{'coalition': true, 'tooltip': 'Radar', 'src': 'spawnRadar.png', 'callback': () => this._selectGroundUnit(e, "Radar")},
|
||||
{'coalition': true, 'tooltip': 'Unarmed', 'src': 'spawnUnarmed.png', 'callback': () => this._selectGroundUnit(e, "Unarmed")}
|
||||
{'coalition': true, 'tooltip': 'Howitzer', 'src': 'spawnHowitzer.png', 'callback': () => this.#selectGroundUnit(e, "Howitzers")},
|
||||
{'coalition': true, 'tooltip': 'SAM', 'src': 'spawnSAM.png', 'callback': () => this.#selectGroundUnit(e, "SAM")},
|
||||
{'coalition': true, 'tooltip': 'IFV', 'src': 'spawnIFV.png', 'callback': () => this.#selectGroundUnit(e, "IFV")},
|
||||
{'coalition': true, 'tooltip': 'Tank', 'src': 'spawnTank.png', 'callback': () => this.#selectGroundUnit(e, "Tanks")},
|
||||
{'coalition': true, 'tooltip': 'MLRS', 'src': 'spawnMLRS.png', 'callback': () => this.#selectGroundUnit(e, "MLRS")},
|
||||
{'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._selectionWheel = new SelectionWheel(e.originalEvent.x, e.originalEvent.y, options);
|
||||
this.showSelectionWheel(e, options, true);
|
||||
}
|
||||
|
||||
/* Spawn smoke selection wheel */
|
||||
_smokeSpawnMenu(e)
|
||||
#smokeSpawnMenu(e)
|
||||
{
|
||||
this.removeSelectionWheel();
|
||||
this.removeSelectionScroll();
|
||||
@ -217,36 +238,36 @@ class Map
|
||||
{'tooltip': 'Green smoke', 'src': 'spawnSmoke.png', 'callback': () => {this.removeSelectionWheel(); this.removeSelectionScroll(); spawnSmoke('green', e.latlng)}, 'tint': 'green'},
|
||||
{'tooltip': 'Orange smoke', 'src': 'spawnSmoke.png', 'callback': () => {this.removeSelectionWheel(); this.removeSelectionScroll(); spawnSmoke('orange', e.latlng)}, 'tint': 'orange'},
|
||||
]
|
||||
this._selectionWheel = new SelectionWheel(e.originalEvent.x, e.originalEvent.y, options);
|
||||
this.showSelectionWheel(e, options, true);
|
||||
}
|
||||
|
||||
/* Spawn an explosion selection wheel (TODO) */
|
||||
_explosionSpawnMenu(e)
|
||||
#explosionSpawnMenu(e)
|
||||
{
|
||||
this.removeSelectionWheel();
|
||||
this.removeSelectionScroll();
|
||||
var options = [
|
||||
|
||||
]
|
||||
this._selectionWheel = new SelectionWheel(e.originalEvent.x, e.originalEvent.y, options);
|
||||
this.showSelectionWheel(e, options, true);
|
||||
}
|
||||
|
||||
/* Show unit selection for air units */
|
||||
_selectAircraft(e, group)
|
||||
#selectAircraft(e, group)
|
||||
{
|
||||
this.removeSelectionWheel();
|
||||
this.removeSelectionScroll();
|
||||
var options = unitTypes.air[group];
|
||||
options.sort();
|
||||
this._selectionScroll = new SelectionScroll(e.originalEvent.x, e.originalEvent.y, options, (unitType) => {
|
||||
this.#selectionScroll = new SelectionScroll(e.originalEvent.x, e.originalEvent.y, options, (unitType) => {
|
||||
this.removeSelectionWheel();
|
||||
this.removeSelectionScroll();
|
||||
this._unitSelectPayload(unitType, e);
|
||||
this.#unitSelectPayload(unitType, e);
|
||||
});
|
||||
}
|
||||
|
||||
/* Show weapon selection for air units */
|
||||
_unitSelectPayload(unitType, e)
|
||||
#unitSelectPayload(unitType, e)
|
||||
{
|
||||
this.removeSelectionWheel();
|
||||
this.removeSelectionScroll();
|
||||
@ -255,29 +276,29 @@ class Map
|
||||
if (options != undefined && options.length > 0)
|
||||
{
|
||||
options.sort();
|
||||
this._selectionScroll = new SelectionScroll(e.originalEvent.x, e.originalEvent.y, options, (payloadName) => {
|
||||
this.#selectionScroll = new SelectionScroll(e.originalEvent.x, e.originalEvent.y, options, (payloadName) => {
|
||||
this.removeSelectionWheel();
|
||||
this.removeSelectionScroll();
|
||||
spawnAircraft(unitType, e.latlng, this._activeCoalition, payloadName, e.airbaseName);
|
||||
spawnAircraft(unitType, e.latlng, this.#activeCoalition, payloadName, e.airbaseName);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
spawnAircraft(unitType, e.latlng, this._activeCoalition);
|
||||
spawnAircraft(unitType, e.latlng, this.#activeCoalition);
|
||||
}
|
||||
}
|
||||
|
||||
/* Show unit selection for ground units */
|
||||
_selectGroundUnit(e, group)
|
||||
#selectGroundUnit(e, group)
|
||||
{
|
||||
this.removeSelectionWheel();
|
||||
this.removeSelectionScroll();
|
||||
var options = unitTypes.vehicles[group];
|
||||
options.sort();
|
||||
this._selectionScroll = new SelectionScroll(e.originalEvent.x, e.originalEvent.y, options, (type) => {
|
||||
this.#selectionScroll = new SelectionScroll(e.originalEvent.x, e.originalEvent.y, options, (type) => {
|
||||
this.removeSelectionWheel();
|
||||
this.removeSelectionScroll();
|
||||
spawnGroundUnit(type, e.latlng, this._activeCoalition);
|
||||
spawnGroundUnit(type, e.latlng, this.#activeCoalition);
|
||||
});
|
||||
}
|
||||
}
|
||||
48
www/src/Map/SelectionScroll.ts
Normal file
@ -0,0 +1,48 @@
|
||||
export class SelectionScroll
|
||||
{
|
||||
#x : number;
|
||||
#y : number;
|
||||
#options : any; // TODO declare interface
|
||||
#container : HTMLElement;
|
||||
|
||||
constructor(x, y, options, callback)
|
||||
{
|
||||
if (options.length > 1)
|
||||
{
|
||||
this.#x = x;
|
||||
this.#y = y;
|
||||
this.#options = options;
|
||||
|
||||
/* Create the container of the scroll */
|
||||
this.#container = document.createElement("div");
|
||||
this.#container.id = 'selection-scroll-container';
|
||||
this.#container.style.left = this.#x + "px";
|
||||
this.#container.style.top = this.#y + "px";
|
||||
document.getElementById("map-container").appendChild(this.#container);
|
||||
|
||||
for (let optionID in this.#options)
|
||||
{
|
||||
var node = document.createElement("div");
|
||||
node.classList.add("selection-scroll-element");
|
||||
node.appendChild(document.createTextNode(this.#options[optionID]));
|
||||
this.#container.appendChild(node);
|
||||
node.addEventListener('click', () => callback(this.#options[optionID]))
|
||||
}
|
||||
|
||||
window.setTimeout(() => this.#show(), 100);
|
||||
}
|
||||
}
|
||||
|
||||
remove()
|
||||
{
|
||||
document.getElementById("map-container").removeChild(this.#container);
|
||||
}
|
||||
|
||||
#show()
|
||||
{
|
||||
this.#container.style.width = 220 + "px";
|
||||
this.#container.style.height = 220 + "px";
|
||||
this.#container.style.left = this.#x - 110 + "px";
|
||||
this.#container.style.top = this.#y - 110 + "px";
|
||||
}
|
||||
}
|
||||
130
www/src/Map/SelectionWheel.ts
Normal file
@ -0,0 +1,130 @@
|
||||
import { deg2rad } from 'Other/Utils.js'
|
||||
|
||||
export class SelectionWheel
|
||||
{
|
||||
#x : number;
|
||||
#y : number;
|
||||
#options : any; // TODO declare interface
|
||||
#angularSize : number;
|
||||
|
||||
#container : HTMLElement;
|
||||
#wheel : HTMLElement;
|
||||
#buttons : HTMLElement[];
|
||||
#switchLabel : HTMLLabelElement;
|
||||
|
||||
constructor(x, y, options, coalition)
|
||||
{
|
||||
if (options.length > 1)
|
||||
{
|
||||
this.#x = x;
|
||||
this.#y = y;
|
||||
this.#options = options;
|
||||
this.#angularSize = 360 / this.#options.length;
|
||||
|
||||
/* Create the container of the wheel */
|
||||
this.#container = document.createElement("div");
|
||||
this.#container.id = 'selection-wheel-container';
|
||||
this.#container.style.left = this.#x + "px";
|
||||
this.#container.style.top = this.#y + "px";
|
||||
document.getElementById("map-container").appendChild(this.#container);
|
||||
|
||||
/* Create the wheel itself */
|
||||
this.#wheel = document.createElement("div");
|
||||
this.#wheel.id = 'selection-wheel';
|
||||
this.#container.appendChild(this.#wheel);
|
||||
|
||||
/* Create the buttons */
|
||||
this.#buttons = [];
|
||||
for (let id in this.#options)
|
||||
{
|
||||
var button = document.createElement("div");
|
||||
button.classList.add("selection-wheel-button");
|
||||
button.style.left = this.#x - 25 + "px";
|
||||
button.style.top = this.#y - 25 + "px";
|
||||
button.addEventListener('click', (e) => this.#options[id].callback(e));
|
||||
this.#container.appendChild(button);
|
||||
this.#buttons.push(button);
|
||||
|
||||
var image = document.createElement("img");
|
||||
image.classList.add("selection-wheel-image");
|
||||
image.src = `img/buttons/${this.#options[id].src}`
|
||||
image.title = this.#options[id].tooltip;
|
||||
if ('tint' in this.#options[id])
|
||||
{
|
||||
button.style.setProperty('background-color', this.#options[id].tint);
|
||||
image.style.opacity = "0";
|
||||
}
|
||||
button.appendChild(image);
|
||||
}
|
||||
|
||||
/* Show the coalition switch if requested */
|
||||
if (coalition)
|
||||
{
|
||||
this.#switchLabel = <HTMLLabelElement>document.createElement("label");
|
||||
this.#switchLabel.classList.add("switch");
|
||||
this.#switchLabel.innerHTML = `<input type="checkbox" id="coalition-switch"> <span class="slider round"></span>`
|
||||
this.#container.appendChild(this.#switchLabel);
|
||||
document.getElementById("coalition-switch").addEventListener('change', (e) => this.#onSwitch(e))
|
||||
|
||||
if (map.getActiveCoalition() == "red")
|
||||
{
|
||||
document.documentElement.style.setProperty('--normal', getComputedStyle(this.#container).getPropertyValue("--red"));
|
||||
(<HTMLInputElement>document.getElementById("coalition-switch")).checked = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
document.documentElement.style.setProperty('--normal', getComputedStyle(this.#container).getPropertyValue("--blue"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
document.documentElement.style.setProperty('--normal', getComputedStyle(this.#container).getPropertyValue("--dark"));
|
||||
}
|
||||
|
||||
window.setTimeout(() => this.#show(), 100);
|
||||
}
|
||||
}
|
||||
|
||||
remove()
|
||||
{
|
||||
if (this.#container != undefined)
|
||||
{
|
||||
this.#container.removeChild(this.#wheel);
|
||||
document.getElementById("map-container").removeChild(this.#container);
|
||||
}
|
||||
}
|
||||
|
||||
#show()
|
||||
{
|
||||
this.#container.style.width = 220 + "px";
|
||||
this.#container.style.height = 220 + "px";
|
||||
this.#container.style.left = this.#x - 110 + "px";
|
||||
this.#container.style.top = this.#y - 110 + "px";
|
||||
|
||||
var r = 80;
|
||||
for (let id in this.#buttons)
|
||||
{
|
||||
var angle = parseInt(id) * this.#angularSize;
|
||||
this.#buttons[id].style.opacity = "1";
|
||||
this.#buttons[id].style.left = this.#x + r * Math.sin(deg2rad(angle)) - 25 + "px";
|
||||
this.#buttons[id].style.top = this.#y - r * Math.cos(deg2rad(angle)) - 25 + "px";
|
||||
}
|
||||
|
||||
if (this.#switchLabel != undefined)
|
||||
{
|
||||
this.#switchLabel.style.opacity = "1";
|
||||
}
|
||||
}
|
||||
|
||||
#onSwitch(e)
|
||||
{
|
||||
if (e.currentTarget.checked) {
|
||||
document.documentElement.style.setProperty('--normal', getComputedStyle(this.#container).getPropertyValue("--red"));
|
||||
map.setActiveCoalition("red");
|
||||
} else {
|
||||
document.documentElement.style.setProperty('--normal', getComputedStyle(this.#container).getPropertyValue("--blue"));
|
||||
map.setActiveCoalition("blue");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
77
www/src/Other/MissionData.ts
Normal file
@ -0,0 +1,77 @@
|
||||
import { Marker, LatLng } from "leaflet";
|
||||
|
||||
export class MissionData
|
||||
{
|
||||
#bullseye : any; //TODO declare interface
|
||||
#bullseyeMarker : Marker;
|
||||
#airbasesMarkers: {[name: string]: Marker};
|
||||
#unitsData : any; //TODO declare interface
|
||||
#airbases : any; //TODO declare interface
|
||||
|
||||
constructor()
|
||||
{
|
||||
this.#bullseye = undefined;
|
||||
this.#bullseyeMarker = undefined;
|
||||
this.#airbasesMarkers = {};
|
||||
}
|
||||
|
||||
update(data)
|
||||
{
|
||||
this.#bullseye = data.missionData.bullseye;
|
||||
this.#unitsData = data.missionData.unitsData;
|
||||
this.#airbases = data.missionData.airbases;
|
||||
this.#drawBullseye();
|
||||
this.#drawAirbases();
|
||||
}
|
||||
|
||||
getUnitData(ID)
|
||||
{
|
||||
if (ID in this.#unitsData)
|
||||
{
|
||||
return this.#unitsData[ID];
|
||||
}
|
||||
else
|
||||
{
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
#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));
|
||||
}
|
||||
}
|
||||
|
||||
#drawAirbases()
|
||||
{
|
||||
for (let idx in this.#airbases)
|
||||
{
|
||||
var airbase = this.#airbases[idx]
|
||||
if (this.#airbasesMarkers[idx] === undefined)
|
||||
{
|
||||
// @ts-ignore TODO: find a good way to extend markers in typescript
|
||||
this.#airbasesMarkers[idx] = new L.Marker.AirbaseMarker(new L.LatLng(airbase.lat, airbase.lng), {name: airbase.callsign}).addTo(map.getMap());
|
||||
this.#airbasesMarkers[idx].on('click', (e) => this.#onAirbaseClick(e));
|
||||
}
|
||||
else
|
||||
{
|
||||
// @ts-ignore TODO: find a good way to extend markers in typescript
|
||||
this.#airbasesMarkers[idx].setCoalitionID(airbase.coalition);
|
||||
this.#airbasesMarkers[idx].setLatLng(new LatLng(airbase.lat, airbase.lng));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#onAirbaseClick(e)
|
||||
{
|
||||
e.airbaseName = e.sourceTarget.options.name;
|
||||
e.coalitionID = e.sourceTarget.coalitionID;
|
||||
map.spawnFromAirbase(e);
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
function distance(lat1, lon1, lat2, lon2)
|
||||
export function distance(lat1, lon1, lat2, lon2)
|
||||
{
|
||||
const R = 6371e3; // metres
|
||||
const φ1 = deg2rad(lat1); // φ, λ in radians
|
||||
@ -14,7 +14,7 @@ function distance(lat1, lon1, lat2, lon2)
|
||||
return d;
|
||||
}
|
||||
|
||||
function bearing(lat1, lon1, lat2, lon2)
|
||||
export function bearing(lat1, lon1, lat2, lon2)
|
||||
{
|
||||
const φ1 = deg2rad(lat1); // φ, λ in radians
|
||||
const φ2 = deg2rad(lat2);
|
||||
@ -28,49 +28,9 @@ function bearing(lat1, lon1, lat2, lon2)
|
||||
return brng;
|
||||
}
|
||||
|
||||
function latlng2xy(lat, lon)
|
||||
{
|
||||
const latBulls = missionData.bullseye.lat;
|
||||
const lonBulls = missionData.bullseye.lng;
|
||||
const d = distance(latBulls, lonBulls, lat, lon);
|
||||
const brng = bearing(latBulls, lonBulls, lat, lon);
|
||||
const x = d * Math.cos(deg2rad(brng));
|
||||
const y = d * Math.sin(deg2rad(brng));
|
||||
|
||||
xy = {};
|
||||
xy.x = x;
|
||||
xy.y = y;
|
||||
|
||||
return xy;
|
||||
}
|
||||
|
||||
function xy2latlng(x, y)
|
||||
{
|
||||
const xBulls = missionData.bullseye.x;
|
||||
const yBulls = missionData.bullseye.y;
|
||||
const latBulls = missionData.bullseye.lat;
|
||||
const lonBulls = missionData.bullseye.lng;
|
||||
|
||||
const R = 6371e3; // metres
|
||||
const φ1 = deg2rad(latBulls); // φ, λ in radians
|
||||
const λ1 = deg2rad(lonBulls); // φ, λ in radians
|
||||
|
||||
const d = Math.sqrt(Math.pow(x - xBulls, 2) + Math.pow(y - yBulls, 2));
|
||||
const brng = -rad2deg(Math.atan2(y - yBulls, x - xBulls));
|
||||
|
||||
const φ2 = Math.asin(Math.sin(φ1)*Math.cos(d/R) + Math.cos(φ1)*Math.sin(d/R)*Math.cos(brng));
|
||||
const λ2 = λ1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(φ1), Math.cos(d/R)-Math.sin(φ1)*Math.sin(φ2));
|
||||
|
||||
latlng = {};
|
||||
latlng.lat = rad2deg(φ2);
|
||||
latlng.lng = rad2deg(λ2);
|
||||
|
||||
return latlng;
|
||||
}
|
||||
|
||||
const zeroPad = (num, places) => String(num).padStart(places, '0')
|
||||
|
||||
function ConvertDDToDMS(D, lng)
|
||||
export function ConvertDDToDMS(D, lng)
|
||||
{
|
||||
var dir = D < 0 ? (lng ? "W" : "S") : lng ? "E" : "N";
|
||||
var deg = 0 | (D < 0 ? (D = -D) : D);
|
||||
@ -84,13 +44,13 @@ function ConvertDDToDMS(D, lng)
|
||||
return dir + zeroPad(deg, 2) + "°" + zeroPad(min, 2) + "'" + zeroPad(sec, 2) + "." + zeroPad(dec, 2) + "\"";
|
||||
}
|
||||
|
||||
function deg2rad(deg)
|
||||
export function deg2rad(deg)
|
||||
{
|
||||
var pi = Math.PI;
|
||||
return deg * (pi/180);
|
||||
}
|
||||
|
||||
function rad2deg(rad)
|
||||
export function rad2deg(rad)
|
||||
{
|
||||
var pi = Math.PI;
|
||||
return rad / (pi/180);
|
||||
@ -1,10 +1,14 @@
|
||||
class FormationControlPanel
|
||||
export class FormationControlPanel
|
||||
{
|
||||
#panel : HTMLElement;
|
||||
#formations : string[];
|
||||
#editing : boolean;
|
||||
|
||||
constructor(id)
|
||||
{
|
||||
this._panel = document.getElementById(id);
|
||||
this.#panel = document.getElementById(id);
|
||||
|
||||
this._formations = ["", "Echelon", "Line abreast", "Box", "Trail", "Finger tip", "Tactical line abreast", "Fluid four", "Spread four"];
|
||||
this.#formations = ["", "Echelon", "Line abreast", "Box", "Trail", "Finger tip", "Tactical line abreast", "Fluid four", "Spread four"];
|
||||
}
|
||||
|
||||
update(selectedUnits)
|
||||
@ -12,24 +16,24 @@ class FormationControlPanel
|
||||
if (selectedUnits.length == 1)
|
||||
{
|
||||
// Don't update if user is editing
|
||||
if (selectedUnits[0].leader && !this._editing)
|
||||
if (selectedUnits[0].leader && !this.#editing)
|
||||
{
|
||||
this._panel.style.bottom = "15px";
|
||||
this._showFormationControls(selectedUnits[0]);
|
||||
this.#panel.style.bottom = "15px";
|
||||
this.#showFormationControls(selectedUnits[0]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this._panel.style.bottom = (-this._panel.offsetHeight - 2) + "px";
|
||||
this._showFormationControls(); // Empty, cleans the panel
|
||||
this.#panel.style.bottom = (-this.#panel.offsetHeight - 2) + "px";
|
||||
this.#showFormationControls(undefined); // Empty, cleans the panel
|
||||
}
|
||||
}
|
||||
|
||||
_showFormationControls(selectedUnit)
|
||||
#showFormationControls(selectedUnit)
|
||||
{
|
||||
if (selectedUnit !== undefined)
|
||||
{
|
||||
this._panel.innerHTML = `
|
||||
this.#panel.innerHTML = `
|
||||
<div style="display: flex">
|
||||
<table class="panel-table" id="unit-info-table">
|
||||
<tr>
|
||||
@ -57,24 +61,24 @@ class FormationControlPanel
|
||||
</div>
|
||||
`;
|
||||
|
||||
var select = document.getElementById("formation-type-select");
|
||||
for(var i = 0; i < this._formations.length; i++) {
|
||||
var opt = this._formations[i];
|
||||
var select: HTMLSelectElement = <HTMLSelectElement>document.getElementById("formation-type-select");
|
||||
for(var i = 0; i < this.#formations.length; i++) {
|
||||
var opt = this.#formations[i];
|
||||
var el = document.createElement("option");
|
||||
el.textContent = opt;
|
||||
el.value = opt;
|
||||
select.appendChild(el);
|
||||
}
|
||||
|
||||
select.addEventListener("focus", () => this._editing = true)
|
||||
select.addEventListener("blur", () => this._editing = false)
|
||||
object.addEventListener("change", () => leader.setformation());
|
||||
select.addEventListener("focus", () => this.#editing = true)
|
||||
select.addEventListener("blur", () => this.#editing = false)
|
||||
//select.addEventListener("change", () => leader.setformation());
|
||||
|
||||
select.value = selectedUnit.formation;
|
||||
}
|
||||
else
|
||||
{
|
||||
this._panel.innerHTML = ``;
|
||||
this.#panel.innerHTML = ``;
|
||||
}
|
||||
}
|
||||
}
|
||||
87
www/src/Panels/PanelButton.ts
Normal file
@ -0,0 +1,87 @@
|
||||
export class PanelButton
|
||||
{
|
||||
#div : HTMLElement;
|
||||
#enabled : boolean;
|
||||
#callbacks : any[]; // TODO how to set type callables?
|
||||
#baseIconHTML : string;
|
||||
|
||||
constructor(parent, icon, tooltip)
|
||||
{
|
||||
this.#div = document.createElement("div");
|
||||
this.setIcon(icon, tooltip);
|
||||
this.setSlashed(false);
|
||||
|
||||
this.#div.classList.add("panel-button");
|
||||
parent.appendChild(this.#div);
|
||||
|
||||
this.setEnabled(true);
|
||||
|
||||
this.#div.onclick = () => this.#onClick();
|
||||
this.#callbacks = [];
|
||||
}
|
||||
|
||||
setEnabled(enabled)
|
||||
{
|
||||
this.#enabled = enabled;
|
||||
if (enabled)
|
||||
{
|
||||
this.#div.classList.remove("panel-button-disabled");
|
||||
}
|
||||
else
|
||||
{
|
||||
this.#div.classList.add("panel-button-disabled");
|
||||
}
|
||||
}
|
||||
|
||||
addCallback(callback)
|
||||
{
|
||||
this.#callbacks.push(callback);
|
||||
}
|
||||
|
||||
clearCallbacks()
|
||||
{
|
||||
this.#callbacks = [];
|
||||
}
|
||||
|
||||
setIcon(icon, tooltip)
|
||||
{
|
||||
if (icon.includes("png"))
|
||||
{
|
||||
this.#baseIconHTML = `<img src="${icon}" title="${tooltip}">`;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.#baseIconHTML = `<i class="fa ${icon}" title="${tooltip}"></i>`;
|
||||
}
|
||||
this.#div.innerHTML = this.#baseIconHTML;
|
||||
}
|
||||
|
||||
setSubicon(subicon)
|
||||
{
|
||||
this.#baseIconHTML = `<div style="display: flex;">${this.#baseIconHTML}<i style="font-size: 10px;" class="fa ${subicon}"></i></div>`;
|
||||
this.#div.innerHTML = this.#baseIconHTML;
|
||||
}
|
||||
|
||||
setSlashed(slashed)
|
||||
{
|
||||
if (slashed)
|
||||
{
|
||||
this.#div.innerHTML = `<div style="display: flex; justify-content: center;">${this.#baseIconHTML}<i style="position:fixed;" class="fa fa-slash"></i></div>`;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.#div.innerHTML = this.#baseIconHTML;
|
||||
}
|
||||
}
|
||||
|
||||
#onClick()
|
||||
{
|
||||
if (this.#enabled)
|
||||
{
|
||||
for (let callback in this.#callbacks)
|
||||
{
|
||||
this.#callbacks[callback]();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
106
www/src/Panels/SettingsPanel.ts
Normal file
@ -0,0 +1,106 @@
|
||||
import { PanelButton } from "./PanelButton.js";
|
||||
|
||||
export class SettingsPanel
|
||||
{
|
||||
#panel : HTMLElement;
|
||||
|
||||
#humanIcon : string;
|
||||
#AIIcon : string;
|
||||
#weaponsIcon : string;
|
||||
#labelsIcon : string;
|
||||
#deadIcon : string;
|
||||
|
||||
#humanButton : PanelButton;
|
||||
#AIButton : PanelButton;
|
||||
#weaponsButton : PanelButton;
|
||||
#deadAliveButton : PanelButton;
|
||||
|
||||
#human : string;
|
||||
#AI : string;
|
||||
#weapons : string;
|
||||
#deadAlive : string;
|
||||
|
||||
constructor(id)
|
||||
{
|
||||
this.#panel = document.getElementById(id);
|
||||
|
||||
/* Create all buttons, disabled by default */
|
||||
this.#humanIcon = "fa-user";
|
||||
this.#AIIcon = "fa-desktop";
|
||||
this.#weaponsIcon = "fa-bomb";
|
||||
this.#labelsIcon = "fa-font";
|
||||
this.#deadIcon = "fa-skull";
|
||||
|
||||
this.#humanButton = new PanelButton(this.#panel, this.#humanIcon, "Player visibility");
|
||||
this.#AIButton = new PanelButton(this.#panel, this.#AIIcon, "AI visibility");
|
||||
this.#weaponsButton = new PanelButton(this.#panel, this.#weaponsIcon, "Weapons visibility");
|
||||
this.#deadAliveButton = new PanelButton(this.#panel, this.#deadIcon, "Dead units visibility");
|
||||
|
||||
this.#humanButton.addCallback(() => this.#onHumanButton());
|
||||
this.#AIButton.addCallback(() => this.#onAIButton());
|
||||
this.#weaponsButton.addCallback(() => this.#onWeaponsButton());
|
||||
this.#deadAliveButton.addCallback(() => this.#cycleDeadAlive());
|
||||
|
||||
this.#human = "labels";
|
||||
this.#humanButton.setSubicon(this.#labelsIcon);
|
||||
this.#AI = "marker";
|
||||
this.#weapons = "marker";
|
||||
this.#deadAlive = "both";
|
||||
}
|
||||
|
||||
getSettings()
|
||||
{
|
||||
return {'human': this.#human, 'AI': this.#AI, 'weapons': this.#weapons, 'deadAlive': this.#deadAlive}
|
||||
}
|
||||
|
||||
#onHumanButton()
|
||||
{
|
||||
this.#human = this.#cycleVisibility(this.#humanButton, this.#human, this.#humanIcon);
|
||||
}
|
||||
|
||||
#onAIButton()
|
||||
{
|
||||
this.#AI = this.#cycleVisibility(this.#AIButton, this.#AI, this.#AIIcon);
|
||||
}
|
||||
|
||||
#onWeaponsButton()
|
||||
{
|
||||
this.#weapons = this.#cycleVisibility(this.#weaponsButton, this.#weapons, this.#weaponsIcon);
|
||||
}
|
||||
|
||||
#cycleVisibility(button, variable, icon)
|
||||
{
|
||||
if (variable === "labels")
|
||||
{
|
||||
variable = "marker";
|
||||
button.setIcon(icon);
|
||||
button.setSlashed(false);
|
||||
}
|
||||
else if (variable === "marker")
|
||||
{
|
||||
variable = "none";
|
||||
button.setSlashed(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
variable = "labels";
|
||||
button.setSubicon(this.#labelsIcon);
|
||||
button.setSlashed(false);
|
||||
}
|
||||
return variable;
|
||||
}
|
||||
|
||||
#cycleDeadAlive()
|
||||
{
|
||||
if (this.#deadAlive === "both")
|
||||
{
|
||||
this.#deadAlive = "alive";
|
||||
this.#deadAliveButton.setSlashed(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.#deadAlive = "both";
|
||||
this.#deadAliveButton.setSlashed(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
43
www/src/Panels/UnitControlPanel.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { PanelButton } from "./PanelButton.js";
|
||||
|
||||
export class UnitControlPanel
|
||||
{
|
||||
#panel : HTMLElement;
|
||||
#slowButton : PanelButton;
|
||||
#fastButton : PanelButton;
|
||||
#descendButton : PanelButton;
|
||||
#climbButton : PanelButton;
|
||||
|
||||
constructor(id)
|
||||
{
|
||||
this.#panel = document.getElementById(id);
|
||||
|
||||
/* Create all buttons, disabled by default */
|
||||
//this.#moveButton = new PanelButton(this.#panel, "fa-play");
|
||||
//this.#stopButton = new PanelButton(this.#panel, "fa-pause");
|
||||
this.#slowButton = new PanelButton(this.#panel, "fa-angle-right", "Decelerate");
|
||||
this.#fastButton = new PanelButton(this.#panel, "fa-angle-double-right", "Accelerate");
|
||||
this.#descendButton = new PanelButton(this.#panel, "fa-arrow-down", "Descend");
|
||||
this.#climbButton = new PanelButton(this.#panel, "fa-arrow-up", "Climb");
|
||||
//this.#repeatButton = new PanelButton(this.#panel, "fa-undo");
|
||||
|
||||
this.setEnabled(false);
|
||||
|
||||
//this.#moveButton.addCallback(unitsManager.selectedUnitsMove);
|
||||
//this.#stopButton.addCallback(() => unitsManager.selectedUnitsChangeSpeed('stop'));
|
||||
this.#slowButton.addCallback(() => unitsManager.selectedUnitsChangeSpeed('slow'));
|
||||
this.#fastButton.addCallback(() => unitsManager.selectedUnitsChangeSpeed('fast'));
|
||||
this.#descendButton.addCallback(() => unitsManager.selectedUnitsChangeAltitude('descend'));
|
||||
this.#climbButton.addCallback(() => unitsManager.selectedUnitsChangeAltitude('climb'));
|
||||
}
|
||||
|
||||
setEnabled(enabled)
|
||||
{
|
||||
//this.#moveButton.setEnabled(true);
|
||||
//this.#stopButton.setEnabled(true);
|
||||
this.#slowButton.setEnabled(enabled);
|
||||
this.#fastButton.setEnabled(enabled);
|
||||
this.#descendButton.setEnabled(enabled);
|
||||
this.#climbButton.setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
@ -1,25 +1,29 @@
|
||||
class UnitInfoPanel
|
||||
import { ConvertDDToDMS, rad2deg } from 'Other/Utils.js'
|
||||
|
||||
export class UnitInfoPanel
|
||||
{
|
||||
#panel: HTMLElement;
|
||||
|
||||
constructor(id)
|
||||
{
|
||||
this._panel = document.getElementById(id);
|
||||
this.#panel = document.getElementById(id);
|
||||
}
|
||||
|
||||
update(selectedUnits)
|
||||
{
|
||||
if (selectedUnits.length == 1)
|
||||
{
|
||||
this._panel.style.bottom = "15px";
|
||||
this._showUnitData(selectedUnits[0]);
|
||||
this.#panel.style.bottom = "15px";
|
||||
this.#showUnitData(selectedUnits[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
this._panel.style.bottom = (-this._panel.offsetHeight - 2) + "px";
|
||||
this._showUnitData(); // Empty, cleans the panel
|
||||
this.#panel.style.bottom = (-this.#panel.offsetHeight - 2) + "px";
|
||||
this.#showUnitData(undefined); // Empty, cleans the panel
|
||||
}
|
||||
}
|
||||
|
||||
_showUnitData(selectedUnit)
|
||||
#showUnitData(selectedUnit)
|
||||
{
|
||||
if (selectedUnit !== undefined)
|
||||
{
|
||||
@ -39,7 +43,7 @@ class UnitInfoPanel
|
||||
}
|
||||
}
|
||||
|
||||
this._panel.innerHTML = `
|
||||
this.#panel.innerHTML = `
|
||||
<div style="display: flex">
|
||||
<table class="panel-table" id="unit-info-table">
|
||||
<tr>
|
||||
@ -135,7 +139,7 @@ class UnitInfoPanel
|
||||
}
|
||||
else
|
||||
{
|
||||
this._panel.innerHTML = ``;
|
||||
this.#panel.innerHTML = ``;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,26 +1,59 @@
|
||||
class Unit
|
||||
import { Marker, LatLng, Polyline } from 'leaflet';
|
||||
import { ConvertDDToDMS } from 'Other/Utils.js'
|
||||
import { showMessage } from 'index.js'
|
||||
import { attackUnit } from 'DCS/DCSCommands.js'
|
||||
|
||||
export class Unit
|
||||
{
|
||||
ID : number;
|
||||
selectable : boolean;
|
||||
// @ts-ignore TODO: find a good way to extend markers in typescript
|
||||
marker : L.Marker.UnitMarker;
|
||||
leader : boolean;
|
||||
wingman : boolean;
|
||||
wingmen : Unit[];
|
||||
formation : string;
|
||||
name : string;
|
||||
unitName : string;
|
||||
groupName : string;
|
||||
latitude : number;
|
||||
longitude : number;
|
||||
altitude : number;
|
||||
heading : number;
|
||||
coalitionID : number;
|
||||
alive : boolean;
|
||||
speed : number;
|
||||
currentTask : string;
|
||||
type : JSON;
|
||||
flags : JSON;
|
||||
activePath : JSON;
|
||||
missionData : JSON;
|
||||
|
||||
#selected : boolean;
|
||||
#preventClick : boolean;
|
||||
#pathMarkers : Marker[];
|
||||
#pathPolyline : Polyline;
|
||||
#targetsPolylines : Polyline[];
|
||||
#timer : number;
|
||||
|
||||
constructor(ID, marker)
|
||||
{
|
||||
this.ID = ID;
|
||||
this.selectable = true;
|
||||
|
||||
// The marker is set by the inherited class
|
||||
this.marker = marker;
|
||||
this.marker.on('click', (e) => this.onClick(e));
|
||||
|
||||
this._selected = false;
|
||||
|
||||
this._pathMarkers = [];
|
||||
|
||||
this._pathPolyline = new L.Polyline([], {color: '#2d3e50', weight: 3, opacity: 0.5, smoothFactor: 1});
|
||||
this._pathPolyline.addTo(map.getMap());
|
||||
|
||||
this._targetsPolylines = [];
|
||||
|
||||
this.marker.on('click', (e) => this.#onClick(e));
|
||||
this.marker.on('dblclick', (e) => this.#onDoubleClick(e));
|
||||
this.leader = true;
|
||||
this.wingmen = [];
|
||||
this.formation = undefined;
|
||||
|
||||
this.#selected = false;
|
||||
this.#preventClick = false;
|
||||
this.#pathMarkers = [];
|
||||
this.#pathPolyline = new Polyline([], {color: '#2d3e50', weight: 3, opacity: 0.5, smoothFactor: 1});
|
||||
this.#pathPolyline.addTo(map.getMap());
|
||||
this.#targetsPolylines = [];
|
||||
}
|
||||
|
||||
update(response)
|
||||
@ -55,8 +88,8 @@ class Unit
|
||||
|
||||
this.missionData = missionData.getUnitData(this.ID)
|
||||
|
||||
this.setSelected(this.getSelected() & this.alive)
|
||||
this.drawMarker();
|
||||
this.setSelected(this.getSelected() && this.alive)
|
||||
this.drawMarker({});
|
||||
if (this.getSelected() && this.activePath != undefined)
|
||||
{
|
||||
this.drawPath();
|
||||
@ -80,9 +113,9 @@ class Unit
|
||||
setSelected(selected)
|
||||
{
|
||||
// Only alive units can be selected. Some units are not selectable (weapons)
|
||||
if ((this.alive || !selected) && this.selectable && this._selected != selected)
|
||||
if ((this.alive || !selected) && this.selectable && this.#selected != selected)
|
||||
{
|
||||
this._selected = selected;
|
||||
this.#selected = selected;
|
||||
this.marker.setSelected(selected);
|
||||
unitsManager.onUnitSelection();
|
||||
}
|
||||
@ -90,7 +123,7 @@ class Unit
|
||||
|
||||
getSelected()
|
||||
{
|
||||
return this._selected;
|
||||
return this.#selected;
|
||||
}
|
||||
|
||||
addDestination(latlng)
|
||||
@ -127,24 +160,40 @@ class Unit
|
||||
this.activePath = undefined;
|
||||
}
|
||||
|
||||
onClick(e)
|
||||
#onClick(e)
|
||||
{
|
||||
if (map.getState() === 'IDLE' || map.getState() === 'MOVE_UNIT' || e.originalEvent.ctrlKey)
|
||||
{
|
||||
if (!e.originalEvent.ctrlKey)
|
||||
{
|
||||
unitsManager.deselectAllUnits();
|
||||
this.#timer = setTimeout(() => {
|
||||
if (!this.#preventClick) {
|
||||
if (map.getState() === 'IDLE' || map.getState() === 'MOVE_UNIT' || e.originalEvent.ctrlKey)
|
||||
{
|
||||
if (!e.originalEvent.ctrlKey)
|
||||
{
|
||||
unitsManager.deselectAllUnits();
|
||||
}
|
||||
this.setSelected(true);
|
||||
}
|
||||
}
|
||||
this.setSelected(true);
|
||||
}
|
||||
else if (map.getState() === 'ATTACK')
|
||||
this.#preventClick = false;
|
||||
}, 200);
|
||||
}
|
||||
|
||||
#onDoubleClick(e)
|
||||
{
|
||||
clearTimeout(this.#timer);
|
||||
this.#preventClick = true;
|
||||
|
||||
var options = [
|
||||
{'tooltip': 'Attack', 'src': 'attack.png', 'callback': () => {map.removeSelectionWheel(); unitsManager.attackUnit(this.ID);}},
|
||||
{'tooltip': 'Go to tanker', 'src': 'tanker.png', 'callback': () => {map.removeSelectionWheel(); showMessage("Function not implemented yet");}},
|
||||
{'tooltip': 'RTB', 'src': 'rtb.png', 'callback': () => {map.removeSelectionWheel(); showMessage("Function not implemented yet");}}
|
||||
]
|
||||
|
||||
if (!this.leader && !this.wingman)
|
||||
{
|
||||
unitsManager.attackUnit(this.ID);
|
||||
}
|
||||
else if (map.getState() === 'FORMATION')
|
||||
{
|
||||
unitsManager.createFormation(this.ID);
|
||||
options.push({'tooltip': 'Create formation', 'src': 'formation.png', 'callback': () => {map.removeSelectionWheel(); unitsManager.createFormation(this.ID);}});
|
||||
}
|
||||
|
||||
map.showSelectionWheel(e, options, false);
|
||||
}
|
||||
|
||||
drawMarker(settings)
|
||||
@ -170,7 +219,7 @@ class Unit
|
||||
|
||||
// Draw the marker
|
||||
var zIndex = this.marker.getZIndex();
|
||||
var newLatLng = new L.LatLng(this.latitude, this.longitude);
|
||||
var newLatLng = new LatLng(this.latitude, this.longitude);
|
||||
this.marker.setLatLng(newLatLng);
|
||||
this.marker.setAngle(this.heading);
|
||||
this.marker.setZIndex(zIndex);
|
||||
@ -183,53 +232,53 @@ class Unit
|
||||
drawPath()
|
||||
{
|
||||
var _points = [];
|
||||
_points.push(new L.LatLng(this.latitude, this.longitude));
|
||||
_points.push(new LatLng(this.latitude, this.longitude));
|
||||
|
||||
// Add markers if missing
|
||||
while (this._pathMarkers.length < Object.keys(this.activePath).length)
|
||||
while (this.#pathMarkers.length < Object.keys(this.activePath).length)
|
||||
{
|
||||
var marker = L.marker([0, 0]).addTo(map.getMap());
|
||||
this._pathMarkers.push(marker);
|
||||
var marker = new Marker([0, 0]).addTo(map.getMap());
|
||||
this.#pathMarkers.push(marker);
|
||||
}
|
||||
|
||||
// Remove markers if too many
|
||||
while (this._pathMarkers.length > Object.keys(this.activePath).length)
|
||||
while (this.#pathMarkers.length > Object.keys(this.activePath).length)
|
||||
{
|
||||
map.getMap().removeLayer(this._pathMarkers[this._pathMarkers.length - 1]);
|
||||
this._pathMarkers.splice(this._pathMarkers.length - 1, 1)
|
||||
map.getMap().removeLayer(this.#pathMarkers[this.#pathMarkers.length - 1]);
|
||||
this.#pathMarkers.splice(this.#pathMarkers.length - 1, 1)
|
||||
}
|
||||
|
||||
// Update the position of the existing markers (to avoid creating markers uselessly)
|
||||
for (let WP in this.activePath)
|
||||
{
|
||||
var destination = this.activePath[WP];
|
||||
this._pathMarkers[parseInt(WP) - 1].setLatLng([destination.lat, destination.lng]);
|
||||
_points.push(new L.LatLng(destination.lat, destination.lng));
|
||||
this._pathPolyline.setLatLngs(_points);
|
||||
this.#pathMarkers[parseInt(WP) - 1].setLatLng([destination.lat, destination.lng]);
|
||||
_points.push(new LatLng(destination.lat, destination.lng));
|
||||
this.#pathPolyline.setLatLngs(_points);
|
||||
}
|
||||
}
|
||||
|
||||
clearPath()
|
||||
{
|
||||
for (let WP in this._pathMarkers)
|
||||
for (let WP in this.#pathMarkers)
|
||||
{
|
||||
map.getMap().removeLayer(this._pathMarkers[WP]);
|
||||
map.getMap().removeLayer(this.#pathMarkers[WP]);
|
||||
}
|
||||
this._pathMarkers = [];
|
||||
this._pathPolyline.setLatLngs([]);
|
||||
this.#pathMarkers = [];
|
||||
this.#pathPolyline.setLatLngs([]);
|
||||
}
|
||||
|
||||
drawTargets()
|
||||
{
|
||||
for (let typeIndex in this.missionData.targets)
|
||||
for (let typeIndex in this.missionData['targets'])
|
||||
{
|
||||
for (let index in this.missionData.targets[typeIndex])
|
||||
for (let index in this.missionData['targets'][typeIndex])
|
||||
{
|
||||
var targetData = this.missionData.targets[typeIndex][index];
|
||||
var targetData = this.missionData['targets'][typeIndex][index];
|
||||
var target = unitsManager.getUnitByID(targetData.object["id_"])
|
||||
if (target != undefined){
|
||||
var startLatLng = new L.LatLng(this.latitude, this.longitude)
|
||||
var endLatLng = new L.LatLng(target.latitude, target.longitude)
|
||||
var startLatLng = new LatLng(this.latitude, this.longitude)
|
||||
var endLatLng = new LatLng(target.latitude, target.longitude)
|
||||
|
||||
var color;
|
||||
if (typeIndex === "radar")
|
||||
@ -248,9 +297,9 @@ class Unit
|
||||
{
|
||||
color = "#FFFFFF";
|
||||
}
|
||||
var targetPolyline = new L.Polyline([startLatLng, endLatLng], {color: color, weight: 3, opacity: 1, smoothFactor: 1});
|
||||
var targetPolyline = new Polyline([startLatLng, endLatLng], {color: color, weight: 3, opacity: 1, smoothFactor: 1});
|
||||
targetPolyline.addTo(map.getMap());
|
||||
this._targetsPolylines.push(targetPolyline)
|
||||
this.#targetsPolylines.push(targetPolyline)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -258,9 +307,9 @@ class Unit
|
||||
|
||||
clearTargets()
|
||||
{
|
||||
for (let index in this._targetsPolylines)
|
||||
for (let index in this.#targetsPolylines)
|
||||
{
|
||||
map.getMap().removeLayer(this._targetsPolylines[index])
|
||||
map.getMap().removeLayer(this.#targetsPolylines[index])
|
||||
}
|
||||
}
|
||||
|
||||
@ -303,7 +352,7 @@ class Unit
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
console.log(this.unitName + " altitude change request: " + speedChange);
|
||||
console.log(this.unitName + " altitude change request: " + altitudeChange);
|
||||
}
|
||||
};
|
||||
|
||||
@ -350,11 +399,11 @@ class Unit
|
||||
}
|
||||
}
|
||||
|
||||
class AirUnit extends Unit
|
||||
export class AirUnit extends Unit
|
||||
{
|
||||
drawMarker()
|
||||
{
|
||||
if (this.flags.Human)
|
||||
if (this.flags['Human'])
|
||||
{
|
||||
super.drawMarker(settingsPanel.getSettings().human);
|
||||
}
|
||||
@ -365,10 +414,11 @@ class AirUnit extends Unit
|
||||
}
|
||||
}
|
||||
|
||||
class Aircraft extends AirUnit
|
||||
export class Aircraft extends AirUnit
|
||||
{
|
||||
constructor(ID, data)
|
||||
{
|
||||
// @ts-ignore TODO: find a good way to extend markers in typescript
|
||||
var marker = new L.Marker.UnitMarker.AirUnitMarker.AircraftMarker({
|
||||
riseOnHover: true,
|
||||
unitName: data.unitName,
|
||||
@ -380,10 +430,11 @@ class Aircraft extends AirUnit
|
||||
}
|
||||
}
|
||||
|
||||
class Helicopter extends AirUnit
|
||||
export class Helicopter extends AirUnit
|
||||
{
|
||||
constructor(ID, data)
|
||||
{
|
||||
// @ts-ignore TODO: find a good way to extend markers in typescript
|
||||
var marker = new L.Marker.UnitMarker.AirUnitMarker.HelicopterMarker({
|
||||
riseOnHover: true,
|
||||
unitName: data.unitName,
|
||||
@ -395,10 +446,11 @@ class Helicopter extends AirUnit
|
||||
}
|
||||
}
|
||||
|
||||
class GroundUnit extends Unit
|
||||
export class GroundUnit extends Unit
|
||||
{
|
||||
constructor(ID, data)
|
||||
{
|
||||
// @ts-ignore TODO: find a good way to extend markers in typescript
|
||||
var marker = new L.Marker.UnitMarker.GroundMarker({
|
||||
riseOnHover: true,
|
||||
unitName: data.unitName,
|
||||
@ -415,10 +467,11 @@ class GroundUnit extends Unit
|
||||
}
|
||||
}
|
||||
|
||||
class NavyUnit extends Unit
|
||||
export class NavyUnit extends Unit
|
||||
{
|
||||
constructor(ID, data)
|
||||
{
|
||||
// @ts-ignore TODO: find a good way to extend markers in typescript
|
||||
var marker = new L.Marker.UnitMarker.NavyMarker({
|
||||
riseOnHover: true,
|
||||
unitName: data.unitName,
|
||||
@ -435,7 +488,7 @@ class NavyUnit extends Unit
|
||||
}
|
||||
}
|
||||
|
||||
class Weapon extends Unit
|
||||
export class Weapon extends Unit
|
||||
{
|
||||
constructor(ID, data)
|
||||
{
|
||||
@ -449,16 +502,17 @@ class Weapon extends Unit
|
||||
super.drawMarker(settingsPanel.getSettings().weapons);
|
||||
}
|
||||
|
||||
onClick(e)
|
||||
#onClick(e)
|
||||
{
|
||||
// Weapons can not be clicked
|
||||
}
|
||||
}
|
||||
|
||||
class Missile extends Weapon
|
||||
export class Missile extends Weapon
|
||||
{
|
||||
constructor(ID, data)
|
||||
{
|
||||
// @ts-ignore TODO: find a good way to extend markers in typescript
|
||||
var marker = new L.Marker.UnitMarker.WeaponMarker.MissileMarker({
|
||||
riseOnHover: true,
|
||||
unitName: "",
|
||||
@ -470,10 +524,11 @@ class Missile extends Weapon
|
||||
}
|
||||
}
|
||||
|
||||
class Bomb extends Weapon
|
||||
export class Bomb extends Weapon
|
||||
{
|
||||
constructor(ID, data)
|
||||
{
|
||||
// @ts-ignore TODO: find a good way to extend markers in typescript
|
||||
var marker = new L.Marker.UnitMarker.WeaponMarker.BombMarker({
|
||||
riseOnHover: true,
|
||||
unitName: "",
|
||||
@ -1,9 +1,17 @@
|
||||
class UnitsManager
|
||||
import { Unit } from 'Unit.js'
|
||||
import { LatLng } from 'leaflet';
|
||||
import { cloneUnit } from 'DCS/DCSCommands.js'
|
||||
import { showMessage } from 'index.js';
|
||||
|
||||
export class UnitsManager
|
||||
{
|
||||
#units: { [ID: number]: Unit};
|
||||
#copiedUnits: Unit[];
|
||||
|
||||
constructor()
|
||||
{
|
||||
this._units = {};
|
||||
this._copiedUnits = [];
|
||||
this.#units = {};
|
||||
this.#copiedUnits = [];
|
||||
}
|
||||
|
||||
addUnit(ID, data)
|
||||
@ -12,13 +20,13 @@ class UnitsManager
|
||||
var constructor = eval(data.category);
|
||||
if (constructor != undefined)
|
||||
{
|
||||
this._units[ID] = new constructor(ID, data);
|
||||
this.#units[ID] = new constructor(ID, data);
|
||||
}
|
||||
}
|
||||
|
||||
getUnitByID(ID)
|
||||
{
|
||||
return this._units[ID];
|
||||
return this.#units[ID];
|
||||
}
|
||||
|
||||
removeUnit(ID)
|
||||
@ -28,9 +36,9 @@ class UnitsManager
|
||||
|
||||
deselectAllUnits()
|
||||
{
|
||||
for (let ID in this._units)
|
||||
for (let ID in this.#units)
|
||||
{
|
||||
this._units[ID].setSelected(false);
|
||||
this.#units[ID].setSelected(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,11 +47,11 @@ class UnitsManager
|
||||
for (let ID in data["units"])
|
||||
{
|
||||
// Create the unit if missing from the local array, then update the data. Drawing is handled by leaflet.
|
||||
if (!(ID in this._units))
|
||||
if (!(ID in this.#units))
|
||||
{
|
||||
this.addUnit(parseInt(ID), data["units"][ID]);
|
||||
}
|
||||
this._units[ID].update(data["units"][ID]);
|
||||
this.#units[ID].update(data["units"][ID]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,25 +61,23 @@ class UnitsManager
|
||||
{
|
||||
map.setState("MOVE_UNIT");
|
||||
unitControlPanel.setEnabled(true);
|
||||
actionPanel.setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
map.setState("IDLE");
|
||||
unitControlPanel.setEnabled(false);
|
||||
actionPanel.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
selectFromBounds(bounds)
|
||||
{
|
||||
this.deselectAllUnits();
|
||||
for (let ID in this._units)
|
||||
for (let ID in this.#units)
|
||||
{
|
||||
var latlng = new L.LatLng(this._units[ID].latitude, this._units[ID].longitude);
|
||||
var latlng = new LatLng(this.#units[ID].latitude, this.#units[ID].longitude);
|
||||
if (bounds.contains(latlng))
|
||||
{
|
||||
this._units[ID].setSelected(true);
|
||||
this.#units[ID].setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -79,11 +85,11 @@ class UnitsManager
|
||||
getSelectedUnits()
|
||||
{
|
||||
var selectedUnits = [];
|
||||
for (let ID in this._units)
|
||||
for (let ID in this.#units)
|
||||
{
|
||||
if (this._units[ID].getSelected())
|
||||
if (this.#units[ID].getSelected())
|
||||
{
|
||||
selectedUnits.push(this._units[ID]);
|
||||
selectedUnits.push(this.#units[ID]);
|
||||
}
|
||||
}
|
||||
return selectedUnits;
|
||||
@ -94,7 +100,12 @@ class UnitsManager
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits)
|
||||
{
|
||||
selectedUnits[idx].addDestination(latlng);
|
||||
var commandedUnit = selectedUnits[idx];
|
||||
if (selectedUnits[idx].wingman)
|
||||
{
|
||||
commandedUnit = this.getLeader(selectedUnits[idx].ID);
|
||||
}
|
||||
commandedUnit.addDestination(latlng);
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,7 +114,12 @@ class UnitsManager
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits)
|
||||
{
|
||||
selectedUnits[idx].clearDestinations();
|
||||
var commandedUnit = selectedUnits[idx];
|
||||
if (selectedUnits[idx].wingman)
|
||||
{
|
||||
commandedUnit = this.getLeader(selectedUnits[idx].ID);
|
||||
}
|
||||
commandedUnit.clearDestinations();
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,14 +160,14 @@ class UnitsManager
|
||||
|
||||
copyUnits()
|
||||
{
|
||||
this._copiedUnits = this.getSelectedUnits();
|
||||
this.#copiedUnits = this.getSelectedUnits();
|
||||
}
|
||||
|
||||
pasteUnits()
|
||||
{
|
||||
for (let idx in this._copiedUnits)
|
||||
for (let idx in this.#copiedUnits)
|
||||
{
|
||||
var unit = this._copiedUnits[idx];
|
||||
var unit = this.#copiedUnits[idx];
|
||||
cloneUnit(unit.ID);
|
||||
}
|
||||
}
|
||||
@ -161,7 +177,13 @@ class UnitsManager
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits)
|
||||
{
|
||||
selectedUnits[idx].attackUnit(ID);
|
||||
// If a unit is a wingman, send the command to its leader
|
||||
var commandedUnit = selectedUnits[idx];
|
||||
if (selectedUnits[idx].wingman)
|
||||
{
|
||||
commandedUnit = this.getLeader(selectedUnits[idx].ID);
|
||||
}
|
||||
commandedUnit.attackUnit(ID);
|
||||
}
|
||||
}
|
||||
|
||||
@ -183,10 +205,12 @@ class UnitsManager
|
||||
}
|
||||
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);
|
||||
@ -203,28 +227,19 @@ class UnitsManager
|
||||
}
|
||||
}
|
||||
|
||||
getUnitsByFormationID(formationID)
|
||||
getLeader(ID)
|
||||
{
|
||||
var formationUnits = [];
|
||||
for (let ID in this._units)
|
||||
{
|
||||
if (this._units[ID].formationID == formationID)
|
||||
{
|
||||
formationUnits.push(this._units[ID]);
|
||||
}
|
||||
}
|
||||
return formationUnits;
|
||||
}
|
||||
|
||||
getLeaderByFormationID(formationID)
|
||||
{
|
||||
var formationUnits = this.getUnitsByFormationID(formationID);
|
||||
for (let unit of formationUnits)
|
||||
for (let idx in this.#units)
|
||||
{
|
||||
var unit = this.#units[idx];
|
||||
if (unit.leader)
|
||||
{
|
||||
return unit;
|
||||
if (unit.wingmen.includes(this.getUnitByID(ID)))
|
||||
{
|
||||
return unit;
|
||||
}
|
||||
}
|
||||
}
|
||||
showMessage("Error: no leader found for this unit")
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
|
||||
var unitTypes = {};
|
||||
|
||||
var unitTypes: any = {};
|
||||
/* NAVY */
|
||||
unitTypes.navy = {};
|
||||
unitTypes.navy.blue = [
|
||||
18
www/src/globals.d.ts
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
import {MissionData} from './Other/MissionData.js'
|
||||
import {UnitsManager} from './Units/UnitsManager.js'
|
||||
import {UnitControlPanel} from './Panels/UnitControlPanel.js'
|
||||
import {UnitInfoPanel} from './Panels/UnitInfoPanel.js'
|
||||
import {FormationControlPanel} from './Panels/FormationControlPanel.js'
|
||||
import {SettingsPanel} from './Panels/SettingsPanel.js'
|
||||
import {Map} from './Map/Map.js'
|
||||
|
||||
declare global {
|
||||
var missionData: MissionData;
|
||||
var settingsPanel: SettingsPanel;
|
||||
var unitsManager: UnitsManager;
|
||||
var unitInfoPanel: UnitInfoPanel;
|
||||
var unitControlPanel: UnitControlPanel;
|
||||
var formationControlPanel: FormationControlPanel;
|
||||
var map: Map;
|
||||
var RESTaddress: string;
|
||||
}
|
||||
@ -1,12 +1,12 @@
|
||||
var missionData;
|
||||
var settingsPanel;
|
||||
var unitsManager;
|
||||
var unitInfoPanel;
|
||||
var unitControlPanel;
|
||||
var unitActionPanel;
|
||||
var formationControlPanel;
|
||||
var map;
|
||||
var RESTaddress = "http://localhost:30000/restdemo";
|
||||
import {MissionData} from './Other/MissionData.js'
|
||||
import {UnitsManager} from './Units/UnitsManager.js'
|
||||
import {UnitControlPanel} from './Panels/UnitControlPanel.js'
|
||||
import {UnitInfoPanel} from './Panels/UnitInfoPanel.js'
|
||||
import {FormationControlPanel} from './Panels/FormationControlPanel.js'
|
||||
import {SettingsPanel} from './Panels/SettingsPanel.js'
|
||||
import {Map} from './Map/Map.js'
|
||||
|
||||
RESTaddress = "http://localhost:30000/restdemo";
|
||||
|
||||
function setup()
|
||||
{
|
||||
@ -18,8 +18,7 @@ function setup()
|
||||
unitControlPanel = new UnitControlPanel("unit-control-panel");
|
||||
formationControlPanel = new FormationControlPanel("formation-control-panel");
|
||||
settingsPanel = new SettingsPanel("settings-panel");
|
||||
actionPanel = new ActionPanel("action-panel")
|
||||
map = new Map();
|
||||
map = new Map();
|
||||
|
||||
// Main update rate. 250ms is minimum time, equal to server update time.
|
||||
setInterval(() => update(), 250);
|
||||
@ -30,7 +29,6 @@ function resize()
|
||||
var unitControlPanelHeight = document.getElementById("header").offsetHeight;
|
||||
document.getElementById("map").style.height = `${window.innerHeight - unitControlPanelHeight - 10}px`;
|
||||
document.getElementById("unit-control-panel").style.left = `${window.innerWidth / 2 - document.getElementById("unit-control-panel").offsetWidth / 2}px`
|
||||
document.getElementById("action-panel").style.top = `${window.innerHeight / 2 - document.getElementById("action-panel").offsetHeight / 2}px`
|
||||
document.getElementById("snackbar").style.left = `${window.innerWidth / 2 - document.getElementById("snackbar").offsetWidth / 2}px`
|
||||
}
|
||||
|
||||
@ -59,33 +57,7 @@ function update()
|
||||
window.onload = setup;
|
||||
window.onresize = resize;
|
||||
|
||||
window.console = {
|
||||
log: function(str){
|
||||
if (str !== this.lastMessage)
|
||||
{
|
||||
var node = document.createElement("div");
|
||||
node.classList.add("log-message");
|
||||
node.appendChild(document.createTextNode("> " + str));
|
||||
document.getElementById("log").appendChild(node);
|
||||
this.lastMessage = str
|
||||
}
|
||||
},
|
||||
|
||||
error: function(str){
|
||||
if (str !== this.lastMessage)
|
||||
{
|
||||
var node = document.createElement("div");
|
||||
node.classList.add("error-message");
|
||||
node.appendChild(document.createTextNode("> *** " + str + "***"));
|
||||
document.getElementById("log").appendChild(node);
|
||||
this.lastMessage = str
|
||||
}
|
||||
},
|
||||
|
||||
lastMessage: "none"
|
||||
}
|
||||
|
||||
function showMessage(message)
|
||||
export function showMessage(message)
|
||||
{
|
||||
// Get the snackbar DIV
|
||||
var x = document.getElementById("snackbar");
|
||||
@ -96,5 +68,4 @@ function showMessage(message)
|
||||
|
||||
// After 3 seconds, remove the show class from DIV
|
||||
setTimeout(function(){ x.className = x.className.replace("show", ""); }, 3000);
|
||||
|
||||
}
|
||||
@ -1,11 +1,22 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"allowJs": true,
|
||||
"target": "es5"
|
||||
"typeRoots": ["node_modules/@types"],
|
||||
"outDir": "./js",
|
||||
"target": "es2018",
|
||||
"lib": [
|
||||
"es2018",
|
||||
"dom"
|
||||
],
|
||||
"types": [
|
||||
"leaflet",
|
||||
"geojson"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"./js/*",
|
||||
"./js/**/*"
|
||||
"include": [
|
||||
"src/**/*",
|
||||
"src/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
}
|
||||