Completed backend for advanced RTS functions

This commit is contained in:
Pax1601
2023-07-23 22:30:25 +02:00
parent 8ffd5ef972
commit 81871b596b
36 changed files with 338 additions and 216 deletions

View File

@@ -390,7 +390,7 @@ class DemoDataGenerator {
startTime: 0
}
ret.mission.RTSOptions = {
ret.mission.commandModeOptions = {
restrictSpawns: true,
restrictToCoalition: true,
setupTime: 0,
@@ -406,13 +406,13 @@ class DemoDataGenerator {
var username = atob(auth.replace("Basic ", "")).split(":")[0];
switch (username) {
case "admin":
ret.mission.RTSOptions.commandMode = "Game master";
ret.mission.commandModeOptions.commandMode = "Game master";
break
case "blue":
ret.mission.RTSOptions.commandMode = "Blue commander";
ret.mission.commandModeOptions.commandMode = "Blue commander";
break;
case "red":
ret.mission.RTSOptions.commandMode = "Red commander";
ret.mission.commandModeOptions.commandMode = "Red commander";
break;
}
}

View File

@@ -20,7 +20,7 @@
display: flex;
}
#rts-toolbar {
#command-mode-toolbar {
align-items: center;
display: flex;
}

View File

@@ -917,12 +917,12 @@ nav.ol-panel> :last-child {
padding-right: 20px;
}
#rts-phase::before {
#command-mode-phase::before {
content: "Time to start";
font-size: 14px;
}
#rts-phase.setup-phase::after {
#command-mode-phase.setup-phase::after {
color: orange;
border: 1px solid orange;
border-radius: 999px;
@@ -933,7 +933,7 @@ nav.ol-panel> :last-child {
font-size: 14px;
}
#rts-phase.game-commenced {
#command-mode-phase.game-commenced {
background-color: var(--background-grey);
color: lightgreen;
border: 1px solid lightgreen;
@@ -944,31 +944,31 @@ nav.ol-panel> :last-child {
align-items: center;
}
#rts-phase.game-commenced::before {
#command-mode-phase.game-commenced::before {
content: "Game commenced";
font-weight: bold;
}
#rts-phase.game-commenced::after {
#command-mode-phase.game-commenced::after {
content: "Spawn restrictions are being enforced";
font-size: 10px;
}
#rts-toolbar .ol-button {
#command-mode-toolbar .ol-button {
border: 1px solid white;
}
#rts-toolbar .ol-button>svg {
#command-mode-toolbar .ol-button>svg {
width: 20px;
height: 20px;
fill: white;
}
#rts-settings-dialog {
#command-mode-settings-dialog {
width: 400px;
}
#rts-settings-dialog>.ol-dialog-content {
#command-mode-settings-dialog>.ol-dialog-content {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
@@ -978,11 +978,11 @@ nav.ol-panel> :last-child {
width: 100%;
}
#rts-settings-dialog>.ol-dialog-content .ol-group {
#command-mode-settings-dialog>.ol-dialog-content .ol-group {
justify-content: space-between;
}
#rts-settings-dialog h4 {
#command-mode-settings-dialog h4 {
white-space: nowrap;
width: fit-content;
}

View File

@@ -19,7 +19,7 @@ interface CustomEventMap {
"mapStateChanged": CustomEvent<string>,
"mapContextMenu": CustomEvent<>,
"mapVisibilityOptionsChanged": CustomEvent<>,
"RTSOptionsChanged": CustomEvent<>,
"commandModeOptionsChanged": CustomEvent<>,
"contactsUpdated": CustomEvent<Unit>,
}

View File

