import React, { MutableRefObject, useEffect, useRef, useState } from "react"; import { Menu } from "./components/menu"; import { Unit } from "../../unit/unit"; import { OlLabelToggle } from "../components/ollabeltoggle"; import { OlRangeSlider } from "../components/olrangeslider"; import { getApp } from "../../olympusapp"; import { OlButtonGroup, OlButtonGroupItem } from "../components/olbuttongroup"; import { OlCheckbox } from "../components/olcheckbox"; import { ROEs, emissionsCountermeasures, reactionsToThreat } from "../../constants/constants"; import { OlToggle } from "../components/oltoggle"; import { OlCoalitionToggle } from "../components/olcoalitiontoggle"; import { olButtonsEmissionsAttack, olButtonsEmissionsDefend, olButtonsEmissionsFree, olButtonsEmissionsSilent, olButtonsIntensity1, olButtonsIntensity2, olButtonsIntensity3, olButtonsRoeDesignated, olButtonsRoeFree, olButtonsRoeHold, olButtonsRoeReturn, olButtonsScatter1, olButtonsScatter2, olButtonsScatter3, olButtonsThreatEvade, olButtonsThreatManoeuvre, olButtonsThreatNone, olButtonsThreatPassive, olButtonsVisibilityAircraft, olButtonsVisibilityDcs, olButtonsVisibilityGroundunit, olButtonsVisibilityGroundunitSam, olButtonsVisibilityHelicopter, olButtonsVisibilityHuman, olButtonsVisibilityNavyunit, olButtonsVisibilityOlympus, } from "../components/olicons"; import { Coalition } from "../../types/types"; import { ftToM, getUnitsByLabel, knotsToMs, mToFt, msToKnots } from "../../other/utils"; import { FaCog, FaGasPump, FaSignal, FaTag } from "react-icons/fa"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { OlSearchBar } from "../components/olsearchbar"; import { OlDropdown, OlDropdownItem } from "../components/oldropdown"; import { UnitBlueprint } from "../../interfaces"; import { FaRadio, FaVolumeHigh } from "react-icons/fa6"; import { OlNumberInput } from "../components/olnumberinput"; import { Radio, TACAN } from "../../interfaces"; import { OlStringInput } from "../components/olstringinput"; import { OlFrequencyInput } from "../components/olfrequencyinput"; import { UnitSink } from "../../audio/unitsink"; export function UnitControlMenu(props: { open: boolean; onClose: () => void }) { const [selectedUnits, setSelectedUnits] = useState([] as Unit[]); const [selectedUnitsData, setSelectedUnitsData] = useState({ desiredAltitude: undefined as undefined | number, desiredAltitudeType: undefined as undefined | string, desiredSpeed: undefined as undefined | number, desiredSpeedType: undefined as undefined | string, ROE: undefined as undefined | string, reactionToThreat: undefined as undefined | string, emissionsCountermeasures: undefined as undefined | string, scenicAAA: undefined as undefined | boolean, missOnPurpose: undefined as undefined | boolean, shotsScatter: undefined as undefined | number, shotsIntensity: undefined as undefined | number, operateAs: undefined as undefined | Coalition, followRoads: undefined as undefined | boolean, isActiveAWACS: undefined as undefined | boolean, isActiveTanker: undefined as undefined | boolean, onOff: undefined as undefined | boolean, isAudioSink: undefined as undefined | boolean, }); const [selectionFilter, setSelectionFilter] = useState({ control: { human: true, dcs: true, olympus: true, }, blue: { aircraft: true, helicopter: true, "groundunit-sam": true, groundunit: true, navyunit: true, }, neutral: { aircraft: true, helicopter: true, "groundunit-sam": true, groundunit: true, navyunit: true, }, red: { aircraft: true, helicopter: true, "groundunit-sam": true, groundunit: true, navyunit: true, }, }); const [selectionBlueprint, setSelectionBlueprint] = useState(null as null | UnitBlueprint); const [searchBarRefState, setSearchBarRefState] = useState(null as MutableRefObject | null); const [filterString, setFilterString] = useState(""); const [showAdvancedSettings, setShowAdvancedSettings] = useState(false); const [activeAdvancedSettings, setActiveAdvancedSettings] = useState(null as null | { radio: Radio; TACAN: TACAN }); const [audioManagerEnabled, setAudioManagerEnabled] = useState(false); var searchBarRef = useRef(null); useEffect(() => { if (!searchBarRefState) setSearchBarRefState(searchBarRef); if (!props.open && selectionBlueprint !== null) setSelectionBlueprint(null); if (!props.open && filterString !== "") setFilterString(""); }); useEffect(() => { /* When a unit is selected, update the data */ document.addEventListener("unitsSelection", (ev: CustomEventInit) => { setSelectedUnits(ev.detail as Unit[]); updateData(); }); /* When a unit is deselected, refresh the view */ document.addEventListener("unitDeselection", (ev: CustomEventInit) => { window.setTimeout(() => updateData(), 200); }); /* When all units are deselected clean the view */ document.addEventListener("clearSelection", () => { setSelectedUnits([]); }); document.addEventListener("audioManagerStateChanged", () => { setAudioManagerEnabled(getApp().getAudioManager().isRunning()); }); }, []); useEffect(() => { setShowAdvancedSettings(false); }, [selectedUnits]) /* Update the current values of the shown data */ function updateData() { const getters = { desiredAltitude: (unit: Unit) => { return Math.round(mToFt(unit.getDesiredAltitude())); }, desiredAltitudeType: (unit: Unit) => { return unit.getDesiredAltitudeType(); }, desiredSpeed: (unit: Unit) => { return Math.round(msToKnots(unit.getDesiredSpeed())); }, desiredSpeedType: (unit: Unit) => { return unit.getDesiredSpeedType(); }, ROE: (unit: Unit) => { return unit.getROE(); }, reactionToThreat: (unit: Unit) => { return unit.getReactionToThreat(); }, emissionsCountermeasures: (unit: Unit) => { return unit.getEmissionsCountermeasures(); }, scenicAAA: (unit: Unit) => { return unit.getState() === "scenic-aaa"; }, missOnPurpose: (unit: Unit) => { return unit.getState() === "miss-on-purpose"; }, shotsScatter: (unit: Unit) => { return unit.getShotsScatter(); }, shotsIntensity: (unit: Unit) => { return unit.getShotsIntensity(); }, operateAs: (unit: Unit) => { return unit.getOperateAs(); }, followRoads: (unit: Unit) => { return unit.getFollowRoads(); }, isActiveAWACS: (unit: Unit) => { return unit.getIsActiveAWACS(); }, isActiveTanker: (unit: Unit) => { return unit.getIsActiveTanker(); }, onOff: (unit: Unit) => { return unit.getOnOff(); }, isAudioSink: (unit: Unit) => { return ( getApp() ?.getAudioManager() .getSinks() .filter((sink) => { return sink instanceof UnitSink; }).length > 0 && getApp() ?.getAudioManager() .getSinks() .find((sink) => { return sink instanceof UnitSink && sink.getUnit() === unit; }) !== undefined ); }, } as { [key in keyof typeof selectedUnitsData]: (unit: Unit) => void }; var updatedData = selectedUnitsData; Object.entries(getters).forEach(([key, getter]) => { updatedData[key] = getApp()?.getUnitsManager()?.getSelectedUnitsVariable(getter); }); setSelectedUnitsData(updatedData); } /* Count how many units are selected of each type, divided by coalition */ var unitOccurences: { blue: { [key: string]: { label: string; occurences: number } }; red: { [key: string]: { label: string; occurences: number } }; neutral: { [key: string]: { label: string; occurences: number } }; } = { blue: {}, red: {}, neutral: {}, }; selectedUnits.forEach((unit) => { if (!(unit.getName() in unitOccurences[unit.getCoalition()])) unitOccurences[unit.getCoalition()][unit.getName()] = { occurences: 1, label: unit.getBlueprint()?.label }; else unitOccurences[unit.getCoalition()][unit.getName()].occurences++; }); const selectedCategories = getApp()?.getUnitsManager()?.getSelectedUnitsCategories() ?? []; const [filteredAircraft, filteredHelicopters, filteredAirDefense, filteredGroundUnits, filteredNavyUnits] = getUnitsByLabel(filterString); const mergedFilteredUnits = Object.assign({}, filteredAircraft, filteredHelicopters, filteredAirDefense, filteredGroundUnits, filteredNavyUnits) as { [key: string]: UnitBlueprint; }; const everyUnitIsGround = selectedCategories.every((category) => { return category === "GroundUnit"; }); const everyUnitIsNavy = selectedCategories.every((category) => { return category === "NavyUnit"; }); const everyUnitIsHelicopter = selectedCategories.every((category) => { return category === "Helicopter"; }); const minAltitude = 0; const minSpeed = 0; let maxAltitude = 60000; let maxSpeed = 800; let altitudeStep = 500; let speedStep = 10; if (everyUnitIsHelicopter) { maxAltitude = 20000; maxSpeed = 200; speedStep = 5; altitudeStep = 100; } if (everyUnitIsGround || everyUnitIsNavy) { maxSpeed = 60; speedStep = 1; } return ( 0 ? `Units selected (x${selectedUnits.length})` : `No units selected`} onClose={props.onClose} canBeHidden={true} > <> {/* ============== Selection tool START ============== */} {selectedUnits.length == 0 && (
Selection tool
The selection tools allows you to select units depending on their category, coalition, and control mode. You can also select units depending on their specific type by using the search input.
Control mode
{Object.entries({ human: ["Human", olButtonsVisibilityHuman], olympus: ["Olympus controlled", olButtonsVisibilityOlympus], dcs: ["From DCS mission", olButtonsVisibilityDcs], }).map((entry, idx) => { return (
{entry[1][0] as string} { selectionFilter["control"][entry[0]] = !selectionFilter["control"][entry[0]]; setSelectionFilter(JSON.parse(JSON.stringify(selectionFilter))); }} toggled={selectionFilter["control"][entry[0]]} />
); })}
Types and coalitions
{selectionBlueprint === null && Object.entries({ aircraft: olButtonsVisibilityAircraft, helicopter: olButtonsVisibilityHelicopter, "groundunit-sam": olButtonsVisibilityGroundunitSam, groundunit: olButtonsVisibilityGroundunit, navyunit: olButtonsVisibilityNavyunit, }).map((entry, idx) => { return ( {["blue", "neutral", "red"].map((coalition) => { return ( ); })} ); })}
BLUE NEUTRAL RED
{ selectionFilter[coalition][entry[0]] = !selectionFilter[coalition][entry[0]]; setSelectionFilter(JSON.parse(JSON.stringify(selectionFilter))); }} />
value)} onChange={() => { const newValue = !Object.values(selectionFilter["blue"]).some((value) => value); Object.keys(selectionFilter["blue"]).forEach((key) => { selectionFilter["blue"][key] = newValue; }); setSelectionFilter(JSON.parse(JSON.stringify(selectionFilter))); }} /> value)} onChange={() => { const newValue = !Object.values(selectionFilter["neutral"]).some((value) => value); Object.keys(selectionFilter["neutral"]).forEach((key) => { selectionFilter["neutral"][key] = newValue; }); setSelectionFilter(JSON.parse(JSON.stringify(selectionFilter))); }} /> value)} onChange={() => { const newValue = !Object.values(selectionFilter["red"]).some((value) => value); Object.keys(selectionFilter["red"]).forEach((key) => { selectionFilter["red"][key] = newValue; }); setSelectionFilter(JSON.parse(JSON.stringify(selectionFilter))); }} />
{ setFilterString(value); selectionBlueprint && setSelectionBlueprint(null); }} text={selectionBlueprint ? selectionBlueprint.label : filterString} />
{filterString !== "" && Object.keys(mergedFilteredUnits).length > 0 && Object.entries(mergedFilteredUnits).map((entry) => { const blueprint = entry[1]; return ( { setSelectionBlueprint(blueprint); }} > {blueprint.label} ); })} {Object.keys(mergedFilteredUnits).length == 0 && No results}
)} {/* ============== Selection tool END ============== */} {/* */} {/* */} {/* */} {/* */} {/* */} {/* */} <> {/* ============== Unit control menu START ============== */} {selectedUnits.length > 0 && ( <> {/* ============== Units list START ============== */}
{ <> {["blue", "red", "neutral"].map((coalition) => { return Object.keys(unitOccurences[coalition]).map((name, idx) => { return (
{unitOccurences[coalition][name].label} x{unitOccurences[coalition][name].occurences}
); }); })} }
{/* ============== Units list END ============== */} {/* ============== Unit basic options START ============== */} <> {!showAdvancedSettings && (
{/* ============== Altitude selector START ============== */} {selectedCategories.every((category) => { return ["Aircraft", "Helicopter"].includes(category); }) && (
Altitude {selectedUnitsData.desiredAltitude !== undefined ? Intl.NumberFormat("en-US").format(selectedUnitsData.desiredAltitude) + " FT" : "Different values"}
{ selectedUnits.forEach((unit) => { unit.setAltitudeType(selectedUnitsData.desiredAltitudeType === "ASL" ? "AGL" : "ASL"); setSelectedUnitsData({ ...selectedUnitsData, desiredAltitudeType: selectedUnitsData.desiredAltitudeType === "ASL" ? "AGL" : "ASL", }); }); }} />
{ selectedUnits.forEach((unit) => { unit.setAltitude(ftToM(Number(ev.target.value))); setSelectedUnitsData({ ...selectedUnitsData, desiredAltitude: Number(ev.target.value), }); }); }} value={selectedUnitsData.desiredAltitude} min={minAltitude} max={maxAltitude} step={altitudeStep} />
)} {/* ============== Altitude selector END ============== */} {/* ============== Airspeed selector START ============== */}
Speed {selectedUnitsData.desiredSpeed !== undefined ? selectedUnitsData.desiredSpeed + " KTS" : "Different values"}
{!(everyUnitIsGround || everyUnitIsNavy) && ( { selectedUnits.forEach((unit) => { unit.setSpeedType(selectedUnitsData.desiredSpeedType === "CAS" ? "GS" : "CAS"); setSelectedUnitsData({ ...selectedUnitsData, desiredSpeedType: selectedUnitsData.desiredSpeedType === "CAS" ? "GS" : "CAS", }); }); }} /> )}
{ selectedUnits.forEach((unit) => { unit.setSpeed(knotsToMs(Number(ev.target.value))); setSelectedUnitsData({ ...selectedUnitsData, desiredSpeed: Number(ev.target.value), }); }); }} value={selectedUnitsData.desiredSpeed} min={minSpeed} max={maxSpeed} step={speedStep} />
{/* ============== Airspeed selector END ============== */} {/* ============== Rules of Engagement START ============== */} {!(selectedUnits.length === 1 && selectedUnits[0].isTanker()) && !(selectedUnits.length === 1 && selectedUnits[0].isAWACS()) && (
Rules of engagement {[olButtonsRoeHold, olButtonsRoeReturn, olButtonsRoeDesignated, olButtonsRoeFree].map((icon, idx) => { return ( { selectedUnits.forEach((unit) => { unit.setROE(ROEs[idx]); setSelectedUnitsData({ ...selectedUnitsData, ROE: ROEs[idx], }); }); }} active={selectedUnitsData.ROE === ROEs[idx]} icon={icon} /> ); })}
)} {/* ============== Rules of Engagement END ============== */} {selectedCategories.every((category) => { return ["Aircraft", "Helicopter"].includes(category); }) && ( <> {/* ============== Threat Reaction START ============== */}
Threat reaction {[olButtonsThreatNone, olButtonsThreatPassive, olButtonsThreatManoeuvre, olButtonsThreatEvade].map((icon, idx) => { return ( { selectedUnits.forEach((unit) => { unit.setReactionToThreat(reactionsToThreat[idx]); setSelectedUnitsData({ ...selectedUnitsData, reactionToThreat: reactionsToThreat[idx], }); }); }} active={selectedUnitsData.reactionToThreat === reactionsToThreat[idx]} icon={icon} /> ); })}
{/* ============== Threat Reaction END ============== */} {/* ============== Radar and ECM START ============== */}
Radar and ECM {[olButtonsEmissionsSilent, olButtonsEmissionsDefend, olButtonsEmissionsAttack, olButtonsEmissionsFree].map((icon, idx) => { return ( { selectedUnits.forEach((unit) => { unit.setEmissionsCountermeasures(emissionsCountermeasures[idx]); setSelectedUnitsData({ ...selectedUnitsData, emissionsCountermeasures: emissionsCountermeasures[idx], }); }); }} active={selectedUnitsData.emissionsCountermeasures === emissionsCountermeasures[idx]} icon={icon} /> ); })}
{/* ============== Radar and ECM END ============== */} )} {/* ============== Tanker and AWACS available button START ============== */} {getApp() ?.getUnitsManager() ?.getSelectedUnitsVariable((unit) => { return unit.isTanker(); }) && (
Make tanker available { selectedUnits.forEach((unit) => { unit.setAdvancedOptions( !selectedUnitsData.isActiveTanker, unit.getIsActiveAWACS(), unit.getTACAN(), unit.getRadio(), unit.getGeneralSettings() ); setSelectedUnitsData({ ...selectedUnitsData, isActiveTanker: !selectedUnitsData.isActiveTanker, }); }); }} />
)} {getApp() ?.getUnitsManager() ?.getSelectedUnitsVariable((unit) => { return unit.isAWACS(); }) && (
Make AWACS available { selectedUnits.forEach((unit) => { unit.setAdvancedOptions( unit.getIsActiveTanker(), !selectedUnitsData.isActiveAWACS, unit.getTACAN(), unit.getRadio(), unit.getGeneralSettings() ); setSelectedUnitsData({ ...selectedUnitsData, isActiveAWACS: !selectedUnitsData.isActiveAWACS, }); }); }} />
)} {/* ============== Tanker and AWACS available button END ============== */} {/* ============== Advanced settings buttons START ============== */} {selectedUnits.length === 1 && (selectedUnits[0].isTanker() || selectedUnits[0].isAWACS()) && (
)} {/* ============== Advanced settings buttons END ============== */} {selectedCategories.every((category) => { return ["GroundUnit", "NavyUnit"].includes(category); }) && ( <>
{/* ============== Scenic AAA toggle START ============== */}
Scenic AAA mode { selectedUnits.forEach((unit) => { selectedUnitsData.scenicAAA ? unit.changeSpeed("stop") : unit.scenicAAA(); setSelectedUnitsData({ ...selectedUnitsData, scenicAAA: !selectedUnitsData.scenicAAA, missOnPurpose: false, }); }); }} />
{/* ============== Scenic AAA toggle END ============== */} {/* ============== Miss on purpose toggle START ============== */}
Miss on purpose mode { selectedUnits.forEach((unit) => { selectedUnitsData.missOnPurpose ? unit.changeSpeed("stop") : unit.missOnPurpose(); setSelectedUnitsData({ ...selectedUnitsData, scenicAAA: false, missOnPurpose: !selectedUnitsData.missOnPurpose, }); }); }} />
{/* ============== Miss on purpose toggle END ============== */}
{/* ============== Shots scatter START ============== */}
Shots scatter {[olButtonsScatter1, olButtonsScatter2, olButtonsScatter3].map((icon, idx) => { return ( { selectedUnits.forEach((unit) => { unit.setShotsScatter(idx + 1); setSelectedUnitsData({ ...selectedUnitsData, shotsScatter: idx + 1, }); }); }} active={selectedUnitsData.shotsScatter === idx + 1} icon={icon} /> ); })}
{/* ============== Shots scatter END ============== */} {/* ============== Shots intensity START ============== */}
Shots intensity {[olButtonsIntensity1, olButtonsIntensity2, olButtonsIntensity3].map((icon, idx) => { return ( { selectedUnits.forEach((unit) => { unit.setShotsIntensity(idx + 1); setSelectedUnitsData({ ...selectedUnitsData, shotsIntensity: idx + 1, }); }); }} active={selectedUnitsData.shotsIntensity === idx + 1} icon={icon} /> ); })}
{/* ============== Shots intensity END ============== */}
{/* ============== Operate as toggle START ============== */}
Operate as { selectedUnits.forEach((unit) => { unit.setOperateAs(selectedUnitsData.operateAs === "blue" ? "red" : "blue"); setSelectedUnitsData({ ...selectedUnitsData, operateAs: selectedUnitsData.operateAs === "blue" ? "red" : "blue", }); }); }} />
{/* ============== Operate as toggle END ============== */}
{/* ============== Follow roads toggle START ============== */}
Follow roads { selectedUnits.forEach((unit) => { unit.setFollowRoads(!selectedUnitsData.followRoads); setSelectedUnitsData({ ...selectedUnitsData, followRoads: !selectedUnitsData.followRoads, }); }); }} />
{/* ============== Follow roads toggle END ============== */} {/* ============== Unit active toggle START ============== */}
Unit active { selectedUnits.forEach((unit) => { unit.setOnOff(!selectedUnitsData.onOff); setSelectedUnitsData({ ...selectedUnitsData, onOff: !selectedUnitsData.onOff, }); }); }} />
{/* ============== Unit active toggle END ============== */} )} {/* ============== Audio sink toggle START ============== */}
Loudspeakers {audioManagerEnabled ? ( { selectedUnits.forEach((unit) => { if (!selectedUnitsData.isAudioSink) { getApp()?.getAudioManager().addUnitSink(unit); setSelectedUnitsData({ ...selectedUnitsData, isAudioSink: true, }); } else { let sink = getApp() ?.getAudioManager() .getSinks() .find((sink) => { return sink instanceof UnitSink && sink.getUnit() === unit; }); if (sink !== undefined) getApp()?.getAudioManager().removeSink(sink); setSelectedUnitsData({ ...selectedUnitsData, isAudioSink: false, }); } }); }} /> ) : (
Enable audio with{" "} {" "}first
)}
{/* ============== Audio sink toggle END ============== */}
)} {/* ============== Advanced settings START ============== */} {showAdvancedSettings && (
Advanced settings
Callsign
<> {selectedUnits[0].isAWACS() && ( <> {["Overlord", "Magic", "Wizard", "Focus", "Darkstar"].map((name, idx) => { return ( { if (activeAdvancedSettings) activeAdvancedSettings.radio.callsign = idx + 1; setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings))); }} > {name} ); })} )} <> {selectedUnits[0].isTanker() && ( <> {["Texaco", "Arco", "Shell"].map((name, idx) => { return ( { if (activeAdvancedSettings) activeAdvancedSettings.radio.callsign = idx + 1; setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings))); }} > {name} ); })} )}
-
{ if (activeAdvancedSettings) activeAdvancedSettings.radio.callsignNumber = Math.max(Math.min(Number(e.target.value), 9), 1); setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings))); }} onDecrease={() => { if (activeAdvancedSettings) activeAdvancedSettings.radio.callsignNumber = Math.max(Math.min(Number(activeAdvancedSettings.radio.callsignNumber - 1), 9), 1); setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings))); }} onIncrease={() => { if (activeAdvancedSettings) activeAdvancedSettings.radio.callsignNumber = Math.max(Math.min(Number(activeAdvancedSettings.radio.callsignNumber + 1), 9), 1); setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings))); }} value={activeAdvancedSettings ? activeAdvancedSettings.radio.callsignNumber : 1} >
TACAN
{ if (activeAdvancedSettings) activeAdvancedSettings.TACAN.channel = Math.max(Math.min(Number(e.target.value), 126), 1); setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings))); }} onDecrease={() => { if (activeAdvancedSettings) activeAdvancedSettings.TACAN.channel = Math.max(Math.min(Number(activeAdvancedSettings.TACAN.channel - 1), 126), 1); setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings))); }} onIncrease={() => { if (activeAdvancedSettings) activeAdvancedSettings.TACAN.channel = Math.max(Math.min(Number(activeAdvancedSettings.TACAN.channel + 1), 126), 1); setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings))); }} value={activeAdvancedSettings ? activeAdvancedSettings.TACAN.channel : 1} > { if (activeAdvancedSettings) activeAdvancedSettings.TACAN.XY = "X"; setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings))); }} > X { if (activeAdvancedSettings) activeAdvancedSettings.TACAN.XY = "Y"; setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings))); }} > Y { if (activeAdvancedSettings) { activeAdvancedSettings.TACAN.callsign = e.target.value; if (activeAdvancedSettings.TACAN.callsign.length > 3) activeAdvancedSettings.TACAN.callsign = activeAdvancedSettings.TACAN.callsign.slice(0, 3); } setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings))); }} />
Enabled{" "} { if (activeAdvancedSettings) activeAdvancedSettings.TACAN.isOn = !activeAdvancedSettings.TACAN.isOn; setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings))); }} />
Radio frequency
{ if (activeAdvancedSettings) { activeAdvancedSettings.radio.frequency = value; setActiveAdvancedSettings(JSON.parse(JSON.stringify(activeAdvancedSettings))); } }} />
)} {/* ============== Advanced settings END ============== */} {/* ============== Unit basic options END ============== */} <> {/* ============== Fuel/payload/radio section START ============== */} {selectedUnits.length === 1 && (
40 && `bg-green-700`} ${selectedUnits[0].getFuel() > 10 && selectedUnits[0].getFuel() <= 40 && ` bg-yellow-700 `} ${selectedUnits[0].getFuel() <= 10 && `bg-red-700`} px-2 py-1 text-sm font-bold text-white `} > {selectedUnits[0].getFuel()}%
{selectedUnits[0].isControlledByOlympus() && (selectedUnits[0].isTanker() || selectedUnits[0].isAWACS()) && ( <> {/* ============== Radio section START ============== */}
{`${selectedUnits[0].isTanker() ? ["Texaco", "Arco", "Shell"][selectedUnits[0].getRadio().callsign - 1] : ["Overlord", "Magic", "Wizard", "Focus", "Darkstar"][selectedUnits[0].getRadio().callsign - 1]}-${selectedUnits[0].getRadio().callsignNumber}`}
{`${(selectedUnits[0].getRadio().frequency / 1000000).toFixed(3)} MHz`}
{selectedUnits[0].getTACAN().isOn ? `${selectedUnits[0].getTACAN().channel}${selectedUnits[0].getTACAN().XY} ${selectedUnits[0].getTACAN().callsign}` : "TACAN OFF"}
{/* ============== Radio section END ============== */}
)} {/* ============== Payload section START ============== */} {!selectedUnits[0].isTanker() && !selectedUnits[0].isAWACS() && selectedUnits[0].getAmmo().map((ammo, idx) => { return (
{ammo.quantity}
{ammo.name}
); })} {/* ============== Payload section END ============== */}
)} {/* ============== Fuel/payload/radio section END ============== */} )} {/* ============== Unit control menu END ============== */}
); }