Grouped units can be deleted now

Also added some performance optimizations on drawing of selected units and removed destination preview icon for single unit selection
This commit is contained in:
Pax1601
2023-11-22 13:12:35 +01:00
parent 3ffeed3b39
commit d3f8d4eff7
12 changed files with 172 additions and 158 deletions

View File

@@ -25,8 +25,6 @@ class DemoDataGenerator {
app.get('/demo/commands', (req, res) => this.command(req, res)); app.get('/demo/commands', (req, res) => this.command(req, res));
app.put('/demo', (req, res) => this.put(req, res)); app.put('/demo', (req, res) => this.put(req, res));
console.log(config["authentication"]["gameMasterPassword"])
app.use('/demo', basicAuth({ app.use('/demo', basicAuth({
users: { users: {
'admin': config["authentication"]["gameMasterPassword"], 'admin': config["authentication"]["gameMasterPassword"],
@@ -54,9 +52,9 @@ class DemoDataGenerator {
isLeader: true isLeader: true
} }
/*
***************** UNCOMMENT TO TEST ALL UNITS **************** /*
// UNCOMMENT TO TEST ALL UNITS ****************
var databases = Object.assign({}, aircraftDatabase, helicopterDatabase, groundUnitDatabase, navyUnitDatabase); var databases = Object.assign({}, aircraftDatabase, helicopterDatabase, groundUnitDatabase, navyUnitDatabase);
var t = Object.keys(databases).length; var t = Object.keys(databases).length;
@@ -93,6 +91,7 @@ class DemoDataGenerator {
} }
*/ */
let idx = 1; let idx = 1;
DEMO_UNIT_DATA[idx] = JSON.parse(JSON.stringify(baseData)); DEMO_UNIT_DATA[idx] = JSON.parse(JSON.stringify(baseData));
DEMO_UNIT_DATA[idx].name = "S_75M_Volhov"; DEMO_UNIT_DATA[idx].name = "S_75M_Volhov";
@@ -117,6 +116,7 @@ class DemoDataGenerator {
DEMO_UNIT_DATA[idx].category = "GroundUnit"; DEMO_UNIT_DATA[idx].category = "GroundUnit";
DEMO_UNIT_DATA[idx].isLeader = false; DEMO_UNIT_DATA[idx].isLeader = false;
idx += 1; idx += 1;
DEMO_UNIT_DATA[idx] = JSON.parse(JSON.stringify(baseData)); DEMO_UNIT_DATA[idx] = JSON.parse(JSON.stringify(baseData));
DEMO_UNIT_DATA[idx].name = "F-14B"; DEMO_UNIT_DATA[idx].name = "F-14B";

View File

@@ -64,7 +64,7 @@ export class ControlTipsPlugin implements OlympusPlugin {
this.#updateTips(); this.#updateTips();
}); });
document.addEventListener("mapVisibilityOptionsChanged", () => { document.addEventListener("mapOptionsChanged", () => {
this.toggle( !this.#app.getMap().getVisibilityOptions()[SHOW_CONTROL_TIPS] ); this.toggle( !this.#app.getMap().getVisibilityOptions()[SHOW_CONTROL_TIPS] );
}); });

View File

@@ -23,7 +23,7 @@ body {
} }
.hidden-cursor { .hidden-cursor {
cursor: none !important; /*cursor: none !important;*/
} }
.hidden-cursor * { .hidden-cursor * {

View File

@@ -157,8 +157,8 @@ export const mapLayers = {
export const IDLE = "Idle"; export const IDLE = "Idle";
export const MOVE_UNIT = "Move unit"; export const MOVE_UNIT = "Move unit";
export const COALITIONAREA_DRAW_POLYGON = "Draw Coalition Area"; export const COALITIONAREA_DRAW_POLYGON = "Draw Coalition Area";
export const visibilityControls: string[] = ["human", "dcs", "aircraft", "helicopter", "groundunit-sam", "groundunit-other", "navyunit", "airbase"]; export const visibilityControls: string[] = ["human", "dcs", "aircraft", "helicopter", "groundunit-sam", "groundunit", "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 visibilityControlsTypes: string[][] = [["human"], ["dcs"], ["aircraft"], ["helicopter"], ["groundunit-sam"], ["groundunit"], ["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 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[] = [{ export const MAP_MARKER_CONTROLS: MapMarkerControl[] = [{
"name": "Human", "name": "Human",
@@ -188,9 +188,9 @@ export const MAP_MARKER_CONTROLS: MapMarkerControl[] = [{
"toggles": ["groundunit-sam"], "toggles": ["groundunit-sam"],
"tooltip": "Toggle air defence units' visibility" "tooltip": "Toggle air defence units' visibility"
}, { }, {
"image": "visibility/groundunit-other.svg", "image": "visibility/groundunit.svg",
"name": "Ground units", "name": "Ground units",
"toggles": ["groundunit-other"], "toggles": ["groundunit"],
"tooltip": "Toggle ground units' visibility" "tooltip": "Toggle ground units' visibility"
}, { }, {
"image": "visibility/navyunit.svg", "image": "visibility/navyunit.svg",

2
client/src/dom.d.ts vendored
View File

@@ -18,7 +18,7 @@ interface CustomEventMap {
"groupDeletion": CustomEvent<Unit[]>, "groupDeletion": CustomEvent<Unit[]>,
"mapStateChanged": CustomEvent<string>, "mapStateChanged": CustomEvent<string>,
"mapContextMenu": CustomEvent<>, "mapContextMenu": CustomEvent<>,
"mapVisibilityOptionsChanged": CustomEvent<>, "mapOptionsChanged": CustomEvent<>,
"commandModeOptionsChanged": CustomEvent<>, "commandModeOptionsChanged": CustomEvent<>,
"contactsUpdated": CustomEvent<Unit>, "contactsUpdated": CustomEvent<Unit>,
"activeCoalitionChanged": CustomEvent<> "activeCoalitionChanged": CustomEvent<>

View File

@@ -198,7 +198,7 @@ export class Map extends L.Map {
this.#panToUnit(this.#centerUnit); this.#panToUnit(this.#centerUnit);
}); });
document.addEventListener("mapVisibilityOptionsChanged", () => { document.addEventListener("mapOptionsChanged", () => {
this.getContainer().toggleAttribute("data-hide-labels", !this.getVisibilityOptions()[SHOW_UNIT_LABELS]); this.getContainer().toggleAttribute("data-hide-labels", !this.getVisibilityOptions()[SHOW_UNIT_LABELS]);
}); });
@@ -572,7 +572,6 @@ export class Map extends L.Map {
else { else {
this.setState(IDLE); this.setState(IDLE);
} }
} }
#onSelectionStart(e: any) { #onSelectionStart(e: any) {
@@ -766,48 +765,45 @@ export class Map extends L.Map {
const singleCursor = !this.#shiftKey; const singleCursor = !this.#shiftKey;
const selectedUnitsCount = getApp().getUnitsManager().getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true }).length; const selectedUnitsCount = getApp().getUnitsManager().getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true }).length;
if (singleCursor) { if (singleCursor) {
if ( this.#destinationPreviewCursors.length != 1) { this.#hideDestinationCursors();
this.#hideDestinationCursors();
var marker = new DestinationPreviewMarker(this.getMouseCoordinates(), { interactive: false });
marker.addTo(this);
this.#destinationPreviewCursors = [marker];
}
this.#destinationPreviewHandleLine.removeFrom(this);
this.#destinationPreviewHandle.removeFrom(this);
} }
else if (!singleCursor) { else if (!singleCursor) {
while (this.#destinationPreviewCursors.length > selectedUnitsCount) { if (selectedUnitsCount > 1) {
this.removeLayer(this.#destinationPreviewCursors[0]); while (this.#destinationPreviewCursors.length > selectedUnitsCount) {
this.#destinationPreviewCursors.splice(0, 1); 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.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() { #updateDestinationCursors() {
const groupLatLng = this.#computeDestinationRotation && this.#destinationRotationCenter != null ? this.#destinationRotationCenter : this.getMouseCoordinates(); const selectedUnitsCount = getApp().getUnitsManager().getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true }).length;
if (this.#destinationPreviewCursors.length == 1) if (selectedUnitsCount > 1) {
this.#destinationPreviewCursors[0].setLatLng(this.getMouseCoordinates()); const groupLatLng = this.#computeDestinationRotation && this.#destinationRotationCenter != null ? this.#destinationRotationCenter : this.getMouseCoordinates();
else { if (this.#destinationPreviewCursors.length == 1)
Object.values(getApp().getUnitsManager().computeGroupDestination(groupLatLng, this.#destinationGroupRotation)).forEach((latlng: L.LatLng, idx: number) => { this.#destinationPreviewCursors[0].setLatLng(this.getMouseCoordinates());
if (idx < this.#destinationPreviewCursors.length) else {
this.#destinationPreviewCursors[idx].setLatLng(this.#shiftKey ? latlng : this.getMouseCoordinates()); Object.values(getApp().getUnitsManager().computeGroupDestination(groupLatLng, this.#destinationGroupRotation)).forEach((latlng: L.LatLng, idx: number) => {
}) if (idx < this.#destinationPreviewCursors.length)
}; this.#destinationPreviewCursors[idx].setLatLng(this.#shiftKey ? latlng : this.getMouseCoordinates());
})
};
this.#destinationPreviewHandleLine.setLatLngs([groupLatLng, this.getMouseCoordinates()]); this.#destinationPreviewHandleLine.setLatLngs([groupLatLng, this.getMouseCoordinates()]);
this.#destinationPreviewHandle.setLatLng(this.getMouseCoordinates()); this.#destinationPreviewHandle.setLatLng(this.getMouseCoordinates());
}
} }
#hideDestinationCursors() { #hideDestinationCursors() {
@@ -861,7 +857,7 @@ export class Map extends L.Map {
#setVisibilityOption(option: string, ev: any) { #setVisibilityOption(option: string, ev: any) {
this.#visibilityOptions[option] = ev.currentTarget.checked; this.#visibilityOptions[option] = ev.currentTarget.checked;
document.dispatchEvent(new CustomEvent("mapVisibilityOptionsChanged")); document.dispatchEvent(new CustomEvent("mapOptionsChanged"));
} }
getMapMarkerControls() { getMapMarkerControls() {

View File

@@ -2,16 +2,13 @@ import { SVGInjector } from "@tanem/svg-injector";
import { getApp } from ".."; import { getApp } from "..";
import { Dropdown } from "../controls/dropdown"; import { Dropdown } from "../controls/dropdown";
import { Slider } from "../controls/slider"; import { Slider } from "../controls/slider";
import { aircraftDatabase } from "../unit/databases/aircraftdatabase";
import { Unit } from "../unit/unit"; import { Unit } from "../unit/unit";
import { Panel } from "./panel"; import { Panel } from "./panel";
import { Switch } from "../controls/switch"; import { Switch } from "../controls/switch";
import { ROEDescriptions, ROEs, altitudeIncrements, emissionsCountermeasures, emissionsCountermeasuresDescriptions, maxAltitudeValues, maxSpeedValues, minAltitudeValues, minSpeedValues, reactionsToThreat, reactionsToThreatDescriptions, shotsIntensityDescriptions, shotsScatterDescriptions, speedIncrements } from "../constants/constants"; import { ROEDescriptions, ROEs, altitudeIncrements, emissionsCountermeasures, emissionsCountermeasuresDescriptions, maxAltitudeValues, maxSpeedValues, minAltitudeValues, minSpeedValues, reactionsToThreat, reactionsToThreatDescriptions, shotsIntensityDescriptions, shotsScatterDescriptions, speedIncrements } from "../constants/constants";
import { ftToM, knotsToMs, mToFt, msToKnots } from "../other/utils"; import { ftToM, knotsToMs, mToFt, msToKnots } from "../other/utils";
import { GeneralSettings, Radio, TACAN } from "../interfaces"; import { GeneralSettings, Radio, TACAN } from "../interfaces";
import { PrimaryToolbar } from "../toolbars/primarytoolbar";
import { ContextActionSet } from "../unit/contextactionset"; import { ContextActionSet } from "../unit/contextactionset";
import { ContextAction } from "../unit/contextaction";
export class UnitControlPanel extends Panel { export class UnitControlPanel extends Panel {
#altitudeSlider: Slider; #altitudeSlider: Slider;
@@ -36,36 +33,36 @@ export class UnitControlPanel extends Panel {
* *
* @param ID - the ID of the HTML element which will contain the context menu * @param ID - the ID of the HTML element which will contain the context menu
*/ */
constructor(ID: string){ constructor(ID: string) {
super(ID); super(ID);
/* Unit control sliders */ /* Unit control sliders */
this.#altitudeSlider = new Slider("altitude-slider", 0, 100, "ft", (value: number) => { getApp().getUnitsManager().setAltitude(ftToM(value)); }); this.#altitudeSlider = new Slider("altitude-slider", 0, 100, "ft", (value: number) => { getApp().getUnitsManager().setAltitude(ftToM(value)); });
this.#altitudeTypeSwitch = new Switch("altitude-type-switch", (value: boolean) => { getApp().getUnitsManager().setAltitudeType(value? "ASL": "AGL"); }); this.#altitudeTypeSwitch = new Switch("altitude-type-switch", (value: boolean) => { getApp().getUnitsManager().setAltitudeType(value ? "ASL" : "AGL"); });
this.#speedSlider = new Slider("speed-slider", 0, 100, "kts", (value: number) => { getApp().getUnitsManager().setSpeed(knotsToMs(value)); }); this.#speedSlider = new Slider("speed-slider", 0, 100, "kts", (value: number) => { getApp().getUnitsManager().setSpeed(knotsToMs(value)); });
this.#speedTypeSwitch = new Switch("speed-type-switch", (value: boolean) => { getApp().getUnitsManager().setSpeedType(value? "CAS": "GS"); }); this.#speedTypeSwitch = new Switch("speed-type-switch", (value: boolean) => { getApp().getUnitsManager().setSpeedType(value ? "CAS" : "GS"); });
/* Option buttons */ /* Option buttons */
// Reversing the ROEs so that the least "aggressive" option is always on the left // Reversing the ROEs so that the least "aggressive" option is always on the left
this.#optionButtons["ROE"] = ROEs.slice(0).reverse().map((option: string, index: number) => { this.#optionButtons["ROE"] = ROEs.slice(0).reverse().map((option: string, index: number) => {
return this.#createOptionButton(option, `roe/${option.toLowerCase()}.svg`, ROEDescriptions.slice(0).reverse()[index], () => { getApp().getUnitsManager().setROE(option); }); return this.#createOptionButton(option, `roe/${option.toLowerCase()}.svg`, ROEDescriptions.slice(0).reverse()[index], () => { getApp().getUnitsManager().setROE(option); });
}).filter((button: HTMLButtonElement, index: number) => {return ROEs[index] !== "";}); }).filter((button: HTMLButtonElement, index: number) => { return ROEs[index] !== ""; });
this.#optionButtons["reactionToThreat"] = reactionsToThreat.map((option: string, index: number) => { this.#optionButtons["reactionToThreat"] = reactionsToThreat.map((option: string, index: number) => {
return this.#createOptionButton(option, `threat/${option.toLowerCase()}.svg`, reactionsToThreatDescriptions[index],() => { getApp().getUnitsManager().setReactionToThreat(option); }); return this.#createOptionButton(option, `threat/${option.toLowerCase()}.svg`, reactionsToThreatDescriptions[index], () => { getApp().getUnitsManager().setReactionToThreat(option); });
}); });
this.#optionButtons["emissionsCountermeasures"] = emissionsCountermeasures.map((option: string, index: number) => { this.#optionButtons["emissionsCountermeasures"] = emissionsCountermeasures.map((option: string, index: number) => {
return this.#createOptionButton(option, `emissions/${option.toLowerCase()}.svg`, emissionsCountermeasuresDescriptions[index],() => { getApp().getUnitsManager().setEmissionsCountermeasures(option); }); return this.#createOptionButton(option, `emissions/${option.toLowerCase()}.svg`, emissionsCountermeasuresDescriptions[index], () => { getApp().getUnitsManager().setEmissionsCountermeasures(option); });
}); });
this.#optionButtons["shotsScatter"] = [1, 2, 3].map((option: number, index: number) => { this.#optionButtons["shotsScatter"] = [1, 2, 3].map((option: number, index: number) => {
return this.#createOptionButton(option.toString(), `scatter/${option.toString().toLowerCase()}.svg`, shotsScatterDescriptions[index],() => { getApp().getUnitsManager().setShotsScatter(option); }); return this.#createOptionButton(option.toString(), `scatter/${option.toString().toLowerCase()}.svg`, shotsScatterDescriptions[index], () => { getApp().getUnitsManager().setShotsScatter(option); });
}); });
this.#optionButtons["shotsIntensity"] = [1, 2, 3].map((option: number, index: number) => { this.#optionButtons["shotsIntensity"] = [1, 2, 3].map((option: number, index: number) => {
return this.#createOptionButton(option.toString(), `intensity/${option.toString().toLowerCase()}.svg`, shotsIntensityDescriptions[index],() => { getApp().getUnitsManager().setShotsIntensity(option); }); return this.#createOptionButton(option.toString(), `intensity/${option.toString().toLowerCase()}.svg`, shotsIntensityDescriptions[index], () => { getApp().getUnitsManager().setShotsIntensity(option); });
}); });
this.getElement().querySelector("#roe-buttons-container")?.append(...this.#optionButtons["ROE"]); this.getElement().querySelector("#roe-buttons-container")?.append(...this.#optionButtons["ROE"]);
@@ -110,29 +107,29 @@ export class UnitControlPanel extends Panel {
/* Mouseover of (?) highlights activation buttons */ /* Mouseover of (?) highlights activation buttons */
const operateAsQuestionMark = <HTMLElement>this.getElement().querySelector("#operate-as h4 img"); const operateAsQuestionMark = <HTMLElement>this.getElement().querySelector("#operate-as h4 img");
operateAsQuestionMark.addEventListener("mouseover", () => { operateAsQuestionMark.addEventListener("mouseover", () => {
document.querySelectorAll(`#rapid-controls button.scenic-action`).forEach((btn:Element) => { document.querySelectorAll(`#rapid-controls button.scenic-action`).forEach((btn: Element) => {
btn.classList.add(`pulse`); btn.classList.add(`pulse`);
}); });
}); });
operateAsQuestionMark.addEventListener("mouseout", () => { operateAsQuestionMark.addEventListener("mouseout", () => {
document.querySelectorAll(`#rapid-controls button.scenic-action.pulse`).forEach((btn:Element) => { document.querySelectorAll(`#rapid-controls button.scenic-action.pulse`).forEach((btn: Element) => {
btn.classList.remove(`pulse`); btn.classList.remove(`pulse`);
}); });
}); });
/* Advanced settings dialog */ /* Advanced settings dialog */
this.#advancedSettingsDialog = <HTMLElement> document.querySelector("#advanced-settings-dialog"); this.#advancedSettingsDialog = <HTMLElement>document.querySelector("#advanced-settings-dialog");
/* Advanced settings dropdowns */ /* Advanced settings dropdowns */
this.#TACANXYDropdown = new Dropdown("TACAN-XY", () => {}); this.#TACANXYDropdown = new Dropdown("TACAN-XY", () => { });
this.#TACANXYDropdown.setOptions(["X", "Y"]); this.#TACANXYDropdown.setOptions(["X", "Y"]);
this.#radioDecimalsDropdown = new Dropdown("radio-decimals", () => {}); this.#radioDecimalsDropdown = new Dropdown("radio-decimals", () => { });
this.#radioDecimalsDropdown.setOptions([".000", ".250", ".500", ".750"]); this.#radioDecimalsDropdown.setOptions([".000", ".250", ".500", ".750"]);
this.#radioCallsignDropdown = new Dropdown("radio-callsign", () => {}); this.#radioCallsignDropdown = new Dropdown("radio-callsign", () => { });
this.#deleteDropdown = new Dropdown("delete-options", () => { }); this.#deleteDropdown = new Dropdown("delete-options", () => { });
/* Events and timer */ /* Events and timer */
window.setInterval(() => {this.update();}, 25); window.setInterval(() => { this.update(); }, 25);
document.addEventListener("unitsSelection", (e: CustomEvent<Unit[]>) => { document.addEventListener("unitsSelection", (e: CustomEvent<Unit[]>) => {
this.show(); this.show();
@@ -143,14 +140,16 @@ export class UnitControlPanel extends Panel {
this.hide(); this.hide();
this.#updateRapidControls(); this.#updateRapidControls();
}); });
document.addEventListener("applyAdvancedSettings", () => {this.#applyAdvancedSettings();}) document.addEventListener("applyAdvancedSettings", () => { this.#applyAdvancedSettings(); })
document.addEventListener("showAdvancedSettings", () => { document.addEventListener("showAdvancedSettings", () => {
this.#updateAdvancedSettingsDialog(getApp().getUnitsManager().getSelectedUnits()); this.#updateAdvancedSettingsDialog(getApp().getUnitsManager().getSelectedUnits());
this.#advancedSettingsDialog.classList.remove("hide"); this.#advancedSettingsDialog.classList.remove("hide");
}); });
/* This is for when a ctrl-click happens on the map for deselection and we need to remove the selected unit from the panel */ /* This is for when a ctrl-click happens on the map for deselection and we need to remove the selected unit from the panel */
document.addEventListener( "unitsDeselection", ( ev:CustomEventInit ) => { document.addEventListener("unitsDeselection", (ev: CustomEventInit) => {
this.getElement().querySelector( `button[data-unit-id="${ev.detail.ID}"]` )?.remove(); this.show();
this.addButtons();
this.#updateRapidControls(); this.#updateRapidControls();
}); });
@@ -166,7 +165,7 @@ export class UnitControlPanel extends Panel {
show() { show() {
const context = getApp().getCurrentContext(); const context = getApp().getCurrentContext();
if ( !context.getUseUnitControlPanel() ) if (!context.getUseUnitControlPanel())
return; return;
super.show(); super.show();
@@ -191,19 +190,19 @@ export class UnitControlPanel extends Panel {
var callsign = unit.getUnitName() || ""; var callsign = unit.getUnitName() || "";
var label = unit.getDatabase()?.getByName(unit.getName())?.label || unit.getName(); var label = unit.getDatabase()?.getByName(unit.getName())?.label || unit.getName();
button.setAttribute("data-unit-id", "" + unit.ID ); button.setAttribute("data-unit-id", "" + unit.ID);
button.setAttribute("data-label", label); button.setAttribute("data-label", label);
button.setAttribute("data-callsign", callsign); button.setAttribute("data-callsign", callsign);
button.setAttribute("data-coalition", unit.getCoalition()); button.setAttribute("data-coalition", unit.getCoalition());
button.classList.add("pill", "highlight-coalition") button.classList.add("pill", "highlight-coalition")
button.addEventListener("click", ( ev:MouseEventInit ) => { button.addEventListener("click", (ev: MouseEventInit) => {
// Ctrl-click deselection // Ctrl-click deselection
if ( ev.ctrlKey === true && ev.shiftKey === false && ev.altKey === false ) { if (ev.ctrlKey === true && ev.shiftKey === false && ev.altKey === false) {
getApp().getUnitsManager().deselectUnit( unit.ID ); getApp().getUnitsManager().deselectUnit(unit.ID);
button.remove(); button.remove();
// Deselect all // Deselect all
} else { } else {
getApp().getUnitsManager().deselectAllUnits(); getApp().getUnitsManager().deselectAllUnits();
getApp().getUnitsManager().selectUnit(unit.ID, true); getApp().getUnitsManager().selectUnit(unit.ID, true);
@@ -219,14 +218,14 @@ export class UnitControlPanel extends Panel {
} }
update() { update() {
if (this.getVisible()){ if (this.getVisible()) {
const element = this.getElement(); const element = this.getElement();
if (element != null && this.#units.length > 0) { if (element != null && this.#units.length > 0) {
/* Toggle visibility of control elements */ /* Toggle visibility of control elements */
var isTanker = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.isTanker();}); var isTanker = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => { return unit.isTanker(); });
var isAWACS = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.isAWACS();}); var isAWACS = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => { return unit.isAWACS(); });
var isActiveTanker = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getIsActiveTanker()}); var isActiveTanker = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => { return unit.getIsActiveTanker() });
var isActiveAWACAS = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getIsActiveAWACS()}); var isActiveAWACAS = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => { return unit.getIsActiveAWACS() });
element.toggleAttribute("data-show-categories-tooltip", this.#selectedUnitsTypes.length > 1); element.toggleAttribute("data-show-categories-tooltip", this.#selectedUnitsTypes.length > 1);
element.toggleAttribute("data-show-speed-slider", this.#selectedUnitsTypes.length == 1); element.toggleAttribute("data-show-speed-slider", this.#selectedUnitsTypes.length == 1);
@@ -236,11 +235,11 @@ export class UnitControlPanel extends Panel {
element.toggleAttribute("data-show-emissions-countermeasures", (this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter")) && !(this.#selectedUnitsTypes.includes("GroundUnit") || this.#selectedUnitsTypes.includes("NavyUnit"))); element.toggleAttribute("data-show-emissions-countermeasures", (this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter")) && !(this.#selectedUnitsTypes.includes("GroundUnit") || this.#selectedUnitsTypes.includes("NavyUnit")));
element.toggleAttribute("data-show-shots-scatter", this.#selectedUnitsTypes.includes("GroundUnit")); //TODO: more refined element.toggleAttribute("data-show-shots-scatter", this.#selectedUnitsTypes.includes("GroundUnit")); //TODO: more refined
element.toggleAttribute("data-show-shots-intensity", this.#selectedUnitsTypes.includes("GroundUnit")); //TODO: more refined element.toggleAttribute("data-show-shots-intensity", this.#selectedUnitsTypes.includes("GroundUnit")); //TODO: more refined
element.toggleAttribute("data-show-tanker-button", getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.isTanker();}) === true); element.toggleAttribute("data-show-tanker-button", getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => { return unit.isTanker(); }) === true);
element.toggleAttribute("data-show-AWACS-button", getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.isAWACS();}) === true); element.toggleAttribute("data-show-AWACS-button", getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => { return unit.isAWACS(); }) === true);
element.toggleAttribute("data-show-on-off", (this.#selectedUnitsTypes.includes("GroundUnit") || this.#selectedUnitsTypes.includes("NavyUnit")) && !(this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter"))); element.toggleAttribute("data-show-on-off", (this.#selectedUnitsTypes.includes("GroundUnit") || this.#selectedUnitsTypes.includes("NavyUnit")) && !(this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter")));
element.toggleAttribute("data-show-follow-roads", (this.#selectedUnitsTypes.length == 1 && this.#selectedUnitsTypes.includes("GroundUnit"))); element.toggleAttribute("data-show-follow-roads", (this.#selectedUnitsTypes.length == 1 && this.#selectedUnitsTypes.includes("GroundUnit")));
element.toggleAttribute("data-show-operate-as", getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getCoalition()}) === "neutral"); element.toggleAttribute("data-show-operate-as", getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => { return unit.getCoalition() }) === "neutral");
if (this.#units.length == 1) { if (this.#units.length == 1) {
if (isAWACS) if (isAWACS)
@@ -253,18 +252,18 @@ export class UnitControlPanel extends Panel {
if (this.#selectedUnitsTypes.length == 1) { if (this.#selectedUnitsTypes.length == 1) {
/* Flight controls */ /* Flight controls */
var desiredAltitude = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredAltitude()}); var desiredAltitude = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => { return unit.getDesiredAltitude() });
var desiredAltitudeType = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredAltitudeType()}); var desiredAltitudeType = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => { return unit.getDesiredAltitudeType() });
var desiredSpeed = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredSpeed()}); var desiredSpeed = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => { return unit.getDesiredSpeed() });
var desiredSpeedType = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredSpeedType()}); var desiredSpeedType = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => { return unit.getDesiredSpeedType() });
var isActiveTanker = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getIsActiveTanker()}); var isActiveTanker = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => { return unit.getIsActiveTanker() });
var isActiveAWACAS = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getIsActiveAWACS()}); var isActiveAWACAS = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => { return unit.getIsActiveAWACS() });
var onOff = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getOnOff()}); var onOff = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => { return unit.getOnOff() });
var followRoads = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getFollowRoads()}); var followRoads = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => { return unit.getFollowRoads() });
var operateAs = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getOperateAs()}); var operateAs = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => { return unit.getOperateAs() });
this.#altitudeTypeSwitch.setValue(desiredAltitudeType != undefined? desiredAltitudeType == "ASL": undefined, false); this.#altitudeTypeSwitch.setValue(desiredAltitudeType != undefined ? desiredAltitudeType == "ASL" : undefined, false);
this.#speedTypeSwitch.setValue(desiredSpeedType != undefined? desiredSpeedType == "CAS": undefined, false); this.#speedTypeSwitch.setValue(desiredSpeedType != undefined ? desiredSpeedType == "CAS" : undefined, false);
this.#speedSlider.setMinMax(minSpeedValues[this.#selectedUnitsTypes[0]], maxSpeedValues[this.#selectedUnitsTypes[0]]); this.#speedSlider.setMinMax(minSpeedValues[this.#selectedUnitsTypes[0]], maxSpeedValues[this.#selectedUnitsTypes[0]]);
this.#altitudeSlider.setMinMax(minAltitudeValues[this.#selectedUnitsTypes[0]], maxAltitudeValues[this.#selectedUnitsTypes[0]]); this.#altitudeSlider.setMinMax(minAltitudeValues[this.#selectedUnitsTypes[0]], maxAltitudeValues[this.#selectedUnitsTypes[0]]);
@@ -309,7 +308,7 @@ export class UnitControlPanel extends Panel {
this.#AWACSSwitch.setValue(isActiveAWACAS, false); this.#AWACSSwitch.setValue(isActiveAWACAS, false);
this.#onOffSwitch.setValue(onOff, false); this.#onOffSwitch.setValue(onOff, false);
this.#followRoadsSwitch.setValue(followRoads, false); this.#followRoadsSwitch.setValue(followRoads, false);
this.#operateAsSwitch.setValue(operateAs? operateAs === "blue": undefined, false); this.#operateAsSwitch.setValue(operateAs ? operateAs === "blue" : undefined, false);
} }
} }
} }
@@ -318,7 +317,7 @@ export class UnitControlPanel extends Panel {
var contextActionSet = new ContextActionSet(); var contextActionSet = new ContextActionSet();
var units = getApp().getUnitsManager().getSelectedUnits(); var units = getApp().getUnitsManager().getSelectedUnits();
var showAltitudeChange = units.some((unit: Unit) => {return ["Aircraft", "Helicopter"].includes(unit.getCategory());}); var showAltitudeChange = units.some((unit: Unit) => { return ["Aircraft", "Helicopter"].includes(unit.getCategory()); });
this.getElement().querySelector("#climb")?.classList.toggle("hide", !showAltitudeChange); this.getElement().querySelector("#climb")?.classList.toggle("hide", !showAltitudeChange);
this.getElement().querySelector("#descend")?.classList.toggle("hide", !showAltitudeChange); this.getElement().querySelector("#descend")?.classList.toggle("hide", !showAltitudeChange);
@@ -347,10 +346,8 @@ export class UnitControlPanel extends Panel {
} }
} }
#updateAdvancedSettingsDialog(units: Unit[]) #updateAdvancedSettingsDialog(units: Unit[]) {
{ if (units.length == 1) {
if (units.length == 1)
{
/* HTML Elements */ /* HTML Elements */
const unitNameEl = this.#advancedSettingsDialog.querySelector("#unit-name") as HTMLElement; const unitNameEl = this.#advancedSettingsDialog.querySelector("#unit-name") as HTMLElement;
const prohibitJettisonCheckbox = this.#advancedSettingsDialog.querySelector("#prohibit-jettison-checkbox")?.querySelector("input") as HTMLInputElement; const prohibitJettisonCheckbox = this.#advancedSettingsDialog.querySelector("#prohibit-jettison-checkbox")?.querySelector("input") as HTMLInputElement;
@@ -414,8 +411,7 @@ export class UnitControlPanel extends Panel {
} }
} }
#applyAdvancedSettings() #applyAdvancedSettings() {
{
/* HTML Elements */ /* HTML Elements */
const prohibitJettisonCheckbox = this.#advancedSettingsDialog.querySelector("#prohibit-jettison-checkbox")?.querySelector("input") as HTMLInputElement; const prohibitJettisonCheckbox = this.#advancedSettingsDialog.querySelector("#prohibit-jettison-checkbox")?.querySelector("input") as HTMLInputElement;
const prohibitAfterburnerCheckbox = this.#advancedSettingsDialog.querySelector("#prohibit-afterburner-checkbox")?.querySelector("input") as HTMLInputElement; const prohibitAfterburnerCheckbox = this.#advancedSettingsDialog.querySelector("#prohibit-afterburner-checkbox")?.querySelector("input") as HTMLInputElement;
@@ -431,7 +427,7 @@ export class UnitControlPanel extends Panel {
/* TACAN */ /* TACAN */
const TACAN: TACAN = { const TACAN: TACAN = {
isOn: TACANCheckbox.checked? true: false, isOn: TACANCheckbox.checked ? true : false,
channel: Number(TACANChannelInput.value), channel: Number(TACANChannelInput.value),
XY: this.#TACANXYDropdown.getValue(), XY: this.#TACANXYDropdown.getValue(),
callsign: TACANCallsignInput.value as string callsign: TACANCallsignInput.value as string
@@ -443,16 +439,16 @@ export class UnitControlPanel extends Panel {
const radio: Radio = { const radio: Radio = {
frequency: (radioMHz * 1000 + Number(radioDecimals.substring(1))) * 1000, frequency: (radioMHz * 1000 + Number(radioDecimals.substring(1))) * 1000,
callsign: this.#radioCallsignDropdown.getIndex() + 1, callsign: this.#radioCallsignDropdown.getIndex() + 1,
callsignNumber: Number(radioCallsignNumberInput.value) callsignNumber: Number(radioCallsignNumberInput.value)
} }
/* General settings */ /* General settings */
const generalSettings: GeneralSettings = { const generalSettings: GeneralSettings = {
prohibitJettison: prohibitJettisonCheckbox.checked? true: false, prohibitJettison: prohibitJettisonCheckbox.checked ? true : false,
prohibitAfterburner: prohibitAfterburnerCheckbox.checked? true: false, prohibitAfterburner: prohibitAfterburnerCheckbox.checked ? true : false,
prohibitAA: prohibitAACheckbox.checked? true: false, prohibitAA: prohibitAACheckbox.checked ? true : false,
prohibitAG: prohibitAGCheckbox.checked? true: false, prohibitAG: prohibitAGCheckbox.checked ? true : false,
prohibitAirWpn: prohibitAirWpnCheckbox.checked? true: false prohibitAirWpn: prohibitAirWpnCheckbox.checked ? true : false
} }
/* Send command and close */ /* Send command and close */

View File

@@ -190,15 +190,17 @@ export abstract class Unit extends CustomMarker {
/* Deselect units if they are hidden */ /* Deselect units if they are hidden */
document.addEventListener("toggleCoalitionVisibility", (ev: CustomEventInit) => { document.addEventListener("toggleCoalitionVisibility", (ev: CustomEventInit) => {
window.setTimeout(() => { this.setSelected(this.getSelected() && !this.getHidden()) }, 300); this.#updateMarker();
this.setSelected(this.getSelected() && !this.getHidden());
}); });
document.addEventListener("toggleUnitVisibility", (ev: CustomEventInit) => { document.addEventListener("toggleMarkerVisibility", (ev: CustomEventInit) => {
window.setTimeout(() => { this.setSelected(this.getSelected() && !this.getHidden()) }, 300); this.#updateMarker();
this.setSelected(this.getSelected() && !this.getHidden());
}); });
/* Update the marker when the visibility options change */ /* Update the marker when the options change */
document.addEventListener("mapVisibilityOptionsChanged", (ev: CustomEventInit) => { document.addEventListener("mapOptionsChanged", (ev: CustomEventInit) => {
this.#updateMarker(); this.#updateMarker();
/* Circles don't like to be updated when the map is zooming */ /* Circles don't like to be updated when the map is zooming */
@@ -684,14 +686,11 @@ export abstract class Unit extends CustomMarker {
/* Hide the unit if it does not belong to the commanded coalition and it is not detected by a method that can pinpoint its location (RWR does not count) */ /* Hide the unit if it does not belong to the commanded coalition and it is not detected by a method that can pinpoint its location (RWR does not count) */
(!this.belongsToCommandedCoalition() && (this.#detectionMethods.length == 0 || (this.#detectionMethods.length == 1 && this.#detectionMethods[0] === RWR))) || (!this.belongsToCommandedCoalition() && (this.#detectionMethods.length == 0 || (this.#detectionMethods.length == 1 && this.#detectionMethods[0] === RWR))) ||
/* Hide the unit if grouping is activated, the unit is not the group leader, it is not selected, and the zoom is higher than the grouping threshold */ /* Hide the unit if grouping is activated, the unit is not the group leader, it is not selected, and the zoom is higher than the grouping threshold */
(getApp().getMap().getVisibilityOptions()[HIDE_GROUP_MEMBERS] && !this.#isLeader && this.getCategory() == "GroundUnit" && getApp().getMap().getZoom() < GROUPING_ZOOM_TRANSITION && (getApp().getMap().getVisibilityOptions()[HIDE_GROUP_MEMBERS] && !this.#isLeader && !this.getSelected() && this.getCategory() == "GroundUnit" && getApp().getMap().getZoom() < GROUPING_ZOOM_TRANSITION &&
(this.belongsToCommandedCoalition() || (!this.belongsToCommandedCoalition() && this.#detectionMethods.length == 0)))); (this.belongsToCommandedCoalition() || (!this.belongsToCommandedCoalition() && this.#detectionMethods.length == 0))));
/* Force dead units to be hidden */ /* Force dead units to be hidden */
this.setHidden(hidden || !this.getAlive()); this.setHidden(hidden || !this.getAlive());
/* Force hidden units to be unselected */
this.setSelected(this.getSelected() && !this.getHidden());
} }
setHidden(hidden: boolean) { setHidden(hidden: boolean) {
@@ -1254,11 +1253,13 @@ export abstract class Unit extends CustomMarker {
} }
#clearPath() { #clearPath() {
for (let WP in this.#pathMarkers) { if (this.#pathPolyline.getLatLngs().length != 0) {
getApp().getMap().removeLayer(this.#pathMarkers[WP]); for (let WP in this.#pathMarkers) {
getApp().getMap().removeLayer(this.#pathMarkers[WP]);
}
this.#pathMarkers = [];
this.#pathPolyline.setLatLngs([]);
} }
this.#pathMarkers = [];
this.#pathPolyline.setLatLngs([]);
} }
#drawContacts() { #drawContacts() {

View File

@@ -6,7 +6,7 @@ import { CoalitionArea } from "../map/coalitionarea/coalitionarea";
import { groundUnitDatabase } from "./databases/groundunitdatabase"; import { groundUnitDatabase } from "./databases/groundunitdatabase";
import { DELETE_CYCLE_TIME, DELETE_SLOW_THRESHOLD, DataIndexes, GAME_MASTER, IADSDensities, IDLE, MOVE_UNIT } from "../constants/constants"; import { DELETE_CYCLE_TIME, DELETE_SLOW_THRESHOLD, DataIndexes, GAME_MASTER, IADSDensities, IDLE, MOVE_UNIT } from "../constants/constants";
import { DataExtractor } from "../server/dataextractor"; import { DataExtractor } from "../server/dataextractor";
import { citiesDatabase } from "./citiesDatabase"; import { citiesDatabase } from "./databases/citiesdatabase";
import { aircraftDatabase } from "./databases/aircraftdatabase"; import { aircraftDatabase } from "./databases/aircraftdatabase";
import { helicopterDatabase } from "./databases/helicopterdatabase"; import { helicopterDatabase } from "./databases/helicopterdatabase";
import { navyUnitDatabase } from "./databases/navyunitdatabase"; import { navyUnitDatabase } from "./databases/navyunitdatabase";
@@ -321,11 +321,13 @@ export class UnitsManager {
getUnitsVariable(variableGetter: CallableFunction, units: Unit[]) { getUnitsVariable(variableGetter: CallableFunction, units: Unit[]) {
if (units.length == 0) if (units.length == 0)
return undefined; return undefined;
return units.map((unit: Unit) => {
return variableGetter(unit); var value: any = variableGetter(units[0]);
})?.reduce((a: any, b: any) => { units.forEach((unit: Unit) => {
return a === b ? a : undefined if (variableGetter(unit) !== value)
return undefined;
}); });
return value;
}; };
/** For a given unit, it returns if and how it is being detected by other units. NOTE: this function will return how a unit is being detected, i.e. how other units are detecting it. It will not return /** For a given unit, it returns if and how it is being detected by other units. NOTE: this function will return how a unit is being detected, i.e. how other units are detecting it. It will not return
@@ -353,6 +355,7 @@ export class UnitsManager {
* @param latlng Position of the new destination * @param latlng Position of the new destination
* @param mantainRelativePosition If true, the selected units will mantain their relative positions when reaching the target. This is useful to maintain a formation for groun/navy units * @param mantainRelativePosition If true, the selected units will mantain their relative positions when reaching the target. This is useful to maintain a formation for groun/navy units
* @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 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) if (units === null)
@@ -412,6 +415,7 @@ export class UnitsManager {
/** Instruct all the selected units to land at a specific location /** Instruct all the selected units to land at a specific location
* *
* @param latlng Location where to land at * @param latlng Location where to land at
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
landAt(latlng: LatLng, units: Unit[] | null = null) { landAt(latlng: LatLng, units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -428,6 +432,7 @@ export class UnitsManager {
/** Instruct all the selected units to change their speed /** Instruct all the selected units to change their speed
* *
* @param speedChange Speed change, either "stop", "slow", or "fast". The specific value depends on the unit category * @param speedChange Speed change, either "stop", "slow", or "fast". The specific value depends on the unit category
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
changeSpeed(speedChange: string, units: Unit[] | null = null) { changeSpeed(speedChange: string, units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -442,6 +447,7 @@ export class UnitsManager {
/** Instruct all the selected units to change their altitude /** Instruct all the selected units to change their altitude
* *
* @param altitudeChange Altitude change, either "climb" or "descend". The specific value depends on the unit category * @param altitudeChange Altitude change, either "climb" or "descend". The specific value depends on the unit category
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
changeAltitude(altitudeChange: string, units: Unit[] | null = null) { changeAltitude(altitudeChange: string, units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -456,6 +462,7 @@ export class UnitsManager {
/** Set a specific speed to all the selected units /** Set a specific speed to all the selected units
* *
* @param speed Value to set, in m/s * @param speed Value to set, in m/s
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
setSpeed(speed: number, units: Unit[] | null = null) { setSpeed(speed: number, units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -471,6 +478,7 @@ export class UnitsManager {
/** Set a specific speed type to all the selected units /** Set a specific speed type to all the selected units
* *
* @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. * @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.
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
setSpeedType(speedType: string, units: Unit[] | null = null) { setSpeedType(speedType: string, units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -486,6 +494,7 @@ export class UnitsManager {
/** Set a specific altitude to all the selected units /** Set a specific altitude to all the selected units
* *
* @param altitude Value to set, in m * @param altitude Value to set, in m
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
setAltitude(altitude: number, units: Unit[] | null = null) { setAltitude(altitude: number, units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -501,6 +510,7 @@ export class UnitsManager {
/** Set a specific altitude type to all the selected units /** Set a specific altitude type to all the selected units
* *
* @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. * @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.
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
setAltitudeType(altitudeType: string, units: Unit[] | null = null) { setAltitudeType(altitudeType: string, units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -516,6 +526,7 @@ export class UnitsManager {
/** Set a specific ROE to all the selected units /** Set a specific ROE to all the selected units
* *
* @param ROE Value to set, see constants for acceptable values * @param ROE 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.
*/ */
setROE(ROE: string, units: Unit[] | null = null) { setROE(ROE: string, units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -531,6 +542,7 @@ export class UnitsManager {
/** Set a specific reaction to threat to all the selected units /** Set a specific reaction to threat to all the selected units
* *
* @param reactionToThreat Value to set, see constants for acceptable values * @param reactionToThreat 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.
*/ */
setReactionToThreat(reactionToThreat: string, units: Unit[] | null = null) { setReactionToThreat(reactionToThreat: string, units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -546,6 +558,7 @@ export class UnitsManager {
/** Set a specific emissions & countermeasures to all the selected units /** Set a specific emissions & countermeasures to all the selected units
* *
* @param emissionCountermeasure Value to set, see constants for acceptable values * @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) if (units === null)
@@ -561,6 +574,7 @@ export class UnitsManager {
/** Turn selected units on or off, only works on ground and navy units /** Turn selected units on or off, only works on ground and navy units
* *
* @param onOff If true, the unit will be turned on * @param onOff If true, the unit will be turned on
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
setOnOff(onOff: boolean, units: Unit[] | null = null) { setOnOff(onOff: boolean, units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -576,6 +590,7 @@ export class UnitsManager {
/** Instruct the selected units to follow roads, only works on ground units /** Instruct the selected units to follow roads, only works on ground units
* *
* @param followRoads If true, units will follow roads * @param followRoads If true, units will follow roads
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
setFollowRoads(followRoads: boolean, units: Unit[] | null = null) { setFollowRoads(followRoads: boolean, units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -591,6 +606,7 @@ export class UnitsManager {
/** Instruct selected units to operate as a certain coalition /** Instruct selected units to operate as a certain coalition
* *
* @param operateAsBool If true, units will operate as blue * @param operateAsBool If true, units will operate as blue
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
setOperateAs(operateAsBool: boolean, units: Unit[] | null = null) { setOperateAs(operateAsBool: boolean, units: Unit[] | null = null) {
var operateAs = operateAsBool ? "blue" : "red"; var operateAs = operateAsBool ? "blue" : "red";
@@ -607,6 +623,7 @@ export class UnitsManager {
/** Instruct units to attack a specific unit /** Instruct units to attack a specific unit
* *
* @param ID ID of the unit to attack * @param ID ID of the unit to attack
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
attackUnit(ID: number, units: Unit[] | null = null) { attackUnit(ID: number, units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -620,7 +637,7 @@ export class UnitsManager {
} }
/** Instruct units to refuel at the nearest tanker, if possible. Else units will RTB /** Instruct units to refuel at the nearest tanker, if possible. Else units will RTB
* * @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
refuel(units: Unit[] | null = null) { refuel(units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -638,6 +655,7 @@ export class UnitsManager {
* @param ID ID of the unit to follow * @param ID ID of the unit to follow
* @param offset Optional parameter, defines a static offset. X: front-rear, positive front, Y: top-bottom, positive top, Z: left-right, positive right * @param offset Optional parameter, defines a static offset. X: front-rear, positive front, Y: top-bottom, positive top, Z: left-right, positive right
* @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 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) if (units === null)
@@ -690,6 +708,7 @@ export class UnitsManager {
/** Instruct the selected units to perform precision bombing of specific coordinates /** Instruct the selected units to perform precision bombing of specific coordinates
* *
* @param latlng Location to bomb * @param latlng Location to bomb
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
bombPoint(latlng: LatLng, units: Unit[] | null = null) { bombPoint(latlng: LatLng, units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -705,6 +724,7 @@ export class UnitsManager {
/** Instruct the selected units to perform carpet bombing of specific coordinates /** Instruct the selected units to perform carpet bombing of specific coordinates
* *
* @param latlng Location to bomb * @param latlng Location to bomb
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
carpetBomb(latlng: LatLng, units: Unit[] | null = null) { carpetBomb(latlng: LatLng, units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -720,6 +740,7 @@ export class UnitsManager {
/** Instruct the selected units to fire at specific coordinates /** Instruct the selected units to fire at specific coordinates
* *
* @param latlng Location to fire at * @param latlng Location to fire at
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
fireAtArea(latlng: LatLng, units: Unit[] | null = null) { fireAtArea(latlng: LatLng, units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -735,6 +756,7 @@ export class UnitsManager {
/** Instruct the selected units to simulate a fire fight at specific coordinates /** Instruct the selected units to simulate a fire fight at specific coordinates
* *
* @param latlng Location to fire at * @param latlng Location to fire at
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
simulateFireFight(latlng: LatLng, units: Unit[] | null = null) { simulateFireFight(latlng: LatLng, units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -756,7 +778,7 @@ export class UnitsManager {
} }
/** Instruct units to enter into scenic AAA mode. Units will shoot in the air without aiming /** Instruct units to enter into scenic AAA mode. Units will shoot in the air without aiming
* * @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
scenicAAA(units: Unit[] | null = null) { scenicAAA(units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -770,7 +792,7 @@ export class UnitsManager {
} }
/** Instruct units to enter into miss on purpose mode. Units will aim to the nearest enemy unit but not precisely. /** Instruct units to enter into miss on purpose mode. Units will aim to the nearest enemy unit but not precisely.
* * @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
missOnPurpose(units: Unit[] | null = null) { missOnPurpose(units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -786,6 +808,7 @@ export class UnitsManager {
/** Instruct units to land at specific point /** Instruct units to land at specific point
* *
* @param latlng Point where to land * @param latlng Point where to land
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
landAtPoint(latlng: LatLng, units: Unit[] | null = null) { landAtPoint(latlng: LatLng, units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -802,6 +825,7 @@ export class UnitsManager {
/** Set a specific shots scatter to all the selected units /** Set a specific shots scatter to all the selected units
* *
* @param shotsScatter Value to set * @param shotsScatter Value to set
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
setShotsScatter(shotsScatter: number, units: Unit[] | null = null) { setShotsScatter(shotsScatter: number, units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -817,6 +841,7 @@ export class UnitsManager {
/** Set a specific shots intensity to all the selected units /** Set a specific shots intensity to all the selected units
* *
* @param shotsScatter Value to set * @param shotsScatter Value to set
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
setShotsIntensity(shotsIntensity: number, units: Unit[] | null = null) { setShotsIntensity(shotsIntensity: number, units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -870,6 +895,7 @@ export class UnitsManager {
/** Set the hotgroup for the selected units. It will be the only hotgroup of the unit /** Set the hotgroup for the selected units. It will be the only hotgroup of the unit
* *
* @param hotgroup Hotgroup number * @param hotgroup Hotgroup number
* @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) { 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));
@@ -879,6 +905,7 @@ export class UnitsManager {
/** Add the selected units to a hotgroup. Units can be in multiple hotgroups at the same type /** Add the selected units to a hotgroup. Units can be in multiple hotgroups at the same type
* *
* @param hotgroup Hotgroup number * @param hotgroup Hotgroup number
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
*/ */
addToHotgroup(hotgroup: number, units: Unit[] | null = null) { addToHotgroup(hotgroup: number, units: Unit[] | null = null) {
if (units === null) if (units === null)
@@ -891,6 +918,7 @@ export class UnitsManager {
/** Delete the selected units /** Delete the selected units
* *
* @param explosion If true, the unit will be deleted using an explosion * @param explosion If true, the unit will be deleted using an explosion
* @param units (Optional) Array of units to apply the control to. If not provided, the operation will be completed on all selected units.
* @returns * @returns
*/ */
delete(explosion: boolean = false, explosionType: string = "", units: Unit[] | null = null) { delete(explosion: boolean = false, explosionType: string = "", units: Unit[] | null = null) {
@@ -929,6 +957,7 @@ export class UnitsManager {
* *
* @param latlng Center of the group after the translation * @param latlng Center of the group after the translation
* @param rotation Rotation of the group, in radians * @param rotation Rotation of the group, in radians
* @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 * @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) {

View File

@@ -37,16 +37,8 @@ export class Weapon extends CustomMarker {
this.ID = ID; this.ID = ID;
/* Deselect units if they are hidden */ /* Update the marker when the options change */
document.addEventListener("toggleCoalitionVisibility", (ev: CustomEventInit) => { document.addEventListener("mapOptionsChanged", (ev: CustomEventInit) => {
window.setTimeout(() => { !this.getHidden() }, 300);
});
document.addEventListener("toggleUnitVisibility", (ev: CustomEventInit) => {
window.setTimeout(() => { !this.getHidden() }, 300);
});
document.addEventListener("mapVisibilityOptionsChanged", (ev: CustomEventInit) => {
this.#updateMarker(); this.#updateMarker();
}); });
} }