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:
parent
fa215142ad
commit
c8e1f76b38
@ -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,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
{
|
||||
export const countryCodes = {
|
||||
"AGGRESSORS": {
|
||||
"flagCode": "RED",
|
||||
"liveryCodes": ["RSO"]
|
||||
@ -250,7 +250,7 @@
|
||||
"SOUTH_AFRICA": {
|
||||
"displayName": "South Africa",
|
||||
"flagCode": "ZA",
|
||||
"liveryCodes": []
|
||||
"liveryCodes": null
|
||||
},
|
||||
"SPAIN": {
|
||||
"flagCode": "ES",
|
||||
@ -323,7 +323,7 @@
|
||||
"SOUTH_OSETIA": {
|
||||
"displayName": "South Ossetia",
|
||||
"flagCode": "UNK",
|
||||
"liveryCodes": []
|
||||
"liveryCodes": null
|
||||
},
|
||||
"NORTH_KOREA": {
|
||||
"displayName": "Democratic People's Republic of Korea",
|
||||
@ -347,7 +347,7 @@
|
||||
"USSR": {
|
||||
"displayName": "USSR",
|
||||
"flagCode": "USSR",
|
||||
"liveryCodes": []
|
||||
"liveryCodes": null
|
||||
},
|
||||
"ECUADOR": {
|
||||
"flagCode": "EC",
|
||||
@ -373,6 +373,6 @@
|
||||
"THIRDREICH": {
|
||||
"displayName": "Third Reich",
|
||||
"flagCode": "THIRD",
|
||||
"liveryCodes": []
|
||||
"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,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user