@@ -14,13 +14,13 @@ interface MissionData {
mission: {
theatre: string,
dateAndTime: DateAndTime;
RTSOptions: RTSOptions;
commandModeOptions: CommandModeOptions;
}
time: number;
sessionHash: string;
}
interface RTSOptions {
interface CommandModeOptions {
commandMode: string;
restrictSpawns: boolean;
restrictToCoalition: boolean;

View File

@@ -1,6 +1,6 @@
import { getMap, getUnitsManager, setActiveCoalition } from "..";
import { getMap, getMissionHandler, getUnitsManager, setActiveCoalition } from "..";
import { BLUE_COMMANDER, GAME_MASTER, RED_COMMANDER } from "../constants/constants";
import { Airbase } from "../missionhandler/airbase";
import { Airbase } from "../mission/airbase";
import { ContextMenu } from "./contextmenu";
export class AirbaseContextMenu extends ContextMenu {
@@ -26,7 +26,7 @@ export class AirbaseContextMenu extends ContextMenu {
this.setParkings(airbase.getParkings());
this.setCoalition(airbase.getCoalition());
this.enableLandButton(getUnitsManager().getSelectedUnitsTypes().length == 1 && ["Aircraft", "Helicopter"].includes(getUnitsManager().getSelectedUnitsTypes()[0]) && (getUnitsManager().getSelectedUnitsCoalition() === airbase.getCoalition() || airbase.getCoalition() === "neutral"))
this.enableSpawnButton(getUnitsManager().getCommandMode() == GAME_MASTER || this.#airbase.getCoalition() == getUnitsManager().getCommandedCoalition());
this.enableSpawnButton(getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER || this.#airbase.getCoalition() == getMissionHandler().getCommandedCoalition());
}
setName(airbaseName: string) {

View File

@@ -1,5 +1,5 @@
import { LatLng } from "leaflet";
import { getMap, getUnitsManager } from "..";
import { getMap, getMissionHandler, getUnitsManager } from "..";
import { GAME_MASTER, IADSTypes } from "../constants/constants";
import { CoalitionArea } from "../map/coalitionarea";
import { ContextMenu } from "./contextmenu";
@@ -81,7 +81,7 @@ export class CoalitionAreaContextMenu extends ContextMenu {
return createCheckboxOption(range, `Add ${range} units to the IADS`);
}));
if (getUnitsManager().getCommandMode() !== GAME_MASTER)
if (getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER)
this.#coalitionSwitch.hide()
}
@@ -114,7 +114,7 @@ export class CoalitionAreaContextMenu extends ContextMenu {
}
#onSwitchClick(value: boolean) {
if (getUnitsManager().getCommandMode() == GAME_MASTER) {
if (getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER) {
this.getCoalitionArea()?.setCoalition(value ? "red" : "blue");
this.getContainer()?.querySelectorAll('[data-coalition]').forEach((element: any) => {
element.setAttribute("data-coalition", this.getCoalitionArea()?.getCoalition())

View File

@@ -169,7 +169,7 @@ export class MapContextMenu extends ContextMenu {
}
});
document.addEventListener("RTSOptionsChanged", (e: any) => {
document.addEventListener("commandModeOptionsChanged", (e: any) => {
this.#refreshOptions();
});
@@ -193,7 +193,7 @@ export class MapContextMenu extends ContextMenu {
else
this.#coalitionSwitch.setValue(undefined);
if (getUnitsManager().getCommandMode() !== GAME_MASTER)
if (getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER)
this.#coalitionSwitch.hide()
this.getContainer()?.querySelector("#coalition-area-button")?.classList.toggle("hide", true);
@@ -562,26 +562,26 @@ export class MapContextMenu extends ContextMenu {
}
#computeSpawnPoints() {
if (getMissionHandler() && getUnitsManager().getCommandMode() !== GAME_MASTER){
if (getMissionHandler() && getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER){
var aircraftCount = parseInt(this.#aircraftCountDropdown.getValue());
var aircraftSpawnPoints = aircraftCount * aircraftDatabase.getSpawnPointsByLabel(this.#aircraftLabelDropdown.getValue());
(<HTMLButtonElement>this.getContainer()?.querySelector("#aircraft-spawn-menu")?.querySelector(".deploy-unit-button")).dataset.points = `${aircraftSpawnPoints}`;
(<HTMLButtonElement>this.getContainer()?.querySelector("#aircraft-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = aircraftSpawnPoints > getMissionHandler().getAvailableSpawnPoints();
(<HTMLButtonElement>this.getContainer()?.querySelector("#aircraft-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = aircraftSpawnPoints >= getMissionHandler().getAvailableSpawnPoints();
var helicopterCount = parseInt(this.#helicopterCountDropdown.getValue());
var helicopterSpawnPoints = helicopterCount * helicopterDatabase.getSpawnPointsByLabel(this.#helicopterLabelDropdown.getValue());
(<HTMLButtonElement>this.getContainer()?.querySelector("#helicopter-spawn-menu")?.querySelector(".deploy-unit-button")).dataset.points = `${helicopterSpawnPoints}`;
(<HTMLButtonElement>this.getContainer()?.querySelector("#helicopter-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = helicopterSpawnPoints > getMissionHandler().getAvailableSpawnPoints();
(<HTMLButtonElement>this.getContainer()?.querySelector("#helicopter-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = helicopterSpawnPoints >= getMissionHandler().getAvailableSpawnPoints();
var groundUnitCount = parseInt(this.#groundUnitCountDropdown.getValue());
var groundUnitSpawnPoints = groundUnitCount * groundUnitDatabase.getSpawnPointsByLabel(this.#groundUnitLabelDropdown.getValue());
(<HTMLButtonElement>this.getContainer()?.querySelector("#groundunit-spawn-menu")?.querySelector(".deploy-unit-button")).dataset.points = `${groundUnitSpawnPoints}`;
(<HTMLButtonElement>this.getContainer()?.querySelector("#groundunit-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = groundUnitSpawnPoints > getMissionHandler().getAvailableSpawnPoints();
(<HTMLButtonElement>this.getContainer()?.querySelector("#groundunit-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = groundUnitSpawnPoints >= getMissionHandler().getAvailableSpawnPoints();
var navyUnitCount = parseInt(this.#navyUnitCountDropdown.getValue());
var navyUnitSpawnPoints = navyUnitCount * navyUnitDatabase.getSpawnPointsByLabel(this.#navyUnitLabelDropdown.getValue());
(<HTMLButtonElement>this.getContainer()?.querySelector("#navyunit-spawn-menu")?.querySelector(".deploy-unit-button")).dataset.points = `${navyUnitSpawnPoints}`;
(<HTMLButtonElement>this.getContainer()?.querySelector("#navyunit-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = navyUnitSpawnPoints > getMissionHandler().getAvailableSpawnPoints();
(<HTMLButtonElement>this.getContainer()?.querySelector("#navyunit-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = navyUnitSpawnPoints >= getMissionHandler().getAvailableSpawnPoints();
}
}
}

View File

@@ -2,7 +2,7 @@ import { Map } from "./map/map"
import { UnitsManager } from "./units/unitsmanager";
import { UnitInfoPanel } from "./panels/unitinfopanel";
import { ConnectionStatusPanel } from "./panels/connectionstatuspanel";
import { MissionHandler } from "./missionhandler/missionhandler";
import { MissionHandler } from "./mission/missionhandler";
import { UnitControlPanel } from "./panels/unitcontrolpanel";
import { MouseInfoPanel } from "./panels/mouseinfopanel";
import { AIC } from "./aic/aic";
@@ -255,17 +255,17 @@ export function getHotgroupPanel() {
}
export function setActiveCoalition(newActiveCoalition: string) {
if (getUnitsManager().getCommandMode() == GAME_MASTER)
if (getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER)
activeCoalition = newActiveCoalition;
}
export function getActiveCoalition() {
if (getUnitsManager().getCommandMode() == GAME_MASTER)
if (getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER)
return activeCoalition;
else {
if (getUnitsManager().getCommandMode() == BLUE_COMMANDER)
if (getMissionHandler().getCommandModeOptions().commandMode == BLUE_COMMANDER)
return "blue";
else if (getUnitsManager().getCommandMode() == RED_COMMANDER)
else if (getMissionHandler().getCommandModeOptions().commandMode == RED_COMMANDER)
return "red";
else
return "neutral";

View File

@@ -1,5 +1,5 @@
import { DomUtil, LatLng, LatLngExpression, Map, Point, Polygon, PolylineOptions } from "leaflet";
import { getMap, getUnitsManager } from "..";
import { getMap, getMissionHandler, getUnitsManager } from "..";
import { CoalitionAreaHandle } from "./coalitionareahandle";
import { CoalitionAreaMiddleHandle } from "./coalitionareamiddlehandle";
import { BLUE_COMMANDER, RED_COMMANDER } from "../constants/constants";
@@ -23,8 +23,8 @@ export class CoalitionArea extends Polygon {
this.#setColors();
this.#registerCallbacks();
if ([BLUE_COMMANDER, RED_COMMANDER].includes(getUnitsManager().getCommandMode()))
this.setCoalition(getUnitsManager().getCommandedCoalition());
if ([BLUE_COMMANDER, RED_COMMANDER].includes(getMissionHandler().getCommandModeOptions().commandMode))
this.setCoalition(getMissionHandler().getCommandedCoalition());
}
setCoalition(coalition: string) {

View File

@@ -5,7 +5,7 @@ import { MapContextMenu } from "../controls/mapcontextmenu";
import { UnitContextMenu } from "../controls/unitcontextmenu";
import { AirbaseContextMenu } from "../controls/airbasecontextmenu";
import { Dropdown } from "../controls/dropdown";
import { Airbase } from "../missionhandler/airbase";
import { Airbase } from "../mission/airbase";
import { Unit } from "../units/unit";
import { bearing, createCheckboxOption } from "../other/utils";
import { DestinationPreviewMarker } from "./destinationpreviewmarker";

View File

@@ -3,7 +3,7 @@ import { getInfoPopup, getMap, getUnitsManager } from "..";
import { Airbase } from "./airbase";
import { Bullseye } from "./bullseye";
import { BLUE_COMMANDER, GAME_MASTER, RED_COMMANDER } from "../constants/constants";
import { setRTSOptions } from "../server/server";
import { setCommandModeOptions } from "../server/server";
import { Dropdown } from "../controls/dropdown";
import { groundUnitDatabase } from "../units/groundunitdatabase";
import { createCheckboxOption, getCheckboxOptions } from "../other/utils";
@@ -16,20 +16,20 @@ export class MissionHandler {
#airbases: { [name: string]: Airbase } = {};
#theatre: string = "";
#dateAndTime: DateAndTime = {date: {Year: 0, Month: 0, Day: 0}, time: {h: 0, m: 0, s: 0}, startTime: 0, elapsedTime: 0};
#RTSOptions: RTSOptions = {commandMode: "Hide all", restrictSpawns: false, restrictToCoalition: false, setupTime: Infinity, spawnPoints: {red: Infinity, blue: Infinity}, eras: []};
#commandModeOptions: CommandModeOptions = {commandMode: "Hide all", restrictSpawns: false, restrictToCoalition: false, setupTime: Infinity, spawnPoints: {red: Infinity, blue: Infinity}, eras: []};
#remainingSetupTime: number = 0;
#spentSpawnPoint: number = 0;
#RTSSettingsDialog: HTMLElement;
#rtsErasDropdown: Dropdown;
#commandModeDialog: HTMLElement;
#commandModeErasDropdown: Dropdown;
constructor() {
document.addEventListener("showRTSSettingsDialog", () => this.showRTSSettingsDialog());
document.addEventListener("applyRTSOptions", () => this.#applyRTSOptions());
document.addEventListener("showCommandModeDialog", () => this.showCommandModeDialog());
document.addEventListener("applycommandModeOptions", () => this.#applycommandModeOptions());
/* RTS settings dialog */
this.#RTSSettingsDialog = <HTMLElement> document.querySelector("#rts-settings-dialog");
/* command-mode settings dialog */
this.#commandModeDialog = <HTMLElement> document.querySelector("#command-mode-settings-dialog");
this.#rtsErasDropdown = new Dropdown("rts-era-options", () => {});
this.#commandModeErasDropdown = new Dropdown("command-mode-era-options", () => {});
}
updateBullseyes(data: BullseyesData) {
@@ -65,27 +65,28 @@ export class MissionHandler {
updateMission(data: MissionData) {
if (data.mission) {
/* Set the mission theatre */
if (data.mission.theatre != this.#theatre) {
this.#theatre = data.mission.theatre;
getMap().setTheatre(this.#theatre);
getInfoPopup().setText("Map set to " + this.#theatre);
}
/* Set the date and time data */
this.#dateAndTime = data.mission.dateAndTime;
this.#setRTSOptions(data.mission.RTSOptions);
getUnitsManager().setCommandMode(this.#RTSOptions.commandMode);
this.#remainingSetupTime = this.#RTSOptions.setupTime - this.getDateAndTime().elapsedTime;
var RTSPhaseEl = document.querySelector("#rts-phase") as HTMLElement;
if (RTSPhaseEl) {
/* Set the command mode options */
this.#setcommandModeOptions(data.mission.commandModeOptions);
this.#remainingSetupTime = this.getCommandModeOptions().setupTime - this.getDateAndTime().elapsedTime;
var commandModePhaseEl = document.querySelector("#command-mode-phase") as HTMLElement;
if (commandModePhaseEl) {
if (this.#remainingSetupTime > 0) {
var remainingTime = `-${new Date(this.#remainingSetupTime * 1000).toISOString().substring(14, 19)}`;
RTSPhaseEl.dataset.remainingTime = remainingTime;
commandModePhaseEl.dataset.remainingTime = remainingTime;
}
RTSPhaseEl.classList.toggle("setup-phase", this.#remainingSetupTime > 0);
RTSPhaseEl.classList.toggle("game-commenced", this.#remainingSetupTime <= 0);
commandModePhaseEl.classList.toggle("setup-phase", this.#remainingSetupTime > 0);
commandModePhaseEl.classList.toggle("game-commenced", this.#remainingSetupTime <= 0);
}
}
}
@@ -98,8 +99,8 @@ export class MissionHandler {
return this.#airbases;
}
getRTSOptions() {
return this.#RTSOptions;
getCommandModeOptions() {
return this.#commandModeOptions;
}
getDateAndTime() {
@@ -111,16 +112,25 @@ export class MissionHandler {
}
getAvailableSpawnPoints() {
if (getUnitsManager().getCommandMode() === GAME_MASTER)
if (this.getCommandModeOptions().commandMode === GAME_MASTER)
return Infinity;
else if (getUnitsManager().getCommandMode() === BLUE_COMMANDER)
return this.getRTSOptions().spawnPoints.blue - this.#spentSpawnPoint;
else if (getUnitsManager().getCommandMode() === RED_COMMANDER)
return this.getRTSOptions().spawnPoints.red - this.#spentSpawnPoint;
else if (this.getCommandModeOptions().commandMode === BLUE_COMMANDER)
return this.getCommandModeOptions().spawnPoints.blue - this.#spentSpawnPoint;
else if (this.getCommandModeOptions().commandMode === RED_COMMANDER)
return this.getCommandModeOptions().spawnPoints.red - this.#spentSpawnPoint;
else
return 0;
}
getCommandedCoalition() {
if (this.getCommandModeOptions().commandMode === BLUE_COMMANDER)
return "blue";
else if (this.getCommandModeOptions().commandMode === RED_COMMANDER)
return "red";
else
return "all";
}
refreshSpawnPoints() {
var spawnPointsEl = document.querySelector("#spawn-points");
if (spawnPointsEl) {
@@ -133,68 +143,68 @@ export class MissionHandler {
this.refreshSpawnPoints();
}
showRTSSettingsDialog() {
showCommandModeDialog() {
/* Create the checkboxes to select the unit eras */
var eras = aircraftDatabase.getEras().concat(helicopterDatabase.getEras()).concat(groundUnitDatabase.getEras()).concat(navyUnitDatabase.getEras());
eras = eras.filter((item: string, index: number) => eras.indexOf(item) === index).sort();
this.#rtsErasDropdown.setOptionsElements(eras.map((era: string) => {
return createCheckboxOption(era, `Enable ${era} units spawns`, this.#RTSOptions.eras.includes(era));
this.#commandModeErasDropdown.setOptionsElements(eras.map((era: string) => {
return createCheckboxOption(era, `Enable ${era} units spawns`, this.getCommandModeOptions().eras.includes(era));
}));
this.#RTSSettingsDialog.classList.remove("hide");
this.#commandModeDialog.classList.remove("hide");
const restrictSpawnsCheckbox = this.#RTSSettingsDialog.querySelector("#restrict-spawns")?.querySelector("input") as HTMLInputElement;
const restrictToCoalitionCheckbox = this.#RTSSettingsDialog.querySelector("#restrict-to-coalition")?.querySelector("input") as HTMLInputElement;
const blueSpawnPointsInput = this.#RTSSettingsDialog.querySelector("#blue-spawn-points")?.querySelector("input") as HTMLInputElement;
const redSpawnPointsInput = this.#RTSSettingsDialog.querySelector("#red-spawn-points")?.querySelector("input") as HTMLInputElement;
const setupTimeInput = this.#RTSSettingsDialog.querySelector("#setup-time")?.querySelector("input") as HTMLInputElement;
const restrictSpawnsCheckbox = this.#commandModeDialog.querySelector("#restrict-spawns")?.querySelector("input") as HTMLInputElement;
const restrictToCoalitionCheckbox = this.#commandModeDialog.querySelector("#restrict-to-coalition")?.querySelector("input") as HTMLInputElement;
const blueSpawnPointsInput = this.#commandModeDialog.querySelector("#blue-spawn-points")?.querySelector("input") as HTMLInputElement;
const redSpawnPointsInput = this.#commandModeDialog.querySelector("#red-spawn-points")?.querySelector("input") as HTMLInputElement;
const setupTimeInput = this.#commandModeDialog.querySelector("#setup-time")?.querySelector("input") as HTMLInputElement;
restrictSpawnsCheckbox.checked = this.#RTSOptions.restrictSpawns;
restrictToCoalitionCheckbox.checked = this.#RTSOptions.restrictToCoalition;
blueSpawnPointsInput.value = String(this.#RTSOptions.spawnPoints.blue);
redSpawnPointsInput.value = String(this.#RTSOptions.spawnPoints.red);
setupTimeInput.value = String(Math.floor(this.#RTSOptions.setupTime / 60.0));
restrictSpawnsCheckbox.checked = this.getCommandModeOptions().restrictSpawns;
restrictToCoalitionCheckbox.checked = this.getCommandModeOptions().restrictToCoalition;
blueSpawnPointsInput.value = String(this.getCommandModeOptions().spawnPoints.blue);
redSpawnPointsInput.value = String(this.getCommandModeOptions().spawnPoints.red);
setupTimeInput.value = String(Math.floor(this.getCommandModeOptions().setupTime / 60.0));
}
#applyRTSOptions() {
this.#RTSSettingsDialog.classList.add("hide");
#applycommandModeOptions() {
this.#commandModeDialog.classList.add("hide");
const restrictSpawnsCheckbox = this.#RTSSettingsDialog.querySelector("#restrict-spawns")?.querySelector("input") as HTMLInputElement;
const restrictToCoalitionCheckbox = this.#RTSSettingsDialog.querySelector("#restrict-to-coalition")?.querySelector("input") as HTMLInputElement;
const blueSpawnPointsInput = this.#RTSSettingsDialog.querySelector("#blue-spawn-points")?.querySelector("input") as HTMLInputElement;
const redSpawnPointsInput = this.#RTSSettingsDialog.querySelector("#red-spawn-points")?.querySelector("input") as HTMLInputElement;
const setupTimeInput = this.#RTSSettingsDialog.querySelector("#setup-time")?.querySelector("input") as HTMLInputElement;
const restrictSpawnsCheckbox = this.#commandModeDialog.querySelector("#restrict-spawns")?.querySelector("input") as HTMLInputElement;
const restrictToCoalitionCheckbox = this.#commandModeDialog.querySelector("#restrict-to-coalition")?.querySelector("input") as HTMLInputElement;
const blueSpawnPointsInput = this.#commandModeDialog.querySelector("#blue-spawn-points")?.querySelector("input") as HTMLInputElement;
const redSpawnPointsInput = this.#commandModeDialog.querySelector("#red-spawn-points")?.querySelector("input") as HTMLInputElement;
const setupTimeInput = this.#commandModeDialog.querySelector("#setup-time")?.querySelector("input") as HTMLInputElement;
var eras: string[] = [];
const enabledEras = getCheckboxOptions(this.#rtsErasDropdown);
const enabledEras = getCheckboxOptions(this.#commandModeErasDropdown);
Object.keys(enabledEras).forEach((key: string) => {if (enabledEras[key]) eras.push(key)});
setRTSOptions(restrictSpawnsCheckbox.checked, restrictToCoalitionCheckbox.checked, {blue: parseInt(blueSpawnPointsInput.value), red: parseInt(redSpawnPointsInput.value)}, eras, parseInt(setupTimeInput.value) * 60);
setCommandModeOptions(restrictSpawnsCheckbox.checked, restrictToCoalitionCheckbox.checked, {blue: parseInt(blueSpawnPointsInput.value), red: parseInt(redSpawnPointsInput.value)}, eras, parseInt(setupTimeInput.value) * 60);
}
#setRTSOptions(RTSOptions: RTSOptions) {
var RTSOptionsChanged = (!RTSOptions.eras.every((value: string, idx: number) => {return value === this.#RTSOptions.eras[idx]}) ||
RTSOptions.spawnPoints.red !== this.#RTSOptions.spawnPoints.red ||
RTSOptions.spawnPoints.blue !== this.#RTSOptions.spawnPoints.blue ||
RTSOptions.restrictSpawns !== this.#RTSOptions.restrictSpawns ||
RTSOptions.restrictToCoalition !== this.#RTSOptions.restrictToCoalition);
#setcommandModeOptions(commandModeOptions: CommandModeOptions) {
var commandModeOptionsChanged = (!commandModeOptions.eras.every((value: string, idx: number) => {return value === this.getCommandModeOptions().eras[idx]}) ||
commandModeOptions.spawnPoints.red !== this.getCommandModeOptions().spawnPoints.red ||
commandModeOptions.spawnPoints.blue !== this.getCommandModeOptions().spawnPoints.blue ||
commandModeOptions.restrictSpawns !== this.getCommandModeOptions().restrictSpawns ||
commandModeOptions.restrictToCoalition !== this.getCommandModeOptions().restrictToCoalition);
this.#RTSOptions = RTSOptions;
this.#commandModeOptions = commandModeOptions;
this.setSpentSpawnPoints(0);
this.refreshSpawnPoints();
if (RTSOptionsChanged) {
document.dispatchEvent(new CustomEvent("RTSOptionsChanged", { detail: this }));
if (commandModeOptionsChanged) {
document.dispatchEvent(new CustomEvent("commandModeOptionsChanged", { detail: this }));
document.getElementById("rts-toolbar")?.classList.remove("hide");
document.getElementById("command-mode-toolbar")?.classList.remove("hide");
const el = document.getElementById("command-mode");
if (el) {
el.dataset.mode = RTSOptions.commandMode;
el.textContent = RTSOptions.commandMode.toUpperCase();
el.dataset.mode = commandModeOptions.commandMode;
el.textContent = commandModeOptions.commandMode.toUpperCase();
}
}
document.querySelector("#spawn-points-container")?.classList.toggle("hide", getUnitsManager().getCommandMode() === GAME_MASTER);
document.querySelector("#rts-settings-button")?.classList.toggle("hide", getUnitsManager().getCommandMode() !== GAME_MASTER);
document.querySelector("#spawn-points-container")?.classList.toggle("hide", this.getCommandModeOptions().commandMode === GAME_MASTER || !this.getCommandModeOptions().restrictSpawns);
document.querySelector("#command-mode-settings-button")?.classList.toggle("hide", this.getCommandModeOptions().commandMode !== GAME_MASTER);
}
#onAirbaseClick(e: any) {

View File

@@ -4,6 +4,7 @@ export class LogPanel extends Panel {
#open: boolean = false;
#queuedMessages: number = 0;
#scrolledDown: boolean = true;
#logs: {[key: string]: string} = {};
constructor(ID: string) {
super(ID);
@@ -26,8 +27,13 @@ export class LogPanel extends Panel {
}
}
appendLogs(logs: string[]) {
logs.forEach((log: string) => this.appendLog(log));
appendLogs(logs: {[key: string]: string}) {
Object.keys(logs).forEach((key: string) => {
if (!(key in this.#logs)) {
this.#logs[key] = logs[key];
this.appendLog(logs[key]);
}
});
}
appendLog(log: string) {

View File

@@ -320,7 +320,7 @@ export function setAdvacedOptions(ID: number, isTanker: boolean, isAWACS: boolea
POST(data, () => { });
}
export function setRTSOptions(restrictSpawns: boolean, restrictToCoalition: boolean, spawnPoints: {blue: number, red: number}, eras: string[], setupTime: number) {
export function setCommandModeOptions(restrictSpawns: boolean, restrictToCoalition: boolean, spawnPoints: {blue: number, red: number}, eras: string[], setupTime: number) {
var command = {
"restrictSpawns": restrictSpawns,
"restrictToCoalition": restrictToCoalition,
@@ -329,7 +329,7 @@ export function setRTSOptions(restrictSpawns: boolean, restrictToCoalition: bool
"setupTime": setupTime
};
var data = { "setRTSOptions": command };
var data = { "setCommandModeOptions": command };
POST(data, () => { });
}
@@ -351,7 +351,7 @@ export function startUpdate() {
return data.time;
});
getLogs((data: any) => {
getLogPanel().appendLogs(Object.values(data.logs))
getLogPanel().appendLogs(data.logs)
return data.time;
});
getUnits((buffer: ArrayBuffer) => {return getUnitsManager()?.update(buffer), true /* Does a full refresh */});
@@ -389,7 +389,7 @@ export function requestRefresh() {
return data.time;
});
getLogs((data: any) => {
getLogPanel().appendLogs(Object.values(data.logs))
getLogPanel().appendLogs(data.logs)
return data.time;
});

View File

@@ -1,4 +1,4 @@
import { getUnitsManager } from "..";
import { getMissionHandler } from "..";
import { GAME_MASTER } from "../constants/constants";
import { UnitDatabase } from "./unitdatabase"
@@ -3982,7 +3982,7 @@ export class AircraftDatabase extends UnitDatabase {
}
getSpawnPointsByName(name: string) {
if (getUnitsManager().getCommandMode() == GAME_MASTER)
if (getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER || !getMissionHandler().getCommandModeOptions().restrictSpawns)
return 0;
const blueprint = this.getByName(name);

View File

@@ -1,4 +1,4 @@
import { getUnitsManager } from "..";
import { getMissionHandler} from "..";
import { GAME_MASTER } from "../constants/constants";
import { UnitDatabase } from "./unitdatabase"
@@ -1463,7 +1463,7 @@ export class GroundUnitDatabase extends UnitDatabase {
}
getSpawnPointsByName(name: string) {
if (getUnitsManager().getCommandMode() == GAME_MASTER)
if (getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER || !getMissionHandler().getCommandModeOptions().restrictSpawns)
return 0;
const blueprint = this.getByName(name);

View File

@@ -1,4 +1,4 @@
import { getUnitsManager } from "..";
import { getMissionHandler } from "..";
import { GAME_MASTER } from "../constants/constants";
import { UnitDatabase } from "./unitdatabase"
@@ -595,7 +595,7 @@ export class HelicopterDatabase extends UnitDatabase {
}
getSpawnPointsByName(name: string) {
if (getUnitsManager().getCommandMode() == GAME_MASTER)
if (getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER || !getMissionHandler().getCommandModeOptions().restrictSpawns)
return 0;
const blueprint = this.getByName(name);

View File

@@ -1,4 +1,4 @@
import { getUnitsManager } from "..";
import { getMissionHandler } from "..";
import { GAME_MASTER } from "../constants/constants";
import { UnitDatabase } from "./unitdatabase"
@@ -461,7 +461,7 @@ export class NavyUnitDatabase extends UnitDatabase {
}
getSpawnPointsByName(name: string) {
if (getUnitsManager().getCommandMode() == GAME_MASTER)
if (getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER || !getMissionHandler().getCommandModeOptions().restrictSpawns)
return 0;
const blueprint = this.getByName(name);

View File

@@ -1,5 +1,5 @@
import { Marker, LatLng, Polyline, Icon, DivIcon, CircleMarker, Map, Point } from 'leaflet';
import { getMap, getUnitsManager } from '..';
import { getMap, getMissionHandler, getUnitsManager } from '..';
import { enumToCoalition, enumToEmissioNCountermeasure, getMarkerCategoryByName, enumToROE, enumToReactionToThreat, enumToState, getUnitDatabaseByCategory, mToFt, msToKnots, rad2deg, bearing, deg2rad } from '../other/utils';
import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, landAt, setAltitude, setReactionToThreat, setROE, setSpeed, refuel, setAdvacedOptions, followUnit, setEmissionsCountermeasures, setSpeedType, setAltitudeType, setOnOff, setFollowRoads, bombPoint, carpetBomb, bombBuilding, fireAtArea } from '../server/server';
import { CustomMarker } from '../map/custommarker';
@@ -336,7 +336,7 @@ export class Unit extends CustomMarker {
}
this.getElement()?.querySelector(`.unit`)?.toggleAttribute("data-is-selected", selected);
if (getMap().getZoom() < 13) {
if (this.getCategory() === "GroundUnit" && getMap().getZoom() < 13) {
if (this.#isLeader)
this.getGroupMembers().forEach((unit: Unit) => unit.setSelected(selected));
else
@@ -384,7 +384,7 @@ export class Unit extends CustomMarker {
}
belongsToCommandedCoalition() {
if (getUnitsManager().getCommandMode() !== GAME_MASTER && getUnitsManager().getCommandedCoalition() !== this.#coalition)
if (getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER && getMissionHandler().getCommandedCoalition() !== this.#coalition)
return false;
return true;
}
@@ -1019,7 +1019,7 @@ export class Unit extends CustomMarker {
}
else if (this.#targetID != 0 && getMap().getVisibilityOptions()[SHOW_UNIT_TARGETS]) {
const target = getUnitsManager().getUnitByID(this.#targetID);
if (target && (getUnitsManager().getCommandMode() == GAME_MASTER || (this.belongsToCommandedCoalition() && getUnitsManager().getUnitDetectedMethods(target).some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))))) {
if (target && (getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER || (this.belongsToCommandedCoalition() && getUnitsManager().getUnitDetectedMethods(target).some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))))) {
this.#drawTargetPosition(target.getPosition());
}
}

View File

@@ -30,15 +30,15 @@ export class UnitDatabase {
}
getBlueprints() {
if (getUnitsManager().getCommandMode() == GAME_MASTER || !getMissionHandler().getRTSOptions().restrictSpawns)
if (getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER || !getMissionHandler().getCommandModeOptions().restrictSpawns)
return this.blueprints;
else {
var filteredBlueprints: { [key: string]: UnitBlueprint } = {};
for (let unit in this.blueprints) {
const blueprint = this.blueprints[unit];
if (this.getSpawnPointsByName(blueprint.name) < getMissionHandler().getAvailableSpawnPoints() &&
getMissionHandler().getRTSOptions().eras.includes(blueprint.era) &&
(!getMissionHandler().getRTSOptions().restrictToCoalition || blueprint.coalition === getUnitsManager().getCommandedCoalition())) {
if (this.getSpawnPointsByName(blueprint.name) <= getMissionHandler().getAvailableSpawnPoints() &&
getMissionHandler().getCommandModeOptions().eras.includes(blueprint.era) &&
(!getMissionHandler().getCommandModeOptions().restrictToCoalition || blueprint.coalition === getMissionHandler().getCommandedCoalition())) {
filteredBlueprints[unit] = blueprint;
}
}

View File

@@ -5,7 +5,7 @@ import { cloneUnit, deleteUnit, spawnAircrafts, spawnGroundUnits, spawnHelicopte
import { bearingAndDistanceToLatLng, deg2rad, keyEventWasInInput, latLngToMercator, mToFt, mercatorToLatLng, msToKnots, polyContains, polygonArea, randomPointInPoly, randomUnitBlueprint } from "../other/utils";
import { CoalitionArea } from "../map/coalitionarea";
import { groundUnitDatabase } from "./groundunitdatabase";
import { BLUE_COMMANDER, DataIndexes, GAME_MASTER, IADSDensities, IDLE, MOVE_UNIT, NONE, RED_COMMANDER } from "../constants/constants";
import { DataIndexes, GAME_MASTER, IADSDensities, IDLE, MOVE_UNIT, NONE } from "../constants/constants";
import { DataExtractor } from "./dataextractor";
import { Contact } from "../@types/unit";
import { citiesDatabase } from "./citiesdatabase";
@@ -19,7 +19,6 @@ export class UnitsManager {
#selectionEventDisabled: boolean = false;
#pasteDisabled: boolean = false;
#hiddenTypes: string[] = [];
#commandMode: string = NONE;
#requestDetectionUpdate: boolean = false;
constructor() {
@@ -36,6 +35,7 @@ export class UnitsManager {
document.addEventListener('exportToFile', () => this.exportToFile());
document.addEventListener('importFromFile', () => this.importFromFile());
document.addEventListener('contactsUpdated', (e: CustomEvent) => {this.#requestDetectionUpdate = true});
document.addEventListener("commandModeOptionsChanged", () => {Object.values(this.#units).forEach((unit: Unit) => unit.updateVisibility())});
}
getSelectableAircraft() {
@@ -96,7 +96,7 @@ export class UnitsManager {
this.#units[ID]?.setData(dataExtractor);
}
if (this.#requestDetectionUpdate && this.getCommandMode() != GAME_MASTER) {
if (this.#requestDetectionUpdate && getMissionHandler().getCommandModeOptions().commandMode != GAME_MASTER) {
for (let ID in this.#units) {
var unit = this.#units[ID];
if (!unit.belongsToCommandedCoalition())
@@ -127,28 +127,6 @@ export class UnitsManager {
return this.#hiddenTypes;
}
setCommandMode(newCommandMode: string) {
if (newCommandMode !== this.#commandMode) {
document.dispatchEvent(new CustomEvent("commandModeChanged", { detail: this }));
this.#commandMode = newCommandMode;
for (let ID in this.#units)
this.#units[ID].updateVisibility();
}
}
getCommandMode() {
return this.#commandMode;
}
getCommandedCoalition() {
if (this.getCommandMode() === BLUE_COMMANDER)
return "blue";
else if (this.getCommandMode() === RED_COMMANDER)
return "red";
else
return "all";
}
selectUnit(ID: number, deselectAllUnits: boolean = true) {
if (deselectAllUnits)
this.getSelectedUnits().filter((unit: Unit) => unit.ID !== ID).forEach((unit: Unit) => unit.setSelected(false));
@@ -573,7 +551,7 @@ export class UnitsManager {
}
pasteUnits() {
if (!this.#pasteDisabled && getUnitsManager().getCommandMode() == GAME_MASTER) {
if (!this.#pasteDisabled && getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER) {
/* Compute the position of the center of the copied units */
var nUnits = this.#copiedUnits.length;
var avgLat = 0;
@@ -613,7 +591,7 @@ export class UnitsManager {
getInfoPopup().setText(`${this.#copiedUnits.length - 1} units pasted`);
}
else {
getInfoPopup().setText(`Unit cloning is disabled in ${getUnitsManager().getCommandMode()} mode`);
getInfoPopup().setText(`Unit cloning is disabled in ${getMissionHandler().getCommandModeOptions().commandMode} mode`);
}
}
@@ -690,34 +668,35 @@ export class UnitsManager {
spawnUnits(category: string, units: any, coalition: string = "blue", immediate: boolean = true, airbase: string = "") {
var spawnPoints = 0;
if (category === "Aircraft") {
if (airbase == "" && getMissionHandler().getRemainingSetupTime() < 0 && this.getCommandMode() !== GAME_MASTER) {
if (airbase == "" && getMissionHandler().getRemainingSetupTime() < 0 && getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER) {
getInfoPopup().setText("Aircrafts can be air spawned during the SETUP phase only");
return false;
}
spawnPoints = units.reduce((points: number, unit: any) => {return points + aircraftDatabase.getSpawnPointsByName(unit.unitType)}, 0);
spawnAircrafts(units, coalition, airbase, immediate, spawnPoints);
} else if (category === "Helicopter") {
if (airbase == "" && getMissionHandler().getRemainingSetupTime() < 0 && this.getCommandMode() !== GAME_MASTER) {
if (airbase == "" && getMissionHandler().getRemainingSetupTime() < 0 && getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER) {
getInfoPopup().setText("Helicopters can be air spawned during the SETUP phase only");
return false;
}
spawnPoints = units.reduce((points: number, unit: any) => {return points + helicopterDatabase.getSpawnPointsByName(unit.unitType)}, 0);
spawnHelicopters(units, coalition, airbase, immediate, spawnPoints);
} else if (category === "GroundUnit") {
if (getMissionHandler().getRemainingSetupTime() < 0 && this.getCommandMode() !== GAME_MASTER) {
if (getMissionHandler().getRemainingSetupTime() < 0 && getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER) {
getInfoPopup().setText("Ground units can be spawned during the SETUP phase only");
return false;
}
spawnPoints = units.reduce((points: number, unit: any) => {return points + groundUnitDatabase.getSpawnPointsByName(unit.unitType)}, 0);
spawnGroundUnits(units, coalition, immediate, spawnPoints);
} else if (category === "NavyUnit") {
if (getMissionHandler().getRemainingSetupTime() < 0 && this.getCommandMode() !== GAME_MASTER) {
if (getMissionHandler().getRemainingSetupTime() < 0 && getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER) {
getInfoPopup().setText("Navy units can be spawned during the SETUP phase only");
return false;
}
spawnPoints = units.reduce((points: number, unit: any) => {return points + navyUnitDatabase.getSpawnPointsByName(unit.unitType)}, 0);
spawnNavyUnits(units, coalition, immediate, spawnPoints);
}
if (spawnPoints <= getMissionHandler().getAvailableSpawnPoints()) {
getMissionHandler().setSpentSpawnPoints(spawnPoints);
return true;

View File

@@ -30,7 +30,7 @@
<div id="toolbar-container">
<%- include('toolbars/primary.ejs') %>
<%- include('toolbars/rts.ejs') %>
<%- include('toolbars/commandmode.ejs') %>
</div>
<%- include('other/dialogs.ejs') %>

View File

@@ -233,11 +233,11 @@
</div>
<div id="rts-settings-dialog" class="ol-panel ol-dialog olympus-dialog-close hide" oncontextmenu="return false;">
<div id="command-mode-settings-dialog" class="ol-panel ol-dialog olympus-dialog-close hide" oncontextmenu="return false;">
<div class="ol-dialog-close" data-on-click="closeDialog"></div>
<div class="ol-dialog-header">
<h3 id="unit-name">RTS mode settings</h3>
<h3 id="unit-name">command-mode mode settings</h3>
</div>
<div class="ol-dialog-content">
@@ -269,7 +269,7 @@
<div class="ol-group">
<label>Available eras: </label>
<div id="rts-era-options" class="ol-select">
<div id="command-mode-era-options" class="ol-select">
<div class="ol-select-value">Select eras</div>
<div class="ol-select-options">
<!-- This is where all the available era buttons will be shown-->
@@ -299,7 +299,7 @@
</div>
<div class="ol-dialog-footer ol-group">
<button class="ol-button-apply" data-on-click="applyRTSOptions">Apply</button>
<button class="ol-button-apply" data-on-click="applycommandModeOptions">Apply</button>
<button class="ol-button-close" data-on-click="closeDialog">Close</button>
</div>
</div>

View File

@@ -0,0 +1,6 @@
<nav id="command-mode-toolbar" class="ol-panel hide" oncontextmenu="return false;">
<span id="command-mode"></span>
<div id="spawn-points-container">Spawn points<span id="spawn-points"></span></div>
<span id="command-mode-phase"></span>
<button id="command-mode-settings-button" class="ol-button" data-on-click="showCommandModeDialog"><img src="/resources/theme/images/icons/gears-solid.svg" inject-svg>Settings</button>
</nav>

View File

@@ -1,6 +0,0 @@
<nav id="rts-toolbar" class="ol-panel hide" oncontextmenu="return false;">
<span id="command-mode"></span>
<div id="spawn-points-container">Spawn points<span id="spawn-points"></span></div>
<span id="rts-phase"></span>
<button id="rts-settings-button" class="ol-button" data-on-click="showRTSSettingsDialog"><img src="/resources/theme/images/icons/gears-solid.svg" inject-svg>Settings</button>
</nav>