mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Added hotkeys
This commit is contained in:
parent
c2b0849fb6
commit
95e18f6503
@ -80,7 +80,9 @@ export class AudioUnitPipeline {
|
||||
/* Don't bother updating parameters if the client is too far away */
|
||||
if (this.#distance < this.#maxDistance) {
|
||||
/* Compute a new gain decreasing with distance. */
|
||||
let newGain = 1.0 - Math.pow(this.#distance / this.#maxDistance, 1); // Arbitrary
|
||||
//let newGain = 1.0 - Math.pow(this.#distance / this.#maxDistance, 1); // Arbitrary
|
||||
|
||||
let newGain = Math.min( 1, 20 / this.#distance )
|
||||
|
||||
/* Set the values of the main gain node and the multitap gain node, used for reverb effect */
|
||||
this.#gainNode.gain.setValueAtTime(newGain, getApp().getAudioManager().getAudioContext().currentTime);
|
||||
|
||||
@ -1,6 +1,29 @@
|
||||
import { LatLng, LatLngBounds } from "leaflet";
|
||||
import { MapOptions } from "../types/types";
|
||||
import { CommandModeOptions } from "../interfaces";
|
||||
import { ContextAction } from "../unit/contextaction";
|
||||
import {
|
||||
faExplosion,
|
||||
faHand,
|
||||
faLocationCrosshairs,
|
||||
faLocationDot,
|
||||
faMapLocation,
|
||||
faPeopleGroup,
|
||||
faPlaneArrival,
|
||||
faRoute,
|
||||
faTrash,
|
||||
faXmarksLines,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { Unit } from "../unit/unit";
|
||||
import { getApp } from "../olympusapp";
|
||||
import {
|
||||
olButtonsContextAttack,
|
||||
olButtonsContextFollow,
|
||||
olButtonsContextLandAtPoint,
|
||||
olButtonsContextRefuel,
|
||||
olButtonsContextSimulateFireFight,
|
||||
} from "../ui/components/olicons";
|
||||
import { FormationCreationRequestEvent, UnitExplosionRequestEvent } from "../events";
|
||||
|
||||
export const UNITS_URI = "units";
|
||||
export const WEAPONS_URI = "weapons";
|
||||
@ -308,7 +331,7 @@ export const MAP_OPTIONS_DEFAULTS = {
|
||||
fillSelectedRing: false,
|
||||
showMinimap: false,
|
||||
protectDCSUnits: true,
|
||||
keepRelativePositions: true
|
||||
keepRelativePositions: true,
|
||||
} as MapOptions;
|
||||
|
||||
export const MAP_HIDDEN_TYPES_DEFAULTS = {
|
||||
@ -400,6 +423,12 @@ export enum AudioMessageType {
|
||||
settings,
|
||||
}
|
||||
|
||||
export enum ContextActionTarget {
|
||||
NONE,
|
||||
UNIT,
|
||||
POINT,
|
||||
}
|
||||
|
||||
export enum ContextActionType {
|
||||
NO_COLOR,
|
||||
MOVE,
|
||||
@ -408,6 +437,238 @@ export enum ContextActionType {
|
||||
ENGAGE,
|
||||
DELETE,
|
||||
}
|
||||
|
||||
export const CONTEXT_ACTION_COLORS = [null, "white", "green", "purple", "blue", "red"];
|
||||
|
||||
export namespace ContextActions {
|
||||
export const STOP = new ContextAction(
|
||||
"stop",
|
||||
"Stop unit",
|
||||
"Stops the unit",
|
||||
faHand,
|
||||
ContextActionTarget.NONE,
|
||||
(units: Unit[], _1, _2) => {
|
||||
getApp().getUnitsManager().stop(units);
|
||||
},
|
||||
{
|
||||
executeImmediately: true,
|
||||
type: ContextActionType.MOVE,
|
||||
hotkey: "KeyZ",
|
||||
}
|
||||
);
|
||||
|
||||
export const MOVE = new ContextAction(
|
||||
"move",
|
||||
"Set destination",
|
||||
"Click on the map to move the units there",
|
||||
faLocationDot,
|
||||
ContextActionTarget.POINT,
|
||||
(units: Unit[], _, targetPosition, originalEvent) => {
|
||||
if (!originalEvent?.ctrlKey) getApp().getUnitsManager().clearDestinations(units);
|
||||
if (targetPosition)
|
||||
getApp()
|
||||
.getUnitsManager()
|
||||
.addDestination(targetPosition, getApp().getMap().getOptions().keepRelativePositions, getApp().getMap().getDestinationRotation(), units);
|
||||
},
|
||||
{ type: ContextActionType.MOVE, hotkey: "KeyX" }
|
||||
);
|
||||
|
||||
export const PATH = new ContextAction(
|
||||
"path",
|
||||
"Create route",
|
||||
"Click on the map to add a destination to the path",
|
||||
faRoute,
|
||||
ContextActionTarget.POINT,
|
||||
(units: Unit[], _, targetPosition) => {
|
||||
if (targetPosition)
|
||||
getApp()
|
||||
.getUnitsManager()
|
||||
.addDestination(targetPosition, getApp().getMap().getOptions().keepRelativePositions, getApp().getMap().getDestinationRotation(), units);
|
||||
},
|
||||
{ type: ContextActionType.MOVE, hotkey: "KeyC" }
|
||||
);
|
||||
|
||||
export const DELETE = new ContextAction(
|
||||
"delete",
|
||||
"Delete unit",
|
||||
"Deletes the unit",
|
||||
faTrash,
|
||||
ContextActionTarget.NONE,
|
||||
(units: Unit[], _1, _2) => {
|
||||
getApp().getUnitsManager().delete(false);
|
||||
},
|
||||
{
|
||||
executeImmediately: true,
|
||||
type: ContextActionType.DELETE,
|
||||
}
|
||||
);
|
||||
|
||||
export const EXPLODE = new ContextAction(
|
||||
"explode",
|
||||
"Explode unit",
|
||||
"Explodes the unit",
|
||||
faExplosion,
|
||||
ContextActionTarget.NONE,
|
||||
(units: Unit[], _1, _2) => {
|
||||
getApp().setState(OlympusState.UNIT_CONTROL, UnitControlSubState.UNIT_EXPLOSION_MENU);
|
||||
UnitExplosionRequestEvent.dispatch(units);
|
||||
},
|
||||
{
|
||||
executeImmediately: true,
|
||||
type: ContextActionType.DELETE,
|
||||
}
|
||||
);
|
||||
|
||||
export const CENTER_MAP = new ContextAction(
|
||||
"center-map",
|
||||
"Center map",
|
||||
"Center the map on the unit and follow it",
|
||||
faMapLocation,
|
||||
ContextActionTarget.NONE,
|
||||
(units: Unit[]) => {
|
||||
getApp().getMap().centerOnUnit(units[0]);
|
||||
},
|
||||
{ executeImmediately: true, type: ContextActionType.OTHER }
|
||||
);
|
||||
|
||||
export const REFUEL = new ContextAction(
|
||||
"refuel",
|
||||
"Refuel at tanker",
|
||||
"Refuel units at the nearest AAR Tanker. If no tanker is available the unit will RTB",
|
||||
olButtonsContextRefuel,
|
||||
ContextActionTarget.NONE,
|
||||
(units: Unit[]) => {
|
||||
getApp().getUnitsManager().refuel(units);
|
||||
},
|
||||
{ executeImmediately: true, type: ContextActionType.ADMIN }
|
||||
);
|
||||
|
||||
export const FOLLOW = new ContextAction(
|
||||
"follow",
|
||||
"Follow unit",
|
||||
"Click on a unit to follow it in formation",
|
||||
olButtonsContextFollow,
|
||||
ContextActionTarget.UNIT,
|
||||
(units: Unit[], targetUnit: Unit | null, _) => {
|
||||
if (targetUnit) {
|
||||
getApp().setState(OlympusState.UNIT_CONTROL, UnitControlSubState.FORMATION);
|
||||
FormationCreationRequestEvent.dispatch(
|
||||
targetUnit,
|
||||
units.filter((unit) => unit !== targetUnit)
|
||||
);
|
||||
}
|
||||
},
|
||||
{ type: ContextActionType.ADMIN }
|
||||
);
|
||||
|
||||
export const BOMB = new ContextAction(
|
||||
"bomb",
|
||||
"Precision bomb location",
|
||||
"Click on a point to execute a precision bombing attack",
|
||||
faLocationCrosshairs,
|
||||
ContextActionTarget.POINT,
|
||||
(units: Unit[], _, targetPosition: LatLng | null) => {
|
||||
if (targetPosition)
|
||||
getApp()
|
||||
.getUnitsManager()
|
||||
.bombPoint(targetPosition, getApp().getMap().getOptions().keepRelativePositions, getApp().getMap().getDestinationRotation(), units);
|
||||
},
|
||||
{ type: ContextActionType.ENGAGE }
|
||||
);
|
||||
|
||||
export const CARPET_BOMB = new ContextAction(
|
||||
"carpet-bomb",
|
||||
"Carpet bomb location",
|
||||
"Click on a point to execute a carpet bombing attack",
|
||||
faXmarksLines,
|
||||
ContextActionTarget.POINT,
|
||||
(units: Unit[], _, targetPosition: LatLng | null) => {
|
||||
if (targetPosition)
|
||||
getApp()
|
||||
.getUnitsManager()
|
||||
.carpetBomb(targetPosition, getApp().getMap().getOptions().keepRelativePositions, getApp().getMap().getDestinationRotation(), units);
|
||||
},
|
||||
{ type: ContextActionType.ENGAGE }
|
||||
);
|
||||
|
||||
export const LAND = new ContextAction(
|
||||
"land",
|
||||
"Land",
|
||||
"Click on a point to land at the nearest airbase",
|
||||
faPlaneArrival,
|
||||
ContextActionTarget.POINT,
|
||||
(units: Unit[], _, targetPosition: LatLng | null) => {
|
||||
if (targetPosition) getApp().getUnitsManager().landAt(targetPosition, units);
|
||||
},
|
||||
{ type: ContextActionType.ADMIN }
|
||||
);
|
||||
|
||||
export const LAND_AT_POINT = new ContextAction(
|
||||
"land-at-point",
|
||||
"Land at location",
|
||||
"Click on a point to land there",
|
||||
olButtonsContextLandAtPoint,
|
||||
ContextActionTarget.POINT,
|
||||
(units: Unit[], _, targetPosition: LatLng | null) => {
|
||||
if (targetPosition)
|
||||
getApp()
|
||||
.getUnitsManager()
|
||||
.landAtPoint(targetPosition, getApp().getMap().getOptions().keepRelativePositions, getApp().getMap().getDestinationRotation(), units);
|
||||
},
|
||||
{ type: ContextActionType.ADMIN }
|
||||
);
|
||||
|
||||
export const GROUP = new ContextAction(
|
||||
"group-ground",
|
||||
"Group ground units",
|
||||
"Create a group of ground units",
|
||||
faPeopleGroup,
|
||||
ContextActionTarget.NONE,
|
||||
(units: Unit[], _1, _2) => {
|
||||
getApp().getUnitsManager().createGroup(units);
|
||||
},
|
||||
{ executeImmediately: true, type: ContextActionType.OTHER }
|
||||
);
|
||||
|
||||
export const ATTACK = new ContextAction(
|
||||
"attack",
|
||||
"Attack unit",
|
||||
"Click on a unit to attack it",
|
||||
olButtonsContextAttack,
|
||||
ContextActionTarget.UNIT,
|
||||
(units: Unit[], targetUnit: Unit | null, _) => {
|
||||
if (targetUnit) getApp().getUnitsManager().attackUnit(targetUnit.ID, units);
|
||||
},
|
||||
{ type: ContextActionType.ENGAGE }
|
||||
);
|
||||
|
||||
export const FIRE_AT_AREA = new ContextAction(
|
||||
"fire-at-area",
|
||||
"Fire at area",
|
||||
"Click on a point to precisely fire at it (if possible)",
|
||||
faLocationCrosshairs,
|
||||
ContextActionTarget.POINT,
|
||||
(units: Unit[], _, targetPosition: LatLng | null) => {
|
||||
if (targetPosition)
|
||||
getApp()
|
||||
.getUnitsManager()
|
||||
.fireAtArea(targetPosition, getApp().getMap().getOptions().keepRelativePositions, getApp().getMap().getDestinationRotation(), units);
|
||||
},
|
||||
{ type: ContextActionType.ENGAGE }
|
||||
);
|
||||
|
||||
export const SIMULATE_FIRE_FIGHT = new ContextAction(
|
||||
"simulate-fire-fight",
|
||||
"Simulate fire fight",
|
||||
"Simulate a fire fight by shooting randomly in a certain large area. WARNING: works correctly only on neutral units, blue or red units will aim",
|
||||
olButtonsContextSimulateFireFight,
|
||||
ContextActionTarget.POINT,
|
||||
(units: Unit[], _, targetPosition: LatLng | null) => {
|
||||
if (targetPosition)
|
||||
getApp()
|
||||
.getUnitsManager()
|
||||
.simulateFireFight(targetPosition, getApp().getMap().getOptions().keepRelativePositions, getApp().getMap().getDestinationRotation(), units);
|
||||
},
|
||||
{ type: ContextActionType.ADMIN }
|
||||
);
|
||||
}
|
||||
|
||||
@ -20,6 +20,8 @@ import {
|
||||
DrawSubState,
|
||||
JTACSubState,
|
||||
UnitControlSubState,
|
||||
ContextActionTarget,
|
||||
ContextActionType,
|
||||
} from "../constants/constants";
|
||||
import { CoalitionPolygon } from "./coalitionarea/coalitionpolygon";
|
||||
import { MapHiddenTypes, MapOptions } from "../types/types";
|
||||
@ -931,7 +933,7 @@ export class Map extends L.Map {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.originalEvent.button === 2) this.#isRotatingDestination = true;
|
||||
if (this.#contextAction?.getTarget() === ContextActionTarget.POINT && e.originalEvent.button === 2) this.#isRotatingDestination = true;
|
||||
this.scrollWheelZoom.disable();
|
||||
|
||||
this.#shortPressTimer = window.setTimeout(() => {
|
||||
@ -1100,10 +1102,12 @@ export class Map extends L.Map {
|
||||
else document.dispatchEvent(new CustomEvent("forceboxselect", { detail: e.originalEvent }));
|
||||
} else if (getApp().getState() === OlympusState.UNIT_CONTROL) {
|
||||
if (e.originalEvent.button === 2) {
|
||||
getApp().setState(OlympusState.UNIT_CONTROL, UnitControlSubState.MAP_CONTEXT_MENU);
|
||||
MapContextMenuRequestEvent.dispatch(pressLocation);
|
||||
if (!getApp().getMap().getContextAction()) {
|
||||
getApp().setState(OlympusState.UNIT_CONTROL, UnitControlSubState.MAP_CONTEXT_MENU);
|
||||
MapContextMenuRequestEvent.dispatch(pressLocation);
|
||||
}
|
||||
} else {
|
||||
if (this.#contextAction?.getTarget() === "position") {
|
||||
if (this.#contextAction?.getTarget() === ContextActionTarget.POINT) {
|
||||
this.dragging.disable();
|
||||
this.#isRotatingDestination = true;
|
||||
} else {
|
||||
@ -1259,9 +1263,9 @@ export class Map extends L.Map {
|
||||
});
|
||||
|
||||
selectedUnits.forEach((unit) => {
|
||||
if (["move", "path", "land-at-point"].includes(this.#contextAction?.getId() ?? "")) {
|
||||
if (this.#contextAction?.getOptions().type === ContextActionType.MOVE) {
|
||||
this.#destinationPreviewMarkers[unit.ID] = new TemporaryUnitMarker(new L.LatLng(0, 0), unit.getName(), unit.getCoalition());
|
||||
} else if (this.#contextAction?.getTarget() === "position" && this.#contextAction?.getId() !== "land") {
|
||||
} else if (this.#contextAction?.getTarget() === ContextActionTarget.POINT) {
|
||||
this.#destinationPreviewMarkers[unit.ID] = new TargetMarker(new L.LatLng(0, 0));
|
||||
}
|
||||
this.#destinationPreviewMarkers[unit.ID]?.addTo(this);
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { ContextActions, OlympusState } from "../constants/constants";
|
||||
import { ShortcutKeyboardOptions, ShortcutMouseOptions } from "../interfaces";
|
||||
import { getApp } from "../olympusapp";
|
||||
import { ShortcutKeyboard, ShortcutMouse } from "./shortcut";
|
||||
@ -117,6 +118,26 @@ export class ShortcutManager {
|
||||
shiftKey: false,
|
||||
});
|
||||
|
||||
for (let contextActionName in ContextActions) {
|
||||
if (ContextActions[contextActionName].getOptions().hotkey) {
|
||||
this.addKeyboardShortcut(`${contextActionName}Hotkey`, {
|
||||
code: ContextActions[contextActionName].getOptions().hotkey,
|
||||
shiftKey: true,
|
||||
callback: () => {
|
||||
const contextActionSet = getApp().getMap().getContextActionSet();
|
||||
if (
|
||||
getApp().getState() === OlympusState.UNIT_CONTROL &&
|
||||
contextActionSet &&
|
||||
ContextActions[contextActionName].getId() in contextActionSet.getContextActions()
|
||||
) {
|
||||
if (ContextActions[contextActionName].getOptions().executeImmediately) ContextActions[contextActionName].executeCallback();
|
||||
else getApp().getMap().setContextAction(ContextActions[contextActionName]);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let PTTKeys = ["KeyZ", "KeyX", "KeyC", "KeyV", "KeyB", "KeyN", "KeyM", "KeyK", "KeyL"];
|
||||
PTTKeys.forEach((key, idx) => {
|
||||
this.addKeyboardShortcut(`PTT${idx}Active`, {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { Unit } from "../../unit/unit";
|
||||
import { ContextAction } from "../../unit/contextaction";
|
||||
import { CONTEXT_ACTION_COLORS, NO_SUBSTATE, OlympusState, OlympusSubState, UnitControlSubState } from "../../constants/constants";
|
||||
import { CONTEXT_ACTION_COLORS, ContextActionTarget, NO_SUBSTATE, OlympusState, OlympusSubState, UnitControlSubState } from "../../constants/constants";
|
||||
import { OlDropdownItem } from "../components/oldropdown";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { LatLng } from "leaflet";
|
||||
@ -69,9 +69,9 @@ export function MapContextMenu(props: {}) {
|
||||
});
|
||||
|
||||
let reorderedActions: ContextAction[] = contextActionSet
|
||||
? Object.values(contextActionSet.getContextActions(appSubState === UnitControlSubState.MAP_CONTEXT_MENU ? "position" : "unit")).sort(
|
||||
(a: ContextAction, b: ContextAction) => (a.getOptions().type < b.getOptions().type ? -1 : 1)
|
||||
)
|
||||
? Object.values(
|
||||
contextActionSet.getContextActions(appSubState === UnitControlSubState.MAP_CONTEXT_MENU ? ContextActionTarget.POINT : ContextActionTarget.UNIT)
|
||||
).sort((a: ContextAction, b: ContextAction) => (a.getOptions().type < b.getOptions().type ? -1 : 1))
|
||||
: [];
|
||||
|
||||
return (
|
||||
@ -107,13 +107,13 @@ export function MapContextMenu(props: {}) {
|
||||
if (contextActionIt.getOptions().executeImmediately) {
|
||||
contextActionIt.executeCallback(null, null);
|
||||
} else {
|
||||
if (appSubState === UnitControlSubState.MAP_CONTEXT_MENU ) {
|
||||
if (appSubState === UnitControlSubState.MAP_CONTEXT_MENU) {
|
||||
contextActionIt.executeCallback(null, latLng);
|
||||
} else if (unit !== null) {
|
||||
contextActionIt.executeCallback(unit, null);
|
||||
}
|
||||
}
|
||||
getApp().setState(OlympusState.UNIT_CONTROL)
|
||||
getApp().setState(OlympusState.UNIT_CONTROL);
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon className="my-auto" icon={contextActionIt.getIcon()} />
|
||||
|
||||
@ -66,20 +66,30 @@ export function UnitControlBar(props: {}) {
|
||||
<div className="flex gap-2 overflow-x-auto no-scrollbar p-2" onScroll={(ev) => onScroll(ev.target)} ref={scrollRef}>
|
||||
{reorderedActions.map((contextActionIt: ContextAction) => {
|
||||
return (
|
||||
<OlStateButton
|
||||
key={contextActionIt.getId()}
|
||||
checked={contextActionIt === contextAction}
|
||||
icon={contextActionIt.getIcon()}
|
||||
tooltip={contextActionIt.getLabel()}
|
||||
buttonColor={CONTEXT_ACTION_COLORS[contextActionIt.getOptions().type ?? 0]}
|
||||
onClick={() => {
|
||||
if (contextActionIt.getOptions().executeImmediately) {
|
||||
contextActionIt.executeCallback(null, null);
|
||||
} else {
|
||||
contextActionIt !== contextAction ? getApp().getMap().setContextAction(contextActionIt) : getApp().getMap().setContextAction(null);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<div className="flex flex-col gap-1">
|
||||
<OlStateButton
|
||||
key={contextActionIt.getId()}
|
||||
checked={contextActionIt === contextAction}
|
||||
icon={contextActionIt.getIcon()}
|
||||
tooltip={contextActionIt.getLabel()}
|
||||
buttonColor={CONTEXT_ACTION_COLORS[contextActionIt.getOptions().type ?? 0]}
|
||||
onClick={() => {
|
||||
if (contextActionIt.getOptions().executeImmediately) {
|
||||
contextActionIt.executeCallback(null, null);
|
||||
} else {
|
||||
contextActionIt !== contextAction ? getApp().getMap().setContextAction(contextActionIt) : getApp().getMap().setContextAction(null);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className={`
|
||||
rounded-sm bg-gray-400 text-center text-xs font-bold
|
||||
text-olympus-800
|
||||
`}
|
||||
>
|
||||
{(contextActionIt.getOptions().hotkey ?? "").replace("Key", "")}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
@ -120,7 +130,7 @@ export function UnitControlBar(props: {}) {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{*/}
|
||||
{*/}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
|
||||
import { Unit } from "./unit";
|
||||
import { LatLng } from "leaflet";
|
||||
import { ContextActionType } from "../constants/constants";
|
||||
import { ContextActionTarget, ContextActionType } from "../constants/constants";
|
||||
|
||||
export interface ContextActionOptions {
|
||||
executeImmediately?: boolean;
|
||||
type: ContextActionType;
|
||||
hotkey?: string;
|
||||
}
|
||||
|
||||
export type ContextActionCallback = (units: Unit[], targetUnit: Unit | null, targetPosition: LatLng | null, originalEvent?: MouseEvent) => void;
|
||||
@ -18,9 +19,9 @@ export class ContextAction {
|
||||
#units: Unit[] = [];
|
||||
#icon: IconDefinition;
|
||||
#options: ContextActionOptions;
|
||||
#target: "unit" | "position" | null = null;
|
||||
#target: ContextActionTarget;
|
||||
|
||||
constructor(id: string, label: string, description: string, icon: IconDefinition, target: "unit" | "position" | null, callback: ContextActionCallback, options: ContextActionOptions) {
|
||||
constructor(id: string, label: string, description: string, icon: IconDefinition, target: ContextActionTarget, callback: ContextActionCallback, options: ContextActionOptions) {
|
||||
this.#id = id;
|
||||
this.#label = label;
|
||||
this.#description = description;
|
||||
@ -33,8 +34,8 @@ export class ContextAction {
|
||||
};
|
||||
}
|
||||
|
||||
addUnit(unit: Unit) {
|
||||
this.#units.push(unit);
|
||||
setUnits(units: Unit[]) {
|
||||
this.#units = units;
|
||||
}
|
||||
|
||||
getId() {
|
||||
|
||||
@ -1,30 +1,26 @@
|
||||
import { ContextActionTarget } from "../constants/constants";
|
||||
import { ContextAction, ContextActionCallback, ContextActionOptions } from "./contextaction";
|
||||
import { Unit } from "./unit";
|
||||
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
|
||||
|
||||
export class ContextActionSet {
|
||||
#contextActions: { [key: string]: ContextAction } = {};
|
||||
#defaultContextAction: ContextAction | null = null;
|
||||
#units: { [key: string]: Unit[] } = {};
|
||||
|
||||
addContextAction(
|
||||
unit: Unit,
|
||||
id: string,
|
||||
label: string,
|
||||
description: string,
|
||||
icon: IconDefinition,
|
||||
target: "unit" | "position" | null,
|
||||
callback: ContextActionCallback,
|
||||
options?: ContextActionOptions
|
||||
contextAction: ContextAction
|
||||
) {
|
||||
options = options || {};
|
||||
|
||||
if (!(id in this.#contextActions)) {
|
||||
this.#contextActions[id] = new ContextAction(id, label, description, icon, target, callback, options);
|
||||
this.#contextActions[contextAction.getId()] = contextAction;
|
||||
if (!(contextAction.getId() in this.#units)) {
|
||||
this.#units[contextAction.getId()] = []
|
||||
this.#contextActions[contextAction.getId()].setUnits(this.#units[contextAction.getId()]);
|
||||
}
|
||||
this.#contextActions[id].addUnit(unit);
|
||||
|
||||
this.#units[contextAction.getId()].push(unit)
|
||||
}
|
||||
|
||||
getContextActions(targetFilter?: string) {
|
||||
getContextActions(targetFilter?: ContextActionTarget) {
|
||||
if (targetFilter) {
|
||||
var filteredContextActionSet = new ContextActionSet();
|
||||
Object.keys(this.#contextActions).forEach((key) => {
|
||||
@ -36,17 +32,10 @@ export class ContextActionSet {
|
||||
|
||||
addDefaultContextAction(
|
||||
unit: Unit,
|
||||
id: string,
|
||||
label: string,
|
||||
description: string,
|
||||
icon: IconDefinition,
|
||||
target: "unit" | "position" | null,
|
||||
callback: ContextActionCallback,
|
||||
options?: ContextActionOptions
|
||||
contextAction: ContextAction
|
||||
) {
|
||||
options = options || {};
|
||||
if (this.#defaultContextAction === null) this.#defaultContextAction = new ContextAction(id, label, description, icon, target, callback, options);
|
||||
this.#defaultContextAction.addUnit(unit);
|
||||
if (this.#defaultContextAction === null) this.#defaultContextAction = contextAction;
|
||||
//this.#defaultContextAction.addUnit(unit);
|
||||
}
|
||||
|
||||
getDefaultContextAction() {
|
||||
|
||||
@ -39,6 +39,7 @@ import {
|
||||
JTACSubState,
|
||||
UnitControlSubState,
|
||||
ContextActionType,
|
||||
ContextActions,
|
||||
} from "../constants/constants";
|
||||
import { DataExtractor } from "../server/dataextractor";
|
||||
import { Weapon } from "../weapon/weapon";
|
||||
@ -80,6 +81,7 @@ import {
|
||||
UnitSelectedEvent,
|
||||
UnitUpdatedEvent,
|
||||
} from "../events";
|
||||
import { ContextAction } from "./contextaction";
|
||||
|
||||
var pathIcon = new Icon({
|
||||
iconUrl: "/vite/images/markers/marker-icon.png",
|
||||
@ -838,102 +840,13 @@ export abstract class Unit extends CustomMarker {
|
||||
*
|
||||
*/
|
||||
appendContextActions(contextActionSet: ContextActionSet) {
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"stop",
|
||||
"Stop unit",
|
||||
"Stops the unit",
|
||||
faHand,
|
||||
null,
|
||||
(units: Unit[], _1, _2) => {
|
||||
getApp().getUnitsManager().stop(units);
|
||||
},
|
||||
{
|
||||
executeImmediately: true,
|
||||
type: ContextActionType.MOVE,
|
||||
}
|
||||
);
|
||||
contextActionSet.addContextAction(this, ContextActions.STOP);
|
||||
contextActionSet.addContextAction(this, ContextActions.MOVE);
|
||||
contextActionSet.addContextAction(this, ContextActions.PATH);
|
||||
contextActionSet.addContextAction(this, ContextActions.DELETE);
|
||||
contextActionSet.addContextAction(this, ContextActions.EXPLODE);
|
||||
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"move",
|
||||
"Set destination",
|
||||
"Click on the map to move the units there",
|
||||
faLocationDot,
|
||||
"position",
|
||||
(units: Unit[], _, targetPosition, originalEvent) => {
|
||||
if (!originalEvent?.ctrlKey) getApp().getUnitsManager().clearDestinations(units);
|
||||
if (targetPosition)
|
||||
getApp()
|
||||
.getUnitsManager()
|
||||
.addDestination(targetPosition, getApp().getMap().getOptions().keepRelativePositions, getApp().getMap().getDestinationRotation(), units);
|
||||
},
|
||||
{ type: ContextActionType.MOVE }
|
||||
);
|
||||
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"path",
|
||||
"Create route",
|
||||
"Click on the map to add a destination to the path",
|
||||
faRoute,
|
||||
"position",
|
||||
(units: Unit[], _, targetPosition) => {
|
||||
if (targetPosition)
|
||||
getApp()
|
||||
.getUnitsManager()
|
||||
.addDestination(targetPosition, getApp().getMap().getOptions().keepRelativePositions, getApp().getMap().getDestinationRotation(), units);
|
||||
},
|
||||
{ type: ContextActionType.MOVE }
|
||||
);
|
||||
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"delete",
|
||||
"Delete unit",
|
||||
"Deletes the unit",
|
||||
faTrash,
|
||||
null,
|
||||
(units: Unit[], _1, _2) => {
|
||||
getApp().getUnitsManager().delete(false);
|
||||
},
|
||||
{
|
||||
executeImmediately: true,
|
||||
type: ContextActionType.DELETE,
|
||||
}
|
||||
);
|
||||
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"explode",
|
||||
"Explode unit",
|
||||
"Explodes the unit",
|
||||
faExplosion,
|
||||
null,
|
||||
(units: Unit[], _1, _2) => {
|
||||
getApp().setState(OlympusState.UNIT_CONTROL, UnitControlSubState.UNIT_EXPLOSION_MENU);
|
||||
UnitExplosionRequestEvent.dispatch(units);
|
||||
},
|
||||
{
|
||||
executeImmediately: true,
|
||||
type: ContextActionType.DELETE,
|
||||
}
|
||||
);
|
||||
|
||||
contextActionSet.addDefaultContextAction(
|
||||
this,
|
||||
"default",
|
||||
"Set destination",
|
||||
"",
|
||||
faRoute,
|
||||
null,
|
||||
(units: Unit[], targetUnit, targetPosition, originalEvent) => {
|
||||
if (targetPosition) {
|
||||
if (!originalEvent?.ctrlKey) getApp().getUnitsManager().clearDestinations(units);
|
||||
getApp().getUnitsManager().addDestination(targetPosition, false, 0, units);
|
||||
}
|
||||
}
|
||||
);
|
||||
contextActionSet.addDefaultContextAction(this, ContextActions.MOVE);
|
||||
}
|
||||
|
||||
drawLines() {
|
||||
@ -1452,7 +1365,7 @@ export abstract class Unit extends CustomMarker {
|
||||
#onLongPress(e: any) {
|
||||
console.log(`Long press on ${this.getUnitName()}`);
|
||||
|
||||
if (e.originalEvent.button === 2) {
|
||||
if (e.originalEvent.button === 2 && !getApp().getMap().getContextAction()) {
|
||||
getApp().setState(OlympusState.UNIT_CONTROL, UnitControlSubState.UNIT_CONTEXT_MENU);
|
||||
UnitContextMenuRequestEvent.dispatch(this);
|
||||
}
|
||||
@ -1869,111 +1782,20 @@ export abstract class AirUnit extends Unit {
|
||||
super.appendContextActions(contextActionSet);
|
||||
|
||||
/* Context actions to be executed immediately */
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"refuel",
|
||||
"Refuel at tanker",
|
||||
"Refuel units at the nearest AAR Tanker. If no tanker is available the unit will RTB",
|
||||
olButtonsContextRefuel,
|
||||
null,
|
||||
(units: Unit[]) => {
|
||||
getApp().getUnitsManager().refuel(units);
|
||||
},
|
||||
{ executeImmediately: true, type: ContextActionType.ADMIN }
|
||||
);
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"center-map",
|
||||
"Center map",
|
||||
"Center the map on the unit and follow it",
|
||||
faMapLocation,
|
||||
null,
|
||||
(units: Unit[]) => {
|
||||
getApp().getMap().centerOnUnit(units[0]);
|
||||
},
|
||||
{ executeImmediately: true, type: ContextActionType.OTHER }
|
||||
);
|
||||
contextActionSet.addContextAction(this, ContextActions.REFUEL);
|
||||
contextActionSet.addContextAction(this, ContextActions.CENTER_MAP);
|
||||
|
||||
/* Context actions that require a target unit */
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"attack",
|
||||
"Attack unit",
|
||||
"Click on a unit to attack it using A/A or A/G weapons",
|
||||
olButtonsContextAttack,
|
||||
"unit",
|
||||
(units: Unit[], targetUnit: Unit | null, _) => {
|
||||
if (targetUnit) getApp().getUnitsManager().attackUnit(targetUnit.ID, units);
|
||||
},
|
||||
{ type: ContextActionType.ENGAGE }
|
||||
);
|
||||
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"follow",
|
||||
"Follow unit",
|
||||
"Click on a unit to follow it in formation",
|
||||
olButtonsContextFollow,
|
||||
"unit",
|
||||
(units: Unit[], targetUnit: Unit | null, _) => {
|
||||
if (targetUnit) {
|
||||
getApp().setState(OlympusState.UNIT_CONTROL, UnitControlSubState.FORMATION);
|
||||
FormationCreationRequestEvent.dispatch(
|
||||
targetUnit,
|
||||
units.filter((unit) => unit !== targetUnit)
|
||||
);
|
||||
}
|
||||
},
|
||||
{ type: ContextActionType.ADMIN }
|
||||
);
|
||||
contextActionSet.addContextAction(this, ContextActions.ATTACK);
|
||||
contextActionSet.addContextAction(this, ContextActions.FOLLOW);
|
||||
|
||||
if (this.canTargetPoint()) {
|
||||
/* Context actions that require a target position */
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"bomb",
|
||||
"Precision bomb location",
|
||||
"Click on a point to execute a precision bombing attack",
|
||||
faLocationCrosshairs,
|
||||
"position",
|
||||
(units: Unit[], _, targetPosition: LatLng | null) => {
|
||||
if (targetPosition)
|
||||
getApp()
|
||||
.getUnitsManager()
|
||||
.bombPoint(targetPosition, getApp().getMap().getOptions().keepRelativePositions, getApp().getMap().getDestinationRotation(), units);
|
||||
},
|
||||
{ type: ContextActionType.ENGAGE }
|
||||
);
|
||||
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"carpet-bomb",
|
||||
"Carpet bomb location",
|
||||
"Click on a point to execute a carpet bombing attack",
|
||||
faXmarksLines,
|
||||
"position",
|
||||
(units: Unit[], _, targetPosition: LatLng | null) => {
|
||||
if (targetPosition)
|
||||
getApp()
|
||||
.getUnitsManager()
|
||||
.carpetBomb(targetPosition, getApp().getMap().getOptions().keepRelativePositions, getApp().getMap().getDestinationRotation(), units);
|
||||
},
|
||||
{ type: ContextActionType.ENGAGE }
|
||||
);
|
||||
contextActionSet.addContextAction(this, ContextActions.BOMB);
|
||||
contextActionSet.addContextAction(this, ContextActions.CARPET_BOMB);
|
||||
}
|
||||
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"land",
|
||||
"Land",
|
||||
"Click on a point to land at the nearest airbase",
|
||||
faPlaneArrival,
|
||||
"position",
|
||||
(units: Unit[], _, targetPosition: LatLng | null) => {
|
||||
if (targetPosition) getApp().getUnitsManager().landAt(targetPosition, units);
|
||||
},
|
||||
{ type: ContextActionType.ADMIN }
|
||||
);
|
||||
contextActionSet.addContextAction(this, ContextActions.LAND);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2010,21 +1832,7 @@ export class Helicopter extends AirUnit {
|
||||
|
||||
appendContextActions(contextActionSet: ContextActionSet) {
|
||||
super.appendContextActions(contextActionSet);
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"land-at-point",
|
||||
"Land at location",
|
||||
"Click on a point to land there",
|
||||
olButtonsContextLandAtPoint,
|
||||
"position",
|
||||
(units: Unit[], _, targetPosition: LatLng | null) => {
|
||||
if (targetPosition)
|
||||
getApp()
|
||||
.getUnitsManager()
|
||||
.landAtPoint(targetPosition, getApp().getMap().getOptions().keepRelativePositions, getApp().getMap().getDestinationRotation(), units);
|
||||
},
|
||||
{ type: ContextActionType.ADMIN }
|
||||
);
|
||||
contextActionSet.addContextAction(this, ContextActions.LAND_AT_POINT);
|
||||
}
|
||||
|
||||
getMarkerCategory() {
|
||||
@ -2062,77 +1870,16 @@ export class GroundUnit extends Unit {
|
||||
super.appendContextActions(contextActionSet);
|
||||
|
||||
/* Context actions to be executed immediately */
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"group-ground",
|
||||
"Group ground units",
|
||||
"Create a group of ground units",
|
||||
faPeopleGroup,
|
||||
null,
|
||||
(units: Unit[], _1, _2) => {
|
||||
getApp().getUnitsManager().createGroup(units);
|
||||
},
|
||||
{ executeImmediately: true, type: ContextActionType.OTHER }
|
||||
);
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"center-map",
|
||||
"Center map",
|
||||
"Center the map on the unit and follow it",
|
||||
faMapLocation,
|
||||
null,
|
||||
(units: Unit[]) => {
|
||||
getApp().getMap().centerOnUnit(units[0]);
|
||||
},
|
||||
{ executeImmediately: true, type: ContextActionType.OTHER }
|
||||
);
|
||||
contextActionSet.addContextAction(this, ContextActions.GROUP);
|
||||
contextActionSet.addContextAction(this, ContextActions.CENTER_MAP);
|
||||
|
||||
/* Context actions that require a target unit */
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"attack",
|
||||
"Attack unit",
|
||||
"Click on a unit to attack it",
|
||||
olButtonsContextAttack,
|
||||
"unit",
|
||||
(units: Unit[], targetUnit: Unit | null, _) => {
|
||||
if (targetUnit) getApp().getUnitsManager().attackUnit(targetUnit.ID, units);
|
||||
},
|
||||
{ type: ContextActionType.ENGAGE }
|
||||
);
|
||||
contextActionSet.addContextAction(this, ContextActions.ATTACK);
|
||||
|
||||
/* Context actions that require a target position */
|
||||
if (this.canTargetPoint()) {
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"fire-at-area",
|
||||
"Fire at area",
|
||||
"Click on a point to precisely fire at it (if possible)",
|
||||
faLocationCrosshairs,
|
||||
"position",
|
||||
(units: Unit[], _, targetPosition: LatLng | null) => {
|
||||
if (targetPosition)
|
||||
getApp()
|
||||
.getUnitsManager()
|
||||
.fireAtArea(targetPosition, getApp().getMap().getOptions().keepRelativePositions, getApp().getMap().getDestinationRotation(), units);
|
||||
},
|
||||
{ type: ContextActionType.ENGAGE }
|
||||
);
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"simulate-fire-fight",
|
||||
"Simulate fire fight",
|
||||
"Simulate a fire fight by shooting randomly in a certain large area. WARNING: works correctly only on neutral units, blue or red units will aim",
|
||||
olButtonsContextSimulateFireFight,
|
||||
"position",
|
||||
(units: Unit[], _, targetPosition: LatLng | null) => {
|
||||
if (targetPosition)
|
||||
getApp()
|
||||
.getUnitsManager()
|
||||
.simulateFireFight(targetPosition, getApp().getMap().getOptions().keepRelativePositions, getApp().getMap().getDestinationRotation(), units);
|
||||
},
|
||||
{ type: ContextActionType.ADMIN }
|
||||
);
|
||||
contextActionSet.addContextAction(this, ContextActions.FIRE_AT_AREA);
|
||||
contextActionSet.addContextAction(this, ContextActions.SIMULATE_FIRE_FIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2192,61 +1939,14 @@ export class NavyUnit extends Unit {
|
||||
super.appendContextActions(contextActionSet);
|
||||
|
||||
/* Context actions to be executed immediately */
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"group-navy",
|
||||
"Group navy units",
|
||||
"Create a group of navy units",
|
||||
faQuestionCircle,
|
||||
null,
|
||||
(units: Unit[], _1, _2) => {
|
||||
getApp().getUnitsManager().createGroup(units);
|
||||
},
|
||||
{ executeImmediately: true, type: ContextActionType.OTHER }
|
||||
);
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"center-map",
|
||||
"Center map",
|
||||
"Center the map on the unit and follow it",
|
||||
faMapLocation,
|
||||
null,
|
||||
(units: Unit[]) => {
|
||||
getApp().getMap().centerOnUnit(units[0]);
|
||||
},
|
||||
{ executeImmediately: true, type: ContextActionType.OTHER }
|
||||
);
|
||||
contextActionSet.addContextAction(this, ContextActions.GROUP);
|
||||
contextActionSet.addContextAction(this, ContextActions.CENTER_MAP);
|
||||
|
||||
/* Context actions that require a target unit */
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"attack",
|
||||
"Attack unit",
|
||||
"Click on a unit to attack it",
|
||||
olButtonsContextAttack,
|
||||
"unit",
|
||||
(units: Unit[], targetUnit: Unit | null, _) => {
|
||||
if (targetUnit) getApp().getUnitsManager().attackUnit(targetUnit.ID, units);
|
||||
},
|
||||
{ type: ContextActionType.ENGAGE }
|
||||
);
|
||||
contextActionSet.addContextAction(this, ContextActions.ATTACK);
|
||||
|
||||
/* Context actions that require a target position */
|
||||
contextActionSet.addContextAction(
|
||||
this,
|
||||
"fire-at-area",
|
||||
"Fire at area",
|
||||
"Click on a point to precisely fire at it (if possible)",
|
||||
faLocationCrosshairs,
|
||||
"position",
|
||||
(units: Unit[], _, targetPosition: LatLng | null) => {
|
||||
if (targetPosition)
|
||||
getApp()
|
||||
.getUnitsManager()
|
||||
.fireAtArea(targetPosition, getApp().getMap().getOptions().keepRelativePositions, getApp().getMap().getDestinationRotation(), units);
|
||||
},
|
||||
{ type: ContextActionType.ENGAGE }
|
||||
);
|
||||
contextActionSet.addContextAction(this, ContextActions.FIRE_AT_AREA);
|
||||
}
|
||||
|
||||
getCategory() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user