fix: Spawn effect menu uses same logic as unit spawn, fixed airbase spawn menu

This commit is contained in:
Davide Passoni 2025-01-22 11:21:42 +01:00
parent 1374f270eb
commit cde33fdd76
5 changed files with 149 additions and 171 deletions

View File

@ -605,7 +605,7 @@ export function SpawnContextMenu(props: {}) {
coalition={spawnCoalition}
onBack={() => setBlueprint(null)}
/>
{!(effect === null) && latlng && <CompactEffectSpawnMenu effect={effect} latlng={latlng} onBack={() => setEffect(null)} />}
<EffectSpawnMenu visible={effect !== null} compact={true} effect={effect} latlng={latlng} onBack={() => setEffect(null)} />
</div>
</div>
</>

View File

@ -117,9 +117,10 @@ export function AirbaseMenu(props: { open: boolean; onClose: () => void; childre
<div key={idx}>
{Object.keys(runway.headings[0]).map((runwayName) => {
return (
<div key={`${idx}-${runwayName}`} className={`
flex w-full justify-between
`}>
<div
key={`${idx}-${runwayName}`}
className={`flex w-full justify-between`}
>
<span>
{" "}
<span className="text-gray-400">RWY</span> {runwayName}
@ -268,14 +269,14 @@ export function AirbaseMenu(props: { open: boolean; onClose: () => void; childre
</div>
)}
<>
{!(blueprint === null) && (
<UnitSpawnMenu
blueprint={blueprint}
starredSpawns={starredSpawns}
airbase={airbase}
coalition={(airbase?.getCoalition() ?? "blue") as Coalition}
/>
)}
<UnitSpawnMenu
visible={blueprint !== null}
compact={false}
blueprint={blueprint}
starredSpawns={starredSpawns}
airbase={airbase}
coalition={(airbase?.getCoalition() ?? "blue") as Coalition}
/>
</>
</>
)}

View File

@ -1,101 +0,0 @@
import React, { useEffect, useState } from "react";
import { OlDropdown, OlDropdownItem } from "../components/oldropdown";
import { getApp } from "../../olympusapp";
import { OlympusState, SpawnSubState } from "../../constants/constants";
import { OlStateButton } from "../components/olstatebutton";
import { faArrowLeft, faSmog } from "@fortawesome/free-solid-svg-icons";
import { LatLng } from "leaflet";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
export function CompactEffectSpawnMenu(props: { effect: string; latlng: LatLng; onBack: () => void }) {
const [explosionType, setExplosionType] = useState("High explosive");
const [smokeColor, setSmokeColor] = useState("white");
return (
<div className="flex h-full flex-col gap-4">
{props.effect === "explosion" && (
<>
<div className="flex">
<FontAwesomeIcon
onClick={props.onBack}
icon={faArrowLeft}
className={`
my-auto mr-1 h-4 cursor-pointer rounded-md p-2
dark:text-gray-500 dark:hover:bg-gray-700 dark:hover:text-white
`}
/>
<span className="my-auto text-white">Explosion type</span>
</div>
<OlDropdown label={explosionType} className="w-full">
{["High explosive", "Napalm", "White phosphorous"].map((optionExplosionType) => {
return (
<OlDropdownItem
key={optionExplosionType}
onClick={() => {
setExplosionType(optionExplosionType);
}}
>
{optionExplosionType}
</OlDropdownItem>
);
})}
</OlDropdown>
</>
)}
{props.effect === "smoke" && (
<>
<div className="flex">
<FontAwesomeIcon
onClick={props.onBack}
icon={faArrowLeft}
className={`
my-auto mr-1 h-4 cursor-pointer rounded-md p-2
dark:text-gray-500 dark:hover:bg-gray-700 dark:hover:text-white
`}
/>
<span className="my-auto text-white">Smoke color</span>
</div>
<div className="flex w-full gap-2">
{["white", "blue", "red", "green", "orange"].map((optionSmokeColor) => {
return (
<OlStateButton
checked={smokeColor === optionSmokeColor}
icon={faSmog}
onClick={() => {
setSmokeColor(optionSmokeColor);
}}
tooltip=""
buttonColor={optionSmokeColor}
/>
);
})}
</div>
</>
)}
<button
type="button"
className={`
m-2 rounded-lg bg-blue-600 px-5 py-2.5 text-sm font-medium text-white
focus:outline-none focus:ring-4
`}
onClick={() => {
if (props.effect === "explosion") {
if (explosionType === "High explosive") getApp().getServerManager().spawnExplosion(50, "normal", props.latlng);
else if (explosionType === "Napalm") getApp().getServerManager().spawnExplosion(50, "napalm", props.latlng);
else if (explosionType === "White phosphorous") getApp().getServerManager().spawnExplosion(50, "phosphorous", props.latlng);
getApp().getMap().addExplosionMarker(props.latlng);
} else if (props.effect === "smoke") {
getApp().getServerManager().spawnSmoke(smokeColor, props.latlng);
getApp()
.getMap()
.addSmokeMarker(props.latlng, smokeColor ?? "white");
}
getApp().setState(OlympusState.IDLE);
}}
>
Spawn
</button>
</div>
);
}

View File

@ -1,74 +1,152 @@
import React, { useEffect, useState } from "react";
import React, { useCallback, useEffect, useState } from "react";
import { OlDropdown, OlDropdownItem } from "../components/oldropdown";
import { getApp } from "../../olympusapp";
import { OlympusState, SpawnSubState } from "../../constants/constants";
import { NO_SUBSTATE, OlympusState, OlympusSubState, SpawnSubState } from "../../constants/constants";
import { OlStateButton } from "../components/olstatebutton";
import { faSmog } from "@fortawesome/free-solid-svg-icons";
import { faArrowLeft, faSmog } from "@fortawesome/free-solid-svg-icons";
import { LatLng } from "leaflet";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { AppStateChangedEvent } from "../../events";
export function EffectSpawnMenu(props: { effect: string }) {
export function EffectSpawnMenu(props: { visible: boolean; compact: boolean; effect: string | null; latlng?: LatLng | null; onBack?: () => void }) {
const [appState, setAppState] = useState(OlympusState.NOT_INITIALIZED);
const [appSubState, setAppSubState] = useState(NO_SUBSTATE as OlympusSubState);
const [explosionType, setExplosionType] = useState("High explosive");
const [smokeColor, setSmokeColor] = useState("white");
/* When the menu is opened show the unit preview on the map as a cursor */
useEffect(() => {
if (props.effect !== null) {
if (props.effect === "explosion")
getApp()?.getMap()?.setEffectRequestTable({
type: props.effect,
explosionType,
});
else if (props.effect === "smoke")
getApp()?.getMap()?.setEffectRequestTable({
type: props.effect,
smokeColor,
});
getApp().setState(OlympusState.SPAWN, SpawnSubState.SPAWN_EFFECT);
} else {
if (getApp().getState() === OlympusState.SPAWN && getApp().getSubState() === SpawnSubState.SPAWN_EFFECT) getApp().setState(OlympusState.IDLE);
AppStateChangedEvent.on((state, subState) => {
setAppState(state);
setAppSubState(subState);
});
}, []);
/* When the menu is opened show the effect preview on the map as a cursor */
const updateEffectRequestTable = useCallback(() => {
if (!props.compact) {
if (props.effect !== null) {
if (props.effect === "explosion")
getApp()?.getMap()?.setEffectRequestTable({
type: props.effect,
explosionType,
});
else if (props.effect === "smoke")
getApp()?.getMap()?.setEffectRequestTable({
type: props.effect,
smokeColor,
});
getApp().setState(OlympusState.SPAWN, SpawnSubState.SPAWN_EFFECT);
} else {
if (appState === OlympusState.SPAWN && appSubState === SpawnSubState.SPAWN_EFFECT) getApp().setState(OlympusState.IDLE);
}
}
});
}, [props.visible, explosionType, smokeColor, props.effect]);
useEffect(updateEffectRequestTable, [props.visible, explosionType, smokeColor]);
return (
<div className="flex h-full flex-col gap-4 p-4">
{props.effect === "explosion" && (
<>
{props.visible ? (
<>
<span className="text-white">Explosion type</span>
<OlDropdown label={explosionType} className="w-full">
{["High explosive", "Napalm", "White phosphorous"].map((optionExplosionType) => {
return (
<OlDropdownItem
key={optionExplosionType}
onClick={() => {
setExplosionType(optionExplosionType);
}}
>
{optionExplosionType}
</OlDropdownItem>
);
})}
</OlDropdown>
</>
)}
{props.effect === "smoke" && (
<>
<span className="text-white">Smoke color</span>
<div className="flex w-full gap-2">
{["white", "blue", "red", "green", "orange"].map((optionSmokeColor) => {
return (
<OlStateButton
checked={smokeColor === optionSmokeColor}
icon={faSmog}
onClick={() => {
setSmokeColor(optionSmokeColor);
}}
tooltip=""
buttonColor={optionSmokeColor}
/>
);
})}
<div className="flex h-full flex-col gap-4 p-4">
{props.effect === "explosion" && (
<>
<div className="flex">
{props.compact && (
<FontAwesomeIcon
onClick={props.onBack}
icon={faArrowLeft}
className={`
my-auto mr-1 h-4 cursor-pointer rounded-md p-2
dark:text-gray-500 dark:hover:bg-gray-700
dark:hover:text-white
`}
/>
)}
<span className="my-auto text-white">Explosion type</span>
</div>
<OlDropdown label={explosionType} className="w-full">
{["High explosive", "Napalm", "White phosphorous"].map((optionExplosionType) => {
return (
<OlDropdownItem
key={optionExplosionType}
onClick={() => {
setExplosionType(optionExplosionType);
}}
>
{optionExplosionType}
</OlDropdownItem>
);
})}
</OlDropdown>
</>
)}
{props.effect === "smoke" && (
<>
<div className="flex">
{props.compact && (
<FontAwesomeIcon
onClick={props.onBack}
icon={faArrowLeft}
className={`
my-auto mr-1 h-4 cursor-pointer rounded-md p-2
dark:text-gray-500 dark:hover:bg-gray-700
dark:hover:text-white
`}
/>
)}
<span className="my-auto text-white">Smoke color</span>
</div>
<div className="flex w-full gap-2">
{["white", "blue", "red", "green", "orange"].map((optionSmokeColor) => {
return (
<OlStateButton
checked={smokeColor === optionSmokeColor}
icon={faSmog}
onClick={() => {
setSmokeColor(optionSmokeColor);
}}
tooltip=""
buttonColor={optionSmokeColor}
/>
);
})}
</div>
</>
)}
{props.compact && (
<button
type="button"
className={`
m-2 rounded-lg bg-blue-600 px-5 py-2.5 text-sm font-medium
text-white
focus:outline-none focus:ring-4
`}
onClick={() => {
if (props.latlng) {
if (props.effect === "explosion") {
if (explosionType === "High explosive") getApp().getServerManager().spawnExplosion(50, "normal", props.latlng);
else if (explosionType === "Napalm") getApp().getServerManager().spawnExplosion(50, "napalm", props.latlng);
else if (explosionType === "White phosphorous") getApp().getServerManager().spawnExplosion(50, "phosphorous", props.latlng);
getApp().getMap().addExplosionMarker(props.latlng);
} else if (props.effect === "smoke") {
getApp().getServerManager().spawnSmoke(smokeColor, props.latlng);
getApp()
.getMap()
.addSmokeMarker(props.latlng, smokeColor ?? "white");
}
}
getApp().setState(OlympusState.IDLE);
}}
>
Spawn
</button>
)}
</div>
</>
) : (
<></>
)}
</div>
</>
);
}

View File

@ -441,7 +441,7 @@ export function SpawnMenu(props: { open: boolean; onClose: () => void; children?
coalition={commandModeOptions.commandMode !== GAME_MASTER ? (commandModeOptions.commandMode === BLUE_COMMANDER ? "blue" : "red") : undefined}
/>
{!(effect === null) && <EffectSpawnMenu effect={effect} />}
<EffectSpawnMenu visible={effect !== null} compact={false} effect={effect} />
</>
</Menu>
);