Completed RTS front end

This commit is contained in:
Pax1601 2023-07-20 17:49:41 +02:00
parent 2e113b468a
commit 5613394a2c
19 changed files with 368 additions and 101 deletions

View File

@ -114,6 +114,8 @@ class DemoDataGenerator {
'red': 'redsocks'
},
}))
this.startTime = Date.now();
}
units(req, res){
@ -380,18 +382,37 @@ class DemoDataGenerator {
mission(req, res){
var ret = {mission: {theatre: "Nevada"}};
ret.time = Date.now();
ret.mission.dateAndTime = {
time: Date.now(),
date: "",
elapsedTime: (Date.now() - this.startTime) / 1000,
startTime: 0
}
ret.mission.RTSOptions = {
restrictSpawns: true,
restrictToCoalition: true,
setupTime: 300,
spawnPoints: {
red: 1000,
blue: 400
},
eras: ["WW2", "Early Cold War", "Late Cold War", "Modern"]
}
var auth = req.get("Authorization");
if (auth) {
var username = atob(auth.replace("Basic ", "")).split(":")[0];
switch (username) {
case "admin":
ret.mission.visibilityMode = "Game master";
ret.mission.RTSOptions.commandMode = "Game master";
break
case "blue":
ret.mission.visibilityMode = "Blue commander";
ret.mission.RTSOptions.commandMode = "Blue commander";
break;
case "red":
ret.mission.visibilityMode = "Red commander";
ret.mission.RTSOptions.commandMode = "Red commander";
break;
}
}

View File

@ -131,7 +131,7 @@ form>div {
.ol-panel {
background-color: var(--background-steel);
border-radius: 15px;
border-radius: var(--border-radius-md);;
box-shadow: 0px 2px 5px #000A;
color: white;
font-size: 12px;
@ -704,7 +704,7 @@ nav.ol-panel> :last-child {
background-image: url("/resources/theme/images/splash/1.png");
background-position: 100% 50%;
background-size: 60%;
border-radius: var(--border-radius-lg);
border-radius: var(--border-radius-md);
overflow: hidden;
width: 1200px;
z-index: 99999;
@ -868,36 +868,122 @@ nav.ol-panel> :last-child {
}
#command-mode {
display: flex;
font-size: 14px;
font-weight: bolder;
padding-left: 10px;
margin-left: -11px;
margin-top: -0px;
margin-bottom: -0px;
height: 58px;
padding: 10px;
border-top-left-radius: var(--border-radius-md);
border-bottom-left-radius: var(--border-radius-md);
align-items: center;
}
#command-mode[data-mode="Game master"] {
background-color: lightgray;
color: var(--secondary-gunmetal-grey);
}
#command-mode[data-mode="Blue commander"] {
color: var(--primary-blue);
background-color: var(--primary-blue);
}
#command-mode[data-mode="Red commander"] {
color: var(--primary-red);
background-color: var(--primary-red);
}
#spawn-points-container {
font-size: 14px;
font-weight: bolder;
}
#spawn-points {
background-color: var(--background-grey);
padding: 5px 15px;
margin: 5px;
margin-left: 15px;
border: 1px white solid;
font-size: 14px;
border-radius: var(--border-radius-sm);
border-radius: var(--border-radius-md);
}
#rts-phase {
#spawn-points-container {
height: 100%;
border-right: 1px solid gray;
display: flex;
align-items: center;
padding-right: 20px;
}
#rts-phase::before {
content: "Time to start";
font-size: 14px;
font-weight: bolder;
}
#rts-phase.setup-phase::after {
color: orange;
border: 1px solid orange;
border-radius: 999px;
padding: 5px 10px;
background-color: var(--background-grey);
margin-left: 15px;
content: attr(data-remaining-time);
font-size: 14px;
}
#rts-phase.game-commenced {
background-color: var(--background-grey);
color: lightgreen;
border: 1px solid lightgreen;
padding: 5px 15px;
border-radius: var(--border-radius-md);
display: flex;
flex-direction: column;
align-items: center;
}
#rts-phase.game-commenced::before {
content: "Game commenced";
font-weight: bold;
}
#rts-phase.game-commenced::after {
content: "Spawn restrictions are being enforced";
font-size: 10px;
}
#rts-toolbar .ol-button {
border: 1px solid white;
}
#rts-toolbar .ol-button>svg {
width: 20px;
height: 20px;
fill: white;
}
#rts-settings-dialog {
width: 400px;
}
#rts-settings-dialog>.ol-dialog-content {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
margin-bottom: 10px;
margin-top: 10px;
row-gap: 10px;
width: 100%;
}
#rts-settings-dialog>.ol-dialog-content .ol-group {
justify-content: space-between;
}
#rts-settings-dialog h4 {
white-space: nowrap;
width: fit-content;
}
.ol-destination-preview-icon {

View File

@ -69,7 +69,7 @@
width: 100%;
}
.deploy-unit-button[data-points]:not([data-points='']):not([data-points='0'])::after {
.deploy-unit-button[data-points]:not([data-points='']):not([data-points='0']):not([data-points='Infinity'])::after {
content: " (" attr(data-points) " points)";
}

View File

@ -25,7 +25,7 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
#unit-control-panel #selected-units-container button {
align-items: center;
border-radius: var(--border-radius-lg);
border-radius: var(--border-radius-md);
display: flex;
font-size: 11px;
height: 32px;

View File

@ -27,7 +27,7 @@
}
#current-task {
border-radius: var(--border-radius-lg);
border-radius: var(--border-radius-md);
margin-top: auto;
padding: 6px 16px;
}

