Merge branch 'main' into 485-improve-miss-on-purpose
@ -605,6 +605,12 @@ nav.ol-panel> :last-child {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ol-navbar-buttons-group > div {
|
||||
align-items: center;
|
||||
display:flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.ol-navbar-buttons-group button {
|
||||
border: none;
|
||||
height: 32px;
|
||||
@ -638,6 +644,47 @@ nav.ol-panel> :last-child {
|
||||
stroke: var(--background-steel) !important;
|
||||
}
|
||||
|
||||
.ol-navbar-buttons-group .protectable button:first-of-type {
|
||||
border-bottom-right-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
width:28px;
|
||||
}
|
||||
|
||||
.ol-navbar-buttons-group > .protectable > button.lock {
|
||||
align-items: center;
|
||||
background-color: var(--primary-red);
|
||||
border-bottom-left-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
display:flex;
|
||||
justify-content: center;
|
||||
width:18px;
|
||||
}
|
||||
|
||||
.ol-navbar-buttons-group > .protectable > button[data-protected].lock {
|
||||
background-color: var(--background-grey);
|
||||
}
|
||||
|
||||
.ol-navbar-buttons-group > .protectable > button.lock svg {
|
||||
height:10px;
|
||||
width:10px;
|
||||
}
|
||||
|
||||
.ol-navbar-buttons-group > .protectable > button.lock svg.locked {
|
||||
filter:invert(100);
|
||||
}
|
||||
|
||||
.ol-navbar-buttons-group > .protectable > button:not([data-protected]).lock svg.unlocked,
|
||||
.ol-navbar-buttons-group > .protectable > button[data-protected].lock svg.locked {
|
||||
display:flex;
|
||||
}
|
||||
|
||||
.ol-navbar-buttons-group > .protectable > button[data-protected].lock svg.unlocked,
|
||||
.ol-navbar-buttons-group > .protectable > button:not([data-protected]).lock svg.locked {
|
||||
display:none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#roe-buttons-container button,
|
||||
#reaction-to-threat-buttons-container button,
|
||||
#emissions-countermeasures-buttons-container button,
|
||||
@ -707,7 +754,6 @@ nav.ol-panel> :last-child {
|
||||
|
||||
@media (min-width: 1700px) {
|
||||
#splash-screen {
|
||||
background-image: url("/resources/theme/images/splash/1.png");
|
||||
background-position: 100% 50%;
|
||||
background-size: contain;
|
||||
}
|
||||
@ -739,7 +785,7 @@ nav.ol-panel> :last-child {
|
||||
top: 0;
|
||||
transform: rotate(-23deg);
|
||||
transform-origin: top right;
|
||||
width: 200px;
|
||||
width: 300px;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M352 144c0-44.2 35.8-80 80-80s80 35.8 80 80v48c0 17.7 14.3 32 32 32s32-14.3 32-32V144C576 64.5 511.5 0 432 0S288 64.5 288 144v48H64c-35.3 0-64 28.7-64 64V448c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V256c0-35.3-28.7-64-64-64H352V144z"/></svg>
|
||||
|
After Width: | Height: | Size: 485 B |
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M144 144v48H304V144c0-44.2-35.8-80-80-80s-80 35.8-80 80zM80 192V144C80 64.5 144.5 0 224 0s144 64.5 144 144v48h16c35.3 0 64 28.7 64 64V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V256c0-35.3 28.7-64 64-64H80z"/></svg>
|
||||
|
After Width: | Height: | Size: 460 B |
BIN
client/public/themes/olympus/images/splash/1.jpg
Normal file
|
After Width: | Height: | Size: 232 KiB |
BIN
client/public/themes/olympus/images/splash/2.jpg
Normal file
|
After Width: | Height: | Size: 520 KiB |
BIN
client/public/themes/olympus/images/splash/3.jpg
Normal file
|
After Width: | Height: | Size: 430 KiB |
BIN
client/public/themes/olympus/images/splash/4.jpg
Normal file
|
After Width: | Height: | Size: 459 KiB |
BIN
client/public/themes/olympus/images/splash/5.jpg
Normal file
|
After Width: | Height: | Size: 364 KiB |
BIN
client/public/themes/olympus/images/splash/6.jpg
Normal file
|
After Width: | Height: | Size: 185 KiB |
BIN
client/public/themes/olympus/images/splash/7.jpg
Normal file
|
After Width: | Height: | Size: 575 KiB |
BIN
client/public/themes/olympus/images/splash/8.jpg
Normal file
|
After Width: | Height: | Size: 379 KiB |
@ -1,4 +1,5 @@
|
||||
import { LatLng, LatLngBounds } from "leaflet";
|
||||
import { MapMarkerControl } from "../map/map";
|
||||
|
||||
export const UNITS_URI = "units";
|
||||
export const WEAPONS_URI = "weapons";
|
||||
@ -117,25 +118,25 @@ export const mapLayers = {
|
||||
"ArcGIS Satellite": {
|
||||
urlTemplate: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
|
||||
minZoom: 1,
|
||||
maxZoom: 16,
|
||||
maxZoom: 18,
|
||||
attribution: "Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, GetApp().getMap()ping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community"
|
||||
},
|
||||
"USGS Topo": {
|
||||
urlTemplate: 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile/{z}/{y}/{x}',
|
||||
minZoom: 1,
|
||||
maxZoom: 16,
|
||||
maxZoom: 18,
|
||||
attribution: 'Tiles courtesy of the <a href="https://usgs.gov/">U.S. Geological Survey</a>'
|
||||
},
|
||||
"OpenStreetMap Mapnik": {
|
||||
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
minZoom: 1,
|
||||
maxZoom: 16,
|
||||
maxZoom: 18,
|
||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
},
|
||||
"OPENVKarte": {
|
||||
urlTemplate: 'https://tileserver.memomaps.de/tilegen/{z}/{x}/{y}.png',
|
||||
minZoom: 1,
|
||||
maxZoom: 16,
|
||||
maxZoom: 18,
|
||||
attribution: 'Map <a href="https://memomaps.de/">memomaps.de</a> <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, map data © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
},
|
||||
"Esri.DeLorme": {
|
||||
@ -147,7 +148,7 @@ export const mapLayers = {
|
||||
"CyclOSM": {
|
||||
urlTemplate: 'https://{s}.tile-cyclosm.openstreetmap.fr/cyclosm/{z}/{x}/{y}.png',
|
||||
minZoom: 1,
|
||||
maxZoom: 16,
|
||||
maxZoom: 18,
|
||||
attribution: '<a href="https://github.com/cyclosm/cyclosm-cartocss-style/releases" title="CyclOSM - Open Bicycle render">CyclOSM</a> | Map data: © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
}
|
||||
}
|
||||
@ -159,6 +160,49 @@ export const COALITIONAREA_DRAW_POLYGON = "Draw Coalition Area";
|
||||
export const visibilityControls: string[] = ["human", "dcs", "aircraft", "helicopter", "groundunit-sam", "groundunit-other", "navyunit", "airbase"];
|
||||
export const visibilityControlsTypes: string[][] = [["human"], ["dcs"], ["aircraft"], ["helicopter"], ["groundunit-sam", "groundunit-sam-radar", "groundunit-sam-launcher"], ["groundunit-other", "groundunit-ewr"], ["navyunit"], ["airbase"]];
|
||||
export const visibilityControlsTooltips: string[] = ["Toggle human players visibility", "Toggle DCS controlled units visibility", "Toggle aircrafts visibility", "Toggle helicopter visibility", "Toggle SAM units visibility", "Toggle ground units (not SAM) visibility", "Toggle navy units visibility", "Toggle airbases visibility"];
|
||||
export const MAP_MARKER_CONTROLS:MapMarkerControl[] = [{
|
||||
"name":"Human",
|
||||
"image": "visibility/human.svg",
|
||||
"toggles": [ "human" ],
|
||||
"tooltip": "Toggle human players' visibility"
|
||||
}, {
|
||||
"image": "visibility/dcs.svg",
|
||||
"isProtected": true,
|
||||
"name":"DCS",
|
||||
"protectable": true,
|
||||
"toggles": [ "dcs" ],
|
||||
"tooltip": "Toggle DCS-controlled units' visibility"
|
||||
}, {
|
||||
"image": "visibility/aircraft.svg",
|
||||
"name":"Aircraft",
|
||||
"toggles": [ "aircraft" ],
|
||||
"tooltip": "Toggle aircraft's visibility"
|
||||
}, {
|
||||
"image": "visibility/helicopter.svg",
|
||||
"name":"Helicopter",
|
||||
"toggles": [ "helicopter" ],
|
||||
"tooltip": "Toggle helicopters' visibility"
|
||||
}, {
|
||||
"image": "visibility/groundunit-sam.svg",
|
||||
"name":"Air defence",
|
||||
"toggles": [ "groundunit-sam" ],
|
||||
"tooltip": "Toggle air defence units' visibility"
|
||||
}, {
|
||||
"image": "visibility/groundunit-other.svg",
|
||||
"name":"Ground units",
|
||||
"toggles": [ "groundunit-other" ],
|
||||
"tooltip": "Toggle ground units' visibility"
|
||||
}, {
|
||||
"image": "visibility/navyunit.svg",
|
||||
"name":"Naval",
|
||||
"toggles": [ "navyunit" ],
|
||||
"tooltip": "Toggle naval units' visibility"
|
||||
}, {
|
||||
"image": "visibility/airbase.svg",
|
||||
"name":"Airbase",
|
||||
"toggles": [ "airbase" ],
|
||||
"tooltip": "Toggle airbase' visibility"
|
||||
}];
|
||||
|
||||
export const IADSTypes = ["AAA", "MANPADS", "SAM Site", "Radar"];
|
||||
export const IADSDensities: {[key: string]: number}= {"AAA": 0.8, "MANPADS": 0.3, "SAM Site": 0.1, "Radar": 0.05};
|
||||
|
||||
11
client/src/context/context.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export interface ContextInterface {
|
||||
|
||||
}
|
||||
|
||||
export class Context {
|
||||
|
||||
constructor( config:ContextInterface ) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
43
client/src/context/contextmanager.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { Manager } from "../other/manager";
|
||||
import { Context, ContextInterface } from "./context";
|
||||
|
||||
export class ContextManager extends Manager {
|
||||
|
||||
#currentContext!:string;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
add( name:string, contextConfig:ContextInterface ) {
|
||||
super.add( name, new Context( contextConfig ) );
|
||||
|
||||
if ( Object.values( this.getAll() ).length === 1 ) {
|
||||
this.#currentContext = name;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
currentContextIs( contextName:string ) {
|
||||
return contextName === this.#currentContext;
|
||||
}
|
||||
|
||||
getCurrentContext() {
|
||||
const contexts = this.getAll();
|
||||
|
||||
return ( contexts.hasOwnProperty( this.#currentContext ) ) ? contexts[this.#currentContext] : false;
|
||||
}
|
||||
|
||||
setContext( contextName:string ) {
|
||||
|
||||
if ( !this.get( contextName ) ) {
|
||||
console.error( `setContext(): context name "${contextName}" does not exist.` );
|
||||
return false;
|
||||
}
|
||||
this.#currentContext = contextName;
|
||||
|
||||
console.log( `Setting context to "${this.#currentContext}".` );
|
||||
}
|
||||
|
||||
}
|
||||
15
client/src/context/contextmenumanager.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { ContextMenu } from "../contextmenus/contextmenu";
|
||||
import { Manager } from "../other/manager";
|
||||
|
||||
export class ContextMenuManager extends Manager {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
add( name:string, contextMenu:ContextMenu ) {
|
||||
super.add( name, contextMenu );
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@ -272,6 +272,7 @@ export interface Listener {
|
||||
export interface ShortcutOptions {
|
||||
altKey?: boolean;
|
||||
callback: CallableFunction;
|
||||
context?: string;
|
||||
ctrlKey?: boolean;
|
||||
name?: string;
|
||||
shiftKey?: boolean;
|
||||
|
||||
@ -12,7 +12,7 @@ import { DestinationPreviewMarker } from "./markers/destinationpreviewmarker";
|
||||
import { TemporaryUnitMarker } from "./markers/temporaryunitmarker";
|
||||
import { ClickableMiniMap } from "./clickableminimap";
|
||||
import { SVGInjector } from '@tanem/svg-injector'
|
||||
import { mapLayers, mapBounds, minimapBoundaries, IDLE, COALITIONAREA_DRAW_POLYGON, visibilityControls, visibilityControlsTooltips, MOVE_UNIT, SHOW_UNIT_CONTACTS, HIDE_GROUP_MEMBERS, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, visibilityControlsTypes, SHOW_UNIT_LABELS, SHOW_UNITS_ENGAGEMENT_RINGS, SHOW_UNITS_ACQUISITION_RINGS, HIDE_UNITS_SHORT_RANGE_RINGS, FILL_SELECTED_RING } from "../constants/constants";
|
||||
import { mapLayers, mapBounds, minimapBoundaries, IDLE, COALITIONAREA_DRAW_POLYGON, visibilityControls, visibilityControlsTooltips, MOVE_UNIT, SHOW_UNIT_CONTACTS, HIDE_GROUP_MEMBERS, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, visibilityControlsTypes, SHOW_UNIT_LABELS, SHOW_UNITS_ENGAGEMENT_RINGS, SHOW_UNITS_ACQUISITION_RINGS, HIDE_UNITS_SHORT_RANGE_RINGS, FILL_SELECTED_RING, MAP_MARKER_CONTROLS } from "../constants/constants";
|
||||
import { TargetMarker } from "./markers/targetmarker";
|
||||
import { CoalitionArea } from "./coalitionarea/coalitionarea";
|
||||
import { CoalitionAreaContextMenu } from "../contextmenus/coalitionareacontextmenu";
|
||||
@ -38,6 +38,15 @@ L.Map.addInitHook("addHandler", "gestureHandling", GestureHandling);
|
||||
require("../../public/javascripts/leaflet.nauticscale.js")
|
||||
require("../../public/javascripts/L.Path.Drag.js")
|
||||
|
||||
export type MapMarkerControl = {
|
||||
"image": string;
|
||||
"isProtected"?: boolean,
|
||||
"name":string,
|
||||
"protectable"?: boolean,
|
||||
"toggles": string[],
|
||||
"tooltip": string
|
||||
}
|
||||
|
||||
export class Map extends L.Map {
|
||||
#ID: string;
|
||||
#state: string;
|
||||
@ -80,6 +89,7 @@ export class Map extends L.Map {
|
||||
#coalitionAreaContextMenu: CoalitionAreaContextMenu = new CoalitionAreaContextMenu("coalition-area-contextmenu");
|
||||
|
||||
#mapSourceDropdown: Dropdown;
|
||||
#mapMarkerControls:MapMarkerControl[] = MAP_MARKER_CONTROLS;
|
||||
#mapVisibilityOptionsDropdown: Dropdown;
|
||||
#optionButtons: { [key: string]: HTMLButtonElement[] } = {}
|
||||
#visibilityOptions: { [key: string]: boolean } = {}
|
||||
@ -201,12 +211,7 @@ export class Map extends L.Map {
|
||||
}, 20);
|
||||
|
||||
/* Option buttons */
|
||||
this.#optionButtons["visibility"] = visibilityControls.map((option: string, index: number) => {
|
||||
var typesArrayString = `"${visibilityControlsTypes[index][0]}"`;
|
||||
visibilityControlsTypes[index].forEach((type: string, idx: number) => { if (idx > 0) typesArrayString = `${typesArrayString}, "${type}"` });
|
||||
return this.#createOptionButton(option, `visibility/${option.toLowerCase()}.svg`, visibilityControlsTooltips[index], "toggleMarkerVisibility", `{"types": [${typesArrayString}]}`);
|
||||
});
|
||||
document.querySelector("#unit-visibility-control")?.append(...this.#optionButtons["visibility"]);
|
||||
this.#createUnitMarkerControlButtons();
|
||||
|
||||
/* Create the checkboxes to select the advanced visibility options */
|
||||
this.addVisibilityOption(SHOW_UNIT_CONTACTS, false);
|
||||
@ -608,16 +613,16 @@ export class Map extends L.Map {
|
||||
const selectedUnitTypes = getApp().getUnitsManager().getSelectedUnitsCategories();
|
||||
|
||||
if (selectedUnitTypes.length === 1 && ["Aircraft", "Helicopter"].includes(selectedUnitTypes[0])) {
|
||||
if (selectedUnitTypes[0] === "Helicopter") {
|
||||
if (selectedUnits.every((unit: Unit) => { return unit.canLandAtPoint()}))
|
||||
options["land-at-point"] = { text: "Land here", tooltip: "Land at this precise location" };
|
||||
}
|
||||
|
||||
if (selectedUnits.every((unit: Unit) => { return unit.canTargetPoint()})) {
|
||||
options["bomb"] = { text: "Precision bombing", tooltip: "Precision bombing of a specific point" };
|
||||
options["carpet-bomb"] = { text: "Carpet bombing", tooltip: "Carpet bombing close to a point" };
|
||||
} else {
|
||||
}
|
||||
|
||||
if (Object.keys(options).length === 0)
|
||||
(getApp().getPopupsManager().get("infoPopup") as Popup).setText(`Selected units can not perform point actions.`);
|
||||
}
|
||||
}
|
||||
else if (selectedUnitTypes.length === 1 && ["GroundUnit", "NavyUnit"].includes(selectedUnitTypes[0])) {
|
||||
if (selectedUnits.every((unit: Unit) => { return unit.canTargetPoint() })) {
|
||||
@ -724,17 +729,62 @@ export class Map extends L.Map {
|
||||
return minimapBoundaries;
|
||||
}
|
||||
|
||||
#createOptionButton(value: string, url: string, title: string, callback: string, argument: string) {
|
||||
var button = document.createElement("button");
|
||||
const img = document.createElement("img");
|
||||
img.src = `/resources/theme/images/buttons/${url}`;
|
||||
img.onload = () => SVGInjector(img);
|
||||
button.title = title;
|
||||
button.value = value;
|
||||
button.appendChild(img);
|
||||
button.setAttribute("data-on-click", callback);
|
||||
button.setAttribute("data-on-click-params", argument);
|
||||
return button;
|
||||
#createUnitMarkerControlButtons() {
|
||||
const unitVisibilityControls = <HTMLElement>document.getElementById("unit-visibility-control");
|
||||
const makeTitle = (isProtected:boolean) => {
|
||||
return ( isProtected ) ? "Unit type is protected and will ignore orders" : "Unit is NOT protected and will respond to orders";
|
||||
}
|
||||
this.#mapMarkerControls.forEach( (control:MapMarkerControl) => {
|
||||
const toggles = `["${control.toggles.join('","')}"]`;
|
||||
const div = document.createElement("div");
|
||||
div.className = control.protectable === true ? "protectable" : "";
|
||||
div.innerHTML = `
|
||||
<button data-on-click="toggleMarkerVisibility" title="${control.tooltip}" data-on-click-params='{"types":${toggles}}'>
|
||||
<img src="/resources/theme/images/buttons/${control.image}" />
|
||||
</button>
|
||||
`;
|
||||
unitVisibilityControls.appendChild(div);
|
||||
|
||||
if ( control.protectable ) {
|
||||
div.innerHTML += `
|
||||
<button class="lock" ${control.isProtected ? "data-protected" : ""} title="${makeTitle(control.isProtected || false)}">
|
||||
<img src="/resources/theme/images/buttons/other/lock-solid.svg" class="locked" />
|
||||
<img src="/resources/theme/images/buttons/other/lock-open-solid.svg" class="unlocked" />
|
||||
</button>`;
|
||||
|
||||
const btn = <HTMLButtonElement>div.querySelector("button.lock");
|
||||
btn.addEventListener("click", (ev:MouseEventInit) => {
|
||||
control.isProtected = !control.isProtected;
|
||||
btn.toggleAttribute("data-protected", control.isProtected);
|
||||
btn.title = makeTitle( control.isProtected );
|
||||
document.dispatchEvent(new CustomEvent("toggleMarkerProtection", {
|
||||
detail: {
|
||||
"_element": btn,
|
||||
"control": control
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
unitVisibilityControls.querySelectorAll(`img[src$=".svg"]`).forEach(img => SVGInjector(img));
|
||||
}
|
||||
|
||||
unitIsProtected(unit:Unit) {
|
||||
const toggles = this.#mapMarkerControls.reduce((list, control:MapMarkerControl) => {
|
||||
if (control.isProtected) {
|
||||
list = list.concat(control.toggles);
|
||||
}
|
||||
return list;
|
||||
}, [] as string[]);
|
||||
|
||||
if (toggles.length === 0)
|
||||
return false;
|
||||
|
||||
return toggles.some((toggle:string) => {
|
||||
// Specific coding for robots - extend later if needed
|
||||
return (toggle === "dcs" && !unit.getControlled() && !unit.getHuman());
|
||||
});
|
||||
}
|
||||
|
||||
#deselectCoalitionAreas() {
|
||||
@ -753,37 +803,35 @@ export class Map extends L.Map {
|
||||
#showDestinationCursors() {
|
||||
const singleCursor = !this.#shiftKey;
|
||||
const selectedUnitsCount = getApp().getUnitsManager().getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true }).length;
|
||||
if (selectedUnitsCount > 0) {
|
||||
if (singleCursor) {
|
||||
if ( this.#destinationPreviewCursors.length != 1) {
|
||||
this.#hideDestinationCursors();
|
||||
var marker = new DestinationPreviewMarker(this.getMouseCoordinates(), { interactive: false });
|
||||
marker.addTo(this);
|
||||
this.#destinationPreviewCursors = [marker];
|
||||
}
|
||||
|
||||
this.#destinationPreviewHandleLine.removeFrom(this);
|
||||
this.#destinationPreviewHandle.removeFrom(this);
|
||||
if (singleCursor) {
|
||||
if ( this.#destinationPreviewCursors.length != 1) {
|
||||
this.#hideDestinationCursors();
|
||||
var marker = new DestinationPreviewMarker(this.getMouseCoordinates(), { interactive: false });
|
||||
marker.addTo(this);
|
||||
this.#destinationPreviewCursors = [marker];
|
||||
}
|
||||
else if (!singleCursor) {
|
||||
while (this.#destinationPreviewCursors.length > selectedUnitsCount) {
|
||||
this.removeLayer(this.#destinationPreviewCursors[0]);
|
||||
this.#destinationPreviewCursors.splice(0, 1);
|
||||
}
|
||||
|
||||
this.#destinationPreviewHandleLine.addTo(this);
|
||||
this.#destinationPreviewHandle.addTo(this);
|
||||
|
||||
while (this.#destinationPreviewCursors.length < selectedUnitsCount) {
|
||||
var cursor = new DestinationPreviewMarker(this.getMouseCoordinates(), { interactive: false });
|
||||
cursor.addTo(this);
|
||||
this.#destinationPreviewCursors.push(cursor);
|
||||
}
|
||||
|
||||
this.#updateDestinationCursors();
|
||||
}
|
||||
this.#destinationPreviewHandleLine.removeFrom(this);
|
||||
this.#destinationPreviewHandle.removeFrom(this);
|
||||
}
|
||||
}
|
||||
else if (!singleCursor) {
|
||||
while (this.#destinationPreviewCursors.length > selectedUnitsCount) {
|
||||
this.removeLayer(this.#destinationPreviewCursors[0]);
|
||||
this.#destinationPreviewCursors.splice(0, 1);
|
||||
}
|
||||
|
||||
this.#destinationPreviewHandleLine.addTo(this);
|
||||
this.#destinationPreviewHandle.addTo(this);
|
||||
|
||||
while (this.#destinationPreviewCursors.length < selectedUnitsCount) {
|
||||
var cursor = new DestinationPreviewMarker(this.getMouseCoordinates(), { interactive: false });
|
||||
cursor.addTo(this);
|
||||
this.#destinationPreviewCursors.push(cursor);
|
||||
}
|
||||
|
||||
this.#updateDestinationCursors();
|
||||
}
|
||||
}
|
||||
|
||||
#updateDestinationCursors() {
|
||||
const groupLatLng = this.#computeDestinationRotation && this.#destinationRotationCenter != null ? this.#destinationRotationCenter : this.getMouseCoordinates();
|
||||
|
||||
@ -25,6 +25,8 @@ import { groundUnitDatabase } from "./unit/databases/groundunitdatabase";
|
||||
import { navyUnitDatabase } from "./unit/databases/navyunitdatabase";
|
||||
import { ConfigurationOptions } from "./interfaces";
|
||||
import { UnitListPanel } from "./panels/unitlistpanel";
|
||||
import { ContextManager } from "./context/contextmanager";
|
||||
import { Context } from "./context/context";
|
||||
|
||||
export class OlympusApp {
|
||||
/* Global data */
|
||||
@ -34,13 +36,14 @@ export class OlympusApp {
|
||||
#map: Map | null = null;
|
||||
|
||||
/* Managers */
|
||||
#contextManager!: ContextManager;
|
||||
#dialogManager!: Manager;
|
||||
#missionManager: MissionManager | null = null;
|
||||
#panelsManager: Manager | null = null;
|
||||
#pluginsManager: PluginsManager | null = null;
|
||||
#popupsManager: Manager | null = null;
|
||||
#serverManager: ServerManager | null = null;
|
||||
#shortcutManager: ShortcutManager | null = null;
|
||||
#shortcutManager!: ShortcutManager;
|
||||
#toolbarsManager: Manager | null = null;
|
||||
#unitsManager: UnitsManager | null = null;
|
||||
#weaponsManager: WeaponsManager | null = null;
|
||||
@ -58,6 +61,14 @@ export class OlympusApp {
|
||||
return this.#map as Map;
|
||||
}
|
||||
|
||||
getCurrentContext() {
|
||||
return this.getContextManager().getCurrentContext() as Context;
|
||||
}
|
||||
|
||||
getContextManager() {
|
||||
return this.#contextManager as ContextManager;
|
||||
}
|
||||
|
||||
getServerManager() {
|
||||
return this.#serverManager as ServerManager;
|
||||
}
|
||||
@ -166,6 +177,10 @@ export class OlympusApp {
|
||||
|
||||
start() {
|
||||
/* Initialize base functionalitites */
|
||||
|
||||
this.#contextManager = new ContextManager();
|
||||
this.#contextManager.add( "olympus", {} );
|
||||
|
||||
this.#map = new Map('map-container');
|
||||
|
||||
this.#missionManager = new MissionManager();
|
||||
@ -214,6 +229,13 @@ export class OlympusApp {
|
||||
|
||||
/* Setup all global events */
|
||||
this.#setupEvents();
|
||||
|
||||
/* Set the splash background image to a random image */
|
||||
var splashScreen = document.getElementById("splash-screen");
|
||||
if (splashScreen) {
|
||||
let i = Math.round(Math.random() * 7 + 1);
|
||||
splashScreen.style.backgroundImage = `url('/resources/theme/images/splash/${i}.jpg')`;
|
||||
}
|
||||
}
|
||||
|
||||
#setupEvents() {
|
||||
@ -244,22 +266,28 @@ export class OlympusApp {
|
||||
|
||||
const shortcutManager = this.getShortcutManager();
|
||||
shortcutManager.addKeyboardShortcut("toggleDemo", {
|
||||
"altKey": false,
|
||||
"callback": () => {
|
||||
this.getServerManager().toggleDemoEnabled();
|
||||
},
|
||||
"code": "KeyT"
|
||||
"code": "KeyT",
|
||||
"context": "olympus",
|
||||
"ctrlKey": false,
|
||||
"shiftKey": false
|
||||
}).addKeyboardShortcut("togglePause", {
|
||||
"altKey": false,
|
||||
"callback": () => {
|
||||
this.getServerManager().setPaused(!this.getServerManager().getPaused());
|
||||
},
|
||||
"code": "Space",
|
||||
"context": "olympus",
|
||||
"ctrlKey": false
|
||||
}).addKeyboardShortcut("deselectAll", {
|
||||
"callback": (ev: KeyboardEvent) => {
|
||||
this.getUnitsManager().deselectAllUnits();
|
||||
},
|
||||
"code": "Escape"
|
||||
"code": "Escape",
|
||||
"context": "olympus"
|
||||
}).addKeyboardShortcut("toggleUnitLabels", {
|
||||
"altKey": false,
|
||||
"callback": () => {
|
||||
@ -269,6 +297,7 @@ export class OlympusApp {
|
||||
}
|
||||
},
|
||||
"code": "KeyL",
|
||||
"context": "olympus",
|
||||
"ctrlKey": false,
|
||||
"shiftKey": false
|
||||
}).addKeyboardShortcut("toggleAcquisitionRings", {
|
||||
@ -280,6 +309,7 @@ export class OlympusApp {
|
||||
}
|
||||
},
|
||||
"code": "KeyE",
|
||||
"context": "olympus",
|
||||
"ctrlKey": false,
|
||||
"shiftKey": false
|
||||
}).addKeyboardShortcut("toggleEngagementRings", {
|
||||
@ -291,6 +321,7 @@ export class OlympusApp {
|
||||
}
|
||||
},
|
||||
"code": "KeyQ",
|
||||
"context": "olympus",
|
||||
"ctrlKey": false,
|
||||
"shiftKey": false
|
||||
}).addKeyboardShortcut("toggleHideShortEngagementRings", {
|
||||
@ -302,6 +333,7 @@ export class OlympusApp {
|
||||
}
|
||||
},
|
||||
"code": "KeyR",
|
||||
"context": "olympus",
|
||||
"ctrlKey": false,
|
||||
"shiftKey": false
|
||||
}).addKeyboardShortcut("toggleFillEngagementRings", {
|
||||
@ -313,6 +345,7 @@ export class OlympusApp {
|
||||
}
|
||||
},
|
||||
"code": "KeyF",
|
||||
"context": "olympus",
|
||||
"ctrlKey": false,
|
||||
"shiftKey": false
|
||||
});
|
||||
@ -324,6 +357,7 @@ export class OlympusApp {
|
||||
this.getMap().handleMapPanning(ev);
|
||||
},
|
||||
"code": code,
|
||||
"context": "olympus",
|
||||
"ctrlKey": false,
|
||||
"event": "keydown"
|
||||
});
|
||||
@ -332,7 +366,8 @@ export class OlympusApp {
|
||||
"callback": (ev: KeyboardEvent) => {
|
||||
this.getMap().handleMapPanning(ev);
|
||||
},
|
||||
"code": code
|
||||
"code": code,
|
||||
"context": "olympus"
|
||||
});
|
||||
});
|
||||
|
||||
@ -353,10 +388,8 @@ export class OlympusApp {
|
||||
},
|
||||
"code": code
|
||||
});
|
||||
});
|
||||
|
||||
// Stop hotgroup controls sending the browser to another tab
|
||||
digits.forEach(code => {
|
||||
// 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) {
|
||||
ev.preventDefault();
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
import { Context } from "../context/context";
|
||||
|
||||
export class Manager {
|
||||
|
||||
#items: { [key: string]: any } = {};
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
add(name: string, item: any) {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { getApp } from "..";
|
||||
import { ShortcutKeyboardOptions, ShortcutMouseOptions, ShortcutOptions } from "../interfaces";
|
||||
import { keyEventWasInInput } from "../other/utils";
|
||||
|
||||
@ -19,6 +20,10 @@ export class ShortcutKeyboard extends Shortcut {
|
||||
super(config);
|
||||
|
||||
document.addEventListener(config.event, (ev: any) => {
|
||||
if ( typeof config.context === "string" && !getApp().getContextManager().currentContextIs( config.context ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ev instanceof KeyboardEvent === false || keyEventWasInInput(ev)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { ShortcutKeyboardOptions, ShortcutMouseOptions } from "../interfaces";
|
||||
import { Manager } from "../other/manager";
|
||||
|
||||
import { ShortcutKeyboard, ShortcutMouse } from "./shortcut";
|
||||
|
||||
export class ShortcutManager extends Manager {
|
||||
|
||||
@ -47,6 +47,8 @@ export class UnitsManager {
|
||||
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() });
|
||||
|
||||
this.#slowDeleteDialog = new Dialog( "slow-delete-dialog" );
|
||||
}
|
||||
|
||||
@ -221,16 +223,29 @@ export class UnitsManager {
|
||||
* @param options Selection options
|
||||
* @returns Array of selected units
|
||||
*/
|
||||
getSelectedUnits(options?: { excludeHumans?: boolean, onlyOnePerGroup?: boolean }) {
|
||||
var selectedUnits = [];
|
||||
for (let ID in this.#units) {
|
||||
if (this.#units[ID].getSelected()) {
|
||||
selectedUnits.push(this.#units[ID]);
|
||||
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)) {
|
||||
if (unit.getSelected()) {
|
||||
if (options) {
|
||||
if (options.excludeHumans && unit.getHuman())
|
||||
continue
|
||||
|
||||
if (options.excludeProtected === true && this.#unitIsProtected(unit)) {
|
||||
numProtectedUnits++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
selectedUnits.push(unit);
|
||||
}
|
||||
}
|
||||
if (options) {
|
||||
if (options.excludeHumans)
|
||||
selectedUnits = selectedUnits.filter((unit: Unit) => { return !unit.getHuman() });
|
||||
if (options.showProtectionReminder === true && numProtectedUnits > selectedUnits.length && selectedUnits.length === 0) {
|
||||
const messageText = (numProtectedUnits === 1) ? `Unit is protected` : `All selected units are protected`;
|
||||
(getApp().getPopupsManager().get("infoPopup") as Popup).setText(messageText);
|
||||
}
|
||||
|
||||
if (options.onlyOnePerGroup) {
|
||||
var temp: Unit[] = [];
|
||||
for (let unit of selectedUnits) {
|
||||
@ -320,7 +335,10 @@ 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)
|
||||
*/
|
||||
selectedUnitsAddDestination(latlng: L.LatLng, mantainRelativePosition: boolean, rotation: number) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
|
||||
if (selectedUnits.length === 0)
|
||||
return;
|
||||
|
||||
/* Compute the destination for each unit. If mantainRelativePosition is true, compute the destination so to hold the relative positions */
|
||||
var unitDestinations: { [key: number]: LatLng } = {};
|
||||
@ -353,7 +371,7 @@ export class UnitsManager {
|
||||
*
|
||||
*/
|
||||
selectedUnitsClearDestinations() {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: false });
|
||||
for (let idx in selectedUnits) {
|
||||
const unit = selectedUnits[idx];
|
||||
if (unit.getState() === "follow") {
|
||||
@ -373,7 +391,7 @@ export class UnitsManager {
|
||||
* @param latlng Location where to land at
|
||||
*/
|
||||
selectedUnitsLandAt(latlng: LatLng) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].landAt(latlng);
|
||||
}
|
||||
@ -385,7 +403,7 @@ export class UnitsManager {
|
||||
* @param speedChange Speed change, either "stop", "slow", or "fast". The specific value depends on the unit category
|
||||
*/
|
||||
selectedUnitsChangeSpeed(speedChange: string) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].changeSpeed(speedChange);
|
||||
}
|
||||
@ -396,7 +414,7 @@ export class UnitsManager {
|
||||
* @param altitudeChange Altitude change, either "climb" or "descend". The specific value depends on the unit category
|
||||
*/
|
||||
selectedUnitsChangeAltitude(altitudeChange: string) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].changeAltitude(altitudeChange);
|
||||
}
|
||||
@ -407,7 +425,7 @@ export class UnitsManager {
|
||||
* @param speed Value to set, in m/s
|
||||
*/
|
||||
selectedUnitsSetSpeed(speed: number) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].setSpeed(speed);
|
||||
}
|
||||
@ -419,7 +437,7 @@ export class UnitsManager {
|
||||
* @param speedType Value to set, either "CAS" or "GS". If "CAS" is selected, the unit will try to maintain the selected Calibrated Air Speed, but DCS will still only maintain a Ground Speed value so errors may arise depending on wind.
|
||||
*/
|
||||
selectedUnitsSetSpeedType(speedType: string) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].setSpeedType(speedType);
|
||||
}
|
||||
@ -431,7 +449,7 @@ export class UnitsManager {
|
||||
* @param altitude Value to set, in m
|
||||
*/
|
||||
selectedUnitsSetAltitude(altitude: number) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].setAltitude(altitude);
|
||||
}
|
||||
@ -443,7 +461,7 @@ export class UnitsManager {
|
||||
* @param altitudeType Value to set, either "ASL" or "AGL". If "AGL" is selected, the unit will try to maintain the selected Above Ground Level altitude. Due to a DCS bug, this will only be true at the final position.
|
||||
*/
|
||||
selectedUnitsSetAltitudeType(altitudeType: string) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].setAltitudeType(altitudeType);
|
||||
}
|
||||
@ -455,7 +473,7 @@ export class UnitsManager {
|
||||
* @param ROE Value to set, see constants for acceptable values
|
||||
*/
|
||||
selectedUnitsSetROE(ROE: string) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].setROE(ROE);
|
||||
}
|
||||
@ -467,7 +485,7 @@ export class UnitsManager {
|
||||
* @param reactionToThreat Value to set, see constants for acceptable values
|
||||
*/
|
||||
selectedUnitsSetReactionToThreat(reactionToThreat: string) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].setReactionToThreat(reactionToThreat);
|
||||
}
|
||||
@ -479,7 +497,7 @@ export class UnitsManager {
|
||||
* @param emissionCountermeasure Value to set, see constants for acceptable values
|
||||
*/
|
||||
selectedUnitsSetEmissionsCountermeasures(emissionCountermeasure: string) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].setEmissionsCountermeasures(emissionCountermeasure);
|
||||
}
|
||||
@ -491,7 +509,7 @@ export class UnitsManager {
|
||||
* @param onOff If true, the unit will be turned on
|
||||
*/
|
||||
selectedUnitsSetOnOff(onOff: boolean) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].setOnOff(onOff);
|
||||
}
|
||||
@ -503,7 +521,7 @@ export class UnitsManager {
|
||||
* @param followRoads If true, units will follow roads
|
||||
*/
|
||||
selectedUnitsSetFollowRoads(followRoads: boolean) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].setFollowRoads(followRoads);
|
||||
}
|
||||
@ -516,7 +534,7 @@ export class UnitsManager {
|
||||
*/
|
||||
selectedUnitsSetOperateAs(operateAsBool: boolean) {
|
||||
var operateAs = operateAsBool? "blue": "red";
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].setOperateAs(operateAs);
|
||||
}
|
||||
@ -528,7 +546,7 @@ export class UnitsManager {
|
||||
* @param ID ID of the unit to attack
|
||||
*/
|
||||
selectedUnitsAttackUnit(ID: number) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].attackUnit(ID);
|
||||
}
|
||||
@ -539,7 +557,7 @@ export class UnitsManager {
|
||||
*
|
||||
*/
|
||||
selectedUnitsRefuel() {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].refuel();
|
||||
}
|
||||
@ -565,7 +583,10 @@ export class UnitsManager {
|
||||
else offset = undefined;
|
||||
}
|
||||
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
|
||||
if ( selectedUnits.length === 0)
|
||||
return;
|
||||
|
||||
var count = 1;
|
||||
var xr = 0; var yr = 1; var zr = -1;
|
||||
@ -601,7 +622,7 @@ export class UnitsManager {
|
||||
* @param latlng Location to bomb
|
||||
*/
|
||||
selectedUnitsBombPoint(latlng: LatLng) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].bombPoint(latlng);
|
||||
}
|
||||
@ -613,7 +634,7 @@ export class UnitsManager {
|
||||
* @param latlng Location to bomb
|
||||
*/
|
||||
selectedUnitsCarpetBomb(latlng: LatLng) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].carpetBomb(latlng);
|
||||
}
|
||||
@ -625,7 +646,7 @@ export class UnitsManager {
|
||||
* @param latlng Location to fire at
|
||||
*/
|
||||
selectedUnitsFireAtArea(latlng: LatLng) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].fireAtArea(latlng);
|
||||
}
|
||||
@ -637,7 +658,7 @@ export class UnitsManager {
|
||||
* @param latlng Location to fire at
|
||||
*/
|
||||
selectedUnitsSimulateFireFight(latlng: LatLng) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
getGroundElevation(latlng, (response: string) => {
|
||||
var groundElevation: number | null = null;
|
||||
try {
|
||||
@ -656,7 +677,7 @@ export class UnitsManager {
|
||||
*
|
||||
*/
|
||||
selectedUnitsScenicAAA() {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].scenicAAA();
|
||||
}
|
||||
@ -667,11 +688,11 @@ export class UnitsManager {
|
||||
*
|
||||
*/
|
||||
selectedUnitsMissOnPurpose() {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].missOnPurpose();
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `unit set to perform miss on purpose AAA`);
|
||||
this.#showActionMessage(selectedUnits, `unit set to perform miss-on-purpose AAA`);
|
||||
}
|
||||
|
||||
/** Instruct units to land at specific point
|
||||
@ -679,12 +700,12 @@ export class UnitsManager {
|
||||
* @param latlng Point where to land
|
||||
*/
|
||||
selectedUnitsLandAtPoint(latlng: LatLng) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true, showProtectionReminder: true });
|
||||
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].landAtPoint(latlng);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `unit simulating fire fight`);
|
||||
this.#showActionMessage(selectedUnits, `unit landing at point`);
|
||||
}
|
||||
|
||||
/** Set a specific shots scatter to all the selected units
|
||||
@ -733,7 +754,7 @@ export class UnitsManager {
|
||||
*
|
||||
*/
|
||||
selectedUnitsCreateGroup() {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: false });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: false, showProtectionReminder: true });
|
||||
if (this.getUnitsCategories(selectedUnits).length == 1) {
|
||||
var units: { ID: number, location: LatLng }[] = [];
|
||||
for (let idx in selectedUnits) {
|
||||
@ -774,7 +795,7 @@ export class UnitsManager {
|
||||
* @returns
|
||||
*/
|
||||
selectedUnitsDelete(explosion: boolean = false) {
|
||||
var selectedUnits = this.getSelectedUnits(); /* Can be applied to humans too */
|
||||
var selectedUnits = this.getSelectedUnits({excludeProtected:true}); /* Can be applied to humans too */
|
||||
const selectionContainsAHuman = selectedUnits.some((unit: Unit) => {
|
||||
return unit.getHuman() === true;
|
||||
});
|
||||
@ -784,7 +805,6 @@ export class UnitsManager {
|
||||
}
|
||||
|
||||
const doDelete = (explosion = false, immediate = false) => {
|
||||
const selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].delete(explosion, immediate);
|
||||
}
|
||||
@ -810,7 +830,7 @@ export class UnitsManager {
|
||||
* @returns Array of positions for each unit, in order
|
||||
*/
|
||||
selectedUnitsComputeGroupDestination(latlng: LatLng, rotation: number) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, excludeProtected: true, onlyOnePerGroup: true });
|
||||
/* Compute the center of the group */
|
||||
var center = { x: 0, y: 0 };
|
||||
selectedUnits.forEach((unit: Unit) => {
|
||||
@ -1089,6 +1109,7 @@ export class UnitsManager {
|
||||
window.setTimeout(() => {
|
||||
document.dispatchEvent(new CustomEvent("unitsSelection", { detail: this.getSelectedUnits() }));
|
||||
this.#selectionEventDisabled = false;
|
||||
this.#showNumberOfSelectedProtectedUnits();
|
||||
}, 100);
|
||||
this.#selectionEventDisabled = true;
|
||||
}
|
||||
@ -1150,4 +1171,21 @@ export class UnitsManager {
|
||||
}, 250);
|
||||
});
|
||||
}
|
||||
|
||||
#showNumberOfSelectedProtectedUnits() {
|
||||
const map = getApp().getMap();
|
||||
const selectedUnits = this.getSelectedUnits();
|
||||
const numSelectedUnits = selectedUnits.length;
|
||||
const numProtectedUnits = selectedUnits.filter((unit:Unit) => map.unitIsProtected(unit) ).length;
|
||||
|
||||
if (numProtectedUnits === 1 && numSelectedUnits === numProtectedUnits)
|
||||
(getApp().getPopupsManager().get("infoPopup") as Popup).setText(`Notice: unit is protected`);
|
||||
|
||||
if (numProtectedUnits > 1)
|
||||
(getApp().getPopupsManager().get("infoPopup") as Popup).setText(`Notice: selection contains ${numProtectedUnits} protected units.`);
|
||||
}
|
||||
|
||||
#unitIsProtected(unit:Unit) {
|
||||
return getApp().getMap().unitIsProtected(unit)
|
||||
}
|
||||
}
|
||||
@ -37,8 +37,8 @@ public:
|
||||
private:
|
||||
list<Command*> commands;
|
||||
list<string> executedCommandsHashes;
|
||||
unsigned int load;
|
||||
double frameRate;
|
||||
unsigned int load = 0;
|
||||
double frameRate = 0;
|
||||
|
||||
bool restrictSpawns = false;
|
||||
bool restrictToCoalition = false;
|
||||
|
||||
@ -7,12 +7,9 @@
|
||||
|
||||
extern UnitsManager* unitsManager;
|
||||
|
||||
Scheduler::Scheduler(lua_State* L) :
|
||||
load(0)
|
||||
Scheduler::Scheduler(lua_State* L)
|
||||
{
|
||||
LogInfo(L, "Scheduler constructor called successfully");
|
||||
|
||||
|
||||
}
|
||||
|
||||
Scheduler::~Scheduler()
|
||||
@ -20,6 +17,7 @@ Scheduler::~Scheduler()
|
||||
|
||||
}
|
||||
|
||||
/* Appends a */
|
||||
void Scheduler::appendCommand(Command* newCommand)
|
||||
{
|
||||
for (auto command : commands) {
|
||||
@ -143,6 +141,7 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
log("Received request with ID: " + key);
|
||||
log(L"Incoming command raw value: " + value.serialize());
|
||||
|
||||
/************************/
|
||||
if (key.compare("setPath") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
@ -150,7 +149,6 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
if (unit != nullptr)
|
||||
{
|
||||
string unitName = unit->getUnitName();
|
||||
json::value path = value[L"path"];
|
||||
list<Coords> newPath;
|
||||
for (unsigned int i = 0; i < path.as_array().size(); i++)
|
||||
@ -164,19 +162,22 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
|
||||
unit->setActivePath(newPath);
|
||||
unit->setState(State::REACH_DESTINATION);
|
||||
log(username + " updated destination path for unit " + unitName, true);
|
||||
log(username + " updated destination path for unit " + unit->getUnitName() + "(" + unit->getName() + ")", true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("smoke") == 0)
|
||||
{
|
||||
string color = to_string(value[L"color"]);
|
||||
double lat = value[L"location"][L"lat"].as_double();
|
||||
double lng = value[L"location"][L"lng"].as_double();
|
||||
log(username + " added a " + color + " smoke at (" + to_string(lat) + ", " + to_string(lng) + ")", true);
|
||||
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
command = dynamic_cast<Command*>(new Smoke(color, loc));
|
||||
log(username + " added a " + color + " smoke at (" + to_string(lat) + ", " + to_string(lng) + ")", true);
|
||||
}
|
||||
else if (key.compare("spawnAircrafts") == 0)
|
||||
/************************/
|
||||
else if (key.compare("spawnAircrafts") == 0 || key.compare("spawnHelicopters") == 0)
|
||||
{
|
||||
bool immediate = value[L"immediate"].as_bool();
|
||||
string coalition = to_string(value[L"coalition"]);
|
||||
@ -200,35 +201,13 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
log(username + " spawned a " + coalition + " " + unitType, true);
|
||||
}
|
||||
|
||||
command = dynamic_cast<Command*>(new SpawnAircrafts(coalition, spawnOptions, airbaseName, country, immediate));
|
||||
if (key.compare("spawnAircrafts") == 0)
|
||||
command = dynamic_cast<Command*>(new SpawnAircrafts(coalition, spawnOptions, airbaseName, country, immediate));
|
||||
else
|
||||
command = dynamic_cast<Command*>(new SpawnHelicopters(coalition, spawnOptions, airbaseName, country, immediate));
|
||||
}
|
||||
else if (key.compare("spawnHelicopters") == 0)
|
||||
{
|
||||
bool immediate = value[L"immediate"].as_bool();
|
||||
string coalition = to_string(value[L"coalition"]);
|
||||
string airbaseName = to_string(value[L"airbaseName"]);
|
||||
string country = to_string(value[L"country"]);
|
||||
|
||||
int spawnPoints = value[L"spawnPoints"].as_number().to_int32();
|
||||
if (!checkSpawnPoints(spawnPoints, coalition)) return;
|
||||
|
||||
vector<SpawnOptions> spawnOptions;
|
||||
for (auto unit : value[L"units"].as_array()) {
|
||||
string unitType = to_string(unit[L"unitType"]);
|
||||
double lat = unit[L"location"][L"lat"].as_double();
|
||||
double lng = unit[L"location"][L"lng"].as_double();
|
||||
double alt = unit[L"altitude"].as_double();
|
||||
Coords location; location.lat = lat; location.lng = lng; location.alt = alt;
|
||||
string loadout = to_string(unit[L"loadout"]);
|
||||
string liveryID = to_string(unit[L"liveryID"]);
|
||||
|
||||
spawnOptions.push_back({ unitType, location, loadout, liveryID });
|
||||
log(username + " spawned a " + coalition + " " + unitType, true);
|
||||
}
|
||||
|
||||
command = dynamic_cast<Command*>(new SpawnHelicopters(coalition, spawnOptions, airbaseName, country, immediate));
|
||||
}
|
||||
else if (key.compare("spawnGroundUnits") == 0)
|
||||
/************************/
|
||||
else if (key.compare("spawnGroundUnits") == 0 || key.compare("spawnNavyUnits") == 0)
|
||||
{
|
||||
bool immediate = value[L"immediate"].as_bool();
|
||||
string coalition = to_string(value[L"coalition"]);
|
||||
@ -249,31 +228,12 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
log(username + " spawned a " + coalition + " " + unitType, true);
|
||||
}
|
||||
|
||||
command = dynamic_cast<Command*>(new SpawnGroundUnits(coalition, spawnOptions, country, immediate));
|
||||
}
|
||||
else if (key.compare("spawnNavyUnits") == 0)
|
||||
{
|
||||
bool immediate = value[L"immediate"].as_bool();
|
||||
string coalition = to_string(value[L"coalition"]);
|
||||
string country = to_string(value[L"country"]);
|
||||
|
||||
int spawnPoints = value[L"spawnPoints"].as_number().to_int32();
|
||||
if (!checkSpawnPoints(spawnPoints, coalition)) return;
|
||||
|
||||
vector<SpawnOptions> spawnOptions;
|
||||
for (auto unit : value[L"units"].as_array()) {
|
||||
string unitType = to_string(unit[L"unitType"]);
|
||||
double lat = unit[L"location"][L"lat"].as_double();
|
||||
double lng = unit[L"location"][L"lng"].as_double();
|
||||
Coords location; location.lat = lat; location.lng = lng;
|
||||
string liveryID = to_string(unit[L"liveryID"]);
|
||||
|
||||
spawnOptions.push_back({ unitType, location, "", liveryID});
|
||||
log(username + " spawned a " + coalition + " " + unitType, true);
|
||||
}
|
||||
|
||||
command = dynamic_cast<Command*>(new SpawnNavyUnits(coalition, spawnOptions, country, immediate));
|
||||
if (key.compare("spawnGroundUnits") == 0)
|
||||
command = dynamic_cast<Command*>(new SpawnGroundUnits(coalition, spawnOptions, country, immediate));
|
||||
else
|
||||
command = dynamic_cast<Command*>(new SpawnNavyUnits(coalition, spawnOptions, country, immediate));
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("attackUnit") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
@ -283,23 +243,13 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
Unit* target = unitsManager->getUnit(targetID);
|
||||
|
||||
string unitName;
|
||||
string targetName;
|
||||
|
||||
if (unit != nullptr)
|
||||
unitName = unit->getUnitName();
|
||||
else
|
||||
return;
|
||||
|
||||
if (target != nullptr)
|
||||
targetName = target->getUnitName();
|
||||
else
|
||||
return;
|
||||
|
||||
log(username + " tasked unit " + unitName + " to attack unit " + targetName, true);
|
||||
unit->setTargetID(targetID);
|
||||
unit->setState(State::ATTACK);
|
||||
if (unit != nullptr && target != nullptr) {
|
||||
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to attack unit " + target->getUnitName() + "(" + target->getName() + ")", true);
|
||||
unit->setTargetID(targetID);
|
||||
unit->setState(State::ATTACK);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("followUnit") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
@ -312,72 +262,80 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
Unit* leader = unitsManager->getUnit(leaderID);
|
||||
|
||||
string unitName;
|
||||
string leaderName;
|
||||
|
||||
if (unit != nullptr)
|
||||
unitName = unit->getUnitName();
|
||||
else
|
||||
return;
|
||||
|
||||
if (leader != nullptr)
|
||||
leaderName = leader->getUnitName();
|
||||
else
|
||||
return;
|
||||
|
||||
log(username + " tasked unit " + unitName + " to follow unit " + leaderName, true);
|
||||
unit->setFormationOffset(Offset(offsetX, offsetY, offsetZ));
|
||||
unit->setLeaderID(leaderID);
|
||||
unit->setState(State::FOLLOW);
|
||||
if (unit != nullptr && leader != nullptr) {
|
||||
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to follow unit " + leader->getUnitName() + "(" + leader->getName() + ")", true);
|
||||
unit->setFormationOffset(Offset(offsetX, offsetY, offsetZ));
|
||||
unit->setLeaderID(leaderID);
|
||||
unit->setState(State::FOLLOW);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("changeSpeed") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
if (unit != nullptr)
|
||||
if (unit != nullptr) {
|
||||
unit->changeSpeed(to_string(value[L"change"]));
|
||||
log(username + " changed " + unit->getUnitName() + "(" + unit->getName() + ") speed: " + to_string(value[L"change"]), true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("changeAltitude") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
if (unit != nullptr)
|
||||
if (unit != nullptr) {
|
||||
unit->changeAltitude(to_string(value[L"change"]));
|
||||
log(username + " changed " + unit->getUnitName() + "(" + unit->getName() + ") altitude: " + to_string(value[L"change"]), true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setSpeed") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
if (unit != nullptr)
|
||||
if (unit != nullptr) {
|
||||
unit->setDesiredSpeed(value[L"speed"].as_double());
|
||||
log(username + " set " + unit->getUnitName() + "(" + unit->getName() + ") speed: " + to_string(value[L"speed"].as_double()), true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setSpeedType") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
if (unit != nullptr)
|
||||
if (unit != nullptr) {
|
||||
unit->setDesiredSpeedType(to_string(value[L"speedType"]));
|
||||
log(username + " set " + unit->getUnitName() + "(" + unit->getName() + ") speed type: " + to_string(value[L"speedType"]), true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setAltitude") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
if (unit != nullptr)
|
||||
if (unit != nullptr) {
|
||||
unit->setDesiredAltitude(value[L"altitude"].as_double());
|
||||
log(username + " set " + unit->getUnitName() + "(" + unit->getName() + ") altitude: " + to_string(value[L"altitude"].as_double()), true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setAltitudeType") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
if (unit != nullptr)
|
||||
if (unit != nullptr) {
|
||||
unit->setDesiredAltitudeType(to_string(value[L"altitudeType"]));
|
||||
log(username + " set " + unit->getUnitName() + "(" + unit->getName() + ") altitude type: " + to_string(value[L"altitudeType"]), true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("cloneUnits") == 0)
|
||||
{
|
||||
vector<CloneOptions> cloneOptions;
|
||||
@ -395,61 +353,80 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
|
||||
command = dynamic_cast<Command*>(new Clone(cloneOptions, deleteOriginal));
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setROE") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unsigned char ROE = value[L"ROE"].as_number().to_uint32();
|
||||
unit->setROE(ROE);
|
||||
log(username + " set unit " + unit->getName() + " ROE to " + to_string(ROE), true);
|
||||
if (unit != nullptr) {
|
||||
unsigned char ROE = value[L"ROE"].as_number().to_uint32();
|
||||
unit->setROE(ROE);
|
||||
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") ROE to " + to_string(ROE), true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setReactionToThreat") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unsigned char reactionToThreat = value[L"reactionToThreat"].as_number().to_uint32();
|
||||
unit->setReactionToThreat(reactionToThreat);
|
||||
log(username + " set unit " + unit->getName() + " reaction to threat to " + to_string(reactionToThreat), true);
|
||||
if (unit != nullptr) {
|
||||
unsigned char reactionToThreat = value[L"reactionToThreat"].as_number().to_uint32();
|
||||
unit->setReactionToThreat(reactionToThreat);
|
||||
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") reaction to threat to " + to_string(reactionToThreat), true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setEmissionsCountermeasures") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unsigned char emissionsCountermeasures = value[L"emissionsCountermeasures"].as_number().to_uint32();
|
||||
unit->setEmissionsCountermeasures(emissionsCountermeasures);
|
||||
log(username + " set unit " + unit->getName() + " emissions and countermeasures to " + to_string(emissionsCountermeasures), true);
|
||||
if (unit != nullptr) {
|
||||
unsigned char emissionsCountermeasures = value[L"emissionsCountermeasures"].as_number().to_uint32();
|
||||
unit->setEmissionsCountermeasures(emissionsCountermeasures);
|
||||
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") emissions and countermeasures to " + to_string(emissionsCountermeasures), true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("landAt") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
double lat = value[L"location"][L"lat"].as_double();
|
||||
double lng = value[L"location"][L"lng"].as_double();
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
unit->landAt(loc);
|
||||
log(username + " tasked unit " + unit->getName() + " to land", true);
|
||||
if (unit != nullptr) {
|
||||
double lat = value[L"location"][L"lat"].as_double();
|
||||
double lng = value[L"location"][L"lng"].as_double();
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
unit->landAt(loc);
|
||||
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to land", true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("deleteUnit") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
bool explosion = value[L"explosion"].as_bool();
|
||||
bool immediate = value[L"immediate"].as_bool();
|
||||
unitsManager->deleteUnit(ID, explosion, immediate);
|
||||
Unit* unit = unitsManager->getUnit(ID);
|
||||
log(username + " deleted unit " + unit->getName(), true);
|
||||
if (unit != nullptr) {
|
||||
unitsManager->deleteUnit(ID, explosion, immediate);
|
||||
log(username + " deleted unit " + unit->getUnitName() + "(" + unit->getName() + ")", true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("refuel") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unit->setState(State::REFUEL);
|
||||
log(username + " tasked unit " + unit->getName() + " to refuel", true);
|
||||
if (unit != nullptr) {
|
||||
unit->setState(State::REFUEL);
|
||||
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to refuel", true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setAdvancedOptions") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
@ -489,24 +466,35 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
});
|
||||
|
||||
unit->resetActiveDestination();
|
||||
|
||||
log(username + " updated unit " + unit->getUnitName() + "(" + unit->getName() + ") advancedOptions", true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setFollowRoads") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
bool followRoads = value[L"followRoads"].as_bool();
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unit->setFollowRoads(followRoads);
|
||||
if (unit != nullptr) {
|
||||
unit->setFollowRoads(followRoads);
|
||||
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") followRoads to: " + (followRoads ? "true" : "false"), true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setOnOff") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
bool onOff = value[L"onOff"].as_bool();
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unit->setOnOff(onOff);
|
||||
if (unit != nullptr) {
|
||||
unit->setOnOff(onOff);
|
||||
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") onOff to: " + (onOff? "true": "false"), true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("explosion") == 0)
|
||||
{
|
||||
unsigned int intensity = value[L"intensity"].as_integer();
|
||||
@ -516,6 +504,7 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
command = dynamic_cast<Command*>(new Explosion(intensity, loc));
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("bombPoint") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
@ -524,10 +513,13 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
double lng = value[L"location"][L"lng"].as_double();
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unit->setState(State::BOMB_POINT);
|
||||
unit->setTargetPosition(loc);
|
||||
log(username + " tasked unit " + unit->getName() + " to bomb a point", true);
|
||||
if (unit != nullptr) {
|
||||
unit->setState(State::BOMB_POINT);
|
||||
unit->setTargetPosition(loc);
|
||||
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to bomb a point", true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("carpetBomb") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
@ -536,10 +528,14 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
double lng = value[L"location"][L"lng"].as_double();
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unit->setState(State::CARPET_BOMB);
|
||||
unit->setTargetPosition(loc);
|
||||
log(username + " tasked unit " + unit->getName() + " to perform carpet bombing", true);
|
||||
if (unit != nullptr) {
|
||||
unit->setState(State::CARPET_BOMB);
|
||||
unit->setTargetPosition(loc);
|
||||
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to perform carpet bombing", true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
/* TODO: this command does not appear to be working in DCS and has been disabled */
|
||||
else if (key.compare("bombBuilding") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
@ -548,9 +544,12 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
double lng = value[L"location"][L"lng"].as_double();
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unit->setState(State::BOMB_BUILDING);
|
||||
unit->setTargetPosition(loc);
|
||||
if (unit != nullptr) {
|
||||
unit->setState(State::BOMB_BUILDING);
|
||||
unit->setTargetPosition(loc);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("fireAtArea") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
@ -559,10 +558,13 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
double lng = value[L"location"][L"lng"].as_double();
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unit->setState(State::FIRE_AT_AREA);
|
||||
unit->setTargetPosition(loc);
|
||||
log(username + " tasked unit " + unit->getName() + " to fire at area", true);
|
||||
if (unit != nullptr) {
|
||||
unit->setState(State::FIRE_AT_AREA);
|
||||
unit->setTargetPosition(loc);
|
||||
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to fire at area", true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("simulateFireFight") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
@ -572,34 +574,45 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
double alt = value[L"altitude"].as_double();
|
||||
Coords loc; loc.lat = lat; loc.lng = lng; loc.alt = alt;
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unit->setState(State::SIMULATE_FIRE_FIGHT);
|
||||
unit->setTargetPosition(loc);
|
||||
log(username + " tasked unit " + unit->getName() + " to simulate a fire fight", true);
|
||||
if (unit != nullptr) {
|
||||
unit->setState(State::SIMULATE_FIRE_FIGHT);
|
||||
unit->setTargetPosition(loc);
|
||||
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to simulate a fire fight", true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("scenicAAA") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unit->setState(State::SCENIC_AAA);
|
||||
log(username + " tasked unit " + unit->getName() + " to enter scenic AAA state", true);
|
||||
if (unit != nullptr) {
|
||||
unit->setState(State::SCENIC_AAA);
|
||||
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to enter scenic AAA state", true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("missOnPurpose") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unit->setState(State::MISS_ON_PURPOSE);
|
||||
log(username + " tasked unit " + unit->getName() + " to enter Miss On Purpose state", true);
|
||||
if (unit != nullptr) {
|
||||
unit->setState(State::MISS_ON_PURPOSE);
|
||||
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to enter Miss On Purpose state", true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setOperateAs") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
unsigned char operateAs = value[L"operateAs"].as_number().to_uint32();
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unit->setOperateAs(operateAs);
|
||||
if (unit != nullptr)
|
||||
unit->setOperateAs(operateAs);
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("landAtPoint") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
@ -609,39 +622,50 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
Coords loc; loc.lat = lat; loc.lng = lng;
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
|
||||
list<Coords> newPath;
|
||||
newPath.push_back(loc);
|
||||
unit->setActivePath(newPath);
|
||||
unit->setState(State::LAND_AT_POINT);
|
||||
|
||||
log(username + " tasked unit " + unit->getName() + " to land at point", true);
|
||||
if (unit != nullptr) {
|
||||
list<Coords> newPath;
|
||||
newPath.push_back(loc);
|
||||
unit->setActivePath(newPath);
|
||||
unit->setState(State::LAND_AT_POINT);
|
||||
|
||||
log(username + " tasked unit " + unit->getUnitName() + "(" + unit->getName() + ") to land at point", true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setShotsScatter") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unsigned char shotsScatter = value[L"shotsScatter"].as_number().to_uint32();
|
||||
unit->setShotsScatter(shotsScatter);
|
||||
log(username + " set unit " + unit->getName() + " shots scatter to " + to_string(shotsScatter), true);
|
||||
if (unit != nullptr) {
|
||||
unsigned char shotsScatter = value[L"shotsScatter"].as_number().to_uint32();
|
||||
unit->setShotsScatter(shotsScatter);
|
||||
log(username + " set unit " + + unit->getUnitName() + "(" + unit->getName() + ") shots scatter to " + to_string(shotsScatter), true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setShotsIntensity") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unsigned char shotsIntensity = value[L"shotsIntensity"].as_number().to_uint32();
|
||||
unit->setShotsIntensity(shotsIntensity);
|
||||
log(username + " set unit " + unit->getName() + " shots intensity to " + to_string(shotsIntensity), true);
|
||||
if (unit != nullptr) {
|
||||
unsigned char shotsIntensity = value[L"shotsIntensity"].as_number().to_uint32();
|
||||
unit->setShotsIntensity(shotsIntensity);
|
||||
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") shots intensity to " + to_string(shotsIntensity), true);
|
||||
}
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("setCommandModeOptions") == 0)
|
||||
{
|
||||
setCommandModeOptions(value);
|
||||
log(username + " updated the Command Mode Options", true);
|
||||
}
|
||||
/************************/
|
||||
else if (key.compare("reloadDatabases") == 0) {
|
||||
unitsManager->loadDatabases();
|
||||
}
|
||||
/************************/
|
||||
else
|
||||
{
|
||||
log("Unknown command: " + key);
|
||||
|
||||