mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Completed advanced settings panel for tanker and AWACS
Reformatted files with larger width, reordered unused icons
This commit is contained in:
@@ -43,18 +43,8 @@ export const states: string[] = [
|
||||
"land-at-point",
|
||||
];
|
||||
export const ROEs: string[] = ["free", "designated", "", "return", "hold"];
|
||||
export const reactionsToThreat: string[] = [
|
||||
"none",
|
||||
"manoeuvre",
|
||||
"passive",
|
||||
"evade",
|
||||
];
|
||||
export const emissionsCountermeasures: string[] = [
|
||||
"silent",
|
||||
"attack",
|
||||
"defend",
|
||||
"free",
|
||||
];
|
||||
export const reactionsToThreat: string[] = ["none", "manoeuvre", "passive", "evade"];
|
||||
export const emissionsCountermeasures: string[] = ["silent", "attack", "defend", "free"];
|
||||
|
||||
export const ERAS = [
|
||||
{
|
||||
@@ -217,17 +207,11 @@ export const mapBounds = {
|
||||
zoom: 5,
|
||||
},
|
||||
MarianaIslands: {
|
||||
bounds: new LatLngBounds(
|
||||
[10.5777778, 135.7477778],
|
||||
[22.5127778, 149.5427778]
|
||||
),
|
||||
bounds: new LatLngBounds([10.5777778, 135.7477778], [22.5127778, 149.5427778]),
|
||||
zoom: 5,
|
||||
},
|
||||
Nevada: {
|
||||
bounds: new LatLngBounds(
|
||||
[34.4037128, -119.7806729],
|
||||
[39.7372411, -112.1130805]
|
||||
),
|
||||
bounds: new LatLngBounds([34.4037128, -119.7806729], [39.7372411, -112.1130805]),
|
||||
zoom: 5,
|
||||
},
|
||||
PersianGulf: {
|
||||
@@ -239,10 +223,7 @@ export const mapBounds = {
|
||||
zoom: 4,
|
||||
},
|
||||
Falklands: {
|
||||
bounds: new LatLngBounds(
|
||||
[-49.097217, -79.418267],
|
||||
[-56.874517, -43.316433]
|
||||
),
|
||||
bounds: new LatLngBounds([-49.097217, -79.418267], [-56.874517, -43.316433]),
|
||||
zoom: 3,
|
||||
},
|
||||
Normandy: { bounds: new LatLngBounds([50.44, -3.29], [48.12, 3.7]), zoom: 5 },
|
||||
@@ -269,8 +250,7 @@ export const IADSDensities: { [key: string]: number } = {
|
||||
"SAM Site": 0.1,
|
||||
"Radar (EWR)": 0.05,
|
||||
};
|
||||
export const GROUND_UNIT_AIR_DEFENCE_REGEX: RegExp =
|
||||
/(\b(AAA|SAM|MANPADS?|[mM]anpads?)|[sS]tinger\b)/;
|
||||
export const GROUND_UNIT_AIR_DEFENCE_REGEX: RegExp = /(\b(AAA|SAM|MANPADS?|[mM]anpads?)|[sS]tinger\b)/;
|
||||
|
||||
export const MAP_OPTIONS_TOOLTIPS = {
|
||||
hideGroupMembers: "Hide group members when zoomed out",
|
||||
@@ -293,7 +273,7 @@ export const MAP_OPTIONS_DEFAULTS = {
|
||||
showUnitsEngagementRings: true,
|
||||
showUnitsAcquisitionRings: true,
|
||||
fillSelectedRing: false,
|
||||
showMinimap: false
|
||||
showMinimap: false,
|
||||
} as MapOptions;
|
||||
|
||||
export const MAP_HIDDEN_TYPES_DEFAULTS = {
|
||||
|
||||
5
frontend/react/src/dom.d.ts
vendored
5
frontend/react/src/dom.d.ts
vendored
@@ -27,10 +27,7 @@ interface CustomEventMap {
|
||||
|
||||
declare global {
|
||||
interface Document {
|
||||
addEventListener<K extends keyof CustomEventMap>(
|
||||
type: K,
|
||||
listener: (this: Document, ev: CustomEventMap[K]) => void
|
||||
): void;
|
||||
addEventListener<K extends keyof CustomEventMap>(type: K, listener: (this: Document, ev: CustomEventMap[K]) => void): void;
|
||||
dispatchEvent<K extends keyof CustomEventMap>(ev: CustomEventMap[K]): void;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,10 +53,7 @@ export var BoxSelect = Handler.extend({
|
||||
},
|
||||
|
||||
_onMouseDown: function (e: any) {
|
||||
if (
|
||||
(e.which == 1 && e.button == 0 && (e.shiftKey || this._forceBoxSelect)) ||
|
||||
(e.type === "touchstart" && this._forceBoxSelect)
|
||||
) {
|
||||
if ((e.which == 1 && e.button == 0 && (e.shiftKey || this._forceBoxSelect)) || (e.type === "touchstart" && this._forceBoxSelect)) {
|
||||
this._map.fire("selectionstart");
|
||||
// Clear the deferred resetState if it hasn't executed yet, otherwise it
|
||||
// will interrupt the interaction and orphan a box element in the container.
|
||||
@@ -67,10 +64,8 @@ export var BoxSelect = Handler.extend({
|
||||
DomUtil.disableImageDrag();
|
||||
this._map.dragging.disable();
|
||||
|
||||
if (e.type === "touchstart")
|
||||
this._startPoint = this._map.mouseEventToContainerPoint(e.touches[0]);
|
||||
else
|
||||
this._startPoint = this._map.mouseEventToContainerPoint(e);
|
||||
if (e.type === "touchstart") this._startPoint = this._map.mouseEventToContainerPoint(e.touches[0]);
|
||||
else this._startPoint = this._map.mouseEventToContainerPoint(e);
|
||||
|
||||
DomEvent.on(
|
||||
//@ts-ignore
|
||||
@@ -101,10 +96,8 @@ export var BoxSelect = Handler.extend({
|
||||
this._map.fire("boxzoomstart");
|
||||
}
|
||||
|
||||
if (e.type === "touchmove")
|
||||
this._point = this._map.mouseEventToContainerPoint(e.touches[0]);
|
||||
else
|
||||
this._point = this._map.mouseEventToContainerPoint(e);
|
||||
if (e.type === "touchmove") this._point = this._map.mouseEventToContainerPoint(e.touches[0]);
|
||||
else this._point = this._map.mouseEventToContainerPoint(e);
|
||||
|
||||
var bounds = new Bounds(this._point, this._startPoint),
|
||||
size = bounds.getSize();
|
||||
@@ -154,10 +147,7 @@ export var BoxSelect = Handler.extend({
|
||||
// Postpone to next JS tick so internal click event handling
|
||||
// still see it as "moved".
|
||||
window.setTimeout(Util.bind(this._resetState, this), 0);
|
||||
var bounds = new LatLngBounds(
|
||||
this._map.containerPointToLatLng(this._startPoint),
|
||||
this._map.containerPointToLatLng(this._point)
|
||||
);
|
||||
var bounds = new LatLngBounds(this._map.containerPointToLatLng(this._startPoint), this._map.containerPointToLatLng(this._point));
|
||||
|
||||
this._forceBoxSelect = false;
|
||||
this._map.fire("selectionend", { selectionBounds: bounds });
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
const CoalitionArea = Base => class extends Base {
|
||||
|
||||
}
|
||||
|
||||
export CoalitionArea;
|
||||
@@ -7,7 +7,7 @@ export class CoalitionAreaHandle extends CustomMarker {
|
||||
|
||||
this.on("add", (e) => {
|
||||
this.getElement()?.addEventListener("touchstart", (e) => e.stopPropagation());
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
createIcon() {
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
import {
|
||||
LatLngExpression,
|
||||
Map,
|
||||
Circle,
|
||||
DivIcon,
|
||||
Marker,
|
||||
CircleOptions,
|
||||
LatLng,
|
||||
} from "leaflet";
|
||||
import { LatLngExpression, Map, Circle, DivIcon, Marker, CircleOptions, LatLng } from "leaflet";
|
||||
import { getApp } from "../../olympusapp";
|
||||
import { CoalitionAreaHandle } from "./coalitionareahandle";
|
||||
import { BLUE_COMMANDER, RED_COMMANDER } from "../../constants/constants";
|
||||
@@ -38,11 +30,7 @@ export class CoalitionCircle extends Circle {
|
||||
|
||||
this.#labelText = `Circle ${totalAreas}`;
|
||||
|
||||
if (
|
||||
[BLUE_COMMANDER, RED_COMMANDER].includes(
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode
|
||||
)
|
||||
)
|
||||
if ([BLUE_COMMANDER, RED_COMMANDER].includes(getApp().getMissionManager().getCommandModeOptions().commandMode))
|
||||
this.setCoalition(getApp().getMissionManager().getCommandedCoalition());
|
||||
|
||||
this.on("drag", () => {
|
||||
@@ -129,14 +117,8 @@ export class CoalitionCircle extends Circle {
|
||||
if (this.#radiusHandle) this.#radiusHandle.removeFrom(getApp().getMap());
|
||||
|
||||
if (this.#selected) {
|
||||
const dest = turf.destination(
|
||||
turf.point([this.getLatLng().lng, this.getLatLng().lat]),
|
||||
this.getRadius() / 1000,
|
||||
0
|
||||
);
|
||||
this.#radiusHandle = new CoalitionAreaHandle(
|
||||
new LatLng(dest.geometry.coordinates[1], dest.geometry.coordinates[0])
|
||||
);
|
||||
const dest = turf.destination(turf.point([this.getLatLng().lng, this.getLatLng().lat]), this.getRadius() / 1000, 0);
|
||||
this.#radiusHandle = new CoalitionAreaHandle(new LatLng(dest.geometry.coordinates[1], dest.geometry.coordinates[0]));
|
||||
this.#radiusHandle.addTo(getApp().getMap());
|
||||
this.#radiusHandle.on("drag", (e: any) => {
|
||||
this.setRadius(this.getLatLng().distanceTo(e.latlng));
|
||||
@@ -156,11 +138,6 @@ export class CoalitionCircle extends Circle {
|
||||
}),
|
||||
interactive: false,
|
||||
}).addTo(this._map);
|
||||
this.#label
|
||||
.getElement()
|
||||
?.classList.add(
|
||||
`ol-coalitionarea-label`,
|
||||
`${this.#selected ? "selected" : `${this.#coalition}`}`
|
||||
);
|
||||
this.#label.getElement()?.classList.add(`ol-coalitionarea-label`, `${this.#selected ? "selected" : `${this.#coalition}`}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
import {
|
||||
LatLng,
|
||||
LatLngExpression,
|
||||
Map,
|
||||
Point,
|
||||
Polygon,
|
||||
PolylineOptions,
|
||||
DivIcon,
|
||||
Marker
|
||||
} from "leaflet";
|
||||
import { LatLng, LatLngExpression, Map, Point, Polygon, PolylineOptions, DivIcon, Marker } from "leaflet";
|
||||
import { getApp } from "../../olympusapp";
|
||||
import { CoalitionAreaHandle } from "./coalitionareahandle";
|
||||
import { CoalitionAreaMiddleHandle } from "./coalitionareamiddlehandle";
|
||||
@@ -27,10 +18,7 @@ export class CoalitionPolygon extends Polygon {
|
||||
#labelText: string;
|
||||
#label: Marker;
|
||||
|
||||
constructor(
|
||||
latlngs: LatLngExpression[] | LatLngExpression[][] | LatLngExpression[][][],
|
||||
options?: PolylineOptions
|
||||
) {
|
||||
constructor(latlngs: LatLngExpression[] | LatLngExpression[][] | LatLngExpression[][][], options?: PolylineOptions) {
|
||||
if (options === undefined) options = {};
|
||||
|
||||
totalAreas++;
|
||||
@@ -45,11 +33,7 @@ export class CoalitionPolygon extends Polygon {
|
||||
|
||||
this.#labelText = `Polygon ${totalAreas}`;
|
||||
|
||||
if (
|
||||
[BLUE_COMMANDER, RED_COMMANDER].includes(
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode
|
||||
)
|
||||
)
|
||||
if ([BLUE_COMMANDER, RED_COMMANDER].includes(getApp().getMissionManager().getCommandModeOptions().commandMode))
|
||||
this.setCoalition(getApp().getMissionManager().getCommandedCoalition());
|
||||
|
||||
this.on("drag", () => {
|
||||
@@ -130,17 +114,11 @@ export class CoalitionPolygon extends Polygon {
|
||||
|
||||
onRemove(map: Map): this {
|
||||
super.onRemove(map);
|
||||
this.#handles
|
||||
.concat(this.#middleHandles)
|
||||
.forEach((handle: CoalitionAreaHandle | CoalitionAreaMiddleHandle) =>
|
||||
handle.removeFrom(getApp().getMap())
|
||||
);
|
||||
this.#handles.concat(this.#middleHandles).forEach((handle: CoalitionAreaHandle | CoalitionAreaMiddleHandle) => handle.removeFrom(getApp().getMap()));
|
||||
return this;
|
||||
}
|
||||
|
||||
setLatLngs(
|
||||
latlngs: LatLngExpression[] | LatLngExpression[][] | LatLngExpression[][][]
|
||||
) {
|
||||
setLatLngs(latlngs: LatLngExpression[] | LatLngExpression[][] | LatLngExpression[][][]) {
|
||||
super.setLatLngs(latlngs);
|
||||
this.#drawLabel();
|
||||
return this;
|
||||
@@ -158,9 +136,7 @@ export class CoalitionPolygon extends Polygon {
|
||||
}
|
||||
|
||||
#setHandles() {
|
||||
this.#handles.forEach((handle: CoalitionAreaHandle) =>
|
||||
handle.removeFrom(getApp().getMap())
|
||||
);
|
||||
this.#handles.forEach((handle: CoalitionAreaHandle) => handle.removeFrom(getApp().getMap()));
|
||||
this.#handles = [];
|
||||
if (this.getSelected()) {
|
||||
var latlngs = this.getLatLngs()[0] as LatLng[];
|
||||
@@ -181,9 +157,7 @@ export class CoalitionPolygon extends Polygon {
|
||||
}
|
||||
|
||||
#setMiddleHandles() {
|
||||
this.#middleHandles.forEach((handle: CoalitionAreaMiddleHandle) =>
|
||||
handle.removeFrom(getApp().getMap())
|
||||
);
|
||||
this.#middleHandles.forEach((handle: CoalitionAreaMiddleHandle) => handle.removeFrom(getApp().getMap()));
|
||||
this.#middleHandles = [];
|
||||
var latlngs = this.getLatLngs()[0] as LatLng[];
|
||||
if (this.getSelected() && latlngs.length >= 2) {
|
||||
@@ -193,13 +167,8 @@ export class CoalitionPolygon extends Polygon {
|
||||
if (lastLatLng != null) {
|
||||
const handle1Point = getApp().getMap().latLngToLayerPoint(latlng);
|
||||
const handle2Point = getApp().getMap().latLngToLayerPoint(lastLatLng);
|
||||
const middlePoint = new Point(
|
||||
(handle1Point.x + handle2Point.x) / 2,
|
||||
(handle1Point.y + handle2Point.y) / 2
|
||||
);
|
||||
const middleLatLng = getApp()
|
||||
.getMap()
|
||||
.layerPointToLatLng(middlePoint);
|
||||
const middlePoint = new Point((handle1Point.x + handle2Point.x) / 2, (handle1Point.y + handle2Point.y) / 2);
|
||||
const middleLatLng = getApp().getMap().layerPointToLatLng(middlePoint);
|
||||
|
||||
const middleHandle = new CoalitionAreaMiddleHandle(middleLatLng);
|
||||
middleHandle.addTo(getApp().getMap());
|
||||
@@ -228,12 +197,7 @@ export class CoalitionPolygon extends Polygon {
|
||||
}),
|
||||
interactive: false,
|
||||
}).addTo(this._map);
|
||||
this.#label
|
||||
.getElement()
|
||||
?.classList.add(
|
||||
`ol-coalitionarea-label`,
|
||||
`${this.#selected ? "selected" : `${this.#coalition}`}`
|
||||
);
|
||||
this.#label.getElement()?.classList.add(`ol-coalitionarea-label`, `${this.#selected ? "selected" : `${this.#coalition}`}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import * as L from "leaflet";
|
||||
|
||||
export const initDraggablePath = () => {
|
||||
export const initDraggablePath = (L) => {
|
||||
//@ts-ignore
|
||||
L.PathDraggable = L.Draggable.extend({
|
||||
initialize: function (path) {
|
||||
@@ -8,9 +6,7 @@ export const initDraggablePath = () => {
|
||||
|
||||
this._canvas = path._map.getRenderer(path) instanceof L.Canvas;
|
||||
|
||||
var element = this._canvas
|
||||
? this._path._map.getRenderer(this._path)._container
|
||||
: this._path._path;
|
||||
var element = this._canvas ? this._path._map.getRenderer(this._path)._container : this._path._path;
|
||||
|
||||
//@ts-ignore
|
||||
L.Draggable.prototype.initialize.call(this, element, element, true);
|
||||
@@ -27,12 +23,7 @@ export const initDraggablePath = () => {
|
||||
|
||||
this._startPoint = new L.Point(first.clientX, first.clientY);
|
||||
|
||||
if (
|
||||
this._canvas &&
|
||||
!this._path._containsPoint(
|
||||
this._path._map.mouseEventToLayerPoint(first)
|
||||
)
|
||||
) {
|
||||
if (this._canvas && !this._path._containsPoint(this._path._map.mouseEventToLayerPoint(first))) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -87,10 +78,7 @@ export const initDraggablePath = () => {
|
||||
|
||||
_onDrag: function (e) {
|
||||
var path = this._path,
|
||||
event =
|
||||
e.originalEvent.touches && e.originalEvent.touches.length === 1
|
||||
? e.originalEvent.touches[0]
|
||||
: e.originalEvent,
|
||||
event = e.originalEvent.touches && e.originalEvent.touches.length === 1 ? e.originalEvent.touches[0] : e.originalEvent,
|
||||
newPoint = L.point(event.clientX, event.clientY),
|
||||
latlng = path._map.layerPointToLatLng(newPoint);
|
||||
|
||||
@@ -108,9 +96,7 @@ export const initDraggablePath = () => {
|
||||
|
||||
path.fire("drag", e);
|
||||
|
||||
e.latlng = this._path.getCenter
|
||||
? this._path.getCenter()
|
||||
: this._path.getLatLng();
|
||||
e.latlng = this._path.getCenter ? this._path.getCenter() : this._path.getLatLng();
|
||||
|
||||
path.fire("move", e);
|
||||
},
|
||||
|
||||
@@ -3,12 +3,7 @@ import { getApp } from "../olympusapp";
|
||||
import { BoxSelect } from "./boxselect";
|
||||
import { Airbase } from "../mission/airbase";
|
||||
import { Unit } from "../unit/unit";
|
||||
import {
|
||||
areaContains,
|
||||
deg2rad,
|
||||
getFunctionArguments,
|
||||
getGroundElevation,
|
||||
} from "../other/utils";
|
||||
import { areaContains, deg2rad, getFunctionArguments, getGroundElevation } from "../other/utils";
|
||||
import { TemporaryUnitMarker } from "./markers/temporaryunitmarker";
|
||||
import { ClickableMiniMap } from "./clickableminimap";
|
||||
import {
|
||||
@@ -38,18 +33,12 @@ import "./map.css";
|
||||
import { CoalitionCircle } from "./coalitionarea/coalitioncircle";
|
||||
|
||||
import { initDraggablePath } from "./coalitionarea/draggablepath";
|
||||
import {
|
||||
faComputerMouse,
|
||||
faDrawPolygon,
|
||||
faHandPointer,
|
||||
faJetFighter,
|
||||
faMap,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { faComputerMouse, faDrawPolygon, faHandPointer, faJetFighter, faMap } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
/* Register the handler for the box selection */
|
||||
L.Map.addInitHook("addHandler", "boxSelect", BoxSelect);
|
||||
|
||||
initDraggablePath();
|
||||
initDraggablePath(L);
|
||||
|
||||
export class Map extends L.Map {
|
||||
/* Options */
|
||||
@@ -141,10 +130,10 @@ export class Map extends L.Map {
|
||||
this.setView([37.23, -115.8], 10);
|
||||
|
||||
/* Minimap */
|
||||
var minimapLayer = new L.TileLayer(
|
||||
"https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
|
||||
{ minZoom: 0, maxZoom: 13 }
|
||||
);
|
||||
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]);
|
||||
this.#miniMapPolyline = new L.Polyline([], { color: "#202831" });
|
||||
this.#miniMapPolyline.addTo(this.#miniMapLayerGroup);
|
||||
@@ -181,15 +170,11 @@ export class Map extends L.Map {
|
||||
|
||||
/* Event listeners */
|
||||
document.addEventListener("hiddenTypesChanged", (ev: CustomEventInit) => {
|
||||
Object.values(getApp().getUnitsManager().getUnits()).forEach(
|
||||
(unit: Unit) => unit.updateVisibility()
|
||||
);
|
||||
Object.values(getApp().getMissionManager().getAirbases()).forEach(
|
||||
(airbase: Airbase) => {
|
||||
if (this.getHiddenTypes().airbase) airbase.removeFrom(this);
|
||||
else airbase.addTo(this);
|
||||
}
|
||||
);
|
||||
Object.values(getApp().getUnitsManager().getUnits()).forEach((unit: Unit) => unit.updateVisibility());
|
||||
Object.values(getApp().getMissionManager().getAirbases()).forEach((airbase: Airbase) => {
|
||||
if (this.getHiddenTypes().airbase) airbase.removeFrom(this);
|
||||
else airbase.addTo(this);
|
||||
});
|
||||
});
|
||||
|
||||
//document.addEventListener("unitUpdated", (ev: CustomEvent) => {
|
||||
@@ -198,10 +183,7 @@ export class Map extends L.Map {
|
||||
//});
|
||||
|
||||
document.addEventListener("mapOptionsChanged", () => {
|
||||
this.getContainer().toggleAttribute(
|
||||
"data-hide-labels",
|
||||
!this.getOptions().showUnitLabels
|
||||
);
|
||||
this.getContainer().toggleAttribute("data-hide-labels", !this.getOptions().showUnitLabels);
|
||||
//this.#cameraControlPort = this.getOptions()[DCS_LINK_PORT] as number;
|
||||
//this.#cameraZoomRatio = 50 / (20 + (this.getOptions()[DCS_LINK_RATIO] as number));
|
||||
|
||||
@@ -263,12 +245,8 @@ export class Map extends L.Map {
|
||||
if (this.#panUp || this.#panDown || this.#panRight || this.#panLeft)
|
||||
this.panBy(
|
||||
new L.Point(
|
||||
((this.#panLeft ? -1 : 0) + (this.#panRight ? 1 : 0)) *
|
||||
this.defaultPanDelta *
|
||||
(this.#isShiftKeyDown ? 3 : 1),
|
||||
((this.#panUp ? -1 : 0) + (this.#panDown ? 1 : 0)) *
|
||||
this.defaultPanDelta *
|
||||
(this.#isShiftKeyDown ? 3 : 1)
|
||||
((this.#panLeft ? -1 : 0) + (this.#panRight ? 1 : 0)) * this.defaultPanDelta * (this.#isShiftKeyDown ? 3 : 1),
|
||||
((this.#panUp ? -1 : 0) + (this.#panDown ? 1 : 0)) * this.defaultPanDelta * (this.#isShiftKeyDown ? 3 : 1)
|
||||
)
|
||||
);
|
||||
}, 20);
|
||||
@@ -289,10 +267,7 @@ export class Map extends L.Map {
|
||||
const layerData = this.#mapLayers[layerName];
|
||||
if (layerData instanceof Array) {
|
||||
let layers = layerData.map((layer: any) => {
|
||||
return new L.TileLayer(
|
||||
layer.urlTemplate.replace("{theatre}", theatre.toLowerCase()),
|
||||
layer
|
||||
);
|
||||
return new L.TileLayer(layer.urlTemplate.replace("{theatre}", theatre.toLowerCase()), layer);
|
||||
});
|
||||
this.#layer = new L.LayerGroup(layers);
|
||||
this.#layer?.addTo(this);
|
||||
@@ -306,13 +281,10 @@ export class Map extends L.Map {
|
||||
let layers: L.TileLayer[] = [];
|
||||
|
||||
layers.push(
|
||||
new L.TileLayer(
|
||||
"https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
|
||||
{
|
||||
minZoom: 1,
|
||||
maxZoom: 19,
|
||||
}
|
||||
)
|
||||
new L.TileLayer("https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}", {
|
||||
minZoom: 1,
|
||||
maxZoom: 19,
|
||||
})
|
||||
);
|
||||
|
||||
/* Load the configuration file */
|
||||
@@ -348,9 +320,7 @@ export class Map extends L.Map {
|
||||
}
|
||||
this.#layerName = layerName;
|
||||
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("mapSourceChanged", { detail: layerName })
|
||||
);
|
||||
document.dispatchEvent(new CustomEvent("mapSourceChanged", { detail: layerName }));
|
||||
}
|
||||
|
||||
getLayerName() {
|
||||
@@ -372,11 +342,7 @@ export class Map extends L.Map {
|
||||
console.log(`Switching from state ${this.#state} to ${state}`);
|
||||
|
||||
/* Operations to perform when leaving a state */
|
||||
if (
|
||||
this.#state === COALITIONAREA_DRAW_POLYGON ||
|
||||
this.#state === COALITIONAREA_DRAW_CIRCLE
|
||||
)
|
||||
this.getSelectedCoalitionArea()?.setEditing(false);
|
||||
if (this.#state === COALITIONAREA_DRAW_POLYGON || this.#state === COALITIONAREA_DRAW_CIRCLE) this.getSelectedCoalitionArea()?.setEditing(false);
|
||||
|
||||
this.#state = state;
|
||||
|
||||
@@ -400,15 +366,11 @@ export class Map extends L.Map {
|
||||
this.#coalitionAreas[this.#coalitionAreas.length - 1].addTo(this);
|
||||
} else if (this.#state === COALITIONAREA_DRAW_CIRCLE) {
|
||||
getApp().getUnitsManager().deselectAllUnits();
|
||||
this.#coalitionAreas.push(
|
||||
new CoalitionCircle(new L.LatLng(0, 0), { radius: 1000 })
|
||||
);
|
||||
this.#coalitionAreas.push(new CoalitionCircle(new L.LatLng(0, 0), { radius: 1000 }));
|
||||
this.#coalitionAreas[this.#coalitionAreas.length - 1].addTo(this);
|
||||
}
|
||||
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("mapStateChanged", { detail: this.#state })
|
||||
);
|
||||
document.dispatchEvent(new CustomEvent("mapStateChanged", { detail: this.#state }));
|
||||
}
|
||||
|
||||
getState() {
|
||||
@@ -449,10 +411,7 @@ export class Map extends L.Map {
|
||||
text: "Spawn unit",
|
||||
},
|
||||
{
|
||||
actions: [
|
||||
touch ? faHandPointer : faComputerMouse,
|
||||
touch ? faHandPointer : faComputerMouse,
|
||||
],
|
||||
actions: [touch ? faHandPointer : faComputerMouse, touch ? faHandPointer : faComputerMouse],
|
||||
target: faMap,
|
||||
text: "Exit spawn mode",
|
||||
},
|
||||
@@ -465,10 +424,7 @@ export class Map extends L.Map {
|
||||
} else if (this.#state === CONTEXT_ACTION) {
|
||||
let controls = [
|
||||
{
|
||||
actions: [
|
||||
touch ? faHandPointer : faComputerMouse,
|
||||
touch ? faHandPointer : faComputerMouse,
|
||||
],
|
||||
actions: [touch ? faHandPointer : faComputerMouse, touch ? faHandPointer : faComputerMouse],
|
||||
target: faMap,
|
||||
text: "Deselect units",
|
||||
},
|
||||
@@ -498,10 +454,7 @@ export class Map extends L.Map {
|
||||
text: "Select shape",
|
||||
},
|
||||
{
|
||||
actions: [
|
||||
touch ? faHandPointer : faComputerMouse,
|
||||
touch ? faHandPointer : faComputerMouse,
|
||||
],
|
||||
actions: [touch ? faHandPointer : faComputerMouse, touch ? faHandPointer : faComputerMouse],
|
||||
target: faMap,
|
||||
text: "Exit drawing mode",
|
||||
},
|
||||
@@ -519,10 +472,7 @@ export class Map extends L.Map {
|
||||
text: "Add vertex to polygon",
|
||||
},
|
||||
{
|
||||
actions: [
|
||||
touch ? faHandPointer : faComputerMouse,
|
||||
touch ? faHandPointer : faComputerMouse,
|
||||
],
|
||||
actions: [touch ? faHandPointer : faComputerMouse, touch ? faHandPointer : faComputerMouse],
|
||||
target: faMap,
|
||||
text: "Finalize polygon",
|
||||
},
|
||||
@@ -557,18 +507,11 @@ export class Map extends L.Map {
|
||||
})
|
||||
);
|
||||
|
||||
this.#coalitionAreas.forEach(
|
||||
(coalitionArea: CoalitionPolygon | CoalitionCircle) =>
|
||||
coalitionArea.setSelected(false)
|
||||
);
|
||||
this.#coalitionAreas.forEach((coalitionArea: CoalitionPolygon | CoalitionCircle) => coalitionArea.setSelected(false));
|
||||
}
|
||||
|
||||
deleteCoalitionArea(coalitionArea: CoalitionPolygon | CoalitionCircle) {
|
||||
if (this.#coalitionAreas.includes(coalitionArea))
|
||||
this.#coalitionAreas.splice(
|
||||
this.#coalitionAreas.indexOf(coalitionArea),
|
||||
1
|
||||
);
|
||||
if (this.#coalitionAreas.includes(coalitionArea)) this.#coalitionAreas.splice(this.#coalitionAreas.indexOf(coalitionArea), 1);
|
||||
|
||||
if (this.hasLayer(coalitionArea)) this.removeLayer(coalitionArea);
|
||||
}
|
||||
@@ -617,9 +560,7 @@ export class Map extends L.Map {
|
||||
this.updateMinimap();
|
||||
|
||||
const boundaries = this.#getMinimapBoundaries();
|
||||
this.#miniMapPolyline.setLatLngs(
|
||||
boundaries[theatre as keyof typeof boundaries]
|
||||
);
|
||||
this.#miniMapPolyline.setLatLngs(boundaries[theatre as keyof typeof boundaries]);
|
||||
|
||||
this.setLayerName(this.#layerName);
|
||||
}
|
||||
@@ -697,12 +638,7 @@ export class Map extends L.Map {
|
||||
}
|
||||
}
|
||||
|
||||
addTemporaryMarker(
|
||||
latlng: L.LatLng,
|
||||
name: string,
|
||||
coalition: string,
|
||||
commandHash?: string
|
||||
) {
|
||||
addTemporaryMarker(latlng: L.LatLng, name: string, coalition: string, commandHash?: string) {
|
||||
var marker = new TemporaryUnitMarker(latlng, name, coalition, commandHash);
|
||||
marker.addTo(this);
|
||||
this.#temporaryMarkers.push(marker);
|
||||
@@ -710,11 +646,9 @@ export class Map extends L.Map {
|
||||
}
|
||||
|
||||
getSelectedCoalitionArea() {
|
||||
const coalitionArea = this.#coalitionAreas.find(
|
||||
(coalitionArea: CoalitionPolygon | CoalitionCircle) => {
|
||||
return coalitionArea.getSelected();
|
||||
}
|
||||
);
|
||||
const coalitionArea = this.#coalitionAreas.find((coalitionArea: CoalitionPolygon | CoalitionCircle) => {
|
||||
return coalitionArea.getSelected();
|
||||
});
|
||||
|
||||
return coalitionArea ?? null;
|
||||
}
|
||||
@@ -794,10 +728,7 @@ export class Map extends L.Map {
|
||||
//}
|
||||
}
|
||||
|
||||
executeContextAction(
|
||||
targetUnit: Unit | null,
|
||||
targetPosition: L.LatLng | null
|
||||
) {
|
||||
executeContextAction(targetUnit: Unit | null, targetPosition: L.LatLng | null) {
|
||||
this.#contextAction?.executeCallback(targetUnit, targetPosition);
|
||||
}
|
||||
|
||||
@@ -847,8 +778,7 @@ export class Map extends L.Map {
|
||||
|
||||
this.#longPressTimer = window.setTimeout(() => {
|
||||
/* If the mouse is still being pressed, execute the long press action */
|
||||
if (this.#isMouseDown && !this.#isDragging && !this.#isZooming)
|
||||
this.#onLongPress(e);
|
||||
if (this.#isMouseDown && !this.#isDragging && !this.#isZooming) this.#onLongPress(e);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
@@ -858,10 +788,7 @@ export class Map extends L.Map {
|
||||
window.clearTimeout(this.#shortPressTimer);
|
||||
window.clearTimeout(this.#longPressTimer);
|
||||
|
||||
if (
|
||||
this.#state === COALITIONAREA_DRAW_POLYGON ||
|
||||
this.#state === COALITIONAREA_DRAW_CIRCLE
|
||||
) {
|
||||
if (this.#state === COALITIONAREA_DRAW_POLYGON || this.#state === COALITIONAREA_DRAW_CIRCLE) {
|
||||
this.setState(COALITIONAREA_EDIT);
|
||||
} else {
|
||||
this.setState(IDLE);
|
||||
@@ -870,10 +797,7 @@ export class Map extends L.Map {
|
||||
|
||||
#onShortPress(e: any) {
|
||||
let touchLocation: L.LatLng;
|
||||
if (e.type === "touchstart")
|
||||
touchLocation = this.containerPointToLatLng(
|
||||
this.mouseEventToContainerPoint(e.touches[0])
|
||||
);
|
||||
if (e.type === "touchstart") touchLocation = this.containerPointToLatLng(this.mouseEventToContainerPoint(e.touches[0]));
|
||||
else touchLocation = new L.LatLng(e.latlng.lat, e.latlng.lng);
|
||||
|
||||
console.log(`Short press at ${touchLocation}`);
|
||||
@@ -893,12 +817,7 @@ export class Map extends L.Map {
|
||||
undefined,
|
||||
undefined,
|
||||
(hash) => {
|
||||
this.addTemporaryMarker(
|
||||
touchLocation,
|
||||
this.#spawnRequestTable?.unit.unitType ?? "unknown",
|
||||
this.#spawnRequestTable?.coalition ?? "blue",
|
||||
hash
|
||||
);
|
||||
this.addTemporaryMarker(touchLocation, this.#spawnRequestTable?.unit.unitType ?? "unknown", this.#spawnRequestTable?.coalition ?? "blue", hash);
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -910,11 +829,7 @@ export class Map extends L.Map {
|
||||
} else if (this.#state === COALITIONAREA_DRAW_CIRCLE) {
|
||||
const selectedArea = this.getSelectedCoalitionArea();
|
||||
if (selectedArea && selectedArea instanceof CoalitionCircle) {
|
||||
if (
|
||||
selectedArea.getLatLng().lat == 0 &&
|
||||
selectedArea.getLatLng().lng == 0
|
||||
)
|
||||
selectedArea.setLatLng(touchLocation);
|
||||
if (selectedArea.getLatLng().lat == 0 && selectedArea.getLatLng().lng == 0) selectedArea.setLatLng(touchLocation);
|
||||
this.setState(COALITIONAREA_EDIT);
|
||||
}
|
||||
} else if (this.#state == COALITIONAREA_EDIT) {
|
||||
@@ -938,10 +853,7 @@ export class Map extends L.Map {
|
||||
|
||||
#onLongPress(e: any) {
|
||||
let touchLocation: L.LatLng;
|
||||
if (e.type === "touchstart")
|
||||
touchLocation = this.containerPointToLatLng(
|
||||
this.mouseEventToContainerPoint(e.touches[0])
|
||||
);
|
||||
if (e.type === "touchstart") touchLocation = this.containerPointToLatLng(this.mouseEventToContainerPoint(e.touches[0]));
|
||||
else touchLocation = new L.LatLng(e.latlng.lat, e.latlng.lng);
|
||||
|
||||
console.log(`Long press at ${touchLocation}`);
|
||||
@@ -949,14 +861,8 @@ export class Map extends L.Map {
|
||||
if (!this.#isDragging && !this.#isZooming) {
|
||||
this.deselectAllCoalitionAreas();
|
||||
if (this.#state === IDLE) {
|
||||
if (e.type === "touchstart")
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("mapForceBoxSelect", { detail: e })
|
||||
);
|
||||
else
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("mapForceBoxSelect", { detail: e.originalEvent })
|
||||
);
|
||||
if (e.type === "touchstart") document.dispatchEvent(new CustomEvent("mapForceBoxSelect", { detail: e }));
|
||||
else document.dispatchEvent(new CustomEvent("mapForceBoxSelect", { detail: e.originalEvent }));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -996,11 +902,7 @@ export class Map extends L.Map {
|
||||
}
|
||||
|
||||
#broadcastPosition() {
|
||||
if (
|
||||
this.#bradcastPositionXmlHttp?.readyState !== 4 &&
|
||||
this.#bradcastPositionXmlHttp !== null
|
||||
)
|
||||
return;
|
||||
if (this.#bradcastPositionXmlHttp?.readyState !== 4 && this.#bradcastPositionXmlHttp !== null) return;
|
||||
|
||||
getGroundElevation(this.getCenter(), (response: string) => {
|
||||
var groundElevation: number | null = null;
|
||||
@@ -1009,18 +911,12 @@ export class Map extends L.Map {
|
||||
this.#bradcastPositionXmlHttp = new XMLHttpRequest();
|
||||
/* Using 127.0.0.1 instead of localhost because the LuaSocket version used in DCS only listens to IPv4. This avoids the lag caused by the
|
||||
browser if it first tries to send the request on the IPv6 address for localhost */
|
||||
this.#bradcastPositionXmlHttp.open(
|
||||
"POST",
|
||||
`http://127.0.0.1:${this.#cameraControlPort}`
|
||||
);
|
||||
this.#bradcastPositionXmlHttp.open("POST", `http://127.0.0.1:${this.#cameraControlPort}`);
|
||||
|
||||
const C = 40075016.686;
|
||||
let mpp =
|
||||
(C * Math.cos(deg2rad(this.getCenter().lat))) /
|
||||
Math.pow(2, this.getZoom() + 8);
|
||||
let mpp = (C * Math.cos(deg2rad(this.getCenter().lat))) / Math.pow(2, this.getZoom() + 8);
|
||||
let d = mpp * 1920;
|
||||
let alt =
|
||||
(((d / 2) * 1) / Math.tan(deg2rad(40))) * this.#cameraZoomRatio;
|
||||
let alt = (((d / 2) * 1) / Math.tan(deg2rad(40))) * this.#cameraZoomRatio;
|
||||
alt = Math.min(alt, 50000);
|
||||
this.#bradcastPositionXmlHttp.send(
|
||||
JSON.stringify({
|
||||
@@ -1038,10 +934,7 @@ export class Map extends L.Map {
|
||||
|
||||
/* */
|
||||
#panToUnit(unit: Unit) {
|
||||
var unitPosition = new L.LatLng(
|
||||
unit.getPosition().lat,
|
||||
unit.getPosition().lng
|
||||
);
|
||||
var unitPosition = new L.LatLng(unit.getPosition().lat, unit.getPosition().lng);
|
||||
this.setView(unitPosition, this.getZoom(), { animate: false });
|
||||
}
|
||||
|
||||
@@ -1067,23 +960,15 @@ export class Map extends L.Map {
|
||||
|
||||
/* Check if the camera control plugin is available. Right now this will only change the color of the button, no changes in functionality */
|
||||
#checkCameraPort() {
|
||||
if (this.#cameraOptionsXmlHttp?.readyState !== 4)
|
||||
this.#cameraOptionsXmlHttp?.abort();
|
||||
if (this.#cameraOptionsXmlHttp?.readyState !== 4) this.#cameraOptionsXmlHttp?.abort();
|
||||
|
||||
this.#cameraOptionsXmlHttp = new XMLHttpRequest();
|
||||
|
||||
/* Using 127.0.0.1 instead of localhost because the LuaSocket version used in DCS only listens to IPv4. This avoids the lag caused by the
|
||||
browser if it first tries to send the request on the IPv6 address for localhost */
|
||||
this.#cameraOptionsXmlHttp.open(
|
||||
"OPTIONS",
|
||||
`http://127.0.0.1:${this.#cameraControlPort}`
|
||||
);
|
||||
this.#cameraOptionsXmlHttp.open("OPTIONS", `http://127.0.0.1:${this.#cameraControlPort}`);
|
||||
this.#cameraOptionsXmlHttp.onload = (res: any) => {
|
||||
if (
|
||||
this.#cameraOptionsXmlHttp !== null &&
|
||||
this.#cameraOptionsXmlHttp.status == 204
|
||||
)
|
||||
this.#setSlaveDCSCameraAvailable(true);
|
||||
if (this.#cameraOptionsXmlHttp !== null && this.#cameraOptionsXmlHttp.status == 204) this.#setSlaveDCSCameraAvailable(true);
|
||||
else this.#setSlaveDCSCameraAvailable(false);
|
||||
};
|
||||
this.#cameraOptionsXmlHttp.onerror = (res: any) => {
|
||||
|
||||
@@ -6,11 +6,7 @@ import { getApp } from "../../olympusapp";
|
||||
export class SmokeMarker extends CustomMarker {
|
||||
#color: string;
|
||||
|
||||
constructor(
|
||||
latlng: LatLngExpression,
|
||||
color: string,
|
||||
options?: MarkerOptions
|
||||
) {
|
||||
constructor(latlng: LatLngExpression, color: string, options?: MarkerOptions) {
|
||||
super(latlng, options);
|
||||
this.setZIndexOffset(9999);
|
||||
this.#color = color;
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import { CustomMarker } from "./custommarker";
|
||||
import { DivIcon, LatLng } from "leaflet";
|
||||
import { SVGInjector } from "@tanem/svg-injector";
|
||||
import {
|
||||
getMarkerCategoryByName,
|
||||
getUnitDatabaseByCategory,
|
||||
} from "../../other/utils";
|
||||
import { getMarkerCategoryByName, getUnitDatabaseByCategory } from "../../other/utils";
|
||||
import { getApp } from "../../olympusapp";
|
||||
|
||||
export class TemporaryUnitMarker extends CustomMarker {
|
||||
@@ -13,12 +10,7 @@ export class TemporaryUnitMarker extends CustomMarker {
|
||||
#commandHash: string | undefined = undefined;
|
||||
#timer: number = 0;
|
||||
|
||||
constructor(
|
||||
latlng: LatLng,
|
||||
name: string,
|
||||
coalition: string,
|
||||
commandHash?: string
|
||||
) {
|
||||
constructor(latlng: LatLng, name: string, coalition: string, commandHash?: string) {
|
||||
super(latlng, { interactive: false });
|
||||
this.#name = name;
|
||||
this.#coalition = coalition;
|
||||
@@ -45,9 +37,7 @@ export class TemporaryUnitMarker extends CustomMarker {
|
||||
|
||||
createIcon() {
|
||||
const category = getMarkerCategoryByName(this.#name);
|
||||
const databaseEntry = getUnitDatabaseByCategory(category)?.getByName(
|
||||
this.#name
|
||||
);
|
||||
const databaseEntry = getUnitDatabaseByCategory(category)?.getByName(this.#name);
|
||||
|
||||
/* Set the icon */
|
||||
var icon = new DivIcon({
|
||||
|
||||
@@ -26,14 +26,8 @@ export class RangeCircle extends Circle {
|
||||
let pathBegun = false;
|
||||
let dtheta = (Math.PI * 2) / 120;
|
||||
for (let theta = 0; theta <= Math.PI * 2; theta += dtheta) {
|
||||
let p1 = new Point(
|
||||
p.x + r * Math.cos(theta),
|
||||
p.y / s + r * Math.sin(theta)
|
||||
);
|
||||
let p2 = new Point(
|
||||
p.x + r * Math.cos(theta + dtheta),
|
||||
p.y / s + r * Math.sin(theta + dtheta)
|
||||
);
|
||||
let p1 = new Point(p.x + r * Math.cos(theta), p.y / s + r * Math.sin(theta));
|
||||
let p2 = new Point(p.x + r * Math.cos(theta + dtheta), p.y / s + r * Math.sin(theta + dtheta));
|
||||
let l1 = this._map.layerPointToLatLng(p1);
|
||||
let l2 = this._map.layerPointToLatLng(p2);
|
||||
let line = new Polyline([l1, l2]);
|
||||
|
||||
@@ -43,23 +43,17 @@ export class Airbase extends CustomMarker {
|
||||
el.appendChild(img);
|
||||
this.getElement()?.appendChild(el);
|
||||
el.addEventListener("mouseover", (ev) => {
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("airbaseMouseover", { detail: this })
|
||||
);
|
||||
document.dispatchEvent(new CustomEvent("airbaseMouseover", { detail: this }));
|
||||
});
|
||||
el.addEventListener("mouseout", (ev) => {
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("airbaseMouseout", { detail: this })
|
||||
);
|
||||
document.dispatchEvent(new CustomEvent("airbaseMouseout", { detail: this }));
|
||||
});
|
||||
el.dataset.coalition = this.#coalition;
|
||||
}
|
||||
|
||||
setCoalition(coalition: string) {
|
||||
this.#coalition = coalition;
|
||||
(<HTMLElement>(
|
||||
this.getElement()?.querySelector(".airbase-icon")
|
||||
)).dataset.coalition = this.#coalition;
|
||||
(<HTMLElement>this.getElement()?.querySelector(".airbase-icon")).dataset.coalition = this.#coalition;
|
||||
}
|
||||
|
||||
getChartData() {
|
||||
|
||||
@@ -25,9 +25,7 @@ export class Bullseye extends CustomMarker {
|
||||
|
||||
setCoalition(coalition: string) {
|
||||
this.#coalition = coalition;
|
||||
(<HTMLElement>(
|
||||
this.getElement()?.querySelector(".bullseye-icon")
|
||||
)).dataset.coalition = this.#coalition;
|
||||
(<HTMLElement>this.getElement()?.querySelector(".bullseye-icon")).dataset.coalition = this.#coalition;
|
||||
}
|
||||
|
||||
getCoalition() {
|
||||
|
||||
@@ -2,13 +2,7 @@ import { LatLng } from "leaflet";
|
||||
import { getApp } from "../olympusapp";
|
||||
import { Airbase } from "./airbase";
|
||||
import { Bullseye } from "./bullseye";
|
||||
import {
|
||||
BLUE_COMMANDER,
|
||||
ERAS,
|
||||
GAME_MASTER,
|
||||
NONE,
|
||||
RED_COMMANDER,
|
||||
} from "../constants/constants";
|
||||
import { BLUE_COMMANDER, ERAS, GAME_MASTER, NONE, RED_COMMANDER } from "../constants/constants";
|
||||
//import { Dropdown } from "../controls/dropdown";
|
||||
import { groundUnitDatabase } from "../unit/databases/groundunitdatabase";
|
||||
//import { createCheckboxOption, getCheckboxOptions } from "../other/utils";
|
||||
@@ -16,13 +10,7 @@ import { aircraftDatabase } from "../unit/databases/aircraftdatabase";
|
||||
import { helicopterDatabase } from "../unit/databases/helicopterdatabase";
|
||||
import { navyUnitDatabase } from "../unit/databases/navyunitdatabase";
|
||||
//import { Popup } from "../popups/popup";
|
||||
import {
|
||||
AirbasesData,
|
||||
BullseyesData,
|
||||
CommandModeOptions,
|
||||
DateAndTime,
|
||||
MissionData,
|
||||
} from "../interfaces";
|
||||
import { AirbasesData, BullseyesData, CommandModeOptions, DateAndTime, MissionData } from "../interfaces";
|
||||
import { Coalition } from "../types/types";
|
||||
|
||||
/** The MissionManager */
|
||||
@@ -53,18 +41,11 @@ export class MissionManager {
|
||||
#coalitions: { red: string[]; blue: string[] } = { red: [], blue: [] };
|
||||
|
||||
constructor() {
|
||||
document.addEventListener("applycommandModeOptions", () =>
|
||||
this.#applycommandModeOptions()
|
||||
);
|
||||
document.addEventListener("showCommandModeDialog", () =>
|
||||
this.showCommandModeDialog()
|
||||
);
|
||||
document.addEventListener(
|
||||
"toggleSpawnRestrictions",
|
||||
(ev: CustomEventInit) => {
|
||||
this.#toggleSpawnRestrictions(ev.detail._element.checked);
|
||||
}
|
||||
);
|
||||
document.addEventListener("applycommandModeOptions", () => this.#applycommandModeOptions());
|
||||
document.addEventListener("showCommandModeDialog", () => this.showCommandModeDialog());
|
||||
document.addEventListener("toggleSpawnRestrictions", (ev: CustomEventInit) => {
|
||||
this.#toggleSpawnRestrictions(ev.detail._element.checked);
|
||||
});
|
||||
|
||||
/* command-mode settings dialog */
|
||||
//this.#commandModeDialog = document.querySelector("#command-mode-settings-dialog") as HTMLElement;
|
||||
@@ -76,27 +57,19 @@ export class MissionManager {
|
||||
* @param object <BulleyesData>
|
||||
*/
|
||||
updateBullseyes(data: BullseyesData) {
|
||||
const commandMode = getApp()
|
||||
.getMissionManager()
|
||||
.getCommandModeOptions().commandMode;
|
||||
const commandMode = getApp().getMissionManager().getCommandModeOptions().commandMode;
|
||||
for (let idx in data.bullseyes) {
|
||||
const bullseye = data.bullseyes[idx];
|
||||
|
||||
// Prevent Red and Blue coalitions seeing each other's bulleye(s)
|
||||
if (
|
||||
(bullseye.coalition === "red" && commandMode === BLUE_COMMANDER) ||
|
||||
(bullseye.coalition === "blue" && commandMode === RED_COMMANDER)
|
||||
) {
|
||||
if ((bullseye.coalition === "red" && commandMode === BLUE_COMMANDER) || (bullseye.coalition === "blue" && commandMode === RED_COMMANDER)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(idx in this.#bullseyes))
|
||||
this.#bullseyes[idx] = new Bullseye([0, 0]).addTo(getApp().getMap());
|
||||
if (!(idx in this.#bullseyes)) this.#bullseyes[idx] = new Bullseye([0, 0]).addTo(getApp().getMap());
|
||||
|
||||
if (bullseye.latitude && bullseye.longitude && bullseye.coalition) {
|
||||
this.#bullseyes[idx].setLatLng(
|
||||
new LatLng(bullseye.latitude, bullseye.longitude)
|
||||
);
|
||||
this.#bullseyes[idx].setLatLng(new LatLng(bullseye.latitude, bullseye.longitude));
|
||||
this.#bullseyes[idx].setCoalition(bullseye.coalition);
|
||||
}
|
||||
}
|
||||
@@ -109,29 +82,17 @@ export class MissionManager {
|
||||
updateAirbases(data: AirbasesData) {
|
||||
for (let idx in data.airbases) {
|
||||
var airbase = data.airbases[idx];
|
||||
if (
|
||||
this.#airbases[airbase.callsign] === undefined &&
|
||||
airbase.callsign != ""
|
||||
) {
|
||||
if (this.#airbases[airbase.callsign] === undefined && airbase.callsign != "") {
|
||||
this.#airbases[airbase.callsign] = new Airbase({
|
||||
position: new LatLng(airbase.latitude, airbase.longitude),
|
||||
name: airbase.callsign,
|
||||
}).addTo(getApp().getMap());
|
||||
this.#airbases[airbase.callsign].on("contextmenu", (e) =>
|
||||
this.#onAirbaseClick(e)
|
||||
);
|
||||
this.#airbases[airbase.callsign].on("contextmenu", (e) => this.#onAirbaseClick(e));
|
||||
this.#loadAirbaseChartData(airbase.callsign);
|
||||
}
|
||||
|
||||
if (
|
||||
this.#airbases[airbase.callsign] != undefined &&
|
||||
airbase.latitude &&
|
||||
airbase.longitude &&
|
||||
airbase.coalition
|
||||
) {
|
||||
this.#airbases[airbase.callsign].setLatLng(
|
||||
new LatLng(airbase.latitude, airbase.longitude)
|
||||
);
|
||||
if (this.#airbases[airbase.callsign] != undefined && airbase.latitude && airbase.longitude && airbase.coalition) {
|
||||
this.#airbases[airbase.callsign].setLatLng(new LatLng(airbase.latitude, airbase.longitude));
|
||||
this.#airbases[airbase.callsign].setCoalition(airbase.coalition);
|
||||
}
|
||||
}
|
||||
@@ -159,23 +120,15 @@ export class MissionManager {
|
||||
|
||||
/* Set the command mode options */
|
||||
this.#setcommandModeOptions(data.mission.commandModeOptions);
|
||||
this.#remainingSetupTime =
|
||||
this.getCommandModeOptions().setupTime -
|
||||
this.getDateAndTime().elapsedTime;
|
||||
var commandModePhaseEl = document.querySelector(
|
||||
"#command-mode-phase"
|
||||
) as HTMLElement;
|
||||
this.#remainingSetupTime = this.getCommandModeOptions().setupTime - this.getDateAndTime().elapsedTime;
|
||||
var commandModePhaseEl = document.querySelector("#command-mode-phase") as HTMLElement;
|
||||
if (commandModePhaseEl) {
|
||||
if (this.#remainingSetupTime > 0) {
|
||||
var remainingTime = `-${new Date(this.#remainingSetupTime * 1000).toISOString().substring(14, 19)}`;
|
||||
commandModePhaseEl.dataset.remainingTime = remainingTime;
|
||||
}
|
||||
|
||||
commandModePhaseEl.classList.toggle(
|
||||
"setup-phase",
|
||||
this.#remainingSetupTime > 0 &&
|
||||
this.getCommandModeOptions().restrictSpawns
|
||||
);
|
||||
commandModePhaseEl.classList.toggle("setup-phase", this.#remainingSetupTime > 0 && this.getCommandModeOptions().restrictSpawns);
|
||||
//commandModePhaseEl.classList.toggle("game-commenced", this.#remainingSetupTime <= 0 || !this.getCommandModeOptions().restrictSpawns);
|
||||
//commandModePhaseEl.classList.toggle("no-restrictions", !this.getCommandModeOptions().restrictSpawns);
|
||||
}
|
||||
@@ -239,24 +192,15 @@ export class MissionManager {
|
||||
}
|
||||
|
||||
getAvailableSpawnPoints() {
|
||||
if (this.getCommandModeOptions().commandMode === GAME_MASTER)
|
||||
return Infinity;
|
||||
else if (this.getCommandModeOptions().commandMode === BLUE_COMMANDER)
|
||||
return (
|
||||
this.getCommandModeOptions().spawnPoints.blue - this.#spentSpawnPoint
|
||||
);
|
||||
else if (this.getCommandModeOptions().commandMode === RED_COMMANDER)
|
||||
return (
|
||||
this.getCommandModeOptions().spawnPoints.red - this.#spentSpawnPoint
|
||||
);
|
||||
if (this.getCommandModeOptions().commandMode === GAME_MASTER) return Infinity;
|
||||
else if (this.getCommandModeOptions().commandMode === BLUE_COMMANDER) return this.getCommandModeOptions().spawnPoints.blue - this.#spentSpawnPoint;
|
||||
else if (this.getCommandModeOptions().commandMode === RED_COMMANDER) return this.getCommandModeOptions().spawnPoints.red - this.#spentSpawnPoint;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
getCommandedCoalition() {
|
||||
if (this.getCommandModeOptions().commandMode === BLUE_COMMANDER)
|
||||
return "blue" as Coalition;
|
||||
else if (this.getCommandModeOptions().commandMode === RED_COMMANDER)
|
||||
return "red" as Coalition;
|
||||
if (this.getCommandModeOptions().commandMode === BLUE_COMMANDER) return "blue" as Coalition;
|
||||
else if (this.getCommandModeOptions().commandMode === RED_COMMANDER) return "red" as Coalition;
|
||||
else return "all" as Coalition;
|
||||
}
|
||||
|
||||
@@ -335,41 +279,27 @@ export class MissionManager {
|
||||
#setcommandModeOptions(commandModeOptions: CommandModeOptions) {
|
||||
/* Refresh all the data if we have exited the NONE state */
|
||||
var requestRefresh = false;
|
||||
if (
|
||||
this.#commandModeOptions.commandMode === NONE &&
|
||||
commandModeOptions.commandMode !== NONE
|
||||
)
|
||||
requestRefresh = true;
|
||||
if (this.#commandModeOptions.commandMode === NONE && commandModeOptions.commandMode !== NONE) requestRefresh = true;
|
||||
|
||||
/* Refresh the page if we have lost Game Master priviledges */
|
||||
if (
|
||||
this.#commandModeOptions.commandMode === GAME_MASTER &&
|
||||
commandModeOptions.commandMode !== GAME_MASTER
|
||||
)
|
||||
location.reload();
|
||||
if (this.#commandModeOptions.commandMode === GAME_MASTER && commandModeOptions.commandMode !== GAME_MASTER) location.reload();
|
||||
|
||||
/* Check if any option has changed */
|
||||
var commandModeOptionsChanged =
|
||||
!commandModeOptions.eras.every((value: string, idx: number) => {
|
||||
return value === this.getCommandModeOptions().eras[idx];
|
||||
}) ||
|
||||
commandModeOptions.spawnPoints.red !==
|
||||
this.getCommandModeOptions().spawnPoints.red ||
|
||||
commandModeOptions.spawnPoints.blue !==
|
||||
this.getCommandModeOptions().spawnPoints.blue ||
|
||||
commandModeOptions.restrictSpawns !==
|
||||
this.getCommandModeOptions().restrictSpawns ||
|
||||
commandModeOptions.restrictToCoalition !==
|
||||
this.getCommandModeOptions().restrictToCoalition;
|
||||
commandModeOptions.spawnPoints.red !== this.getCommandModeOptions().spawnPoints.red ||
|
||||
commandModeOptions.spawnPoints.blue !== this.getCommandModeOptions().spawnPoints.blue ||
|
||||
commandModeOptions.restrictSpawns !== this.getCommandModeOptions().restrictSpawns ||
|
||||
commandModeOptions.restrictToCoalition !== this.getCommandModeOptions().restrictToCoalition;
|
||||
|
||||
this.#commandModeOptions = commandModeOptions;
|
||||
this.setSpentSpawnPoints(0);
|
||||
this.refreshSpawnPoints();
|
||||
|
||||
if (commandModeOptionsChanged) {
|
||||
document.dispatchEvent(
|
||||
new CustomEvent("commandModeOptionsChanged", { detail: this })
|
||||
);
|
||||
document.dispatchEvent(new CustomEvent("commandModeOptionsChanged", { detail: this }));
|
||||
document.getElementById("command-mode-toolbar")?.classList.remove("hide");
|
||||
const el = document.getElementById("command-mode");
|
||||
if (el) {
|
||||
@@ -380,24 +310,13 @@ export class MissionManager {
|
||||
|
||||
document
|
||||
.querySelector("#spawn-points-container")
|
||||
?.classList.toggle(
|
||||
"hide",
|
||||
this.getCommandModeOptions().commandMode === GAME_MASTER ||
|
||||
!this.getCommandModeOptions().restrictSpawns
|
||||
);
|
||||
document
|
||||
.querySelector("#command-mode-settings-button")
|
||||
?.classList.toggle(
|
||||
"hide",
|
||||
this.getCommandModeOptions().commandMode !== GAME_MASTER
|
||||
);
|
||||
?.classList.toggle("hide", this.getCommandModeOptions().commandMode === GAME_MASTER || !this.getCommandModeOptions().restrictSpawns);
|
||||
document.querySelector("#command-mode-settings-button")?.classList.toggle("hide", this.getCommandModeOptions().commandMode !== GAME_MASTER);
|
||||
|
||||
if (requestRefresh) getApp().getServerManager().refreshAll();
|
||||
}
|
||||
|
||||
#onAirbaseClick(e: any) {
|
||||
|
||||
}
|
||||
#onAirbaseClick(e: any) {}
|
||||
|
||||
#loadAirbaseChartData(callsign: string) {
|
||||
if (!this.#theatre) {
|
||||
@@ -405,11 +324,7 @@ export class MissionManager {
|
||||
}
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open(
|
||||
"GET",
|
||||
`api/airbases/${this.#theatre.toLowerCase()}/${callsign}`,
|
||||
true
|
||||
);
|
||||
xhr.open("GET", `api/airbases/${this.#theatre.toLowerCase()}/${callsign}`, true);
|
||||
xhr.responseType = "json";
|
||||
xhr.onload = () => {
|
||||
var status = xhr.status;
|
||||
|
||||
@@ -19,12 +19,7 @@ import { UnitsManager } from "./unit/unitsmanager";
|
||||
import { WeaponsManager } from "./weapon/weaponsmanager";
|
||||
import { ServerManager } from "./server/servermanager";
|
||||
|
||||
import {
|
||||
BLUE_COMMANDER,
|
||||
DEFAULT_CONTEXT,
|
||||
GAME_MASTER,
|
||||
RED_COMMANDER,
|
||||
} from "./constants/constants";
|
||||
import { BLUE_COMMANDER, DEFAULT_CONTEXT, GAME_MASTER, RED_COMMANDER } from "./constants/constants";
|
||||
import { aircraftDatabase } from "./unit/databases/aircraftdatabase";
|
||||
import { helicopterDatabase } from "./unit/databases/helicopterdatabase";
|
||||
import { groundUnitDatabase } from "./unit/databases/groundunitdatabase";
|
||||
@@ -96,10 +91,7 @@ export class OlympusApp {
|
||||
* @param newActiveCoalition
|
||||
*/
|
||||
setActiveCoalition(newActiveCoalition: Coalition) {
|
||||
if (
|
||||
this.getMissionManager().getCommandModeOptions().commandMode ==
|
||||
GAME_MASTER
|
||||
) {
|
||||
if (this.getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER) {
|
||||
this.#activeCoalition = newActiveCoalition;
|
||||
document.dispatchEvent(new CustomEvent("activeCoalitionChanged"));
|
||||
}
|
||||
@@ -110,22 +102,10 @@ export class OlympusApp {
|
||||
* @returns The active coalition
|
||||
*/
|
||||
getActiveCoalition(): Coalition {
|
||||
if (
|
||||
this.getMissionManager().getCommandModeOptions().commandMode ==
|
||||
GAME_MASTER
|
||||
)
|
||||
return this.#activeCoalition;
|
||||
if (this.getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER) return this.#activeCoalition;
|
||||
else {
|
||||
if (
|
||||
this.getMissionManager().getCommandModeOptions().commandMode ==
|
||||
BLUE_COMMANDER
|
||||
)
|
||||
return "blue";
|
||||
else if (
|
||||
this.getMissionManager().getCommandModeOptions().commandMode ==
|
||||
RED_COMMANDER
|
||||
)
|
||||
return "red";
|
||||
if (this.getMissionManager().getCommandModeOptions().commandMode == BLUE_COMMANDER) return "blue";
|
||||
else if (this.getMissionManager().getCommandModeOptions().commandMode == RED_COMMANDER) return "red";
|
||||
else return "neutral";
|
||||
}
|
||||
}
|
||||
@@ -173,46 +153,32 @@ export class OlympusApp {
|
||||
this.#weaponsManager = new WeaponsManager();
|
||||
|
||||
/* Set the address of the server */
|
||||
this.getServerManager().setAddress(
|
||||
window.location.href.split("?")[0].replace("vite/", "")
|
||||
);
|
||||
this.getServerManager().setAddress(window.location.href.split("?")[0].replace("vite/", ""));
|
||||
|
||||
/* Setup all global events */
|
||||
this.#setupEvents();
|
||||
|
||||
/* Check if we are running the latest version */
|
||||
const request = new Request(
|
||||
"https://raw.githubusercontent.com/Pax1601/DCSOlympus/main/version.json"
|
||||
);
|
||||
const request = new Request("https://raw.githubusercontent.com/Pax1601/DCSOlympus/main/version.json");
|
||||
fetch(request)
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
return response.json();
|
||||
} else {
|
||||
throw new Error(
|
||||
"Error connecting to Github to retrieve latest version"
|
||||
);
|
||||
throw new Error("Error connecting to Github to retrieve latest version");
|
||||
}
|
||||
})
|
||||
.then((res) => {
|
||||
this.#latestVersion = res["version"];
|
||||
const latestVersionSpan = document.getElementById(
|
||||
"latest-version"
|
||||
) as HTMLElement;
|
||||
const latestVersionSpan = document.getElementById("latest-version") as HTMLElement;
|
||||
if (latestVersionSpan) {
|
||||
latestVersionSpan.innerHTML = this.#latestVersion ?? "Unknown";
|
||||
latestVersionSpan.classList.toggle(
|
||||
"new-version",
|
||||
this.#latestVersion !== VERSION
|
||||
);
|
||||
latestVersionSpan.classList.toggle("new-version", this.#latestVersion !== VERSION);
|
||||
}
|
||||
});
|
||||
|
||||
/* Load the config file from the server */
|
||||
const configRequest = new Request(
|
||||
window.location.href.split("?")[0].replace("vite/", "") +
|
||||
"resources/config"
|
||||
);
|
||||
const configRequest = new Request(window.location.href.split("?")[0].replace("vite/", "") + "resources/config");
|
||||
fetch(configRequest)
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
|
||||
@@ -4,12 +4,7 @@ import { UnitDatabase } from "../unit/databases/unitdatabase";
|
||||
import { aircraftDatabase } from "../unit/databases/aircraftdatabase";
|
||||
import { helicopterDatabase } from "../unit/databases/helicopterdatabase";
|
||||
import { groundUnitDatabase } from "../unit/databases/groundunitdatabase";
|
||||
import {
|
||||
ROEs,
|
||||
emissionsCountermeasures,
|
||||
reactionsToThreat,
|
||||
states,
|
||||
} from "../constants/constants";
|
||||
import { ROEs, emissionsCountermeasures, reactionsToThreat, states } from "../constants/constants";
|
||||
import { navyUnitDatabase } from "../unit/databases/navyunitdatabase";
|
||||
import { DateAndTime, UnitBlueprint } from "../interfaces";
|
||||
import { Converter } from "usng";
|
||||
@@ -17,41 +12,27 @@ import { MGRS } from "../types/types";
|
||||
import { getApp } from "../olympusapp";
|
||||
import { featureCollection } from "turf";
|
||||
|
||||
export function bearing(
|
||||
lat1: number,
|
||||
lon1: number,
|
||||
lat2: number,
|
||||
lon2: number
|
||||
) {
|
||||
export function bearing(lat1: number, lon1: number, lat2: number, lon2: number) {
|
||||
const φ1 = deg2rad(lat1); // φ, λ in radians
|
||||
const φ2 = deg2rad(lat2);
|
||||
const λ1 = deg2rad(lon1); // φ, λ in radians
|
||||
const λ2 = deg2rad(lon2);
|
||||
const y = Math.sin(λ2 - λ1) * Math.cos(φ2);
|
||||
const x =
|
||||
Math.cos(φ1) * Math.sin(φ2) -
|
||||
Math.sin(φ1) * Math.cos(φ2) * Math.cos(λ2 - λ1);
|
||||
const x = Math.cos(φ1) * Math.sin(φ2) - Math.sin(φ1) * Math.cos(φ2) * Math.cos(λ2 - λ1);
|
||||
const θ = Math.atan2(y, x);
|
||||
const brng = (rad2deg(θ) + 360) % 360; // in degrees
|
||||
|
||||
return brng;
|
||||
}
|
||||
|
||||
export function distance(
|
||||
lat1: number,
|
||||
lon1: number,
|
||||
lat2: number,
|
||||
lon2: number
|
||||
) {
|
||||
export function distance(lat1: number, lon1: number, lat2: number, lon2: number) {
|
||||
const R = 6371e3; // metres
|
||||
const φ1 = deg2rad(lat1); // φ, λ in radians
|
||||
const φ2 = deg2rad(lat2);
|
||||
const Δφ = deg2rad(lat2 - lat1);
|
||||
const Δλ = deg2rad(lon2 - lon1);
|
||||
|
||||
const a =
|
||||
Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
|
||||
Math.cos(φ1) * Math.cos(φ2) * Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
|
||||
const a = Math.sin(Δφ / 2) * Math.sin(Δφ / 2) + Math.cos(φ1) * Math.cos(φ2) * Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
|
||||
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||
|
||||
const d = R * c; // in metres
|
||||
@@ -59,25 +40,12 @@ export function distance(
|
||||
return d;
|
||||
}
|
||||
|
||||
export function bearingAndDistanceToLatLng(
|
||||
lat: number,
|
||||
lon: number,
|
||||
brng: number,
|
||||
dist: number
|
||||
) {
|
||||
export function bearingAndDistanceToLatLng(lat: number, lon: number, brng: number, dist: number) {
|
||||
const R = 6371e3; // metres
|
||||
const φ1 = deg2rad(lat); // φ, λ in radians
|
||||
const λ1 = deg2rad(lon);
|
||||
const φ2 = Math.asin(
|
||||
Math.sin(φ1) * Math.cos(dist / R) +
|
||||
Math.cos(φ1) * Math.sin(dist / R) * Math.cos(brng)
|
||||
);
|
||||
const λ2 =
|
||||
λ1 +
|
||||
Math.atan2(
|
||||
Math.sin(brng) * Math.sin(dist / R) * Math.cos(φ1),
|
||||
Math.cos(dist / R) - Math.sin(φ1) * Math.sin(φ2)
|
||||
);
|
||||
const φ2 = Math.asin(Math.sin(φ1) * Math.cos(dist / R) + Math.cos(φ1) * Math.sin(dist / R) * Math.cos(brng));
|
||||
const λ2 = λ1 + Math.atan2(Math.sin(brng) * Math.sin(dist / R) * Math.cos(φ1), Math.cos(dist / R) - Math.sin(φ1) * Math.sin(φ2));
|
||||
|
||||
return new LatLng(rad2deg(φ2), rad2deg(λ2));
|
||||
}
|
||||
@@ -89,30 +57,8 @@ export function ConvertDDToDMS(D: number, lng: boolean) {
|
||||
var sec = (0 | (((D * 60) % 1) * 6000)) / 100;
|
||||
var dec = Math.round((sec - Math.floor(sec)) * 100);
|
||||
var sec = Math.floor(sec);
|
||||
if (lng)
|
||||
return (
|
||||
dir +
|
||||
zeroPad(deg, 3) +
|
||||
"°" +
|
||||
zeroPad(min, 2) +
|
||||
"'" +
|
||||
zeroPad(sec, 2) +
|
||||
"." +
|
||||
zeroPad(dec, 2) +
|
||||
'"'
|
||||
);
|
||||
else
|
||||
return (
|
||||
dir +
|
||||
zeroPad(deg, 2) +
|
||||
"°" +
|
||||
zeroPad(min, 2) +
|
||||
"'" +
|
||||
zeroPad(sec, 2) +
|
||||
"." +
|
||||
zeroPad(dec, 2) +
|
||||
'"'
|
||||
);
|
||||
if (lng) return dir + zeroPad(deg, 3) + "°" + zeroPad(min, 2) + "'" + zeroPad(sec, 2) + "." + zeroPad(dec, 2) + '"';
|
||||
else return dir + zeroPad(deg, 2) + "°" + zeroPad(min, 2) + "'" + zeroPad(sec, 2) + "." + zeroPad(dec, 2) + '"';
|
||||
}
|
||||
|
||||
export function dataPointMap(container: HTMLElement, data: any) {
|
||||
@@ -149,10 +95,7 @@ export function generateUUIDv4() {
|
||||
|
||||
export function keyEventWasInInput(event: KeyboardEvent) {
|
||||
const target = event.target;
|
||||
return (
|
||||
target instanceof HTMLElement &&
|
||||
["INPUT", "TEXTAREA"].includes(target.nodeName)
|
||||
);
|
||||
return target instanceof HTMLElement && ["INPUT", "TEXTAREA"].includes(target.nodeName);
|
||||
}
|
||||
|
||||
export function reciprocalHeading(heading: number): number {
|
||||
@@ -167,11 +110,7 @@ export function reciprocalHeading(heading: number): number {
|
||||
* @param decimal <boolean> whether this is a decimal number or not
|
||||
*
|
||||
* */
|
||||
export const zeroAppend = function (
|
||||
num: number,
|
||||
places: number,
|
||||
decimal: boolean = false
|
||||
) {
|
||||
export const zeroAppend = function (num: number, places: number, decimal: boolean = false) {
|
||||
var string = decimal ? num.toFixed(2) : String(num);
|
||||
while (string.length < places) {
|
||||
string = "0" + string;
|
||||
@@ -213,8 +152,7 @@ export function editDistance(s1: string, s2: string) {
|
||||
else {
|
||||
if (j > 0) {
|
||||
var newValue = costs[j - 1];
|
||||
if (s1.charAt(i - 1) != s2.charAt(j - 1))
|
||||
newValue = Math.min(Math.min(newValue, lastValue), costs[j]) + 1;
|
||||
if (s1.charAt(i - 1) != s2.charAt(j - 1)) newValue = Math.min(Math.min(newValue, lastValue), costs[j]) + 1;
|
||||
costs[j - 1] = lastValue;
|
||||
lastValue = newValue;
|
||||
}
|
||||
@@ -225,16 +163,9 @@ export function editDistance(s1: string, s2: string) {
|
||||
return costs[s2.length];
|
||||
}
|
||||
|
||||
export function latLngToMGRS(
|
||||
lat: number,
|
||||
lng: number,
|
||||
precision: number = 4
|
||||
): MGRS | false {
|
||||
export function latLngToMGRS(lat: number, lng: number, precision: number = 4): MGRS | false {
|
||||
if (precision < 0 || precision > 6) {
|
||||
console.error(
|
||||
"latLngToMGRS: precision must be a number >= 0 and <= 6. Given precision: " +
|
||||
precision
|
||||
);
|
||||
console.error("latLngToMGRS: precision must be a number >= 0 and <= 6. Given precision: " + precision);
|
||||
return false;
|
||||
}
|
||||
const mgrs = new Converter({}).LLtoMGRS(lat, lng, precision);
|
||||
@@ -261,10 +192,7 @@ export function latLngToUTM(lat: number, lng: number) {
|
||||
return new Converter({}).LLtoUTM(lat, lng);
|
||||
}
|
||||
|
||||
export function latLngToMercator(
|
||||
lat: number,
|
||||
lng: number
|
||||
): { x: number; y: number } {
|
||||
export function latLngToMercator(lat: number, lng: number): { x: number; y: number } {
|
||||
var rMajor = 6378137; //Equatorial Radius, WGS84
|
||||
var shift = Math.PI * rMajor;
|
||||
var x = (lng * shift) / 180;
|
||||
@@ -279,9 +207,7 @@ export function mercatorToLatLng(x: number, y: number) {
|
||||
var shift = Math.PI * rMajor;
|
||||
var lng = (x / shift) * 180.0;
|
||||
var lat = (y / shift) * 180.0;
|
||||
lat =
|
||||
(180 / Math.PI) *
|
||||
(2 * Math.atan(Math.exp((lat * Math.PI) / 180.0)) - Math.PI / 2.0);
|
||||
lat = (180 / Math.PI) * (2 * Math.atan(Math.exp((lat * Math.PI) / 180.0)) - Math.PI / 2.0);
|
||||
|
||||
return { lng: lng, lat: lat };
|
||||
}
|
||||
@@ -325,21 +251,13 @@ export function polyContains(latlng: LatLng, polygon: Polygon) {
|
||||
return [latlng.lng, latlng.lat];
|
||||
}),
|
||||
];
|
||||
coordinates[0].push([
|
||||
polygon.getLatLngs()[0][0].lng,
|
||||
polygon.getLatLngs()[0][0].lat,
|
||||
]);
|
||||
coordinates[0].push([polygon.getLatLngs()[0][0].lng, polygon.getLatLngs()[0][0].lat]);
|
||||
const poly = turf.polygon(coordinates);
|
||||
return turf.inside(turf.point([latlng.lng, latlng.lat]), poly);
|
||||
}
|
||||
|
||||
export function circleContains(latlng: LatLng, circle: Circle) {
|
||||
const poly = turf.circle(
|
||||
turf.point([circle.getLatLng().lng, circle.getLatLng().lat]),
|
||||
circle.getRadius() / 1000,
|
||||
100,
|
||||
"kilometers"
|
||||
);
|
||||
const poly = turf.circle(turf.point([circle.getLatLng().lng, circle.getLatLng().lat]), circle.getRadius() / 1000, 100, "kilometers");
|
||||
return turf.inside(turf.point([latlng.lng, latlng.lat]), poly);
|
||||
}
|
||||
|
||||
@@ -349,16 +267,10 @@ export function polyCenter(polygon: Polygon) {
|
||||
return [latlng.lng, latlng.lat];
|
||||
}),
|
||||
];
|
||||
coordinates[0].push([
|
||||
polygon.getLatLngs()[0][0].lng,
|
||||
polygon.getLatLngs()[0][0].lat,
|
||||
]);
|
||||
coordinates[0].push([polygon.getLatLngs()[0][0].lng, polygon.getLatLngs()[0][0].lat]);
|
||||
const poly = turf.polygon(coordinates);
|
||||
const center = turf.center(featureCollection([poly]));
|
||||
return new LatLng(
|
||||
center.geometry.coordinates[1],
|
||||
center.geometry.coordinates[0]
|
||||
);
|
||||
return new LatLng(center.geometry.coordinates[1], center.geometry.coordinates[0]);
|
||||
}
|
||||
|
||||
export function randomPointInPoly(polygon: Polygon): LatLng {
|
||||
@@ -376,10 +288,7 @@ export function randomPointInPoly(polygon: Polygon): LatLng {
|
||||
return [latlng.lng, latlng.lat];
|
||||
}),
|
||||
];
|
||||
coordinates[0].push([
|
||||
polygon.getLatLngs()[0][0].lng,
|
||||
polygon.getLatLngs()[0][0].lat,
|
||||
]);
|
||||
coordinates[0].push([polygon.getLatLngs()[0][0].lng, polygon.getLatLngs()[0][0].lat]);
|
||||
const poly = turf.polygon(coordinates);
|
||||
var inside = turf.inside(turf.point([lng, lat]), poly);
|
||||
|
||||
@@ -410,9 +319,7 @@ export function randomUnitBlueprint(
|
||||
|
||||
/* If a specific type or role is provided, use only the blueprints of that type or role */
|
||||
if (options.type && options.role) {
|
||||
console.error(
|
||||
"Can't create random unit if both type and role are provided. Either create by type or by role."
|
||||
);
|
||||
console.error("Can't create random unit if both type and role are provided. Either create by type or by role.");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -439,18 +346,14 @@ export function randomUnitBlueprint(
|
||||
/* Keep only the units that have an era included in the requested values */
|
||||
if (options.eras) {
|
||||
unitBlueprints = unitBlueprints.filter((unitBlueprint: UnitBlueprint) => {
|
||||
return unitBlueprint.era
|
||||
? options.eras?.includes(unitBlueprint.era)
|
||||
: true;
|
||||
return unitBlueprint.era ? options.eras?.includes(unitBlueprint.era) : true;
|
||||
});
|
||||
}
|
||||
|
||||
/* Keep only the units that have the correct coalition, if selected */
|
||||
if (options.coalition) {
|
||||
unitBlueprints = unitBlueprints.filter((unitBlueprint: UnitBlueprint) => {
|
||||
return unitBlueprint.coalition && unitBlueprint.coalition !== ""
|
||||
? options.coalition === unitBlueprint.coalition
|
||||
: true;
|
||||
return unitBlueprint.coalition && unitBlueprint.coalition !== "" ? options.coalition === unitBlueprint.coalition : true;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -463,8 +366,7 @@ export function getMarkerCategoryByName(name: string) {
|
||||
else if (helicopterDatabase.getByName(name) != null) return "helicopter";
|
||||
else if (groundUnitDatabase.getByName(name) != null) {
|
||||
var type = groundUnitDatabase.getByName(name)?.type ?? "";
|
||||
if (/\bAAA|SAM\b/.test(type) || /\bmanpad|stinger\b/i.test(type))
|
||||
return "groundunit-sam";
|
||||
if (/\bAAA|SAM\b/.test(type) || /\bmanpad|stinger\b/i.test(type)) return "groundunit-sam";
|
||||
else return "groundunit-other";
|
||||
} else if (navyUnitDatabase.getByName(name) != null) return "navyunit";
|
||||
else return "aircraft"; // TODO add other unit types
|
||||
@@ -473,8 +375,7 @@ export function getMarkerCategoryByName(name: string) {
|
||||
export function getUnitDatabaseByCategory(category: string) {
|
||||
if (category.toLowerCase() == "aircraft") return aircraftDatabase;
|
||||
else if (category.toLowerCase() == "helicopter") return helicopterDatabase;
|
||||
else if (category.toLowerCase().includes("groundunit"))
|
||||
return groundUnitDatabase;
|
||||
else if (category.toLowerCase().includes("groundunit")) return groundUnitDatabase;
|
||||
else if (category.toLowerCase().includes("navyunit")) return navyUnitDatabase;
|
||||
else return null;
|
||||
}
|
||||
@@ -502,14 +403,12 @@ export function enumToROE(ROE: number) {
|
||||
}
|
||||
|
||||
export function enumToReactionToThreat(reactionToThreat: number) {
|
||||
if (reactionToThreat < reactionsToThreat.length)
|
||||
return reactionsToThreat[reactionToThreat];
|
||||
if (reactionToThreat < reactionsToThreat.length) return reactionsToThreat[reactionToThreat];
|
||||
else return reactionsToThreat[0];
|
||||
}
|
||||
|
||||
export function enumToEmissioNCountermeasure(emissionCountermeasure: number) {
|
||||
if (emissionCountermeasure < emissionsCountermeasures.length)
|
||||
return emissionsCountermeasures[emissionCountermeasure];
|
||||
if (emissionCountermeasure < emissionsCountermeasures.length) return emissionsCountermeasures[emissionCountermeasure];
|
||||
else return emissionsCountermeasures[0];
|
||||
}
|
||||
|
||||
@@ -595,25 +494,16 @@ export function getFunctionArguments(func) {
|
||||
var ARGUMENT_NAMES = /([^\s,]+)/g;
|
||||
|
||||
var fnStr = func.toString().replace(STRIP_COMMENTS, "");
|
||||
var result = fnStr
|
||||
.slice(fnStr.indexOf("(") + 1, fnStr.indexOf(")"))
|
||||
.match(ARGUMENT_NAMES);
|
||||
var result = fnStr.slice(fnStr.indexOf("(") + 1, fnStr.indexOf(")")).match(ARGUMENT_NAMES);
|
||||
if (result === null) result = [];
|
||||
return result;
|
||||
}
|
||||
|
||||
export function filterBlueprintsByLabel(
|
||||
blueprints: { [key: string]: UnitBlueprint },
|
||||
filterString: string
|
||||
) {
|
||||
export function filterBlueprintsByLabel(blueprints: { [key: string]: UnitBlueprint }, filterString: string) {
|
||||
var filteredBlueprints: { [key: string]: UnitBlueprint } = {};
|
||||
if (blueprints) {
|
||||
Object.entries(blueprints).forEach(([key, value]) => {
|
||||
if (
|
||||
value.enabled &&
|
||||
(filterString === "" || value.label.includes(filterString))
|
||||
)
|
||||
filteredBlueprints[key] = value;
|
||||
if (value.enabled && (filterString === "" || value.label.includes(filterString))) filteredBlueprints[key] = value;
|
||||
});
|
||||
}
|
||||
return filteredBlueprints;
|
||||
@@ -621,35 +511,24 @@ export function filterBlueprintsByLabel(
|
||||
|
||||
export function getUnitsByLabel(filterString: string) {
|
||||
/* Filter aircrafts, helicopters, and navyunits */
|
||||
const filteredAircraft = filterBlueprintsByLabel(
|
||||
getApp()?.getAircraftDatabase()?.blueprints,
|
||||
filterString
|
||||
);
|
||||
const filteredHelicopters = filterBlueprintsByLabel(
|
||||
getApp()?.getHelicopterDatabase()?.blueprints,
|
||||
filterString
|
||||
);
|
||||
const filteredNavyUnits = filterBlueprintsByLabel(
|
||||
getApp()?.getNavyUnitDatabase()?.blueprints,
|
||||
filterString
|
||||
);
|
||||
const filteredAircraft = filterBlueprintsByLabel(getApp()?.getAircraftDatabase()?.blueprints, filterString);
|
||||
const filteredHelicopters = filterBlueprintsByLabel(getApp()?.getHelicopterDatabase()?.blueprints, filterString);
|
||||
const filteredNavyUnits = filterBlueprintsByLabel(getApp()?.getNavyUnitDatabase()?.blueprints, filterString);
|
||||
|
||||
/* Split ground units between air defence and all others */
|
||||
var filteredAirDefense: { [key: string]: UnitBlueprint } = {};
|
||||
var filteredGroundUnits: { [key: string]: UnitBlueprint } = {};
|
||||
Object.keys(getApp()?.getGroundUnitDatabase()?.blueprints ?? {}).forEach(
|
||||
(key) => {
|
||||
var blueprint = getApp()?.getGroundUnitDatabase()?.blueprints[key];
|
||||
var type = blueprint.label;
|
||||
if (/\bAAA|SAM\b/.test(type) || /\bmanpad|stinger\b/i.test(type)) {
|
||||
filteredAirDefense[key] = blueprint;
|
||||
} else {
|
||||
filteredGroundUnits[key] = blueprint;
|
||||
}
|
||||
Object.keys(getApp()?.getGroundUnitDatabase()?.blueprints ?? {}).forEach((key) => {
|
||||
var blueprint = getApp()?.getGroundUnitDatabase()?.blueprints[key];
|
||||
var type = blueprint.label;
|
||||
if (/\bAAA|SAM\b/.test(type) || /\bmanpad|stinger\b/i.test(type)) {
|
||||
filteredAirDefense[key] = blueprint;
|
||||
} else {
|
||||
filteredGroundUnits[key] = blueprint;
|
||||
}
|
||||
);
|
||||
});
|
||||
filteredAirDefense = filterBlueprintsByLabel(filteredAirDefense, filterString);
|
||||
filteredGroundUnits = filterBlueprintsByLabel(filteredGroundUnits, filterString);
|
||||
|
||||
return [filteredAircraft, filteredHelicopters, filteredAirDefense, filteredGroundUnits, filteredNavyUnits]
|
||||
}
|
||||
return [filteredAircraft, filteredHelicopters, filteredAirDefense, filteredGroundUnits, filteredNavyUnits];
|
||||
}
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
import { LatLng } from "leaflet";
|
||||
import {
|
||||
Ammo,
|
||||
Contact,
|
||||
GeneralSettings,
|
||||
Offset,
|
||||
Radio,
|
||||
TACAN,
|
||||
} from "../interfaces";
|
||||
import { Ammo, Contact, GeneralSettings, Offset, Radio, TACAN } from "../interfaces";
|
||||
|
||||
export class DataExtractor {
|
||||
#seekPosition = 0;
|
||||
@@ -65,11 +58,7 @@ export class DataExtractor {
|
||||
}
|
||||
|
||||
extractLatLng() {
|
||||
return new LatLng(
|
||||
this.extractFloat64(),
|
||||
this.extractFloat64(),
|
||||
this.extractFloat64()
|
||||
);
|
||||
return new LatLng(this.extractFloat64(), this.extractFloat64(), this.extractFloat64());
|
||||
}
|
||||
|
||||
extractFromBitmask(bitmask: number, position: number) {
|
||||
@@ -78,10 +67,7 @@ export class DataExtractor {
|
||||
|
||||
extractString(length?: number) {
|
||||
if (length === undefined) length = this.extractUInt16();
|
||||
var stringBuffer = this.#buffer.slice(
|
||||
this.#seekPosition,
|
||||
this.#seekPosition + length
|
||||
);
|
||||
var stringBuffer = this.#buffer.slice(this.#seekPosition, this.#seekPosition + length);
|
||||
var view = new Int8Array(stringBuffer);
|
||||
var stringLength = length;
|
||||
view.every((value: number, idx: number) => {
|
||||
|
||||
@@ -13,16 +13,7 @@ import {
|
||||
emissionsCountermeasures,
|
||||
reactionsToThreat,
|
||||
} from "../constants/constants";
|
||||
import {
|
||||
AirbasesData,
|
||||
BullseyesData,
|
||||
GeneralSettings,
|
||||
MissionData,
|
||||
Radio,
|
||||
ServerRequestOptions,
|
||||
ServerStatus,
|
||||
TACAN,
|
||||
} from "../interfaces";
|
||||
import { AirbasesData, BullseyesData, GeneralSettings, MissionData, Radio, ServerRequestOptions, ServerStatus, TACAN } from "../interfaces";
|
||||
|
||||
export class ServerManager {
|
||||
#connected: boolean = false;
|
||||
@@ -67,11 +58,7 @@ export class ServerManager {
|
||||
/* If a request on this uri is still pending (meaning it's not done or did not yet fail), skip the request, to avoid clogging the TCP workers */
|
||||
/* If we are forcing the request we don't care if one already exists, just send it. CAREFUL: this makes sense only for low frequency requests, like refreshes, when we
|
||||
are reasonably confident any previous request will be done before we make a new one on the same URI. */
|
||||
if (
|
||||
uri in this.#requests &&
|
||||
this.#requests[uri].readyState !== 4 &&
|
||||
!force
|
||||
) {
|
||||
if (uri in this.#requests && this.#requests[uri].readyState !== 4 && !force) {
|
||||
console.warn(`GET request on ${uri} URI still pending, skipping...`);
|
||||
return;
|
||||
}
|
||||
@@ -81,33 +68,22 @@ export class ServerManager {
|
||||
/* Assemble the request options string */
|
||||
var optionsString = "";
|
||||
if (options?.time != undefined) optionsString = `time=${options.time}`;
|
||||
if (options?.commandHash != undefined)
|
||||
optionsString = `commandHash=${options.commandHash}`;
|
||||
if (options?.commandHash != undefined) optionsString = `commandHash=${options.commandHash}`;
|
||||
|
||||
/* On the connection */
|
||||
xmlHttp.open(
|
||||
"GET",
|
||||
`${this.#REST_ADDRESS}/${uri}${optionsString ? `?${optionsString}` : ""}`,
|
||||
true
|
||||
);
|
||||
xmlHttp.open("GET", `${this.#REST_ADDRESS}/${uri}${optionsString ? `?${optionsString}` : ""}`, true);
|
||||
|
||||
/* If provided, set the credentials */
|
||||
if (this.#username && this.#password)
|
||||
xmlHttp.setRequestHeader(
|
||||
"Authorization",
|
||||
"Basic " + btoa(`${this.#username}:${this.#password}`)
|
||||
);
|
||||
if (this.#username && this.#password) xmlHttp.setRequestHeader("Authorization", "Basic " + btoa(`${this.#username}:${this.#password}`));
|
||||
|
||||
/* If specified, set the response type */
|
||||
if (responseType)
|
||||
xmlHttp.responseType = responseType as XMLHttpRequestResponseType;
|
||||
if (responseType) xmlHttp.responseType = responseType as XMLHttpRequestResponseType;
|
||||
|
||||
xmlHttp.onload = (e) => {
|
||||
if (xmlHttp.status == 200) {
|
||||
/* Success */
|
||||
this.setConnected(true);
|
||||
if (xmlHttp.responseType == "arraybuffer")
|
||||
this.#lastUpdateTimes[uri] = callback(xmlHttp.response);
|
||||
if (xmlHttp.responseType == "arraybuffer") this.#lastUpdateTimes[uri] = callback(xmlHttp.response);
|
||||
else {
|
||||
const result = JSON.parse(xmlHttp.responseText);
|
||||
this.#lastUpdateTimes[uri] = callback(result);
|
||||
@@ -141,11 +117,7 @@ export class ServerManager {
|
||||
var xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.open("PUT", this.#REST_ADDRESS);
|
||||
xmlHttp.setRequestHeader("Content-Type", "application/json");
|
||||
if (this.#username && this.#password)
|
||||
xmlHttp.setRequestHeader(
|
||||
"Authorization",
|
||||
"Basic " + btoa(`${this.#username}:${this.#password}`)
|
||||
);
|
||||
if (this.#username && this.#password) xmlHttp.setRequestHeader("Authorization", "Basic " + btoa(`${this.#username}:${this.#password}`));
|
||||
xmlHttp.onload = (res: any) => {
|
||||
var res = JSON.parse(xmlHttp.responseText);
|
||||
callback(res.commandHash);
|
||||
@@ -157,99 +129,47 @@ export class ServerManager {
|
||||
|
||||
getConfig(callback: CallableFunction) {
|
||||
var xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.open(
|
||||
"GET",
|
||||
window.location.href.split("?")[0].replace("vite/", "") + "config",
|
||||
true
|
||||
);
|
||||
xmlHttp.open("GET", window.location.href.split("?")[0].replace("vite/", "") + "config", true);
|
||||
xmlHttp.onload = function (e) {
|
||||
var data = JSON.parse(xmlHttp.responseText);
|
||||
callback(data);
|
||||
};
|
||||
xmlHttp.onerror = function () {
|
||||
console.error(
|
||||
"An error occurred during the XMLHttpRequest, could not retrieve configuration file"
|
||||
);
|
||||
console.error("An error occurred during the XMLHttpRequest, could not retrieve configuration file");
|
||||
};
|
||||
xmlHttp.send(null);
|
||||
}
|
||||
|
||||
setAddress(address: string) {
|
||||
this.#REST_ADDRESS = `${address.replace('vite/', '')}olympus`;
|
||||
this.#REST_ADDRESS = `${address.replace("vite/", "")}olympus`;
|
||||
console.log(`Setting REST address to ${this.#REST_ADDRESS}`);
|
||||
}
|
||||
|
||||
getAirbases(
|
||||
callback: CallableFunction,
|
||||
errorCallback: CallableFunction = () => {}
|
||||
) {
|
||||
getAirbases(callback: CallableFunction, errorCallback: CallableFunction = () => {}) {
|
||||
this.GET(callback, errorCallback, AIRBASES_URI);
|
||||
}
|
||||
|
||||
getBullseye(
|
||||
callback: CallableFunction,
|
||||
errorCallback: CallableFunction = () => {}
|
||||
) {
|
||||
getBullseye(callback: CallableFunction, errorCallback: CallableFunction = () => {}) {
|
||||
this.GET(callback, errorCallback, BULLSEYE_URI);
|
||||
}
|
||||
|
||||
getLogs(
|
||||
callback: CallableFunction,
|
||||
refresh: boolean = false,
|
||||
errorCallback: CallableFunction = () => {}
|
||||
) {
|
||||
this.GET(
|
||||
callback,
|
||||
errorCallback,
|
||||
LOGS_URI,
|
||||
{ time: refresh ? 0 : this.#lastUpdateTimes[LOGS_URI] },
|
||||
"text",
|
||||
refresh
|
||||
);
|
||||
getLogs(callback: CallableFunction, refresh: boolean = false, errorCallback: CallableFunction = () => {}) {
|
||||
this.GET(callback, errorCallback, LOGS_URI, { time: refresh ? 0 : this.#lastUpdateTimes[LOGS_URI] }, "text", refresh);
|
||||
}
|
||||
|
||||
getMission(
|
||||
callback: CallableFunction,
|
||||
errorCallback: CallableFunction = () => {}
|
||||
) {
|
||||
getMission(callback: CallableFunction, errorCallback: CallableFunction = () => {}) {
|
||||
this.GET(callback, errorCallback, MISSION_URI);
|
||||
}
|
||||
|
||||
getUnits(
|
||||
callback: CallableFunction,
|
||||
refresh: boolean = false,
|
||||
errorCallback: CallableFunction = () => {}
|
||||
) {
|
||||
this.GET(
|
||||
callback,
|
||||
errorCallback,
|
||||
UNITS_URI,
|
||||
{ time: refresh ? 0 : this.#lastUpdateTimes[UNITS_URI] },
|
||||
"arraybuffer",
|
||||
refresh
|
||||
);
|
||||
getUnits(callback: CallableFunction, refresh: boolean = false, errorCallback: CallableFunction = () => {}) {
|
||||
this.GET(callback, errorCallback, UNITS_URI, { time: refresh ? 0 : this.#lastUpdateTimes[UNITS_URI] }, "arraybuffer", refresh);
|
||||
}
|
||||
|
||||
getWeapons(
|
||||
callback: CallableFunction,
|
||||
refresh: boolean = false,
|
||||
errorCallback: CallableFunction = () => {}
|
||||
) {
|
||||
this.GET(
|
||||
callback,
|
||||
errorCallback,
|
||||
WEAPONS_URI,
|
||||
{ time: refresh ? 0 : this.#lastUpdateTimes[WEAPONS_URI] },
|
||||
"arraybuffer",
|
||||
refresh
|
||||
);
|
||||
getWeapons(callback: CallableFunction, refresh: boolean = false, errorCallback: CallableFunction = () => {}) {
|
||||
this.GET(callback, errorCallback, WEAPONS_URI, { time: refresh ? 0 : this.#lastUpdateTimes[WEAPONS_URI] }, "arraybuffer", refresh);
|
||||
}
|
||||
|
||||
isCommandExecuted(
|
||||
callback: CallableFunction,
|
||||
commandHash: string,
|
||||
errorCallback: CallableFunction = () => {}
|
||||
) {
|
||||
isCommandExecuted(callback: CallableFunction, commandHash: string, errorCallback: CallableFunction = () => {}) {
|
||||
this.GET(callback, errorCallback, COMMANDS_URI, {
|
||||
commandHash: commandHash,
|
||||
});
|
||||
@@ -261,22 +181,13 @@ export class ServerManager {
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
spawnSmoke(
|
||||
color: string,
|
||||
latlng: LatLng,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
spawnSmoke(color: string, latlng: LatLng, callback: CallableFunction = () => {}) {
|
||||
var command = { color: color, location: latlng };
|
||||
var data = { smoke: command };
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
spawnExplosion(
|
||||
intensity: number,
|
||||
explosionType: string,
|
||||
latlng: LatLng,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
spawnExplosion(intensity: number, explosionType: string, latlng: LatLng, callback: CallableFunction = () => {}) {
|
||||
var command = {
|
||||
explosionType: explosionType,
|
||||
intensity: intensity,
|
||||
@@ -328,14 +239,7 @@ export class ServerManager {
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
spawnGroundUnits(
|
||||
units: any,
|
||||
coalition: string,
|
||||
country: string,
|
||||
immediate: boolean,
|
||||
spawnPoints: number,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
spawnGroundUnits(units: any, coalition: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => {}) {
|
||||
var command = {
|
||||
units: units,
|
||||
coalition: coalition,
|
||||
@@ -347,14 +251,7 @@ export class ServerManager {
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
spawnNavyUnits(
|
||||
units: any,
|
||||
coalition: string,
|
||||
country: string,
|
||||
immediate: boolean,
|
||||
spawnPoints: number,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
spawnNavyUnits(units: any, coalition: string, country: string, immediate: boolean, spawnPoints: number, callback: CallableFunction = () => {}) {
|
||||
var command = {
|
||||
units: units,
|
||||
coalition: coalition,
|
||||
@@ -366,22 +263,13 @@ export class ServerManager {
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
attackUnit(
|
||||
ID: number,
|
||||
targetID: number,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
attackUnit(ID: number, targetID: number, callback: CallableFunction = () => {}) {
|
||||
var command = { ID: ID, targetID: targetID };
|
||||
var data = { attackUnit: command };
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
followUnit(
|
||||
ID: number,
|
||||
targetID: number,
|
||||
offset: { x: number; y: number; z: number },
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
followUnit(ID: number, targetID: number, offset: { x: number; y: number; z: number }, callback: CallableFunction = () => {}) {
|
||||
// X: front-rear, positive front
|
||||
// Y: top-bottom, positive bottom
|
||||
// Z: left-right, positive right
|
||||
@@ -397,12 +285,7 @@ export class ServerManager {
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
cloneUnits(
|
||||
units: { ID: number; location: LatLng }[],
|
||||
deleteOriginal: boolean,
|
||||
spawnPoints: number,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
cloneUnits(units: { ID: number; location: LatLng }[], deleteOriginal: boolean, spawnPoints: number, callback: CallableFunction = () => {}) {
|
||||
var command = {
|
||||
units: units,
|
||||
deleteOriginal: deleteOriginal,
|
||||
@@ -412,13 +295,7 @@ export class ServerManager {
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
deleteUnit(
|
||||
ID: number,
|
||||
explosion: boolean,
|
||||
explosionType: string,
|
||||
immediate: boolean,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
deleteUnit(ID: number, explosion: boolean, explosionType: string, immediate: boolean, callback: CallableFunction = () => {}) {
|
||||
var command = {
|
||||
ID: ID,
|
||||
explosion: explosion,
|
||||
@@ -435,11 +312,7 @@ export class ServerManager {
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
changeSpeed(
|
||||
ID: number,
|
||||
speedChange: string,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
changeSpeed(ID: number, speedChange: string, callback: CallableFunction = () => {}) {
|
||||
var command = { ID: ID, change: speedChange };
|
||||
var data = { changeSpeed: command };
|
||||
this.PUT(data, callback);
|
||||
@@ -451,52 +324,31 @@ export class ServerManager {
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setSpeedType(
|
||||
ID: number,
|
||||
speedType: string,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
setSpeedType(ID: number, speedType: string, callback: CallableFunction = () => {}) {
|
||||
var command = { ID: ID, speedType: speedType };
|
||||
var data = { setSpeedType: command };
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
changeAltitude(
|
||||
ID: number,
|
||||
altitudeChange: string,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
changeAltitude(ID: number, altitudeChange: string, callback: CallableFunction = () => {}) {
|
||||
var command = { ID: ID, change: altitudeChange };
|
||||
var data = { changeAltitude: command };
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setAltitudeType(
|
||||
ID: number,
|
||||
altitudeType: string,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
setAltitudeType(ID: number, altitudeType: string, callback: CallableFunction = () => {}) {
|
||||
var command = { ID: ID, altitudeType: altitudeType };
|
||||
var data = { setAltitudeType: command };
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setAltitude(
|
||||
ID: number,
|
||||
altitude: number,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
setAltitude(ID: number, altitude: number, callback: CallableFunction = () => {}) {
|
||||
var command = { ID: ID, altitude: altitude };
|
||||
var data = { setAltitude: command };
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
createFormation(
|
||||
ID: number,
|
||||
isLeader: boolean,
|
||||
wingmenIDs: number[],
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
createFormation(ID: number, isLeader: boolean, wingmenIDs: number[], callback: CallableFunction = () => {}) {
|
||||
var command = { ID: ID, wingmenIDs: wingmenIDs, isLeader: isLeader };
|
||||
var data = { setLeader: command };
|
||||
this.PUT(data, callback);
|
||||
@@ -508,11 +360,7 @@ export class ServerManager {
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setReactionToThreat(
|
||||
ID: number,
|
||||
reactionToThreat: string,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
setReactionToThreat(ID: number, reactionToThreat: string, callback: CallableFunction = () => {}) {
|
||||
var command = {
|
||||
ID: ID,
|
||||
reactionToThreat: reactionsToThreat.indexOf(reactionToThreat),
|
||||
@@ -521,16 +369,10 @@ export class ServerManager {
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setEmissionsCountermeasures(
|
||||
ID: number,
|
||||
emissionCountermeasure: string,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
setEmissionsCountermeasures(ID: number, emissionCountermeasure: string, callback: CallableFunction = () => {}) {
|
||||
var command = {
|
||||
ID: ID,
|
||||
emissionsCountermeasures: emissionsCountermeasures.indexOf(
|
||||
emissionCountermeasure
|
||||
),
|
||||
emissionsCountermeasures: emissionsCountermeasures.indexOf(emissionCountermeasure),
|
||||
};
|
||||
var data = { setEmissionsCountermeasures: command };
|
||||
this.PUT(data, callback);
|
||||
@@ -542,21 +384,13 @@ export class ServerManager {
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setFollowRoads(
|
||||
ID: number,
|
||||
followRoads: boolean,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
setFollowRoads(ID: number, followRoads: boolean, callback: CallableFunction = () => {}) {
|
||||
var command = { ID: ID, followRoads: followRoads };
|
||||
var data = { setFollowRoads: command };
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setOperateAs(
|
||||
ID: number,
|
||||
operateAs: number,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
setOperateAs(ID: number, operateAs: number, callback: CallableFunction = () => {}) {
|
||||
var command = { ID: ID, operateAs: operateAs };
|
||||
var data = { setOperateAs: command };
|
||||
this.PUT(data, callback);
|
||||
@@ -574,94 +408,57 @@ export class ServerManager {
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
carpetBomb(
|
||||
ID: number,
|
||||
latlng: LatLng,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
carpetBomb(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) {
|
||||
var command = { ID: ID, location: latlng };
|
||||
var data = { carpetBomb: command };
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
bombBuilding(
|
||||
ID: number,
|
||||
latlng: LatLng,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
bombBuilding(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) {
|
||||
var command = { ID: ID, location: latlng };
|
||||
var data = { bombBuilding: command };
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
fireAtArea(
|
||||
ID: number,
|
||||
latlng: LatLng,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
fireAtArea(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) {
|
||||
var command = { ID: ID, location: latlng };
|
||||
var data = { fireAtArea: command };
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
simulateFireFight(
|
||||
ID: number,
|
||||
latlng: LatLng,
|
||||
altitude: number,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
simulateFireFight(ID: number, latlng: LatLng, altitude: number, callback: CallableFunction = () => {}) {
|
||||
var command = { ID: ID, location: latlng, altitude: altitude };
|
||||
var data = { simulateFireFight: command };
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
// TODO: Remove coalition
|
||||
scenicAAA(
|
||||
ID: number,
|
||||
coalition: string,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
scenicAAA(ID: number, coalition: string, callback: CallableFunction = () => {}) {
|
||||
var command = { ID: ID, coalition: coalition };
|
||||
var data = { scenicAAA: command };
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
// TODO: Remove coalition
|
||||
missOnPurpose(
|
||||
ID: number,
|
||||
coalition: string,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
missOnPurpose(ID: number, coalition: string, callback: CallableFunction = () => {}) {
|
||||
var command = { ID: ID, coalition: coalition };
|
||||
var data = { missOnPurpose: command };
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
landAtPoint(
|
||||
ID: number,
|
||||
latlng: LatLng,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
landAtPoint(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) {
|
||||
var command = { ID: ID, location: latlng };
|
||||
var data = { landAtPoint: command };
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setShotsScatter(
|
||||
ID: number,
|
||||
shotsScatter: number,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
setShotsScatter(ID: number, shotsScatter: number, callback: CallableFunction = () => {}) {
|
||||
var command = { ID: ID, shotsScatter: shotsScatter };
|
||||
var data = { setShotsScatter: command };
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setShotsIntensity(
|
||||
ID: number,
|
||||
shotsIntensity: number,
|
||||
callback: CallableFunction = () => {}
|
||||
) {
|
||||
setShotsIntensity(ID: number, shotsIntensity: number, callback: CallableFunction = () => {}) {
|
||||
var command = { ID: ID, shotsIntensity: shotsIntensity };
|
||||
var data = { setShotsIntensity: command };
|
||||
this.PUT(data, callback);
|
||||
@@ -735,11 +532,7 @@ export class ServerManager {
|
||||
|
||||
this.#intervals.push(
|
||||
window.setInterval(() => {
|
||||
if (
|
||||
!this.getPaused() &&
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode !=
|
||||
NONE
|
||||
) {
|
||||
if (!this.getPaused() && getApp().getMissionManager().getCommandModeOptions().commandMode != NONE) {
|
||||
this.getAirbases((data: AirbasesData) => {
|
||||
this.checkSessionHash(data.sessionHash);
|
||||
getApp().getMissionManager()?.updateAirbases(data);
|
||||
@@ -751,11 +544,7 @@ export class ServerManager {
|
||||
|
||||
this.#intervals.push(
|
||||
window.setInterval(() => {
|
||||
if (
|
||||
!this.getPaused() &&
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode !=
|
||||
NONE
|
||||
) {
|
||||
if (!this.getPaused() && getApp().getMissionManager().getCommandModeOptions().commandMode != NONE) {
|
||||
this.getBullseye((data: BullseyesData) => {
|
||||
this.checkSessionHash(data.sessionHash);
|
||||
getApp().getMissionManager()?.updateBullseyes(data);
|
||||
@@ -767,11 +556,7 @@ export class ServerManager {
|
||||
|
||||
this.#intervals.push(
|
||||
window.setInterval(() => {
|
||||
if (
|
||||
!this.getPaused() &&
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode !=
|
||||
NONE
|
||||
) {
|
||||
if (!this.getPaused() && getApp().getMissionManager().getCommandModeOptions().commandMode != NONE) {
|
||||
this.getLogs((data: any) => {
|
||||
this.checkSessionHash(data.sessionHash);
|
||||
//(getApp().getPanelsManager().get("log") as LogPanel).appendLogs(data.logs)
|
||||
@@ -783,11 +568,7 @@ export class ServerManager {
|
||||
|
||||
this.#intervals.push(
|
||||
window.setInterval(() => {
|
||||
if (
|
||||
!this.getPaused() &&
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode !=
|
||||
NONE
|
||||
) {
|
||||
if (!this.getPaused() && getApp().getMissionManager().getCommandModeOptions().commandMode != NONE) {
|
||||
this.getUnits((buffer: ArrayBuffer) => {
|
||||
var time = getApp().getUnitsManager()?.update(buffer);
|
||||
return time;
|
||||
@@ -798,11 +579,7 @@ export class ServerManager {
|
||||
|
||||
this.#intervals.push(
|
||||
window.setInterval(() => {
|
||||
if (
|
||||
!this.getPaused() &&
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode !=
|
||||
NONE
|
||||
) {
|
||||
if (!this.getPaused() && getApp().getMissionManager().getCommandModeOptions().commandMode != NONE) {
|
||||
this.getWeapons((buffer: ArrayBuffer) => {
|
||||
var time = getApp().getWeaponsManager()?.update(buffer);
|
||||
return time;
|
||||
@@ -814,11 +591,7 @@ export class ServerManager {
|
||||
this.#intervals.push(
|
||||
window.setInterval(
|
||||
() => {
|
||||
if (
|
||||
!this.getPaused() &&
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode !=
|
||||
NONE
|
||||
) {
|
||||
if (!this.getPaused() && getApp().getMissionManager().getCommandModeOptions().commandMode != NONE) {
|
||||
this.getUnits((buffer: ArrayBuffer) => {
|
||||
var time = getApp().getUnitsManager()?.update(buffer);
|
||||
return time;
|
||||
@@ -832,11 +605,8 @@ export class ServerManager {
|
||||
// Mission clock and elapsed time
|
||||
this.#intervals.push(
|
||||
window.setInterval(() => {
|
||||
const elapsedMissionTime = getApp()
|
||||
.getMissionManager()
|
||||
.getDateAndTime().elapsedTime;
|
||||
this.#serverIsPaused =
|
||||
elapsedMissionTime === this.#previousMissionElapsedTime;
|
||||
const elapsedMissionTime = getApp().getMissionManager().getDateAndTime().elapsedTime;
|
||||
this.#serverIsPaused = elapsedMissionTime === this.#previousMissionElapsedTime;
|
||||
this.#previousMissionElapsedTime = elapsedMissionTime;
|
||||
|
||||
document.dispatchEvent(
|
||||
@@ -844,8 +614,7 @@ export class ServerManager {
|
||||
detail: {
|
||||
frameRate: getApp().getMissionManager().getFrameRate(),
|
||||
load: getApp().getMissionManager().getLoad(),
|
||||
elapsedTime: getApp().getMissionManager().getDateAndTime()
|
||||
.elapsedTime,
|
||||
elapsedTime: getApp().getMissionManager().getDateAndTime().elapsedTime,
|
||||
missionTime: getApp().getMissionManager().getDateAndTime().time,
|
||||
connected: this.getConnected(),
|
||||
paused: this.getPaused(),
|
||||
@@ -857,11 +626,7 @@ export class ServerManager {
|
||||
|
||||
this.#intervals.push(
|
||||
window.setInterval(() => {
|
||||
if (
|
||||
!this.getPaused() &&
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode !=
|
||||
NONE
|
||||
) {
|
||||
if (!this.getPaused() && getApp().getMissionManager().getCommandModeOptions().commandMode != NONE) {
|
||||
this.getWeapons((buffer: ArrayBuffer) => {
|
||||
var time = getApp().getWeaponsManager()?.update(buffer);
|
||||
return time;
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import { getApp } from "../olympusapp";
|
||||
import {
|
||||
ShortcutKeyboardOptions,
|
||||
ShortcutMouseOptions,
|
||||
ShortcutOptions,
|
||||
} from "../interfaces";
|
||||
import { ShortcutKeyboardOptions, ShortcutMouseOptions, ShortcutOptions } from "../interfaces";
|
||||
import { keyEventWasInInput } from "../other/utils";
|
||||
|
||||
export abstract class Shortcut {
|
||||
@@ -24,10 +20,7 @@ export class ShortcutKeyboard extends Shortcut {
|
||||
super(config);
|
||||
|
||||
document.addEventListener(config.event, (ev: any) => {
|
||||
if (
|
||||
typeof config.context === "string" &&
|
||||
getApp().getCurrentContext() !== config.context
|
||||
) {
|
||||
if (typeof config.context === "string" && getApp().getCurrentContext() !== config.context) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -40,15 +33,9 @@ export class ShortcutKeyboard extends Shortcut {
|
||||
}
|
||||
|
||||
if (
|
||||
(typeof config.altKey !== "boolean" ||
|
||||
(typeof config.altKey === "boolean" &&
|
||||
ev.altKey === config.altKey)) &&
|
||||
(typeof config.ctrlKey !== "boolean" ||
|
||||
(typeof config.ctrlKey === "boolean" &&
|
||||
ev.ctrlKey === config.ctrlKey)) &&
|
||||
(typeof config.shiftKey !== "boolean" ||
|
||||
(typeof config.shiftKey === "boolean" &&
|
||||
ev.shiftKey === config.shiftKey))
|
||||
(typeof config.altKey !== "boolean" || (typeof config.altKey === "boolean" && ev.altKey === config.altKey)) &&
|
||||
(typeof config.ctrlKey !== "boolean" || (typeof config.ctrlKey === "boolean" && ev.ctrlKey === config.ctrlKey)) &&
|
||||
(typeof config.shiftKey !== "boolean" || (typeof config.shiftKey === "boolean" && ev.shiftKey === config.shiftKey))
|
||||
) {
|
||||
config.callback(ev);
|
||||
}
|
||||
|
||||
@@ -18,18 +18,14 @@ export class ShortcutManager {
|
||||
});
|
||||
|
||||
document.addEventListener("keyup", (ev: KeyboardEvent) => {
|
||||
this.#keysBeingHeld = this.#keysBeingHeld.filter(
|
||||
(held) => held !== ev.code
|
||||
);
|
||||
this.#keysBeingHeld = this.#keysBeingHeld.filter((held) => held !== ev.code);
|
||||
this.#keyUpCallbacks.forEach((callback) => callback(ev));
|
||||
});
|
||||
|
||||
this.addKeyboardShortcut("togglePause", {
|
||||
altKey: false,
|
||||
callback: () => {
|
||||
getApp()
|
||||
.getServerManager()
|
||||
.setPaused(!getApp().getServerManager().getPaused());
|
||||
getApp().getServerManager().setPaused(!getApp().getServerManager().getPaused());
|
||||
},
|
||||
code: "Space",
|
||||
context: DEFAULT_CONTEXT,
|
||||
@@ -45,12 +41,7 @@ export class ShortcutManager {
|
||||
.addKeyboardShortcut("toggleUnitLabels", {
|
||||
altKey: false,
|
||||
callback: () => {
|
||||
getApp()
|
||||
.getMap()
|
||||
.setOption(
|
||||
"showUnitLabels",
|
||||
!getApp().getMap().getOptions().showUnitLabels
|
||||
);
|
||||
getApp().getMap().setOption("showUnitLabels", !getApp().getMap().getOptions().showUnitLabels);
|
||||
},
|
||||
code: "KeyL",
|
||||
context: DEFAULT_CONTEXT,
|
||||
@@ -60,12 +51,7 @@ export class ShortcutManager {
|
||||
.addKeyboardShortcut("toggleAcquisitionRings", {
|
||||
altKey: false,
|
||||
callback: () => {
|
||||
getApp()
|
||||
.getMap()
|
||||
.setOption(
|
||||
"showUnitsAcquisitionRings",
|
||||
!getApp().getMap().getOptions().showUnitsAcquisitionRings
|
||||
);
|
||||
getApp().getMap().setOption("showUnitsAcquisitionRings", !getApp().getMap().getOptions().showUnitsAcquisitionRings);
|
||||
},
|
||||
code: "KeyE",
|
||||
context: DEFAULT_CONTEXT,
|
||||
@@ -75,12 +61,7 @@ export class ShortcutManager {
|
||||
.addKeyboardShortcut("toggleEngagementRings", {
|
||||
altKey: false,
|
||||
callback: () => {
|
||||
getApp()
|
||||
.getMap()
|
||||
.setOption(
|
||||
"showUnitsEngagementRings",
|
||||
!getApp().getMap().getOptions().showUnitsEngagementRings
|
||||
);
|
||||
getApp().getMap().setOption("showUnitsEngagementRings", !getApp().getMap().getOptions().showUnitsEngagementRings);
|
||||
},
|
||||
code: "KeyQ",
|
||||
context: DEFAULT_CONTEXT,
|
||||
@@ -90,12 +71,7 @@ export class ShortcutManager {
|
||||
.addKeyboardShortcut("toggleHideShortEngagementRings", {
|
||||
altKey: false,
|
||||
callback: () => {
|
||||
getApp()
|
||||
.getMap()
|
||||
.setOption(
|
||||
"hideUnitsShortRangeRings",
|
||||
!getApp().getMap().getOptions().hideUnitsShortRangeRings
|
||||
);
|
||||
getApp().getMap().setOption("hideUnitsShortRangeRings", !getApp().getMap().getOptions().hideUnitsShortRangeRings);
|
||||
},
|
||||
code: "KeyR",
|
||||
context: DEFAULT_CONTEXT,
|
||||
@@ -105,12 +81,7 @@ export class ShortcutManager {
|
||||
.addKeyboardShortcut("toggleDetectionLines", {
|
||||
altKey: false,
|
||||
callback: () => {
|
||||
getApp()
|
||||
.getMap()
|
||||
.setOption(
|
||||
"showUnitTargets",
|
||||
!getApp().getMap().getOptions().showUnitTargets
|
||||
);
|
||||
getApp().getMap().setOption("showUnitTargets", !getApp().getMap().getOptions().showUnitTargets);
|
||||
},
|
||||
code: "KeyF",
|
||||
context: DEFAULT_CONTEXT,
|
||||
@@ -120,12 +91,7 @@ export class ShortcutManager {
|
||||
.addKeyboardShortcut("toggleGroupMembers", {
|
||||
altKey: false,
|
||||
callback: () => {
|
||||
getApp()
|
||||
.getMap()
|
||||
.setOption(
|
||||
"hideGroupMembers",
|
||||
!getApp().getMap().getOptions().hideGroupMembers
|
||||
);
|
||||
getApp().getMap().setOption("hideGroupMembers", !getApp().getMap().getOptions().hideGroupMembers);
|
||||
},
|
||||
code: "KeyG",
|
||||
context: DEFAULT_CONTEXT,
|
||||
@@ -153,16 +119,7 @@ export class ShortcutManager {
|
||||
shiftKey: false,
|
||||
});
|
||||
|
||||
[
|
||||
"KeyW",
|
||||
"KeyA",
|
||||
"KeyS",
|
||||
"KeyD",
|
||||
"ArrowLeft",
|
||||
"ArrowRight",
|
||||
"ArrowUp",
|
||||
"ArrowDown",
|
||||
].forEach((code) => {
|
||||
["KeyW", "KeyA", "KeyS", "KeyD", "ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].forEach((code) => {
|
||||
this.addKeyboardShortcut(`pan${code}keydown`, {
|
||||
altKey: false,
|
||||
callback: (ev: KeyboardEvent) => {
|
||||
@@ -183,17 +140,7 @@ export class ShortcutManager {
|
||||
});
|
||||
});
|
||||
|
||||
const digits = [
|
||||
"Digit1",
|
||||
"Digit2",
|
||||
"Digit3",
|
||||
"Digit4",
|
||||
"Digit5",
|
||||
"Digit6",
|
||||
"Digit7",
|
||||
"Digit8",
|
||||
"Digit9",
|
||||
];
|
||||
const digits = ["Digit1", "Digit2", "Digit3", "Digit4", "Digit5", "Digit6", "Digit7", "Digit8", "Digit9"];
|
||||
|
||||
digits.forEach((code) => {
|
||||
this.addKeyboardShortcut(`hotgroup${code}`, {
|
||||
@@ -202,15 +149,18 @@ export class ShortcutManager {
|
||||
if (ev.ctrlKey && ev.shiftKey)
|
||||
getApp()
|
||||
.getUnitsManager()
|
||||
.selectUnitsByHotgroup(parseInt(ev.code.substring(5)), false); // "Select hotgroup X in addition to any units already selected"
|
||||
.selectUnitsByHotgroup(parseInt(ev.code.substring(5)), false);
|
||||
// "Select hotgroup X in addition to any units already selected"
|
||||
else if (ev.ctrlKey && !ev.shiftKey)
|
||||
getApp()
|
||||
.getUnitsManager()
|
||||
.setHotgroup(parseInt(ev.code.substring(5))); // "These selected units are hotgroup X (forget any previous membership)"
|
||||
.setHotgroup(parseInt(ev.code.substring(5)));
|
||||
// "These selected units are hotgroup X (forget any previous membership)"
|
||||
else if (!ev.ctrlKey && ev.shiftKey)
|
||||
getApp()
|
||||
.getUnitsManager()
|
||||
.addToHotgroup(parseInt(ev.code.substring(5))); // "Add (append) these units to hotgroup X (in addition to any existing members)"
|
||||
.addToHotgroup(parseInt(ev.code.substring(5)));
|
||||
// "Add (append) these units to hotgroup X (in addition to any existing members)"
|
||||
else
|
||||
getApp()
|
||||
.getUnitsManager()
|
||||
@@ -221,22 +171,14 @@ export class ShortcutManager {
|
||||
|
||||
// Stop hotgroup controls sending the browser to another tab
|
||||
document.addEventListener("keydown", (ev: KeyboardEvent) => {
|
||||
if (
|
||||
ev.code === code &&
|
||||
ev.ctrlKey === true &&
|
||||
ev.altKey === false &&
|
||||
ev.shiftKey === false
|
||||
) {
|
||||
if (ev.code === code && ev.ctrlKey === true && ev.altKey === false && ev.shiftKey === false) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
addKeyboardShortcut(
|
||||
name: string,
|
||||
shortcutKeyboardOptions: ShortcutKeyboardOptions
|
||||
) {
|
||||
addKeyboardShortcut(name: string, shortcutKeyboardOptions: ShortcutKeyboardOptions) {
|
||||
this.#items[name] = new ShortcutKeyboard(shortcutKeyboardOptions);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import { createContext } from "react";
|
||||
import {
|
||||
MAP_HIDDEN_TYPES_DEFAULTS,
|
||||
MAP_OPTIONS_DEFAULTS,
|
||||
} from "./constants/constants";
|
||||
import { MAP_HIDDEN_TYPES_DEFAULTS, MAP_OPTIONS_DEFAULTS } from "./constants/constants";
|
||||
|
||||
export const StateContext = createContext({
|
||||
mainMenuVisible: false,
|
||||
@@ -15,7 +12,7 @@ export const StateContext = createContext({
|
||||
mapOptions: MAP_OPTIONS_DEFAULTS,
|
||||
mapSources: [] as string[],
|
||||
activeMapSource: "",
|
||||
mapBoxSelection: false
|
||||
mapBoxSelection: false,
|
||||
});
|
||||
|
||||
export const StateProvider = StateContext.Provider;
|
||||
|
||||
@@ -2,31 +2,21 @@ import React, { useEffect, useRef, useState } from "react";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faArrowCircleDown } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
export function OlAccordion(props: {
|
||||
title: string;
|
||||
children?: JSX.Element | JSX.Element[];
|
||||
showArrows?: boolean;
|
||||
}) {
|
||||
var [open, setOpen] = useState(false);
|
||||
var [scrolledUp, setScrolledUp] = useState(true);
|
||||
var [scrolledDown, setScrolledDown] = useState(false);
|
||||
export function OlAccordion(props: { title: string; children?: JSX.Element | JSX.Element[]; showArrows?: boolean }) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [scrolledUp, setScrolledUp] = useState(true);
|
||||
const [scrolledDown, setScrolledDown] = useState(false);
|
||||
|
||||
var contentRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
contentRef.current &&
|
||||
(contentRef.current as HTMLElement).children[0]?.addEventListener(
|
||||
"scroll",
|
||||
(e: any) => {
|
||||
if (e.target.clientHeight < e.target.scrollHeight) {
|
||||
setScrolledDown(
|
||||
e.target.scrollTop ===
|
||||
e.target.scrollHeight - e.target.offsetHeight
|
||||
);
|
||||
setScrolledUp(e.target.scrollTop === 0);
|
||||
}
|
||||
(contentRef.current as HTMLElement).children[0]?.addEventListener("scroll", (e: any) => {
|
||||
if (e.target.clientHeight < e.target.scrollHeight) {
|
||||
setScrolledDown(e.target.scrollTop === e.target.scrollHeight - e.target.offsetHeight);
|
||||
setScrolledUp(e.target.scrollTop === 0);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
return (
|
||||
@@ -61,13 +51,7 @@ export function OlAccordion(props: {
|
||||
fill="none"
|
||||
viewBox="0 0 10 6"
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M9 5 5 1 1 5"
|
||||
/>
|
||||
<path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 5 5 1 1 5" />
|
||||
</svg>
|
||||
</button>
|
||||
</h3>
|
||||
|
||||
@@ -2,19 +2,11 @@ import { IconProp } from "@fortawesome/fontawesome-svg-core";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import React from "react";
|
||||
|
||||
export function OlButtonGroup(props: {
|
||||
children?: JSX.Element | JSX.Element[];
|
||||
}) {
|
||||
return (
|
||||
<div className="inline-flex rounded-md shadow-sm">{props.children}</div>
|
||||
);
|
||||
export function OlButtonGroup(props: { children?: JSX.Element | JSX.Element[] }) {
|
||||
return <div className="inline-flex rounded-md shadow-sm">{props.children}</div>;
|
||||
}
|
||||
|
||||
export function OlButtonGroupItem(props: {
|
||||
icon: IconProp;
|
||||
active: boolean;
|
||||
onClick: () => void;
|
||||
}) {
|
||||
export function OlButtonGroupItem(props: { icon: IconProp; active: boolean; onClick: () => void }) {
|
||||
return (
|
||||
<button
|
||||
onClick={props.onClick}
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
import React from "react";
|
||||
import {
|
||||
faSkull,
|
||||
faCamera,
|
||||
faFlag,
|
||||
faLink,
|
||||
faUnlink,
|
||||
faAngleDoubleRight,
|
||||
faExclamationCircle,
|
||||
faInfoCircle,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { faSkull, faCamera, faFlag, faLink, faUnlink, faAngleDoubleRight, faExclamationCircle, faInfoCircle } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
// Error message callout, only to be used for error messages
|
||||
@@ -21,12 +12,7 @@ export function ErrorCallout(props: { title?: string; description?: string }) {
|
||||
dark:bg-gray-800 dark:text-red-500
|
||||
`}
|
||||
>
|
||||
{props.title && (
|
||||
<FontAwesomeIcon
|
||||
className="mt-1"
|
||||
icon={faExclamationCircle}
|
||||
></FontAwesomeIcon>
|
||||
)}
|
||||
{props.title && <FontAwesomeIcon className="mt-1" icon={faExclamationCircle}></FontAwesomeIcon>}
|
||||
<div
|
||||
className={`
|
||||
flex flex-col content-center items-start gap-2 text-pretty font-bold
|
||||
@@ -55,9 +41,7 @@ export function InfoCallout(props: { title?: string; description?: string }) {
|
||||
dark:bg-gray-800 dark:text-blue-400
|
||||
`}
|
||||
>
|
||||
{props.title && (
|
||||
<FontAwesomeIcon className="mt-1" icon={faInfoCircle}></FontAwesomeIcon>
|
||||
)}
|
||||
{props.title && <FontAwesomeIcon className="mt-1" icon={faInfoCircle}></FontAwesomeIcon>}
|
||||
<div
|
||||
className={`
|
||||
flex flex-col content-center items-start gap-2 text-pretty font-medium
|
||||
@@ -88,10 +72,7 @@ export function CommandCallout(props: { coalition?: string }) {
|
||||
dark:bg-gray-800 dark:text-gray-400
|
||||
`}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
className="mt-1"
|
||||
icon={faAngleDoubleRight}
|
||||
></FontAwesomeIcon>
|
||||
<FontAwesomeIcon className="mt-1" icon={faAngleDoubleRight}></FontAwesomeIcon>
|
||||
<div
|
||||
className={`
|
||||
content-center items-start gap-2 whitespace-break-spaces text-pretty
|
||||
@@ -100,13 +81,9 @@ export function CommandCallout(props: { coalition?: string }) {
|
||||
>
|
||||
You are playing as
|
||||
{props.coalition == "blue" ? (
|
||||
<div className="inline-block font-bold text-blue-500">
|
||||
BLUE COMMANDER
|
||||
</div>
|
||||
<div className="inline-block font-bold text-blue-500">BLUE COMMANDER</div>
|
||||
) : (
|
||||
<div className="inline-block font-bold text-red-500">
|
||||
RED COMMANDER
|
||||
</div>
|
||||
<div className="inline-block font-bold text-red-500">RED COMMANDER</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import React, { ChangeEvent } from "react";
|
||||
|
||||
export function OlCheckbox(props: {
|
||||
checked: boolean;
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
|
||||
}) {
|
||||
export function OlCheckbox(props: { checked: boolean; className?: string; disabled?: boolean; onChange: (e: ChangeEvent<HTMLInputElement>) => void }) {
|
||||
return (
|
||||
<input
|
||||
onChange={props.onChange}
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
import React from "react";
|
||||
import { Coalition } from "../../types/types";
|
||||
|
||||
export function OlCoalitionToggle(props: {
|
||||
coalition: Coalition | undefined;
|
||||
onClick: () => void;
|
||||
}) {
|
||||
export function OlCoalitionToggle(props: { coalition: Coalition | undefined; onClick: () => void }) {
|
||||
return (
|
||||
<div
|
||||
className="inline-flex cursor-pointer items-center"
|
||||
onClick={props.onClick}
|
||||
>
|
||||
<div className="inline-flex cursor-pointer items-center" onClick={props.onClick}>
|
||||
<button className="peer sr-only" />
|
||||
<div
|
||||
data-flash={props.coalition === undefined}
|
||||
@@ -39,9 +33,7 @@ export function OlCoalitionToggle(props: {
|
||||
data-[flash='true']:after:animate-pulse
|
||||
`}
|
||||
>
|
||||
{props.coalition
|
||||
? `${props.coalition[0].toLocaleUpperCase() + props.coalition.substring(1)}`
|
||||
: "Diff. values"}
|
||||
{props.coalition ? `${props.coalition[0].toLocaleUpperCase() + props.coalition.substring(1)}` : "Diff. values"}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -11,11 +11,9 @@ export function OlDropdown(props: {
|
||||
buttonRef?: MutableRefObject<null> | null;
|
||||
open?: boolean;
|
||||
}) {
|
||||
var [open, setOpen] =
|
||||
props.open !== undefined ? [props.open, () => {}] : useState(false);
|
||||
const [open, setOpen] = props.open !== undefined ? [props.open, () => {}] : useState(false);
|
||||
var contentRef = useRef(null);
|
||||
var buttonRef =
|
||||
props.buttonRef !== undefined ? props.buttonRef : useRef(null);
|
||||
var buttonRef = props.buttonRef !== undefined ? props.buttonRef : useRef(null);
|
||||
|
||||
function setPosition(content: HTMLDivElement, button: HTMLButtonElement) {
|
||||
/* Reset the position of the content */
|
||||
@@ -24,7 +22,7 @@ export function OlDropdown(props: {
|
||||
content.style.height = "";
|
||||
|
||||
/* Get the position and size of the button and the content elements */
|
||||
var [cxl, cyt, cxr, cyb, cw, ch] = [
|
||||
let [cxl, cyt, cxr, cyb, cw, ch] = [
|
||||
content.getBoundingClientRect().x,
|
||||
content.getBoundingClientRect().y,
|
||||
content.getBoundingClientRect().x + content.clientWidth,
|
||||
@@ -32,7 +30,7 @@ export function OlDropdown(props: {
|
||||
content.clientWidth,
|
||||
content.clientHeight,
|
||||
];
|
||||
var [bxl, byt, bxr, byb, bbw, bh] = [
|
||||
let [bxl, byt, bxr, byb, bbw, bh] = [
|
||||
button.getBoundingClientRect().x,
|
||||
button.getBoundingClientRect().y,
|
||||
button.getBoundingClientRect().x + button.clientWidth,
|
||||
@@ -81,11 +79,7 @@ export function OlDropdown(props: {
|
||||
/* Register click events to automatically close the dropdown when clicked anywhere outside of it */
|
||||
document.addEventListener("click", function (event) {
|
||||
const target = event.target;
|
||||
if (
|
||||
target &&
|
||||
!content.contains(target as HTMLElement) &&
|
||||
!button.contains(target as HTMLElement)
|
||||
) {
|
||||
if (target && !content.contains(target as HTMLElement) && !button.contains(target as HTMLElement)) {
|
||||
setOpen(false);
|
||||
}
|
||||
});
|
||||
@@ -93,9 +87,7 @@ export function OlDropdown(props: {
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
className={props.className ?? ""}
|
||||
>
|
||||
<div className={props.className ?? ""}>
|
||||
{props.buttonRef === undefined && (
|
||||
<button
|
||||
ref={buttonRef}
|
||||
@@ -111,12 +103,8 @@ export function OlDropdown(props: {
|
||||
`}
|
||||
type="button"
|
||||
>
|
||||
{props.leftIcon && (
|
||||
<FontAwesomeIcon icon={props.leftIcon} className={`mr-3`} />
|
||||
)}
|
||||
<span className="overflow-hidden text-ellipsis text-nowrap">
|
||||
{props.label ?? ""}
|
||||
</span>
|
||||
{props.leftIcon && <FontAwesomeIcon icon={props.leftIcon} className={`mr-3`} />}
|
||||
<span className="overflow-hidden text-ellipsis text-nowrap">{props.label ?? ""}</span>
|
||||
<svg
|
||||
className={`
|
||||
ml-auto ms-3 h-2.5 w-2.5 flex-none transition-transform
|
||||
@@ -127,13 +115,7 @@ export function OlDropdown(props: {
|
||||
fill="none"
|
||||
viewBox="0 0 10 6"
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="m1 1 4 4 4-4"
|
||||
/>
|
||||
<path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="m1 1 4 4 4-4" />
|
||||
</svg>
|
||||
</button>
|
||||
)}
|
||||
@@ -142,7 +124,7 @@ export function OlDropdown(props: {
|
||||
ref={contentRef}
|
||||
data-open={open}
|
||||
className={`
|
||||
absolute divide-y divide-gray-100 overflow-y-scroll no-scrollbar
|
||||
absolute z-40 divide-y divide-gray-100 overflow-y-scroll no-scrollbar
|
||||
rounded-lg bg-white p-2 shadow
|
||||
dark:bg-gray-700
|
||||
data-[open='false']:hidden
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,18 +1,13 @@
|
||||
import React from "react";
|
||||
|
||||
export function OlLabelToggle(props: {
|
||||
toggled: boolean | undefined;
|
||||
leftLabel: string;
|
||||
rightLabel: string;
|
||||
onClick: () => void;
|
||||
}) {
|
||||
export function OlLabelToggle(props: { toggled: boolean | undefined; leftLabel: string; rightLabel: string; onClick: () => void }) {
|
||||
return (
|
||||
<button
|
||||
onClick={props.onClick}
|
||||
className={`
|
||||
relative flex h-10 w-[120px] flex-none cursor-pointer select-none
|
||||
flex-row justify-between rounded-md border px-1 py-[5px] text-sm
|
||||
contents-center
|
||||
flex-row content-center justify-between rounded-md border px-1 py-[5px]
|
||||
text-sm
|
||||
dark:border-gray-600 dark:border-transparent dark:bg-gray-700
|
||||
dark:hover:bg-gray-600 dark:focus:ring-blue-800
|
||||
focus:outline-none focus:ring-2 focus:ring-blue-300
|
||||
@@ -31,7 +26,7 @@ export function OlLabelToggle(props: {
|
||||
<span
|
||||
data-active={!(props.toggled ?? false)}
|
||||
className={`
|
||||
my-auto pl-3 font-normal transition-colors z-ui-1
|
||||
absolute left-[17px] top-[8px] font-normal transition-colors
|
||||
dark:data-[active='false']:text-gray-400
|
||||
dark:data-[active='true']:text-white
|
||||
`}
|
||||
@@ -41,7 +36,7 @@ export function OlLabelToggle(props: {
|
||||
<span
|
||||
data-active={props.toggled ?? false}
|
||||
className={`
|
||||
my-auto pr-3.5 font-normal transition-colors z-ui-1
|
||||
absolute right-[17px] top-[8px] font-normal transition-colors
|
||||
dark:data-[active='false']:text-gray-400
|
||||
dark:data-[active='true']:text-white
|
||||
`}
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
import React, { ChangeEvent, useEffect, useId } from "react";
|
||||
import React, { ChangeEvent } from "react";
|
||||
import { zeroAppend } from "../../other/utils";
|
||||
|
||||
export function OlNumberInput(props: {
|
||||
value: number;
|
||||
min: number;
|
||||
max: number;
|
||||
minLength?: number;
|
||||
className?: string;
|
||||
onDecrease: () => void;
|
||||
onIncrease: () => void;
|
||||
onChange: (e: ChangeEvent<HTMLInputElement>) => void;
|
||||
}) {
|
||||
return (
|
||||
<div className="min-w-32">
|
||||
<div
|
||||
className={`
|
||||
${props.className ?? ""}
|
||||
min-w-32
|
||||
`}
|
||||
>
|
||||
<div className="relative flex max-w-[8rem] items-center">
|
||||
<button
|
||||
type="button"
|
||||
@@ -31,13 +39,7 @@ export function OlNumberInput(props: {
|
||||
fill="none"
|
||||
viewBox="0 0 18 2"
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M1 1h16"
|
||||
/>
|
||||
<path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M1 1h16" />
|
||||
</svg>
|
||||
</button>
|
||||
<input
|
||||
@@ -53,7 +55,7 @@ export function OlNumberInput(props: {
|
||||
dark:focus:ring-blue-700
|
||||
focus:border-blue-700 focus:ring-blue-500
|
||||
`}
|
||||
value={props.value}
|
||||
value={zeroAppend(props.value, props.minLength ?? 0)}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
@@ -75,13 +77,7 @@ export function OlNumberInput(props: {
|
||||
fill="none"
|
||||
viewBox="0 0 18 18"
|
||||
>
|
||||
<path
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M9 1v16M1 9h16"
|
||||
/>
|
||||
<path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 1v16M1 9h16" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -2,10 +2,7 @@ import { faMultiply, faSearch } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import React, { useId, useRef } from "react";
|
||||
|
||||
export function OlSearchBar(props: {
|
||||
onChange: (e: string) => void;
|
||||
text: string;
|
||||
}) {
|
||||
export function OlSearchBar(props: { onChange: (e: string) => void; text: string }) {
|
||||
const searchId = useId();
|
||||
const inputRef = useRef(null);
|
||||
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
import { IconProp } from "@fortawesome/fontawesome-svg-core";
|
||||
import {
|
||||
faExternalLink,
|
||||
faLock,
|
||||
faLockOpen,
|
||||
faUnlock,
|
||||
faUnlockAlt,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { faExternalLink, faLock, faLockOpen, faUnlock, faUnlockAlt } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import React, { useRef, useState } from "react";
|
||||
import { OlTooltip } from "./oltooltip";
|
||||
@@ -18,7 +12,7 @@ export function OlStateButton(props: {
|
||||
onClick: () => void;
|
||||
children?: JSX.Element | JSX.Element[];
|
||||
}) {
|
||||
var [hover, setHover] = useState(false);
|
||||
const [hover, setHover] = useState(false);
|
||||
var buttonRef = useRef(null);
|
||||
|
||||
const className =
|
||||
@@ -49,8 +43,8 @@ export function OlStateButton(props: {
|
||||
}}
|
||||
>
|
||||
<div className="m-auto flex w-fit content-center justify-center gap-2">
|
||||
<FontAwesomeIcon icon={props.icon} className="m-auto"/>
|
||||
{props.children}
|
||||
<FontAwesomeIcon icon={props.icon} className="m-auto" />
|
||||
{props.children}
|
||||
</div>
|
||||
</button>
|
||||
{hover && <OlTooltip buttonRef={buttonRef} content={props.tooltip} />}
|
||||
@@ -58,14 +52,8 @@ export function OlStateButton(props: {
|
||||
);
|
||||
}
|
||||
|
||||
export function OlRoundStateButton(props: {
|
||||
className?: string;
|
||||
checked: boolean;
|
||||
icon: IconProp;
|
||||
tooltip: string;
|
||||
onClick: () => void;
|
||||
}) {
|
||||
var [hover, setHover] = useState(false);
|
||||
export function OlRoundStateButton(props: { className?: string; checked: boolean; icon: IconProp; tooltip: string; onClick: () => void }) {
|
||||
const [hover, setHover] = useState(false);
|
||||
var buttonRef = useRef(null);
|
||||
|
||||
const className =
|
||||
@@ -106,13 +94,8 @@ export function OlRoundStateButton(props: {
|
||||
);
|
||||
}
|
||||
|
||||
export function OlLockStateButton(props: {
|
||||
className?: string;
|
||||
checked: boolean;
|
||||
tooltip: string;
|
||||
onClick: () => void;
|
||||
}) {
|
||||
var [hover, setHover] = useState(false);
|
||||
export function OlLockStateButton(props: { className?: string; checked: boolean; tooltip: string; onClick: () => void }) {
|
||||
const [hover, setHover] = useState(false);
|
||||
var buttonRef = useRef(null);
|
||||
|
||||
const className =
|
||||
@@ -143,10 +126,7 @@ export function OlLockStateButton(props: {
|
||||
setHover(false);
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
className="pt-[3px]"
|
||||
icon={props.checked == true ? faUnlockAlt : faLock}
|
||||
/>
|
||||
<FontAwesomeIcon className="pt-[3px]" icon={props.checked == true ? faUnlockAlt : faLock} />
|
||||
</button>
|
||||
{hover && <OlTooltip buttonRef={buttonRef} content={props.tooltip} />}
|
||||
</>
|
||||
|
||||
28
frontend/react/src/ui/components/olstringinput.tsx
Normal file
28
frontend/react/src/ui/components/olstringinput.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import React, { ChangeEvent } from "react";
|
||||
|
||||
export function OlStringInput(props: { value: string; className?: string; onChange: (e: ChangeEvent<HTMLInputElement>) => void }) {
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
${props.className ?? ""}
|
||||
min-w-32
|
||||
`}
|
||||
>
|
||||
<div className="relative flex max-w-[8rem] items-center">
|
||||
<input
|
||||
type="text"
|
||||
onChange={props.onChange}
|
||||
className={`
|
||||
block h-10 w-full rounded-md border-[2px] bg-gray-50 py-2.5
|
||||
text-center text-sm text-gray-900
|
||||
dark:border-gray-700 dark:bg-olympus-600 dark:text-white
|
||||
dark:placeholder-gray-400 dark:focus:border-blue-700
|
||||
dark:focus:ring-blue-700
|
||||
focus:border-blue-700 focus:ring-blue-500
|
||||
`}
|
||||
value={props.value}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,14 +1,8 @@
|
||||
import React from "react";
|
||||
|
||||
export function OlToggle(props: {
|
||||
toggled: boolean | undefined;
|
||||
onClick: () => void;
|
||||
}) {
|
||||
export function OlToggle(props: { toggled: boolean | undefined; onClick: () => void }) {
|
||||
return (
|
||||
<div
|
||||
className="inline-flex cursor-pointer items-center"
|
||||
onClick={props.onClick}
|
||||
>
|
||||
<div className="inline-flex cursor-pointer items-center" onClick={props.onClick}>
|
||||
<button className="peer sr-only" />
|
||||
<div
|
||||
data-flash={props.toggled === undefined}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
|
||||
export function OlTooltip(props: {
|
||||
content: string;
|
||||
buttonRef: React.MutableRefObject<null>;
|
||||
}) {
|
||||
export function OlTooltip(props: { content: string; buttonRef: React.MutableRefObject<null> }) {
|
||||
var contentRef = useRef(null);
|
||||
|
||||
function setPosition(content: HTMLDivElement, button: HTMLButtonElement) {
|
||||
@@ -13,7 +10,7 @@ export function OlTooltip(props: {
|
||||
content.style.height = "";
|
||||
|
||||
/* Get the position and size of the button and the content elements */
|
||||
var [cxl, cyt, cxr, cyb, cw, ch] = [
|
||||
let [cxl, cyt, cxr, cyb, cw, ch] = [
|
||||
content.getBoundingClientRect().x,
|
||||
content.getBoundingClientRect().y,
|
||||
content.getBoundingClientRect().x + content.clientWidth,
|
||||
@@ -21,7 +18,7 @@ export function OlTooltip(props: {
|
||||
content.clientWidth,
|
||||
content.clientHeight,
|
||||
];
|
||||
var [bxl, byt, bxr, byb, bbw, bh] = [
|
||||
let [bxl, byt, bxr, byb, bbw, bh] = [
|
||||
button.getBoundingClientRect().x,
|
||||
button.getBoundingClientRect().y,
|
||||
button.getBoundingClientRect().x + button.clientWidth,
|
||||
@@ -73,8 +70,8 @@ export function OlTooltip(props: {
|
||||
<div
|
||||
ref={contentRef}
|
||||
className={`
|
||||
absolute whitespace-nowrap z-ui-4 rounded-lg bg-gray-900 px-3 py-2
|
||||
text-sm font-medium text-white shadow-sm
|
||||
absolute whitespace-nowrap rounded-lg bg-gray-900 px-3 py-2 text-sm
|
||||
font-medium text-white shadow-sm
|
||||
dark:bg-gray-700
|
||||
`}
|
||||
>
|
||||
|
||||
@@ -2,19 +2,10 @@ import React from "react";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { IconProp } from "@fortawesome/fontawesome-svg-core";
|
||||
import { UnitBlueprint } from "../../interfaces";
|
||||
import {
|
||||
faArrowRightLong,
|
||||
faCaretRight,
|
||||
faCircleArrowRight,
|
||||
faLongArrowAltRight,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { faArrowRightLong, faCaretRight, faCircleArrowRight, faLongArrowAltRight } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faArrowRight } from "@fortawesome/free-solid-svg-icons/faArrowRight";
|
||||
|
||||
export function OlUnitEntryList(props: {
|
||||
icon: IconProp;
|
||||
blueprint: UnitBlueprint;
|
||||
onClick: () => void;
|
||||
}) {
|
||||
export function OlUnitEntryList(props: { icon: IconProp; blueprint: UnitBlueprint; onClick: () => void }) {
|
||||
return (
|
||||
<div
|
||||
onClick={props.onClick}
|
||||
@@ -25,9 +16,7 @@ export function OlUnitEntryList(props: {
|
||||
`}
|
||||
>
|
||||
<FontAwesomeIcon icon={props.icon} className="text-sm"></FontAwesomeIcon>
|
||||
<div className="flex-1 px-2 text-left font-normal">
|
||||
{props.blueprint.label}
|
||||
</div>
|
||||
<div className="flex-1 px-2 text-left font-normal">{props.blueprint.label}</div>
|
||||
<div
|
||||
className={`
|
||||
rounded-full bg-olympus-800 px-2 py-0.5 text-xs font-bold
|
||||
|
||||
@@ -2,10 +2,7 @@ import React from "react";
|
||||
import { UnitBlueprint } from "../../interfaces";
|
||||
import { Coalition } from "../../types/types";
|
||||
|
||||
export function OlUnitSummary(props: {
|
||||
blueprint: UnitBlueprint;
|
||||
coalition: Coalition;
|
||||
}) {
|
||||
export function OlUnitSummary(props: { blueprint: UnitBlueprint; coalition: Coalition }) {
|
||||
return (
|
||||
<div
|
||||
data-coalition={props.coalition}
|
||||
|
||||
@@ -1,17 +1,8 @@
|
||||
import React from "react";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faArrowRight,
|
||||
faCheckCircle,
|
||||
faExternalLink,
|
||||
faLink,
|
||||
faUnlink,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { faArrowRight, faCheckCircle, faExternalLink, faLink, faUnlink } from "@fortawesome/free-solid-svg-icons";
|
||||
|
||||
export function Card(props: {
|
||||
children?: JSX.Element | JSX.Element[];
|
||||
className?: string;
|
||||
}) {
|
||||
export function Card(props: { children?: JSX.Element | JSX.Element[]; className?: string }) {
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import React from "react";
|
||||
|
||||
export function Modal(props: {
|
||||
grayout?: boolean;
|
||||
children?: JSX.Element | JSX.Element[];
|
||||
className?: string;
|
||||
}) {
|
||||
export function Modal(props: { grayout?: boolean; children?: JSX.Element | JSX.Element[]; className?: string }) {
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
${props.className}
|
||||
fixed left-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%] z-ui-4
|
||||
fixed left-[50%] top-[50%] z-40 translate-x-[-50%] translate-y-[-50%]
|
||||
rounded-xl border-[1px] border-solid border-gray-700 drop-shadow-md
|
||||
`}
|
||||
>
|
||||
|
||||
@@ -1,27 +1,10 @@
|
||||
import React, { useState, version } from "react";
|
||||
import React, { useState } from "react";
|
||||
import { Modal } from "./components/modal";
|
||||
import { Card } from "./components/card";
|
||||
import {
|
||||
ErrorCallout,
|
||||
InfoCallout,
|
||||
CommandCallout,
|
||||
} from "../../ui/components/olcallout";
|
||||
import { ErrorCallout } from "../../ui/components/olcallout";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import {
|
||||
faArrowRight,
|
||||
faCheckCircle,
|
||||
faDatabase,
|
||||
faExclamation,
|
||||
faExclamationCircle,
|
||||
faExternalLink,
|
||||
faLink,
|
||||
faServer,
|
||||
faSitemap,
|
||||
faUnlink,
|
||||
faWindowMaximize,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { VERSION, connectedToServer } from "../../olympusapp";
|
||||
import { faFirefoxBrowser } from "@fortawesome/free-brands-svg-icons";
|
||||
import { faArrowRight, faCheckCircle, faExternalLink } from "@fortawesome/free-solid-svg-icons";
|
||||
import { VERSION } from "../../olympusapp";
|
||||
|
||||
export function LoginModal(props: {
|
||||
checkingPassword: boolean;
|
||||
@@ -38,7 +21,7 @@ export function LoginModal(props: {
|
||||
<Modal
|
||||
className={`
|
||||
inline-flex h-[75%] max-h-[530px] w-[80%] max-w-[1100px] overflow-y-auto
|
||||
scroll-smooth bg-white z-ui-5
|
||||
scroll-smooth bg-white
|
||||
dark:bg-olympus-800
|
||||
max-md:h-full max-md:max-h-full max-md:w-full max-md:rounded-none
|
||||
max-md:border-none
|
||||
@@ -46,7 +29,9 @@ export function LoginModal(props: {
|
||||
>
|
||||
<img
|
||||
src="/vite/images/splash/1.jpg"
|
||||
className={`contents-center w-full object-cover opacity-[7%]`}
|
||||
className={`
|
||||
contents-center w-full object-cover opacity-[7%]
|
||||
`}
|
||||
></img>
|
||||
<div
|
||||
className={`
|
||||
@@ -107,7 +92,9 @@ export function LoginModal(props: {
|
||||
<span className="size-[80px] min-w-14">
|
||||
<img
|
||||
src="..\vite\images\olympus-500x500.png"
|
||||
className={`flex w-full`}
|
||||
className={`
|
||||
flex w-full
|
||||
`}
|
||||
></img>
|
||||
</span>
|
||||
<div className={`flex flex-col items-start gap-1`}>
|
||||
@@ -126,10 +113,7 @@ export function LoginModal(props: {
|
||||
dark:text-green-400
|
||||
`}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={faCheckCircle}
|
||||
className={`my-auto`}
|
||||
/>
|
||||
<FontAwesomeIcon icon={faCheckCircle} className={`my-auto`} />
|
||||
Version {VERSION}
|
||||
</div>
|
||||
</div>
|
||||
@@ -149,9 +133,7 @@ export function LoginModal(props: {
|
||||
</label>
|
||||
<input
|
||||
type="password"
|
||||
onChange={(ev) =>
|
||||
setPassword(ev.currentTarget.value)
|
||||
}
|
||||
onChange={(ev) => setPassword(ev.currentTarget.value)}
|
||||
className={`
|
||||
block w-full max-w-80 rounded-lg border
|
||||
border-gray-300 bg-gray-50 p-2.5 text-sm
|
||||
@@ -182,10 +164,7 @@ export function LoginModal(props: {
|
||||
`}
|
||||
>
|
||||
Login
|
||||
<FontAwesomeIcon
|
||||
className={`my-auto`}
|
||||
icon={faArrowRight}
|
||||
/>
|
||||
<FontAwesomeIcon className={`my-auto`} icon={faArrowRight} />
|
||||
</button>
|
||||
{/*
|
||||
<button type="button" className="flex content-center items-center gap-2 text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium text-sm px-5 py-2.5 me-2 mb-2 dark:bg-gray-800 dark:hover:bg-gray-700 focus:outline-none dark:focus:ring-blue-800 rounded-sm dark:border-gray-600 border-[1px] dark:text-gray-400">
|
||||
@@ -213,9 +192,7 @@ export function LoginModal(props: {
|
||||
<input
|
||||
type="text"
|
||||
autoComplete="username"
|
||||
onChange={(ev) =>
|
||||
setDisplayName(ev.currentTarget.value)
|
||||
}
|
||||
onChange={(ev) => setDisplayName(ev.currentTarget.value)}
|
||||
className={`
|
||||
block w-full max-w-80 rounded-lg border
|
||||
border-gray-300 bg-gray-50 p-2.5 text-sm
|
||||
@@ -246,10 +223,7 @@ export function LoginModal(props: {
|
||||
`}
|
||||
>
|
||||
Continue
|
||||
<FontAwesomeIcon
|
||||
className={`my-auto`}
|
||||
icon={faArrowRight}
|
||||
/>
|
||||
<FontAwesomeIcon className={`my-auto`} icon={faArrowRight} />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@@ -344,10 +318,7 @@ export function LoginModal(props: {
|
||||
`}
|
||||
>
|
||||
YouTube Video Guide
|
||||
<FontAwesomeIcon
|
||||
className={`my-auto text-xs text-gray-400`}
|
||||
icon={faExternalLink}
|
||||
/>
|
||||
<FontAwesomeIcon className={`my-auto text-xs text-gray-400`} icon={faExternalLink} />
|
||||
</div>
|
||||
<div
|
||||
className={`
|
||||
@@ -355,9 +326,7 @@ export function LoginModal(props: {
|
||||
dark:text-gray-400
|
||||
`}
|
||||
>
|
||||
Check out our official video tutorial on how to get started with
|
||||
Olympus - so you can immediately start controlling the
|
||||
battlefield.
|
||||
Check out our official video tutorial on how to get started with Olympus - so you can immediately start controlling the battlefield.
|
||||
</div>
|
||||
</Card>
|
||||
<Card className="flex">
|
||||
@@ -374,10 +343,7 @@ export function LoginModal(props: {
|
||||
`}
|
||||
>
|
||||
Wiki Guide
|
||||
<FontAwesomeIcon
|
||||
className={`my-auto text-xs text-gray-400`}
|
||||
icon={faExternalLink}
|
||||
/>
|
||||
<FontAwesomeIcon className={`my-auto text-xs text-gray-400`} icon={faExternalLink} />
|
||||
</div>
|
||||
<div
|
||||
className={`
|
||||
@@ -396,13 +362,9 @@ export function LoginModal(props: {
|
||||
max-lg:flex-col
|
||||
`}
|
||||
>
|
||||
DCS Olympus (the "MATERIAL" or "Software") is provided completely free
|
||||
to users subject to the terms of the CC BY-NC-SA 4.0 Licence except
|
||||
where such terms conflict with this disclaimer, in which case, the
|
||||
terms of this disclaimer shall prevail. Any party making use of the
|
||||
Software in any manner agrees to be bound by the terms set out in the
|
||||
disclaimer. THIS MATERIAL IS NOT MADE OR SUPPORTED BY EAGLE DYNAMICS
|
||||
SA.
|
||||
DCS Olympus (the "MATERIAL" or "Software") is provided completely free to users subject to the terms of the CC BY-NC-SA 4.0 Licence except where such
|
||||
terms conflict with this disclaimer, in which case, the terms of this disclaimer shall prevail. Any party making use of the Software in any manner
|
||||
agrees to be bound by the terms set out in the disclaimer. THIS MATERIAL IS NOT MADE OR SUPPORTED BY EAGLE DYNAMICS SA.
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
@@ -20,8 +20,8 @@ export function Menu(props: {
|
||||
<div
|
||||
data-open={props.open}
|
||||
className={`
|
||||
absolute left-16 right-0 top-[58px] bg-transparent z-ui-3
|
||||
pointer-events-none h-[calc(100vh-58px)] transition-transform
|
||||
pointer-events-none absolute left-16 right-0 top-[58px] z-10
|
||||
h-[calc(100vh-58px)] bg-transparent transition-transform
|
||||
data-[open='false']:-translate-x-full
|
||||
sm:w-[400px]
|
||||
`}
|
||||
@@ -71,7 +71,7 @@ export function Menu(props: {
|
||||
{props.canBeHidden == true && (
|
||||
<div
|
||||
className={`
|
||||
flex h-8 justify-center z-ui-4 pointer-events-auto backdrop-blur-lg
|
||||
pointer-events-auto flex h-8 justify-center backdrop-blur-lg
|
||||
backdrop-grayscale
|
||||
dark:bg-olympus-800/90
|
||||
`}
|
||||
@@ -80,7 +80,11 @@ export function Menu(props: {
|
||||
{hide ? (
|
||||
<FaChevronUp className="mx-auto my-auto text-gray-400" />
|
||||
) : (
|
||||
<FaChevronDown className="mx-auto my-auto text-gray-400" />
|
||||
<FaChevronDown
|
||||
className={`
|
||||
mx-auto my-auto text-gray-400
|
||||
`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -24,8 +24,8 @@ export function ControlsPanel(props: {}) {
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
absolute bottom-[20px] right-[10px] w-80 z-ui-0 flex flex-col
|
||||
items-center justify-between gap-1 p-3 text-sm
|
||||
absolute bottom-[20px] right-[10px] flex w-80 flex-col items-center
|
||||
justify-between gap-1 p-3 text-sm
|
||||
`}
|
||||
>
|
||||
{controls.map((control) => {
|
||||
@@ -37,9 +37,7 @@ export function ControlsPanel(props: {}) {
|
||||
dark:bg-olympus-800/90 dark:text-gray-200
|
||||
`}
|
||||
>
|
||||
<div className="my-auto overflow-hidden text-nowrap">
|
||||
{control.text}
|
||||
</div>
|
||||
<div className="my-auto overflow-hidden text-nowrap">{control.text}</div>
|
||||
<div
|
||||
className={`
|
||||
ml-auto flex gap-1 rounded-full bg-olympus-500 px-2 py-0.5
|
||||
@@ -55,7 +53,9 @@ export function ControlsPanel(props: {}) {
|
||||
) : (
|
||||
<FontAwesomeIcon
|
||||
icon={action}
|
||||
className={`my-auto ml-auto`}
|
||||
className={`
|
||||
my-auto ml-auto
|
||||
`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -2,12 +2,7 @@ import React, { useEffect, useState } from "react";
|
||||
import { Menu } from "./components/menu";
|
||||
import { FaQuestionCircle, FaRegCircle, FaTrash } from "react-icons/fa";
|
||||
import { getApp } from "../../olympusapp";
|
||||
import {
|
||||
COALITIONAREA_DRAW_CIRCLE,
|
||||
COALITIONAREA_DRAW_POLYGON,
|
||||
COALITIONAREA_EDIT,
|
||||
IDLE,
|
||||
} from "../../constants/constants";
|
||||
import { COALITIONAREA_DRAW_CIRCLE, COALITIONAREA_DRAW_POLYGON, COALITIONAREA_EDIT, IDLE } from "../../constants/constants";
|
||||
import { OlStateButton } from "../components/olstatebutton";
|
||||
import { faDrawPolygon } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faCircle } from "@fortawesome/free-regular-svg-icons";
|
||||
@@ -22,14 +17,11 @@ import { CoalitionCircle } from "../../map/coalitionarea/coalitioncircle";
|
||||
export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
const [drawingPolygon, setDrawingPolygon] = useState(false);
|
||||
const [drawingCircle, setDrawingCircle] = useState(false);
|
||||
const [activeCoalitionArea, setActiveCoalitionArea] = useState(
|
||||
null as null | CoalitionPolygon | CoalitionCircle
|
||||
);
|
||||
const [activeCoalitionArea, setActiveCoalitionArea] = useState(null as null | CoalitionPolygon | CoalitionCircle);
|
||||
const [areaCoalition, setAreaCoalition] = useState("blue" as Coalition);
|
||||
const [IADSDensity, setIADSDensity] = useState(50);
|
||||
const [IADSDistribution, setIADSDistribution] = useState(50);
|
||||
const [forceCoalitionAppropriateUnits, setForceCoalitionApproriateUnits] =
|
||||
useState(false);
|
||||
const [forceCoalitionAppropriateUnits, setForceCoalitionApproriateUnits] = useState(false);
|
||||
|
||||
const [typesSelection, setTypesSelection] = useState({});
|
||||
const [erasSelection, setErasSelection] = useState({});
|
||||
@@ -37,55 +29,30 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
|
||||
useEffect(() => {
|
||||
/* If we are not in polygon drawing mode, force the draw polygon button off */
|
||||
if (
|
||||
drawingPolygon &&
|
||||
getApp().getMap().getState() !== COALITIONAREA_DRAW_POLYGON
|
||||
)
|
||||
setDrawingPolygon(false);
|
||||
if (drawingPolygon && getApp().getMap().getState() !== COALITIONAREA_DRAW_POLYGON) setDrawingPolygon(false);
|
||||
|
||||
/* If we are not in circle drawing mode, force the draw circle button off */
|
||||
if (
|
||||
drawingCircle &&
|
||||
getApp().getMap().getState() !== COALITIONAREA_DRAW_CIRCLE
|
||||
)
|
||||
setDrawingCircle(false);
|
||||
if (drawingCircle && getApp().getMap().getState() !== COALITIONAREA_DRAW_CIRCLE) setDrawingCircle(false);
|
||||
|
||||
/* If we are not in any drawing mode, force the map in edit mode */
|
||||
if (props.open && !drawingPolygon && !drawingCircle)
|
||||
getApp().getMap().setState(COALITIONAREA_EDIT);
|
||||
if (props.open && !drawingPolygon && !drawingCircle) getApp().getMap().setState(COALITIONAREA_EDIT);
|
||||
|
||||
/* Align the state of the coalition toggle to the coalition of the area */
|
||||
if (
|
||||
activeCoalitionArea &&
|
||||
activeCoalitionArea?.getCoalition() !== areaCoalition
|
||||
)
|
||||
setAreaCoalition(activeCoalitionArea?.getCoalition());
|
||||
if (activeCoalitionArea && activeCoalitionArea?.getCoalition() !== areaCoalition) setAreaCoalition(activeCoalitionArea?.getCoalition());
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!props.open) {
|
||||
if (
|
||||
[
|
||||
COALITIONAREA_EDIT,
|
||||
COALITIONAREA_DRAW_CIRCLE,
|
||||
COALITIONAREA_DRAW_POLYGON,
|
||||
].includes(getApp()?.getMap()?.getState())
|
||||
)
|
||||
if ([COALITIONAREA_EDIT, COALITIONAREA_DRAW_CIRCLE, COALITIONAREA_DRAW_POLYGON].includes(getApp()?.getMap()?.getState()))
|
||||
getApp().getMap().setState(IDLE);
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("mapStateChanged", (event: any) => {
|
||||
if (
|
||||
drawingPolygon &&
|
||||
getApp().getMap().getState() !== COALITIONAREA_DRAW_POLYGON
|
||||
)
|
||||
setDrawingPolygon(false);
|
||||
if (drawingPolygon && getApp().getMap().getState() !== COALITIONAREA_DRAW_POLYGON) setDrawingPolygon(false);
|
||||
|
||||
if (getApp().getMap().getState() == COALITIONAREA_EDIT) {
|
||||
setActiveCoalitionArea(
|
||||
getApp().getMap().getSelectedCoalitionArea() ?? null
|
||||
);
|
||||
setActiveCoalitionArea(getApp().getMap().getSelectedCoalitionArea() ?? null);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -109,21 +76,15 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
{activeCoalitionArea === null && !drawingPolygon && !drawingCircle && (
|
||||
<>
|
||||
<div className="p-4 text-sm text-gray-400">
|
||||
The draw tool allows you to quickly draw areas on the map and use
|
||||
these areas to spawn units and activate triggers.
|
||||
The draw tool allows you to quickly draw areas on the map and use these areas to spawn units and activate triggers.
|
||||
</div>
|
||||
<div className="mx-6 flex rounded-lg bg-olympus-400 p-4 text-sm">
|
||||
<div>
|
||||
<FaQuestionCircle className="my-4 ml-2 mr-6 text-gray-400" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="text-gray-100">
|
||||
Use the polygon or circle tool to draw areas on the map.
|
||||
</div>
|
||||
<div className="text-gray-400">
|
||||
After drawing a shape, select it to see the options for
|
||||
spawning units. Click on a shape to select it.
|
||||
</div>
|
||||
<div className="text-gray-100">Use the polygon or circle tool to draw areas on the map.</div>
|
||||
<div className="text-gray-400">After drawing a shape, select it to see the options for spawning units. Click on a shape to select it.</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
@@ -137,12 +98,9 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
<FaQuestionCircle className="my-4 ml-2 mr-6 text-gray-400" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="text-gray-100">
|
||||
Click on the map to add vertices to the polygon.
|
||||
</div>
|
||||
<div className="text-gray-100">Click on the map to add vertices to the polygon.</div>
|
||||
<div className="text-gray-400">
|
||||
When you are done, double click on the map to finalize the
|
||||
polygon. Vertices can be dragged or added to adjust the shape.
|
||||
When you are done, double click on the map to finalize the polygon. Vertices can be dragged or added to adjust the shape.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -156,13 +114,8 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
<FaQuestionCircle className="my-4 ml-2 mr-6 text-gray-400" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="text-gray-100">
|
||||
Click on the map to add a new circle.
|
||||
</div>
|
||||
<div className="text-gray-400">
|
||||
You can drag the circle to move it and you can use the handle to
|
||||
set the radius.
|
||||
</div>
|
||||
<div className="text-gray-100">Click on the map to add a new circle.</div>
|
||||
<div className="text-gray-400">You can drag the circle to move it and you can use the handle to set the radius.</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -177,8 +130,7 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
tooltip={"Add a new polygon"}
|
||||
checked={drawingPolygon}
|
||||
onClick={() => {
|
||||
if (drawingPolygon)
|
||||
getApp().getMap().setState(COALITIONAREA_EDIT);
|
||||
if (drawingPolygon) getApp().getMap().setState(COALITIONAREA_EDIT);
|
||||
else getApp().getMap().setState(COALITIONAREA_DRAW_POLYGON);
|
||||
setDrawingPolygon(!drawingPolygon);
|
||||
}}
|
||||
@@ -191,8 +143,7 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
tooltip={"Add a new circle"}
|
||||
checked={drawingCircle}
|
||||
onClick={() => {
|
||||
if (drawingCircle)
|
||||
getApp().getMap().setState(COALITIONAREA_EDIT);
|
||||
if (drawingCircle) getApp().getMap().setState(COALITIONAREA_EDIT);
|
||||
else getApp().getMap().setState(COALITIONAREA_DRAW_CIRCLE);
|
||||
setDrawingCircle(!drawingCircle);
|
||||
}}
|
||||
@@ -213,13 +164,14 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
>
|
||||
<div className="my-auto flex justify-between text-md">
|
||||
Area label
|
||||
<div className="rounded-md bg-red-800 p-2" onClick={() => {
|
||||
getApp().getMap().deleteCoalitionArea(activeCoalitionArea);
|
||||
setActiveCoalitionArea(null);
|
||||
}}>
|
||||
<FaTrash
|
||||
className={`text-gray-50`}
|
||||
></FaTrash>
|
||||
<div
|
||||
className="rounded-md bg-red-800 p-2"
|
||||
onClick={() => {
|
||||
getApp().getMap().deleteCoalitionArea(activeCoalitionArea);
|
||||
setActiveCoalitionArea(null);
|
||||
}}
|
||||
>
|
||||
<FaTrash className={`text-gray-50`}></FaTrash>
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
@@ -233,9 +185,7 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
focus:border-blue-500 focus:ring-blue-500
|
||||
`}
|
||||
placeholder={activeCoalitionArea.getLabelText()}
|
||||
onInput={(ev) =>
|
||||
activeCoalitionArea.setLabelText(ev.currentTarget.value)
|
||||
}
|
||||
onInput={(ev) => activeCoalitionArea.setLabelText(ev.currentTarget.value)}
|
||||
></input>
|
||||
</div>
|
||||
<div
|
||||
@@ -262,9 +212,7 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
bg-olympus-600 p-5
|
||||
`}
|
||||
>
|
||||
<div className="border-b-2 border-b-olympus-100 pb-4 text-gray-300">
|
||||
Automatic IADS generation
|
||||
</div>
|
||||
<div className="border-b-2 border-b-olympus-100 pb-4 text-gray-300">Automatic IADS generation</div>
|
||||
<OlDropdown className="" label="Units types">
|
||||
{getApp()
|
||||
.getGroundUnitDatabase()
|
||||
@@ -272,9 +220,7 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
.map((type) => {
|
||||
if (!(type in typesSelection)) {
|
||||
typesSelection[type] = true;
|
||||
setTypesSelection(
|
||||
JSON.parse(JSON.stringify(typesSelection))
|
||||
);
|
||||
setTypesSelection(JSON.parse(JSON.stringify(typesSelection)));
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -283,9 +229,7 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
checked={typesSelection[type]}
|
||||
onChange={(ev) => {
|
||||
typesSelection[type] = ev.currentTarget.checked;
|
||||
setTypesSelection(
|
||||
JSON.parse(JSON.stringify(typesSelection))
|
||||
);
|
||||
setTypesSelection(JSON.parse(JSON.stringify(typesSelection)));
|
||||
}}
|
||||
/>
|
||||
{type}
|
||||
@@ -300,9 +244,7 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
.map((era) => {
|
||||
if (!(era in erasSelection)) {
|
||||
erasSelection[era] = true;
|
||||
setErasSelection(
|
||||
JSON.parse(JSON.stringify(erasSelection))
|
||||
);
|
||||
setErasSelection(JSON.parse(JSON.stringify(erasSelection)));
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -311,9 +253,7 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
checked={erasSelection[era]}
|
||||
onChange={(ev) => {
|
||||
erasSelection[era] = ev.currentTarget.checked;
|
||||
setErasSelection(
|
||||
JSON.parse(JSON.stringify(erasSelection))
|
||||
);
|
||||
setErasSelection(JSON.parse(JSON.stringify(erasSelection)));
|
||||
}}
|
||||
/>
|
||||
{era}
|
||||
@@ -325,9 +265,7 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
{["Short range", "Medium range", "Long range"].map((range) => {
|
||||
if (!(range in rangesSelection)) {
|
||||
rangesSelection[range] = true;
|
||||
setRangesSelection(
|
||||
JSON.parse(JSON.stringify(rangesSelection))
|
||||
);
|
||||
setRangesSelection(JSON.parse(JSON.stringify(rangesSelection)));
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -336,9 +274,7 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
checked={rangesSelection[range]}
|
||||
onChange={(ev) => {
|
||||
rangesSelection[range] = ev.currentTarget.checked;
|
||||
setErasSelection(
|
||||
JSON.parse(JSON.stringify(rangesSelection))
|
||||
);
|
||||
setErasSelection(JSON.parse(JSON.stringify(rangesSelection)));
|
||||
}}
|
||||
/>
|
||||
{range}
|
||||
@@ -388,9 +324,7 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
<OlCheckbox
|
||||
checked={forceCoalitionAppropriateUnits}
|
||||
onChange={() => {
|
||||
setForceCoalitionApproriateUnits(
|
||||
!forceCoalitionAppropriateUnits
|
||||
);
|
||||
setForceCoalitionApproriateUnits(!forceCoalitionAppropriateUnits);
|
||||
}}
|
||||
/>
|
||||
Force coalition appropriate units
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
OlRoundStateButton,
|
||||
OlStateButton,
|
||||
OlLockStateButton,
|
||||
} from "../components/olstatebutton";
|
||||
import {
|
||||
faSkull,
|
||||
faCamera,
|
||||
faFlag,
|
||||
faLink,
|
||||
faUnlink,
|
||||
faBars,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { OlRoundStateButton, OlStateButton, OlLockStateButton } from "../components/olstatebutton";
|
||||
import { faSkull, faCamera, faFlag, faLink, faUnlink, faBars } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { EventsConsumer } from "../../eventscontext";
|
||||
import { StateConsumer } from "../../statecontext";
|
||||
@@ -61,20 +50,22 @@ export function Header() {
|
||||
{() => (
|
||||
<nav
|
||||
className={`
|
||||
flex w-full gap-4 border-gray-200 bg-gray-300 px-3
|
||||
drop-shadow-md z-ui-4 align-center
|
||||
z-10 flex w-full gap-4 border-gray-200 bg-gray-300 px-3
|
||||
drop-shadow-md align-center
|
||||
dark:border-gray-800 dark:bg-olympus-900
|
||||
`}
|
||||
>
|
||||
<img
|
||||
src="vite/images/icon.png"
|
||||
className="my-auto h-10 w-10 rounded-md p-0"
|
||||
className={`
|
||||
my-auto h-10 w-10 rounded-md p-0
|
||||
`}
|
||||
></img>
|
||||
{!scrolledLeft && (
|
||||
<FaChevronLeft
|
||||
className={`
|
||||
absolute left-14 h-full w-6 rounded-lg px-2 py-3.5
|
||||
text-gray-200 z-ui-1
|
||||
text-gray-200
|
||||
dark:bg-olympus-900
|
||||
`}
|
||||
/>
|
||||
@@ -124,11 +115,7 @@ export function Header() {
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<OlLockStateButton
|
||||
checked={false}
|
||||
onClick={() => {}}
|
||||
tooltip="Lock/unlock protected units (from scripted mission)"
|
||||
/>
|
||||
<OlLockStateButton checked={false} onClick={() => {}} tooltip="Lock/unlock protected units (from scripted mission)" />
|
||||
</div>
|
||||
<div className={`h-8 w-0 border-l-[2px] border-gray-700`}></div>
|
||||
<div
|
||||
@@ -145,12 +132,7 @@ export function Header() {
|
||||
<OlRoundStateButton
|
||||
key={entry[0]}
|
||||
onClick={() => {
|
||||
getApp()
|
||||
.getMap()
|
||||
.setHiddenType(
|
||||
entry[0],
|
||||
!appState.mapHiddenTypes[entry[0]]
|
||||
);
|
||||
getApp().getMap().setHiddenType(entry[0], !appState.mapHiddenTypes[entry[0]]);
|
||||
}}
|
||||
checked={!appState.mapHiddenTypes[entry[0]]}
|
||||
icon={entry[1]}
|
||||
@@ -166,36 +148,21 @@ export function Header() {
|
||||
`}
|
||||
>
|
||||
<OlRoundStateButton
|
||||
onClick={() =>
|
||||
getApp()
|
||||
.getMap()
|
||||
.setHiddenType("blue", !appState.mapHiddenTypes["blue"])
|
||||
}
|
||||
onClick={() => getApp().getMap().setHiddenType("blue", !appState.mapHiddenTypes["blue"])}
|
||||
checked={!appState.mapHiddenTypes["blue"]}
|
||||
icon={faFlag}
|
||||
className={"!text-blue-500"}
|
||||
tooltip={"Hide/show blue units"}
|
||||
/>
|
||||
<OlRoundStateButton
|
||||
onClick={() =>
|
||||
getApp()
|
||||
.getMap()
|
||||
.setHiddenType("red", !appState.mapHiddenTypes["red"])
|
||||
}
|
||||
onClick={() => getApp().getMap().setHiddenType("red", !appState.mapHiddenTypes["red"])}
|
||||
checked={!appState.mapHiddenTypes["red"]}
|
||||
icon={faFlag}
|
||||
className={"!text-red-500"}
|
||||
tooltip={"Hide/show red units"}
|
||||
/>
|
||||
<OlRoundStateButton
|
||||
onClick={() =>
|
||||
getApp()
|
||||
.getMap()
|
||||
.setHiddenType(
|
||||
"neutral",
|
||||
!appState.mapHiddenTypes["neutral"]
|
||||
)
|
||||
}
|
||||
onClick={() => getApp().getMap().setHiddenType("neutral", !appState.mapHiddenTypes["neutral"])}
|
||||
checked={!appState.mapHiddenTypes["neutral"]}
|
||||
icon={faFlag}
|
||||
className={"!text-gray-500"}
|
||||
@@ -221,12 +188,7 @@ export function Header() {
|
||||
<OlRoundStateButton
|
||||
key={entry[0]}
|
||||
onClick={() => {
|
||||
getApp()
|
||||
.getMap()
|
||||
.setHiddenType(
|
||||
entry[0],
|
||||
!appState.mapHiddenTypes[entry[0]]
|
||||
);
|
||||
getApp().getMap().setHiddenType(entry[0], !appState.mapHiddenTypes[entry[0]]);
|
||||
}}
|
||||
checked={!appState.mapHiddenTypes[entry[0]]}
|
||||
icon={entry[1]}
|
||||
@@ -236,25 +198,12 @@ export function Header() {
|
||||
})}
|
||||
</div>
|
||||
|
||||
<OlLabelToggle
|
||||
toggled={false}
|
||||
leftLabel={"Live"}
|
||||
rightLabel={"Map"}
|
||||
onClick={() => {}}
|
||||
></OlLabelToggle>
|
||||
<OlStateButton
|
||||
checked={false}
|
||||
icon={faCamera}
|
||||
onClick={() => {}}
|
||||
tooltip="Activate/deactivate camera plugin"
|
||||
/>
|
||||
<OlLabelToggle toggled={false} leftLabel={"Live"} rightLabel={"Map"} onClick={() => {}}></OlLabelToggle>
|
||||
<OlStateButton checked={false} icon={faCamera} onClick={() => {}} tooltip="Activate/deactivate camera plugin" />
|
||||
<OlDropdown label={appState.activeMapSource} className="w-60">
|
||||
{appState.mapSources.map((source) => {
|
||||
return (
|
||||
<OlDropdownItem
|
||||
key={source}
|
||||
onClick={() => getApp().getMap().setLayerName(source)}
|
||||
>
|
||||
<OlDropdownItem key={source} onClick={() => getApp().getMap().setLayerName(source)}>
|
||||
<div className="truncate">{source}</div>
|
||||
</OlDropdownItem>
|
||||
);
|
||||
@@ -265,7 +214,7 @@ export function Header() {
|
||||
<FaChevronRight
|
||||
className={`
|
||||
absolute right-0 h-full w-6 rounded-lg px-2 py-3.5
|
||||
text-gray-200 z-ui-1
|
||||
text-gray-200
|
||||
dark:bg-olympus-900
|
||||
`}
|
||||
/>
|
||||
|
||||
@@ -16,18 +16,9 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { VERSION } from "../../olympusapp";
|
||||
import { faGithub } from "@fortawesome/free-brands-svg-icons";
|
||||
|
||||
export function MainMenu(props: {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
children?: JSX.Element | JSX.Element[];
|
||||
}) {
|
||||
export function MainMenu(props: { open: boolean; onClose: () => void; children?: JSX.Element | JSX.Element[] }) {
|
||||
return (
|
||||
<Menu
|
||||
title="Main Menu"
|
||||
open={props.open}
|
||||
showBackButton={false}
|
||||
onClose={props.onClose}
|
||||
>
|
||||
<Menu title="Main Menu" open={props.open} showBackButton={false} onClose={props.onClose}>
|
||||
<div
|
||||
className={`
|
||||
flex flex-col gap-1 p-5 font-normal text-gray-900
|
||||
@@ -45,10 +36,7 @@ export function MainMenu(props: {
|
||||
<FontAwesomeIcon icon={faCheckCircle} className={`my-auto`} />
|
||||
Olympus Version {VERSION}
|
||||
</div>
|
||||
<div className="text-sm text-gray-400">
|
||||
You can use the Olympus Manager to update port, passwords or other
|
||||
settings.
|
||||
</div>
|
||||
<div className="text-sm text-gray-400">You can use the Olympus Manager to update port, passwords or other settings.</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
|
||||
@@ -5,18 +5,18 @@ import { getApp } from "../../olympusapp";
|
||||
import { FaChevronDown, FaChevronUp } from "react-icons/fa6";
|
||||
|
||||
export function MiniMapPanel(props: {}) {
|
||||
var [frameRate, setFrameRate] = useState(0);
|
||||
var [load, setLoad] = useState(0);
|
||||
var [elapsedTime, setElapsedTime] = useState(0);
|
||||
var [missionTime, setMissionTime] = useState({
|
||||
const [frameRate, setFrameRate] = useState(0);
|
||||
const [load, setLoad] = useState(0);
|
||||
const [elapsedTime, setElapsedTime] = useState(0);
|
||||
const [missionTime, setMissionTime] = useState({
|
||||
h: 0,
|
||||
m: 0,
|
||||
s: 0,
|
||||
} as DateAndTime["time"]);
|
||||
var [connected, setConnected] = useState(false);
|
||||
var [paused, setPaused] = useState(false);
|
||||
var [showMissionTime, setShowMissionTime] = useState(false);
|
||||
var [showMinimap, setShowMinimap] = useState(false);
|
||||
const [connected, setConnected] = useState(false);
|
||||
const [paused, setPaused] = useState(false);
|
||||
const [showMissionTime, setShowMissionTime] = useState(false);
|
||||
const [showMinimap, setShowMinimap] = useState(false);
|
||||
|
||||
document.addEventListener("serverStatusUpdated", (ev) => {
|
||||
const detail = (ev as CustomEvent).detail;
|
||||
@@ -73,7 +73,7 @@ export function MiniMapPanel(props: {}) {
|
||||
className={`
|
||||
absolute right-[10px]
|
||||
${showMinimap ? `top-[232px]` : `top-[70px]`}
|
||||
w-[288px] z-ui-0 flex items-center justify-between
|
||||
flex w-[288px] items-center justify-between
|
||||
${showMinimap ? `rounded-b-lg` : `rounded-lg`}
|
||||
bg-gray-200 p-3 text-sm backdrop-blur-lg backdrop-grayscale
|
||||
dark:bg-olympus-800/90 dark:text-gray-200
|
||||
|
||||
@@ -6,19 +6,9 @@ import { OlNumberInput } from "../components/olnumberinput";
|
||||
import { MapOptions } from "../../types/types";
|
||||
import { getApp } from "../../olympusapp";
|
||||
|
||||
export function Options(props: {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
options: MapOptions;
|
||||
children?: JSX.Element | JSX.Element[];
|
||||
}) {
|
||||
export function Options(props: { open: boolean; onClose: () => void; options: MapOptions; children?: JSX.Element | JSX.Element[] }) {
|
||||
return (
|
||||
<Menu
|
||||
title="User preferences"
|
||||
open={props.open}
|
||||
showBackButton={false}
|
||||
onClose={props.onClose}
|
||||
>
|
||||
<Menu title="User preferences" open={props.open} showBackButton={false} onClose={props.onClose}>
|
||||
<div
|
||||
className={`
|
||||
flex flex-col gap-2 p-5 font-normal text-gray-800
|
||||
@@ -32,15 +22,10 @@ export function Options(props: {
|
||||
dark:hover:bg-olympus-400
|
||||
`}
|
||||
onClick={() => {
|
||||
getApp()
|
||||
.getMap()
|
||||
.setOption("showUnitLabels", !props.options.showUnitLabels);
|
||||
getApp().getMap().setOption("showUnitLabels", !props.options.showUnitLabels);
|
||||
}}
|
||||
>
|
||||
<OlCheckbox
|
||||
checked={props.options.showUnitLabels}
|
||||
onChange={() => {}}
|
||||
></OlCheckbox>
|
||||
<OlCheckbox checked={props.options.showUnitLabels} onChange={() => {}}></OlCheckbox>
|
||||
<span>Show Unit Labels</span>
|
||||
<kbd
|
||||
className={`
|
||||
@@ -59,18 +44,10 @@ export function Options(props: {
|
||||
dark:hover:bg-olympus-400
|
||||
`}
|
||||
onClick={() => {
|
||||
getApp()
|
||||
.getMap()
|
||||
.setOption(
|
||||
"showUnitsEngagementRings",
|
||||
!props.options.showUnitsEngagementRings
|
||||
);
|
||||
getApp().getMap().setOption("showUnitsEngagementRings", !props.options.showUnitsEngagementRings);
|
||||
}}
|
||||
>
|
||||
<OlCheckbox
|
||||
checked={props.options.showUnitsEngagementRings}
|
||||
onChange={() => {}}
|
||||
></OlCheckbox>
|
||||
<OlCheckbox checked={props.options.showUnitsEngagementRings} onChange={() => {}}></OlCheckbox>
|
||||
<span>Show Threat Rings</span>
|
||||
<kbd
|
||||
className={`
|
||||
@@ -89,18 +66,10 @@ export function Options(props: {
|
||||
dark:hover:bg-olympus-400
|
||||
`}
|
||||
onClick={() => {
|
||||
getApp()
|
||||
.getMap()
|
||||
.setOption(
|
||||
"showUnitsAcquisitionRings",
|
||||
!props.options.showUnitsAcquisitionRings
|
||||
);
|
||||
getApp().getMap().setOption("showUnitsAcquisitionRings", !props.options.showUnitsAcquisitionRings);
|
||||
}}
|
||||
>
|
||||
<OlCheckbox
|
||||
checked={props.options.showUnitsAcquisitionRings}
|
||||
onChange={() => {}}
|
||||
></OlCheckbox>
|
||||
<OlCheckbox checked={props.options.showUnitsAcquisitionRings} onChange={() => {}}></OlCheckbox>
|
||||
<span>Show Detection rings</span>
|
||||
<kbd
|
||||
className={`
|
||||
@@ -119,15 +88,10 @@ export function Options(props: {
|
||||
dark:hover:bg-olympus-400
|
||||
`}
|
||||
onClick={() => {
|
||||
getApp()
|
||||
.getMap()
|
||||
.setOption("showUnitTargets", !props.options.showUnitTargets);
|
||||
getApp().getMap().setOption("showUnitTargets", !props.options.showUnitTargets);
|
||||
}}
|
||||
>
|
||||
<OlCheckbox
|
||||
checked={props.options.showUnitTargets}
|
||||
onChange={() => {}}
|
||||
></OlCheckbox>
|
||||
<OlCheckbox checked={props.options.showUnitTargets} onChange={() => {}}></OlCheckbox>
|
||||
<span>Show Detection lines</span>
|
||||
<kbd
|
||||
className={`
|
||||
@@ -146,18 +110,10 @@ export function Options(props: {
|
||||
dark:hover:bg-olympus-400
|
||||
`}
|
||||
onClick={() => {
|
||||
getApp()
|
||||
.getMap()
|
||||
.setOption(
|
||||
"hideUnitsShortRangeRings",
|
||||
!props.options.hideUnitsShortRangeRings
|
||||
);
|
||||
getApp().getMap().setOption("hideUnitsShortRangeRings", !props.options.hideUnitsShortRangeRings);
|
||||
}}
|
||||
>
|
||||
<OlCheckbox
|
||||
checked={props.options.hideUnitsShortRangeRings}
|
||||
onChange={() => {}}
|
||||
></OlCheckbox>
|
||||
<OlCheckbox checked={props.options.hideUnitsShortRangeRings} onChange={() => {}}></OlCheckbox>
|
||||
<span>Hide Short range Rings</span>
|
||||
<kbd
|
||||
className={`
|
||||
@@ -176,15 +132,10 @@ export function Options(props: {
|
||||
dark:hover:bg-olympus-400
|
||||
`}
|
||||
onClick={() => {
|
||||
getApp()
|
||||
.getMap()
|
||||
.setOption("hideGroupMembers", !props.options.hideGroupMembers);
|
||||
getApp().getMap().setOption("hideGroupMembers", !props.options.hideGroupMembers);
|
||||
}}
|
||||
>
|
||||
<OlCheckbox
|
||||
checked={props.options.hideGroupMembers}
|
||||
onChange={() => {}}
|
||||
></OlCheckbox>
|
||||
<OlCheckbox checked={props.options.hideGroupMembers} onChange={() => {}}></OlCheckbox>
|
||||
<span>Hide Group members</span>
|
||||
<kbd
|
||||
className={`
|
||||
@@ -203,15 +154,10 @@ export function Options(props: {
|
||||
dark:hover:bg-olympus-400
|
||||
`}
|
||||
onClick={() => {
|
||||
getApp()
|
||||
.getMap()
|
||||
.setOption("showMinimap", !props.options.showMinimap);
|
||||
getApp().getMap().setOption("showMinimap", !props.options.showMinimap);
|
||||
}}
|
||||
>
|
||||
<OlCheckbox
|
||||
checked={props.options.showMinimap}
|
||||
onChange={() => {}}
|
||||
></OlCheckbox>
|
||||
<OlCheckbox checked={props.options.showMinimap} onChange={() => {}}></OlCheckbox>
|
||||
<span>Show minimap</span>
|
||||
<kbd
|
||||
className={`
|
||||
|
||||
@@ -1,14 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
import { OlStateButton } from "../components/olstatebutton";
|
||||
import {
|
||||
faGamepad,
|
||||
faRuler,
|
||||
faPencil,
|
||||
faEllipsisV,
|
||||
faCog,
|
||||
faQuestionCircle,
|
||||
faPlusSquare
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { faGamepad, faRuler, faPencil, faEllipsisV, faCog, faQuestionCircle, faPlusSquare } from "@fortawesome/free-solid-svg-icons";
|
||||
import { EventsConsumer } from "../../eventscontext";
|
||||
import { StateConsumer } from "../../statecontext";
|
||||
|
||||
@@ -20,7 +12,7 @@ export function SideBar() {
|
||||
{(events) => (
|
||||
<nav
|
||||
className={`
|
||||
flex flex-col z-ui-4 h-full bg-gray-300
|
||||
absolute left-0 z-20 flex h-full flex-col bg-gray-300
|
||||
dark:bg-olympus-900
|
||||
`}
|
||||
>
|
||||
@@ -52,12 +44,7 @@ export function SideBar() {
|
||||
icon={faGamepad}
|
||||
tooltip=""
|
||||
></OlStateButton>
|
||||
<OlStateButton
|
||||
onClick={events.toggleMeasureMenuVisible}
|
||||
checked={appState.measureMenuVisible}
|
||||
icon={faRuler}
|
||||
tooltip=""
|
||||
></OlStateButton>
|
||||
<OlStateButton onClick={events.toggleMeasureMenuVisible} checked={appState.measureMenuVisible} icon={faRuler} tooltip=""></OlStateButton>
|
||||
<OlStateButton
|
||||
onClick={events.toggleDrawingMenuVisible}
|
||||
checked={appState.drawingMenuVisible}
|
||||
@@ -73,9 +60,7 @@ export function SideBar() {
|
||||
`}
|
||||
>
|
||||
<OlStateButton
|
||||
onClick={() =>
|
||||
window.open("https://github.com/Pax1601/DCSOlympus/wiki")
|
||||
}
|
||||
onClick={() => window.open("https://github.com/Pax1601/DCSOlympus/wiki")}
|
||||
checked={false}
|
||||
icon={faQuestionCircle}
|
||||
tooltip="Open user guide on separate window"
|
||||
|
||||
@@ -20,26 +20,15 @@ import { getUnitsByLabel } from "../../other/utils";
|
||||
|
||||
library.add(faPlus);
|
||||
|
||||
export function SpawnMenu(props: {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
children?: JSX.Element | JSX.Element[];
|
||||
}) {
|
||||
var [blueprint, setBlueprint] = useState(null as null | UnitBlueprint);
|
||||
var [filterString, setFilterString] = useState("");
|
||||
export function SpawnMenu(props: { open: boolean; onClose: () => void; children?: JSX.Element | JSX.Element[] }) {
|
||||
const [blueprint, setBlueprint] = useState(null as null | UnitBlueprint);
|
||||
const [filterString, setFilterString] = useState("");
|
||||
|
||||
const [
|
||||
filteredAircraft,
|
||||
filteredHelicopters,
|
||||
filteredAirDefense,
|
||||
filteredGroundUnits,
|
||||
filteredNavyUnits,
|
||||
] = getUnitsByLabel(filterString);
|
||||
const [filteredAircraft, filteredHelicopters, filteredAirDefense, filteredGroundUnits, filteredNavyUnits] = getUnitsByLabel(filterString);
|
||||
|
||||
useEffect(() => {
|
||||
if (!props.open) {
|
||||
if (getApp()?.getMap()?.getState() === SPAWN_UNIT)
|
||||
getApp().getMap().setState(IDLE);
|
||||
if (getApp()?.getMap()?.getState() === SPAWN_UNIT) getApp().getMap().setState(IDLE);
|
||||
if (blueprint !== null) setBlueprint(null);
|
||||
}
|
||||
});
|
||||
@@ -58,10 +47,7 @@ export function SpawnMenu(props: {
|
||||
<>
|
||||
{blueprint === null && (
|
||||
<div className="p-5">
|
||||
<OlSearchBar
|
||||
onChange={(value) => setFilterString(value)}
|
||||
text={filterString}
|
||||
/>
|
||||
<OlSearchBar onChange={(value) => setFilterString(value)} text={filterString} />
|
||||
<OlAccordion title={`Aircraft`}>
|
||||
<div
|
||||
className={`
|
||||
@@ -69,14 +55,7 @@ export function SpawnMenu(props: {
|
||||
`}
|
||||
>
|
||||
{Object.entries(filteredAircraft).map((entry) => {
|
||||
return (
|
||||
<OlUnitEntryList
|
||||
key={entry[0]}
|
||||
icon={olButtonsVisibilityAircraft}
|
||||
blueprint={entry[1]}
|
||||
onClick={() => setBlueprint(entry[1])}
|
||||
/>
|
||||
);
|
||||
return <OlUnitEntryList key={entry[0]} icon={olButtonsVisibilityAircraft} blueprint={entry[1]} onClick={() => setBlueprint(entry[1])} />;
|
||||
})}
|
||||
</div>
|
||||
</OlAccordion>
|
||||
@@ -87,14 +66,7 @@ export function SpawnMenu(props: {
|
||||
`}
|
||||
>
|
||||
{Object.entries(filteredHelicopters).map((entry) => {
|
||||
return (
|
||||
<OlUnitEntryList
|
||||
key={entry[0]}
|
||||
icon={olButtonsVisibilityHelicopter}
|
||||
blueprint={entry[1]}
|
||||
onClick={() => setBlueprint(entry[1])}
|
||||
/>
|
||||
);
|
||||
return <OlUnitEntryList key={entry[0]} icon={olButtonsVisibilityHelicopter} blueprint={entry[1]} onClick={() => setBlueprint(entry[1])} />;
|
||||
})}
|
||||
</div>
|
||||
</OlAccordion>
|
||||
@@ -105,14 +77,7 @@ export function SpawnMenu(props: {
|
||||
`}
|
||||
>
|
||||
{Object.entries(filteredAirDefense).map((entry) => {
|
||||
return (
|
||||
<OlUnitEntryList
|
||||
key={entry[0]}
|
||||
icon={olButtonsVisibilityGroundunitSam}
|
||||
blueprint={entry[1]}
|
||||
onClick={() => setBlueprint(entry[1])}
|
||||
/>
|
||||
);
|
||||
return <OlUnitEntryList key={entry[0]} icon={olButtonsVisibilityGroundunitSam} blueprint={entry[1]} onClick={() => setBlueprint(entry[1])} />;
|
||||
})}
|
||||
</div>
|
||||
</OlAccordion>
|
||||
@@ -123,14 +88,7 @@ export function SpawnMenu(props: {
|
||||
`}
|
||||
>
|
||||
{Object.entries(filteredGroundUnits).map((entry) => {
|
||||
return (
|
||||
<OlUnitEntryList
|
||||
key={entry[0]}
|
||||
icon={olButtonsVisibilityGroundunit}
|
||||
blueprint={entry[1]}
|
||||
onClick={() => setBlueprint(entry[1])}
|
||||
/>
|
||||
);
|
||||
return <OlUnitEntryList key={entry[0]} icon={olButtonsVisibilityGroundunit} blueprint={entry[1]} onClick={() => setBlueprint(entry[1])} />;
|
||||
})}
|
||||
</div>
|
||||
</OlAccordion>
|
||||
@@ -141,14 +99,7 @@ export function SpawnMenu(props: {
|
||||
`}
|
||||
>
|
||||
{Object.entries(filteredNavyUnits).map((entry) => {
|
||||
return (
|
||||
<OlUnitEntryList
|
||||
key={entry[0]}
|
||||
icon={olButtonsVisibilityNavyunit}
|
||||
blueprint={entry[1]}
|
||||
onClick={() => setBlueprint(entry[1])}
|
||||
/>
|
||||
);
|
||||
return <OlUnitEntryList key={entry[0]} icon={olButtonsVisibilityNavyunit} blueprint={entry[1]} onClick={() => setBlueprint(entry[1])} />;
|
||||
})}
|
||||
</div>
|
||||
</OlAccordion>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,14 +9,10 @@ import { FaInfoCircle } from "react-icons/fa";
|
||||
import { FaChevronLeft, FaChevronRight } from "react-icons/fa6";
|
||||
|
||||
export function UnitMouseControlBar(props: {}) {
|
||||
var [open, setOpen] = useState(false);
|
||||
var [selectedUnits, setSelectedUnits] = useState([] as Unit[]);
|
||||
var [contextActionsSet, setContextActionsSet] = useState(
|
||||
new ContextActionSet()
|
||||
);
|
||||
var [activeContextAction, setActiveContextAction] = useState(
|
||||
null as null | ContextAction
|
||||
);
|
||||
const [open, setOpen] = useState(false);
|
||||
const [selectedUnits, setSelectedUnits] = useState([] as Unit[]);
|
||||
const [contextActionsSet, setContextActionsSet] = useState(new ContextActionSet());
|
||||
const [activeContextAction, setActiveContextAction] = useState(null as null | ContextAction);
|
||||
const [scrolledLeft, setScrolledLeft] = useState(true);
|
||||
const [scrolledRight, setScrolledRight] = useState(false);
|
||||
|
||||
@@ -87,7 +83,7 @@ export function UnitMouseControlBar(props: {}) {
|
||||
<div
|
||||
className={`
|
||||
absolute left-[50%] top-16 flex max-w-[80%]
|
||||
translate-x-[calc(-50%+2rem)] gap-2 rounded-md bg-gray-200 z-ui-2
|
||||
translate-x-[calc(-50%+2rem)] gap-2 rounded-md bg-gray-200
|
||||
dark:bg-olympus-900
|
||||
`}
|
||||
>
|
||||
@@ -100,40 +96,34 @@ export function UnitMouseControlBar(props: {}) {
|
||||
`}
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
className="flex gap-2 overflow-x-auto no-scrollbar p-2"
|
||||
onScroll={(ev) => onScroll(ev.target)}
|
||||
ref={scrollRef}
|
||||
>
|
||||
{Object.values(contextActionsSet.getContextActions()).map(
|
||||
(contextAction) => {
|
||||
return (
|
||||
<OlStateButton
|
||||
checked={contextAction === activeContextAction}
|
||||
icon={contextAction.getIcon()}
|
||||
tooltip={contextAction.getLabel()}
|
||||
onClick={() => {
|
||||
if (contextAction.getOptions().executeImmediately) {
|
||||
setActiveContextAction(null);
|
||||
contextAction.executeCallback(null, null);
|
||||
<div className="flex gap-2 overflow-x-auto no-scrollbar p-2" onScroll={(ev) => onScroll(ev.target)} ref={scrollRef}>
|
||||
{Object.values(contextActionsSet.getContextActions()).map((contextAction) => {
|
||||
return (
|
||||
<OlStateButton
|
||||
checked={contextAction === activeContextAction}
|
||||
icon={contextAction.getIcon()}
|
||||
tooltip={contextAction.getLabel()}
|
||||
onClick={() => {
|
||||
if (contextAction.getOptions().executeImmediately) {
|
||||
setActiveContextAction(null);
|
||||
contextAction.executeCallback(null, null);
|
||||
} else {
|
||||
if (activeContextAction != contextAction) {
|
||||
setActiveContextAction(contextAction);
|
||||
getApp().getMap().setState(CONTEXT_ACTION, {
|
||||
contextAction: contextAction,
|
||||
});
|
||||
} else {
|
||||
if (activeContextAction != contextAction) {
|
||||
setActiveContextAction(contextAction);
|
||||
getApp().getMap().setState(CONTEXT_ACTION, {
|
||||
contextAction: contextAction,
|
||||
});
|
||||
} else {
|
||||
setActiveContextAction(null);
|
||||
getApp().getMap().setState(CONTEXT_ACTION, {
|
||||
contextAction: null,
|
||||
});
|
||||
}
|
||||
setActiveContextAction(null);
|
||||
getApp().getMap().setState(CONTEXT_ACTION, {
|
||||
contextAction: null,
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
)}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{!scrolledRight && (
|
||||
<FaChevronRight
|
||||
@@ -148,9 +138,9 @@ export function UnitMouseControlBar(props: {}) {
|
||||
{activeContextAction && (
|
||||
<div
|
||||
className={`
|
||||
absolute left-[50%] top-32 flex translate-x-[calc(-50%+2rem)]
|
||||
items-center gap-2 rounded-md bg-gray-200 p-4 z-ui-1
|
||||
min-w-[300px]
|
||||
absolute left-[50%] top-32 flex min-w-[300px]
|
||||
translate-x-[calc(-50%+2rem)] items-center gap-2 rounded-md
|
||||
bg-gray-200 p-4
|
||||
dark:bg-olympus-800
|
||||
`}
|
||||
>
|
||||
|
||||
@@ -21,14 +21,12 @@ export function UnitSpawnMenu(props: { blueprint: UnitBlueprint }) {
|
||||
const altitudeStep = 500;
|
||||
|
||||
/* State initialization */
|
||||
var [spawnCoalition, setSpawnCoalition] = useState("blue" as Coalition);
|
||||
var [spawnNumber, setSpawnNumber] = useState(1);
|
||||
var [spawnRole, setSpawnRole] = useState("");
|
||||
var [spawnLoadoutName, setSpawnLoadout] = useState("");
|
||||
var [spawnAltitude, setSpawnAltitude] = useState(
|
||||
(maxAltitude - minAltitude) / 2
|
||||
);
|
||||
var [spawnAltitudeType, setSpawnAltitudeType] = useState(false);
|
||||
const [spawnCoalition, setSpawnCoalition] = useState("blue" as Coalition);
|
||||
const [spawnNumber, setSpawnNumber] = useState(1);
|
||||
const [spawnRole, setSpawnRole] = useState("");
|
||||
const [spawnLoadoutName, setSpawnLoadout] = useState("");
|
||||
const [spawnAltitude, setSpawnAltitude] = useState((maxAltitude - minAltitude) / 2);
|
||||
const [spawnAltitudeType, setSpawnAltitudeType] = useState(false);
|
||||
|
||||
/* When the menu is opened show the unit preview on the map as a cursor */
|
||||
useEffect(() => {
|
||||
@@ -53,8 +51,7 @@ export function UnitSpawnMenu(props: { blueprint: UnitBlueprint }) {
|
||||
},
|
||||
});
|
||||
} else {
|
||||
if (getApp()?.getMap()?.getState() === SPAWN_UNIT)
|
||||
getApp().getMap().setState(IDLE);
|
||||
if (getApp()?.getMap()?.getState() === SPAWN_UNIT) getApp().getMap().setState(IDLE);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -76,9 +73,7 @@ export function UnitSpawnMenu(props: { blueprint: UnitBlueprint }) {
|
||||
});
|
||||
|
||||
/* Initialize the loadout */
|
||||
spawnLoadoutName === "" &&
|
||||
loadouts.length > 0 &&
|
||||
setSpawnLoadout(loadouts[0].name);
|
||||
spawnLoadoutName === "" && loadouts.length > 0 && setSpawnLoadout(loadouts[0].name);
|
||||
const spawnLoadout = props.blueprint.loadouts?.find((loadout) => {
|
||||
return loadout.name === spawnLoadoutName;
|
||||
});
|
||||
@@ -111,13 +106,7 @@ export function UnitSpawnMenu(props: { blueprint: UnitBlueprint }) {
|
||||
setSpawnNumber(Math.min(maxNumber, spawnNumber + 1));
|
||||
}}
|
||||
onChange={(ev) => {
|
||||
!isNaN(Number(ev.target.value)) &&
|
||||
setSpawnNumber(
|
||||
Math.max(
|
||||
minNumber,
|
||||
Math.min(maxNumber, Number(ev.target.value))
|
||||
)
|
||||
);
|
||||
!isNaN(Number(ev.target.value)) && setSpawnNumber(Math.max(minNumber, Math.min(maxNumber, Number(ev.target.value))));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
@@ -143,12 +132,7 @@ export function UnitSpawnMenu(props: { blueprint: UnitBlueprint }) {
|
||||
`}
|
||||
>{`${Intl.NumberFormat("en-US").format(spawnAltitude)} FT`}</span>
|
||||
</div>
|
||||
<OlLabelToggle
|
||||
toggled={spawnAltitudeType}
|
||||
leftLabel={"AGL"}
|
||||
rightLabel={"ASL"}
|
||||
onClick={() => setSpawnAltitudeType(!spawnAltitudeType)}
|
||||
/>
|
||||
<OlLabelToggle toggled={spawnAltitudeType} leftLabel={"AGL"} rightLabel={"ASL"} onClick={() => setSpawnAltitudeType(!spawnAltitudeType)} />
|
||||
</div>
|
||||
<OlRangeSlider
|
||||
onChange={(ev) => setSpawnAltitude(Number(ev.target.value))}
|
||||
|
||||
@@ -11,14 +11,7 @@ import { MainMenu } from "./panels/mainmenu";
|
||||
import { SideBar } from "./panels/sidebar";
|
||||
import { Options } from "./panels/options";
|
||||
import { MapHiddenTypes, MapOptions } from "../types/types";
|
||||
import {
|
||||
BLUE_COMMANDER,
|
||||
GAME_MASTER,
|
||||
IDLE,
|
||||
MAP_HIDDEN_TYPES_DEFAULTS,
|
||||
MAP_OPTIONS_DEFAULTS,
|
||||
RED_COMMANDER,
|
||||
} from "../constants/constants";
|
||||
import { BLUE_COMMANDER, GAME_MASTER, IDLE, MAP_HIDDEN_TYPES_DEFAULTS, MAP_OPTIONS_DEFAULTS, RED_COMMANDER } from "../constants/constants";
|
||||
import { getApp, setupApp } from "../olympusapp";
|
||||
import { LoginModal } from "./modals/login";
|
||||
import { sha256 } from "js-sha256";
|
||||
@@ -39,22 +32,22 @@ export type OlympusState = {
|
||||
};
|
||||
|
||||
export function UI() {
|
||||
var [loginModalVisible, setLoginModalVisible] = useState(true);
|
||||
var [mainMenuVisible, setMainMenuVisible] = useState(false);
|
||||
var [spawnMenuVisible, setSpawnMenuVisible] = useState(false);
|
||||
var [unitControlMenuVisible, setUnitControlMenuVisible] = useState(false);
|
||||
var [measureMenuVisible, setMeasureMenuVisible] = useState(false);
|
||||
var [drawingMenuVisible, setDrawingMenuVisible] = useState(false);
|
||||
var [optionsMenuVisible, setOptionsMenuVisible] = useState(false);
|
||||
var [mapHiddenTypes, setMapHiddenTypes] = useState(MAP_HIDDEN_TYPES_DEFAULTS);
|
||||
var [mapOptions, setMapOptions] = useState(MAP_OPTIONS_DEFAULTS);
|
||||
var [checkingPassword, setCheckingPassword] = useState(false);
|
||||
var [loginError, setLoginError] = useState(false);
|
||||
var [commandMode, setCommandMode] = useState(null as null | string);
|
||||
var [mapSources, setMapSources] = useState([] as string[]);
|
||||
var [activeMapSource, setActiveMapSource] = useState("");
|
||||
var [mapBoxSelection, setMapBoxSelection] = useState(false);
|
||||
var [mapState, setMapState] = useState(IDLE);
|
||||
const [loginModalVisible, setLoginModalVisible] = useState(true);
|
||||
const [mainMenuVisible, setMainMenuVisible] = useState(false);
|
||||
const [spawnMenuVisible, setSpawnMenuVisible] = useState(false);
|
||||
const [unitControlMenuVisible, setUnitControlMenuVisible] = useState(false);
|
||||
const [measureMenuVisible, setMeasureMenuVisible] = useState(false);
|
||||
const [drawingMenuVisible, setDrawingMenuVisible] = useState(false);
|
||||
const [optionsMenuVisible, setOptionsMenuVisible] = useState(false);
|
||||
const [mapHiddenTypes, setMapHiddenTypes] = useState(MAP_HIDDEN_TYPES_DEFAULTS);
|
||||
const [mapOptions, setMapOptions] = useState(MAP_OPTIONS_DEFAULTS);
|
||||
const [checkingPassword, setCheckingPassword] = useState(false);
|
||||
const [loginError, setLoginError] = useState(false);
|
||||
const [commandMode, setCommandMode] = useState(null as null | string);
|
||||
const [mapSources, setMapSources] = useState([] as string[]);
|
||||
const [activeMapSource, setActiveMapSource] = useState("");
|
||||
const [mapBoxSelection, setMapBoxSelection] = useState(false);
|
||||
const [mapState, setMapState] = useState(IDLE);
|
||||
|
||||
document.addEventListener("hiddenTypesChanged", (ev) => {
|
||||
setMapHiddenTypes({ ...getApp().getMap().getHiddenTypes() });
|
||||
@@ -65,10 +58,9 @@ export function UI() {
|
||||
});
|
||||
|
||||
document.addEventListener("mapStateChanged", (ev) => {
|
||||
if ((ev as CustomEvent).detail === IDLE && mapState !== IDLE)
|
||||
hideAllMenus();
|
||||
|
||||
setMapState(String((ev as CustomEvent).detail))
|
||||
if ((ev as CustomEvent).detail === IDLE && mapState !== IDLE) hideAllMenus();
|
||||
|
||||
setMapState(String((ev as CustomEvent).detail));
|
||||
});
|
||||
|
||||
document.addEventListener("mapSourceChanged", (ev) => {
|
||||
@@ -78,9 +70,7 @@ export function UI() {
|
||||
|
||||
document.addEventListener("configLoaded", (ev) => {
|
||||
let config = getApp().getConfig();
|
||||
var sources = Object.keys(config.mapMirrors).concat(
|
||||
Object.keys(config.mapLayers)
|
||||
);
|
||||
var sources = Object.keys(config.mapMirrors).concat(Object.keys(config.mapLayers));
|
||||
setMapSources(sources);
|
||||
setActiveMapSource(sources[0]);
|
||||
});
|
||||
@@ -112,9 +102,7 @@ export function UI() {
|
||||
(response) => {
|
||||
const commandMode = response.mission.commandModeOptions.commandMode;
|
||||
try {
|
||||
[GAME_MASTER, BLUE_COMMANDER, RED_COMMANDER].includes(commandMode)
|
||||
? setCommandMode(commandMode)
|
||||
: setLoginError(true);
|
||||
[GAME_MASTER, BLUE_COMMANDER, RED_COMMANDER].includes(commandMode) ? setCommandMode(commandMode) : setLoginError(true);
|
||||
} catch {
|
||||
setLoginError(true);
|
||||
}
|
||||
@@ -197,14 +185,18 @@ export function UI() {
|
||||
},
|
||||
}}
|
||||
>
|
||||
<div className="absolute left-0 top-0 flex h-full w-full flex-col">
|
||||
<div
|
||||
className={`
|
||||
absolute left-0 top-0 flex h-full w-full flex-col
|
||||
`}
|
||||
>
|
||||
<Header />
|
||||
<div className="flex h-full">
|
||||
<div className="flex justify-reverse h-full">
|
||||
{loginModalVisible && (
|
||||
<>
|
||||
<div
|
||||
className={`
|
||||
fixed left-0 top-0 h-full w-full z-ui-5 bg-[#111111]/95
|
||||
fixed left-0 top-0 z-30 h-full w-full bg-[#111111]/95
|
||||
`}
|
||||
></div>
|
||||
<LoginModal
|
||||
@@ -223,32 +215,17 @@ export function UI() {
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<SideBar />
|
||||
<MainMenu
|
||||
open={mainMenuVisible}
|
||||
onClose={() => setMainMenuVisible(false)}
|
||||
/>
|
||||
<SpawnMenu
|
||||
open={spawnMenuVisible}
|
||||
onClose={() => setSpawnMenuVisible(false)}
|
||||
/>
|
||||
<Options
|
||||
open={optionsMenuVisible}
|
||||
onClose={() => setOptionsMenuVisible(false)}
|
||||
options={mapOptions}
|
||||
/>
|
||||
<div id="map-container" className="z-0 h-full w-screen" />
|
||||
<MainMenu open={mainMenuVisible} onClose={() => setMainMenuVisible(false)} />
|
||||
<SpawnMenu open={spawnMenuVisible} onClose={() => setSpawnMenuVisible(false)} />
|
||||
<Options open={optionsMenuVisible} onClose={() => setOptionsMenuVisible(false)} options={mapOptions} />
|
||||
<MiniMapPanel />
|
||||
<ControlsPanel />
|
||||
<UnitControlMenu
|
||||
open={unitControlMenuVisible}
|
||||
onClose={() => setUnitControlMenuVisible(false)}
|
||||
/>
|
||||
<DrawingMenu
|
||||
open={drawingMenuVisible}
|
||||
onClose={() => setDrawingMenuVisible(false)}
|
||||
/>
|
||||
<div id="map-container" className="h-full w-screen" />
|
||||
<UnitControlMenu open={unitControlMenuVisible} onClose={() => setUnitControlMenuVisible(false)} />
|
||||
<DrawingMenu open={drawingMenuVisible} onClose={() => setDrawingMenuVisible(false)} />
|
||||
|
||||
<UnitMouseControlBar />
|
||||
<SideBar />
|
||||
</div>
|
||||
</div>
|
||||
</EventsProvider>
|
||||
|
||||
@@ -6,11 +6,7 @@ export interface ContextActionOptions {
|
||||
executeImmediately?: boolean;
|
||||
}
|
||||
|
||||
export type ContextActionCallback = (
|
||||
units: Unit[],
|
||||
targetUnit: Unit | null,
|
||||
targetPosition: LatLng | null
|
||||
) => void;
|
||||
export type ContextActionCallback = (units: Unit[], targetUnit: Unit | null, targetPosition: LatLng | null) => void;
|
||||
|
||||
export class ContextAction {
|
||||
#id: string = "";
|
||||
@@ -21,14 +17,7 @@ export class ContextAction {
|
||||
#icon: IconDefinition;
|
||||
#options: ContextActionOptions;
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
description: string,
|
||||
icon: IconDefinition,
|
||||
callback: ContextActionCallback,
|
||||
options: ContextActionOptions
|
||||
) {
|
||||
constructor(id: string, label: string, description: string, icon: IconDefinition, callback: ContextActionCallback, options: ContextActionOptions) {
|
||||
this.#id = id;
|
||||
this.#label = label;
|
||||
this.#description = description;
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import {
|
||||
ContextAction,
|
||||
ContextActionCallback,
|
||||
ContextActionOptions,
|
||||
} from "./contextaction";
|
||||
import { ContextAction, ContextActionCallback, ContextActionOptions } from "./contextaction";
|
||||
import { Unit } from "./unit";
|
||||
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
|
||||
|
||||
@@ -21,14 +17,7 @@ export class ContextActionSet {
|
||||
options = options || {};
|
||||
|
||||
if (!(id in this.#contextActions)) {
|
||||
this.#contextActions[id] = new ContextAction(
|
||||
id,
|
||||
label,
|
||||
description,
|
||||
icon,
|
||||
callback,
|
||||
options
|
||||
);
|
||||
this.#contextActions[id] = new ContextAction(id, label, description, icon, callback, options);
|
||||
}
|
||||
this.#contextActions[id].addUnit(unit);
|
||||
}
|
||||
|
||||
@@ -4,10 +4,7 @@ import { UnitDatabase } from "./unitdatabase";
|
||||
|
||||
export class AircraftDatabase extends UnitDatabase {
|
||||
constructor() {
|
||||
super(
|
||||
window.location.href.split("?")[0].replace("vite/", "") +
|
||||
"api/databases/units/aircraftdatabase"
|
||||
);
|
||||
super(window.location.href.split("?")[0].replace("vite/", "") + "api/databases/units/aircraftdatabase");
|
||||
}
|
||||
|
||||
getCategory() {
|
||||
@@ -15,11 +12,7 @@ export class AircraftDatabase extends UnitDatabase {
|
||||
}
|
||||
|
||||
getSpawnPointsByName(name: string) {
|
||||
if (
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode ==
|
||||
GAME_MASTER ||
|
||||
!getApp().getMissionManager().getCommandModeOptions().restrictSpawns
|
||||
)
|
||||
if (getApp().getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER || !getApp().getMissionManager().getCommandModeOptions().restrictSpawns)
|
||||
return 0;
|
||||
|
||||
const blueprint = this.getByName(name);
|
||||
|
||||
@@ -4,18 +4,11 @@ import { UnitDatabase } from "./unitdatabase";
|
||||
|
||||
export class GroundUnitDatabase extends UnitDatabase {
|
||||
constructor() {
|
||||
super(
|
||||
window.location.href.split("?")[0].replace("vite/", "") +
|
||||
"api/databases/units/groundunitdatabase"
|
||||
);
|
||||
super(window.location.href.split("?")[0].replace("vite/", "") + "api/databases/units/groundunitdatabase");
|
||||
}
|
||||
|
||||
getSpawnPointsByName(name: string) {
|
||||
if (
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode ==
|
||||
GAME_MASTER ||
|
||||
!getApp().getMissionManager().getCommandModeOptions().restrictSpawns
|
||||
)
|
||||
if (getApp().getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER || !getApp().getMissionManager().getCommandModeOptions().restrictSpawns)
|
||||
return 0;
|
||||
|
||||
const blueprint = this.getByName(name);
|
||||
|
||||
@@ -4,18 +4,11 @@ import { UnitDatabase } from "./unitdatabase";
|
||||
|
||||
export class HelicopterDatabase extends UnitDatabase {
|
||||
constructor() {
|
||||
super(
|
||||
window.location.href.split("?")[0].replace("vite/", "") +
|
||||
"api/databases/units/helicopterdatabase"
|
||||
);
|
||||
super(window.location.href.split("?")[0].replace("vite/", "") + "api/databases/units/helicopterdatabase");
|
||||
}
|
||||
|
||||
getSpawnPointsByName(name: string) {
|
||||
if (
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode ==
|
||||
GAME_MASTER ||
|
||||
!getApp().getMissionManager().getCommandModeOptions().restrictSpawns
|
||||
)
|
||||
if (getApp().getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER || !getApp().getMissionManager().getCommandModeOptions().restrictSpawns)
|
||||
return 0;
|
||||
|
||||
const blueprint = this.getByName(name);
|
||||
|
||||
@@ -4,18 +4,11 @@ import { UnitDatabase } from "./unitdatabase";
|
||||
|
||||
export class NavyUnitDatabase extends UnitDatabase {
|
||||
constructor() {
|
||||
super(
|
||||
window.location.href.split("?")[0].replace("vite/", "") +
|
||||
"api/databases/units/navyunitdatabase"
|
||||
);
|
||||
super(window.location.href.split("?")[0].replace("vite/", "") + "api/databases/units/navyunitdatabase");
|
||||
}
|
||||
|
||||
getSpawnPointsByName(name: string) {
|
||||
if (
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode ==
|
||||
GAME_MASTER ||
|
||||
!getApp().getMissionManager().getCommandModeOptions().restrictSpawns
|
||||
)
|
||||
if (getApp().getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER || !getApp().getMissionManager().getCommandModeOptions().restrictSpawns)
|
||||
return 0;
|
||||
|
||||
const blueprint = this.getByName(name);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { LatLng } from "leaflet";
|
||||
import { getApp } from "../../olympusapp";
|
||||
import { GAME_MASTER } from "../../constants/constants";
|
||||
import { UnitBlueprint } from "../../interfaces";
|
||||
import { LoadoutBlueprint, UnitBlueprint } from "../../interfaces";
|
||||
|
||||
export abstract class UnitDatabase {
|
||||
blueprints: { [key: string]: UnitBlueprint } = {};
|
||||
@@ -49,15 +49,13 @@ export abstract class UnitDatabase {
|
||||
|
||||
getBlueprints(includeDisabled: boolean = false) {
|
||||
if (
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode ==
|
||||
GAME_MASTER ||
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER ||
|
||||
!getApp().getMissionManager().getCommandModeOptions().restrictSpawns
|
||||
) {
|
||||
var filteredBlueprints: { [key: string]: UnitBlueprint } = {};
|
||||
for (let unit in this.blueprints) {
|
||||
const blueprint = this.blueprints[unit];
|
||||
if (blueprint.enabled || includeDisabled)
|
||||
filteredBlueprints[unit] = blueprint;
|
||||
if (blueprint.enabled || includeDisabled) filteredBlueprints[unit] = blueprint;
|
||||
}
|
||||
return filteredBlueprints;
|
||||
} else {
|
||||
@@ -66,16 +64,10 @@ export abstract class UnitDatabase {
|
||||
const blueprint = this.blueprints[unit];
|
||||
if (
|
||||
(blueprint.enabled || includeDisabled) &&
|
||||
this.getSpawnPointsByName(blueprint.name) <=
|
||||
getApp().getMissionManager().getAvailableSpawnPoints() &&
|
||||
getApp()
|
||||
.getMissionManager()
|
||||
.getCommandModeOptions()
|
||||
.eras.includes(blueprint.era) &&
|
||||
(!getApp().getMissionManager().getCommandModeOptions()
|
||||
.restrictToCoalition ||
|
||||
blueprint.coalition ===
|
||||
getApp().getMissionManager().getCommandedCoalition() ||
|
||||
this.getSpawnPointsByName(blueprint.name) <= getApp().getMissionManager().getAvailableSpawnPoints() &&
|
||||
getApp().getMissionManager().getCommandModeOptions().eras.includes(blueprint.era) &&
|
||||
(!getApp().getMissionManager().getCommandModeOptions().restrictToCoalition ||
|
||||
blueprint.coalition === getApp().getMissionManager().getCommandedCoalition() ||
|
||||
blueprint.coalition === undefined)
|
||||
) {
|
||||
filteredBlueprints[unit] = blueprint;
|
||||
@@ -107,11 +99,7 @@ export abstract class UnitDatabase {
|
||||
var filteredBlueprints = this.getBlueprints();
|
||||
var types: string[] = [];
|
||||
for (let unit in filteredBlueprints) {
|
||||
if (
|
||||
typeof unitFilter === "function" &&
|
||||
!unitFilter(filteredBlueprints[unit])
|
||||
)
|
||||
continue;
|
||||
if (typeof unitFilter === "function" && !unitFilter(filteredBlueprints[unit])) continue;
|
||||
var type = filteredBlueprints[unit].type;
|
||||
if (type && type !== "" && !types.includes(type)) types.push(type);
|
||||
}
|
||||
@@ -132,7 +120,7 @@ export abstract class UnitDatabase {
|
||||
/* Get all blueprints by range */
|
||||
getByRange(range: string) {
|
||||
var filteredBlueprints = this.getBlueprints();
|
||||
var unitswithrange = [];
|
||||
var unitswithrange: UnitBlueprint[] = [];
|
||||
var minRange = 0;
|
||||
var maxRange = 0;
|
||||
|
||||
@@ -161,7 +149,7 @@ export abstract class UnitDatabase {
|
||||
/* Get all blueprints by type */
|
||||
getByType(type: string) {
|
||||
var filteredBlueprints = this.getBlueprints();
|
||||
var units = [];
|
||||
var units: UnitBlueprint[] = [];
|
||||
for (let unit in filteredBlueprints) {
|
||||
if (filteredBlueprints[unit].type === type) {
|
||||
units.push(filteredBlueprints[unit]);
|
||||
@@ -173,15 +161,12 @@ export abstract class UnitDatabase {
|
||||
/* Get all blueprints by role */
|
||||
getByRole(role: string) {
|
||||
var filteredBlueprints = this.getBlueprints();
|
||||
var units = [];
|
||||
var units: UnitBlueprint[] = [];
|
||||
for (let unit in filteredBlueprints) {
|
||||
var loadouts = filteredBlueprints[unit].loadouts;
|
||||
if (loadouts) {
|
||||
for (let loadout of loadouts) {
|
||||
if (
|
||||
loadout.roles.includes(role) ||
|
||||
loadout.roles.includes(role.toLowerCase())
|
||||
) {
|
||||
if (loadout.roles.includes(role) || loadout.roles.includes(role.toLowerCase())) {
|
||||
units.push(filteredBlueprints[unit]);
|
||||
break;
|
||||
}
|
||||
@@ -194,7 +179,7 @@ export abstract class UnitDatabase {
|
||||
/* Get the names of all the loadouts for a specific unit and for a specific role */
|
||||
getLoadoutNamesByRole(name: string, role: string) {
|
||||
var filteredBlueprints = this.getBlueprints();
|
||||
var loadoutsByRole = [];
|
||||
var loadoutsByRole: string[] = [];
|
||||
var loadouts = filteredBlueprints[name].loadouts;
|
||||
if (loadouts) {
|
||||
for (let loadout of loadouts) {
|
||||
|
||||
@@ -8,8 +8,7 @@ export class Group {
|
||||
this.#name = name;
|
||||
|
||||
document.addEventListener("unitDeath", (e: any) => {
|
||||
if (this.#members.includes(e.detail))
|
||||
this.getLeader()?.onGroupChanged(e.detail);
|
||||
if (this.#members.includes(e.detail)) this.getLeader()?.onGroupChanged(e.detail);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -15,11 +15,9 @@ export class UnitDataFileExport extends UnitDataFile {
|
||||
//this.dialog = new Dialog(elementId);
|
||||
//this.#element = this.dialog.getElement();
|
||||
|
||||
this.#element
|
||||
.querySelector(".start-transfer")
|
||||
?.addEventListener("click", (ev: MouseEventInit) => {
|
||||
this.#doExport();
|
||||
});
|
||||
this.#element.querySelector(".start-transfer")?.addEventListener("click", (ev: MouseEventInit) => {
|
||||
this.#doExport();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,9 +63,7 @@ export class UnitDataFileExport extends UnitDataFile {
|
||||
let selectedUnits: Unit[] = [];
|
||||
|
||||
this.#element
|
||||
.querySelectorAll(
|
||||
`input[type="checkbox"][name="category-coalition-selection"]:checked`
|
||||
)
|
||||
.querySelectorAll(`input[type="checkbox"][name="category-coalition-selection"]:checked`)
|
||||
.forEach(<HTMLInputElement>(checkbox: HTMLInputElement) => {
|
||||
if (checkbox instanceof HTMLInputElement) {
|
||||
const [category, coalition] = checkbox.value.split(":"); // e.g. "category:coalition"
|
||||
@@ -83,8 +79,7 @@ export class UnitDataFileExport extends UnitDataFile {
|
||||
var unitsToExport: { [key: string]: any } = {};
|
||||
selectedUnits.forEach((unit: Unit) => {
|
||||
var data: any = unit.getData();
|
||||
if (unit.getGroupName() in unitsToExport)
|
||||
unitsToExport[unit.getGroupName()].push(data);
|
||||
if (unit.getGroupName() in unitsToExport) unitsToExport[unit.getGroupName()].push(data);
|
||||
else unitsToExport[unit.getGroupName()] = [data];
|
||||
});
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,15 +19,7 @@ import {
|
||||
} from "../other/utils";
|
||||
import { CoalitionPolygon } from "../map/coalitionarea/coalitionpolygon";
|
||||
import { groundUnitDatabase } from "./databases/groundunitdatabase";
|
||||
import {
|
||||
CONTEXT_ACTION,
|
||||
DELETE_CYCLE_TIME,
|
||||
DELETE_SLOW_THRESHOLD,
|
||||
DataIndexes,
|
||||
GAME_MASTER,
|
||||
IADSDensities,
|
||||
IDLE,
|
||||
} from "../constants/constants";
|
||||
import { CONTEXT_ACTION, DELETE_CYCLE_TIME, DELETE_SLOW_THRESHOLD, DataIndexes, GAME_MASTER, IADSDensities, IDLE } from "../constants/constants";
|
||||
import { DataExtractor } from "../server/dataextractor";
|
||||
import { citiesDatabase } from "./databases/citiesdatabase";
|
||||
import { aircraftDatabase } from "./databases/aircraftdatabase";
|
||||
@@ -36,12 +28,7 @@ import { navyUnitDatabase } from "./databases/navyunitdatabase";
|
||||
import { TemporaryUnitMarker } from "../map/markers/temporaryunitmarker";
|
||||
//import { Popup } from "../popups/popup";
|
||||
//import { HotgroupPanel } from "../panels/hotgrouppanel";
|
||||
import {
|
||||
Contact,
|
||||
UnitBlueprint,
|
||||
UnitData,
|
||||
UnitSpawnTable,
|
||||
} from "../interfaces";
|
||||
import { Contact, UnitBlueprint, UnitData, UnitSpawnTable } from "../interfaces";
|
||||
//import { Dialog } from "../dialog/dialog";
|
||||
import { Group } from "./group";
|
||||
import { UnitDataFileExport } from "./importexport/unitdatafileexport";
|
||||
@@ -68,18 +55,14 @@ export class UnitsManager {
|
||||
this.#units = {};
|
||||
|
||||
document.addEventListener("commandModeOptionsChanged", () => {
|
||||
Object.values(this.#units).forEach((unit: Unit) =>
|
||||
unit.updateVisibility()
|
||||
);
|
||||
Object.values(this.#units).forEach((unit: Unit) => unit.updateVisibility());
|
||||
});
|
||||
document.addEventListener("contactsUpdated", (e: CustomEvent) => {
|
||||
document.addEventListener("contactsUpdated", (e) => {
|
||||
this.#requestDetectionUpdate = true;
|
||||
});
|
||||
document.addEventListener("copy", () => this.copy());
|
||||
document.addEventListener("deleteSelectedUnits", () => this.delete());
|
||||
document.addEventListener("explodeSelectedUnits", (e: any) =>
|
||||
this.delete(true, e.detail.type)
|
||||
);
|
||||
document.addEventListener("explodeSelectedUnits", (e: any) => this.delete(true, e.detail.type));
|
||||
document.addEventListener("exportToFile", () => this.exportToFile());
|
||||
document.addEventListener("importFromFile", () => this.importFromFile());
|
||||
document.addEventListener("keyup", (event) => this.#onKeyUp(event));
|
||||
@@ -90,18 +73,11 @@ export class UnitsManager {
|
||||
document.addEventListener("selectedUnitsChangeSpeed", (e: any) => {
|
||||
this.changeSpeed(e.detail.type);
|
||||
});
|
||||
document.addEventListener("unitDeselection", (e: CustomEvent) =>
|
||||
this.#onUnitDeselection(e.detail)
|
||||
);
|
||||
document.addEventListener("unitSelection", (e: CustomEvent) =>
|
||||
this.#onUnitSelection(e.detail)
|
||||
);
|
||||
document.addEventListener(
|
||||
"toggleMarkerProtection",
|
||||
(ev: CustomEventInit) => {
|
||||
this.#showNumberOfSelectedProtectedUnits();
|
||||
}
|
||||
);
|
||||
document.addEventListener("unitDeselection", (e) => this.#onUnitDeselection((e as CustomEvent).detail));
|
||||
document.addEventListener("unitSelection", (e) => this.#onUnitSelection((e as CustomEvent).detail));
|
||||
document.addEventListener("toggleMarkerProtection", (e) => {
|
||||
this.#showNumberOfSelectedProtectedUnits();
|
||||
});
|
||||
|
||||
//this.#slowDeleteDialog = new Dialog("slow-delete-dialog");
|
||||
}
|
||||
@@ -171,11 +147,7 @@ export class UnitsManager {
|
||||
else if (map.getIsUnitProtected(unit)) data.dcsProtected.push(unit);
|
||||
else data.dcsUnprotected.push(unit);
|
||||
});
|
||||
data.controllable = [].concat(
|
||||
data.dcsUnprotected,
|
||||
data.human,
|
||||
data.olympus
|
||||
);
|
||||
data.controllable = [].concat(data.dcsUnprotected, data.human, data.olympus);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -185,15 +157,10 @@ export class UnitsManager {
|
||||
*/
|
||||
showProtectedUnitsPopup(numOfProtectedUnits: number) {
|
||||
if (numOfProtectedUnits < 1) return;
|
||||
const messageText =
|
||||
numOfProtectedUnits === 1
|
||||
? `Unit is protected`
|
||||
: `All selected units are protected`;
|
||||
const messageText = numOfProtectedUnits === 1 ? `Unit is protected` : `All selected units are protected`;
|
||||
//(getApp().getPopupsManager().get("infoPopup") as Popup).setText(messageText);
|
||||
// Cheap way for now until we use more locks
|
||||
let lock = <HTMLElement>(
|
||||
document.querySelector("#unit-visibility-control button.lock")
|
||||
);
|
||||
let lock = <HTMLElement>document.querySelector("#unit-visibility-control button.lock");
|
||||
lock.classList.add("prompt");
|
||||
setTimeout(() => lock.classList.remove("prompt"), 4000);
|
||||
}
|
||||
@@ -238,8 +205,7 @@ export class UnitsManager {
|
||||
|
||||
if (groupName !== "") {
|
||||
/* If the group does not yet exist, create it */
|
||||
if (!(groupName in this.#groups))
|
||||
this.#groups[groupName] = new Group(groupName);
|
||||
if (!(groupName in this.#groups)) this.#groups[groupName] = new Group(groupName);
|
||||
|
||||
/* If the unit was not assigned to a group yet, assign it */
|
||||
if (unit.getGroup() === null) this.#groups[groupName].addMember(unit);
|
||||
@@ -249,16 +215,11 @@ export class UnitsManager {
|
||||
/* If we are not in Game Master mode, visibility of units by the user is determined by the detections of the units themselves. This is performed here.
|
||||
This operation is computationally expensive, therefore it is only performed when #requestDetectionUpdate is true. This happens whenever a change in the detectionUpdates is detected
|
||||
*/
|
||||
if (
|
||||
this.#requestDetectionUpdate &&
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode !=
|
||||
GAME_MASTER
|
||||
) {
|
||||
if (this.#requestDetectionUpdate && getApp().getMissionManager().getCommandModeOptions().commandMode != GAME_MASTER) {
|
||||
/* Create a dictionary of empty detection methods arrays */
|
||||
var detectionMethods: { [key: string]: number[] } = {};
|
||||
for (let ID in this.#units) detectionMethods[ID] = [];
|
||||
for (let ID in getApp().getWeaponsManager().getWeapons())
|
||||
detectionMethods[ID] = [];
|
||||
for (let ID in getApp().getWeaponsManager().getWeapons()) detectionMethods[ID] = [];
|
||||
|
||||
/* Fill the array with the detection methods */
|
||||
for (let ID in this.#units) {
|
||||
@@ -267,10 +228,7 @@ export class UnitsManager {
|
||||
const contacts = unit.getContacts();
|
||||
contacts.forEach((contact: Contact) => {
|
||||
const contactID = contact.ID;
|
||||
if (
|
||||
contactID in detectionMethods &&
|
||||
!detectionMethods[contactID].includes(contact.detectionMethod)
|
||||
)
|
||||
if (contactID in detectionMethods && !detectionMethods[contactID].includes(contact.detectionMethod))
|
||||
detectionMethods[contactID]?.push(contact.detectionMethod);
|
||||
});
|
||||
}
|
||||
@@ -320,10 +278,7 @@ export class UnitsManager {
|
||||
this.deselectAllUnits();
|
||||
for (let ID in this.#units) {
|
||||
if (this.#units[ID].getHidden() == false) {
|
||||
var latlng = new LatLng(
|
||||
this.#units[ID].getPosition().lat,
|
||||
this.#units[ID].getPosition().lng
|
||||
);
|
||||
var latlng = new LatLng(this.#units[ID].getPosition().lat, this.#units[ID].getPosition().lng);
|
||||
if (bounds.contains(latlng)) {
|
||||
this.#units[ID].setSelected(true);
|
||||
}
|
||||
@@ -340,9 +295,7 @@ export class UnitsManager {
|
||||
this.deselectAllUnits();
|
||||
}
|
||||
|
||||
this.getUnitsByHotgroup(hotgroup).forEach((unit: Unit) =>
|
||||
unit.setSelected(true)
|
||||
);
|
||||
this.getUnitsByHotgroup(hotgroup).forEach((unit: Unit) => unit.setSelected(true));
|
||||
}
|
||||
|
||||
/** Get all the currently selected units
|
||||
@@ -350,12 +303,7 @@ export class UnitsManager {
|
||||
* @param options Selection options
|
||||
* @returns Array of selected units
|
||||
*/
|
||||
getSelectedUnits(options?: {
|
||||
excludeHumans?: boolean;
|
||||
excludeProtected?: boolean;
|
||||
onlyOnePerGroup?: boolean;
|
||||
showProtectionReminder?: boolean;
|
||||
}) {
|
||||
getSelectedUnits(options?: { excludeHumans?: boolean; excludeProtected?: boolean; onlyOnePerGroup?: boolean; showProtectionReminder?: boolean }) {
|
||||
let selectedUnits: Unit[] = [];
|
||||
let numProtectedUnits = 0;
|
||||
for (const [ID, unit] of Object.entries(this.#units)) {
|
||||
@@ -363,10 +311,7 @@ export class UnitsManager {
|
||||
if (options) {
|
||||
if (options.excludeHumans && unit.getHuman()) continue;
|
||||
|
||||
if (
|
||||
options.excludeProtected === true &&
|
||||
this.#unitIsProtected(unit)
|
||||
) {
|
||||
if (options.excludeProtected === true && this.#unitIsProtected(unit)) {
|
||||
numProtectedUnits++;
|
||||
continue;
|
||||
}
|
||||
@@ -375,23 +320,13 @@ export class UnitsManager {
|
||||
}
|
||||
}
|
||||
if (options) {
|
||||
if (
|
||||
options.showProtectionReminder === true &&
|
||||
numProtectedUnits > selectedUnits.length &&
|
||||
selectedUnits.length === 0
|
||||
)
|
||||
if (options.showProtectionReminder === true && numProtectedUnits > selectedUnits.length && selectedUnits.length === 0)
|
||||
this.showProtectedUnitsPopup(numProtectedUnits);
|
||||
|
||||
if (options.onlyOnePerGroup) {
|
||||
var temp: Unit[] = [];
|
||||
for (let unit of selectedUnits) {
|
||||
if (
|
||||
!temp.some(
|
||||
(otherUnit: Unit) =>
|
||||
unit.getGroupName() == otherUnit.getGroupName()
|
||||
)
|
||||
)
|
||||
temp.push(unit);
|
||||
if (!temp.some((otherUnit: Unit) => unit.getGroupName() == otherUnit.getGroupName())) temp.push(unit);
|
||||
}
|
||||
selectedUnits = temp;
|
||||
}
|
||||
@@ -466,11 +401,7 @@ export class UnitsManager {
|
||||
this.#units[idx].getCoalition() != unit.getCoalition()
|
||||
) {
|
||||
this.#units[idx].getContacts().forEach((contact: Contact) => {
|
||||
if (
|
||||
contact.ID == unit.ID &&
|
||||
!detectionMethods.includes(contact.detectionMethod)
|
||||
)
|
||||
detectionMethods.push(contact.detectionMethod);
|
||||
if (contact.ID == unit.ID && !detectionMethods.includes(contact.detectionMethod)) detectionMethods.push(contact.detectionMethod);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -485,12 +416,7 @@ export class UnitsManager {
|
||||
* @param rotation Rotation in radians by which the formation will be rigidly rotated. E.g. a ( V ) formation will look like this ( < ) if rotated pi/4 radians (90 degrees)
|
||||
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
|
||||
*/
|
||||
addDestination(
|
||||
latlng: L.LatLng,
|
||||
mantainRelativePosition: boolean,
|
||||
rotation: number,
|
||||
units: Unit[] | null = null
|
||||
) {
|
||||
addDestination(latlng: L.LatLng, mantainRelativePosition: boolean, rotation: number, units: Unit[] | null = null) {
|
||||
if (units === null)
|
||||
units = this.getSelectedUnits({
|
||||
excludeHumans: true,
|
||||
@@ -509,8 +435,7 @@ export class UnitsManager {
|
||||
|
||||
/* Compute the destination for each unit. If mantainRelativePosition is true, compute the destination so to hold the relative positions */
|
||||
var unitDestinations: { [key: number]: LatLng } = {};
|
||||
if (mantainRelativePosition)
|
||||
unitDestinations = this.computeGroupDestination(latlng, rotation);
|
||||
if (mantainRelativePosition) unitDestinations = this.computeGroupDestination(latlng, rotation);
|
||||
else
|
||||
units.forEach((unit: Unit) => {
|
||||
unitDestinations[unit.ID] = latlng;
|
||||
@@ -523,8 +448,7 @@ export class UnitsManager {
|
||||
if (leader && leader.getSelected()) leader.addDestination(latlng);
|
||||
else unit.addDestination(latlng);
|
||||
} else {
|
||||
if (unit.ID in unitDestinations)
|
||||
unit.addDestination(unitDestinations[unit.ID]);
|
||||
if (unit.ID in unitDestinations) unit.addDestination(unitDestinations[unit.ID]);
|
||||
}
|
||||
});
|
||||
this.#showActionMessage(units, " new destination added");
|
||||
@@ -790,10 +714,7 @@ export class UnitsManager {
|
||||
units = segregatedUnits.controllable;
|
||||
|
||||
units.forEach((unit: Unit) => unit.setReactionToThreat(reactionToThreat));
|
||||
this.#showActionMessage(
|
||||
units,
|
||||
`reaction to threat set to ${reactionToThreat}`
|
||||
);
|
||||
this.#showActionMessage(units, `reaction to threat set to ${reactionToThreat}`);
|
||||
}
|
||||
|
||||
/** Set a specific emissions & countermeasures to all the selected units
|
||||
@@ -801,10 +722,7 @@ export class UnitsManager {
|
||||
* @param emissionCountermeasure Value to set, see constants for acceptable values
|
||||
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
|
||||
*/
|
||||
setEmissionsCountermeasures(
|
||||
emissionCountermeasure: string,
|
||||
units: Unit[] | null = null
|
||||
) {
|
||||
setEmissionsCountermeasures(emissionCountermeasure: string, units: Unit[] | null = null) {
|
||||
if (units === null)
|
||||
units = this.getSelectedUnits({
|
||||
excludeHumans: true,
|
||||
@@ -821,13 +739,8 @@ export class UnitsManager {
|
||||
|
||||
units = segregatedUnits.controllable;
|
||||
|
||||
units.forEach((unit: Unit) =>
|
||||
unit.setEmissionsCountermeasures(emissionCountermeasure)
|
||||
);
|
||||
this.#showActionMessage(
|
||||
units,
|
||||
`emissions & countermeasures set to ${emissionCountermeasure}`
|
||||
);
|
||||
units.forEach((unit: Unit) => unit.setEmissionsCountermeasures(emissionCountermeasure));
|
||||
this.#showActionMessage(units, `emissions & countermeasures set to ${emissionCountermeasure}`);
|
||||
}
|
||||
|
||||
/** Turn selected units on or off, only works on ground and navy units
|
||||
@@ -932,10 +845,7 @@ export class UnitsManager {
|
||||
units = segregatedUnits.controllable;
|
||||
|
||||
units.forEach((unit: Unit) => unit.attackUnit(ID));
|
||||
this.#showActionMessage(
|
||||
units,
|
||||
`attacking unit ${this.getUnitByID(ID)?.getUnitName()}`
|
||||
);
|
||||
this.#showActionMessage(units, `attacking unit ${this.getUnitByID(ID)?.getUnitName()}`);
|
||||
}
|
||||
|
||||
/** Instruct units to refuel at the nearest tanker, if possible. Else units will RTB
|
||||
@@ -957,10 +867,7 @@ export class UnitsManager {
|
||||
}
|
||||
|
||||
segregatedUnits.controllable.forEach((unit: Unit) => unit.refuel());
|
||||
this.#showActionMessage(
|
||||
segregatedUnits.controllable,
|
||||
`sent to nearest tanker`
|
||||
);
|
||||
this.#showActionMessage(segregatedUnits.controllable, `sent to nearest tanker`);
|
||||
}
|
||||
|
||||
/** Instruct the selected units to follow another unit in a formation. Only works for aircrafts and helicopters.
|
||||
@@ -970,12 +877,7 @@ export class UnitsManager {
|
||||
* @param formation Optional parameter, defines a predefined formation type. Values are: "trail", "echelon-lh", "echelon-rh", "line-abreast-lh", "line-abreast-rh", "front", "diamond"
|
||||
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
|
||||
*/
|
||||
followUnit(
|
||||
ID: number,
|
||||
offset?: { x: number; y: number; z: number },
|
||||
formation?: string,
|
||||
units: Unit[] | null = null
|
||||
) {
|
||||
followUnit(ID: number, offset?: { x: number; y: number; z: number }, formation?: string, units: Unit[] | null = null) {
|
||||
if (units === null)
|
||||
units = this.getSelectedUnits({
|
||||
excludeHumans: true,
|
||||
@@ -1062,10 +964,7 @@ export class UnitsManager {
|
||||
count++;
|
||||
}
|
||||
});
|
||||
this.#showActionMessage(
|
||||
units,
|
||||
`following unit ${this.getUnitByID(ID)?.getUnitName()}`
|
||||
);
|
||||
this.#showActionMessage(units, `following unit ${this.getUnitByID(ID)?.getUnitName()}`);
|
||||
}
|
||||
|
||||
/** Instruct the selected units to perform precision bombing of specific coordinates
|
||||
@@ -1173,13 +1072,9 @@ export class UnitsManager {
|
||||
try {
|
||||
groundElevation = parseFloat(response);
|
||||
} catch {
|
||||
console.warn(
|
||||
"Simulate fire fight: could not retrieve ground elevation"
|
||||
);
|
||||
console.warn("Simulate fire fight: could not retrieve ground elevation");
|
||||
}
|
||||
units?.forEach((unit: Unit) =>
|
||||
unit.simulateFireFight(latlng, groundElevation)
|
||||
);
|
||||
units?.forEach((unit: Unit) => unit.simulateFireFight(latlng, groundElevation));
|
||||
});
|
||||
this.#showActionMessage(units, `unit simulating fire fight`);
|
||||
}
|
||||
@@ -1346,16 +1241,8 @@ export class UnitsManager {
|
||||
|
||||
if (this.getUnitsCategories(units).length == 1) {
|
||||
var unitsData: { ID: number; location: LatLng }[] = [];
|
||||
units.forEach((unit: Unit) =>
|
||||
unitsData.push({ ID: unit.ID, location: unit.getPosition() })
|
||||
);
|
||||
getApp()
|
||||
.getServerManager()
|
||||
.cloneUnits(
|
||||
unitsData,
|
||||
true,
|
||||
0 /* No spawn points, we delete the original units */
|
||||
);
|
||||
units.forEach((unit: Unit) => unitsData.push({ ID: unit.ID, location: unit.getPosition() }));
|
||||
getApp().getServerManager().cloneUnits(unitsData, true, 0 /* No spawn points, we delete the original units */);
|
||||
this.#showActionMessage(units, `created a group`);
|
||||
} else {
|
||||
//(getApp().getPopupsManager().get("infoPopup") as Popup).setText(`Groups can only be created from units of the same category`);
|
||||
@@ -1368,9 +1255,7 @@ export class UnitsManager {
|
||||
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
|
||||
*/
|
||||
setHotgroup(hotgroup: number, units: Unit[] | null = null) {
|
||||
this.getUnitsByHotgroup(hotgroup).forEach((unit: Unit) =>
|
||||
unit.setHotgroup(null)
|
||||
);
|
||||
this.getUnitsByHotgroup(hotgroup).forEach((unit: Unit) => unit.setHotgroup(null));
|
||||
this.addToHotgroup(hotgroup);
|
||||
}
|
||||
|
||||
@@ -1392,11 +1277,7 @@ export class UnitsManager {
|
||||
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
|
||||
* @returns
|
||||
*/
|
||||
delete(
|
||||
explosion: boolean = false,
|
||||
explosionType: string = "",
|
||||
units: Unit[] | null = null
|
||||
) {
|
||||
delete(explosion: boolean = false, explosionType: string = "", units: Unit[] | null = null) {
|
||||
if (units === null)
|
||||
units = this.getSelectedUnits({
|
||||
excludeProtected: true,
|
||||
@@ -1417,21 +1298,13 @@ export class UnitsManager {
|
||||
|
||||
if (
|
||||
selectionContainsAHuman &&
|
||||
!confirm(
|
||||
"Your selection includes a human player. Deleting humans causes their vehicle to crash.\n\nAre you sure you want to do this?"
|
||||
)
|
||||
!confirm("Your selection includes a human player. Deleting humans causes their vehicle to crash.\n\nAre you sure you want to do this?")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const doDelete = (
|
||||
explosion = false,
|
||||
explosionType = "",
|
||||
immediate = false
|
||||
) => {
|
||||
units?.forEach((unit: Unit) =>
|
||||
unit.delete(explosion, explosionType, immediate)
|
||||
);
|
||||
const doDelete = (explosion = false, explosionType = "", immediate = false) => {
|
||||
units?.forEach((unit: Unit) => unit.delete(explosion, explosionType, immediate));
|
||||
this.#showActionMessage(units as Unit[], `deleted`);
|
||||
};
|
||||
|
||||
@@ -1453,11 +1326,7 @@ export class UnitsManager {
|
||||
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
|
||||
* @returns Array of positions for each unit, in order
|
||||
*/
|
||||
computeGroupDestination(
|
||||
latlng: LatLng,
|
||||
rotation: number,
|
||||
units: Unit[] | null = null
|
||||
) {
|
||||
computeGroupDestination(latlng: LatLng, rotation: number, units: Unit[] | null = null) {
|
||||
if (units === null)
|
||||
units = this.getSelectedUnits({
|
||||
excludeHumans: true,
|
||||
@@ -1479,10 +1348,7 @@ export class UnitsManager {
|
||||
var len = units.length;
|
||||
var center = { x: 0, y: 0 };
|
||||
units.forEach((unit: Unit) => {
|
||||
var mercator = latLngToMercator(
|
||||
unit.getPosition().lat,
|
||||
unit.getPosition().lng
|
||||
);
|
||||
var mercator = latLngToMercator(unit.getPosition().lat, unit.getPosition().lng);
|
||||
center.x += mercator.x / len;
|
||||
center.y += mercator.y / len;
|
||||
});
|
||||
@@ -1490,10 +1356,7 @@ export class UnitsManager {
|
||||
/* Compute the distances from the center of the group */
|
||||
var unitDestinations: { [key: number]: LatLng } = {};
|
||||
units.forEach((unit: Unit) => {
|
||||
var mercator = latLngToMercator(
|
||||
unit.getPosition().lat,
|
||||
unit.getPosition().lng
|
||||
);
|
||||
var mercator = latLngToMercator(unit.getPosition().lat, unit.getPosition().lng);
|
||||
var distancesFromCenter = {
|
||||
dx: mercator.x - center.x,
|
||||
dy: mercator.y - center.y,
|
||||
@@ -1504,12 +1367,8 @@ export class UnitsManager {
|
||||
dx: 0,
|
||||
dy: 0,
|
||||
};
|
||||
rotatedDistancesFromCenter.dx =
|
||||
distancesFromCenter.dx * Math.cos(deg2rad(rotation)) -
|
||||
distancesFromCenter.dy * Math.sin(deg2rad(rotation));
|
||||
rotatedDistancesFromCenter.dy =
|
||||
distancesFromCenter.dx * Math.sin(deg2rad(rotation)) +
|
||||
distancesFromCenter.dy * Math.cos(deg2rad(rotation));
|
||||
rotatedDistancesFromCenter.dx = distancesFromCenter.dx * Math.cos(deg2rad(rotation)) - distancesFromCenter.dy * Math.sin(deg2rad(rotation));
|
||||
rotatedDistancesFromCenter.dy = distancesFromCenter.dx * Math.sin(deg2rad(rotation)) + distancesFromCenter.dy * Math.cos(deg2rad(rotation));
|
||||
|
||||
/* Compute the final position of the unit */
|
||||
var destMercator = latLngToMercator(latlng.lat, latlng.lng); // Convert destination point to mercator
|
||||
@@ -1552,28 +1411,18 @@ export class UnitsManager {
|
||||
let spawnPoints = 0;
|
||||
|
||||
/* If spawns are restricted, check that the user has the necessary spawn points */
|
||||
if (
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode !=
|
||||
GAME_MASTER
|
||||
) {
|
||||
if (
|
||||
getApp().getMissionManager().getCommandModeOptions().restrictSpawns &&
|
||||
getApp().getMissionManager().getRemainingSetupTime() < 0
|
||||
) {
|
||||
if (getApp().getMissionManager().getCommandModeOptions().commandMode != GAME_MASTER) {
|
||||
if (getApp().getMissionManager().getCommandModeOptions().restrictSpawns && getApp().getMissionManager().getRemainingSetupTime() < 0) {
|
||||
//(getApp().getPopupsManager().get("infoPopup") as Popup).setText(`Units can be pasted only during SETUP phase`);
|
||||
return false;
|
||||
}
|
||||
|
||||
this.#copiedUnits.forEach((unit: UnitData) => {
|
||||
let unitSpawnPoints = getUnitDatabaseByCategory(
|
||||
unit.category
|
||||
)?.getSpawnPointsByName(unit.name);
|
||||
let unitSpawnPoints = getUnitDatabaseByCategory(unit.category)?.getSpawnPointsByName(unit.name);
|
||||
if (unitSpawnPoints !== undefined) spawnPoints += unitSpawnPoints;
|
||||
});
|
||||
|
||||
if (
|
||||
spawnPoints > getApp().getMissionManager().getAvailableSpawnPoints()
|
||||
) {
|
||||
if (spawnPoints > getApp().getMissionManager().getAvailableSpawnPoints()) {
|
||||
//(getApp().getPopupsManager().get("infoPopup") as Popup).setText("Not enough spawn points available!");
|
||||
return false;
|
||||
}
|
||||
@@ -1603,18 +1452,10 @@ export class UnitsManager {
|
||||
let markers: TemporaryUnitMarker[] = [];
|
||||
groups[groupName].forEach((unit: UnitData) => {
|
||||
var position = new LatLng(
|
||||
getApp().getMap().getMouseCoordinates().lat +
|
||||
unit.position.lat -
|
||||
avgLat,
|
||||
getApp().getMap().getMouseCoordinates().lng +
|
||||
unit.position.lng -
|
||||
avgLng
|
||||
);
|
||||
markers.push(
|
||||
getApp()
|
||||
.getMap()
|
||||
.addTemporaryMarker(position, unit.name, unit.coalition)
|
||||
getApp().getMap().getMouseCoordinates().lat + unit.position.lat - avgLat,
|
||||
getApp().getMap().getMouseCoordinates().lng + unit.position.lng - avgLng
|
||||
);
|
||||
markers.push(getApp().getMap().addTemporaryMarker(position, unit.name, unit.coalition));
|
||||
units.push({ ID: unit.ID, location: position });
|
||||
});
|
||||
|
||||
@@ -1667,29 +1508,18 @@ export class UnitsManager {
|
||||
Object.keys(airbases).forEach((airbaseName: string) => {
|
||||
var airbase = airbases[airbaseName];
|
||||
/* Check if the city is inside the coalition area */
|
||||
if (
|
||||
areaContains(
|
||||
new LatLng(airbase.getLatLng().lat, airbase.getLatLng().lng),
|
||||
coalitionArea
|
||||
)
|
||||
) {
|
||||
if (areaContains(new LatLng(airbase.getLatLng().lat, airbase.getLatLng().lng), coalitionArea)) {
|
||||
/* Arbitrary formula to obtain a number of units */
|
||||
var pointsNumber = 2 + (10 * density) / 100;
|
||||
for (let i = 0; i < pointsNumber; i++) {
|
||||
/* Place the unit nearby the airbase, depending on the distribution parameter */
|
||||
var bearing = Math.random() * 360;
|
||||
var distance = Math.random() * distribution * 100;
|
||||
const latlng = bearingAndDistanceToLatLng(
|
||||
airbase.getLatLng().lat,
|
||||
airbase.getLatLng().lng,
|
||||
bearing,
|
||||
distance
|
||||
);
|
||||
const latlng = bearingAndDistanceToLatLng(airbase.getLatLng().lat, airbase.getLatLng().lng, bearing, distance);
|
||||
|
||||
/* Make sure the unit is still inside the coalition area */
|
||||
if (areaContains(latlng, coalitionArea)) {
|
||||
const type =
|
||||
activeTypes[Math.floor(Math.random() * activeTypes.length)];
|
||||
const type = activeTypes[Math.floor(Math.random() * activeTypes.length)];
|
||||
if (Math.random() < IADSDensities[type]) {
|
||||
/* Get a random blueprint depending on the selected parameters and spawn the unit */
|
||||
let unitBlueprint: UnitBlueprint | null;
|
||||
@@ -1729,74 +1559,65 @@ export class UnitsManager {
|
||||
}
|
||||
});
|
||||
|
||||
citiesDatabase.forEach(
|
||||
(city: { lat: number; lng: number; pop: number }) => {
|
||||
/* Check if the city is inside the coalition area */
|
||||
if (areaContains(new LatLng(city.lat, city.lng), coalitionArea)) {
|
||||
/* Arbitrary formula to obtain a number of units depending on the city population */
|
||||
var pointsNumber = 2 + (Math.pow(city.pop, 0.15) * density) / 100;
|
||||
for (let i = 0; i < pointsNumber; i++) {
|
||||
/* Place the unit nearby the city, depending on the distribution parameter */
|
||||
var bearing = Math.random() * 360;
|
||||
var distance = Math.random() * distribution * 100;
|
||||
const latlng = bearingAndDistanceToLatLng(
|
||||
city.lat,
|
||||
city.lng,
|
||||
bearing,
|
||||
distance
|
||||
);
|
||||
citiesDatabase.forEach((city: { lat: number; lng: number; pop: number }) => {
|
||||
/* Check if the city is inside the coalition area */
|
||||
if (areaContains(new LatLng(city.lat, city.lng), coalitionArea)) {
|
||||
/* Arbitrary formula to obtain a number of units depending on the city population */
|
||||
var pointsNumber = 2 + (Math.pow(city.pop, 0.15) * density) / 100;
|
||||
for (let i = 0; i < pointsNumber; i++) {
|
||||
/* Place the unit nearby the city, depending on the distribution parameter */
|
||||
var bearing = Math.random() * 360;
|
||||
var distance = Math.random() * distribution * 100;
|
||||
const latlng = bearingAndDistanceToLatLng(city.lat, city.lng, bearing, distance);
|
||||
|
||||
/* Make sure the unit is still inside the coalition area */
|
||||
if (areaContains(latlng, coalitionArea)) {
|
||||
const type =
|
||||
activeTypes[Math.floor(Math.random() * activeTypes.length)];
|
||||
if (Math.random() < IADSDensities[type]) {
|
||||
/* Get a random blueprint depending on the selected parameters and spawn the unit */
|
||||
let unitBlueprint: UnitBlueprint | null;
|
||||
if (forceCoalition)
|
||||
unitBlueprint = randomUnitBlueprint(groundUnitDatabase, {
|
||||
type: type,
|
||||
eras: activeEras,
|
||||
ranges: activeRanges,
|
||||
coalition: coalitionArea.getCoalition(),
|
||||
});
|
||||
else
|
||||
unitBlueprint = randomUnitBlueprint(groundUnitDatabase, {
|
||||
type: type,
|
||||
eras: activeEras,
|
||||
ranges: activeRanges,
|
||||
});
|
||||
/* Make sure the unit is still inside the coalition area */
|
||||
if (areaContains(latlng, coalitionArea)) {
|
||||
const type = activeTypes[Math.floor(Math.random() * activeTypes.length)];
|
||||
if (Math.random() < IADSDensities[type]) {
|
||||
/* Get a random blueprint depending on the selected parameters and spawn the unit */
|
||||
let unitBlueprint: UnitBlueprint | null;
|
||||
if (forceCoalition)
|
||||
unitBlueprint = randomUnitBlueprint(groundUnitDatabase, {
|
||||
type: type,
|
||||
eras: activeEras,
|
||||
ranges: activeRanges,
|
||||
coalition: coalitionArea.getCoalition(),
|
||||
});
|
||||
else
|
||||
unitBlueprint = randomUnitBlueprint(groundUnitDatabase, {
|
||||
type: type,
|
||||
eras: activeEras,
|
||||
ranges: activeRanges,
|
||||
});
|
||||
|
||||
if (unitBlueprint)
|
||||
this.spawnUnits(
|
||||
"GroundUnit",
|
||||
[
|
||||
{
|
||||
unitType: unitBlueprint.name,
|
||||
location: latlng,
|
||||
liveryID: "",
|
||||
skill: "High",
|
||||
},
|
||||
],
|
||||
coalitionArea.getCoalition(),
|
||||
false,
|
||||
"",
|
||||
""
|
||||
);
|
||||
}
|
||||
if (unitBlueprint)
|
||||
this.spawnUnits(
|
||||
"GroundUnit",
|
||||
[
|
||||
{
|
||||
unitType: unitBlueprint.name,
|
||||
location: latlng,
|
||||
liveryID: "",
|
||||
skill: "High",
|
||||
},
|
||||
],
|
||||
coalitionArea.getCoalition(),
|
||||
false,
|
||||
"",
|
||||
""
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/** Export all the ground and navy units to file. Does not work on Aircraft and Helicopter units.
|
||||
* TODO: Extend to aircraft and helicopters
|
||||
*/
|
||||
exportToFile() {
|
||||
if (!this.#unitDataExport)
|
||||
this.#unitDataExport = new UnitDataFileExport("unit-export-dialog");
|
||||
if (!this.#unitDataExport) this.#unitDataExport = new UnitDataFileExport("unit-export-dialog");
|
||||
this.#unitDataExport.showForm(Object.values(this.#units));
|
||||
}
|
||||
|
||||
@@ -1804,8 +1625,7 @@ export class UnitsManager {
|
||||
* TODO: extend to support aircraft and helicopters
|
||||
*/
|
||||
importFromFile() {
|
||||
if (!this.#unitDataImport)
|
||||
this.#unitDataImport = new UnitDataFileImport("unit-import-dialog");
|
||||
if (!this.#unitDataImport) this.#unitDataImport = new UnitDataFileImport("unit-import-dialog");
|
||||
this.#unitDataImport.selectFile();
|
||||
}
|
||||
|
||||
@@ -1834,8 +1654,7 @@ export class UnitsManager {
|
||||
var spawnsRestricted =
|
||||
getApp().getMissionManager().getCommandModeOptions().restrictSpawns &&
|
||||
getApp().getMissionManager().getRemainingSetupTime() < 0 &&
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode !==
|
||||
GAME_MASTER;
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode !== GAME_MASTER;
|
||||
|
||||
if (category === "Aircraft") {
|
||||
if (airbase == "" && spawnsRestricted) {
|
||||
@@ -1845,18 +1664,7 @@ export class UnitsManager {
|
||||
spawnPoints = units.reduce((points: number, unit: UnitSpawnTable) => {
|
||||
return points + aircraftDatabase.getSpawnPointsByName(unit.unitType);
|
||||
}, 0);
|
||||
spawnFunction = () =>
|
||||
getApp()
|
||||
.getServerManager()
|
||||
.spawnAircrafts(
|
||||
units,
|
||||
coalition,
|
||||
airbase,
|
||||
country,
|
||||
immediate,
|
||||
spawnPoints,
|
||||
callback
|
||||
);
|
||||
spawnFunction = () => getApp().getServerManager().spawnAircrafts(units, coalition, airbase, country, immediate, spawnPoints, callback);
|
||||
} else if (category === "Helicopter") {
|
||||
if (airbase == "" && spawnsRestricted) {
|
||||
//(getApp().getPopupsManager().get("infoPopup") as Popup).setText("Helicopters can be air spawned during the SETUP phase only");
|
||||
@@ -1865,18 +1673,7 @@ export class UnitsManager {
|
||||
spawnPoints = units.reduce((points: number, unit: UnitSpawnTable) => {
|
||||
return points + helicopterDatabase.getSpawnPointsByName(unit.unitType);
|
||||
}, 0);
|
||||
spawnFunction = () =>
|
||||
getApp()
|
||||
.getServerManager()
|
||||
.spawnHelicopters(
|
||||
units,
|
||||
coalition,
|
||||
airbase,
|
||||
country,
|
||||
immediate,
|
||||
spawnPoints,
|
||||
callback
|
||||
);
|
||||
spawnFunction = () => getApp().getServerManager().spawnHelicopters(units, coalition, airbase, country, immediate, spawnPoints, callback);
|
||||
} else if (category === "GroundUnit") {
|
||||
if (spawnsRestricted) {
|
||||
//(getApp().getPopupsManager().get("infoPopup") as Popup).setText("Ground units can be spawned during the SETUP phase only");
|
||||
@@ -1885,17 +1682,7 @@ export class UnitsManager {
|
||||
spawnPoints = units.reduce((points: number, unit: UnitSpawnTable) => {
|
||||
return points + groundUnitDatabase.getSpawnPointsByName(unit.unitType);
|
||||
}, 0);
|
||||
spawnFunction = () =>
|
||||
getApp()
|
||||
.getServerManager()
|
||||
.spawnGroundUnits(
|
||||
units,
|
||||
coalition,
|
||||
country,
|
||||
immediate,
|
||||
spawnPoints,
|
||||
callback
|
||||
);
|
||||
spawnFunction = () => getApp().getServerManager().spawnGroundUnits(units, coalition, country, immediate, spawnPoints, callback);
|
||||
} else if (category === "NavyUnit") {
|
||||
if (spawnsRestricted) {
|
||||
//(getApp().getPopupsManager().get("infoPopup") as Popup).setText("Navy units can be spawned during the SETUP phase only");
|
||||
@@ -1904,17 +1691,7 @@ export class UnitsManager {
|
||||
spawnPoints = units.reduce((points: number, unit: UnitSpawnTable) => {
|
||||
return points + navyUnitDatabase.getSpawnPointsByName(unit.unitType);
|
||||
}, 0);
|
||||
spawnFunction = () =>
|
||||
getApp()
|
||||
.getServerManager()
|
||||
.spawnNavyUnits(
|
||||
units,
|
||||
coalition,
|
||||
country,
|
||||
immediate,
|
||||
spawnPoints,
|
||||
callback
|
||||
);
|
||||
spawnFunction = () => getApp().getServerManager().spawnNavyUnits(units, coalition, country, immediate, spawnPoints, callback);
|
||||
}
|
||||
|
||||
if (spawnPoints <= getApp().getMissionManager().getAvailableSpawnPoints()) {
|
||||
@@ -2033,9 +1810,7 @@ export class UnitsManager {
|
||||
const map = getApp().getMap();
|
||||
const units = this.getSelectedUnits();
|
||||
const numSelectedUnits = units.length;
|
||||
const numProtectedUnits = units.filter((unit: Unit) =>
|
||||
map.getIsUnitProtected(unit)
|
||||
).length;
|
||||
const numProtectedUnits = units.filter((unit: Unit) => map.getIsUnitProtected(unit)).length;
|
||||
|
||||
//if (numProtectedUnits === 1 && numSelectedUnits === numProtectedUnits)
|
||||
//(getApp().getPopupsManager().get("infoPopup") as Popup).setText(`Notice: unit is protected`);
|
||||
|
||||
@@ -1,23 +1,9 @@
|
||||
import { LatLng, DivIcon, Map } from "leaflet";
|
||||
import { getApp } from "../olympusapp";
|
||||
import {
|
||||
enumToCoalition,
|
||||
mToFt,
|
||||
msToKnots,
|
||||
rad2deg,
|
||||
zeroAppend,
|
||||
} from "../other/utils";
|
||||
import { enumToCoalition, mToFt, msToKnots, rad2deg, zeroAppend } from "../other/utils";
|
||||
import { CustomMarker } from "../map/markers/custommarker";
|
||||
import { SVGInjector } from "@tanem/svg-injector";
|
||||
import {
|
||||
DLINK,
|
||||
DataIndexes,
|
||||
GAME_MASTER,
|
||||
IRST,
|
||||
OPTIC,
|
||||
RADAR,
|
||||
VISUAL,
|
||||
} from "../constants/constants";
|
||||
import { DLINK, DataIndexes, GAME_MASTER, IRST, OPTIC, RADAR, VISUAL } from "../constants/constants";
|
||||
import { DataExtractor } from "../server/dataextractor";
|
||||
import { ObjectIconOptions } from "../interfaces";
|
||||
|
||||
@@ -153,8 +139,7 @@ export class Weapon extends CustomMarker {
|
||||
|
||||
belongsToCommandedCoalition() {
|
||||
if (
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode !==
|
||||
GAME_MASTER &&
|
||||
getApp().getMissionManager().getCommandModeOptions().commandMode !== GAME_MASTER &&
|
||||
getApp().getMissionManager().getCommandedCoalition() !== this.#coalition
|
||||
)
|
||||
return false;
|
||||
@@ -197,10 +182,7 @@ export class Weapon extends CustomMarker {
|
||||
img.src = `/vite/images/units/${this.getMarkerCategory()}.svg`;
|
||||
img.onload = () => SVGInjector(img);
|
||||
unitIcon.appendChild(img);
|
||||
unitIcon.toggleAttribute(
|
||||
"data-rotate-to-heading",
|
||||
this.getIconOptions().rotateToHeading
|
||||
);
|
||||
unitIcon.toggleAttribute("data-rotate-to-heading", this.getIconOptions().rotateToHeading);
|
||||
el.append(unitIcon);
|
||||
}
|
||||
|
||||
@@ -211,10 +193,7 @@ export class Weapon extends CustomMarker {
|
||||
updateVisibility() {
|
||||
const hiddenUnits = getApp().getMap().getHiddenTypes();
|
||||
var hidden =
|
||||
hiddenUnits[this.getMarkerCategory()] ||
|
||||
hiddenUnits[this.#coalition] ||
|
||||
(!this.belongsToCommandedCoalition() &&
|
||||
this.#detectionMethods.length == 0);
|
||||
hiddenUnits[this.getMarkerCategory()] || hiddenUnits[this.#coalition] || (!this.belongsToCommandedCoalition() && this.#detectionMethods.length == 0);
|
||||
|
||||
this.setHidden(hidden || !this.#alive);
|
||||
}
|
||||
@@ -244,12 +223,7 @@ export class Weapon extends CustomMarker {
|
||||
setDetectionMethods(newDetectionMethods: number[]) {
|
||||
if (!this.belongsToCommandedCoalition()) {
|
||||
/* Check if the detection methods of this unit have changed */
|
||||
if (
|
||||
this.#detectionMethods.length !== newDetectionMethods.length ||
|
||||
this.getDetectionMethods().some(
|
||||
(value) => !newDetectionMethods.includes(value)
|
||||
)
|
||||
) {
|
||||
if (this.#detectionMethods.length !== newDetectionMethods.length || this.getDetectionMethods().some((value) => !newDetectionMethods.includes(value))) {
|
||||
/* Force a redraw of the unit to reflect the new status of the detection methods */
|
||||
this.setHidden(true);
|
||||
this.#detectionMethods = newDetectionMethods;
|
||||
@@ -273,53 +247,35 @@ export class Weapon extends CustomMarker {
|
||||
|
||||
/* Draw the marker */
|
||||
if (!this.getHidden()) {
|
||||
if (
|
||||
this.getLatLng().lat !== this.#position.lat ||
|
||||
this.getLatLng().lng !== this.#position.lng
|
||||
) {
|
||||
if (this.getLatLng().lat !== this.#position.lat || this.getLatLng().lng !== this.#position.lng) {
|
||||
this.setLatLng(new LatLng(this.#position.lat, this.#position.lng));
|
||||
}
|
||||
|
||||
var element = this.getElement();
|
||||
if (element != null) {
|
||||
/* Draw the velocity vector */
|
||||
element
|
||||
.querySelector(".unit-vvi")
|
||||
?.setAttribute("style", `height: ${15 + this.#speed / 5}px;`);
|
||||
element.querySelector(".unit-vvi")?.setAttribute("style", `height: ${15 + this.#speed / 5}px;`);
|
||||
|
||||
/* Set dead/alive flag */
|
||||
element
|
||||
.querySelector(".unit")
|
||||
?.toggleAttribute("data-is-dead", !this.#alive);
|
||||
element.querySelector(".unit")?.toggleAttribute("data-is-dead", !this.#alive);
|
||||
|
||||
/* Set altitude and speed */
|
||||
if (element.querySelector(".unit-altitude"))
|
||||
(<HTMLElement>element.querySelector(".unit-altitude")).innerText =
|
||||
"FL" +
|
||||
zeroAppend(
|
||||
Math.floor(mToFt(this.#position.alt as number) / 100),
|
||||
3
|
||||
);
|
||||
(<HTMLElement>element.querySelector(".unit-altitude")).innerText = "FL" + zeroAppend(Math.floor(mToFt(this.#position.alt as number) / 100), 3);
|
||||
if (element.querySelector(".unit-speed"))
|
||||
(<HTMLElement>element.querySelector(".unit-speed")).innerText =
|
||||
String(Math.floor(msToKnots(this.#speed))) + "GS";
|
||||
(<HTMLElement>element.querySelector(".unit-speed")).innerText = String(Math.floor(msToKnots(this.#speed))) + "GS";
|
||||
|
||||
/* Rotate elements according to heading */
|
||||
element.querySelectorAll("[data-rotate-to-heading]").forEach((el) => {
|
||||
const headingDeg = rad2deg(this.#heading);
|
||||
let currentStyle = el.getAttribute("style") || "";
|
||||
el.setAttribute(
|
||||
"style",
|
||||
currentStyle + `transform:rotate(${headingDeg}deg);`
|
||||
);
|
||||
el.setAttribute("style", currentStyle + `transform:rotate(${headingDeg}deg);`);
|
||||
});
|
||||
}
|
||||
|
||||
/* Set vertical offset for altitude stacking */
|
||||
var pos = getApp().getMap().latLngToLayerPoint(this.getLatLng()).round();
|
||||
this.setZIndexOffset(
|
||||
1000 + Math.floor(this.#position.alt as number) - pos.y
|
||||
);
|
||||
this.setZIndexOffset(1000 + Math.floor(this.#position.alt as number) - pos.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -334,12 +290,7 @@ export class Missile extends Weapon {
|
||||
}
|
||||
|
||||
getMarkerCategory() {
|
||||
if (
|
||||
this.belongsToCommandedCoalition() ||
|
||||
this.getDetectionMethods().includes(VISUAL) ||
|
||||
this.getDetectionMethods().includes(OPTIC)
|
||||
)
|
||||
return "missile";
|
||||
if (this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC)) return "missile";
|
||||
else return "aircraft";
|
||||
}
|
||||
|
||||
@@ -348,35 +299,20 @@ export class Missile extends Weapon {
|
||||
showState: false,
|
||||
showVvi:
|
||||
!this.belongsToCommandedCoalition() &&
|
||||
!this.getDetectionMethods().some((value) =>
|
||||
[VISUAL, OPTIC].includes(value)
|
||||
) &&
|
||||
this.getDetectionMethods().some((value) =>
|
||||
[RADAR, IRST, DLINK].includes(value)
|
||||
),
|
||||
!this.getDetectionMethods().some((value) => [VISUAL, OPTIC].includes(value)) &&
|
||||
this.getDetectionMethods().some((value) => [RADAR, IRST, DLINK].includes(value)),
|
||||
showHealth: false,
|
||||
showHotgroup: false,
|
||||
showUnitIcon:
|
||||
this.belongsToCommandedCoalition() ||
|
||||
this.getDetectionMethods().some((value) =>
|
||||
[VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value)
|
||||
),
|
||||
showUnitIcon: this.belongsToCommandedCoalition() || this.getDetectionMethods().some((value) => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value)),
|
||||
showShortLabel: false,
|
||||
showFuel: false,
|
||||
showAmmo: false,
|
||||
showSummary:
|
||||
!this.belongsToCommandedCoalition() &&
|
||||
!this.getDetectionMethods().some((value) =>
|
||||
[VISUAL, OPTIC].includes(value)
|
||||
) &&
|
||||
this.getDetectionMethods().some((value) =>
|
||||
[RADAR, IRST, DLINK].includes(value)
|
||||
),
|
||||
!this.getDetectionMethods().some((value) => [VISUAL, OPTIC].includes(value)) &&
|
||||
this.getDetectionMethods().some((value) => [RADAR, IRST, DLINK].includes(value)),
|
||||
showCallsign: false,
|
||||
rotateToHeading:
|
||||
this.belongsToCommandedCoalition() ||
|
||||
this.getDetectionMethods().includes(VISUAL) ||
|
||||
this.getDetectionMethods().includes(OPTIC),
|
||||
rotateToHeading: this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -391,12 +327,7 @@ export class Bomb extends Weapon {
|
||||
}
|
||||
|
||||
getMarkerCategory() {
|
||||
if (
|
||||
this.belongsToCommandedCoalition() ||
|
||||
this.getDetectionMethods().includes(VISUAL) ||
|
||||
this.getDetectionMethods().includes(OPTIC)
|
||||
)
|
||||
return "bomb";
|
||||
if (this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC)) return "bomb";
|
||||
else return "aircraft";
|
||||
}
|
||||
|
||||
@@ -405,35 +336,20 @@ export class Bomb extends Weapon {
|
||||
showState: false,
|
||||
showVvi:
|
||||
!this.belongsToCommandedCoalition() &&
|
||||
!this.getDetectionMethods().some((value) =>
|
||||
[VISUAL, OPTIC].includes(value)
|
||||
) &&
|
||||
this.getDetectionMethods().some((value) =>
|
||||
[RADAR, IRST, DLINK].includes(value)
|
||||
),
|
||||
!this.getDetectionMethods().some((value) => [VISUAL, OPTIC].includes(value)) &&
|
||||
this.getDetectionMethods().some((value) => [RADAR, IRST, DLINK].includes(value)),
|
||||
showHealth: false,
|
||||
showHotgroup: false,
|
||||
showUnitIcon:
|
||||
this.belongsToCommandedCoalition() ||
|
||||
this.getDetectionMethods().some((value) =>
|
||||
[VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value)
|
||||
),
|
||||
showUnitIcon: this.belongsToCommandedCoalition() || this.getDetectionMethods().some((value) => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value)),
|
||||
showShortLabel: false,
|
||||
showFuel: false,
|
||||
showAmmo: false,
|
||||
showSummary:
|
||||
!this.belongsToCommandedCoalition() &&
|
||||
!this.getDetectionMethods().some((value) =>
|
||||
[VISUAL, OPTIC].includes(value)
|
||||
) &&
|
||||
this.getDetectionMethods().some((value) =>
|
||||
[RADAR, IRST, DLINK].includes(value)
|
||||
),
|
||||
!this.getDetectionMethods().some((value) => [VISUAL, OPTIC].includes(value)) &&
|
||||
this.getDetectionMethods().some((value) => [RADAR, IRST, DLINK].includes(value)),
|
||||
showCallsign: false,
|
||||
rotateToHeading:
|
||||
this.belongsToCommandedCoalition() ||
|
||||
this.getDetectionMethods().includes(VISUAL) ||
|
||||
this.getDetectionMethods().includes(OPTIC),
|
||||
rotateToHeading: this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,7 @@ export class WeaponsManager {
|
||||
this.#weapons = {};
|
||||
|
||||
document.addEventListener("commandModeOptionsChanged", () => {
|
||||
Object.values(this.#weapons).forEach((weapon: Weapon) =>
|
||||
weapon.updateVisibility()
|
||||
);
|
||||
Object.values(this.#weapons).forEach((weapon: Weapon) => weapon.updateVisibility());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -96,18 +94,9 @@ export class WeaponsManager {
|
||||
var detectionMethods: number[] = [];
|
||||
var units = getApp().getUnitsManager().getUnits();
|
||||
for (let idx in units) {
|
||||
if (
|
||||
units[idx].getAlive() &&
|
||||
units[idx].getIsLeader() &&
|
||||
units[idx].getCoalition() !== "neutral" &&
|
||||
units[idx].getCoalition() != weapon.getCoalition()
|
||||
) {
|
||||
if (units[idx].getAlive() && units[idx].getIsLeader() && units[idx].getCoalition() !== "neutral" && units[idx].getCoalition() != weapon.getCoalition()) {
|
||||
units[idx].getContacts().forEach((contact: Contact) => {
|
||||
if (
|
||||
contact.ID == weapon.ID &&
|
||||
!detectionMethods.includes(contact.detectionMethod)
|
||||
)
|
||||
detectionMethods.push(contact.detectionMethod);
|
||||
if (contact.ID == weapon.ID && !detectionMethods.includes(contact.detectionMethod)) detectionMethods.push(contact.detectionMethod);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user