View File

@ -10,6 +10,16 @@ interface BullseyesData {
time: number;
}
interface MissionData {
mission: {
theatre: string,
dateAndTime: DateAndTime;
RTSOptions: RTSOptions;
}
time: number;
sessionHash: string;
}
interface RTSOptions {
commandMode: string;
restrictSpawns: boolean;
@ -29,14 +39,6 @@ interface DateAndTime {
startTime: number;
}
interface MissionData {
theatre: string,
dateAndTime: DateAndTime;
RTSOptions: RTSOptions;
time: number;
sessionHash: string;
}
interface LogData {
logs: {[key: string]: string},
sessionHash: string;

View File

@ -1,5 +1,6 @@
import { LatLng, LatLngBounds } from "leaflet";
export const NONE = "None";
export const GAME_MASTER = "Game master";
export const BLUE_COMMANDER = "Blue commander";
export const RED_COMMANDER = "Red commander";

View File

@ -7,6 +7,7 @@ import { Dropdown } from "./dropdown";
import { Slider } from "./slider";
import { Switch } from "./switch";
import { groundUnitDatabase } from "../units/groundunitdatabase";
import { createCheckboxOption, getCheckboxOptions } from "../other/utils";
export class CoalitionAreaContextMenu extends ContextMenu {
#coalitionSwitch: Switch;
@ -56,7 +57,7 @@ export class CoalitionAreaContextMenu extends ContextMenu {
document.addEventListener("contextMenuCreateIads", (e: any) => {
const area = this.getCoalitionArea();
if (area)
getUnitsManager().createIADS(area, this.#getCheckboxOptions(this.#iadsTypesDropdown), this.#getCheckboxOptions(this.#iadsErasDropdown), this.#getCheckboxOptions(this.#iadsRangesDropdown), this.#iadsDensitySlider.getValue(), this.#iadsDistributionSlider.getValue());
getUnitsManager().createIADS(area, getCheckboxOptions(this.#iadsTypesDropdown), getCheckboxOptions(this.#iadsErasDropdown), getCheckboxOptions(this.#iadsRangesDropdown), this.#iadsDensitySlider.getValue(), this.#iadsDistributionSlider.getValue());
})
this.hide();
}
@ -66,18 +67,18 @@ export class CoalitionAreaContextMenu extends ContextMenu {
/* Create the checkboxes to select the unit roles */
this.#iadsTypesDropdown.setOptionsElements(IADSTypes.map((role: string) => {
return this.#createCheckboxOption(role);
return createCheckboxOption(role, `Add ${role}s to the IADS` );
}));
/* Create the checkboxes to select the unit periods */
this.#iadsErasDropdown.setOptionsElements(groundUnitDatabase.getEras().map((era: string) => {
return this.#createCheckboxOption(era);
return createCheckboxOption(era, `Add ${era} era units to the IADS`);
}));
/* Create the checkboxes to select the unit ranges */
this.#iadsRangesDropdown.setOptionsElements(groundUnitDatabase.getRanges().map((range: string) => {
return this.#createCheckboxOption(range);
return createCheckboxOption(range, `Add ${range} units to the IADS`);
}));
if (getUnitsManager().getCommandMode() !== GAME_MASTER)
@ -120,33 +121,4 @@ export class CoalitionAreaContextMenu extends ContextMenu {
});
}
}
#createCheckboxOption(text: string) {
var div = document.createElement("div");
div.classList.add("ol-checkbox");
var label = document.createElement("label");
label.title = `Add ${text}s to the IADS`;
var input = document.createElement("input");
input.type = "checkbox";
input.checked = true;
var span = document.createElement("span");
span.innerText = text;
label.appendChild(input);
label.appendChild(span);
div.appendChild(label);
return div as HTMLElement;
}
#getCheckboxOptions(dropdown: Dropdown) {
var values: { [key: string]: boolean } = {};
const element = dropdown.getOptionElements();
for (let idx = 0; idx < element.length; idx++) {
const option = element.item(idx) as HTMLElement;
const key = option.querySelector("span")?.innerText;
const value = option.querySelector("input")?.checked;
if (key !== undefined && value !== undefined)
values[key] = value;
}
return values;
}
}

