Merge pull request #230 from Pax1601/218-add-humandcs-controlledolympus-controller-icon

218 add humandcs controlledolympus controller icon
This commit is contained in:
Pax1601
2023-04-28 15:43:22 +02:00
committed by GitHub
25 changed files with 4566 additions and 84 deletions

View File

@@ -8,7 +8,7 @@ export class AICFormation_Single extends AICFormation implements AICFormationInt
"name" = "single";
"numGroups" = 1;
"summary" = "One contact on its own";
"unitBreakdown" = [];
"unitBreakdown": string[] = [];
constructor() {

View File

@@ -46,7 +46,7 @@ class ATCDataHandler {
startUpdates() {
this.#updateInterval = setInterval( () => {
this.#updateInterval = window.setInterval( () => {
const aBoardIsVisible = this.#atc.getBoards().some( board => board.boardIsVisible() );

View File

@@ -83,7 +83,7 @@ export abstract class ATCBoard {
});
setInterval( () => {
window.setInterval( () => {
this.updateClock();
}, 1000 );
@@ -206,7 +206,7 @@ export abstract class ATCBoard {
this.#strips[ flightId ].element.remove();
this.#strips[ flightId ].isDeleted = true;
setTimeout( () => {
window.setTimeout( () => {
delete this.#strips[ flightId ];
}, 10000 );
@@ -326,7 +326,7 @@ export abstract class ATCBoard {
resetSuggestions();
searchTimeout = setTimeout( () => {
searchTimeout = window.setTimeout( () => {
const searchString = unitName.value.toLowerCase();
@@ -408,7 +408,7 @@ export abstract class ATCBoard {
return;
}
this.#updateInterval = setInterval( () => {
this.#updateInterval = window.setInterval( () => {
this.update();

View File

@@ -90,10 +90,8 @@ function readConfig(config: any)
{
const address = config["server"]["address"];
const port = config["server"]["port"];
if ((typeof address === 'string' || address instanceof String) && typeof port == 'number')
{
setAddress(window.location.hostname, <number>port);
}
if (typeof address === 'string' && typeof port == 'number')
setAddress(address == "*"? window.location.hostname: address, <number>port);
/* On the first connection, force request of full data */
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
@@ -122,7 +120,7 @@ function requestUpdate() {
checkSessionHash(data.sessionHash);
}
}, false);
setTimeout(() => requestUpdate(), getConnected() ? 250 : 1000);
window.setTimeout(() => requestUpdate(), getConnected() ? 250 : 1000);
getConnectionStatusPanel()?.update(getConnected());
}
@@ -134,7 +132,9 @@ function requestRefresh() {
getUnitsManager()?.update(data);
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
getBullseyes((data: BullseyesData) => getMissionData()?.update(data));
getMission((data: any) => {getMissionData()?.update(data)});
getMission((data: any) => {
getMissionData()?.update(data)
});
// Update the list of existing units
getUnitDataTable()?.update();
@@ -142,7 +142,7 @@ function requestRefresh() {
checkSessionHash(data.sessionHash);
}
}, true);
setTimeout(() => requestRefresh(), 5000);
window.setTimeout(() => requestRefresh(), 5000);
}
function checkSessionHash(newSessionHash: string) {

View File

@@ -114,7 +114,7 @@ export var BoxSelect = Handler.extend({
if (!this._moved) { return; }
// Postpone to next JS tick so internal click event handling
// still see it as "moved".
setTimeout(Util.bind(this._resetState, this), 0);
window.setTimeout(Util.bind(this._resetState, this), 0);
var bounds = new LatLngBounds(
this._map.containerPointToLatLng(this._startPoint),
this._map.containerPointToLatLng(this._point));

View File

@@ -1,4 +1,6 @@
import * as L from "leaflet"
import { MiniMap, MiniMapOptions } from "leaflet-control-mini-map";
import { getUnitsManager } from "..";
import { BoxSelect } from "./boxselect";
import { MapContextMenu } from "../controls/mapcontextmenu";
@@ -8,18 +10,35 @@ import { Dropdown } from "../controls/dropdown";
import { Airbase } from "../missionhandler/airbase";
import { Unit } from "../units/unit";
// TODO a bit of a hack, this module is provided as pure javascript only
require("../../node_modules/leaflet.nauticscale/dist/leaflet.nauticscale.js")
export const IDLE = "IDLE";
export const MOVE_UNIT = "MOVE_UNIT";
L.Map.addInitHook('addHandler', 'boxSelect', BoxSelect);
export class ClickableMiniMap extends MiniMap {
constructor(layer: L.TileLayer | L.LayerGroup, options?: MiniMapOptions)
{
super(layer, options);
}
getMap() {
//@ts-ignore needed to access not exported member. A bit of a hack, required to access click events
return this._miniMap;
}
}
export class Map extends L.Map {
#state: string;
#layer: L.TileLayer | null = null;
#preventLeftClick: boolean = false;
#leftClickTimer: number = 0;
#leftClickTimer: any = 0;
#lastMousePosition: L.Point = new L.Point(0, 0);
#centerUnit: Unit | null = null;
#miniMap: ClickableMiniMap | null = null;
#miniMapLayerGroup: L.LayerGroup;
#mapContextMenu: MapContextMenu = new MapContextMenu("map-contextmenu");
#unitContextMenu: UnitContextMenu = new UnitContextMenu("unit-contextmenu");
@@ -30,11 +49,59 @@ export class Map extends L.Map {
constructor(ID: string) {
/* Init the leaflet map */
//@ts-ignore
super(ID, { doubleClickZoom: false, zoomControl: false, boxZoom: false, boxSelect: true, zoomAnimation: false });
this.setView([37.23, -115.8], 12);
super(ID, { doubleClickZoom: false, zoomControl: false, boxZoom: false, boxSelect: true, zoomAnimation: true, maxBoundsViscosity: 1.0, minZoom: 7 });
this.setView([37.23, -115.8], 10);
this.setLayer("ArcGIS Satellite");
/* Minimap */
/* Draw the limits of the maps in the minimap*/
var latlngs = [[ // NTTR
new L.LatLng(39.7982463, -119.985425 ),
new L.LatLng(34.4037128, -119.7806729),
new L.LatLng(34.3483316, -112.4529351),
new L.LatLng(39.7372411, -112.1130805),
new L.LatLng(39.7982463, -119.985425 )
],
[ // Syria
new L.LatLng(37.3630556, 29.2686111),
new L.LatLng(31.8472222, 29.8975),
new L.LatLng(32.1358333, 42.1502778),
new L.LatLng(37.7177778, 42.3716667),
new L.LatLng(37.3630556, 29.2686111)
],
[ // Caucasus
new L.LatLng(39.6170191, 27.634935),
new L.LatLng(38.8735863, 47.1423108),
new L.LatLng(47.3907982, 49.3101946),
new L.LatLng(48.3955879, 26.7753625),
new L.LatLng(39.6170191, 27.634935)
],
[ // Persian Gulf
new L.LatLng(32.9355285, 46.5623682),
new L.LatLng(21.729393, 47.572675),
new L.LatLng(21.8501348, 63.9734737),
new L.LatLng(33.131584, 64.7313594),
new L.LatLng(32.9355285, 46.5623682)
],
[ // Marianas
new L.LatLng(22.09, 135.0572222),
new L.LatLng(10.5777778, 135.7477778),
new L.LatLng(10.7725, 149.3918333),
new L.LatLng(22.5127778, 149.5427778),
new L.LatLng(22.09, 135.0572222)
]
];
var minimapLayer = new L.TileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', { minZoom: 0, maxZoom: 13 });
this.#miniMapLayerGroup = new L.LayerGroup([minimapLayer]);
var miniMapPolyline = new L.Polyline(latlngs, {color: '#202831'});
miniMapPolyline.addTo(this.#miniMapLayerGroup);
/* Scale */
//@ts-ignore TODO more hacking because the module is provided as a pure javascript module only
L.control.scalenautic({position: "topright", maxWidth: 300, nautic: true, metric: true, imperial: false}).addTo(this);
/* Init the state machine */
this.#state = IDLE;
@@ -198,12 +265,11 @@ export class Map extends L.Map {
}
/* Spawn from air base */
spawnFromAirbase(e: any)
{
spawnFromAirbase(e: any) {
//this.#aircraftSpawnMenu(e);
}
centerOnUnit(ID: number | null){
centerOnUnit(ID: number | null) {
if (ID != null)
{
this.options.scrollWheelZoom = 'center';
@@ -215,6 +281,47 @@ export class Map extends L.Map {
}
}
setTheatre(theatre: string) {
var bounds = new L.LatLngBounds([-90, -180], [90, 180]);
var miniMapZoom = 5;
if (theatre == "Syria")
bounds = new L.LatLngBounds([31.8472222, 29.8975], [37.7177778, 42.3716667]);
else if (theatre == "MarianaIslands")
bounds = new L.LatLngBounds([10.5777778, 135.7477778], [22.5127778, 149.5427778]);
else if (theatre == "Nevada")
bounds = new L.LatLngBounds([34.4037128, -119.7806729], [39.7372411, -112.1130805])
else if (theatre == "PersianGulf")
bounds = new L.LatLngBounds([21.729393, 47.572675], [33.131584, 64.7313594])
else if (theatre == "Falklands")
{
// TODO
}
else if (theatre == "Caucasus")
{
bounds = new L.LatLngBounds([39.6170191, 27.634935], [47.3907982, 49.3101946])
miniMapZoom = 4;
}
this.setView(bounds.getCenter(), 8);
this.setMaxBounds(bounds);
if (this.#miniMap)
this.#miniMap.remove();
//@ts-ignore // Needed because some of the inputs are wrong in the original module interface
this.#miniMap = new ClickableMiniMap(this.#miniMapLayerGroup, {position: "topright", width: 192*1.5, height: 108*1.5, zoomLevelFixed: miniMapZoom, centerFixed: bounds.getCenter()}).addTo(this);
this.#miniMap.disableInteractivity();
this.#miniMap.getMap().on("click", (e: any) => {
if (this.#miniMap)
this.setView(e.latlng);
})
}
getMiniMapLayerGroup() {
return this.#miniMapLayerGroup;
}
/* Event handlers */
#onClick(e: any) {
if (!this.#preventLeftClick) {
@@ -252,7 +359,7 @@ export class Map extends L.Map {
{
clearTimeout(this.#leftClickTimer);
this.#preventLeftClick = true;
this.#leftClickTimer = setTimeout(() => {
this.#leftClickTimer = window.setTimeout(() => {
this.#preventLeftClick = false;
}, 200);
getUnitsManager().selectFromBounds(e.selectionBounds);

View File

@@ -1,5 +1,5 @@
import { Marker, LatLng, Icon } from "leaflet";
import { getInfoPopup, getMap, getUnitsManager } from "..";
import { getInfoPopup, getMap } from "..";
import { Airbase } from "./airbase";
var bullseyeIcons = [
@@ -43,21 +43,10 @@ export class MissionHandler
if ("mission" in data)
{
if (data.mission.theatre != this.#theatre)
if (data.mission != null && data.mission.theatre != this.#theatre)
{
this.#theatre = data.mission.theatre
if (this.#theatre == "Syria")
getMap().setView(new LatLng(34.5, 36.0), 8);
else if (this.#theatre == "MarianaIslands")
getMap().setView(new LatLng(16.7, 145.7), 7);
else if (this.#theatre == "Nevada")
getMap().setView(new LatLng(37.1, -115.2), 8);
else if (this.#theatre == "PersianGulf")
getMap().setView(new LatLng(26.5, 55.3), 8);
else if (this.#theatre == "Falklands")
getMap().setView(new LatLng(-50.6, -42.7), 7);
else if (this.#theatre == "Caucasus")
getMap().setView(new LatLng(42.1, 42.3), 8);
this.#theatre = data.mission.theatre;
getMap().setTheatre(this.#theatre);
getInfoPopup().setText("Map set to " + this.#theatre);
}

View File

@@ -82,7 +82,7 @@ export class MouseInfoPanel extends Panel {
el.dataset.bearing = zeroAppend(Math.floor(bear), 3);
el.dataset.distance = zeroAppend(Math.floor(dist*0.000539957), 3);
el.dataset.distanceUnits = "nm";
el.dataset.distanceUnits = "NM";
}
}
@@ -176,7 +176,7 @@ export class MouseInfoPanel extends Panel {
bng = "360";
}
let data = [ `${bng}°`, `${Math.floor(dist*0.000539957)}nm`, `${reciprocal}°` ];
let data = [ `${bng}°`, `${Math.floor(dist*0.000539957)}NM`, `${reciprocal}°` ];
if ( bear < 180 ) {
data = data.reverse();
@@ -229,7 +229,7 @@ export class MouseInfoPanel extends Panel {
pos.dataset.bearing = "---";
pos.dataset.distance = "---";
pos.dataset.distanceUnits = "nm";
pos.dataset.distanceUnits = "NM";
}
}

View File

@@ -42,7 +42,7 @@ export class UnitInfoPanel extends Panel {
document.addEventListener("unitsSelection", (e: CustomEvent<Unit[]>) => this.#onUnitsSelection(e.detail));
document.addEventListener("unitsDeselection", (e: CustomEvent<Unit[]>) => this.#onUnitsDeselection(e.detail));
document.addEventListener("clearSelection", () => this.#onUnitsDeselection([]));
document.addEventListener("clearSelection", (e: CustomEvent<Unit[]>) => this.#onUnitsDeselection([]));
document.addEventListener("unitUpdated", (e: CustomEvent<Unit>) => this.#onUnitUpdate(e.detail));
this.hide();

View File

@@ -17,10 +17,10 @@ export class Popup extends Panel {
clearTimeout(this.#visibilityTimer);
clearTimeout(this.#hideTimer);
this.#visibilityTimer = setTimeout(() => {
this.#visibilityTimer = window.setTimeout(() => {
this.getElement().classList.remove("visible");
this.getElement().classList.add("invisible");
this.#hideTimer = setTimeout(() => this.hide(), 2000);
this.#hideTimer = window.setTimeout(() => this.hide(), 2000);
}, this.#fadeTime);
}
}

View File

@@ -18,12 +18,12 @@ export function toggleDemoEnabled()
demoEnabled = !demoEnabled;
}
export function GET(callback: CallableFunction, uri: string){
export function GET(callback: CallableFunction, uri: string, options?: string){
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", `${demoEnabled? DEMO_ADDRESS: REST_ADDRESS}/${uri}`, true);
xmlHttp.open("GET", `${demoEnabled? DEMO_ADDRESS: REST_ADDRESS}/${uri}${options? options: ''}`, true);
xmlHttp.onload = function (e) {
var data = JSON.parse(xmlHttp.responseText);
if (parseInt(data.time) > lastUpdateTime)
if (uri !== UNITS_URI || parseInt(data.time) > lastUpdateTime)
{
callback(data);
lastUpdateTime = parseInt(data.time);
@@ -84,7 +84,7 @@ export function getMission(callback: CallableFunction) {
}
export function getUnits(callback: CallableFunction, refresh: boolean = false) {
GET(callback, `${UNITS_URI}?time=${refresh? 0: lastUpdateTime}`);
GET(callback, `${UNITS_URI}`, `?time=${refresh? 0: lastUpdateTime}`);
}
export function addDestination(ID: number, path: any) {

View File

@@ -2064,8 +2064,8 @@ export class AircraftDatabase extends UnitDatabase {
],
"filename": "kc-135.png"
},
"KC-135MPRS": {
"name": "KC-135MPRS",
"KC135MPRS": {
"name": "KC135MPRS",
"label": "KC-135 MPRS Stratotanker",
"shortLabel": "135M",
"loadouts": [
@@ -2083,6 +2083,44 @@ export class AircraftDatabase extends UnitDatabase {
],
"filename": "kc-135.png"
},
"KC_10_Extender": {
"name": "KC_10_Extender",
"label": "KC-10 Extender",
"shortLabel": "KC10",
"loadouts": [
{
"fuel": 1,
"items": [
],
"roles": [
"Tanker"
],
"code": "",
"name": "Default Tanker"
}
],
"filename": "kc-10.png"
},
"KC_10_Extender_D": {
"name": "KC_10_Extender_D",
"label": "KC-10 Extender (Drogue)",
"shortLabel": "KC10",
"loadouts": [
{
"fuel": 1,
"items": [
],
"roles": [
"Tanker"
],
"code": "",
"name": "Default Tanker"
}
],
"filename": "kc-10.png"
},
"MiG-15bis": {
"name": "MiG-15bis",
"label": "MiG-15 Fagot",

View File

@@ -1,9 +1,10 @@
import { Marker, LatLng, Polyline, Icon, DivIcon } from 'leaflet';
import { Marker, LatLng, Polyline, Icon, DivIcon, CircleMarker } from 'leaflet';
import { getMap, getUnitsManager } from '..';
import { rad2deg } from '../other/utils';
import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, getUnits, landAt, setAltitude, setReactionToThreat, setROE, setSpeed, refuel, setAdvacedOptions, followUnit } from '../server/server';
import { aircraftDatabase } from './aircraftdatabase';
import { groundUnitsDatabase } from './groundunitsdatabase';
import { field } from 'geomag'
var pathIcon = new Icon({
iconUrl: 'images/marker-icon.png',
@@ -77,6 +78,7 @@ export class Unit extends Marker {
#pathMarkers: Marker[] = [];
#pathPolyline: Polyline;
#targetsPolylines: Polyline[];
#miniMapMarker: CircleMarker | null = null;
#timer: number = 0;
#forceUpdate: boolean = false;
@@ -107,11 +109,11 @@ export class Unit extends Marker {
/* Deselect units if they are hidden */
document.addEventListener("toggleCoalitionVisibility", (ev: CustomEventInit) => {
setTimeout(() => {this.setSelected(this.getSelected() && !this.getHidden())}, 300);
window.setTimeout(() => {this.setSelected(this.getSelected() && !this.getHidden())}, 300);
});
document.addEventListener("toggleUnitVisibility", (ev: CustomEventInit) => {
setTimeout(() => {this.setSelected(this.getSelected() && !this.getHidden())}, 300);
window.setTimeout(() => {this.setSelected(this.getSelected() && !this.getHidden())}, 300);
});
/* Set the unit data */
@@ -124,7 +126,6 @@ export class Unit extends Marker {
iconAnchor: [0, 0]
});
this.setIcon(icon);
}
getMarkerHTML() {
@@ -392,7 +393,7 @@ export class Unit extends Marker {
}
#onClick(e: any) {
this.#timer = setTimeout(() => {
this.#timer = window.setTimeout(() => {
if (!this.#preventClick) {
if (getMap().getState() === 'IDLE' || getMap().getState() === 'MOVE_UNIT' || e.originalEvent.ctrlKey) {
if (!e.originalEvent.ctrlKey) {
@@ -517,8 +518,33 @@ export class Unit extends Marker {
#updateMarker() {
this.updateVisibility();
if (!this.getHidden()) {
if (this.getBaseData().alive )
{
if (this.#miniMapMarker == null)
{
this.#miniMapMarker = new CircleMarker(new LatLng(this.getFlightData().latitude, this.getFlightData().longitude), {radius: 0.5});
if (this.getMissionData().coalition == "neutral")
this.#miniMapMarker.setStyle({color: "#CFD9E8"});
else if (this.getMissionData().coalition == "red")
this.#miniMapMarker.setStyle({color: "#ff5858"});
else
this.#miniMapMarker.setStyle({color: "#247be2"});
this.#miniMapMarker.addTo(getMap().getMiniMapLayerGroup());
this.#miniMapMarker.bringToBack();
}
else {
this.#miniMapMarker.setLatLng(new LatLng(this.getFlightData().latitude, this.getFlightData().longitude));
this.#miniMapMarker.bringToBack();
}
}
else {
if (this.#miniMapMarker != null && getMap().getMiniMapLayerGroup().hasLayer(this.#miniMapMarker)) {
getMap().getMiniMapLayerGroup().removeLayer(this.#miniMapMarker);
this.#miniMapMarker = null;
}
}
if (!this.getHidden()) {
this.setLatLng(new LatLng(this.getFlightData().latitude, this.getFlightData().longitude));
var element = this.getElement();
if (element != null) {
@@ -530,17 +556,20 @@ export class Unit extends Marker {
element.querySelector(".unit")?.toggleAttribute("data-is-dead", !this.getBaseData().alive);
element.querySelector(".unit")?.setAttribute("data-state", this.getTaskData().currentState.toLowerCase());
var unitHeadingDiv = element.querySelector(".unit-heading");
if (unitHeadingDiv != null)
unitHeadingDiv.innerHTML = String(Math.floor(rad2deg(this.getFlightData().heading)));
if (this.getMissionData().flags.Human) // Unit is human
element.querySelector(".unit")?.setAttribute("data-state", "human");
else if (!this.getBaseData().AI) // Unit is under DCS control (no Olympus)
element.querySelector(".unit")?.setAttribute("data-state", "dcs");
else // Unit is under Olympus control
element.querySelector(".unit")?.setAttribute("data-state", this.getTaskData().currentState.toLowerCase());
var unitAltitudeDiv = element.querySelector(".unit-altitude");
if (unitAltitudeDiv != null) {
unitAltitudeDiv.innerHTML = String(Math.floor(this.getFlightData().altitude / 0.3048 / 1000));
}
if (unitAltitudeDiv != null)
unitAltitudeDiv.innerHTML = "FL" + String(Math.floor(this.getFlightData().altitude / 0.3048 / 1000));
var unitSpeedDiv = element.querySelector(".unit-speed");
if (unitSpeedDiv != null)
unitSpeedDiv.innerHTML = String(Math.floor(this.getFlightData().speed * 1.94384 ) );
element.querySelectorAll( "[data-rotate-to-heading]" ).forEach( el => {
const headingDeg = rad2deg( this.getFlightData().heading );
@@ -548,9 +577,7 @@ export class Unit extends Marker {
el.setAttribute( "style", currentStyle + `transform:rotate(${headingDeg}deg);` );
});
var unitSpeedDiv = element.querySelector(".unit-speed");
if (unitSpeedDiv != null)
unitSpeedDiv.innerHTML = String(Math.floor(this.getFlightData().speed * 1.94384 ) );
}
var pos = getMap().latLngToLayerPoint(this.getLatLng()).round();

View File

@@ -68,7 +68,7 @@ export class UnitsManager {
Object.keys(data.units)
.filter((ID: string) => !(ID in this.#units))
.reduce((timeout: number, ID: string) => {
setTimeout(() => {
window.setTimeout(() => {
if (!(ID in this.#units))
this.addUnit(parseInt(ID), data.units[ID]);
this.#units[parseInt(ID)]?.setData(data.units[ID]);
@@ -330,7 +330,7 @@ export class UnitsManager {
this.#showActionMessage(this.#copiedUnits, `pasted`);
}
this.#pasteDisabled = true;
setTimeout(() => this.#pasteDisabled = false, 250);
window.setTimeout(() => this.#pasteDisabled = false, 250);
}
}
@@ -348,7 +348,7 @@ export class UnitsManager {
/* Disable the firing of the selection event for a certain amount of time. This avoids firing many events if many units are selected */
if (!this.#selectionEventDisabled)
{
setTimeout(() => {
window.setTimeout(() => {
document.dispatchEvent(new CustomEvent("unitsSelection", {detail: this.getSelectedUnits()}));
this.#selectionEventDisabled = false;
}, 100);