fix: Unable to clone units if game master with spawn restrictions on

Other minor graphical fixes
This commit is contained in:
Pax1601
2025-03-25 19:30:00 +01:00
parent bc65bf546f
commit 41b4328eaf
18 changed files with 622 additions and 78 deletions

View File

@@ -34,7 +34,6 @@ export var IP = window.location.toString();
export class OlympusApp {
/* Global data */
#latestVersion: string | undefined = undefined;
#config: OlympusConfig;
#state: OlympusState = OlympusState.NOT_INITIALIZED;
#subState: OlympusSubState = NO_SUBSTATE;
@@ -135,25 +134,6 @@ export class OlympusApp {
this.#coalitionAreasManager = new CoalitionAreasManager();
this.#drawingsManager = new DrawingsManager();
/* Check if we are running the latest version */
const request = new Request("https://raw.githubusercontent.com/Pax1601/DCSOlympus/main/version.json");
fetch(request)
.then((response) => {
if (response.status === 200) {
return response.json();
} else {
throw new Error("Error connecting to Github to retrieve latest version");
}
})
.then((res) => {
this.#latestVersion = res["version"];
const latestVersionSpan = document.getElementById("latest-version") as HTMLElement;
if (latestVersionSpan) {
latestVersionSpan.innerHTML = this.#latestVersion ?? "Unknown";
latestVersionSpan.classList.toggle("new-version", this.#latestVersion !== VERSION);
}
});
/* Load the config file from the server */
const configRequest = new Request("./resources/config", {
headers: {

File diff suppressed because one or more lines are too long

View File

@@ -20,6 +20,14 @@ import {
olButtonsVisibilityGroundunitSam,
olButtonsVisibilityHelicopter,
olButtonsVisibilityNavyunit,
olIconsApc,
olIconsArtillery,
olIconsEwr,
olIconsInfantry,
olIconsRadar,
olIconsTactical,
olIconsTank,
olIconsTruck,
} from "../components/olicons";
import { OlUnitListEntry } from "../components/olunitlistentry";
import { OlSearchBar } from "../components/olsearchbar";
@@ -306,9 +314,15 @@ export function SpawnContextMenu(props: {}) {
/>
);
})}
{blueprints?.length === 0 && <span className={`
{blueprints?.length === 0 && (
<span
className={`
text-gray-200
`}>No aircraft available</span>}
`}
>
No aircraft available
</span>
)}
</div>
</>
)}
@@ -356,9 +370,15 @@ export function SpawnContextMenu(props: {}) {
/>
);
})}
{blueprints?.length === 0 && <span className={`
{blueprints?.length === 0 && (
<span
className={`
text-gray-200
`}>No helicopter available</span>}
`}
>
No helicopter available
</span>
)}
</div>
</>
)}
@@ -409,9 +429,15 @@ export function SpawnContextMenu(props: {}) {
/>
);
})}
{blueprints?.length === 0 && <span className={`
{blueprints?.length === 0 && (
<span
className={`
text-gray-200
`}>No air defence unit available</span>}
`}
>
No air defence unit available
</span>
)}
</div>
</>
)}
@@ -454,7 +480,21 @@ export function SpawnContextMenu(props: {}) {
return (
<OlUnitListEntry
key={blueprint.name}
icon={olButtonsVisibilityGroundunit}
icon={
{
Infantry: olIconsInfantry,
APC: olIconsApc,
Artillery: olIconsArtillery,
Radar: olIconsRadar,
"Radar (EWR)": olIconsEwr,
Tank: olIconsTank,
"Tactical Vehicle": olIconsTactical,
None: olButtonsVisibilityGroundunit,
Unarmed: olIconsTruck,
AAA: olButtonsVisibilityGroundunitSam,
"SAM Site Parts": olButtonsVisibilityGroundunitSam,
}[blueprint.type ?? "None"]
}
blueprint={blueprint}
onClick={() => setBlueprint(blueprint)}
showCost={showCost}
@@ -462,9 +502,15 @@ export function SpawnContextMenu(props: {}) {
/>
);
})}
{blueprints?.length === 0 && <span className={`
{blueprints?.length === 0 && (
<span
className={`
text-gray-200
`}>No ground unit available</span>}
`}
>
No ground unit available
</span>
)}
</div>
</>
)}
@@ -512,13 +558,19 @@ export function SpawnContextMenu(props: {}) {
/>
);
})}
{blueprints?.length === 0 && <span className={`
{blueprints?.length === 0 && (
<span
className={`
text-gray-200
`}>No navy unit available</span>}
`}
>
No navy unit available
</span>
)}
</div>
</>
)}
{openAccordion === CategoryGroup.EFFECT && commandModeOptions.commandMode === GAME_MASTER && (
{openAccordion === CategoryGroup.EFFECT && commandModeOptions.commandMode === GAME_MASTER && (
<>
<div
className={`
@@ -545,10 +597,8 @@ export function SpawnContextMenu(props: {}) {
</div>
</>
)}
{openAccordion === CategoryGroup.EFFECT && commandModeOptions.commandMode !== GAME_MASTER && (
<div className="text-white">
Not available in this mode
</div>
{openAccordion === CategoryGroup.EFFECT && commandModeOptions.commandMode !== GAME_MASTER && (
<div className="text-white">Not available in this mode</div>
)}
{openAccordion === CategoryGroup.SEARCH && (
<div className="flex flex-col gap-2">

View File

@@ -46,7 +46,7 @@ export function AWACSMenu(props: { open: boolean; onClose: () => void; children?
/>
<div className="flex flex-col gap-1 text-sm text-gray-500">
<p>1 Use the coalition toggle to change your coalition as AWACS.</p>
<p>2 Optionally, set a friendly unit as reference by right clicking on it and selecting "Set AWACS reference" to create tactical calls.</p>
<p>2 Optionally, set a friendly unit as reference by left clicking and holding on it and selecting "Set AWACS reference" to create tactical calls.</p>
</div>
</div>
<div className="flex gap-4">

View File

@@ -1,23 +1,9 @@
import React, { useEffect, useRef, useState } from "react";
import { OlRoundStateButton, OlStateButton, OlLockStateButton } from "../components/olstatebutton";
import {
faSkull,
faCamera,
faFlag,
faVolumeHigh,
faDownload,
faUpload,
faDrawPolygon,
faCircle,
faTriangleExclamation,
faWifi,
faHourglass,
faInfo,
faObjectGroup,
} from "@fortawesome/free-solid-svg-icons";
import { faSkull, faCamera, faFlag, faVolumeHigh, faDrawPolygon, faTriangleExclamation, faWifi, faObjectGroup } from "@fortawesome/free-solid-svg-icons";
import { OlDropdownItem, OlDropdown } from "../components/oldropdown";
import { OlLabelToggle } from "../components/ollabeltoggle";
import { getApp, IP } from "../../olympusapp";
import { getApp, IP, VERSION } from "../../olympusapp";
import {
olButtonsVisibilityAirbase,
olButtonsVisibilityAircraft,
@@ -39,20 +25,10 @@ import {
SessionDataChangedEvent,
SessionDataSavedEvent,
} from "../../events";
import {
BLUE_COMMANDER,
COMMAND_MODE_OPTIONS_DEFAULTS,
ImportExportSubstate,
MAP_HIDDEN_TYPES_DEFAULTS,
MAP_OPTIONS_DEFAULTS,
OlympusState,
RED_COMMANDER,
} from "../../constants/constants";
import { BLUE_COMMANDER, COMMAND_MODE_OPTIONS_DEFAULTS, MAP_HIDDEN_TYPES_DEFAULTS, MAP_OPTIONS_DEFAULTS, RED_COMMANDER } from "../../constants/constants";
import { OlympusConfig } from "../../interfaces";
import { FaCheck, FaQuestionCircle, FaSave, FaSpinner } from "react-icons/fa";
import { FaCheck, FaSpinner } from "react-icons/fa";
import { OlExpandingTooltip } from "../components/olexpandingtooltip";
import { ftToM } from "../../other/utils";
import { LatLng } from "leaflet";
export function Header() {
const [mapHiddenTypes, setMapHiddenTypes] = useState(MAP_HIDDEN_TYPES_DEFAULTS);
@@ -64,12 +40,16 @@ export function Header() {
const [audioEnabled, setAudioEnabled] = useState(false);
const [commandModeOptions, setCommandModeOptions] = useState(COMMAND_MODE_OPTIONS_DEFAULTS);
const [savingSessionData, setSavingSessionData] = useState(false);
const [latestVersion, setLatestVersion] = useState("");
const [isLatestVersion, setIsLatestVersion] = useState(false);
const [isBetaVersion, setIsBetaVersion] = useState(false);
const [isDevVersion, setIsDevVersion] = useState(false);
useEffect(() => {
HiddenTypesChangedEvent.on((hiddenTypes) => setMapHiddenTypes({ ...hiddenTypes }));
MapOptionsChangedEvent.on((mapOptions) => {
setMapOptions({ ...mapOptions })
});
setMapOptions({ ...mapOptions });
});
MapSourceChangedEvent.on((source) => setMapSource(source));
ConfigLoadedEvent.on((config: OlympusConfig) => {
// Timeout needed to make sure the map configuration has updated
@@ -83,6 +63,48 @@ export function Header() {
});
SessionDataChangedEvent.on(() => setSavingSessionData(true));
SessionDataSavedEvent.on(() => setSavingSessionData(false));
/* Check if we are running the latest version */
const request = new Request("https://raw.githubusercontent.com/Pax1601/DCSOlympus/main/version.json");
fetch(request)
.then((response) => {
if (response.status === 200) {
return response.json();
} else {
throw new Error("Error connecting to Github to retrieve latest version");
}
})
.then((res) => {
setLatestVersion(res["version"]);
if (VERSION === "{{OLYMPUS_VERSION_NUMBER}}") {
console.log("OLYMPUS_VERSION_NUMBER is not set. Skipping version check.");
setIsDevVersion(true);
return;
}
/* Check if the new version is newer than the current one */
/* Extract the version numbers */
const currentVersion = VERSION.replace("v", "").split(".");
const newVersion = res["version"].replace("v", "").split(".");
setIsBetaVersion(true);
setIsLatestVersion(true);
/* Compare the version numbers */
for (var i = 0; i < currentVersion.length; i++) {
if (parseInt(newVersion[i]) > parseInt(currentVersion[i])) {
setIsLatestVersion(false);
}
}
/* Check if this is a beta version checking if this version is newer */
for (var i = 0; i < currentVersion.length; i++) {
if (parseInt(newVersion[i]) < parseInt(currentVersion[i])) {
setIsBetaVersion(false);
}
}
});
}, []);
/* Initialize the "scroll" position of the element */
@@ -174,6 +196,20 @@ export function Header() {
</div>
)}
</div>
{isDevVersion ? (
<div className={`text-gray-400`}>Development build</div>
) : (
<>
<div>
{!isLatestVersion && (
<div className={`animate-pulse text-gray-400`}>
<span className={`font-bold`}>New version available:</span> {latestVersion}
</div>
)}
</div>
<div>{!isBetaVersion && <div className={`text-gray-400`}>beta version</div>}</div>
</>
)}
</div>
{commandModeOptions.commandMode === BLUE_COMMANDER && (

View File

@@ -7,11 +7,17 @@ import { OlUnitListEntry } from "../components/olunitlistentry";
import { UnitSpawnMenu } from "./unitspawnmenu";
import { SpawnRequestTable, UnitBlueprint } from "../../interfaces";
import {
olButtonsVisibilityAircraft,
olButtonsVisibilityGroundunit,
olButtonsVisibilityGroundunitSam,
olButtonsVisibilityHelicopter,
olButtonsVisibilityNavyunit,
olIconsApc,
olIconsArtillery,
olIconsEwr,
olIconsInfantry,
olIconsRadar,
olIconsTactical,
olIconsTank,
olIconsTruck,
} from "../components/olicons";
import { faExplosion, faSmog } from "@fortawesome/free-solid-svg-icons";
import { OlEffectListEntry } from "../components/oleffectlistentry";
@@ -99,6 +105,8 @@ export function SpawnMenu(props: { open: boolean; onClose: () => void; children?
});
}
filteredBlueprints.sort((a, b) => a.label.localeCompare(b.label));
useEffect(() => {
if (!props.open) {
if (blueprint !== null) setBlueprint(null);
@@ -263,7 +271,7 @@ export function SpawnMenu(props: { open: boolean; onClose: () => void; children?
return (
<OlUnitListEntry
key={blueprint.name}
icon={olButtonsVisibilityHelicopter}
silhouette={blueprint.filename}
blueprint={blueprint}
onClick={() => setBlueprint(blueprint)}
showCost={showCost}
@@ -339,9 +347,13 @@ export function SpawnMenu(props: { open: boolean; onClose: () => void; children?
/>
);
})}
{filteredBlueprints.filter((blueprint) => blueprint.canAAA).length === 0 && <span className={`
text-gray-400
`}>No AAA unit available</span>}
{filteredBlueprints.filter((blueprint) => blueprint.canAAA).length === 0 && (
<span
className={`text-gray-400`}
>
No AAA unit available
</span>
)}
</div>
</OlAccordion>
<OlAccordion
@@ -389,7 +401,21 @@ export function SpawnMenu(props: { open: boolean; onClose: () => void; children?
return (
<OlUnitListEntry
key={blueprint.name}
icon={olButtonsVisibilityGroundunit}
icon={
{
Infantry: olIconsInfantry,
APC: olIconsApc,
Artillery: olIconsArtillery,
Radar: olIconsRadar,
"Radar (EWR)": olIconsEwr,
Tank: olIconsTank,
"Tactical Vehicle": olIconsTactical,
None: olButtonsVisibilityGroundunit,
Unarmed: olIconsTruck,
AAA: olButtonsVisibilityGroundunitSam,
"SAM Site Parts": olButtonsVisibilityGroundunitSam,
}[blueprint.type ?? "None"]
}
blueprint={blueprint}
onClick={() => setBlueprint(blueprint)}
showCost={showCost}