mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Better unitmarker.ts integration. Added scheduler load divider. Rationalized units.ts and added interfaces (to be completed)
This commit is contained in:
parent
236523ee2b
commit
c5a1b00cfd
@ -2,6 +2,9 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Olympus UI Kit</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;600&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" type="text/css" href="stylesheets/olympus.css" />
|
||||
<link rel="stylesheet" type="text/css" href="stylesheets/uikit.css" />
|
||||
</head>
|
||||
|
||||
6
client/src/@types/server.d.ts
vendored
Normal file
6
client/src/@types/server.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
interface ServerData {
|
||||
units: {[key: string]: UnitData},
|
||||
bullseye: any, //TODO
|
||||
airbases: any, //TODO
|
||||
logs: any //TODO
|
||||
}
|
||||
52
client/src/@types/unit.d.ts
vendored
Normal file
52
client/src/@types/unit.d.ts
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
interface FlightData {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
altitude: number;
|
||||
heading: number;
|
||||
speed: number;
|
||||
}
|
||||
|
||||
interface MissionData {
|
||||
fuel: number;
|
||||
flags: any;
|
||||
ammo: any;
|
||||
targets: any;
|
||||
hasTask: boolean;
|
||||
coalition: string;
|
||||
}
|
||||
|
||||
interface FormationData {
|
||||
formation: string;
|
||||
isLeader: boolean;
|
||||
isWingman: boolean;
|
||||
leaderID: number;
|
||||
wingmen: Unit[];
|
||||
wingmenIDs: number[];
|
||||
}
|
||||
|
||||
interface TaskData {
|
||||
currentTask: string;
|
||||
activePath: any;
|
||||
targetSpeed: number;
|
||||
targetAltitude: number;
|
||||
}
|
||||
|
||||
interface OptionsData {
|
||||
ROE: string;
|
||||
reactionToThreat: string;
|
||||
}
|
||||
|
||||
interface UnitData {
|
||||
AI: boolean;
|
||||
name: string;
|
||||
unitName: string;
|
||||
groupName: string;
|
||||
alive: boolean;
|
||||
category: string;
|
||||
|
||||
flightData: FlightData;
|
||||
missionData: MissionData;
|
||||
formationData: FormationData;
|
||||
taskData: TaskData;
|
||||
optionsData: OptionsData;
|
||||
}
|
||||
@ -1,260 +0,0 @@
|
||||
import * as L from 'leaflet'
|
||||
import { getUnitsManager, setConnected } from '..';
|
||||
import { ConvertDDToDMS } from '../other/utils';
|
||||
|
||||
/* Edit here to change server address */
|
||||
var RESTaddress = "http://localhost:30000/restdemo";
|
||||
|
||||
export function getDataFromDCS(callback: CallableFunction) {
|
||||
/* Request the updated unit data from the server */
|
||||
var xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.open("GET", RESTaddress, true);
|
||||
|
||||
xmlHttp.onload = function (e) {
|
||||
var data = JSON.parse(xmlHttp.responseText);
|
||||
callback(data);
|
||||
setConnected(true);
|
||||
};
|
||||
|
||||
xmlHttp.onerror = function () {
|
||||
console.error("An error occurred during the XMLHttpRequest");
|
||||
setConnected(false);
|
||||
};
|
||||
xmlHttp.send(null);
|
||||
}
|
||||
|
||||
export function addDestination(ID: number, path: any) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => { };
|
||||
|
||||
var command = { "ID": ID, "path": path }
|
||||
var data = { "setPath": command }
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function spawnSmoke(color: string, latlng: L.LatLng) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
//console.log("Added " + color + " smoke at " + ConvertDDToDMS(latlng.lat, false) + " " + ConvertDDToDMS(latlng.lng, true));
|
||||
}
|
||||
};
|
||||
|
||||
var command = { "color": color, "location": latlng };
|
||||
var data = { "smoke": command }
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function spawnGroundUnit(type: string, latlng: L.LatLng, coalition: string) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
//console.log("Added " + coalition + " " + type + " at " + ConvertDDToDMS(latlng.lat, false) + " " + ConvertDDToDMS(latlng.lng, true));
|
||||
}
|
||||
};
|
||||
|
||||
var command = { "type": type, "location": latlng, "coalition": coalition };
|
||||
var data = { "spawnGround": command }
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function spawnAircraft(type: string, latlng: L.LatLng, coalition: string, payloadName: string | null = null, airbaseName: string | null = null) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
//console.log("Added " + coalition + " " + type + " at " + ConvertDDToDMS(latlng.lat, false) + " " + ConvertDDToDMS(latlng.lng, true));
|
||||
}
|
||||
};
|
||||
|
||||
var command = { "type": type, "location": latlng, "coalition": coalition, "payloadName": payloadName != null? payloadName: "", "airbaseName": airbaseName != null? airbaseName: ""};
|
||||
var data = { "spawnAir": command }
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function attackUnit(ID: number, targetID: number) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
//console.log("Unit " + getUnitsManager().getUnitByID(ID).unitName + " attack " + getUnitsManager().getUnitByID(targetID).unitName);
|
||||
}
|
||||
};
|
||||
|
||||
var command = { "ID": ID, "targetID": targetID };
|
||||
var data = { "attackUnit": command }
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function cloneUnit(ID: number, latlng: L.LatLng) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
//console.log("Unit " + getUnitsManager().getUnitByID(ID).unitName + " cloned");
|
||||
}
|
||||
};
|
||||
|
||||
var command = { "ID": ID, "location": latlng };
|
||||
var data = { "cloneUnit": command }
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function deleteUnit(ID: number) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
//console.log("Unit " + getUnitsManager().getUnitByID(ID).unitName + " cloned");
|
||||
}
|
||||
};
|
||||
|
||||
var command = { "ID": ID};
|
||||
var data = { "deleteUnit": command }
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function landAt(ID: number, latlng: L.LatLng) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
//console.log("Unit " + getUnitsManager().getUnitByID(ID).unitName + " cloned");
|
||||
}
|
||||
};
|
||||
|
||||
var command = { "ID": ID, "location": latlng };
|
||||
var data = { "landAt": command }
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function changeSpeed(ID: number, speedChange: string) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
//console.log(getUnitsManager().getUnitByID(ID).unitName + " speed change request: " + speedChange);
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"ID": ID, "change": speedChange}
|
||||
var data = {"changeSpeed": command}
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function setSpeed(ID: number, speed: number) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
//console.log(getUnitsManager().getUnitByID(ID).unitName + " speed change request: " + speedChange);
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"ID": ID, "speed": speed}
|
||||
var data = {"setSpeed": command}
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function changeAltitude(ID: number, altitudeChange: string) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
//console.log(getUnitsManager().getUnitByID(ID).unitName + " altitude change request: " + altitudeChange);
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"ID": ID, "change": altitudeChange}
|
||||
var data = {"changeAltitude": command}
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function setAltitude(ID: number, altitude: number) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
//console.log(getUnitsManager().getUnitByID(ID).unitName + " speed change request: " + speedChange);
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"ID": ID, "altitude": altitude}
|
||||
var data = {"setAltitude": command}
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function createFormation(ID: number, isLeader: boolean, wingmenIDs: number[]) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
//console.log(getUnitsManager().getUnitByID(ID).unitName + " created formation with: " + wingmenIDs);
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"ID": ID, "wingmenIDs": wingmenIDs, "isLeader": isLeader}
|
||||
var data = {"setLeader": command}
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function setROE(ID: number, ROE: string) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
//console.log(getUnitsManager().getUnitByID(ID).unitName + " speed change request: " + speedChange);
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"ID": ID, "ROE": ROE}
|
||||
var data = {"setROE": command}
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
|
||||
export function setReactionToThreat(ID: number, reactionToThreat: string) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("PUT", RESTaddress);
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4) {
|
||||
//console.log(getUnitsManager().getUnitByID(ID).unitName + " speed change request: " + speedChange);
|
||||
}
|
||||
};
|
||||
|
||||
var command = {"ID": ID, "reactionToThreat": reactionToThreat}
|
||||
var data = {"setReactionToThreat": command}
|
||||
|
||||
xhr.send(JSON.stringify(data));
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
import { Map } from "./map/map"
|
||||
import { getDataFromDCS } from "./dcs/dcs"
|
||||
import { getDataFromDCS } from "./server/server"
|
||||
import { UnitsManager } from "./units/unitsmanager";
|
||||
import { UnitInfoPanel } from "./panels/unitinfopanel";
|
||||
import { ContextMenu } from "./controls/contextmenu";
|
||||
@ -39,9 +39,6 @@ var aicHelpButton: Button;
|
||||
var atc: ATC;
|
||||
var atcToggleButton: Button;
|
||||
|
||||
var altitudeSlider: Slider;
|
||||
var airspeedSlider: Slider;
|
||||
|
||||
var connected: boolean;
|
||||
var activeCoalition: string;
|
||||
|
||||
@ -132,7 +129,7 @@ function requestUpdate() {
|
||||
connectionStatusPanel.update(getConnected());
|
||||
}
|
||||
|
||||
export function update(data: JSON) {
|
||||
export function update(data: ServerData) {
|
||||
unitsManager.update(data);
|
||||
missionData.update(data);
|
||||
logPanel.update(data);
|
||||
@ -182,9 +179,4 @@ export function getConnected() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
export function getUnitControlSliders() {
|
||||
return {altitude: altitudeSlider, airspeed: airspeedSlider}
|
||||
}
|
||||
|
||||
|
||||
window.onload = setup;
|
||||
@ -1,9 +1,9 @@
|
||||
import * as L from "leaflet"
|
||||
import { getContextMenu, getUnitsManager, getActiveCoalition, getMouseInfoPanel } from "..";
|
||||
import { spawnAircraft, spawnGroundUnit, spawnSmoke } from "../dcs/dcs";
|
||||
import { spawnAircraft, spawnGroundUnit, spawnSmoke } from "../server/server";
|
||||
import { bearing, distance, zeroAppend } from "../other/utils";
|
||||
import { getAircraftLabelsByRole, getLoadoutsByName, getLoadoutNamesByRole, getAircraftNameByLabel } from "../units/aircraftdatabase";
|
||||
import { unitTypes } from "../units/unitTypes";
|
||||
import { aircraftDatabase } from "../units/aircraftdatabase";
|
||||
import { unitTypes } from "../units/unittypes";
|
||||
import { BoxSelect } from "./boxselect";
|
||||
|
||||
L.Map.addInitHook('addHandler', 'boxSelect', BoxSelect);
|
||||
@ -238,7 +238,7 @@ export class Map extends L.Map {
|
||||
var selectedUnits = getUnitsManager().getSelectedUnits();
|
||||
if (selectedUnits && selectedUnits.length == 1)
|
||||
{
|
||||
selectedUnitPosition = new L.LatLng(selectedUnits[0].latitude, selectedUnits[0].longitude);
|
||||
selectedUnitPosition = new L.LatLng(selectedUnits[0].getFlightData().latitude, selectedUnits[0].getFlightData().longitude);
|
||||
}
|
||||
getMouseInfoPanel().update(<L.LatLng>e.latlng, this.#measurePoint, selectedUnitPosition);
|
||||
|
||||
@ -309,10 +309,10 @@ export class Map extends L.Map {
|
||||
/* Show unit selection for air units */
|
||||
#selectAircraft(e: SpawnEvent, role: string) {
|
||||
this.hideContextMenu();
|
||||
var options = getAircraftLabelsByRole(role);
|
||||
var options = aircraftDatabase.getLabelsByRole(role);
|
||||
this.showContextMenu(e, "Select aircraft", options, (label: string) => {
|
||||
this.hideContextMenu();
|
||||
var name = getAircraftNameByLabel(label);
|
||||
var name = aircraftDatabase.getNameByLabel(label);
|
||||
if (name != null)
|
||||
this.#unitSelectPayload(e, name, role);
|
||||
}, true);
|
||||
@ -321,14 +321,14 @@ export class Map extends L.Map {
|
||||
/* Show weapon selection for air units */
|
||||
#unitSelectPayload(e: SpawnEvent, unitType: string, role: string) {
|
||||
this.hideContextMenu();
|
||||
var options = getLoadoutNamesByRole(unitType, role);
|
||||
var options = aircraftDatabase.getLoadoutNamesByRole(unitType, role);
|
||||
//options = payloadNames[unitType]
|
||||
if (options != undefined && options.length > 0) {
|
||||
options.sort();
|
||||
this.showContextMenu({x: e.x, y: e.y, latlng: e.latlng}, "Select loadout", options, (loadoutName: string) => {
|
||||
this.hideContextMenu();
|
||||
var loadout = getLoadoutsByName(unitType, loadoutName);
|
||||
spawnAircraft(unitType, e.latlng, getActiveCoalition(), loadout.code, e.airbaseName);
|
||||
var loadout = aircraftDatabase.getLoadoutsByName(unitType, loadoutName);
|
||||
spawnAircraft(unitType, e.latlng, getActiveCoalition(), loadout != null? loadout.code: "", e.airbaseName);
|
||||
}, true);
|
||||
}
|
||||
else {
|
||||
|
||||
@ -27,7 +27,7 @@ export class MissionData
|
||||
this.#airbasesMarkers = {};
|
||||
}
|
||||
|
||||
update(data: any)
|
||||
update(data: ServerData)
|
||||
{
|
||||
this.#bullseyes = data.bullseye;
|
||||
this.#airbases = data.airbases;
|
||||
|
||||
@ -147,7 +147,7 @@ export class UnitControlPanel extends Panel {
|
||||
for (let unit of units)
|
||||
{
|
||||
this.#addUnitButton(unit, this.#selectedUnitsContainer);
|
||||
if (unit.isLeader)
|
||||
if (unit.getFormationData().isLeader)
|
||||
for (let wingman of unit.getWingmen())
|
||||
this.#addUnitButton(wingman, this.#selectedUnitsContainer);
|
||||
}
|
||||
@ -160,16 +160,16 @@ export class UnitControlPanel extends Panel {
|
||||
/* Unit name (actually type, but DCS calls it name for some reason) */
|
||||
var nameDiv = document.createElement("div");
|
||||
nameDiv.classList.add("ol-rounded-container-small");
|
||||
if (unit.name.length >= 7)
|
||||
nameDiv.innerHTML = `${unit.name.substring(0, 4)} ...`;
|
||||
if (unit.getData().name.length >= 7)
|
||||
nameDiv.innerHTML = `${unit.getData().name.substring(0, 4)} ...`;
|
||||
else
|
||||
nameDiv.innerHTML = `${unit.name}`;
|
||||
nameDiv.innerHTML = `${unit.getData().name}`;
|
||||
|
||||
/* Unit icon */
|
||||
var icon = document.createElement("img");
|
||||
if (unit.isLeader)
|
||||
if (unit.getFormationData().isLeader)
|
||||
icon.src = "images/icons/formation.png"
|
||||
else if (unit.isWingman)
|
||||
else if (unit.getFormationData().isWingman)
|
||||
{
|
||||
var wingmen = unit.getLeader()?.getWingmen();
|
||||
if (wingmen && wingmen.lastIndexOf(unit) == wingmen.length - 1)
|
||||
@ -181,7 +181,7 @@ export class UnitControlPanel extends Panel {
|
||||
else
|
||||
icon.src = "images/icons/singleton.png"
|
||||
|
||||
el.innerHTML = unit.unitName;
|
||||
el.innerHTML = unit.getData().unitName;
|
||||
|
||||
el.prepend(nameDiv);
|
||||
|
||||
@ -195,12 +195,12 @@ export class UnitControlPanel extends Panel {
|
||||
el.classList.add("not-selected")
|
||||
|
||||
/* Set background color */
|
||||
el.classList.toggle("red", unit.coalitionID == 1);
|
||||
icon.classList.toggle("red", unit.coalitionID == 1);
|
||||
el.classList.toggle("blue", unit.coalitionID == 2);
|
||||
icon.classList.toggle("blue", unit.coalitionID == 2);
|
||||
el.classList.toggle("neutral", unit.coalitionID == 0);
|
||||
icon.classList.toggle("neutral", unit.coalitionID == 0);
|
||||
el.classList.toggle("red", unit.getMissionData().coalition === "red");
|
||||
icon.classList.toggle("red", unit.getMissionData().coalition === "red");
|
||||
el.classList.toggle("blue", unit.getMissionData().coalition === "blue");
|
||||
icon.classList.toggle("blue", unit.getMissionData().coalition === "blue");
|
||||
el.classList.toggle("neutral", unit.getMissionData().coalition === "neutral");
|
||||
icon.classList.toggle("neutral", unit.getMissionData().coalition === "neutral");
|
||||
|
||||
el.addEventListener("click", () => getUnitsManager().selectUnit(unit.ID));
|
||||
container.appendChild(el);
|
||||
@ -275,14 +275,14 @@ export class UnitControlPanel extends Panel {
|
||||
var leaderFound = false;
|
||||
for (let unit of units)
|
||||
{
|
||||
if (unit.isLeader)
|
||||
if (unit.getFormationData().isLeader)
|
||||
{
|
||||
if (leaderFound)
|
||||
return false
|
||||
else
|
||||
leaderFound = true;
|
||||
}
|
||||
if (!unit.isLeader)
|
||||
if (!unit.getFormationData().isLeader)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@ -291,7 +291,7 @@ export class UnitControlPanel extends Panel {
|
||||
#checkUnitsAlreadyInFormation(units: Unit[])
|
||||
{
|
||||
for (let unit of units)
|
||||
if (unit.isLeader)
|
||||
if (unit.getFormationData().isLeader)
|
||||
return true
|
||||
return false
|
||||
}
|
||||
@ -301,10 +301,10 @@ export class UnitControlPanel extends Panel {
|
||||
var airspeed = null;
|
||||
for (let unit of units)
|
||||
{
|
||||
if (unit.targetSpeed != airspeed && airspeed != null)
|
||||
if (unit.getTaskData().targetSpeed != airspeed && airspeed != null)
|
||||
return null
|
||||
else
|
||||
airspeed = unit.targetSpeed;
|
||||
airspeed = unit.getTaskData().targetSpeed;
|
||||
}
|
||||
return airspeed;
|
||||
}
|
||||
@ -314,10 +314,10 @@ export class UnitControlPanel extends Panel {
|
||||
var altitude = null;
|
||||
for (let unit of units)
|
||||
{
|
||||
if (unit.targetAltitude != altitude && altitude != null)
|
||||
if (unit.getTaskData().targetAltitude != altitude && altitude != null)
|
||||
return null
|
||||
else
|
||||
altitude = unit.targetAltitude;
|
||||
altitude = unit.getTaskData().targetAltitude;
|
||||
}
|
||||
return altitude;
|
||||
}
|
||||
@ -327,10 +327,10 @@ export class UnitControlPanel extends Panel {
|
||||
var ROE = null;
|
||||
for (let unit of units)
|
||||
{
|
||||
if (unit.ROE !== ROE && ROE != null)
|
||||
if (unit.getOptionsData().ROE !== ROE && ROE != null)
|
||||
return null
|
||||
else
|
||||
ROE = unit.ROE;
|
||||
ROE = unit.getOptionsData().ROE;
|
||||
}
|
||||
return ROE;
|
||||
}
|
||||
@ -340,10 +340,10 @@ export class UnitControlPanel extends Panel {
|
||||
var reactionToThreat = null;
|
||||
for (let unit of units)
|
||||
{
|
||||
if (unit.reactionToThreat !== reactionToThreat && reactionToThreat != null)
|
||||
if (unit.getOptionsData().reactionToThreat !== reactionToThreat && reactionToThreat != null)
|
||||
return null
|
||||
else
|
||||
reactionToThreat = unit.reactionToThreat;
|
||||
reactionToThreat = unit.getOptionsData().reactionToThreat;
|
||||
}
|
||||
return reactionToThreat;
|
||||
}
|
||||
|
||||
@ -36,35 +36,35 @@ export class UnitInfoPanel extends Panel {
|
||||
update(unit: Unit) {
|
||||
if (this.getElement() != null) {
|
||||
/* Set the unit info */
|
||||
this.#unitName.innerHTML = unit.unitName;
|
||||
this.#groupName.innerHTML = unit.groupName;
|
||||
this.#name.innerHTML = unit.name;
|
||||
this.#heading.innerHTML = String(Math.floor(rad2deg(unit.heading)) + " °");
|
||||
this.#altitude.innerHTML = String(Math.floor(unit.altitude / 0.3048) + " ft");
|
||||
this.#groundSpeed.innerHTML = String(Math.floor(unit.speed * 1.94384) + " kts");
|
||||
this.#fuel.innerHTML = String(unit.fuel + "%");
|
||||
this.#latitude.innerHTML = ConvertDDToDMS(unit.latitude, false);
|
||||
this.#longitude.innerHTML = ConvertDDToDMS(unit.longitude, true);
|
||||
this.#task.innerHTML = unit.currentTask !== ""? unit.currentTask: "No task";
|
||||
this.#unitName.innerHTML = unit.getData().unitName;
|
||||
this.#groupName.innerHTML = unit.getData().groupName;
|
||||
this.#name.innerHTML = unit.getData().name;
|
||||
this.#heading.innerHTML = String(Math.floor(rad2deg(unit.getFlightData().heading)) + " °");
|
||||
this.#altitude.innerHTML = String(Math.floor(unit.getFlightData().altitude / 0.3048) + " ft");
|
||||
this.#groundSpeed.innerHTML = String(Math.floor(unit.getFlightData().speed * 1.94384) + " kts");
|
||||
this.#fuel.innerHTML = String(unit.getMissionData().fuel + "%");
|
||||
this.#latitude.innerHTML = ConvertDDToDMS(unit.getFlightData().latitude, false);
|
||||
this.#longitude.innerHTML = ConvertDDToDMS(unit.getFlightData().longitude, true);
|
||||
this.#task.innerHTML = unit.getTaskData().currentTask !== ""? unit.getTaskData().currentTask: "No task";
|
||||
|
||||
/* Set the class of the task container */
|
||||
this.#task.classList.toggle("red", unit.coalitionID == 1);
|
||||
this.#task.classList.toggle("blue", unit.coalitionID == 2);
|
||||
this.#task.classList.toggle("neutral", unit.coalitionID == 0);
|
||||
this.#task.classList.toggle("red", unit.getMissionData().coalition === "red");
|
||||
this.#task.classList.toggle("blue", unit.getMissionData().coalition === "blue");
|
||||
this.#task.classList.toggle("neutral", unit.getMissionData().coalition === "neutral");
|
||||
|
||||
/* Add the loadout elements */
|
||||
var els = this.getElement().getElementsByClassName("js-loadout-element");
|
||||
while (els.length > 0)
|
||||
this.#loadoutContainer.removeChild(els[0]);
|
||||
|
||||
for (let index in unit.ammo)
|
||||
for (let index in unit.getMissionData().ammo)
|
||||
this.#addLoadoutElement(unit, index);
|
||||
}
|
||||
}
|
||||
|
||||
#addLoadoutElement(unit: Unit, index: string)
|
||||
{
|
||||
var ammo = unit.ammo[index];
|
||||
var ammo = unit.getMissionData().ammo[index];
|
||||
var displayName = ammo.desc.displayName;
|
||||
var amount = ammo.count;
|
||||
var el = document.createElement("div")
|
||||
|
||||
@ -49,29 +49,29 @@ export class VisibilityControlPanel {
|
||||
var uncontrolledVisibilityCheckbox = <HTMLInputElement> this.#element.querySelector("#uncontrolled-visibility");
|
||||
var uncontrolledVisibility = !uncontrolledVisibilityCheckbox.checked;
|
||||
|
||||
var airVisibilityCheckbox = <HTMLInputElement> this.#element.querySelector("#air-visibility");
|
||||
if (airVisibilityCheckbox.checked)
|
||||
AirUnit.setVisibility({human: "full", ai: activeVisibility, uncontrolled: uncontrolledVisibility? activeVisibility: "hidden", dead: "hidden"});
|
||||
else
|
||||
AirUnit.setVisibility({human: "hidden", ai: "hidden", uncontrolled: "hidden", dead: "hidden"});
|
||||
|
||||
var groundVisibilityCheckbox = <HTMLInputElement> this.#element.querySelector("#ground-visibility");
|
||||
if (groundVisibilityCheckbox.checked)
|
||||
GroundUnit.setVisibility({human: activeVisibility, ai: activeVisibility, uncontrolled: uncontrolledVisibility? activeVisibility: "hidden", dead: "hidden"});
|
||||
else
|
||||
GroundUnit.setVisibility({human: "hidden", ai: "hidden", uncontrolled: "hidden", dead: "hidden"});
|
||||
|
||||
var navyVisibilityCheckbox = <HTMLInputElement> this.#element.querySelector("#navy-visibility");
|
||||
if (navyVisibilityCheckbox.checked)
|
||||
NavyUnit.setVisibility({human: activeVisibility, ai: activeVisibility, uncontrolled: uncontrolledVisibility? activeVisibility: "hidden", dead: "hidden"});
|
||||
else
|
||||
NavyUnit.setVisibility({human: "hidden", ai: "hidden", uncontrolled: "hidden", dead: "hidden"});
|
||||
|
||||
var weaponVisibilityCheckbox = <HTMLInputElement> this.#element.querySelector("#weapon-visibility");
|
||||
if (weaponVisibilityCheckbox.checked)
|
||||
Weapon.setVisibility({human: activeVisibility, ai: activeVisibility, uncontrolled: uncontrolledVisibility? activeVisibility: "hidden", dead: "hidden"});
|
||||
else
|
||||
Weapon.setVisibility({human: "hidden", ai: "hidden", uncontrolled: "hidden", dead: "hidden"});
|
||||
//var airVisibilityCheckbox = <HTMLInputElement> this.#element.querySelector("#air-visibility");
|
||||
//if (airVisibilityCheckbox.checked)
|
||||
// AirUnit.setVisibility({human: "full", AI: activeVisibility, uncontrolled: uncontrolledVisibility? activeVisibility: "hidden", dead: "hidden"});
|
||||
//else
|
||||
// AirUnit.setVisibility({human: "hidden", AI: "hidden", uncontrolled: "hidden", dead: "hidden"});
|
||||
//
|
||||
//var groundVisibilityCheckbox = <HTMLInputElement> this.#element.querySelector("#ground-visibility");
|
||||
//if (groundVisibilityCheckbox.checked)
|
||||
// GroundUnit.setVisibility({human: activeVisibility, AI: activeVisibility, uncontrolled: uncontrolledVisibility? activeVisibility: "hidden", dead: "hidden"});
|
||||
//else
|
||||
// GroundUnit.setVisibility({human: "hidden", AI: "hidden", uncontrolled: "hidden", dead: "hidden"});
|
||||
//
|
||||
//var navyVisibilityCheckbox = <HTMLInputElement> this.#element.querySelector("#navy-visibility");
|
||||
//if (navyVisibilityCheckbox.checked)
|
||||
// NavyUnit.setVisibility({human: activeVisibility, AI: activeVisibility, uncontrolled: uncontrolledVisibility? activeVisibility: "hidden", dead: "hidden"});
|
||||
//else
|
||||
// NavyUnit.setVisibility({human: "hidden", AI: "hidden", uncontrolled: "hidden", dead: "hidden"});
|
||||
//
|
||||
//var weaponVisibilityCheckbox = <HTMLInputElement> this.#element.querySelector("#weapon-visibility");
|
||||
//if (weaponVisibilityCheckbox.checked)
|
||||
// Weapon.setVisibility({human: activeVisibility, AI: activeVisibility, uncontrolled: uncontrolledVisibility? activeVisibility: "hidden", dead: "hidden"});
|
||||
//else
|
||||
// Weapon.setVisibility({human: "hidden", AI: "hidden", uncontrolled: "hidden", dead: "hidden"});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,14 +1,8 @@
|
||||
import { Marker, LatLng, Polyline, Icon } from 'leaflet';
|
||||
import { getMap, getUnitsManager} from '..';
|
||||
import { getMap, getUnitsManager } from '..';
|
||||
import { UnitMarker, MarkerOptions, AircraftMarker, HelicopterMarker, GroundUnitMarker, NavyUnitMarker, WeaponMarker, MissileMarker, BombMarker } from './unitmarker';
|
||||
import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, landAt, setAltitude, setReactionToThreat, setROE, setSpeed } from '../dcs/dcs';
|
||||
|
||||
interface VisibilityOptions {
|
||||
dead: string;
|
||||
ai: string;
|
||||
uncontrolled: string;
|
||||
human: string;
|
||||
}
|
||||
import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, landAt, setAltitude, setReactionToThreat, setROE, setSpeed } from '../server/server';
|
||||
import { aircraftDatabase } from './aircraftdatabase';
|
||||
|
||||
var pathIcon = new Icon({
|
||||
iconUrl: 'images/marker-icon.png',
|
||||
@ -17,60 +11,37 @@ var pathIcon = new Icon({
|
||||
});
|
||||
|
||||
export class Unit {
|
||||
ID: number = -1;
|
||||
AI: boolean = false;
|
||||
formation: string = "";
|
||||
name: string = "";
|
||||
unitName: string = "";
|
||||
groupName: string = "";
|
||||
latitude: number = 0;
|
||||
longitude: number = 0;
|
||||
altitude: number = 0;
|
||||
heading: number = 0;
|
||||
speed: number = 0;
|
||||
coalitionID: number = -1;
|
||||
alive: boolean = true;
|
||||
currentTask: string = "";
|
||||
fuel: number = 0;
|
||||
type: any = null;
|
||||
flags: any = null;
|
||||
activePath: any = null;
|
||||
ammo: any = null;
|
||||
targets: any = null;
|
||||
hasTask: boolean = false;
|
||||
isLeader: boolean = false;
|
||||
isWingman: boolean = false;
|
||||
leaderID: number = 0;
|
||||
wingmen: Unit[] = [];
|
||||
wingmenIDs: number[] = [];
|
||||
targetSpeed: number = 0;
|
||||
targetAltitude: number = 0;
|
||||
ROE: string = "";
|
||||
reactionToThreat: string = "";
|
||||
|
||||
ID: number;
|
||||
|
||||
#data: UnitData;
|
||||
#marker: UnitMarker;
|
||||
|
||||
#selectable: boolean;
|
||||
#selected: boolean = false;
|
||||
|
||||
#preventClick: boolean = false;
|
||||
|
||||
#pathMarkers: Marker[] = [];
|
||||
#pathPolyline: Polyline;
|
||||
#targetsPolylines: Polyline[];
|
||||
#marker: UnitMarker;
|
||||
|
||||
#timer: number = 0;
|
||||
#forceUpdate: boolean = false;
|
||||
|
||||
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;
|
||||
static getConstructor(type: string) {
|
||||
if (type === "GroundUnit") return GroundUnit;
|
||||
if (type === "Aircraft") return Aircraft;
|
||||
if (type === "Helicopter") return Helicopter;
|
||||
if (type === "Missile") return Missile;
|
||||
if (type === "Bomb") return Bomb;
|
||||
if (type === "NavyUnit") return NavyUnit;
|
||||
}
|
||||
|
||||
constructor(ID: number, marker: UnitMarker) {
|
||||
constructor(ID: number, marker: UnitMarker, data: UnitData) {
|
||||
this.ID = ID;
|
||||
|
||||
this.#selectable = true;
|
||||
this.#data = data;
|
||||
|
||||
/* The marker is set by the inherited class */
|
||||
this.#marker = marker;
|
||||
@ -83,42 +54,34 @@ export class Unit {
|
||||
this.#targetsPolylines = [];
|
||||
}
|
||||
|
||||
update(response: any) {
|
||||
update(response: UnitData) {
|
||||
var updateMarker = false;
|
||||
if (this.latitude != response['latitude'] || this.longitude != response['longitude'] || this.alive != response['alive'] || this.#forceUpdate)
|
||||
if (this.#data.flightData.latitude != response.flightData.latitude || this.#data.flightData.longitude != response.flightData.longitude || this.#data.alive != response.alive || this.#forceUpdate)
|
||||
updateMarker = true;
|
||||
|
||||
for (let entry in response) {
|
||||
// @ts-ignore TODO handle better
|
||||
this[entry] = response[entry];
|
||||
}
|
||||
|
||||
// TODO handle better
|
||||
if (response['activePath'] == undefined)
|
||||
this.activePath = null
|
||||
this.#data = response;
|
||||
|
||||
/* Dead units can't be selected */
|
||||
this.setSelected(this.getSelected() && this.alive)
|
||||
this.setSelected(this.getSelected() && this.#data.alive)
|
||||
|
||||
if (updateMarker)
|
||||
this.#updateMarker();
|
||||
|
||||
this.#clearTargets();
|
||||
if (this.getSelected() && this.activePath != null)
|
||||
{
|
||||
if (this.getSelected()) {
|
||||
this.#drawPath();
|
||||
this.#drawTargets();
|
||||
}
|
||||
else
|
||||
this.#clearPath();
|
||||
this.#clearPath();
|
||||
}
|
||||
|
||||
setSelected(selected: boolean) {
|
||||
/* Only alive units can be selected. Some units are not selectable (weapons) */
|
||||
if ((this.alive || !selected) && this.#selectable && this.#selected != selected) {
|
||||
if ((this.#data.alive || !selected) && this.#selectable && this.#selected != selected) {
|
||||
this.#selected = selected;
|
||||
this.#marker.setSelected(selected);
|
||||
document.dispatchEvent(new CustomEvent("unitSelection", {detail: this}));
|
||||
document.dispatchEvent(new CustomEvent("unitSelection", { detail: this }));
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,8 +99,8 @@ export class Unit {
|
||||
|
||||
addDestination(latlng: L.LatLng) {
|
||||
var path: any = {};
|
||||
if (this.activePath != null) {
|
||||
path = this.activePath;
|
||||
if (this.#data.taskData.activePath != null) {
|
||||
path = this.#data.taskData.activePath;
|
||||
path[(Object.keys(path).length + 1).toString()] = latlng;
|
||||
}
|
||||
else {
|
||||
@ -147,7 +110,7 @@ export class Unit {
|
||||
}
|
||||
|
||||
clearDestinations() {
|
||||
this.activePath = null;
|
||||
this.#data.taskData.activePath = null;
|
||||
}
|
||||
|
||||
getHidden() {
|
||||
@ -155,7 +118,7 @@ export class Unit {
|
||||
}
|
||||
|
||||
getLeader() {
|
||||
return getUnitsManager().getUnitByID(this.leaderID);
|
||||
return getUnitsManager().getUnitByID(this.#data.formationData.leaderID);
|
||||
}
|
||||
|
||||
getFormation() {
|
||||
@ -164,10 +127,8 @@ export class Unit {
|
||||
|
||||
getWingmen() {
|
||||
var wingmen: Unit[] = [];
|
||||
if (this.wingmenIDs != null)
|
||||
{
|
||||
for (let ID of this.wingmenIDs)
|
||||
{
|
||||
if (this.#data.formationData.wingmenIDs != null) {
|
||||
for (let ID of this.#data.formationData.wingmenIDs) {
|
||||
var unit = getUnitsManager().getUnitByID(ID)
|
||||
if (unit)
|
||||
wingmen.push(unit);
|
||||
@ -176,11 +137,86 @@ export class Unit {
|
||||
return wingmen;
|
||||
}
|
||||
|
||||
forceUpdate()
|
||||
{
|
||||
forceUpdate() {
|
||||
this.#forceUpdate = true;
|
||||
}
|
||||
|
||||
getData() {
|
||||
return this.#data;
|
||||
}
|
||||
|
||||
getFlightData() {
|
||||
return this.#data.flightData;
|
||||
}
|
||||
|
||||
getTaskData() {
|
||||
return this.#data.taskData;
|
||||
}
|
||||
|
||||
getMissionData() {
|
||||
return this.#data.missionData;
|
||||
}
|
||||
|
||||
getFormationData() {
|
||||
return this.#data.formationData;
|
||||
}
|
||||
|
||||
getOptionsData() {
|
||||
return this.#data.optionsData;
|
||||
}
|
||||
|
||||
attackUnit(targetID: number) {
|
||||
/* Call DCS attackUnit function */
|
||||
if (this.ID != targetID) {
|
||||
attackUnit(this.ID, targetID);
|
||||
}
|
||||
else {
|
||||
// TODO: show a message
|
||||
}
|
||||
}
|
||||
|
||||
landAt(latlng: LatLng) {
|
||||
landAt(this.ID, latlng);
|
||||
}
|
||||
|
||||
changeSpeed(speedChange: string) {
|
||||
changeSpeed(this.ID, speedChange);
|
||||
}
|
||||
|
||||
changeAltitude(altitudeChange: string) {
|
||||
changeAltitude(this.ID, altitudeChange);
|
||||
}
|
||||
|
||||
setSpeed(speed: number) {
|
||||
setSpeed(this.ID, speed);
|
||||
}
|
||||
|
||||
setAltitude(altitude: number) {
|
||||
setAltitude(this.ID, altitude);
|
||||
}
|
||||
|
||||
setROE(ROE: string) {
|
||||
setROE(this.ID, ROE);
|
||||
}
|
||||
|
||||
setReactionToThreat(reactionToThreat: string) {
|
||||
setReactionToThreat(this.ID, reactionToThreat);
|
||||
}
|
||||
|
||||
delete() {
|
||||
deleteUnit(this.ID);
|
||||
}
|
||||
|
||||
/*
|
||||
setformation(formation)
|
||||
{
|
||||
}
|
||||
*/
|
||||
|
||||
setLeader(isLeader: boolean, wingmenIDs: number[] = []) {
|
||||
setLeader(this.ID, isLeader, wingmenIDs);
|
||||
}
|
||||
|
||||
#onClick(e: any) {
|
||||
this.#timer = setTimeout(() => {
|
||||
if (!this.#preventClick) {
|
||||
@ -206,7 +242,7 @@ export class Unit {
|
||||
'Follow'
|
||||
]
|
||||
|
||||
getMap().showContextMenu(e.originalEvent, "Action: " + this.unitName, options, (action: string) => this.#executeAction(action));
|
||||
getMap().showContextMenu(e.originalEvent, "Action: " + this.#data.unitName, options, (action: string) => this.#executeAction(action));
|
||||
}
|
||||
|
||||
#executeAction(action: string) {
|
||||
@ -225,14 +261,13 @@ export class Unit {
|
||||
if (getMap().hasLayer(this.#marker) && this.getHidden()) {
|
||||
getMap().removeLayer(this.#marker);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.#marker.setLatLng(new LatLng(this.latitude, this.longitude));
|
||||
else {
|
||||
this.#marker.setLatLng(new LatLng(this.#data.flightData.latitude, this.#data.flightData.longitude));
|
||||
this.#marker.draw({
|
||||
heading: this.heading,
|
||||
speed: this.speed,
|
||||
altitude: this.altitude,
|
||||
alive: this.alive
|
||||
heading: this.#data.flightData.heading,
|
||||
speed: this.#data.flightData.speed,
|
||||
altitude: this.#data.flightData.altitude,
|
||||
alive: this.#data.alive
|
||||
});
|
||||
}
|
||||
|
||||
@ -240,25 +275,25 @@ export class Unit {
|
||||
}
|
||||
|
||||
#drawPath() {
|
||||
if (this.activePath != null) {
|
||||
if (this.#data.taskData.activePath != null) {
|
||||
var points = [];
|
||||
points.push(new LatLng(this.latitude, this.longitude));
|
||||
points.push(new LatLng(this.#data.flightData.latitude, this.#data.flightData.longitude));
|
||||
|
||||
/* Add markers if missing */
|
||||
while (this.#pathMarkers.length < Object.keys(this.activePath).length) {
|
||||
while (this.#pathMarkers.length < Object.keys(this.#data.taskData.activePath).length) {
|
||||
var marker = new Marker([0, 0], { icon: pathIcon }).addTo(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.#data.taskData.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];
|
||||
for (let WP in this.#data.taskData.activePath) {
|
||||
var destination = this.#data.taskData.activePath[WP];
|
||||
this.#pathMarkers[parseInt(WP) - 1].setLatLng([destination.lat, destination.lng]);
|
||||
points.push(new LatLng(destination.lat, destination.lng));
|
||||
this.#pathPolyline.setLatLngs(points);
|
||||
@ -274,36 +309,25 @@ export class Unit {
|
||||
this.#pathPolyline.setLatLngs([]);
|
||||
}
|
||||
|
||||
#drawTargets()
|
||||
{
|
||||
for (let typeIndex in this.targets)
|
||||
{
|
||||
for (let index in this.targets[typeIndex])
|
||||
{
|
||||
var targetData = this.targets[typeIndex][index];
|
||||
#drawTargets() {
|
||||
for (let typeIndex in this.getMissionData().targets) {
|
||||
for (let index in this.getMissionData().targets[typeIndex]) {
|
||||
var targetData = this.getMissionData().targets[typeIndex][index];
|
||||
var target = getUnitsManager().getUnitByID(targetData.object["id_"])
|
||||
if (target != null){
|
||||
var startLatLng = new LatLng(this.latitude, this.longitude)
|
||||
var endLatLng = new LatLng(target.latitude, target.longitude)
|
||||
|
||||
if (target != null) {
|
||||
var startLatLng = new LatLng(this.#data.flightData.latitude, this.#data.flightData.longitude)
|
||||
var endLatLng = new LatLng(target.getFlightData().latitude, target.getFlightData().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});
|
||||
var targetPolyline = new Polyline([startLatLng, endLatLng], { color: color, weight: 3, opacity: 1, smoothFactor: 1 });
|
||||
targetPolyline.addTo(getMap());
|
||||
this.#targetsPolylines.push(targetPolyline)
|
||||
}
|
||||
@ -311,242 +335,102 @@ export class Unit {
|
||||
}
|
||||
}
|
||||
|
||||
#clearTargets()
|
||||
{
|
||||
for (let index in this.#targetsPolylines)
|
||||
{
|
||||
#clearTargets() {
|
||||
for (let index in this.#targetsPolylines) {
|
||||
getMap().removeLayer(this.#targetsPolylines[index])
|
||||
}
|
||||
}
|
||||
|
||||
attackUnit(targetID: number) {
|
||||
/* Call DCS attackUnit function */
|
||||
if (this.ID != targetID) {
|
||||
attackUnit(this.ID, targetID);
|
||||
}
|
||||
else {
|
||||
// TODO: show a message
|
||||
}
|
||||
}
|
||||
|
||||
landAt(latlng: LatLng)
|
||||
{
|
||||
landAt(this.ID, latlng);
|
||||
}
|
||||
|
||||
changeSpeed(speedChange: string)
|
||||
{
|
||||
changeSpeed(this.ID, speedChange);
|
||||
}
|
||||
|
||||
changeAltitude(altitudeChange: string)
|
||||
{
|
||||
changeAltitude(this.ID, altitudeChange);
|
||||
}
|
||||
|
||||
setSpeed(speed: number)
|
||||
{
|
||||
setSpeed(this.ID, speed);
|
||||
}
|
||||
|
||||
setAltitude(altitude: number)
|
||||
{
|
||||
setAltitude(this.ID, altitude);
|
||||
}
|
||||
|
||||
setROE(ROE: string)
|
||||
{
|
||||
setROE(this.ID, ROE);
|
||||
}
|
||||
|
||||
setReactionToThreat(reactionToThreat: string)
|
||||
{
|
||||
setReactionToThreat(this.ID, reactionToThreat);
|
||||
}
|
||||
|
||||
delete()
|
||||
{
|
||||
deleteUnit(this.ID);
|
||||
}
|
||||
|
||||
/*
|
||||
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(isLeader: boolean, wingmenIDs: number[] = [])
|
||||
{
|
||||
setLeader(this.ID, isLeader, wingmenIDs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class AirUnit extends Unit {
|
||||
static visibility: VisibilityOptions = {dead: "hidden", ai: "partial", uncontrolled: "partial", human: "full"}
|
||||
static setVisibility(visibility: VisibilityOptions)
|
||||
{
|
||||
getUnitsManager().forceUpdate();
|
||||
AirUnit.visibility = visibility;
|
||||
}
|
||||
|
||||
static getVisibility()
|
||||
{
|
||||
return AirUnit.visibility;
|
||||
}
|
||||
|
||||
getHidden() {
|
||||
if (this.alive)
|
||||
{
|
||||
if (this.flags.user)
|
||||
return AirUnit.getVisibility().human === "hidden"
|
||||
|
||||
if (this.AI)
|
||||
return AirUnit.getVisibility().ai === "hidden"
|
||||
else
|
||||
return AirUnit.getVisibility().uncontrolled === "hidden"
|
||||
}
|
||||
else
|
||||
{
|
||||
return AirUnit.getVisibility().dead === "hidden"
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export class Aircraft extends AirUnit {
|
||||
constructor(ID: number, options: MarkerOptions) {
|
||||
var marker = new AircraftMarker(options);
|
||||
super(ID, marker);
|
||||
constructor(ID: number, data: UnitData) {
|
||||
var marker = new AircraftMarker({
|
||||
AI: data.AI,
|
||||
unitName: data.unitName,
|
||||
name: aircraftDatabase.getShortLabelByName(data.name),
|
||||
human: data.missionData.flags.human,
|
||||
coalition: data.missionData.coalition});
|
||||
super(ID, marker, data);
|
||||
}
|
||||
}
|
||||
|
||||
export class Helicopter extends AirUnit {
|
||||
constructor(ID: number, options: MarkerOptions) {
|
||||
var marker = new HelicopterMarker(options);
|
||||
super(ID, marker);
|
||||
constructor(ID: number, data: UnitData) {
|
||||
var marker = new HelicopterMarker({
|
||||
AI: data.AI,
|
||||
unitName: data.unitName,
|
||||
name: "H",
|
||||
human: data.missionData.flags.human,
|
||||
coalition: data.missionData.coalition});
|
||||
super(ID, marker, data);
|
||||
}
|
||||
}
|
||||
|
||||
export class GroundUnit extends Unit {
|
||||
static visibility: VisibilityOptions = {dead: "hidden", ai: "partial", uncontrolled: "partial", human: "partial"}
|
||||
static setVisibility(visibility: VisibilityOptions)
|
||||
{
|
||||
getUnitsManager().forceUpdate();
|
||||
GroundUnit.visibility = visibility;
|
||||
}
|
||||
|
||||
static getVisibility()
|
||||
{
|
||||
return GroundUnit.visibility;
|
||||
}
|
||||
|
||||
constructor(ID: number, options: MarkerOptions) {
|
||||
var marker = new GroundUnitMarker(options);
|
||||
super(ID, marker);
|
||||
constructor(ID: number, data: UnitData) {
|
||||
var marker = new GroundUnitMarker({
|
||||
AI: data.AI,
|
||||
unitName: data.unitName,
|
||||
name: "G",
|
||||
human: data.missionData.flags.human,
|
||||
coalition: data.missionData.coalition});
|
||||
super(ID, marker, data);
|
||||
}
|
||||
|
||||
getHidden() {
|
||||
if (this.alive)
|
||||
{
|
||||
if (this.flags.user)
|
||||
return GroundUnit.getVisibility().human === "hidden"
|
||||
|
||||
if (this.AI)
|
||||
return GroundUnit.getVisibility().ai === "hidden"
|
||||
else
|
||||
return GroundUnit.getVisibility().uncontrolled === "hidden"
|
||||
}
|
||||
else
|
||||
{
|
||||
return GroundUnit.getVisibility().dead === "hidden"
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export class NavyUnit extends Unit {
|
||||
static visibility: VisibilityOptions = {dead: "hidden", ai: "partial", uncontrolled: "partial", human: "partial"}
|
||||
static setVisibility(visibility: VisibilityOptions)
|
||||
{
|
||||
getUnitsManager().forceUpdate();
|
||||
NavyUnit.visibility = visibility;
|
||||
}
|
||||
|
||||
static getVisibility()
|
||||
{
|
||||
return NavyUnit.visibility;
|
||||
}
|
||||
|
||||
constructor(ID: number, options: MarkerOptions) {
|
||||
var marker = new NavyUnitMarker(options);
|
||||
super(ID, marker);
|
||||
constructor(ID: number, data: UnitData) {
|
||||
var marker = new NavyUnitMarker({
|
||||
AI: data.AI,
|
||||
unitName: data.unitName,
|
||||
name: "N",
|
||||
human: data.missionData.flags.human,
|
||||
coalition: data.missionData.coalition});
|
||||
super(ID, marker, data);
|
||||
}
|
||||
|
||||
getHidden() {
|
||||
if (this.alive)
|
||||
{
|
||||
if (this.AI)
|
||||
return NavyUnit.getVisibility().ai === "hidden"
|
||||
else
|
||||
return NavyUnit.getVisibility().uncontrolled === "hidden"
|
||||
}
|
||||
else
|
||||
{
|
||||
return NavyUnit.getVisibility().dead === "hidden"
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export class Weapon extends Unit {
|
||||
static visibility: VisibilityOptions = {dead: "hidden", ai: "partial", uncontrolled: "partial", human: "partial"}
|
||||
static setVisibility(visibility: VisibilityOptions)
|
||||
{
|
||||
getUnitsManager().forceUpdate();
|
||||
Weapon.visibility = visibility;
|
||||
}
|
||||
|
||||
static getVisibility()
|
||||
{
|
||||
return Weapon.visibility;
|
||||
}
|
||||
|
||||
constructor(ID: number, marker: UnitMarker)
|
||||
{
|
||||
super(ID, marker);
|
||||
constructor(ID: number, marker: UnitMarker, data: UnitData) {
|
||||
super(ID, marker, data);
|
||||
this.setSelectable(false);
|
||||
}
|
||||
|
||||
getHidden() {
|
||||
if (this.alive)
|
||||
return Weapon.getVisibility().uncontrolled === "hidden"
|
||||
else
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export class Missile extends Weapon {
|
||||
constructor(ID: number, options: MarkerOptions) {
|
||||
var marker = new MissileMarker(options);
|
||||
super(ID, marker);
|
||||
constructor(ID: number, data: UnitData) {
|
||||
var marker = new MissileMarker({
|
||||
AI: data.AI,
|
||||
unitName: data.unitName,
|
||||
name: "M",
|
||||
human: data.missionData.flags.human,
|
||||
coalition: data.missionData.coalition});
|
||||
super(ID, marker, data);
|
||||
}
|
||||
}
|
||||
|
||||
export class Bomb extends Weapon {
|
||||
constructor(ID: number, options: MarkerOptions) {
|
||||
var marker = new BombMarker(options);
|
||||
super(ID, marker);
|
||||
constructor(ID: number, data: UnitData) {
|
||||
var marker = new BombMarker({
|
||||
AI: data.AI,
|
||||
unitName: data.unitName,
|
||||
name: "B",
|
||||
human: data.missionData.flags.human,
|
||||
coalition: data.missionData.coalition});
|
||||
super(ID, marker, data);
|
||||
}
|
||||
}
|
||||
|
||||
92
client/src/units/unitdatabase.ts
Normal file
92
client/src/units/unitdatabase.ts
Normal file
@ -0,0 +1,92 @@
|
||||
export interface LoadoutItemBlueprint {
|
||||
name: string;
|
||||
quantity: number;
|
||||
}
|
||||
|
||||
export interface LoadoutBlueprint {
|
||||
fuel: number;
|
||||
items: LoadoutItemBlueprint[];
|
||||
roles: string[];
|
||||
code: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface UnitBlueprint {
|
||||
name: string;
|
||||
label: string;
|
||||
shortLabel: string;
|
||||
loadouts: LoadoutBlueprint[];
|
||||
}
|
||||
|
||||
export class UnitDatabase {
|
||||
units: {[key: string]: UnitBlueprint} = {};
|
||||
|
||||
constructor()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
getLabelsByRole(role: string)
|
||||
{
|
||||
var units = [];
|
||||
for (let unit in this.units)
|
||||
{
|
||||
for (let loadout of this.units[unit].loadouts)
|
||||
{
|
||||
if (loadout.roles.includes(role))
|
||||
{
|
||||
units.push(this.units[unit].label)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return units;
|
||||
}
|
||||
|
||||
getLoadoutNamesByRole(unit: string, role: string)
|
||||
{
|
||||
var loadouts = [];
|
||||
for (let loadout of this.units[unit].loadouts)
|
||||
{
|
||||
if (loadout.roles.includes(role) || loadout.roles.includes(""))
|
||||
{
|
||||
loadouts.push(loadout.name)
|
||||
}
|
||||
}
|
||||
return loadouts;
|
||||
}
|
||||
|
||||
getLoadoutsByName(unit: string, loadoutName: string)
|
||||
{
|
||||
for (let loadout of this.units[unit].loadouts)
|
||||
{
|
||||
if (loadout.name === loadoutName)
|
||||
{
|
||||
return loadout;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
getNameByLabel(label: string)
|
||||
{
|
||||
for (let name in this.units)
|
||||
{
|
||||
if (this.units[name].label === label)
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
getLabelByName(name: string)
|
||||
{
|
||||
return this.units[name] === undefined? name: this.units[name].label;
|
||||
}
|
||||
|
||||
getShortLabelByName(name: string)
|
||||
{
|
||||
return this.units[name] === undefined? name: this.units[name].shortLabel;
|
||||
}
|
||||
}
|
||||
@ -1,58 +1,43 @@
|
||||
import * as L from 'leaflet'
|
||||
import { getMap } from '..'
|
||||
import { rad2deg } from '../other/utils'
|
||||
import { getAircrafImage, getAircraftLabelByName } from './aircraftdatabase'
|
||||
import { AirUnit, GroundUnit, NavyUnit, Weapon } from './unit'
|
||||
|
||||
export interface MarkerOptions {
|
||||
unitName: string
|
||||
name: string
|
||||
human: boolean
|
||||
coalitionID: number
|
||||
type: any
|
||||
unitName: string,
|
||||
name: string,
|
||||
human: boolean,
|
||||
coalition: string,
|
||||
AI: boolean
|
||||
}
|
||||
|
||||
export interface MarkerData {
|
||||
heading: number
|
||||
speed: number
|
||||
altitude: number
|
||||
heading: number,
|
||||
speed: number,
|
||||
altitude: number,
|
||||
alive: boolean
|
||||
}
|
||||
|
||||
export class UnitMarker extends L.Marker {
|
||||
#unitName: string
|
||||
#name: string
|
||||
#human: boolean
|
||||
#AI: boolean
|
||||
#alive: boolean = true
|
||||
#options: MarkerOptions;
|
||||
#data: MarkerData;
|
||||
#selected: boolean = false
|
||||
|
||||
constructor(options: MarkerOptions) {
|
||||
super(new L.LatLng(0, 0), { riseOnHover: true });
|
||||
this.#unitName = options.unitName;
|
||||
this.#name = getAircraftLabelByName(options.name);
|
||||
this.#human = options.human;
|
||||
this.#AI = options.AI;
|
||||
|
||||
var coalition = "";
|
||||
if (options.coalitionID == 1)
|
||||
coalition = "red"
|
||||
else if (options.coalitionID == 2)
|
||||
coalition = "blue"
|
||||
else
|
||||
coalition = "neutral"
|
||||
this.#options = options;
|
||||
this.#data = {heading: 0, speed: 0, altitude: 0, alive: true};
|
||||
|
||||
var icon = new L.DivIcon({
|
||||
html: `<div class="unit"
|
||||
data-coalition=${coalition}
|
||||
data-pilot=${this.#human? "human": "ai"}>
|
||||
data-coalition=${this.#options.coalition}
|
||||
data-pilot=${this.#options.human? "human": "ai"}>
|
||||
<div class="unit-spotlight">
|
||||
<div class="unit-selected-border">
|
||||
<div class="unit-vvi">
|
||||
<div class="unit-vvi-heading"></div>
|
||||
</div>
|
||||
<div class="unit-id">${this.#name}</div>
|
||||
<div class="unit-id">${this.#options.name}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="unit-hotgroup">
|
||||
@ -68,7 +53,7 @@ export class UnitMarker extends L.Marker {
|
||||
<div data-ammo-type="other"></div>
|
||||
</div>
|
||||
<div class="unit-summary">
|
||||
<div class="unit-callsign">${this.#unitName}</div>
|
||||
<div class="unit-callsign">${this.#options.unitName}</div>
|
||||
<div class="unit-heading"></div>
|
||||
<div class="unit-altitude"></div>
|
||||
</div>
|
||||
@ -87,14 +72,14 @@ export class UnitMarker extends L.Marker {
|
||||
}
|
||||
|
||||
draw(data: MarkerData) {
|
||||
this.#alive = data.alive;
|
||||
this.#data;
|
||||
|
||||
var element = this.getElement();
|
||||
|
||||
if (element != null)
|
||||
{
|
||||
element.querySelector(".unit")?.setAttribute("data-is-selected", String(this.getSelected()));
|
||||
element.querySelector(".unit-vvi-heading")?.setAttribute("style",`transform: rotate(${rad2deg(data.heading)}deg); width: ${data.speed / 5}px`);
|
||||
element.querySelector(".unit-vvi-heading")?.setAttribute("style",`transform: rotate(${rad2deg(data.heading)}deg); width: ${15 + data.speed / 5}px`);
|
||||
element.querySelector(".unit")?.setAttribute("data-fuel-level", "20");
|
||||
element.querySelector(".unit")?.setAttribute("data-has-fox-1", "true");
|
||||
|
||||
var unitHeadingDiv = element.querySelector(".unit-heading");
|
||||
if (unitHeadingDiv != null)
|
||||
@ -102,7 +87,7 @@ export class UnitMarker extends L.Marker {
|
||||
|
||||
var unitAltitudeDiv = element.querySelector(".unit-altitude");
|
||||
if (unitAltitudeDiv != null)
|
||||
unitAltitudeDiv.innerHTML = String(Math.floor(data.altitude / 1000));
|
||||
unitAltitudeDiv.innerHTML = String(Math.floor(data.altitude / 0.3048 / 1000));
|
||||
}
|
||||
var pos = getMap().latLngToLayerPoint(this.getLatLng()).round();
|
||||
this.setZIndexOffset(Math.floor(data.altitude) - pos.y);
|
||||
@ -110,9 +95,7 @@ export class UnitMarker extends L.Marker {
|
||||
|
||||
setSelected(selected: boolean) {
|
||||
this.#selected = selected;
|
||||
this.getElement()?.querySelector("#icon")?.classList.remove("ol-unit-marker-hovered");
|
||||
this.getElement()?.querySelector("#ring")?.classList.toggle("ol-unit-marker-selected", selected);
|
||||
this.getElement()?.querySelector("#background")?.classList.toggle("ol-unit-marker-selected", selected);
|
||||
this.getElement()?.querySelector(".unit")?.setAttribute("data-is-selected", String(this.getSelected()));
|
||||
}
|
||||
|
||||
getSelected() {
|
||||
@ -120,141 +103,46 @@ export class UnitMarker extends L.Marker {
|
||||
}
|
||||
|
||||
setHovered(hovered: boolean) {
|
||||
this.getElement()?.querySelector("#icon")?.classList.toggle("ol-unit-marker-hovered", hovered && this.#alive);
|
||||
this.getElement()?.querySelector("#icon")?.classList.toggle("ol-unit-marker-hovered", hovered && this.#data.alive);
|
||||
}
|
||||
|
||||
getName() {
|
||||
return this.#name;
|
||||
getData() {
|
||||
return this.#data;
|
||||
}
|
||||
|
||||
getHuman() {
|
||||
return this.#human;
|
||||
}
|
||||
|
||||
getAI() {
|
||||
return this.#AI;
|
||||
}
|
||||
|
||||
getAlive() {
|
||||
return this.#alive;
|
||||
}
|
||||
|
||||
getVisibility() {
|
||||
return "full";
|
||||
}
|
||||
|
||||
getUnitImage() {
|
||||
return new Image().src = "images/units/unit.png"
|
||||
getOptions() {
|
||||
return this.#options;
|
||||
}
|
||||
}
|
||||
|
||||
export class AirUnitMarker extends UnitMarker {
|
||||
getVisibility() {
|
||||
if (this.getAlive())
|
||||
{
|
||||
if (this.getSelected())
|
||||
return "full";
|
||||
else if (this.getHuman())
|
||||
return AirUnit.getVisibility().human;
|
||||
else if (this.getAI())
|
||||
return AirUnit.getVisibility().ai;
|
||||
else
|
||||
return AirUnit.getVisibility().uncontrolled;
|
||||
}
|
||||
else
|
||||
return "minimal";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class AircraftMarker extends AirUnitMarker {
|
||||
getUnitImage()
|
||||
{
|
||||
return new Image().src = "images/units/" + getAircrafImage(this.getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class HelicopterMarker extends AirUnitMarker {
|
||||
getUnitImage()
|
||||
{
|
||||
return new Image().src = "images/units/airUnit.png"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class GroundUnitMarker extends UnitMarker {
|
||||
/* Are user driven units recognized as human? */
|
||||
getVisibility() {
|
||||
if (this.getAlive())
|
||||
{
|
||||
if (this.getSelected())
|
||||
return "full";
|
||||
else if (this.getHuman())
|
||||
return GroundUnit.getVisibility().human;
|
||||
else if (this.getAI())
|
||||
return GroundUnit.getVisibility().ai;
|
||||
else
|
||||
return GroundUnit.getVisibility().uncontrolled;
|
||||
}
|
||||
else
|
||||
return "minimal";
|
||||
}
|
||||
|
||||
getUnitImage()
|
||||
{
|
||||
return new Image().src = "images/units/groundUnit.png"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class NavyUnitMarker extends UnitMarker {
|
||||
getVisibility() {
|
||||
if (this.getAlive())
|
||||
{
|
||||
if (this.getSelected())
|
||||
return "full";
|
||||
else if (this.getHuman())
|
||||
return NavyUnit.getVisibility().human;
|
||||
else if (this.getAI())
|
||||
return NavyUnit.getVisibility().ai;
|
||||
else
|
||||
return NavyUnit.getVisibility().uncontrolled;
|
||||
}
|
||||
else
|
||||
return "minimal";
|
||||
}
|
||||
|
||||
getUnitImage()
|
||||
{
|
||||
return new Image().src = "images/units/navyUnit.png"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class WeaponMarker extends UnitMarker {
|
||||
getVisibility() {
|
||||
if (this.getAlive())
|
||||
{
|
||||
if (this.getSelected())
|
||||
return "full";
|
||||
else if (this.getHuman())
|
||||
return Weapon.getVisibility().human;
|
||||
else if (this.getAI())
|
||||
return Weapon.getVisibility().ai;
|
||||
else
|
||||
return Weapon.getVisibility().uncontrolled;
|
||||
}
|
||||
else
|
||||
return "minimal";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class BombMarker extends WeaponMarker {
|
||||
getUnitImage()
|
||||
{
|
||||
return new Image().src = "images/units/bomb.png"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class MissileMarker extends WeaponMarker {
|
||||
getUnitImage()
|
||||
{
|
||||
return new Image().src = "images/units/missile.png"
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
import { LatLng, LatLngBounds } from "leaflet";
|
||||
import { getMap, getUnitControlPanel, getUnitInfoPanel } from "..";
|
||||
import { Unit, GroundUnit } from "./unit";
|
||||
import { cloneUnit } from "../dcs/dcs";
|
||||
import { cloneUnit } from "../server/server";
|
||||
|
||||
export class UnitsManager {
|
||||
#units: { [ID: number]: Unit };
|
||||
@ -40,19 +40,11 @@ export class UnitsManager {
|
||||
return this.#units;
|
||||
}
|
||||
|
||||
addUnit(ID: number, data: any) {
|
||||
addUnit(ID: number, data: UnitData) {
|
||||
/* 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.flags.Human,
|
||||
coalitionID: data.coalitionID,
|
||||
type: data.type,
|
||||
AI: data.AI
|
||||
}
|
||||
this.#units[ID] = new constructor(ID, options);
|
||||
this.#units[ID] = new constructor(ID, data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,13 +72,13 @@ export class UnitsManager {
|
||||
this.#units[ID]?.setSelected(true);
|
||||
}
|
||||
|
||||
update(data: any) {
|
||||
for (let ID in data["units"]) {
|
||||
update(data: ServerData) {
|
||||
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.addUnit(parseInt(ID), data.units[ID]);
|
||||
}
|
||||
this.#units[parseInt(ID)].update(data["units"][ID]);
|
||||
this.#units[parseInt(ID)].update(data.units[ID]);
|
||||
}
|
||||
|
||||
/* Update the unit info panel */
|
||||
@ -124,7 +116,7 @@ export class UnitsManager {
|
||||
{
|
||||
if (this.#units[ID].getHidden() == false)
|
||||
{
|
||||
var latlng = new LatLng(this.#units[ID].latitude, this.#units[ID].longitude);
|
||||
var latlng = new LatLng(this.#units[ID].getFlightData().latitude, this.#units[ID].getFlightData().longitude);
|
||||
if (bounds.contains(latlng))
|
||||
{
|
||||
this.#units[ID].setSelected(true);
|
||||
@ -148,9 +140,9 @@ export class UnitsManager {
|
||||
for (let idx in this.getSelectedUnits())
|
||||
{
|
||||
var unit = this.getSelectedUnits()[idx];
|
||||
if (unit.isLeader)
|
||||
if (unit.getFormationData().isLeader)
|
||||
leaders.push(unit);
|
||||
else if (unit.isWingman)
|
||||
else if (unit.getFormationData().isWingman)
|
||||
{
|
||||
var leader = unit.getLeader();
|
||||
if (leader && !leaders.includes(leader))
|
||||
@ -165,7 +157,7 @@ export class UnitsManager {
|
||||
for (let idx in this.getSelectedUnits())
|
||||
{
|
||||
var unit = this.getSelectedUnits()[idx];
|
||||
if (!unit.isLeader && !unit.isWingman)
|
||||
if (!unit.getFormationData().isLeader && !unit.getFormationData().isWingman)
|
||||
singletons.push(unit);
|
||||
}
|
||||
return singletons;
|
||||
@ -290,12 +282,12 @@ export class UnitsManager {
|
||||
var wingmenIDs = [];
|
||||
for (let idx in selectedUnits)
|
||||
{
|
||||
if (selectedUnits[idx].isWingman)
|
||||
if (selectedUnits[idx].getFormationData().isWingman)
|
||||
{
|
||||
//console.log(selectedUnits[idx].unitName + " is already in a formation.");
|
||||
return;
|
||||
}
|
||||
else if (selectedUnits[idx].isLeader)
|
||||
else if (selectedUnits[idx].getFormationData().isLeader)
|
||||
{
|
||||
//console.log(selectedUnits[idx].unitName + " is already in a formation.");
|
||||
return;
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
<div class="ol-panel" id="unit-control-panel">
|
||||
<!--
|
||||
|
||||
<div id="ol-title-label">Selected units</div>
|
||||
|
||||
<div id="selected-units-container" class="ol-scrollable">
|
||||
-->
|
||||
|
||||
<!-- This is where all the unit selection buttons will be shown-->
|
||||
<!--
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!--
|
||||
<div id="formation-creation-container" data-feature-switch="ai-formations">
|
||||
<div class="rectangular-button white" id="create-formation"><img src="images\buttons\create.svg">Create formation</div>
|
||||
<div class="rectangular-button white" id="undo-formation"><img src="images\buttons\erase.svg">Undo formation</div>
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
<<<<<<< HEAD
|
||||
Olympus.unitPayloads = {
|
||||
["A-10A"] = { ["MK-84*2 , LAU-68*2 , AGM-65K*2"] = { [1] = { ["CLSID"] = "{6D21ECEA-F85B-4E8D-9D51-31DC9B8AA4EF}" },
|
||||
[2] = { ["CLSID"] = "{174C6E6D-0C3D-42ff-BCB3-0853CB371F5C}" },
|
||||
@ -25177,5 +25176,4 @@ Olympus.unitPayloads = {["A-10A"]={["MK-84*2 , LAU-68*2 , AGM-65K*2"]={[1] = {["
|
||||
[2] = {["CLSID"]="XM158_MK5"},
|
||||
[5] = {["CLSID"]="XM158_MK5"},
|
||||
[6] = {["CLSID"]="M134_R"}}},
|
||||
["UH-60A"]={}}
|
||||
>>>>>>> 433b4bdf569d0aca79794685ee41021190722f5b
|
||||
["UH-60A"]={}}
|
||||
@ -17,7 +17,7 @@ namespace SetCommandType {
|
||||
REACTION_ON_THREAT = 1,
|
||||
RADAR_USING = 3,
|
||||
FLARE_USING = 4,
|
||||
Formation = 5,
|
||||
FORMATION = 5,
|
||||
RTB_ON_BINGO = 6,
|
||||
SILENCE = 7,
|
||||
RTB_ON_OUT_OF_AMMO = 10,
|
||||
@ -56,9 +56,6 @@ namespace ReactionToThreat {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Base command class */
|
||||
class Command
|
||||
{
|
||||
@ -66,6 +63,7 @@ public:
|
||||
int getPriority() { return priority; }
|
||||
int getType() { return type; }
|
||||
virtual wstring getString(lua_State* L) = 0;
|
||||
virtual int getLoad() = 0;
|
||||
|
||||
protected:
|
||||
int priority = CommandPriority::LOW;
|
||||
@ -88,6 +86,7 @@ public:
|
||||
type = CommandType::MOVE;
|
||||
};
|
||||
virtual wstring getString(lua_State* L);
|
||||
virtual int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const int ID;
|
||||
@ -110,6 +109,7 @@ public:
|
||||
type = CommandType::SMOKE;
|
||||
};
|
||||
virtual wstring getString(lua_State* L);
|
||||
virtual int getLoad() { return 5; }
|
||||
|
||||
private:
|
||||
const wstring color;
|
||||
@ -129,6 +129,7 @@ public:
|
||||
type = CommandType::SPAWN_GROUND;
|
||||
};
|
||||
virtual wstring getString(lua_State* L);
|
||||
virtual int getLoad() { return 100; }
|
||||
|
||||
private:
|
||||
const wstring coalition;
|
||||
@ -150,8 +151,8 @@ public:
|
||||
priority = CommandPriority::LOW;
|
||||
type = CommandType::SPAWN_AIR;
|
||||
};
|
||||
|
||||
virtual wstring getString(lua_State* L);
|
||||
virtual int getLoad() { return 100; }
|
||||
|
||||
private:
|
||||
const wstring coalition;
|
||||
@ -173,6 +174,7 @@ public:
|
||||
type = CommandType::CLONE;
|
||||
};
|
||||
virtual wstring getString(lua_State* L);
|
||||
virtual int getLoad() { return 100; }
|
||||
|
||||
private:
|
||||
const int ID;
|
||||
@ -190,6 +192,7 @@ public:
|
||||
type = CommandType::CLONE;
|
||||
};
|
||||
virtual wstring getString(lua_State* L);
|
||||
virtual int getLoad() { return 20; }
|
||||
|
||||
private:
|
||||
const int ID;
|
||||
@ -207,6 +210,7 @@ public:
|
||||
type = CommandType::FOLLOW;
|
||||
};
|
||||
virtual wstring getString(lua_State* L);
|
||||
virtual int getLoad() { return 10; }
|
||||
|
||||
private:
|
||||
const int ID;
|
||||
@ -224,6 +228,7 @@ public:
|
||||
type = CommandType::RESET_TASK;
|
||||
};
|
||||
virtual wstring getString(lua_State* L);
|
||||
virtual int getLoad() { return 10; }
|
||||
|
||||
private:
|
||||
const int ID;
|
||||
@ -241,6 +246,7 @@ public:
|
||||
type = CommandType::RESET_TASK;
|
||||
};
|
||||
virtual wstring getString(lua_State* L);
|
||||
virtual int getLoad() { return 10; }
|
||||
|
||||
private:
|
||||
const int ID;
|
||||
@ -260,6 +266,7 @@ public:
|
||||
type = CommandType::RESET_TASK;
|
||||
};
|
||||
virtual wstring getString(lua_State* L);
|
||||
virtual int getLoad() { return 10; }
|
||||
|
||||
private:
|
||||
const int ID;
|
||||
|
||||
@ -15,5 +15,6 @@ public:
|
||||
|
||||
private:
|
||||
list<Command*> commands;
|
||||
int load;
|
||||
};
|
||||
|
||||
|
||||
@ -7,9 +7,10 @@
|
||||
|
||||
extern UnitsManager* unitsManager;
|
||||
|
||||
Scheduler::Scheduler(lua_State* L)
|
||||
Scheduler::Scheduler(lua_State* L):
|
||||
load(0)
|
||||
{
|
||||
LogInfo(L, "Units Factory constructor called successfully");
|
||||
LogInfo(L, "Scheduler constructor called successfully");
|
||||
}
|
||||
|
||||
Scheduler::~Scheduler()
|
||||
@ -24,6 +25,13 @@ void Scheduler::appendCommand(Command* command)
|
||||
|
||||
void Scheduler::execute(lua_State* L)
|
||||
{
|
||||
/* Decrease the active computation load. New commands can be sent only if the load has reached 0.
|
||||
This is needed to avoid server lag. */
|
||||
if (load > 0) {
|
||||
load--;
|
||||
return;
|
||||
}
|
||||
|
||||
int priority = CommandPriority::HIGH;
|
||||
while (priority >= CommandPriority::LOW)
|
||||
{
|
||||
@ -33,9 +41,8 @@ void Scheduler::execute(lua_State* L)
|
||||
{
|
||||
wstring commandString = L"Olympus.protectedCall(" + command->getString(L) + L")";
|
||||
if (dostring_in(L, "server", to_string(commandString)))
|
||||
{
|
||||
log(L"Error executing command " + commandString);
|
||||
}
|
||||
load = command->getLoad();
|
||||
commands.remove(command);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -61,15 +61,11 @@ void Unit::updateExportData(json::value json)
|
||||
/* All units which contain the name "Olympus" are automatically under AI control */
|
||||
/* TODO: I don't really like using this method */
|
||||
if (unitName.find(L"Olympus") != wstring::npos)
|
||||
{
|
||||
AI = true;
|
||||
}
|
||||
|
||||
/* If the unit is alive and it is not a human, run the AI Loop that performs the requested commands and instructions (moving, attacking, etc) */
|
||||
if (AI && alive && flags[L"Human"].as_bool() == false)
|
||||
{
|
||||
AIloop();
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::updateMissionData(json::value json)
|
||||
@ -88,44 +84,56 @@ json::value Unit::json()
|
||||
{
|
||||
auto json = json::value::object();
|
||||
|
||||
json[L"alive"] = alive;
|
||||
/********** Base data **********/
|
||||
json[L"AI"] = AI;
|
||||
json[L"name"] = json::value::string(name);
|
||||
json[L"unitName"] = json::value::string(unitName);
|
||||
json[L"groupName"] = json::value::string(groupName);
|
||||
json[L"type"] = type;
|
||||
json[L"country"] = country;
|
||||
json[L"coalitionID"] = coalitionID;
|
||||
json[L"latitude"] = latitude;
|
||||
json[L"longitude"] = longitude;
|
||||
json[L"altitude"] = altitude;
|
||||
json[L"speed"] = speed;
|
||||
json[L"heading"] = heading;
|
||||
json[L"flags"] = flags;
|
||||
json[L"alive"] = alive;
|
||||
json[L"category"] = json::value::string(getCategory());
|
||||
json[L"currentTask"] = json::value::string(getCurrentTask());
|
||||
json[L"isLeader"] = isLeader;
|
||||
json[L"isWingman"] = isWingman;
|
||||
json[L"formation"] = json::value::string(formation);
|
||||
json[L"fuel"] = fuel;
|
||||
json[L"ammo"] = ammo;
|
||||
json[L"targets"] = targets;
|
||||
json[L"targetSpeed"] = getTargetSpeed();
|
||||
json[L"targetAltitude"] = getTargetAltitude();
|
||||
json[L"hasTask"] = hasTask;
|
||||
json[L"ROE"] = json::value::string(ROE);
|
||||
json[L"reactionToThreat"] = json::value::string(reactionToThreat);
|
||||
|
||||
/********** Flight data **********/
|
||||
json[L"flightData"] = json::value::object();
|
||||
json[L"flightData"][L"latitude"] = latitude;
|
||||
json[L"flightData"][L"longitude"] = longitude;
|
||||
json[L"flightData"][L"altitude"] = altitude;
|
||||
json[L"flightData"][L"speed"] = speed;
|
||||
json[L"flightData"][L"heading"] = heading;
|
||||
|
||||
/********** Mission data **********/
|
||||
json[L"missionData"] = json::value::object();
|
||||
json[L"missionData"][L"fuel"] = fuel;
|
||||
json[L"missionData"][L"ammo"] = ammo;
|
||||
json[L"missionData"][L"targets"] = targets;
|
||||
json[L"missionData"][L"hasTask"] = hasTask;
|
||||
if (coalitionID == 0)
|
||||
json[L"missionData"][L"coalition"] = json::value::string(L"neutral");
|
||||
else if (coalitionID == 1)
|
||||
json[L"missionData"][L"coalition"] = json::value::string(L"red");
|
||||
else
|
||||
json[L"missionData"][L"coalition"] = json::value::string(L"blue");
|
||||
json[L"missionData"][L"flags"] = flags;
|
||||
|
||||
/********** Formation data **********/
|
||||
json[L"formationData"] = json::value::object();
|
||||
json[L"formationData"][L"isLeader"] = isLeader;
|
||||
json[L"formationData"][L"isWingman"] = isWingman;
|
||||
json[L"formationData"][L"formation"] = json::value::string(formation);
|
||||
int i = 0;
|
||||
for (auto itr = wingmen.begin(); itr != wingmen.end(); itr++)
|
||||
json[L"wingmenIDs"][i++] = (*itr)->getID();
|
||||
json[L"formationData"][L"wingmenIDs"][i++] = (*itr)->getID();
|
||||
|
||||
if (leader != nullptr)
|
||||
json[L"leaderID"] = leader->getID();
|
||||
json[L"formationData"][L"leaderID"] = leader->getID();
|
||||
|
||||
/********** Task data **********/
|
||||
json[L"taskData"] = json::value::object();
|
||||
json[L"taskData"][L"currentTask"] = json::value::string(getCurrentTask());
|
||||
json[L"taskData"][L"targetSpeed"] = getTargetSpeed();
|
||||
json[L"taskData"][L"targetAltitude"] = getTargetAltitude();
|
||||
/* Send the active path as a json object */
|
||||
auto path = json::value::object();
|
||||
if (activePath.size() > 0) {
|
||||
auto path = json::value::object();
|
||||
int count = 1;
|
||||
for (auto& destination : activePath)
|
||||
{
|
||||
@ -135,8 +143,13 @@ json::value Unit::json()
|
||||
json[L"alt"] = destination.alt;
|
||||
path[to_wstring(count++)] = json;
|
||||
}
|
||||
json[L"activePath"] = path;
|
||||
}
|
||||
json[L"taskData"][L"activePath"] = path;
|
||||
|
||||
/********** Options data **********/
|
||||
json[L"optionsData"] = json::value::object();
|
||||
json[L"optionsData"][L"ROE"] = json::value::string(ROE);
|
||||
json[L"optionsData"][L"reactionToThreat"] = json::value::string(reactionToThreat);
|
||||
|
||||
return json;
|
||||
}
|
||||
@ -178,7 +191,6 @@ bool Unit::isTargetAlive()
|
||||
return false;
|
||||
}
|
||||
|
||||
/* This function reset the activation so that the AI lopp will call again the MoveCommand. This is useful to change speed and altitude, for example */
|
||||
void Unit::resetActiveDestination()
|
||||
{
|
||||
activeDestination = Coords(NULL);
|
||||
|
||||
@ -60,21 +60,17 @@ extern "C" DllExport int coreFrame(lua_State* L)
|
||||
|
||||
const std::chrono::duration<double> duration = std::chrono::system_clock::now() - before;
|
||||
|
||||
// TODO make intervals editable
|
||||
/* TODO make intervals editable */
|
||||
if (duration.count() > UPDATE_TIME_INTERVAL)
|
||||
{
|
||||
if (unitsManager != nullptr)
|
||||
{
|
||||
unitsManager->updateExportData(L);
|
||||
}
|
||||
|
||||
// TODO allow for different intervals
|
||||
if (scheduler != nullptr)
|
||||
{
|
||||
scheduler->execute(L);
|
||||
}
|
||||
before = std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
if (scheduler != nullptr)
|
||||
scheduler->execute(L);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user