Started migration to TypeScript
37
www/css/AirbaseMarker.css
Normal file
@@ -0,0 +1,37 @@
|
||||
.airbasemarker-container-table {
|
||||
height: 60px;
|
||||
width: 60px;
|
||||
left: -30px;
|
||||
top: -30px;
|
||||
border: 1px transparent solid;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.airbasemarker-icon-img {
|
||||
height: 60px;
|
||||
width: 60px;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
display: block;
|
||||
opacity: 0.8;
|
||||
position: absolute;
|
||||
filter: drop-shadow(1px 1px 0 white) drop-shadow(1px -1px 0 white) drop-shadow(-1px 1px 0 white) drop-shadow(-1px -1px 0 white);
|
||||
}
|
||||
|
||||
.airbasemarker-icon-img-blue {
|
||||
filter: invert(37%) sepia(21%) saturate(7402%) hue-rotate(193deg) brightness(103%) contrast(104%) drop-shadow(1px 1px 0 white) drop-shadow(1px -1px 0 white) drop-shadow(-1px 1px 0 white) drop-shadow(-1px -1px 0 white);
|
||||
}
|
||||
|
||||
.airbasemarker-icon-img-red {
|
||||
filter: invert(21%) sepia(96%) saturate(4897%) hue-rotate(353deg) brightness(108%) contrast(90%) drop-shadow(1px 1px 0 white) drop-shadow(1px -1px 0 white) drop-shadow(-1px 1px 0 white) drop-shadow(-1px -1px 0 white);
|
||||
}
|
||||
|
||||
.airbasemarker-name-div {
|
||||
bottom: -20px;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
font: 800 14px Arial;
|
||||
white-space: nowrap;
|
||||
-webkit-text-fill-color: white;
|
||||
-webkit-text-stroke: 1px;
|
||||
}
|
||||
@@ -40,3 +40,47 @@ body{
|
||||
color: rgb(255, 154, 154);
|
||||
text-shadow: 1px 1px #000, -1px -1px #000, 1px -1px #000, -1px 1px #000;
|
||||
}
|
||||
|
||||
/* The snackbar - position it at the bottom and in the middle of the screen */
|
||||
#snackbar {
|
||||
visibility: hidden; /* Hidden by default. Visible on click */
|
||||
min-width: 250px; /* Set a default minimum width */
|
||||
background-color: #2d3e50; /* Black background color */
|
||||
color: #fff; /* White text color */
|
||||
text-align: center; /* Centered text */
|
||||
border-radius: 2px; /* Rounded borders */
|
||||
padding: 16px; /* Padding */
|
||||
position: fixed; /* Sit on top of the screen */
|
||||
z-index: 1000; /* Add a z-index if needed */
|
||||
top: 120px; /* 30px from the bottom */
|
||||
}
|
||||
|
||||
/* Show the snackbar when clicking on a button (class added with JavaScript) */
|
||||
#snackbar.show {
|
||||
visibility: visible; /* Show the snackbar */
|
||||
/* Add animation: Take 0.5 seconds to fade in and out the snackbar.
|
||||
However, delay the fade out process for 2.5 seconds */
|
||||
-webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;
|
||||
animation: fadein 0.5s, fadeout 0.5s 2.5s;
|
||||
}
|
||||
|
||||
/* Animations to fade the snackbar in and out */
|
||||
@-webkit-keyframes fadein {
|
||||
from {top: 0; opacity: 0;}
|
||||
to {top: 120px; opacity: 1;}
|
||||
}
|
||||
|
||||
@keyframes fadein {
|
||||
from {top: 0; opacity: 0;}
|
||||
to {top: 120px; opacity: 1;}
|
||||
}
|
||||
|
||||
@-webkit-keyframes fadeout {
|
||||
from {top: 120px; opacity: 1;}
|
||||
to {top: 0; opacity: 0;}
|
||||
}
|
||||
|
||||
@keyframes fadeout {
|
||||
from {top: 120px; opacity: 1;}
|
||||
to {top: 0; opacity: 0;}
|
||||
}
|
||||
@@ -6,3 +6,23 @@
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.leaflet-container.move-cursor-enabled {
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.leaflet-container.attack-cursor-enabled {
|
||||
cursor: url("../img/buttons/attack.png") 25 15,auto;
|
||||
}
|
||||
|
||||
.leaflet-marker-icon.attack-cursor-enabled {
|
||||
cursor: url("../img/buttons/attack.png") 25 15,auto;
|
||||
}
|
||||
|
||||
.leaflet-container.formation-cursor-enabled {
|
||||
cursor: url("../img/buttons/formation.png") 25 15,auto;
|
||||
}
|
||||
|
||||
.leaflet-marker-icon.formation-cursor-enabled {
|
||||
cursor: url("../img/buttons/formation.png") 25 15,auto;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
left: 10px;
|
||||
bottom: -80px;
|
||||
bottom: -102px;
|
||||
transition: bottom 0.2s;
|
||||
}
|
||||
|
||||
.unit-control-panel {
|
||||
background-color: #202831;
|
||||
height: 40px;
|
||||
width: 400px;
|
||||
width: 200px;
|
||||
border: solid white 1px;
|
||||
font-size: 12px;
|
||||
position: fixed;
|
||||
@@ -28,7 +28,23 @@
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.control-panel {
|
||||
.action-panel {
|
||||
background-color: #202831;
|
||||
height: 400px;
|
||||
width: 40px;
|
||||
border: solid white 1px;
|
||||
font-size: 12px;
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
left: 10px;
|
||||
top: 50px;
|
||||
transition: height 0.2s;
|
||||
display: flex;
|
||||
align-content: flex-start;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.settings-panel {
|
||||
background-color: #202831;
|
||||
height: 40px;
|
||||
width: 100%;
|
||||
@@ -38,6 +54,19 @@
|
||||
justify-content: left;
|
||||
}
|
||||
|
||||
.formation-control-panel {
|
||||
background-color: #202831;
|
||||
height: 100px;
|
||||
width: 300px;
|
||||
border: solid white 1px;
|
||||
font-size: 12px;
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
left: 830px;
|
||||
bottom: -102px;
|
||||
transition: bottom 0.2s;
|
||||
}
|
||||
|
||||
.panel-table {
|
||||
text-shadow: 1px 1px #000, -1px -1px #000, 1px -1px #000, -1px 1px #000;
|
||||
height: 100%;
|
||||
@@ -70,8 +99,6 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
transition: font-size 0.05s;
|
||||
text-shadow: 1px 1px #000, -1px -1px #000, 1px -1px #000, -1px 1px #000;
|
||||
}
|
||||
|
||||
.panel-button:hover {
|
||||
@@ -80,6 +107,7 @@
|
||||
|
||||
.panel-button:active {
|
||||
color: white;
|
||||
filter: brightness(110%);
|
||||
}
|
||||
|
||||
.panel-button-disabled {
|
||||
|
||||
BIN
www/img/airbase.png
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
BIN
www/img/buttons/attack.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
www/img/buttons/bomb.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
www/img/buttons/carpet.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
www/img/buttons/formation.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
www/img/buttons/land.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
www/img/buttons/spawnAWACS.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
www/img/buttons/spawnCAP.png
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
www/img/buttons/spawnCAS.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
www/img/buttons/spawnDrone.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
www/img/buttons/spawnStrike.png
Normal file
|
After Width: | Height: | Size: 8.1 KiB |
BIN
www/img/buttons/spawnTanker.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
www/img/buttons/spawnTransport.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
@@ -7,6 +7,7 @@
|
||||
<link rel="stylesheet" href="css/index.css"/>
|
||||
<link rel="stylesheet" href="css/panels.css"/>
|
||||
<link rel="stylesheet" href="css/Map.css"/>
|
||||
<link rel="stylesheet" href="css/AirbaseMarker.css"/>
|
||||
<link rel="stylesheet" href="css/UnitMarker.css"/>
|
||||
<link rel="stylesheet" href="css/SelectionWheel.css"/>
|
||||
<link rel="stylesheet" href="css/SelectionScroll.css"/>
|
||||
@@ -18,36 +19,48 @@
|
||||
<script src="https://unpkg.com/leaflet@1.9.2/dist/leaflet.js"
|
||||
integrity="sha256-o9N1jGDZrf5tS+Ft4gbIK7mYMipq9lqpVJ91xHSyKhg="
|
||||
crossorigin=""></script>
|
||||
<script src="js/payloadNames.js"></script>
|
||||
<script src="js/ControlPanel.js"></script>
|
||||
<script src="js/DCSCommands.js"></script>
|
||||
<script src="js/Utils.js"></script>
|
||||
<script src="js/unitTypes.js"></script>
|
||||
<script src="js/PanelButton.js"></script>
|
||||
<script src="js/UnitInfoPanel.js"></script>
|
||||
<script src="js/UnitControlPanel.js"></script>
|
||||
<script src="js/Map.js"></script>
|
||||
<script src="js/MissionData.js"></script>
|
||||
<script src="js/Unit.js"></script>
|
||||
<script src="js/UnitMarker.js"></script>
|
||||
<script src="js/UnitsManager.js"></script>
|
||||
<script src="js/SelectionWheel.js"></script>
|
||||
<script src="js/SelectionScroll.js"></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 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">
|
||||
<tr id="header">
|
||||
<td>
|
||||
<div class="control-panel" id="top-control-panel"></div>
|
||||
<div class="settings-panel" id="settings-panel"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id="map-container">
|
||||
<div id="map"></div>
|
||||
<div id="log"></div>
|
||||
<div class="unit-info-panel" id="left-panel"></div>
|
||||
<div class="unit-control-panel" id="top-panel"></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>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -32,7 +32,7 @@ function spawnGroundUnit(type, latlng, coalition)
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
function spawnAirUnit(type, latlng, coalition, payloadName)
|
||||
function spawnAircraft(type, latlng, coalition, payloadName = "", airbaseName = "")
|
||||
{
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
@@ -43,25 +43,42 @@ function spawnAirUnit(type, latlng, coalition, payloadName)
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"type": type, "location": latlng, "coalition": coalition, "payloadName": payloadName};
|
||||
var command = {"type": type, "location": latlng, "coalition": coalition, "payloadName": payloadName, "airbaseName": airbaseName};
|
||||
var data = {"spawnAir": command}
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
function attackUnit(unitID, targetID)
|
||||
function attackUnit(ID, targetID)
|
||||
{
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
console.log("Unit " + unitsManager.getUnit(unitID).unitName + " attack " + unitsManager.getUnit(targetID).unitName );
|
||||
console.log("Unit " + unitsManager.getUnitByID(ID).unitName + " attack " + unitsManager.getUnitByID(targetID).unitName );
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"unitID": unitID, "targetID": targetID};
|
||||
var command = {"ID": ID, "targetID": targetID};
|
||||
var data = {"attackUnit": command}
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
function cloneUnit(ID)
|
||||
{
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
console.log("Unit " + unitsManager.getUnitByID(ID).unitName + " cloned");
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"ID": ID};
|
||||
var data = {"cloneUnit": command}
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
@@ -17,7 +17,10 @@ class Map
|
||||
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.setState("IDLE");
|
||||
|
||||
this._selectionWheel = undefined;
|
||||
@@ -52,14 +55,42 @@ class Map
|
||||
setState(newState)
|
||||
{
|
||||
this._state = newState;
|
||||
|
||||
var cursorElements = document.getElementsByClassName("action-cursor");
|
||||
for (let item of cursorElements)
|
||||
{
|
||||
item.classList.remove("move-cursor-enabled", "attack-cursor-enabled", "formation-cursor-enabled");
|
||||
}
|
||||
if (this._state === "IDLE")
|
||||
{
|
||||
L.DomUtil.removeClass(this._map._container, 'move-cursor-enabled');
|
||||
|
||||
}
|
||||
else if (this._state === "UNIT_SELECTED")
|
||||
else if (this._state === "MOVE_UNIT")
|
||||
{
|
||||
L.DomUtil.addClass(this._map._container, 'move-cursor-enabled');
|
||||
for (let item of cursorElements)
|
||||
{
|
||||
item.classList.add("move-cursor-enabled");
|
||||
}
|
||||
}
|
||||
else if (this._state === "ATTACK")
|
||||
{
|
||||
for (let item of cursorElements)
|
||||
{
|
||||
item.classList.add("attack-cursor-enabled");
|
||||
}
|
||||
}
|
||||
else if (this._state === "FORMATION")
|
||||
{
|
||||
for (let item of cursorElements)
|
||||
{
|
||||
item.classList.add("formation-cursor-enabled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getState()
|
||||
{
|
||||
return this._state;
|
||||
}
|
||||
|
||||
/* Set the active coalition (for persistency) */
|
||||
@@ -77,6 +108,7 @@ class Map
|
||||
// Right click
|
||||
_onContextMenu(e)
|
||||
{
|
||||
this.setState("IDLE");
|
||||
unitsManager.deselectAllUnits();
|
||||
this.removeSelectionWheel();
|
||||
this.removeSelectionScroll();
|
||||
@@ -90,7 +122,7 @@ class Map
|
||||
{
|
||||
|
||||
}
|
||||
else if (this._state === "UNIT_SELECTED")
|
||||
else if (this._state === "MOVE_UNIT")
|
||||
{
|
||||
if (!e.originalEvent.ctrlKey)
|
||||
{
|
||||
@@ -102,13 +134,16 @@ class Map
|
||||
|
||||
_onDoubleClick(e)
|
||||
{
|
||||
var options = [
|
||||
{'tooltip': 'Air unit', 'src': 'spawnAir.png', 'callback': () => this._unitSelectAir(e)},
|
||||
{'tooltip': 'Ground unit', 'src': 'spawnGround.png', 'callback': () => this._groundSpawnMenu(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);
|
||||
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)}
|
||||
]
|
||||
this._selectionWheel = new SelectionWheel(e.originalEvent.x, e.originalEvent.y, options);
|
||||
}
|
||||
}
|
||||
|
||||
/* Selection wheel and selection scroll functions */
|
||||
@@ -130,30 +165,42 @@ class Map
|
||||
}
|
||||
}
|
||||
|
||||
/* Spawn a new air unit selection wheel (TODO, divide units by type, like bomber, fighter, tanker etc)*/
|
||||
_airSpawnMenu(e)
|
||||
/* Show unit selection for air units */
|
||||
spawnFromAirbase(e)
|
||||
{
|
||||
this._selectAircraft(e);
|
||||
}
|
||||
|
||||
/* Spawn a new ground unit selection wheel */
|
||||
_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")},
|
||||
]
|
||||
this._selectionWheel = new SelectionWheel(e.originalEvent.x, e.originalEvent.y, options);
|
||||
}
|
||||
|
||||
/* Spawn a new ground unit selection wheel */
|
||||
_groundSpawnMenu(e)
|
||||
_groundUnitSpawnMenu(e)
|
||||
{
|
||||
this.removeSelectionWheel();
|
||||
this.removeSelectionScroll();
|
||||
var options = [
|
||||
{'coalition': true, 'tooltip': 'Howitzer', 'src': 'spawnHowitzer.png', 'callback': () => this._unitSelectGround(e, "Howitzers")},
|
||||
{'coalition': true, 'tooltip': 'SAM', 'src': 'spawnSAM.png', 'callback': () => this._unitSelectGround(e, "SAM")},
|
||||
{'coalition': true, 'tooltip': 'IFV', 'src': 'spawnIFV.png', 'callback': () => this._unitSelectGround(e, "IFV")},
|
||||
{'coalition': true, 'tooltip': 'Tank', 'src': 'spawnTank.png', 'callback': () => this._unitSelectGround(e, "Tanks")},
|
||||
{'coalition': true, 'tooltip': 'MLRS', 'src': 'spawnMLRS.png', 'callback': () => this._unitSelectGround(e, "MLRS")},
|
||||
{'coalition': true, 'tooltip': 'Radar', 'src': 'spawnRadar.png', 'callback': () => this._unitSelectGround(e, "Radar")},
|
||||
{'coalition': true, 'tooltip': 'Unarmed', 'src': 'spawnUnarmed.png', 'callback': () => this._unitSelectGround(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);
|
||||
}
|
||||
@@ -185,11 +232,11 @@ class Map
|
||||
}
|
||||
|
||||
/* Show unit selection for air units */
|
||||
_unitSelectAir(e)
|
||||
_selectAircraft(e, group)
|
||||
{
|
||||
this.removeSelectionWheel();
|
||||
this.removeSelectionScroll();
|
||||
var options = unitTypes.air;
|
||||
var options = unitTypes.air[group];
|
||||
options.sort();
|
||||
this._selectionScroll = new SelectionScroll(e.originalEvent.x, e.originalEvent.y, options, (unitType) => {
|
||||
this.removeSelectionWheel();
|
||||
@@ -205,16 +252,23 @@ class Map
|
||||
this.removeSelectionScroll();
|
||||
var options = [];
|
||||
options = payloadNames[unitType]
|
||||
options.sort();
|
||||
this._selectionScroll = new SelectionScroll(e.originalEvent.x, e.originalEvent.y, options, (payloadName) => {
|
||||
this.removeSelectionWheel();
|
||||
this.removeSelectionScroll();
|
||||
spawnAirUnit(unitType, e.latlng, this._activeCoalition, payloadName);
|
||||
});
|
||||
if (options != undefined && options.length > 0)
|
||||
{
|
||||
options.sort();
|
||||
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);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
spawnAircraft(unitType, e.latlng, this._activeCoalition);
|
||||
}
|
||||
}
|
||||
|
||||
/* Show unit selection for ground units */
|
||||
_unitSelectGround(e, group)
|
||||
_selectGroundUnit(e, group)
|
||||
{
|
||||
this.removeSelectionWheel();
|
||||
this.removeSelectionScroll();
|
||||
@@ -36,6 +36,7 @@ class SelectionWheel
|
||||
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);
|
||||
@@ -1,39 +0,0 @@
|
||||
class MissionData
|
||||
{
|
||||
constructor()
|
||||
{
|
||||
this._bullseye = undefined;
|
||||
this._bullseyeMarker = undefined;
|
||||
}
|
||||
|
||||
update(data)
|
||||
{
|
||||
this._bullseye = data.missionData.bullseye;
|
||||
this._unitsData = data.missionData.unitsData;
|
||||
this._drawBullseye();
|
||||
}
|
||||
|
||||
getUnitData(ID)
|
||||
{
|
||||
if (ID in this._unitsData)
|
||||
{
|
||||
return this._unitsData[ID];
|
||||
}
|
||||
else
|
||||
{
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
_drawBullseye()
|
||||
{
|
||||
if (this._bullseyeMarker === undefined)
|
||||
{
|
||||
this._bullseyeMarker = L.marker([this._bullseye.lat, this._bullseye.lng]).addTo(map.getMap());
|
||||
}
|
||||
else
|
||||
{
|
||||
this._bullseyeMarker .setLatLng(new L.LatLng(this._bullseye.lat, this._bullseye.lng));
|
||||
}
|
||||
}
|
||||
}
|
||||
53
www/js/Other/AirbaseMarker.js
Normal file
@@ -0,0 +1,53 @@
|
||||
L.Marker.AirbaseMarker = L.Marker.extend(
|
||||
{
|
||||
options: {
|
||||
name: "No name",
|
||||
position: undefined,
|
||||
coalitionID: 2,
|
||||
iconSrc: "img/airbase.png"
|
||||
},
|
||||
|
||||
// Marker constructor
|
||||
initialize: function(latlng, options) {
|
||||
this._latlng = latlng;
|
||||
if (options != undefined)
|
||||
{
|
||||
L.setOptions(this, options);
|
||||
}
|
||||
var icon = new L.DivIcon({
|
||||
html: `<table class="unitmarker-container-table" id="container-table">
|
||||
<tr>
|
||||
<td>
|
||||
<img class="airbasemarker-icon-img" id="icon-img" src="${this.options.iconSrc}">
|
||||
<div class="airbasemarker-name-div" id="name">${this.options.name}</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>`,
|
||||
className: 'airbase-marker-icon'}); // Set the marker, className must be set to avoid white square
|
||||
this.setIcon(icon);
|
||||
},
|
||||
|
||||
setCoalitionID: function(coalitionID)
|
||||
{
|
||||
this.options.coalitionID = coalitionID;
|
||||
// Set the coalitionID
|
||||
var img = this._icon.querySelector("#icon-img");
|
||||
img.classList.remove("airbasemarker-icon-img-blue");
|
||||
img.classList.remove("airbasemarker-icon-img-red");
|
||||
if (this.options.coalitionID == 2)
|
||||
{
|
||||
img.classList.add("airbasemarker-icon-img-blue");
|
||||
}
|
||||
else if (this.options.coalitionID == 1)
|
||||
{
|
||||
img.classList.add("airbasemarker-icon-img-red");
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// By default markers can be hovered and clicked
|
||||
L.Marker.AirbaseMarker.addInitHook(function()
|
||||
{
|
||||
|
||||
});
|
||||
67
www/js/Other/MissionData.js
Normal file
@@ -0,0 +1,67 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
30
www/js/Panels/ActionPanel.js
Normal file
@@ -0,0 +1,30 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
82
www/js/Panels/FormationControlPanel.js
Normal file
@@ -0,0 +1,82 @@
|
||||
class FormationControlPanel
|
||||
{
|
||||
constructor(id)
|
||||
{
|
||||
this._panel = document.getElementById(id);
|
||||
|
||||
this._formations = ["", "Echelon", "Line abreast", "Box", "Trail", "Finger tip", "Tactical line abreast", "Fluid four", "Spread four"];
|
||||
}
|
||||
|
||||
update(selectedUnits)
|
||||
{
|
||||
if (selectedUnits.length == 1)
|
||||
{
|
||||
// Don't update if user is editing
|
||||
if (selectedUnits[0].leader && !this._editing)
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
_showFormationControls(selectedUnit)
|
||||
{
|
||||
if (selectedUnit !== undefined)
|
||||
{
|
||||
this._panel.innerHTML = `
|
||||
<div style="display: flex">
|
||||
<table class="panel-table" id="unit-info-table">
|
||||
<tr>
|
||||
<td colspan="4" class="panel-title">
|
||||
FORMATION CONTROL
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="panel-label">
|
||||
Formation:
|
||||
</td>
|
||||
<td class="panel-content">
|
||||
${selectedUnit.formationID}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="panel-label">
|
||||
Formation type:
|
||||
</td>
|
||||
<td class="panel-content">
|
||||
<select id="formation-type-select"></select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
`;
|
||||
|
||||
var select = 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.value = selectedUnit.formation;
|
||||
}
|
||||
else
|
||||
{
|
||||
this._panel.innerHTML = ``;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
class PanelButton
|
||||
{
|
||||
constructor(parent, icon)
|
||||
constructor(parent, icon, tooltip)
|
||||
{
|
||||
this._div = document.createElement("div");
|
||||
this.setIcon(icon);
|
||||
this.setIcon(icon, tooltip);
|
||||
this.setSlashed(false);
|
||||
|
||||
this._div.classList.add("panel-button");
|
||||
@@ -38,9 +38,16 @@ class PanelButton
|
||||
this._callbacks = [];
|
||||
}
|
||||
|
||||
setIcon(icon)
|
||||
setIcon(icon, tooltip)
|
||||
{
|
||||
this._baseIcon = `<i class="fa ${icon}"></i>`;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
class ControlPanel
|
||||
class SettingsPanel
|
||||
{
|
||||
constructor(id)
|
||||
{
|
||||
this._panel = document.getElementById(id);
|
||||
/* Create all buttons, disabled by default */
|
||||
|
||||
/* 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);
|
||||
this._AIButton = new PanelButton(this._panel, this._AIIcon);
|
||||
this._weaponsButton = new PanelButton(this._panel, this._weaponsIcon);
|
||||
this._deadAliveButton = new PanelButton(this._panel, this._deadIcon);
|
||||
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());
|
||||
35
www/js/Panels/UnitControlPanel.js
Normal file
@@ -0,0 +1,35 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -7,23 +7,15 @@ class UnitInfoPanel
|
||||
|
||||
update(selectedUnits)
|
||||
{
|
||||
if (selectedUnits.length > 0)
|
||||
if (selectedUnits.length == 1)
|
||||
{
|
||||
this._panel.style.bottom = "15px";
|
||||
if (selectedUnits.length == 1)
|
||||
{
|
||||
this._showUnitData(selectedUnits[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
this._showUnitData();
|
||||
this._panel.style.bottom = "-80px";
|
||||
}
|
||||
this._showUnitData(selectedUnits[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
this._showUnitData();
|
||||
this._panel.style.bottom = "-80px";
|
||||
this._panel.style.bottom = (-this._panel.offsetHeight - 2) + "px";
|
||||
this._showUnitData(); // Empty, cleans the panel
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +32,7 @@ class UnitInfoPanel
|
||||
var displayName = ammo.desc.displayName;
|
||||
var amount = ammo.count;
|
||||
loadout += amount + "x" + displayName;
|
||||
if (parseInt(index) < Object.keys(selectedUnit.missionData.ammo).length - 1)
|
||||
if (parseInt(index) < Object.keys(selectedUnit.missionData.ammo).length)
|
||||
{
|
||||
loadout += ", ";
|
||||
}
|
||||
@@ -143,15 +135,7 @@ class UnitInfoPanel
|
||||
}
|
||||
else
|
||||
{
|
||||
this._panel.innerHTML = `
|
||||
<table class="panel-table">
|
||||
<tr>
|
||||
<td class="panel-title">
|
||||
UNIT INFO
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
`;
|
||||
this._panel.innerHTML = ``;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +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");
|
||||
this._fastButton = new PanelButton(this._panel, "fa-angle-double-right");
|
||||
this._descendButton = new PanelButton(this._panel, "fa-arrow-down");
|
||||
this._climbButton = new PanelButton(this._panel, "fa-arrow-up");
|
||||
this._repeatButton = new PanelButton(this._panel, "fa-undo");
|
||||
|
||||
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'));
|
||||
}
|
||||
|
||||
enableButtons(enableAltitudeButtons)
|
||||
{
|
||||
this._moveButton.setEnabled(true);
|
||||
this._stopButton.setEnabled(true);
|
||||
this._slowButton.setEnabled(true);
|
||||
this._fastButton.setEnabled(true);
|
||||
if (enableAltitudeButtons)
|
||||
{
|
||||
this._descendButton.setEnabled(true);
|
||||
this._climbButton.setEnabled(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
disableButtons()
|
||||
{
|
||||
this._moveButton.setEnabled(false);
|
||||
this._stopButton.setEnabled(false);
|
||||
this._slowButton.setEnabled(false);
|
||||
this._fastButton.setEnabled(false);
|
||||
this._descendButton.setEnabled(false);
|
||||
this._climbButton.setEnabled(false);
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ class Unit
|
||||
// The marker is set by the inherited class
|
||||
this.marker = marker;
|
||||
this.marker.on('click', (e) => this.onClick(e));
|
||||
this.marker.on('contextmenu', (e) => this.onRightClick(e));
|
||||
|
||||
this._selected = false;
|
||||
|
||||
@@ -18,6 +17,10 @@ class Unit
|
||||
this._pathPolyline.addTo(map.getMap());
|
||||
|
||||
this._targetsPolylines = [];
|
||||
|
||||
this.leader = true;
|
||||
this.wingmen = [];
|
||||
this.formation = undefined;
|
||||
}
|
||||
|
||||
update(response)
|
||||
@@ -37,6 +40,19 @@ class Unit
|
||||
this.speed = response["speed"];
|
||||
this.currentTask = response["currentTask"];
|
||||
|
||||
this.leader = response["leader"];
|
||||
this.wingman = response["wingman"];
|
||||
|
||||
this.wingmen = [];
|
||||
if (response["wingmenIDs"] != undefined)
|
||||
{
|
||||
for (let ID of response["wingmenIDs"])
|
||||
{
|
||||
this.wingmen.push(unitsManager.getUnitByID(ID));
|
||||
}
|
||||
}
|
||||
this.formation = response["formation"];
|
||||
|
||||
this.missionData = missionData.getUnitData(this.ID)
|
||||
|
||||
this.setSelected(this.getSelected() & this.alive)
|
||||
@@ -113,22 +129,28 @@ class Unit
|
||||
|
||||
onClick(e)
|
||||
{
|
||||
if (!e.originalEvent.ctrlKey)
|
||||
if (map.getState() === 'IDLE' || map.getState() === 'MOVE_UNIT' || e.originalEvent.ctrlKey)
|
||||
{
|
||||
unitsManager.deselectAllUnits();
|
||||
if (!e.originalEvent.ctrlKey)
|
||||
{
|
||||
unitsManager.deselectAllUnits();
|
||||
}
|
||||
this.setSelected(true);
|
||||
}
|
||||
else if (map.getState() === 'ATTACK')
|
||||
{
|
||||
unitsManager.attackUnit(this.ID);
|
||||
}
|
||||
else if (map.getState() === 'FORMATION')
|
||||
{
|
||||
unitsManager.createFormation(this.ID);
|
||||
}
|
||||
this.setSelected(true);
|
||||
}
|
||||
|
||||
onRightClick(e)
|
||||
{
|
||||
unitsManager.onUnitRightClick(this.ID);
|
||||
}
|
||||
|
||||
drawMarker(settings)
|
||||
{
|
||||
// Hide the marker if disabled
|
||||
if ((settings === 'none' || (controlPanel.getSettings().deadAlive === "alive" && !this.alive)))
|
||||
if ((settings === 'none' || (settingsPanel.getSettings().deadAlive === "alive" && !this.alive)))
|
||||
{
|
||||
// Remove the marker if present
|
||||
if (map.getMap().hasLayer(this.marker))
|
||||
@@ -204,30 +226,32 @@ class Unit
|
||||
for (let index in this.missionData.targets[typeIndex])
|
||||
{
|
||||
var targetData = this.missionData.targets[typeIndex][index];
|
||||
var target = unitsManager.getUnit(targetData.object["id_"])
|
||||
var startLatLng = new L.LatLng(this.latitude, this.longitude)
|
||||
var endLatLng = new L.LatLng(target.latitude, target.longitude)
|
||||
|
||||
var color;
|
||||
if (typeIndex === "radar")
|
||||
{
|
||||
color = "#FFFF00";
|
||||
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 color;
|
||||
if (typeIndex === "radar")
|
||||
{
|
||||
color = "#FFFF00";
|
||||
}
|
||||
else if (typeIndex === "visual")
|
||||
{
|
||||
color = "#FF00FF";
|
||||
}
|
||||
else if (typeIndex === "rwr")
|
||||
{
|
||||
color = "#00FF00";
|
||||
}
|
||||
else
|
||||
{
|
||||
color = "#FFFFFF";
|
||||
}
|
||||
var targetPolyline = new L.Polyline([startLatLng, endLatLng], {color: color, weight: 3, opacity: 1, smoothFactor: 1});
|
||||
targetPolyline.addTo(map.getMap());
|
||||
this._targetsPolylines.push(targetPolyline)
|
||||
}
|
||||
else if (typeIndex === "visual")
|
||||
{
|
||||
color = "#FF00FF";
|
||||
}
|
||||
else if (typeIndex === "rwr")
|
||||
{
|
||||
color = "#00FF00";
|
||||
}
|
||||
else
|
||||
{
|
||||
color = "#FFFFFF";
|
||||
}
|
||||
var targetPolyline = new L.Polyline([startLatLng, endLatLng], {color: color, weight: 3, opacity: 1, smoothFactor: 1});
|
||||
targetPolyline.addTo(map.getMap());
|
||||
this._targetsPolylines.push(targetPolyline)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,7 +267,14 @@ class Unit
|
||||
attackUnit(targetID)
|
||||
{
|
||||
// Call DCS attackUnit function
|
||||
attackUnit(this.ID, targetID);
|
||||
if (this.ID != targetID)
|
||||
{
|
||||
attackUnit(this.ID, targetID);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: show a message
|
||||
}
|
||||
}
|
||||
|
||||
changeSpeed(speedChange)
|
||||
@@ -281,19 +312,55 @@ class Unit
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
setformation(formation)
|
||||
{
|
||||
// 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 + " formation change: " + formation);
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"ID": this.ID, "formation": formation}
|
||||
var data = {"setFormation": command}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
class AirUnit extends Unit
|
||||
{
|
||||
drawMarker()
|
||||
{
|
||||
if (this.flags.human)
|
||||
if (this.flags.Human)
|
||||
{
|
||||
super.drawMarker(controlPanel.getSettings().human);
|
||||
super.drawMarker(settingsPanel.getSettings().human);
|
||||
}
|
||||
else
|
||||
{
|
||||
super.drawMarker(controlPanel.getSettings().AI);
|
||||
super.drawMarker(settingsPanel.getSettings().AI);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -344,7 +411,7 @@ class GroundUnit extends Unit
|
||||
|
||||
drawMarker()
|
||||
{
|
||||
super.drawMarker(controlPanel.getSettings().AI);
|
||||
super.drawMarker(settingsPanel.getSettings().AI);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,7 +431,7 @@ class NavyUnit extends Unit
|
||||
|
||||
drawMarker()
|
||||
{
|
||||
super.drawMarker(controlPanel.getSettings().AI);
|
||||
super.drawMarker(settingsPanel.getSettings().AI);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,25 +439,20 @@ class Weapon extends Unit
|
||||
{
|
||||
constructor(ID, data)
|
||||
{
|
||||
// Weapons can not be selected
|
||||
self.selectable = false;
|
||||
super(ID, data);
|
||||
// Weapons can not be selected
|
||||
this.selectable = false;
|
||||
}
|
||||
|
||||
drawMarker()
|
||||
{
|
||||
super.drawMarker(controlPanel.getSettings().weapons);
|
||||
super.drawMarker(settingsPanel.getSettings().weapons);
|
||||
}
|
||||
|
||||
onClick(e)
|
||||
{
|
||||
// Weapons can not be clicked
|
||||
}
|
||||
|
||||
onRightClick(e)
|
||||
{
|
||||
// Weapons can not be clicked
|
||||
}
|
||||
}
|
||||
|
||||
class Missile extends Weapon
|
||||
@@ -25,7 +25,7 @@ L.Marker.UnitMarker = L.Marker.extend(
|
||||
</td>
|
||||
</tr>
|
||||
</table>`,
|
||||
className: 'unit-marker-icon'}); // Set the unit marker, className must be set to avoid white square
|
||||
className: 'action-cursor'}); // Set the unit marker, className must be set to avoid white square
|
||||
this.setIcon(icon);
|
||||
},
|
||||
|
||||
@@ -38,18 +38,6 @@ L.Marker.UnitMarker = L.Marker.extend(
|
||||
|
||||
this._icon.style.outline = "transparent"; // Removes the rectangular outline
|
||||
|
||||
// Set the unit name in the marker
|
||||
var unitNameDiv = this._icon.querySelector("#unitName");
|
||||
if (this.options.human)
|
||||
{
|
||||
unitNameDiv.innerHTML = `<i class="fas fa-user"></i> ${this.options.unitName}`;
|
||||
}
|
||||
else
|
||||
{
|
||||
unitNameDiv.innerHTML = `${this.options.unitName}`;
|
||||
}
|
||||
unitNameDiv.style.left = (-(unitNameDiv.offsetWidth - this._icon.querySelector("#icon-img").height) / 2) + "px";
|
||||
|
||||
// Set the unit name in the marker
|
||||
var nameDiv = this._icon.querySelector("#name");
|
||||
nameDiv.innerHTML = this.options.name;
|
||||
@@ -70,6 +58,7 @@ L.Marker.UnitMarker = L.Marker.extend(
|
||||
// If the unit is not alive it is drawn with darker colours
|
||||
setAlive: function(alive)
|
||||
{
|
||||
this.alive = alive
|
||||
var table = this._icon.querySelector("#container-table");
|
||||
if (alive)
|
||||
{
|
||||
@@ -114,7 +103,7 @@ L.Marker.UnitMarker = L.Marker.extend(
|
||||
}
|
||||
else
|
||||
{
|
||||
if (img.classList.contains("unitmarker-icon-img-hovered")) img.classList.remove("unitmarker-icon-img-hovered");
|
||||
img.classList.remove("unitmarker-icon-img-hovered");
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -151,8 +140,11 @@ L.Marker.UnitMarker = L.Marker.extend(
|
||||
|
||||
setLabelsVisibility(visibility)
|
||||
{
|
||||
this._icon.querySelector("#unitName").style.opacity = visibility ? "1": "0";
|
||||
this._icon.querySelector("#unitName").innerHTML = visibility ? this.options.unitName : "";
|
||||
var unitNameDiv = this._icon.querySelector("#unitName");
|
||||
unitNameDiv.style.opacity = visibility ? "1": "0";
|
||||
var unitName = this.options.human ? `<i class="fas fa-user"></i> ${this.options.unitName}` : `${this.options.unitName}`;
|
||||
unitNameDiv.innerHTML = visibility ? unitName : "";
|
||||
unitNameDiv.style.left = (-(unitNameDiv.offsetWidth - this._icon.querySelector("#icon-img").height) / 2) + "px";
|
||||
//this._icon.querySelector("#name").style.opacity = visibility ? "1": "0";
|
||||
//this._icon.querySelector("#name").innerHTML = visibility ? this.options.name : "";
|
||||
this._icon.querySelector("#altitude-div").style.opacity = visibility ? "1": "0";
|
||||
@@ -225,8 +217,9 @@ L.Marker.UnitMarker.WeaponMarker = L.Marker.UnitMarker.extend({})
|
||||
L.Marker.UnitMarker.WeaponMarker.addInitHook(function()
|
||||
{
|
||||
// Weapons are not selectable
|
||||
this.on('mouseover', function(e) {});
|
||||
this.on('mouseout', function(e) {});
|
||||
this.on('mouseover', function(e) {
|
||||
e.target.setHovered(false);
|
||||
});
|
||||
});
|
||||
|
||||
// Missile
|
||||
@@ -3,6 +3,7 @@ class UnitsManager
|
||||
constructor()
|
||||
{
|
||||
this._units = {};
|
||||
this._copiedUnits = [];
|
||||
}
|
||||
|
||||
addUnit(ID, data)
|
||||
@@ -15,7 +16,7 @@ class UnitsManager
|
||||
}
|
||||
}
|
||||
|
||||
getUnit(ID)
|
||||
getUnitByID(ID)
|
||||
{
|
||||
return this._units[ID];
|
||||
}
|
||||
@@ -50,22 +51,15 @@ class UnitsManager
|
||||
{
|
||||
if (this.getSelectedUnits().length > 0)
|
||||
{
|
||||
map.setState("UNIT_SELECTED");
|
||||
unitControlPanel.enableButtons(true);
|
||||
map.setState("MOVE_UNIT");
|
||||
unitControlPanel.setEnabled(true);
|
||||
actionPanel.setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
map.setState("IDLE");
|
||||
unitControlPanel.disableButtons();
|
||||
}
|
||||
}
|
||||
|
||||
onUnitRightClick(ID)
|
||||
{
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits)
|
||||
{
|
||||
selectedUnits[idx].attackUnit(ID);
|
||||
unitControlPanel.setEnabled(false);
|
||||
actionPanel.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,4 +129,102 @@ class UnitsManager
|
||||
selectedUnits[idx].changeAltitude(altitudeChange);
|
||||
}
|
||||
}
|
||||
|
||||
handleKeyEvent(e)
|
||||
{
|
||||
if (e.originalEvent.code === 'KeyC' && e.originalEvent.ctrlKey)
|
||||
{
|
||||
this.copyUnits();
|
||||
}
|
||||
else if (e.originalEvent.code === 'KeyV' && e.originalEvent.ctrlKey)
|
||||
{
|
||||
this.pasteUnits();
|
||||
}
|
||||
}
|
||||
|
||||
copyUnits()
|
||||
{
|
||||
this._copiedUnits = this.getSelectedUnits();
|
||||
}
|
||||
|
||||
pasteUnits()
|
||||
{
|
||||
for (let idx in this._copiedUnits)
|
||||
{
|
||||
var unit = this._copiedUnits[idx];
|
||||
cloneUnit(unit.ID);
|
||||
}
|
||||
}
|
||||
|
||||
attackUnit(ID)
|
||||
{
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits)
|
||||
{
|
||||
selectedUnits[idx].attackUnit(ID);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
getUnitsByFormationID(formationID)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (unit.leader)
|
||||
{
|
||||
return unit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -206,68 +206,70 @@ unitTypes.vehicles.Unarmed = [
|
||||
]
|
||||
|
||||
/* AIRPLANES */
|
||||
unitTypes.air = [
|
||||
"Tornado GR4",
|
||||
"Tornado IDS",
|
||||
"F/A-18A",
|
||||
unitTypes.air = {}
|
||||
|
||||
unitTypes.air.CAP = [
|
||||
"F-4E",
|
||||
"F/A-18C",
|
||||
"MiG-29S",
|
||||
"MiG-29A",
|
||||
"F-14A",
|
||||
"Tu-22M3",
|
||||
"F-4E",
|
||||
"B-52H",
|
||||
"MiG-27K",
|
||||
"F-111F",
|
||||
"A-10A",
|
||||
"Su-27",
|
||||
"MiG-29G",
|
||||
"MiG-23MLD",
|
||||
"Su-25",
|
||||
"Su-25TM",
|
||||
"Su-25T",
|
||||
"Su-33",
|
||||
"MiG-25PD",
|
||||
"MiG-25RBT",
|
||||
"Su-30",
|
||||
"MiG-31",
|
||||
"Mirage 2000-5",
|
||||
"F-15C",
|
||||
"F-5E",
|
||||
"F-16C bl.52d",
|
||||
]
|
||||
|
||||
unitTypes.air.CAS = [
|
||||
"Tornado IDS",
|
||||
"F-4E",
|
||||
"F/A-18C",
|
||||
"MiG-27K",
|
||||
"A-10C",
|
||||
"Su-25",
|
||||
"Su-34",
|
||||
"Su-17M4",
|
||||
"MiG-31",
|
||||
"F-15E",
|
||||
]
|
||||
|
||||
unitTypes.air.strike = [
|
||||
"Tu-22M3",
|
||||
"B-52H",
|
||||
"F-111F",
|
||||
"Tu-95MS",
|
||||
"Su-24M",
|
||||
"Tu-160",
|
||||
"F-117A",
|
||||
"B-1B",
|
||||
"S-3B",
|
||||
"S-3B Tanker",
|
||||
"Mirage 2000-5",
|
||||
"F-15C",
|
||||
"F-15E",
|
||||
"F-5E",
|
||||
"MiG-29K",
|
||||
"Tu-142",
|
||||
]
|
||||
|
||||
unitTypes.air.tank = [
|
||||
"S-3B Tanker",
|
||||
"KC-135",
|
||||
"IL-78M",
|
||||
]
|
||||
|
||||
unitTypes.air.awacs = [
|
||||
"A-50",
|
||||
"E-3A",
|
||||
"E-2D",
|
||||
]
|
||||
|
||||
unitTypes.air.drone = [
|
||||
"MQ-1A Predator",
|
||||
"MQ-9 Reaper",
|
||||
]
|
||||
|
||||
unitTypes.air.transport = [
|
||||
"C-130",
|
||||
"An-26B",
|
||||
"An-30M",
|
||||
"C-17A",
|
||||
"A-50",
|
||||
"E-3A",
|
||||
"IL-78M",
|
||||
"E-2D",
|
||||
"IL-76MD",
|
||||
"F-16C bl.50",
|
||||
"F-16C bl.52d",
|
||||
"Su-24MR",
|
||||
"F-16A",
|
||||
"F-16A MLU",
|
||||
"MQ-1A Predator",
|
||||
"Yak-40",
|
||||
"A-10C",
|
||||
"KC-135",
|
||||
"L-39ZA",
|
||||
"P-51D",
|
||||
"MQ-9 Reaper",
|
||||
"FW-190D9",
|
||||
"TF-51D"
|
||||
]
|
||||
|
||||
]
|
||||
@@ -1,8 +1,10 @@
|
||||
var missionData;
|
||||
var controlPanel;
|
||||
var settingsPanel;
|
||||
var unitsManager;
|
||||
var unitInfoPanel;
|
||||
var unitControlPanel;
|
||||
var unitActionPanel;
|
||||
var formationControlPanel;
|
||||
var map;
|
||||
var RESTaddress = "http://localhost:30000/restdemo";
|
||||
|
||||
@@ -12,10 +14,11 @@ function setup()
|
||||
missionData = new MissionData();
|
||||
unitsManager = new UnitsManager();
|
||||
|
||||
unitInfoPanel = new UnitInfoPanel("left-panel");
|
||||
unitControlPanel = new UnitControlPanel("top-panel");
|
||||
controlPanel = new ControlPanel("top-control-panel");
|
||||
|
||||
unitInfoPanel = new UnitInfoPanel("unit-info-panel");
|
||||
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();
|
||||
|
||||
// Main update rate. 250ms is minimum time, equal to server update time.
|
||||
@@ -26,7 +29,9 @@ function resize()
|
||||
{
|
||||
var unitControlPanelHeight = document.getElementById("header").offsetHeight;
|
||||
document.getElementById("map").style.height = `${window.innerHeight - unitControlPanelHeight - 10}px`;
|
||||
document.getElementById("top-panel").style.left = `${window.innerWidth / 2 - document.getElementById("top-panel").offsetWidth / 2}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`
|
||||
}
|
||||
|
||||
/* GET new data from the server */
|
||||
@@ -42,6 +47,7 @@ function update()
|
||||
missionData.update(data);
|
||||
unitsManager.update(data);
|
||||
unitInfoPanel.update(unitsManager.getSelectedUnits());
|
||||
formationControlPanel.update(unitsManager.getSelectedUnits());
|
||||
};
|
||||
|
||||
xmlHttp.onerror = function () {
|
||||
@@ -77,4 +83,18 @@ window.console = {
|
||||
},
|
||||
|
||||
lastMessage: "none"
|
||||
}
|
||||
|
||||
function showMessage(message)
|
||||
{
|
||||
// Get the snackbar DIV
|
||||
var x = document.getElementById("snackbar");
|
||||
|
||||
// Add the "show" class to DIV
|
||||
x.className = "show";
|
||||
x.innerHTML = message;
|
||||
|
||||
// After 3 seconds, remove the show class from DIV
|
||||
setTimeout(function(){ x.className = x.className.replace("show", ""); }, 3000);
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
python -m http.server
|
||||
11
www/tsconfig.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"allowJs": true,
|
||||
"target": "es5"
|
||||
},
|
||||
"include": [
|
||||
"./js/*",
|
||||
"./js/**/*"
|
||||
]
|
||||
}
|
||||