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:
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;
|
||||
|
||||
Reference in New Issue
Block a user