mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Fixed IADS creation and added livery/skill selection for units
This commit is contained in:
@@ -68,28 +68,13 @@ export const ROEs: string[] = ["free", "designated", "", "return", "hold"];
|
||||
export const reactionsToThreat: string[] = ["none", "manoeuvre", "passive", "evade"];
|
||||
export const emissionsCountermeasures: string[] = ["silent", "attack", "defend", "free"];
|
||||
|
||||
export const ERAS = [
|
||||
{
|
||||
name: "Early Cold War",
|
||||
chronologicalOrder: 2,
|
||||
},
|
||||
{
|
||||
name: "Late Cold War",
|
||||
chronologicalOrder: 4,
|
||||
},
|
||||
{
|
||||
name: "Mid Cold War",
|
||||
chronologicalOrder: 3,
|
||||
},
|
||||
{
|
||||
name: "Modern",
|
||||
chronologicalOrder: 5,
|
||||
},
|
||||
{
|
||||
name: "WW2",
|
||||
chronologicalOrder: 1,
|
||||
},
|
||||
];
|
||||
export enum ERAS_ORDER {
|
||||
"WW2",
|
||||
"Early Cold War",
|
||||
"Mid Cold War",
|
||||
"Late Cold War",
|
||||
"Modern"
|
||||
};
|
||||
|
||||
export const ROEDescriptions: string[] = [
|
||||
"Free (Attack anyone)",
|
||||
@@ -227,6 +212,14 @@ export const minimapBoundaries = {
|
||||
new LatLng(34.312222, 36.897778),
|
||||
new LatLng(34.312222, 28.523333),
|
||||
],
|
||||
Afghanistan: [
|
||||
// Sinai
|
||||
new LatLng(36.22, 61.21),
|
||||
new LatLng(30.42, 61.21),
|
||||
new LatLng(30.42, 68.05),
|
||||
new LatLng(36.22, 68.05),
|
||||
new LatLng(36.22, 61.21),
|
||||
],
|
||||
};
|
||||
|
||||
export const mapBounds = {
|
||||
@@ -259,6 +252,7 @@ export const mapBounds = {
|
||||
bounds: new LatLngBounds([34.312222, 28.523333], [25.946944, 36.897778]),
|
||||
zoom: 4,
|
||||
},
|
||||
Afghanistan: { bounds: new LatLngBounds([36.22, 61.21], [30.42, 68.05]), zoom: 5 },
|
||||
};
|
||||
|
||||
export const defaultMapMirrors = {};
|
||||
@@ -277,7 +271,7 @@ export enum OlympusState {
|
||||
OPTIONS = "Options",
|
||||
AUDIO = "Audio",
|
||||
AIRBASE = "Airbase",
|
||||
GAME_MASTER = "Game master"
|
||||
GAME_MASTER = "Game master",
|
||||
}
|
||||
|
||||
export const NO_SUBSTATE = "No substate";
|
||||
@@ -308,12 +302,12 @@ export enum JTACSubState {
|
||||
export enum SpawnSubState {
|
||||
NO_SUBSTATE = "No substate",
|
||||
SPAWN_UNIT = "Unit",
|
||||
SPAWN_EFFECT = "Effect"
|
||||
SPAWN_EFFECT = "Effect",
|
||||
}
|
||||
|
||||
export enum OptionsSubstate {
|
||||
NO_SUBSTATE = "No substate",
|
||||
KEYBIND = "Keybind"
|
||||
KEYBIND = "Keybind",
|
||||
}
|
||||
|
||||
export type OlympusSubState = DrawSubState | JTACSubState | SpawnSubState | OptionsSubstate | string;
|
||||
@@ -341,7 +335,7 @@ export const MAP_OPTIONS_DEFAULTS: MapOptions = {
|
||||
cameraPluginPort: 3003,
|
||||
cameraPluginRatio: 1,
|
||||
cameraPluginEnabled: false,
|
||||
cameraPluginMode: 'map'
|
||||
cameraPluginMode: "map",
|
||||
};
|
||||
|
||||
export const MAP_HIDDEN_TYPES_DEFAULTS = {
|
||||
|
||||
@@ -380,7 +380,7 @@ export class MouseMovedEvent {
|
||||
|
||||
static dispatch(latlng: LatLng, elevation?: number) {
|
||||
document.dispatchEvent(new CustomEvent(this.name, { detail: { latlng, elevation } }));
|
||||
console.log(`Event ${this.name} dispatched`);
|
||||
// Logging disabled since periodic
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,6 +463,6 @@ export class BullseyesDataChanged {
|
||||
|
||||
static dispatch(bullseyes: { [name: string]: Bullseye } ) {
|
||||
document.dispatchEvent(new CustomEvent(this.name, { detail: { bullseyes } }));
|
||||
console.log(`Event ${this.name} dispatched`);
|
||||
// Logging disabled since periodic
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +99,7 @@ export interface SpawnRequestTable {
|
||||
category: string;
|
||||
coalition: string;
|
||||
unit: UnitSpawnTable;
|
||||
amount: number;
|
||||
quickAccessName?: string
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ export class CoalitionPolygon extends Polygon {
|
||||
});
|
||||
|
||||
this.on("remove", () => {
|
||||
this.#label.removeFrom(this._map);
|
||||
this.#label?.removeFrom(this._map);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1048,7 +1048,7 @@ export class Map extends L.Map {
|
||||
.getUnitsManager()
|
||||
.spawnUnits(
|
||||
this.#spawnRequestTable.category,
|
||||
[this.#spawnRequestTable.unit],
|
||||
Array(this.#spawnRequestTable.amount).fill(this.#spawnRequestTable.unit),
|
||||
this.#spawnRequestTable.coalition,
|
||||
false,
|
||||
undefined,
|
||||
|
||||
378
frontend/react/src/ui/data/codes.ts
Normal file
378
frontend/react/src/ui/data/codes.ts
Normal file
@@ -0,0 +1,378 @@
|
||||
export const countryCodes = {
|
||||
"AGGRESSORS": {
|
||||
"flagCode": "RED",
|
||||
"liveryCodes": ["RSO"]
|
||||
},
|
||||
"INSURGENTS": {
|
||||
"flagCode": "UNK",
|
||||
"liveryCodes": ["INS"]
|
||||
},
|
||||
"ALGERIA": {
|
||||
"flagCode": "DZ",
|
||||
"liveryCodes": ["DZA"]
|
||||
},
|
||||
"ARGENTINA": {
|
||||
"flagCode": "AR",
|
||||
"liveryCodes": ["ARG"]
|
||||
},
|
||||
"AUSTRALIA": {
|
||||
"flagCode": "AU",
|
||||
"liveryCodes": ["AUS", "AUSAF"]
|
||||
},
|
||||
"AUSTRIA": {
|
||||
"flagCode": "AT",
|
||||
"liveryCodes": ["AUT"]
|
||||
},
|
||||
"BAHRAIN": {
|
||||
"flagCode": "BH",
|
||||
"liveryCodes": ["BHR"]
|
||||
},
|
||||
"BELARUS": {
|
||||
"flagCode": "BY",
|
||||
"liveryCodes": ["BLR"]
|
||||
},
|
||||
"BELGIUM": {
|
||||
"flagCode": "BE",
|
||||
"liveryCodes": ["BEL"]
|
||||
},
|
||||
"BOLIVIA": {
|
||||
"flagCode": "BO",
|
||||
"liveryCodes": ["BOL"]
|
||||
},
|
||||
"BRAZIL": {
|
||||
"flagCode": "BR",
|
||||
"liveryCodes": ["BRA"]
|
||||
},
|
||||
"BULGARIA": {
|
||||
"flagCode": "BG",
|
||||
"liveryCodes": ["BGR"]
|
||||
},
|
||||
"CANADA": {
|
||||
"flagCode": "CA",
|
||||
"liveryCodes": ["CAN"]
|
||||
},
|
||||
"CHILE": {
|
||||
"flagCode": "CL",
|
||||
"liveryCodes": ["CHL"]
|
||||
},
|
||||
"CHINA": {
|
||||
"flagCode": "CN",
|
||||
"liveryCodes": ["CHN"]
|
||||
},
|
||||
"CROATIA": {
|
||||
"flagCode": "HR",
|
||||
"liveryCodes": ["HRV"]
|
||||
},
|
||||
"CUBA": {
|
||||
"flagCode": "CU",
|
||||
"liveryCodes": ["CUB"]
|
||||
},
|
||||
"CYPRUS": {
|
||||
"flagCode": "CY",
|
||||
"liveryCodes": ["CYP"]
|
||||
},
|
||||
"CHEZH_REPUBLIC": {
|
||||
"displayName": "Czech Republic",
|
||||
"flagCode": "CZ",
|
||||
"liveryCodes": ["CZE"]
|
||||
},
|
||||
"DENMARK": {
|
||||
"flagCode": "DK",
|
||||
"liveryCodes": ["DEN"]
|
||||
},
|
||||
"EGYPT": {
|
||||
"flagCode": "EG",
|
||||
"liveryCodes": ["EGY", "EGP"]
|
||||
},
|
||||
"ETHIOPIA": {
|
||||
"flagCode": "ET",
|
||||
"liveryCodes": ["ETH"]
|
||||
},
|
||||
"FINLAND": {
|
||||
"flagCode": "FI",
|
||||
"liveryCodes": ["FIN"]
|
||||
},
|
||||
"FRANCE": {
|
||||
"flagCode": "FR",
|
||||
"liveryCodes": ["FRA"]
|
||||
},
|
||||
"GEORGIA": {
|
||||
"flagCode": "GE",
|
||||
"liveryCodes": ["GRG"]
|
||||
},
|
||||
"GERMANY": {
|
||||
"flagCode": "DE",
|
||||
"liveryCodes": ["GER"]
|
||||
},
|
||||
"GHANA": {
|
||||
"flagCode": "GH",
|
||||
"liveryCodes": ["GHA"]
|
||||
},
|
||||
"GREECE": {
|
||||
"flagCode": "GR",
|
||||
"liveryCodes": ["GRC"]
|
||||
},
|
||||
"HONDURAS": {
|
||||
"flagCode": "HN",
|
||||
"liveryCodes": ["HND"]
|
||||
},
|
||||
"HUNGARY": {
|
||||
"flagCode": "HU",
|
||||
"liveryCodes": ["HUN"]
|
||||
},
|
||||
"INDIA": {
|
||||
"flagCode": "IN",
|
||||
"liveryCodes": ["IND"]
|
||||
},
|
||||
"INDONESIA": {
|
||||
"flagCode": "ID",
|
||||
"liveryCodes": ["IDN"]
|
||||
},
|
||||
"IRAN": {
|
||||
"flagCode": "IR",
|
||||
"liveryCodes": ["IRN"]
|
||||
},
|
||||
"IRAQ": {
|
||||
"flagCode": "IQ",
|
||||
"liveryCodes": ["IRQ"]
|
||||
},
|
||||
"ISRAEL": {
|
||||
"flagCode": "IL",
|
||||
"liveryCodes": ["ISR"]
|
||||
},
|
||||
"ITALY": {
|
||||
"flagCode": "IT",
|
||||
"liveryCodes": ["ITA"]
|
||||
},
|
||||
"JAPAN": {
|
||||
"flagCode": "JP",
|
||||
"liveryCodes": ["JPN"]
|
||||
},
|
||||
"JORDAN": {
|
||||
"flagCode": "JO",
|
||||
"liveryCodes": ["JOR"]
|
||||
},
|
||||
"KAZAKHSTAN": {
|
||||
"flagCode": "KZ",
|
||||
"liveryCodes": ["KAZ"]
|
||||
},
|
||||
"SOUTH_KOREA": {
|
||||
"displayName": "South Korea",
|
||||
"flagCode": "KR",
|
||||
"liveryCodes": ["KOR"]
|
||||
},
|
||||
"KUWAIT": {
|
||||
"flagCode": "KW",
|
||||
"liveryCodes": ["KWT"]
|
||||
},
|
||||
"LEBANON": {
|
||||
"flagCode": "LB",
|
||||
"liveryCodes": ["LBN"]
|
||||
},
|
||||
"MALAYSIA": {
|
||||
"flagCode": "MY",
|
||||
"liveryCodes": ["MYS"]
|
||||
},
|
||||
"MEXICO": {
|
||||
"flagCode": "MX",
|
||||
"liveryCodes": ["MEX"]
|
||||
},
|
||||
"MOROCCO": {
|
||||
"flagCode": "MA",
|
||||
"liveryCodes": ["MAR"]
|
||||
},
|
||||
"THE_NETHERLANDS": {
|
||||
"displayName": "The Netherlands",
|
||||
"flagCode": "NL",
|
||||
"liveryCodes": ["NETH"]
|
||||
},
|
||||
"NIGERIA": {
|
||||
"flagCode": "NG",
|
||||
"liveryCodes": ["NGA"]
|
||||
},
|
||||
"NORWAY": {
|
||||
"flagCode": "NO",
|
||||
"liveryCodes": ["NOR"]
|
||||
},
|
||||
"OMAN": {
|
||||
"flagCode": "OM",
|
||||
"liveryCodes": ["OMN"]
|
||||
},
|
||||
"PAKISTAN": {
|
||||
"flagCode": "PK",
|
||||
"liveryCodes": ["PAK"]
|
||||
},
|
||||
"PERU": {
|
||||
"flagCode": "PE",
|
||||
"liveryCodes": ["PER"]
|
||||
},
|
||||
"PHILIPPINES": {
|
||||
"flagCode": "PH",
|
||||
"liveryCodes": ["PHL"]
|
||||
},
|
||||
"POLAND": {
|
||||
"flagCode": "PL",
|
||||
"liveryCodes": ["POL"]
|
||||
},
|
||||
"PORTUGAL": {
|
||||
"flagCode": "PT",
|
||||
"liveryCodes": ["PRT"]
|
||||
},
|
||||
"QATAR": {
|
||||
"flagCode": "QA",
|
||||
"liveryCodes": ["QAT"]
|
||||
},
|
||||
"ROMANIA": {
|
||||
"flagCode": "RO",
|
||||
"liveryCodes": ["ROU"]
|
||||
},
|
||||
"RUSSIA": {
|
||||
"flagCode": "RU",
|
||||
"liveryCodes": ["RUS"]
|
||||
},
|
||||
"SAUDI_ARABIA": {
|
||||
"displayName": "Saudi Arabia",
|
||||
"flagCode": "SA",
|
||||
"liveryCodes": ["SAU"]
|
||||
},
|
||||
"SERBIA": {
|
||||
"flagCode": "RS",
|
||||
"liveryCodes": ["SRB"]
|
||||
},
|
||||
"SLOVAKIA": {
|
||||
"flagCode": "SK",
|
||||
"liveryCodes": ["SVK"]
|
||||
},
|
||||
"SLOVENIA": {
|
||||
"flagCode": "SI",
|
||||
"liveryCodes": ["SVN"]
|
||||
},
|
||||
"SOUTH_AFRICA": {
|
||||
"displayName": "South Africa",
|
||||
"flagCode": "ZA",
|
||||
"liveryCodes": null
|
||||
},
|
||||
"SPAIN": {
|
||||
"flagCode": "ES",
|
||||
"liveryCodes": ["SPN", "SPA"]
|
||||
},
|
||||
"SUDAN": {
|
||||
"flagCode": "SD",
|
||||
"liveryCodes": ["SDN", "SUN"]
|
||||
},
|
||||
"SWEDEN": {
|
||||
"flagCode": "SE",
|
||||
"liveryCodes": ["SWE"]
|
||||
},
|
||||
"SWITZERLAND": {
|
||||
"flagCode": "CH",
|
||||
"liveryCodes": ["SUI"]
|
||||
},
|
||||
"SYRIA": {
|
||||
"flagCode": "SY",
|
||||
"liveryCodes": ["SYR"]
|
||||
},
|
||||
"THAILAND": {
|
||||
"flagCode": "TH",
|
||||
"liveryCodes": ["THA"]
|
||||
},
|
||||
"TUNISIA": {
|
||||
"flagCode": "TN",
|
||||
"liveryCodes": ["TUN"]
|
||||
},
|
||||
"TURKEY": {
|
||||
"flagCode": "TR",
|
||||
"liveryCodes": ["TUR"]
|
||||
},
|
||||
"UKRAINE": {
|
||||
"flagCode": "UA",
|
||||
"liveryCodes": ["UKR"]
|
||||
},
|
||||
"UNITED_ARAB_EMIRATES": {
|
||||
"displayName": "United Arab Emirates",
|
||||
"flagCode": "AE",
|
||||
"liveryCodes": ["ARE"]
|
||||
},
|
||||
"UK": {
|
||||
"displayName": "United Kingdom",
|
||||
"flagCode": "GB",
|
||||
"liveryCodes": ["UK"]
|
||||
},
|
||||
"USA": {
|
||||
"displayName": "United States of America",
|
||||
"flagCode": "US",
|
||||
"liveryCodes": ["USA", "USAF"]
|
||||
},
|
||||
"VENEZUELA": {
|
||||
"flagCode": "VE",
|
||||
"liveryCodes": ["VEN"]
|
||||
},
|
||||
"VIETNAM": {
|
||||
"flagCode": "VN",
|
||||
"liveryCodes": ["VNM"]
|
||||
},
|
||||
"YEMEN": {
|
||||
"flagCode": "YE",
|
||||
"liveryCodes": ["YEM"]
|
||||
},
|
||||
"CJTF_BLUE": {
|
||||
"displayName": "Combined Joint Task Force Blue",
|
||||
"flagCode": "BLUE",
|
||||
"liveryCodes": ["BLUE"]
|
||||
},
|
||||
"SOUTH_OSETIA": {
|
||||
"displayName": "South Ossetia",
|
||||
"flagCode": "UNK",
|
||||
"liveryCodes": null
|
||||
},
|
||||
"NORTH_KOREA": {
|
||||
"displayName": "Democratic People's Republic of Korea",
|
||||
"flagCode": "KP",
|
||||
"liveryCodes": ["PRK"]
|
||||
},
|
||||
"CJTF_RED": {
|
||||
"displayName": "Combined Joint Task Force Red",
|
||||
"flagCode": "RED",
|
||||
"liveryCodes": ["RED"]
|
||||
},
|
||||
"ABKHAZIA": {
|
||||
"flagCode": "UNK",
|
||||
"liveryCodes": ["ABH"]
|
||||
},
|
||||
"ITALIAN_SOCIAL_REPUBLIC": {
|
||||
"displayName": "Italian Social Republic",
|
||||
"flagCode": "SOCIAL",
|
||||
"liveryCodes": ["RSI"]
|
||||
},
|
||||
"USSR": {
|
||||
"displayName": "USSR",
|
||||
"flagCode": "USSR",
|
||||
"liveryCodes": null
|
||||
},
|
||||
"ECUADOR": {
|
||||
"flagCode": "EC",
|
||||
"liveryCodes": ["ECU"]
|
||||
},
|
||||
"LIBYA": {
|
||||
"flagCode": "LY",
|
||||
"liveryCodes": ["LBY", "LIB"]
|
||||
},
|
||||
"UN_PEACEKEEPERS": {
|
||||
"displayName": "United Nations",
|
||||
"flagCode": "UNK",
|
||||
"liveryCodes": ["UN"]
|
||||
},
|
||||
"GDR": {
|
||||
"flagCode": "UNK",
|
||||
"liveryCodes": ["GDR"]
|
||||
},
|
||||
"YUGOSLAVIA": {
|
||||
"flagCode": "YUG",
|
||||
"liveryCodes": ["YUG"]
|
||||
},
|
||||
"THIRDREICH": {
|
||||
"displayName": "Third Reich",
|
||||
"flagCode": "THIRD",
|
||||
"liveryCodes": null
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import { OlCheckbox } from "../components/olcheckbox";
|
||||
import { Coalition } from "../../types/types";
|
||||
import { OlRangeSlider } from "../components/olrangeslider";
|
||||
import { CoalitionCircle } from "../../map/coalitionarea/coalitioncircle";
|
||||
import { DrawSubState, NO_SUBSTATE, OlympusState, OlympusSubState } from "../../constants/constants";
|
||||
import { DrawSubState, ERAS_ORDER, IADSTypes, NO_SUBSTATE, OlympusState, OlympusSubState } from "../../constants/constants";
|
||||
import { AppStateChangedEvent, CoalitionAreaSelectedEvent } from "../../events";
|
||||
import { UnitBlueprint } from "../../interfaces";
|
||||
|
||||
@@ -37,20 +37,8 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
}, []);
|
||||
|
||||
/* Get all the unique types and eras for groundunits */
|
||||
/* TODO move in effect */
|
||||
const blueprints = getApp()?.getUnitsManager().getDatabase().getBlueprints();
|
||||
let types: string[] = [];
|
||||
let eras: string[] = [];
|
||||
if (blueprints) {
|
||||
types = blueprints
|
||||
.filter((blueprint) => blueprint.category === "groundunit")
|
||||
.map((blueprint) => blueprint.type)
|
||||
.filter((type) => type !== undefined);
|
||||
eras = blueprints
|
||||
.filter((blueprint) => blueprint.category === "groundunit")
|
||||
.map((blueprint) => blueprint.era)
|
||||
.filter((era) => era !== undefined);
|
||||
}
|
||||
let types = IADSTypes;
|
||||
let eras = getApp()?.getUnitsManager().getDatabase().getEras().sort((era1, era2) => ERAS_ORDER[era1] > ERAS_ORDER[era2] ? 1: -1 );
|
||||
|
||||
useEffect(() => {
|
||||
if (getApp()) {
|
||||
@@ -105,7 +93,7 @@ export function DrawingMenu(props: { open: boolean; onClose: () => void }) {
|
||||
tooltip={"Add a new circle"}
|
||||
checked={appSubState === DrawSubState.DRAW_CIRCLE}
|
||||
onClick={() => {
|
||||
if (appSubState === DrawSubState.DRAW_CIRCLE) getApp().setState(OlympusState.DRAW, DrawSubState.EDIT);
|
||||
if (appSubState === DrawSubState.DRAW_CIRCLE) getApp().setState(OlympusState.DRAW);
|
||||
else getApp().setState(OlympusState.DRAW, DrawSubState.DRAW_CIRCLE);
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Menu } from "./components/menu";
|
||||
import { OlCheckbox } from "../components/olcheckbox";
|
||||
import { OlRangeSlider } from "../components/olrangeslider";
|
||||
import { OlNumberInput } from "../components/olnumberinput";
|
||||
import { MapOptions } from "../../types/types";
|
||||
import { getApp } from "../../olympusapp";
|
||||
import { CommandModeOptions, ServerStatus } from "../../interfaces";
|
||||
import { ServerStatus } from "../../interfaces";
|
||||
import { CommandModeOptionsChangedEvent, ServerStatusUpdatedEvent } from "../../events";
|
||||
import { BLUE_COMMANDER, COMMAND_MODE_OPTIONS_DEFAULTS, ERAS, GAME_MASTER, RED_COMMANDER } from "../../constants/constants";
|
||||
import { BLUE_COMMANDER, COMMAND_MODE_OPTIONS_DEFAULTS, ERAS_ORDER, GAME_MASTER, RED_COMMANDER } from "../../constants/constants";
|
||||
|
||||
export function GameMasterMenu(props: { open: boolean; onClose: () => void; children?: JSX.Element | JSX.Element[] }) {
|
||||
const [commandModeOptions, setCommandModeOptions] = useState(COMMAND_MODE_OPTIONS_DEFAULTS);
|
||||
@@ -40,12 +38,20 @@ export function GameMasterMenu(props: { open: boolean; onClose: () => void; chil
|
||||
GAME MASTER
|
||||
</div>
|
||||
)}
|
||||
{commandModeOptions.commandMode === BLUE_COMMANDER && <div className={`
|
||||
w-full rounded-md bg-blue-600 p-2 text-center font-bold
|
||||
`}>BLUE COMMANDER</div>}
|
||||
{commandModeOptions.commandMode === RED_COMMANDER && <div className={`
|
||||
w-full rounded-md bg-red-700 p-2 text-center font-bold
|
||||
`}>RED COMMANDER</div>}
|
||||
{commandModeOptions.commandMode === BLUE_COMMANDER && (
|
||||
<div
|
||||
className={`w-full rounded-md bg-blue-600 p-2 text-center font-bold`}
|
||||
>
|
||||
BLUE COMMANDER
|
||||
</div>
|
||||
)}
|
||||
{commandModeOptions.commandMode === RED_COMMANDER && (
|
||||
<div
|
||||
className={`w-full rounded-md bg-red-700 p-2 text-center font-bold`}
|
||||
>
|
||||
RED COMMANDER
|
||||
</div>
|
||||
)}
|
||||
{serverStatus.elapsedTime > currentSetupTime && (
|
||||
<div
|
||||
className={`
|
||||
@@ -112,36 +118,40 @@ export function GameMasterMenu(props: { open: boolean; onClose: () => void; chil
|
||||
Restrict spawns to coalition
|
||||
</span>
|
||||
</div>
|
||||
{ERAS.sort((a, b) => (a.chronologicalOrder > b.chronologicalOrder ? 1 : -1)).map((era) => {
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
group flex flex-row rounded-md justify-content cursor-pointer
|
||||
gap-4 p-2
|
||||
dark:hover:bg-olympus-400
|
||||
`}
|
||||
onClick={() => {
|
||||
if (!commandModeOptions.restrictSpawns || commandModeOptions.commandMode !== GAME_MASTER) return;
|
||||
const newCommandModeOptions = { ...commandModeOptions };
|
||||
if (commandModeOptions.eras.includes(era.name)) newCommandModeOptions.eras.splice(newCommandModeOptions.eras.indexOf(era.name));
|
||||
else newCommandModeOptions.eras.push(era.name);
|
||||
setCommandModeOptions(newCommandModeOptions);
|
||||
}}
|
||||
>
|
||||
<OlCheckbox
|
||||
checked={commandModeOptions.eras.includes(era.name)}
|
||||
onChange={() => {}}
|
||||
disabled={!commandModeOptions.restrictSpawns || commandModeOptions.commandMode !== GAME_MASTER}
|
||||
/>
|
||||
<span
|
||||
data-disabled={!commandModeOptions.restrictSpawns || commandModeOptions.commandMode !== GAME_MASTER}
|
||||
className={`data-[disabled='true']:text-gray-400`}
|
||||
{Object.keys(ERAS_ORDER)
|
||||
.filter((item) => {
|
||||
return isNaN(Number(item));
|
||||
})
|
||||
.map((era) => {
|
||||
return (
|
||||
<div
|
||||
className={`
|
||||
group flex flex-row rounded-md justify-content
|
||||
cursor-pointer gap-4 p-2
|
||||
dark:hover:bg-olympus-400
|
||||
`}
|
||||
onClick={() => {
|
||||
if (!commandModeOptions.restrictSpawns || commandModeOptions.commandMode !== GAME_MASTER) return;
|
||||
const newCommandModeOptions = { ...commandModeOptions };
|
||||
if (commandModeOptions.eras.includes(era)) newCommandModeOptions.eras.splice(newCommandModeOptions.eras.indexOf(era));
|
||||
else newCommandModeOptions.eras.push(era);
|
||||
setCommandModeOptions(newCommandModeOptions);
|
||||
}}
|
||||
>
|
||||
Allow {era.name} units
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<OlCheckbox
|
||||
checked={commandModeOptions.eras.includes(era)}
|
||||
onChange={() => {}}
|
||||
disabled={!commandModeOptions.restrictSpawns || commandModeOptions.commandMode !== GAME_MASTER}
|
||||
/>
|
||||
<span
|
||||
data-disabled={!commandModeOptions.restrictSpawns || commandModeOptions.commandMode !== GAME_MASTER}
|
||||
className={`data-[disabled='true']:text-gray-400`}
|
||||
>
|
||||
Allow {era} units
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
<div
|
||||
className={`
|
||||
@@ -264,12 +274,9 @@ export function GameMasterMenu(props: { open: boolean; onClose: () => void; chil
|
||||
group flex flex-row rounded-md justify-content gap-4 px-4 py-2
|
||||
`}
|
||||
>
|
||||
<span className="mr-auto">Elapsed time (seconds)</span>{" "}
|
||||
<span
|
||||
className={`w-32 text-center`}
|
||||
>
|
||||
{serverStatus.elapsedTime?.toFixed()}
|
||||
</span>
|
||||
<span className="mr-auto">Elapsed time (seconds)</span> <span className={`
|
||||
w-32 text-center
|
||||
`}>{serverStatus.elapsedTime?.toFixed()}</span>
|
||||
</div>
|
||||
{commandModeOptions.commandMode === GAME_MASTER && (
|
||||
<button
|
||||
|
||||
@@ -53,14 +53,12 @@ export function MiniMapPanel(props: {}) {
|
||||
|
||||
return (
|
||||
<div
|
||||
onClick={() => setShowMissionTime(!showMissionTime)}
|
||||
className={`
|
||||
absolute right-[10px]
|
||||
${mapOptions.showMinimap ? `bottom-[188px]` : `bottom-[20px]`}
|
||||
flex w-[288px] items-center justify-between
|
||||
${mapOptions.showMinimap ? `rounded-t-lg` : `rounded-lg`}
|
||||
cursor-pointer bg-gray-200 p-3 text-sm backdrop-blur-lg
|
||||
backdrop-grayscale
|
||||
bg-gray-200 p-3 text-sm backdrop-blur-lg backdrop-grayscale
|
||||
dark:bg-olympus-800/90 dark:text-gray-200
|
||||
`}
|
||||
>
|
||||
@@ -88,16 +86,16 @@ export function MiniMapPanel(props: {}) {
|
||||
{serverStatus.load}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex gap-2 font-semibold">
|
||||
<div className="flex cursor-pointer gap-2 font-semibold" onClick={() => setShowMissionTime(!showMissionTime)}>
|
||||
{showMissionTime ? "MT" : "ET"}: {timeString}
|
||||
</div>
|
||||
<div className={`relative h-4 w-4 rounded-full bg-[#8BFF63]`}></div>
|
||||
</>
|
||||
)}
|
||||
{mapOptions.showMinimap ? (
|
||||
<FaChevronDown onClick={() => getApp().getMap().setOption("showMinimap", false)} />
|
||||
<FaChevronDown className="cursor-pointer" onClick={() => getApp().getMap().setOption("showMinimap", false)} />
|
||||
) : (
|
||||
<FaChevronUp onClick={() => getApp().getMap().setOption("showMinimap", true)} />
|
||||
<FaChevronUp className="cursor-pointer" onClick={() => getApp().getMap().setOption("showMinimap", true)} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -15,8 +15,16 @@ import { Airbase } from "../../mission/airbase";
|
||||
import { altitudeIncrements, groupUnitCount, maxAltitudeValues, minAltitudeValues, OlympusState, SpawnSubState } from "../../constants/constants";
|
||||
import { faStar } from "@fortawesome/free-solid-svg-icons";
|
||||
import { OlStringInput } from "../components/olstringinput";
|
||||
import { countryCodes } from "../data/codes";
|
||||
import { OlAccordion } from "../components/olaccordion";
|
||||
|
||||
export function UnitSpawnMenu(props: { starredSpawns: { [key: string]: SpawnRequestTable }, blueprint: UnitBlueprint; spawnAtLocation: boolean; airbase?: Airbase | null; coalition?: Coalition }) {
|
||||
export function UnitSpawnMenu(props: {
|
||||
starredSpawns: { [key: string]: SpawnRequestTable };
|
||||
blueprint: UnitBlueprint;
|
||||
spawnAtLocation: boolean;
|
||||
airbase?: Airbase | null;
|
||||
coalition?: Coalition;
|
||||
}) {
|
||||
/* Compute the min and max values depending on the unit type */
|
||||
const minNumber = 1;
|
||||
const maxNumber = groupUnitCount[props.blueprint.category];
|
||||
@@ -31,7 +39,10 @@ export function UnitSpawnMenu(props: { starredSpawns: { [key: string]: SpawnRequ
|
||||
const [spawnLoadoutName, setSpawnLoadout] = useState("");
|
||||
const [spawnAltitude, setSpawnAltitude] = useState((maxAltitude - minAltitude) / 2);
|
||||
const [spawnAltitudeType, setSpawnAltitudeType] = useState(false);
|
||||
|
||||
const [spawnLiveryID, setSpawnLiveryID] = useState("");
|
||||
const [spawnSkill, setSpawnSkill] = useState("High");
|
||||
const [showLoadout, setShowLoadout] = useState(false);
|
||||
|
||||
const [quickAccessName, setQuickAccessName] = useState("No name");
|
||||
const [key, setKey] = useState("");
|
||||
const [spawnRequestTable, setSpawnRequestTable] = useState(null as null | SpawnRequestTable);
|
||||
@@ -61,8 +72,8 @@ export function UnitSpawnMenu(props: { starredSpawns: { [key: string]: SpawnRequ
|
||||
if (key in props.starredSpawns && props.starredSpawns[key].quickAccessName) setQuickAccessName(props.starredSpawns[key].quickAccessName);
|
||||
else setQuickAccessName("No name");
|
||||
}
|
||||
}, [props.starredSpawns, key])
|
||||
useEffect(updateQuickAccessName, [key])
|
||||
}, [props.starredSpawns, key]);
|
||||
useEffect(updateQuickAccessName, [key]);
|
||||
|
||||
/* Callback and effect to update the spawn request table */
|
||||
const updateSpawnRequestTable = useCallback(() => {
|
||||
@@ -72,16 +83,17 @@ export function UnitSpawnMenu(props: { starredSpawns: { [key: string]: SpawnRequ
|
||||
unit: {
|
||||
unitType: props.blueprint.name,
|
||||
location: new LatLng(0, 0), // This will be filled when the user clicks on the map to spawn the unit
|
||||
skill: "High",
|
||||
liveryID: "",
|
||||
skill: spawnSkill,
|
||||
liveryID: spawnLiveryID,
|
||||
altitude: ftToM(spawnAltitude),
|
||||
loadout: props.blueprint.loadouts?.find((loadout) => loadout.name === spawnLoadoutName)?.code ?? "",
|
||||
},
|
||||
amount: spawnNumber,
|
||||
coalition: spawnCoalition,
|
||||
});
|
||||
}
|
||||
}, [props.blueprint, spawnAltitude, spawnLoadoutName, spawnCoalition]);
|
||||
useEffect(updateSpawnRequestTable, [props.blueprint, spawnAltitude, spawnLoadoutName, spawnCoalition]);
|
||||
}, [props.blueprint, spawnAltitude, spawnLoadoutName, spawnCoalition, spawnNumber, spawnLiveryID, spawnSkill]);
|
||||
useEffect(updateSpawnRequestTable, [props.blueprint, spawnAltitude, spawnLoadoutName, spawnCoalition, spawnNumber, spawnLiveryID, spawnSkill]);
|
||||
|
||||
/* Effect to update the coalition if it is force externally */
|
||||
useEffect(() => {
|
||||
@@ -115,6 +127,30 @@ export function UnitSpawnMenu(props: { starredSpawns: { [key: string]: SpawnRequ
|
||||
<div className="flex flex-col">
|
||||
<OlUnitSummary blueprint={props.blueprint} coalition={spawnCoalition} />
|
||||
<div className="flex h-fit flex-col gap-5 px-5 pb-8 pt-6">
|
||||
<div
|
||||
className={`
|
||||
inline-flex w-full flex-row content-center justify-between gap-2
|
||||
`}
|
||||
>
|
||||
<div className="my-auto text-sm text-white">Quick access: </div>
|
||||
<OlStringInput
|
||||
onChange={(e) => {
|
||||
setQuickAccessName(e.target.value);
|
||||
}}
|
||||
value={quickAccessName}
|
||||
/>
|
||||
<OlStateButton
|
||||
onClick={() => {
|
||||
if (spawnRequestTable)
|
||||
key in props.starredSpawns
|
||||
? getApp().getMap().removeStarredSpawnRequestTable(key)
|
||||
: getApp().getMap().addStarredSpawnRequestTable(key, spawnRequestTable);
|
||||
}}
|
||||
tooltip="Save this spawn for quick access"
|
||||
checked={key in props.starredSpawns}
|
||||
icon={faStar}
|
||||
></OlStateButton>
|
||||
</div>
|
||||
<div
|
||||
className={`
|
||||
inline-flex w-full flex-row content-center justify-between gap-2
|
||||
@@ -146,43 +182,7 @@ export function UnitSpawnMenu(props: { starredSpawns: { [key: string]: SpawnRequ
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={`
|
||||
inline-flex w-full flex-row content-center justify-between gap-2
|
||||
`}
|
||||
>
|
||||
<div className="my-auto text-sm text-white">Quick access: </div>
|
||||
<OlStringInput
|
||||
onChange={(e) => {
|
||||
setQuickAccessName(e.target.value);
|
||||
}}
|
||||
value={quickAccessName}
|
||||
/>
|
||||
<OlStateButton
|
||||
onClick={() => {
|
||||
key in props.starredSpawns
|
||||
? getApp().getMap().removeStarredSpawnRequestTable(key)
|
||||
: getApp()
|
||||
.getMap()
|
||||
.addStarredSpawnRequestTable(key, {
|
||||
category: props.blueprint.category,
|
||||
unit: {
|
||||
unitType: props.blueprint.name,
|
||||
location: new LatLng(0, 0), // This will be filled when the user clicks on the map to spawn the unit
|
||||
skill: "High",
|
||||
liveryID: "",
|
||||
altitude: ftToM(spawnAltitude),
|
||||
loadout: props.blueprint.loadouts?.find((loadout) => loadout.name === spawnLoadoutName)?.code ?? "",
|
||||
},
|
||||
coalition: spawnCoalition,
|
||||
quickAccessName: quickAccessName,
|
||||
});
|
||||
}}
|
||||
tooltip="Save this spawn for quick access"
|
||||
checked={key in props.starredSpawns}
|
||||
icon={faStar}
|
||||
></OlStateButton>
|
||||
</div>
|
||||
|
||||
{["aircraft", "helicopter"].includes(props.blueprint.category) && (
|
||||
<>
|
||||
{!props.airbase && (
|
||||
@@ -219,18 +219,16 @@ export function UnitSpawnMenu(props: { starredSpawns: { [key: string]: SpawnRequ
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<div className="flex flex-row content-center justify-between">
|
||||
<span
|
||||
className={`
|
||||
h-8 font-normal
|
||||
dark:text-white
|
||||
`}
|
||||
>
|
||||
Role
|
||||
</span>
|
||||
</div>
|
||||
<OlDropdown label={spawnRole} className="w-full">
|
||||
<div className="flex content-center justify-between gap-2">
|
||||
<span
|
||||
className={`
|
||||
my-auto font-normal
|
||||
dark:text-white
|
||||
`}
|
||||
>
|
||||
Role
|
||||
</span>
|
||||
<OlDropdown label={spawnRole} className="w-64">
|
||||
{roles.map((role) => {
|
||||
return (
|
||||
<OlDropdownItem
|
||||
@@ -246,18 +244,16 @@ export function UnitSpawnMenu(props: { starredSpawns: { [key: string]: SpawnRequ
|
||||
})}
|
||||
</OlDropdown>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex flex-row content-center justify-between">
|
||||
<span
|
||||
className={`
|
||||
h-8 font-normal
|
||||
dark:text-white
|
||||
`}
|
||||
>
|
||||
Weapons
|
||||
</span>
|
||||
</div>
|
||||
<OlDropdown label={spawnLoadoutName} className={`w-full w-max-full`}>
|
||||
<div className="flex content-center justify-between gap-2">
|
||||
<span
|
||||
className={`
|
||||
my-auto font-normal
|
||||
dark:text-white
|
||||
`}
|
||||
>
|
||||
Weapons
|
||||
</span>
|
||||
<OlDropdown label={spawnLoadoutName} className={`w-64`}>
|
||||
{loadouts.map((loadout) => {
|
||||
return (
|
||||
<OlDropdownItem
|
||||
@@ -281,37 +277,135 @@ export function UnitSpawnMenu(props: { starredSpawns: { [key: string]: SpawnRequ
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<div className="flex content-center justify-between gap-2">
|
||||
<span
|
||||
className={`
|
||||
my-auto font-normal
|
||||
dark:text-white
|
||||
`}
|
||||
>
|
||||
Livery
|
||||
</span>
|
||||
<OlDropdown
|
||||
label={props.blueprint.liveries ? (props.blueprint.liveries[spawnLiveryID]?.name ?? "Default") : "No livery"}
|
||||
className={`w-64`}
|
||||
>
|
||||
{props.blueprint.liveries &&
|
||||
Object.keys(props.blueprint.liveries)
|
||||
.sort((ida, idb) => {
|
||||
if (props.blueprint.liveries) {
|
||||
if (props.blueprint.liveries[ida].countries.length > 1) return 1;
|
||||
return props.blueprint.liveries[ida].countries[0] > props.blueprint.liveries[idb].countries[0] ? 1 : -1;
|
||||
} else return -1;
|
||||
})
|
||||
.map((id) => {
|
||||
let country = Object.values(countryCodes).find((countryCode) => {
|
||||
if (props.blueprint.liveries && countryCode.liveryCodes?.includes(props.blueprint.liveries[id].countries[0])) return true;
|
||||
});
|
||||
return (
|
||||
<OlDropdownItem
|
||||
onClick={() => {
|
||||
setSpawnLiveryID(id);
|
||||
}}
|
||||
className={`w-full`}
|
||||
>
|
||||
<span
|
||||
className={`
|
||||
w-full content-center overflow-hidden text-ellipsis
|
||||
text-nowrap text-left w-max-full flex gap-2
|
||||
`}
|
||||
>
|
||||
{props.blueprint.liveries && props.blueprint.liveries[id].countries.length == 1 && (
|
||||
<img src={`images/countries/${country?.flagCode.toLowerCase()}.svg`} className={`
|
||||
h-6
|
||||
`} />
|
||||
)}
|
||||
|
||||
<div className="my-auto truncate">
|
||||
<span
|
||||
className={`
|
||||
w-full overflow-hidden text-left w-max-full
|
||||
`}
|
||||
>
|
||||
{props.blueprint.liveries ? props.blueprint.liveries[id].name : ""}
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
</OlDropdownItem>
|
||||
);
|
||||
})}
|
||||
</OlDropdown>
|
||||
</div>
|
||||
<div className="flex content-center justify-between gap-2">
|
||||
<span
|
||||
className={`
|
||||
my-auto font-normal
|
||||
dark:text-white
|
||||
`}
|
||||
>
|
||||
Skill
|
||||
</span>
|
||||
<OlDropdown label={spawnSkill} className={`w-64`}>
|
||||
{["Average", "Good", "High", "Excellent"].map((skill) => {
|
||||
return (
|
||||
<OlDropdownItem
|
||||
onClick={() => {
|
||||
setSpawnSkill(skill);
|
||||
}}
|
||||
className={`w-full`}
|
||||
>
|
||||
<span
|
||||
className={`
|
||||
w-full content-center overflow-hidden text-ellipsis
|
||||
text-nowrap text-left w-max-full flex gap-2
|
||||
`}
|
||||
>
|
||||
<div className="my-auto">{skill}</div>
|
||||
</span>
|
||||
</OlDropdownItem>
|
||||
);
|
||||
})}
|
||||
</OlDropdown>
|
||||
</div>
|
||||
</div>
|
||||
{spawnLoadout && spawnLoadout.items.length > 0 && (
|
||||
<div
|
||||
className={`
|
||||
flex h-fit flex-col gap-1 p-4
|
||||
flex h-fit flex-col gap-1 px-4 py-2
|
||||
dark:bg-olympus-200/30
|
||||
`}
|
||||
>
|
||||
{spawnLoadout.items.map((item) => {
|
||||
return (
|
||||
<div className="flex content-center gap-2">
|
||||
<div
|
||||
className={`
|
||||
my-auto w-6 min-w-6 rounded-full py-0.5 text-center text-sm
|
||||
font-bold text-gray-500
|
||||
dark:bg-[#17212D]
|
||||
`}
|
||||
>
|
||||
{item.quantity}
|
||||
<OlAccordion
|
||||
onClick={() => {
|
||||
setShowLoadout(!showLoadout);
|
||||
}}
|
||||
open={showLoadout}
|
||||
title="Loadout"
|
||||
>
|
||||
{spawnLoadout.items.map((item) => {
|
||||
return (
|
||||
<div className="flex content-center gap-2">
|
||||
<div
|
||||
className={`
|
||||
my-auto w-6 min-w-6 rounded-full py-0.5 text-center
|
||||
text-sm font-bold text-gray-500
|
||||
dark:bg-[#17212D]
|
||||
`}
|
||||
>
|
||||
{item.quantity}
|
||||
</div>
|
||||
<div
|
||||
className={`
|
||||
my-auto overflow-hidden text-ellipsis text-nowrap text-sm
|
||||
dark:text-gray-300
|
||||
`}
|
||||
>
|
||||
{item.name}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={`
|
||||
my-auto overflow-hidden text-ellipsis text-nowrap text-sm
|
||||
dark:text-gray-300
|
||||
`}
|
||||
>
|
||||
{item.name}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
);
|
||||
})}
|
||||
</OlAccordion>
|
||||
</div>
|
||||
)}
|
||||
{!props.spawnAtLocation && (
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
bearingAndDistanceToLatLng,
|
||||
deg2rad,
|
||||
getGroundElevation,
|
||||
keyEventWasInInput,
|
||||
latLngToMercator,
|
||||
mToFt,
|
||||
mercatorToLatLng,
|
||||
@@ -17,10 +16,7 @@ import { DELETE_CYCLE_TIME, DELETE_SLOW_THRESHOLD, DataIndexes, GAME_MASTER, IAD
|
||||
import { DataExtractor } from "../server/dataextractor";
|
||||
import { citiesDatabase } from "./databases/citiesdatabase";
|
||||
import { TemporaryUnitMarker } from "../map/markers/temporaryunitmarker";
|
||||
//import { Popup } from "../popups/popup";
|
||||
//import { HotgroupPanel } from "../panels/hotgrouppanel";
|
||||
import { Contact, UnitBlueprint, UnitData, UnitSpawnTable } from "../interfaces";
|
||||
//import { Dialog } from "../dialog/dialog";
|
||||
import { Group } from "./group";
|
||||
import { UnitDataFileExport } from "./importexport/unitdatafileexport";
|
||||
import { UnitDataFileImport } from "./importexport/unitdatafileimport";
|
||||
@@ -1357,7 +1353,7 @@ export class UnitsManager {
|
||||
|
||||
if (unitBlueprint)
|
||||
this.spawnUnits(
|
||||
"GroundUnit",
|
||||
unitBlueprint.category,
|
||||
[
|
||||
{
|
||||
unitType: unitBlueprint.name,
|
||||
@@ -1410,7 +1406,7 @@ export class UnitsManager {
|
||||
|
||||
if (unitBlueprint)
|
||||
this.spawnUnits(
|
||||
"GroundUnit",
|
||||
unitBlueprint.category,
|
||||
[
|
||||
{
|
||||
unitType: unitBlueprint.name,
|
||||
|
||||
Reference in New Issue
Block a user