import React, { useEffect, useState } from "react"; import { Menu } from "./components/menu"; import { FaArrowDown, FaArrowUp, FaChevronRight, FaTrash } from "react-icons/fa"; import { getApp } from "../../olympusapp"; import { OlStateButton } from "../components/olstatebutton"; import { faDrawPolygon, faEye, faEyeSlash, faMapLocation } from "@fortawesome/free-solid-svg-icons"; import { faCircle } from "@fortawesome/free-regular-svg-icons"; import { CoalitionPolygon } from "../../map/coalitionarea/coalitionpolygon"; import { OlCoalitionToggle } from "../components/olcoalitiontoggle"; import { OlDropdown, OlDropdownItem } from "../components/oldropdown"; import { OlCheckbox } from "../components/olcheckbox"; import { Coalition } from "../../types/types"; import { OlRangeSlider } from "../components/olrangeslider"; import { CoalitionCircle } from "../../map/coalitionarea/coalitioncircle"; import { DrawSubState, ERAS_ORDER, IADSTypes, NO_SUBSTATE, OlympusState, OlympusSubState } from "../../constants/constants"; import { AppStateChangedEvent, CoalitionAreasChangedEvent, CoalitionAreaSelectedEvent, DrawingsInitEvent, DrawingsUpdatedEvent } from "../../events"; import { FaCopy, FaPencil, FaRegCompass, FaXmark } from "react-icons/fa6"; import { deepCopyTable } from "../../other/utils"; import { DCSDrawing, DCSDrawingsContainer, DCSEmptyLayer } from "../../map/drawings/drawingsmanager"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { OlSearchBar } from "../components/olsearchbar"; export function DrawingMenu(props: { open: boolean; onClose: () => void }) { const [appState, setAppState] = useState(OlympusState.NOT_INITIALIZED); const [appSubState, setAppSubState] = useState(NO_SUBSTATE as OlympusSubState); const [activeCoalitionArea, setActiveCoalitionArea] = useState(null as null | CoalitionPolygon | CoalitionCircle); const [coalitionAreas, setCoalitionAreas] = useState([] as (CoalitionPolygon | CoalitionCircle)[]); const [IADSDensity, setIADSDensity] = useState(50); const [IADSDistribution, setIADSDistribution] = useState(50); const [forceCoalitionAppropriateUnits, setForceCoalitionApproriateUnits] = useState(false); const [typesSelection, setTypesSelection] = useState({}); const [erasSelection, setErasSelection] = useState({}); const [rangesSelection, setRangesSelection] = useState({}); const [openContainers, setOpenContainers] = useState([] as DCSDrawingsContainer[]); const [mainDrawingsContainer, setDrawingsContainer] = useState({ container: null } as { container: null | DCSDrawingsContainer }); const [navpointsContainer, setNavpointsContainer] = useState({ container: null } as { container: null | DCSDrawingsContainer }); const [searchString, setSearchString] = useState(""); const [navpointSearchString, setNavpointSearchString] = useState(""); useEffect(() => { AppStateChangedEvent.on((state, subState) => { setAppState(state); setAppSubState(subState); }); DrawingsInitEvent.on((drawingContainer, navpointsContainer) => { setDrawingsContainer({ container: drawingContainer }); setNavpointsContainer({ container: navpointsContainer }); }); DrawingsUpdatedEvent.on(() => { setDrawingsContainer({ container: getApp().getDrawingsManager().getDrawingsContainer() }); setNavpointsContainer({ container: getApp().getDrawingsManager().getNavpointsContainer() }); }); }, []); /* Get all the unique types and eras for groundunits */ let types = IADSTypes; let eras = getApp() ?.getUnitsManager() .getDatabase() .getEras() .sort((era1, era2) => (ERAS_ORDER[era1] > ERAS_ORDER[era2] ? 1 : -1)); useEffect(() => { CoalitionAreaSelectedEvent.on((coalitionArea) => setActiveCoalitionArea(coalitionArea)); CoalitionAreasChangedEvent.on((coalitionAreas) => setCoalitionAreas([...coalitionAreas])); }, []); function getDrawingLabelColor(drawing: DCSDrawingsContainer | DCSDrawing) { return drawing.getVisibility() ? `text-gray-200` : `text-gray-600`; } function renderDrawingsContainerControls(container: DCSDrawingsContainer, containerSearchString: string) { if (container.hasSearchString(containerSearchString)) { /* The following snippet automatically open containers that contains searched drawings */ if (!openContainers.includes(container) && containerSearchString != "") { openContainers.push(container); setOpenContainers([...openContainers]); } return (
{ if (openContainers.includes(container)) { let index = openContainers.indexOf(container); openContainers.splice(index, 1); } else { openContainers.push(container); } setOpenContainers([...openContainers]); }} > { if (container === mainDrawingsContainer.container) { getApp().getMap().setOption("showMissionDrawings", !getApp().getMap().getOptions().showMissionDrawings); } else { container.setVisibility(!container.getVisibility(), true); } }} />
{container.getName()}
{ container.setOpacity(Number(ev.currentTarget.value) / 100); }} className={`my-auto ml-auto max-w-32`} >
{openContainers.includes(container) && container.getSubContainers().map((container) => renderDrawingsContainerControls(container, containerSearchString))} {openContainers.includes(container) && container.getDrawings().map((drawing, index) => { if (drawing instanceof DCSEmptyLayer) return <>; if (!drawing.getName().toLowerCase().includes(containerSearchString.toLowerCase())) return <>; return (
{ drawing.setVisibility(!drawing.getVisibility()); }} />
{drawing.getName()}
{ const latLng = drawing.getLayer()["getLatLng"] && drawing.getLayer()["getLatLng"](); const bounds = drawing.getLayer()["getBounds"] && drawing.getLayer()["getBounds"](); latLng && getApp().getMap().setView(latLng, 14); bounds && getApp().getMap().fitBounds(bounds); }} />
); })}
); } else { return <>; } } return ( { getApp().getCoalitionAreasManager().setSelectedArea(null); getApp().setState(OlympusState.DRAW, DrawSubState.NO_SUBSTATE); }} wiki={() => { return (

Drawing menu

The drawing menu allows you to create and manage custom drawings, such as polygons and circles, and to generate IADS (Integrated Air Defense System) areas. Moreover, you can manage the visibility and opacity of mission drawings, i.e. drawings from the Mission Editor.

Custom drawings and IADS

To create a custom drawing, click on the 'Add polygon' or 'Add circle' buttons, then click on the map to add polygons or to move the drawing. Double-click on the map to finish your creation. You can then edit the drawing by clicking on it. You can also move it up or down in the list, or delete it.
You can change the name and the coalition of the area. You can also generate an IADS area by selecting the types, eras, and ranges of units you want to include in the area. You can also set the density and distribution of the IADS. If you check the 'Force coalition appropriate units' box, the IADS will only include units that are appropriate for the coalition of the area (e.g. Hawk SAMs for {""} blue and SA-6 SAMs for red ).
The IADS generator will create a random distribution of units in the area, based on the density and distribution you set. Units will be concentrated around cities, and airbases that belong to the selected coalition.

Mission drawings

You can manage the visibility and opacity of mission drawings by clicking on the eye icon. Moreover, you can change the opacity of the drawing by using the slider. You can also hide or show all the drawings in a container.
You can search for a specific drawing by typing in the search bar. The search is case-insensitive and will match any part of the drawing name.
Any change you make is persistent and will be saved for the next time you reload Olympus, as long as the DCS mission was not restarted.
); }} > <> {appState === OlympusState.DRAW && appSubState === DrawSubState.NO_SUBSTATE && (
{coalitionAreas.map((coalitionArea) => { return (
{ coalitionArea.setSelected(true); getApp().setState(OlympusState.DRAW, DrawSubState.EDIT); }} >
{coalitionArea.getLabelText()}
{ ev.stopPropagation(); getApp().getCoalitionAreasManager().moveAreaUp(coalitionArea); }} className={` my-auto ml-auto rounded-md p-2 text-3xl hover:bg-white/10 `} /> { ev.stopPropagation(); getApp().getCoalitionAreasManager().moveCoalitionAreaDown(coalitionArea); }} className={` my-auto rounded-md p-2 text-3xl hover:bg-white/10 `} /> { ev.stopPropagation(); getApp().getCoalitionAreasManager().deleteCoalitionArea(coalitionArea); }} className={` my-auto rounded-md p-2 text-3xl hover:bg-red-500/50 `} />
); })}
getApp().setState(OlympusState.DRAW, DrawSubState.DRAW_POLYGON)} >
Add polygon
getApp().setState(OlympusState.DRAW, DrawSubState.DRAW_CIRCLE)}>
Add circle
Mission drawings
{ setSearchString(search); if (search === "") { setOpenContainers([]); } }} text={searchString || ""} >
{mainDrawingsContainer.container && renderDrawingsContainerControls(mainDrawingsContainer.container, searchString)}
Navpoints
{ setNavpointSearchString(search); if (search === "") { setOpenContainers([]); } }} text={navpointSearchString || ""} >
{navpointsContainer.container && renderDrawingsContainerControls(navpointsContainer.container, navpointSearchString)}
)}
{activeCoalitionArea !== null && (
Area label
{ getApp().getCoalitionAreasManager().deleteCoalitionArea(activeCoalitionArea); getApp().setState(OlympusState.DRAW); setActiveCoalitionArea(null); }} >
activeCoalitionArea.setLabelText(ev.currentTarget.value)} >
Coalition:
{ let newCoalition = ""; if (activeCoalitionArea.getCoalition() === "blue") newCoalition = "neutral"; else if (activeCoalitionArea.getCoalition() === "neutral") newCoalition = "red"; else if (activeCoalitionArea.getCoalition() === "red") newCoalition = "blue"; activeCoalitionArea.setCoalition(newCoalition as Coalition); }} >
Automatic IADS generation
{types.map((type, idx) => { if (!(type in typesSelection)) { typesSelection[type] = true; setTypesSelection(deepCopyTable(typesSelection)); } return ( { typesSelection[type] = ev.currentTarget.checked; setTypesSelection(deepCopyTable(typesSelection)); }} />
{type}
); })}
{eras.map((era) => { if (!(era in erasSelection)) { erasSelection[era] = true; setErasSelection(deepCopyTable(erasSelection)); } return ( { erasSelection[era] = ev.currentTarget.checked; setErasSelection(deepCopyTable(erasSelection)); }} />
{era}
); })}
{["Short range", "Medium range", "Long range"].map((range) => { if (!(range in rangesSelection)) { rangesSelection[range] = true; setRangesSelection(deepCopyTable(rangesSelection)); } return ( { rangesSelection[range] = ev.currentTarget.checked; setErasSelection(deepCopyTable(rangesSelection)); }} />
{range}
); })}
IADS Density
{IADSDensity}%
{ setIADSDensity(Number(ev.currentTarget.value)); }} >
IADS Distribution
{IADSDistribution}%
{ setIADSDistribution(Number(ev.target.value)); }} >
{ setForceCoalitionApproriateUnits(!forceCoalitionAppropriateUnits); }} /> Force coalition appropriate units
)}
); }