mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Continue migration to node express typescript
This commit is contained in:
1
client/src/units/payloadNames.ts
Normal file
1
client/src/units/payloadNames.ts
Normal file
File diff suppressed because one or more lines are too long
512
client/src/units/unit.ts
Normal file
512
client/src/units/unit.ts
Normal file
@@ -0,0 +1,512 @@
|
||||
import { Marker, LatLng, Polyline } from 'leaflet';
|
||||
import { ConvertDDToDMS } from '../other/utils';
|
||||
import { getMap, getUnitsManager } from '..';
|
||||
import { UnitMarker, MarkerOptions } from './unitmarker';
|
||||
import { addDestination } from '../dcs/dcs';
|
||||
//import { attackUnit } from 'DCS/DCSCommands.js'
|
||||
|
||||
export class Unit
|
||||
{
|
||||
ID : number;
|
||||
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 : Object | null;
|
||||
flags : Object | null;
|
||||
activePath : any | null; // TODO: declare inteface
|
||||
missionData : Object | null;
|
||||
|
||||
#selectable : boolean;
|
||||
#selected : boolean;
|
||||
#preventClick : boolean;
|
||||
#pathMarkers : Marker[];
|
||||
#pathPolyline : Polyline;
|
||||
#targetsPolylines : Polyline[];
|
||||
#marker : UnitMarker;
|
||||
#timer : number;
|
||||
|
||||
static getConstructor(name: string)
|
||||
{
|
||||
if (name === "GroundUnit") return GroundUnit;
|
||||
if (name === "Aircraft") return Aircraft;
|
||||
if (name === "Helicopter") return Helicopter;
|
||||
if (name === "Missile") return Missile;
|
||||
if (name === "Bomb") return Bomb;
|
||||
if (name === "NavyUnit") return NavyUnit;
|
||||
}
|
||||
|
||||
constructor(ID: number, marker: UnitMarker)
|
||||
{
|
||||
this.ID = ID;
|
||||
|
||||
/* Names */
|
||||
this.name = "";
|
||||
this.unitName = "";
|
||||
this.groupName = "";
|
||||
|
||||
/* Position and speed */
|
||||
this.latitude = 0;
|
||||
this.longitude = 0;
|
||||
this.altitude = 0;
|
||||
this.heading = 0;
|
||||
this.speed = 0;
|
||||
|
||||
/* Tasking */
|
||||
this.coalitionID = 0;
|
||||
this.alive = true;
|
||||
this.currentTask = "";
|
||||
|
||||
/* Formation */
|
||||
this.leader = false;
|
||||
this.wingman = false;
|
||||
this.wingmen = [];
|
||||
this.formation = "";
|
||||
|
||||
/* Structures */
|
||||
this.type = null;
|
||||
this.flags = null;
|
||||
this.activePath = null;
|
||||
this.missionData = null;
|
||||
|
||||
this.#selectable = true;
|
||||
this.#timer = 0;
|
||||
|
||||
/* The marker is set by the inherited class */
|
||||
this.#marker = marker;
|
||||
this.#marker.on('click', (e) => this.#onClick(e));
|
||||
//this.#marker.on('dblclick', (e) => this.#onDoubleClick(e));
|
||||
|
||||
this.#selected = false;
|
||||
this.#preventClick = false;
|
||||
this.#pathMarkers = [];
|
||||
this.#pathPolyline = new Polyline([], {color: '#2d3e50', weight: 3, opacity: 0.5, smoothFactor: 1});
|
||||
this.#pathPolyline.addTo(getMap());
|
||||
this.#targetsPolylines = [];
|
||||
}
|
||||
|
||||
update(response: JSON)
|
||||
{
|
||||
for (let entry in response)
|
||||
{
|
||||
// @ts-ignore
|
||||
this[entry] = response[entry];
|
||||
}
|
||||
|
||||
this.#updateMarker();
|
||||
|
||||
if (this.getSelected())
|
||||
this.#drawPath();
|
||||
else
|
||||
this.#clearPath();
|
||||
|
||||
/*
|
||||
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)
|
||||
|
||||
|
||||
|
||||
this.clearTargets();
|
||||
this.missionData = missionData.getUnitData(this.ID);
|
||||
if (this.missionData != undefined)
|
||||
{
|
||||
if (this.getSelected())
|
||||
{
|
||||
this.drawTargets();
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
setSelected(selected: boolean)
|
||||
{
|
||||
// Only alive units can be selected. Some units are not selectable (weapons)
|
||||
if ((this.alive || !selected) && this.#selectable && this.#selected != selected)
|
||||
{
|
||||
this.#selected = selected;
|
||||
this.#marker.setSelected(selected);
|
||||
getUnitsManager().onUnitSelection();
|
||||
}
|
||||
}
|
||||
|
||||
getSelected()
|
||||
{
|
||||
return this.#selected;
|
||||
}
|
||||
|
||||
addDestination(latlng: L.LatLng)
|
||||
{
|
||||
var path: any = {};
|
||||
if (this.activePath != undefined)
|
||||
{
|
||||
path = this.activePath;
|
||||
path[(Object.keys(path).length + 1).toString()] = latlng;
|
||||
}
|
||||
else
|
||||
{
|
||||
path = {"1": latlng};
|
||||
}
|
||||
addDestination
|
||||
}
|
||||
|
||||
clearDestinations()
|
||||
{
|
||||
this.activePath = undefined;
|
||||
}
|
||||
|
||||
#onClick(e: any)
|
||||
{
|
||||
this.#timer = setTimeout(() => {
|
||||
if (!this.#preventClick) {
|
||||
if (getMap().getState() === 'IDLE' || getMap().getState() === 'MOVE_UNIT' || e.originalEvent.ctrlKey)
|
||||
{
|
||||
if (!e.originalEvent.ctrlKey)
|
||||
{
|
||||
getUnitsManager().deselectAllUnits();
|
||||
}
|
||||
this.setSelected(true);
|
||||
}
|
||||
}
|
||||
this.#preventClick = false;
|
||||
}, 200);
|
||||
}
|
||||
|
||||
#updateMarker()
|
||||
{
|
||||
/* Add the marker if not present */
|
||||
if (!getMap().hasLayer(this.#marker))
|
||||
{
|
||||
this.#marker.addTo(getMap());
|
||||
}
|
||||
|
||||
this.#marker.setLatLng(new LatLng(this.latitude, this.longitude));
|
||||
this.#marker.draw({
|
||||
heading: this.heading,
|
||||
speed: this.speed,
|
||||
altitude: this.altitude,
|
||||
alive: this.alive
|
||||
});
|
||||
}
|
||||
|
||||
#drawPath()
|
||||
{
|
||||
if (this.activePath != null)
|
||||
{
|
||||
var _points = [];
|
||||
_points.push(new LatLng(this.latitude, this.longitude));
|
||||
|
||||
// Add markers if missing
|
||||
while (this.#pathMarkers.length < Object.keys(this.activePath).length)
|
||||
{
|
||||
var marker = new Marker([0, 0]).addTo(getMap());
|
||||
this.#pathMarkers.push(marker);
|
||||
}
|
||||
|
||||
// Remove markers if too many
|
||||
while (this.#pathMarkers.length > Object.keys(this.activePath).length)
|
||||
{
|
||||
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 LatLng(destination.lat, destination.lng));
|
||||
this.#pathPolyline.setLatLngs(_points);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#clearPath()
|
||||
{
|
||||
for (let WP in this.#pathMarkers)
|
||||
{
|
||||
getMap().removeLayer(this.#pathMarkers[WP]);
|
||||
}
|
||||
this.#pathMarkers = [];
|
||||
this.#pathPolyline.setLatLngs([]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
#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)
|
||||
{
|
||||
options.push({'tooltip': 'Create formation', 'src': 'formation.png', 'callback': () => {map.removeSelectionWheel(); unitsManager.createFormation(this.ID);}});
|
||||
}
|
||||
|
||||
map.showSelectionWheel(e, options, false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
drawPath()
|
||||
{
|
||||
var _points = [];
|
||||
_points.push(new LatLng(this.latitude, this.longitude));
|
||||
|
||||
// Add markers if missing
|
||||
while (this.#pathMarkers.length < Object.keys(this.activePath).length)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 LatLng(destination.lat, destination.lng));
|
||||
this.#pathPolyline.setLatLngs(_points);
|
||||
}
|
||||
}
|
||||
|
||||
clearPath()
|
||||
{
|
||||
for (let WP in this.#pathMarkers)
|
||||
{
|
||||
map.getMap().removeLayer(this.#pathMarkers[WP]);
|
||||
}
|
||||
this.#pathMarkers = [];
|
||||
this.#pathPolyline.setLatLngs([]);
|
||||
}
|
||||
|
||||
drawTargets()
|
||||
{
|
||||
for (let typeIndex in this.missionData['targets'])
|
||||
{
|
||||
for (let index in this.missionData['targets'][typeIndex])
|
||||
{
|
||||
var targetData = this.missionData['targets'][typeIndex][index];
|
||||
var target = unitsManager.getUnitByID(targetData.object["id_"])
|
||||
if (target != undefined){
|
||||
var startLatLng = new LatLng(this.latitude, this.longitude)
|
||||
var endLatLng = new 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 Polyline([startLatLng, endLatLng], {color: color, weight: 3, opacity: 1, smoothFactor: 1});
|
||||
targetPolyline.addTo(map.getMap());
|
||||
this.#targetsPolylines.push(targetPolyline)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clearTargets()
|
||||
{
|
||||
for (let index in this.#targetsPolylines)
|
||||
{
|
||||
map.getMap().removeLayer(this.#targetsPolylines[index])
|
||||
}
|
||||
}
|
||||
|
||||
attackUnit(targetID)
|
||||
{
|
||||
// Call DCS attackUnit function
|
||||
if (this.ID != targetID)
|
||||
{
|
||||
attackUnit(this.ID, targetID);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: show a message
|
||||
}
|
||||
}
|
||||
|
||||
changeSpeed(speedChange)
|
||||
{
|
||||
// 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 + " speed change request: " + speedChange);
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"ID": this.ID, "change": speedChange}
|
||||
var data = {"changeSpeed": command}
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
changeAltitude(altitudeChange)
|
||||
{
|
||||
// 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 + " altitude change request: " + altitudeChange);
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"ID": this.ID, "change": altitudeChange}
|
||||
var data = {"changeAltitude": command}
|
||||
|
||||
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));
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
export class AirUnit extends Unit
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
export class Aircraft extends AirUnit
|
||||
{
|
||||
constructor(ID: number, options: MarkerOptions)
|
||||
{
|
||||
var marker = new UnitMarker(options);
|
||||
super(ID, marker);
|
||||
}
|
||||
}
|
||||
|
||||
export class Helicopter extends AirUnit
|
||||
{
|
||||
constructor(ID: number, options: MarkerOptions)
|
||||
{
|
||||
var marker = new UnitMarker(options);
|
||||
super(ID, marker);
|
||||
}
|
||||
}
|
||||
|
||||
export class GroundUnit extends Unit
|
||||
{
|
||||
constructor(ID: number, options: MarkerOptions)
|
||||
{
|
||||
var marker = new UnitMarker(options);
|
||||
super(ID, marker);
|
||||
}
|
||||
}
|
||||
|
||||
export class NavyUnit extends Unit
|
||||
{
|
||||
constructor(ID: number, options: MarkerOptions)
|
||||
{
|
||||
var marker = new UnitMarker(options);
|
||||
super(ID, marker);
|
||||
}
|
||||
}
|
||||
|
||||
export class Weapon extends Unit
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
export class Missile extends Weapon
|
||||
{
|
||||
constructor(ID: number, options: MarkerOptions)
|
||||
{
|
||||
var marker = new UnitMarker(options);
|
||||
super(ID, marker);
|
||||
}
|
||||
}
|
||||
|
||||
export class Bomb extends Weapon
|
||||
{
|
||||
constructor(ID: number, options: MarkerOptions)
|
||||
{
|
||||
var marker = new UnitMarker(options);
|
||||
super(ID, marker);
|
||||
}
|
||||
}
|
||||
276
client/src/units/unitTypes.ts
Normal file
276
client/src/units/unitTypes.ts
Normal file
@@ -0,0 +1,276 @@
|
||||
|
||||
|
||||
export var unitTypes: any = {};
|
||||
/* NAVY */
|
||||
unitTypes.navy = {};
|
||||
unitTypes.navy.blue = [
|
||||
"VINSON",
|
||||
"PERRY",
|
||||
"TICONDEROG"
|
||||
]
|
||||
|
||||
unitTypes.navy.red = [
|
||||
"ALBATROS",
|
||||
"KUZNECOW",
|
||||
"MOLNIYA",
|
||||
"MOSCOW",
|
||||
"NEUSTRASH",
|
||||
"PIOTR",
|
||||
"REZKY"
|
||||
]
|
||||
|
||||
unitTypes.navy.civil = [
|
||||
"ELNYA",
|
||||
"Dry-cargo ship-2",
|
||||
"Dry-cargo ship-1",
|
||||
"ZWEZDNY"
|
||||
]
|
||||
|
||||
unitTypes.navy.submarine = [
|
||||
"KILO",
|
||||
"SOM"
|
||||
]
|
||||
|
||||
unitTypes.navy.speedboat = [
|
||||
"speedboat"
|
||||
]
|
||||
|
||||
/* VEHICLES (GROUND) */
|
||||
unitTypes.vehicles = []
|
||||
unitTypes.vehicles.Howitzers = [
|
||||
"2B11 mortar",
|
||||
"SAU Gvozdika",
|
||||
"SAU Msta",
|
||||
"SAU Akatsia",
|
||||
"SAU 2-C9",
|
||||
"M-109"
|
||||
]
|
||||
|
||||
unitTypes.vehicles.IFV = [
|
||||
"AAV7",
|
||||
"BMD-1",
|
||||
"BMP-1",
|
||||
"BMP-2",
|
||||
"BMP-3",
|
||||
"Boman",
|
||||
"BRDM-2",
|
||||
"BTR-80",
|
||||
"BTR_D",
|
||||
"Bunker",
|
||||
"Cobra",
|
||||
"LAV-25",
|
||||
"M1043 HMMWV Armament",
|
||||
"M1045 HMMWV TOW",
|
||||
"M1126 Stryker ICV",
|
||||
"M-113",
|
||||
"M1134 Stryker ATGM",
|
||||
"M-2 Bradley",
|
||||
"Marder",
|
||||
"MCV-80",
|
||||
"MTLB",
|
||||
"Paratrooper RPG-16",
|
||||
"Paratrooper AKS-74",
|
||||
"Sandbox",
|
||||
"Soldier AK",
|
||||
"Infantry AK",
|
||||
"Soldier M249",
|
||||
"Soldier M4",
|
||||
"Soldier M4 GRG",
|
||||
"Soldier RPG",
|
||||
"TPZ"
|
||||
]
|
||||
|
||||
unitTypes.vehicles.MLRS = [
|
||||
"Grad-URAL",
|
||||
"Uragan_BM-27",
|
||||
"Smerch",
|
||||
"MLRS"
|
||||
]
|
||||
|
||||
unitTypes.vehicles.SAM = [
|
||||
"2S6 Tunguska",
|
||||
"Kub 2P25 ln",
|
||||
"5p73 s-125 ln",
|
||||
"S-300PS 5P85C ln",
|
||||
"S-300PS 5P85D ln",
|
||||
"SA-11 Buk LN 9A310M1",
|
||||
"Osa 9A33 ln",
|
||||
"Tor 9A331",
|
||||
"Strela-10M3",
|
||||
"Strela-1 9P31",
|
||||
"SA-11 Buk CC 9S470M1",
|
||||
"SA-8 Osa LD 9T217",
|
||||
"Patriot AMG",
|
||||
"Patriot ECS",
|
||||
"Gepard",
|
||||
"Hawk pcp",
|
||||
"SA-18 Igla manpad",
|
||||
"SA-18 Igla comm",
|
||||
"Igla manpad INS",
|
||||
"SA-18 Igla-S manpad",
|
||||
"SA-18 Igla-S comm",
|
||||
"Vulcan",
|
||||
"Hawk ln",
|
||||
"M48 Chaparral",
|
||||
"M6 Linebacker",
|
||||
"Patriot ln",
|
||||
"M1097 Avenger",
|
||||
"Patriot EPP",
|
||||
"Patriot cp",
|
||||
"Roland ADS",
|
||||
"S-300PS 54K6 cp",
|
||||
"Stinger manpad GRG",
|
||||
"Stinger manpad dsr",
|
||||
"Stinger comm dsr",
|
||||
"Stinger manpad",
|
||||
"Stinger comm",
|
||||
"ZSU-23-4 Shilka",
|
||||
"ZU-23 Emplacement Closed",
|
||||
"ZU-23 Emplacement",
|
||||
"ZU-23 Closed Insurgent",
|
||||
"Ural-375 ZU-23 Insurgent",
|
||||
"ZU-23 Insurgent",
|
||||
"Ural-375 ZU-23"
|
||||
]
|
||||
|
||||
unitTypes.vehicles.Radar = [
|
||||
"1L13 EWR",
|
||||
"Kub 1S91 str",
|
||||
"S-300PS 40B6M tr",
|
||||
"S-300PS 40B6MD sr",
|
||||
"55G6 EWR",
|
||||
"S-300PS 64H6E sr",
|
||||
"SA-11 Buk SR 9S18M1",
|
||||
"Dog Ear radar",
|
||||
"Hawk tr",
|
||||
"Hawk sr",
|
||||
"Patriot str",
|
||||
"Hawk cwar",
|
||||
"p-19 s-125 sr",
|
||||
"Roland Radar",
|
||||
"snr s-125 tr"
|
||||
]
|
||||
|
||||
unitTypes.vehicles.Structures = [
|
||||
"house1arm",
|
||||
"house2arm",
|
||||
"outpost_road",
|
||||
"outpost",
|
||||
"houseA_arm"
|
||||
]
|
||||
|
||||
unitTypes.vehicles.Tanks = [
|
||||
"Challenger2",
|
||||
"Leclerc",
|
||||
"Leopard1A3",
|
||||
"Leopard-2",
|
||||
"M-60",
|
||||
"M1128 Stryker MGS",
|
||||
"M-1 Abrams",
|
||||
"T-55",
|
||||
"T-72B",
|
||||
"T-80UD",
|
||||
"T-90"
|
||||
]
|
||||
|
||||
unitTypes.vehicles.Unarmed = [
|
||||
"Ural-4320 APA-5D",
|
||||
"ATMZ-5",
|
||||
"ATZ-10",
|
||||
"GAZ-3307",
|
||||
"GAZ-3308",
|
||||
"GAZ-66",
|
||||
"M978 HEMTT Tanker",
|
||||
"HEMTT TFFT",
|
||||
"IKARUS Bus",
|
||||
"KAMAZ Truck",
|
||||
"LAZ Bus",
|
||||
"Hummer",
|
||||
"M 818",
|
||||
"MAZ-6303",
|
||||
"Predator GCS",
|
||||
"Predator TrojanSpirit",
|
||||
"Suidae",
|
||||
"Tigr_233036",
|
||||
"Trolley bus",
|
||||
"UAZ-469",
|
||||
"Ural ATsP-6",
|
||||
"Ural-375 PBU",
|
||||
"Ural-375",
|
||||
"Ural-4320-31",
|
||||
"Ural-4320T",
|
||||
"VAZ Car",
|
||||
"ZiL-131 APA-80",
|
||||
"SKP-11",
|
||||
"ZIL-131 KUNG",
|
||||
"ZIL-4331"
|
||||
]
|
||||
|
||||
/* AIRPLANES */
|
||||
unitTypes.air = {}
|
||||
|
||||
unitTypes.air.CAP = [
|
||||
"F-4E",
|
||||
"F/A-18C",
|
||||
"MiG-29S",
|
||||
"F-14A",
|
||||
"Su-27",
|
||||
"MiG-23MLD",
|
||||
"Su-33",
|
||||
"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",
|
||||
"F-15E",
|
||||
]
|
||||
|
||||
unitTypes.air.strike = [
|
||||
"Tu-22M3",
|
||||
"B-52H",
|
||||
"F-111F",
|
||||
"Tu-95MS",
|
||||
"Su-24M",
|
||||
"Tu-160",
|
||||
"F-117A",
|
||||
"B-1B",
|
||||
"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",
|
||||
"IL-76MD",
|
||||
]
|
||||
147
client/src/units/unitmarker.ts
Normal file
147
client/src/units/unitmarker.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
import * as L from 'leaflet'
|
||||
import { Symbol } from 'milsymbol'
|
||||
|
||||
export interface MarkerOptions
|
||||
{
|
||||
unitName: string
|
||||
name: string
|
||||
human: boolean
|
||||
coalitionID: number
|
||||
type: any
|
||||
}
|
||||
|
||||
export interface MarkerData
|
||||
{
|
||||
heading: number
|
||||
speed: number
|
||||
altitude: number
|
||||
alive: boolean
|
||||
}
|
||||
|
||||
export class UnitMarker extends L.Marker
|
||||
{
|
||||
#unitName: string
|
||||
#name: string
|
||||
#human: boolean
|
||||
#coalitionID: number
|
||||
#alive: boolean
|
||||
|
||||
constructor(options: MarkerOptions)
|
||||
{
|
||||
super(new L.LatLng(0, 0), {riseOnHover: true});
|
||||
this.#unitName = options.unitName
|
||||
this.#name = options.name
|
||||
this.#human = options.human
|
||||
this.#coalitionID = options.coalitionID
|
||||
|
||||
this.#alive = true;
|
||||
|
||||
var symbol = new Symbol(this.#computeMarkerCode(options), {size: 100});
|
||||
var img = symbol.asCanvas().toDataURL('image/png');
|
||||
|
||||
var icon = new L.DivIcon({
|
||||
html: `<table class="unit-marker-container" id="container">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="unit-marker-icon" id="icon"><img src="${img}"></div>
|
||||
<div class="unit-marker-unitName" id="unitName">${this.#unitName}</div>
|
||||
<div class="unit-marker-altitude" id="altitude"></div>
|
||||
<div class="unit-marker-speed" id="speed"></div>
|
||||
<div class="unit-marker-name" id="name">${this.#name}</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>`,
|
||||
className: 'unit-marker'});
|
||||
this.setIcon(icon);
|
||||
}
|
||||
|
||||
onAdd(map: L.Map): this
|
||||
{
|
||||
super.onAdd(map);
|
||||
var element = <HTMLElement>this.getElement();
|
||||
this.addEventListener('mouseover', function(e: any) { e.target?.setHovered(true);});
|
||||
this.addEventListener('mouseout', function(e: any) { e.target?.setHovered(false);});
|
||||
return this
|
||||
}
|
||||
|
||||
draw(data: MarkerData)
|
||||
{
|
||||
var element = this.getElement();
|
||||
if (element != null)
|
||||
{
|
||||
var nameDiv = <HTMLElement>element.querySelector("#name");
|
||||
var unitNameDiv = <HTMLElement>element.querySelector("#unitName");
|
||||
var container = <HTMLElement>element.querySelector("#container");
|
||||
var icon = <HTMLElement>element.querySelector("#icon");
|
||||
var altitudeDiv = <HTMLElement>element.querySelector("#altitude");
|
||||
var speedDiv = <HTMLElement>element.querySelector("#speed");
|
||||
|
||||
nameDiv.style.left = (-(nameDiv.offsetWidth - container.offsetWidth) / 2) + "px";
|
||||
unitNameDiv.style.left = (-(unitNameDiv.offsetWidth - container.offsetWidth) / 2) + "px";
|
||||
|
||||
icon.style.transform = "rotate(" + data.heading + "rad)";
|
||||
altitudeDiv.innerHTML = String(Math.round(data.altitude / 0.3048 / 100) / 10);
|
||||
speedDiv.innerHTML = String(Math.round(data.speed * 1.94384));
|
||||
}
|
||||
}
|
||||
|
||||
setSelected(selected: boolean)
|
||||
{
|
||||
this.getElement()?.querySelector("#icon")?.classList.remove("unit-marker-hovered");
|
||||
this.getElement()?.querySelector("#icon")?.classList.toggle("unit-marker-selected", selected);
|
||||
}
|
||||
|
||||
setHovered(hovered: boolean)
|
||||
{
|
||||
this.getElement()?.querySelector("#icon")?.classList.toggle("unit-marker-hovered", hovered && this.#alive);
|
||||
}
|
||||
|
||||
#computeMarkerCode(options: MarkerOptions)
|
||||
{
|
||||
var identity = "00";
|
||||
var set = "00";
|
||||
var entity = "00";
|
||||
var entityType = "00";
|
||||
var entitySubtype = "00";
|
||||
|
||||
/* Identity */
|
||||
if (options.coalitionID == 1)
|
||||
identity = "06" /* Hostile */
|
||||
else if (options.coalitionID == 2)
|
||||
identity = "03" /* Friendly */
|
||||
else
|
||||
identity = "04" /* Neutral */
|
||||
|
||||
if (options.type.level1 == 1)
|
||||
{
|
||||
set = "01"
|
||||
entity = "11"
|
||||
if (options.type.level2 == 1)
|
||||
entityType = "01"
|
||||
else if (options.type.level2 == 1)
|
||||
entityType = "02"
|
||||
|
||||
if (options.type.level3 == 1)
|
||||
entitySubtype = "04";
|
||||
else if (options.type.level3 == 2)
|
||||
entitySubtype = "05";
|
||||
else if (options.type.level3 == 3)
|
||||
entitySubtype = "04";
|
||||
else if (options.type.level3 == 4)
|
||||
entitySubtype = "02";
|
||||
else if (options.type.level3 == 5)
|
||||
entitySubtype = "00";
|
||||
else if (options.type.level3 == 6)
|
||||
entitySubtype = "00";
|
||||
}
|
||||
else if (options.type.level1 == 2)
|
||||
set = "10"
|
||||
else if (options.type.level1 == 3)
|
||||
set = "30"
|
||||
else if (options.type.level1 == 2)
|
||||
set = "02"
|
||||
|
||||
|
||||
return `10${identity}${set}0000${entity}${entityType}${entitySubtype}0000`
|
||||
}
|
||||
}
|
||||
260
client/src/units/unitsmanager.ts
Normal file
260
client/src/units/unitsmanager.ts
Normal file
@@ -0,0 +1,260 @@
|
||||
import { getUnitInfoPanel } from "..";
|
||||
import { Unit, GroundUnit } from "./unit";
|
||||
|
||||
export class UnitsManager
|
||||
{
|
||||
#units: { [ID: number]: Unit};
|
||||
#copiedUnits: Unit[];
|
||||
|
||||
constructor()
|
||||
{
|
||||
this.#units = {};
|
||||
this.#copiedUnits = [];
|
||||
}
|
||||
|
||||
addUnit(ID: number, data: any)
|
||||
{
|
||||
// The name of the unit category is exactly the same as the constructor name
|
||||
var constructor = Unit.getConstructor(data.category);
|
||||
if (constructor != undefined)
|
||||
{
|
||||
var options = {
|
||||
unitName: data.unitName,
|
||||
name: data.name,
|
||||
human: data.human,
|
||||
coalitionID: data.coalitionID,
|
||||
type: data.type
|
||||
}
|
||||
this.#units[ID] = new constructor(ID, options);
|
||||
}
|
||||
}
|
||||
|
||||
getUnitByID(ID: number)
|
||||
{
|
||||
return this.#units[ID];
|
||||
}
|
||||
|
||||
removeUnit(ID: number)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
deselectAllUnits()
|
||||
{
|
||||
for (let ID in this.#units)
|
||||
{
|
||||
this.#units[ID].setSelected(false);
|
||||
}
|
||||
}
|
||||
|
||||
update(data: any)
|
||||
{
|
||||
for (let ID in data["units"])
|
||||
{
|
||||
// Create the unit if missing from the local array, then update the data. Drawing is handled by leaflet.
|
||||
if (!(ID in this.#units))
|
||||
{
|
||||
this.addUnit(parseInt(ID), data["units"][ID]);
|
||||
}
|
||||
this.#units[parseInt(ID)].update(data["units"][ID]);
|
||||
}
|
||||
|
||||
if (this.getSelectedUnits().length == 1)
|
||||
{
|
||||
getUnitInfoPanel().show();
|
||||
getUnitInfoPanel().update(this.getSelectedUnits()[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
getUnitInfoPanel().hide();
|
||||
}
|
||||
}
|
||||
|
||||
onUnitSelection()
|
||||
{
|
||||
//if (this.getSelectedUnits().length > 0)
|
||||
//{
|
||||
// map.setState("MOVE_UNIT");
|
||||
// unitControlPanel.setEnabled(true);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// map.setState("IDLE");
|
||||
// unitControlPanel.setEnabled(false);
|
||||
//}
|
||||
}
|
||||
|
||||
// selectFromBounds(bounds)
|
||||
// {
|
||||
// this.deselectAllUnits();
|
||||
// for (let ID in this.#units)
|
||||
// {
|
||||
// var latlng = new LatLng(this.#units[ID].latitude, this.#units[ID].longitude);
|
||||
// if (bounds.contains(latlng))
|
||||
// {
|
||||
// this.#units[ID].setSelected(true);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
getSelectedUnits()
|
||||
{
|
||||
var selectedUnits = [];
|
||||
for (let ID in this.#units)
|
||||
{
|
||||
if (this.#units[ID].getSelected())
|
||||
{
|
||||
selectedUnits.push(this.#units[ID]);
|
||||
}
|
||||
}
|
||||
return selectedUnits;
|
||||
}
|
||||
|
||||
// addDestination(latlng)
|
||||
// {
|
||||
// var selectedUnits = this.getSelectedUnits();
|
||||
// for (let idx in selectedUnits)
|
||||
// {
|
||||
// var commandedUnit = selectedUnits[idx];
|
||||
// if (selectedUnits[idx].wingman)
|
||||
// {
|
||||
// commandedUnit = this.getLeader(selectedUnits[idx].ID);
|
||||
// }
|
||||
// commandedUnit.addDestination(latlng);
|
||||
// }
|
||||
// }
|
||||
|
||||
// clearDestinations()
|
||||
// {
|
||||
// var selectedUnits = this.getSelectedUnits();
|
||||
// for (let idx in selectedUnits)
|
||||
// {
|
||||
// var commandedUnit = selectedUnits[idx];
|
||||
// if (selectedUnits[idx].wingman)
|
||||
// {
|
||||
// commandedUnit = this.getLeader(selectedUnits[idx].ID);
|
||||
// }
|
||||
// commandedUnit.clearDestinations();
|
||||
// }
|
||||
// }
|
||||
|
||||
// selectedUnitsMove()
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
// selectedUnitsChangeSpeed(speedChange)
|
||||
// {
|
||||
// var selectedUnits = this.getSelectedUnits();
|
||||
// for (let idx in selectedUnits)
|
||||
// {
|
||||
// selectedUnits[idx].changeSpeed(speedChange);
|
||||
// }
|
||||
// }
|
||||
|
||||
// selectedUnitsChangeAltitude(altitudeChange)
|
||||
// {
|
||||
// var selectedUnits = this.getSelectedUnits();
|
||||
// for (let idx in selectedUnits)
|
||||
// {
|
||||
// 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)
|
||||
// {
|
||||
// // 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);
|
||||
// }
|
||||
// }
|
||||
|
||||
// createFormation(ID)
|
||||
// {
|
||||
// var selectedUnits = this.getSelectedUnits();
|
||||
// var wingmenIDs = [];
|
||||
// for (let idx in selectedUnits)
|
||||
// {
|
||||
// if (selectedUnits[idx].wingman)
|
||||
// {
|
||||
// showMessage(selectedUnits[idx].unitName + " is already in a formation.");
|
||||
// return;
|
||||
// }
|
||||
// else if (selectedUnits[idx].leader)
|
||||
// {
|
||||
// showMessage(selectedUnits[idx].unitName + " is already in a formation.");
|
||||
// return;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// /* TODO
|
||||
// if (selectedUnits[idx].category !== this.getUnitByID(ID).category)
|
||||
// {
|
||||
// showMessage("All units must be of the same category to create a formation.");
|
||||
// }
|
||||
// */
|
||||
// if (selectedUnits[idx].ID != ID)
|
||||
// {
|
||||
// wingmenIDs.push(selectedUnits[idx].ID);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (wingmenIDs.length > 0)
|
||||
// {
|
||||
// this.getUnitByID(ID).setLeader(wingmenIDs);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// showMessage("At least 2 units must be selected to create a formation.");
|
||||
// }
|
||||
// }
|
||||
|
||||
// getLeader(ID)
|
||||
// {
|
||||
// for (let idx in this.#units)
|
||||
// {
|
||||
// var unit = this.#units[idx];
|
||||
// if (unit.leader)
|
||||
// {
|
||||
// if (unit.wingmen.includes(this.getUnitByID(ID)))
|
||||
// {
|
||||
// return unit;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// showMessage("Error: no leader found for this unit")
|
||||
// }
|
||||
}
|
||||
Reference in New Issue
Block a user