View File

@ -90,7 +90,6 @@ export class MapContextMenu extends ContextMenu {
});
document.addEventListener("contextMenuDeployAircrafts", () => {
this.#spawnOptions.coalition = getActiveCoalition();
if (this.#spawnOptions) {
var unitTable = {unitType: this.#spawnOptions.name, location: this.#spawnOptions.latlng, altitude: this.#spawnOptions.altitude, loadout: this.#spawnOptions.loadout};
@ -219,6 +218,8 @@ export class MapContextMenu extends ContextMenu {
this.getContainer()?.querySelector("#explosion-menu")?.classList.toggle("hide", type !== "explosion");
this.getContainer()?.querySelector("#explosion-spawn-button")?.classList.toggle("is-open", type === "explosion");
(this.getContainer()?.querySelectorAll(".deploy-unit-button"))?.forEach((element: Node) => {(element as HTMLButtonElement).disabled = true;})
this.#resetAircraftRole();
this.#resetAircraftLabel();
this.#resetHelicopterRole();

View File

@ -3,6 +3,13 @@ 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 { Dropdown } from "../controls/dropdown";
import { groundUnitDatabase } from "../units/groundunitdatabase";
import { createCheckboxOption, getCheckboxOptions } from "../other/utils";
import { aircraftDatabase } from "../units/aircraftdatabase";
import { helicopterDatabase } from "../units/helicopterdatabase";
import { navyUnitDatabase } from "../units/navyunitdatabase";
export class MissionHandler {
#bullseyes: { [name: string]: Bullseye } = {};
@ -12,9 +19,17 @@ export class MissionHandler {
#RTSOptions: RTSOptions = {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;
constructor() {
document.addEventListener("showRTSSettingsDialog", () => this.showRTSSettingsDialog());
document.addEventListener("applyRTSOptions", () => this.#applyRTSOptions());
/* RTS settings dialog */
this.#RTSSettingsDialog = <HTMLElement> document.querySelector("#rts-settings-dialog");
this.#rtsErasDropdown = new Dropdown("rts-era-options", () => {});
}
updateBullseyes(data: BullseyesData) {
@ -49,26 +64,27 @@ export class MissionHandler {
}
updateMission(data: MissionData) {
if (data.theatre != this.#theatre) {
this.#theatre = data.theatre;
if (data.mission.theatre != this.#theatre) {
this.#theatre = data.mission.theatre;
getMap().setTheatre(this.#theatre);
getInfoPopup().setText("Map set to " + this.#theatre);
}
this.#dateAndTime = data.dateAndTime;
this.#dateAndTime = data.mission.dateAndTime;
this.#setRTSOptions(data.RTSOptions);
this.#setRTSOptions(data.mission.RTSOptions);
getUnitsManager().setCommandMode(this.#RTSOptions.commandMode);
this.#remainingSetupTime = this.#RTSOptions.setupTime - this.getDateAndTime().elapsedTime;
var RTSPhaseEl = document.querySelector("#rts-phase");
var RTSPhaseEl = document.querySelector("#rts-phase") as HTMLElement;
if (RTSPhaseEl) {
if (this.#remainingSetupTime > 0) {
var remainingTime = `Time to start: -${new Date(this.#remainingSetupTime * 1000).toISOString().substring(14, 19)}`;
RTSPhaseEl.textContent = remainingTime;
} else {
RTSPhaseEl.textContent = "FIGHT";
}
var remainingTime = `-${new Date(this.#remainingSetupTime * 1000).toISOString().substring(14, 19)}`;
RTSPhaseEl.dataset.remainingTime = remainingTime;
}
RTSPhaseEl.classList.toggle("setup-phase", this.#remainingSetupTime > 0);
RTSPhaseEl.classList.toggle("game-commenced", this.#remainingSetupTime <= 0);
}
}
@ -104,6 +120,9 @@ export class MissionHandler {
}
refreshSpawnPoints() {
if (getUnitsManager().getCommandMode() === GAME_MASTER)
document.querySelector("#spawn-points-container")?.classList.add("hide");
var spawnPointsEl = document.querySelector("#spawn-points");
if (spawnPointsEl) {
spawnPointsEl.textContent = `${this.getAvailableSpawnPoints()}`;
@ -115,6 +134,44 @@ export class MissionHandler {
this.refreshSpawnPoints();
}
showRTSSettingsDialog() {
/* 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.#RTSSettingsDialog.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;
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));
}
#applyRTSOptions() {
this.#RTSSettingsDialog.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;
var eras: string[] = [];
const enabledEras = getCheckboxOptions(this.#rtsErasDropdown);
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);
}
#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 ||
@ -126,8 +183,16 @@ export class MissionHandler {
this.setSpentSpawnPoints(0);
this.refreshSpawnPoints();
if (RTSOptionsChanged)
if (RTSOptionsChanged) {
document.dispatchEvent(new CustomEvent("RTSOptionsChanged", { detail: this }));
document.getElementById("rts-toolbar")?.classList.remove("hide");
const el = document.getElementById("command-mode");
if (el) {
el.dataset.mode = RTSOptions.commandMode;
el.textContent = RTSOptions.commandMode.toUpperCase();
}
}
}
#onAirbaseClick(e: any) {

View File

@ -6,6 +6,7 @@ import { helicopterDatabase } from "../units/helicopterdatabase";
import { groundUnitDatabase } from "../units/groundunitdatabase";
import { Buffer } from "buffer";
import { ROEs, emissionsCountermeasures, reactionsToThreat, states } from "../constants/constants";
import { Dropdown } from "../controls/dropdown";
export function bearing(lat1: number, lon1: number, lat2: number, lon2: number) {
const φ1 = deg2rad(lat1); // φ, λ in radians
@ -363,4 +364,33 @@ export function convertDateAndTimeToDate(dateAndTime: DateAndTime) {
}
return new Date(year, month, date.Day, time.h, time.m, time.s);
}
export function createCheckboxOption(value: string, text: string, checked: boolean = true) {
var div = document.createElement("div");
div.classList.add("ol-checkbox");
var label = document.createElement("label");
label.title = text;
var input = document.createElement("input");
input.type = "checkbox";
input.checked = checked;
var span = document.createElement("span");
span.innerText = value;
label.appendChild(input);
label.appendChild(span);
div.appendChild(label);
return div as HTMLElement;
}
export function getCheckboxOptions(dropdown: Dropdown) {
var values: { [key: string]: boolean } = {};
const element = dropdown.getOptionElements();
for (let idx = 0; idx < element.length; idx++) {
const option = element.item(idx) as HTMLElement;
const key = option.querySelector("span")?.innerText;
const value = option.querySelector("input")?.checked;
if (key !== undefined && value !== undefined)
values[key] = value;
}
return values;
}

View File

@ -1,5 +1,5 @@
import { LatLng } from 'leaflet';
import { getConnectionStatusPanel, getInfoPopup, getMissionData, getServerStatusPanel, getUnitDataTable, getUnitsManager, setLoginStatus } from '..';
import { getConnectionStatusPanel, getInfoPopup, getMissionHandler, getServerStatusPanel, getUnitDataTable, getUnitsManager, setLoginStatus } from '..';
import { GeneralSettings, Radio, TACAN } from '../@types/unit';
import { ROEs, emissionsCountermeasures, reactionsToThreat } from '../constants/constants';
@ -320,13 +320,37 @@ 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) {
var command = {
"restrictSpawns": restrictSpawns,
"restrictToCoalition": restrictToCoalition,
"spawnPoints": spawnPoints,
"eras": eras,
"setupTime": setupTime
};
var data = { "setRTSOptions": command };
POST(data, () => { });
}
export function startUpdate() {
/* On the first connection, force request of full data */
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
getBullseye((data: BullseyesData) => getMissionData()?.update(data));
getMission((data: any) => {
getMissionData()?.update(data);
getAirbases((data: AirbasesData) => {
checkSessionHash(data.sessionHash);
getMissionHandler()?.updateAirbases(data);
});
getBullseye((data: BullseyesData) => {
checkSessionHash(data.sessionHash);
getMissionHandler()?.updateBullseyes(data);
});
getMission((data: MissionData) => {
checkSessionHash(data.sessionHash);
getMissionHandler()?.updateMission(data);
});
getLogs((data: any) => {
for (let key in data.logs)
console.log(data.logs[key]);
return data.time;
});
getUnits((buffer: ArrayBuffer) => {return getUnitsManager()?.update(buffer), true /* Does a full refresh */});
@ -360,10 +384,8 @@ export function requestRefresh() {
getMissionHandler()?.updateMission(data);
});
getLogs((data: any) => {
for (let key in data.logs) {
if (key != "requestTime")
console.log(data.logs[key]);
}
for (let key in data.logs)
console.log(data.logs[key]);
return data.time;
});

View File

@ -1336,7 +1336,7 @@ export class GroundUnitDatabase extends UnitDatabase {
"Suidae": {
"name": "Suidae",
"coalition": "",
"era": "Prehistoric",
"era": "Modern",
"label": "Suidae",
"shortLabel": "Suidae",
"filename": "",

View File

@ -6,7 +6,7 @@ import { CustomMarker } from '../map/custommarker';
import { SVGInjector } from '@tanem/svg-injector';
import { UnitDatabase } from './unitdatabase';
import { TargetMarker } from '../map/targetmarker';
import { BLUE_COMMANDER, BOMBING, CARPET_BOMBING, DLINK, DataIndexes, FIRE_AT_AREA, GAME_MASTER, IDLE, IRST, MOVE_UNIT, OPTIC, RADAR, RED_COMMANDER, ROEs, RWR, VISUAL, emissionsCountermeasures, reactionsToThreat, states } from '../constants/constants';
import { BOMBING, CARPET_BOMBING, DLINK, DataIndexes, FIRE_AT_AREA, GAME_MASTER, IDLE, IRST, MOVE_UNIT, OPTIC, RADAR, ROEs, RWR, VISUAL, emissionsCountermeasures, reactionsToThreat, states } from '../constants/constants';
import { Ammo, Contact, GeneralSettings, Offset, Radio, TACAN, UnitIconOptions } from '../@types/unit';
import { DataExtractor } from './dataextractor';
import { groundUnitDatabase } from './groundunitdatabase';
@ -378,7 +378,7 @@ export class Unit extends CustomMarker {
}
belongsToCommandedCoalition() {
if (getUnitsManager().getCommandedCoalition() !== this.#coalition)
if (getUnitsManager().getCommandMode() !== GAME_MASTER && getUnitsManager().getCommandedCoalition() !== this.#coalition)
return false;
return true;
}

View File

@ -188,10 +188,10 @@ export class UnitDatabase {
if (blueprint)
return this.getSpawnPointsByName(blueprint.name);
else
return 0;
return Infinity;
}
getSpawnPointsByName(name: string) {
return 0;
return Infinity;
}
}

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, RED_COMMANDER } from "../constants/constants";
import { BLUE_COMMANDER, DataIndexes, GAME_MASTER, IADSDensities, IDLE, MOVE_UNIT, NONE, RED_COMMANDER } from "../constants/constants";
import { DataExtractor } from "./dataextractor";
import { Contact } from "../@types/unit";
import { citiesDatabase } from "./citiesdatabase";
@ -19,7 +19,7 @@ export class UnitsManager {
#selectionEventDisabled: boolean = false;
#pasteDisabled: boolean = false;
#hiddenTypes: string[] = [];
#commandMode: string = GAME_MASTER;
#commandMode: string = NONE;
#requestDetectionUpdate: boolean = false;
constructor() {
@ -130,11 +130,6 @@ export class UnitsManager {
setCommandMode(newCommandMode: string) {
if (newCommandMode !== this.#commandMode) {
document.dispatchEvent(new CustomEvent("commandModeChanged", { detail: this }));
const el = document.getElementById("command-mode");
if (el) {
el.dataset.mode = newCommandMode;
el.textContent = newCommandMode.toUpperCase();
}
this.#commandMode = newCommandMode;
for (let ID in this.#units)
this.#units[ID].updateVisibility();
@ -568,7 +563,7 @@ export class UnitsManager {
units.push({unitType: unit.getName(), location: unit.getPosition()});
}
const category = this.getSelectedUnitsTypes()[0];
this.spawnUnit(category, units, coalition, true);
this.spawnUnits(category, units, coalition, true);
}
/***********************************************/
@ -605,7 +600,7 @@ export class UnitsManager {
getMap().addTemporaryMarker(position, unit.name, unit.coalition);
return {unitType: unit.name, location: position};
});
this.spawnUnit(groups[groupName][0].category, units, groups[groupName][0].coalition, true);
this.spawnUnits(groups[groupName][0].category, units, groups[groupName][0].coalition, true);
}
else {
groups[groupName].forEach((unit: any) => {
@ -695,28 +690,28 @@ 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) {
if (airbase == "" && getMissionHandler().getRemainingSetupTime() < 0 && this.getCommandMode() !== 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) {
if (airbase == "" && getMissionHandler().getRemainingSetupTime() < 0 && this.getCommandMode() !== GAME_MASTER) {
getInfoPopup().setText("Helicopters can be air spawned during the SETUP phase only");
return false;
}
spawnPoints = units.reduce((unit: any, points: number) => {return points + helicopterDatabase.getSpawnPointsByName(unit.unitType)}, 0);
spawnHelicopters(units, coalition, airbase, immediate, spawnPoints);
} else if (category === "GroundUnit") {
if (getMissionHandler().getRemainingSetupTime() < 0) {
if (getMissionHandler().getRemainingSetupTime() < 0 && this.getCommandMode() !== GAME_MASTER) {
getInfoPopup().setText("Ground units can be spawned during the SETUP phase only");
return false;
}
spawnPoints = units.reduce((unit: any, points: number) => {return points + groundUnitDatabase.getSpawnPointsByName(unit.unitType)}, 0);
spawnGroundUnits(units, coalition, immediate, spawnPoints);
} else if (category === "NavyUnit") {
if (getMissionHandler().getRemainingSetupTime() < 0) {
if (getMissionHandler().getRemainingSetupTime() < 0 && this.getCommandMode() !== GAME_MASTER) {
getInfoPopup().setText("Navy units can be spawned during the SETUP phase only");
return false;
}

View File

@ -183,7 +183,6 @@
</div>
<div id="custom-formation-dialog" class="ol-panel ol-dialog olympus-dialog-close hide" oncontextmenu="return false;">
<div class="ol-dialog-close" data-on-click="closeDialog"></div>
@ -231,4 +230,76 @@
<button class="ol-button-apply" data-on-click="applyCustomFormation">Apply</button>
<button class="ol-button-close" data-on-click="closeDialog">Close</button>
</div>
</div>
<div id="rts-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>
</div>
<div class="ol-dialog-content">
<div id="restrict-spawns" class="ol-checkbox">
<label title="If false, no spawn restrictions will be applied">
<input type="checkbox"/>
Restrict spawns
</label>
</div>
<div id="restrict-to-coalition" class="ol-checkbox">
<label title="If true, commanders will be allowed to only spawn units that belong to their coalition. E.g. blue commanders will be able to spawn F/A-18 Hornets, but not MiG-29s.">
<input type="checkbox"/>
Restrict units to coalition
</label>
</div>
<div class="ol-group">
<label>Setup time: </label>
<div class="ol-group">
<div id="setup-time" class="ol-text-input">
<input type="number" min="-99999" max="99999" step="1" value="10">
</div>
<label>minutes</label>
</div>
</div>
<div class="ol-group">
<label>Available eras: </label>
<div id="rts-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-->
</div>
</div>
</div>
<div class="ol-group">
<h4>Spawn points</h4>
<hr>
</div>
<div class="ol-group">
<label>Blue spawn points: </label>
<div id="blue-spawn-points" class="ol-text-input">
<input type="number" min="0" max="999999" step="1" value="1000">
</div>
</div>
<div class="ol-group">
<label>Red spawn points: </label>
<div id="red-spawn-points" class="ol-text-input">
<input type="number" min="0" max="999999" step="1" value="1000">
</div>
</div>
</div>
<div class="ol-dialog-footer ol-group">
<button class="ol-button-apply" data-on-click="applyRTSOptions">Apply</button>
<button class="ol-button-close" data-on-click="closeDialog">Close</button>
</div>
</div>

View File

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

View File

@ -117,11 +117,11 @@ void Server::handle_get(http_request request)
else if (URI.compare(MISSION_URI) == 0 && missionData.has_object_field(L"mission")) {
answer[L"mission"] = missionData[L"mission"];
if (password.compare(gameMasterPassword) == 0)
answer[L"mission"][L"visibilityMode"] = json::value(L"Game master");
answer[L"mission"][L"commandMode"] = json::value(L"Game master");
else if (password.compare(blueCommanderPassword) == 0)
answer[L"mission"][L"visibilityMode"] = json::value(L"Blue commander");
answer[L"mission"][L"commandMode"] = json::value(L"Blue commander");
else if (password.compare(redCommanderPassword) == 0)
answer[L"mission"][L"visibilityMode"] = json::value(L"Red commander");
answer[L"mission"][L"commandMode"] = json::value(L"Red commander");
}
answer[L"time"] = json::value::string(to_wstring(ms.count()));