diff --git a/client/public/stylesheets/other/contextmenus.css b/client/public/stylesheets/other/contextmenus.css index 561239cf..b6a39d96 100644 --- a/client/public/stylesheets/other/contextmenus.css +++ b/client/public/stylesheets/other/contextmenus.css @@ -30,6 +30,11 @@ flex-direction: column; justify-content: space-between; row-gap: 5px; + padding: 20px; +} + +#map-contextmenu>div:nth-child(n+4)>div { + width: 100%; } .contextmenu-advanced-options { @@ -192,8 +197,7 @@ content: "Create neutral unit"; } -#aircraft-loadout-preview, -#helicopter-loadout-preview { +.unit-loadout-preview { align-content: space-between; align-items: center; column-gap: 10px; @@ -202,16 +206,14 @@ width: 100%; } -#aircaft-loadout-list, -#helicopter-loadout-list { +.unit-loadout-list { align-content: center; display: flex; flex-direction: column; height: 100%; } -#aircraft-unit-image, -#helicopter-unit-image { +.unit-image { filter: invert(100%); width: 25%; margin-bottom: 10px; diff --git a/client/public/stylesheets/style/style.css b/client/public/stylesheets/style/style.css index c73088e1..16bbd7a6 100644 --- a/client/public/stylesheets/style/style.css +++ b/client/public/stylesheets/style/style.css @@ -1304,10 +1304,6 @@ input[type=number]::-webkit-outer-spin-button { transform: translateX(calc((var(--width) - var(--height)) * 0.5)); } -.ol-contexmenu-panel { - padding: 20px; -} - .ol-coalition-switch[data-value="false"]>.ol-switch-fill { background-color: var(--primary-blue); } diff --git a/client/src/controls/dropdown.ts b/client/src/controls/dropdown.ts index 1501a9d1..10d0837d 100644 --- a/client/src/controls/dropdown.ts +++ b/client/src/controls/dropdown.ts @@ -7,10 +7,14 @@ export class Dropdown { #optionsList: string[] = []; #index: number = 0; - constructor(ID: string, callback: CallableFunction, options: string[] | null = null) { - this.#element = document.getElementById(ID); - this.#options = this.#element.querySelector(".ol-select-options"); - this.#value = this.#element.querySelector(".ol-select-value"); + constructor(element: string | HTMLElement, callback: CallableFunction, options: string[] | null = null) { + if (typeof element === 'string') + this.#element = document.getElementById(element) as HTMLElement; + else + this.#element = element; + + this.#options = this.#element.querySelector(".ol-select-options") as HTMLElement; + this.#value = this.#element.querySelector(".ol-select-value") as HTMLElement; this.#defaultValue = this.#value.innerText; this.#callback = callback; @@ -18,9 +22,7 @@ export class Dropdown { this.setOptions(options); } - this.#value.addEventListener("click", (ev) => { - this.#toggle(); - }); + this.#value.addEventListener("click", (ev) => { this.#toggle(); }); document.addEventListener("click", (ev) => { if (!(this.#value.contains(ev.target as Node) || this.#options.contains(ev.target as Node) || this.#element.contains(ev.target as Node))) { diff --git a/client/src/controls/mapcontextmenu.ts b/client/src/controls/mapcontextmenu.ts index 45491409..92ec77ac 100644 --- a/client/src/controls/mapcontextmenu.ts +++ b/client/src/controls/mapcontextmenu.ts @@ -12,38 +12,14 @@ import { ftToM } from "../other/utils"; import { GAME_MASTER } from "../constants/constants"; import { navyUnitDatabase } from "../unit/navyunitdatabase"; import { CoalitionArea } from "../map/coalitionarea"; +import { UnitSpawnMenu } from "./unitspawnmenu"; export class MapContextMenu extends ContextMenu { #coalitionSwitch: Switch; + #aircraftSpawnMenu: UnitSpawnMenu; - #aircraftCountryDropdown: Dropdown; - #aircraftRoleDropdown: Dropdown; - #aircraftLabelDropdown: Dropdown; - #aircraftCountDropdown: Dropdown; - #aircraftLoadoutDropdown: Dropdown; - #aircraftLiveryDropdown: Dropdown; - #aircraftSpawnAltitudeSlider: Slider; - - #helicopterCountryDropdown: Dropdown; - #helicopterRoleDropdown: Dropdown; - #helicopterLabelDropdown: Dropdown; - #helicopterCountDropdown: Dropdown; - #helicopterLoadoutDropdown: Dropdown; - #helicopterLiveryDropdown: Dropdown; - #helicopterSpawnAltitudeSlider: Slider; - - #groundUnitTypeDropdown: Dropdown; - #groundUnitLabelDropdown: Dropdown; - #groundUnitCountDropdown: Dropdown; - - #navyUnitTypeDropdown: Dropdown; - #navyUnitLabelDropdown: Dropdown; - #navyUnitCountDropdown: Dropdown; - - #spawnOptions = { role: "", name: "", latlng: new LatLng(0, 0), coalition: "blue", loadout: "", airbaseName: "", liveryID: "", altitude: 0, count: 1, country: "" }; #coalitionArea: CoalitionArea | null = null; - #countryCodes: any; - + constructor(id: string) { super(id); @@ -51,50 +27,7 @@ export class MapContextMenu extends ContextMenu { this.#coalitionSwitch.setValue(false); this.#coalitionSwitch.getContainer()?.addEventListener("contextmenu", (e) => this.#onSwitchRightClick(e)); - var count = []; - for (let i = 1; i < 10; i++) count.push(String(i)); - - /* Aircraft menu */ - this.#aircraftCountryDropdown = new Dropdown("aircraft-country-options", () => { /* Custom button implementation */ }); - this.#aircraftRoleDropdown = new Dropdown("aircraft-role-options", (role: string) => this.#setAircraftRole(role)); - this.#aircraftLabelDropdown = new Dropdown("aircraft-label-options", (type: string) => this.#setAircraftLabel(type)); - this.#aircraftCountDropdown = new Dropdown("aircraft-count-options", (count: string) => this.#setAircraftCount(count)); - this.#aircraftCountDropdown.setOptions(["1", "2", "3", "4"]); - this.#aircraftCountDropdown.setValue("1"); - this.#aircraftLoadoutDropdown = new Dropdown("aircraft-loadout-options", (loadout: string) => this.#setAircraftLoadout(loadout)); - this.#aircraftLiveryDropdown = new Dropdown("aircraft-livery-options", (livery: string) => this.#setAircraftLivery(livery)); - this.#aircraftSpawnAltitudeSlider = new Slider("aircraft-spawn-altitude-slider", 0, 50000, "ft", (value: number) => {this.#spawnOptions.altitude = ftToM(value);}); - this.#aircraftSpawnAltitudeSlider.setIncrement(500); - this.#aircraftSpawnAltitudeSlider.setValue(20000); - this.#aircraftSpawnAltitudeSlider.setActive(true); - - /* Helicopter menu */ - this.#helicopterCountryDropdown = new Dropdown("helicopter-country-options", (country: string) => this.#setHelicopterCountry(country)); - this.#helicopterRoleDropdown = new Dropdown("helicopter-role-options", (role: string) => this.#setHelicopterRole(role)); - this.#helicopterLabelDropdown = new Dropdown("helicopter-label-options", (type: string) => this.#setHelicopterLabel(type)); - this.#helicopterCountDropdown = new Dropdown("helicopter-count-options", (count: string) => this.#setHelicopterCount(count)); - this.#helicopterCountDropdown.setOptions(["1", "2", "3", "4"]); - this.#helicopterCountDropdown.setValue("1"); - this.#helicopterLoadoutDropdown = new Dropdown("helicopter-loadout-options", (loadout: string) => this.#setHelicopterLoadout(loadout)); - this.#helicopterLiveryDropdown = new Dropdown("helicopter-livery-options", (livery: string) => this.#setHelicopterLivery(livery)); - this.#helicopterSpawnAltitudeSlider = new Slider("helicopter-spawn-altitude-slider", 0, 10000, "ft", (value: number) => {this.#spawnOptions.altitude = ftToM(value);}); - this.#helicopterSpawnAltitudeSlider.setIncrement(50); - this.#helicopterSpawnAltitudeSlider.setValue(5000); - this.#helicopterSpawnAltitudeSlider.setActive(true); - - /* Ground unit menu */ - this.#groundUnitTypeDropdown = new Dropdown("groundunit-type-options", (type: string) => this.#setGroundUnitType(type)); - this.#groundUnitLabelDropdown = new Dropdown("groundunit-label-options", (name: string) => this.#setGroundUnitLabel(name)); - this.#groundUnitCountDropdown = new Dropdown("groundunit-count-options", (count: string) => this.#setGroundUnitCount(count)); - this.#groundUnitCountDropdown.setOptions(count); - this.#groundUnitCountDropdown.setValue("1"); - - /* Navy unit menu */ - this.#navyUnitTypeDropdown = new Dropdown("navyunit-type-options", (type: string) => this.#setNavyUnitType(type)); - this.#navyUnitLabelDropdown = new Dropdown("navyunit-label-options", (name: string) => this.#setNavyUnitLabel(name)); - this.#navyUnitCountDropdown = new Dropdown("navyunit-count-options", (count: string) => this.#setNavyUnitCount(count)); - this.#navyUnitCountDropdown.setOptions(count); - this.#navyUnitCountDropdown.setValue("1"); + this.#aircraftSpawnMenu = new UnitSpawnMenu("aircraft-spawn-menu", aircraftDatabase); document.addEventListener("mapContextMenuShow", (e: any) => { if (this.getVisibleSubMenu() !== e.detail.type) @@ -104,85 +37,19 @@ export class MapContextMenu extends ContextMenu { }); document.addEventListener("contextMenuDeployAircrafts", () => { - this.#spawnOptions.coalition = getActiveCoalition(); - if (this.#spawnOptions) { - var unitTable = { - unitType: this.#spawnOptions.name, - location: this.#spawnOptions.latlng, - altitude: this.#spawnOptions.altitude, - loadout: this.#spawnOptions.loadout, - liveryID: this.#spawnOptions.liveryID - }; - var units = []; - for (let i = 1; i < parseInt(this.#aircraftCountDropdown.getValue()) + 1; i++) { - units.push(unitTable); - } - if (getUnitsManager().spawnUnits("Aircraft", units, getActiveCoalition(), false, this.#spawnOptions.airbaseName, this.#spawnOptions.country)) { - getMap().addTemporaryMarker(this.#spawnOptions.latlng, this.#spawnOptions.name, getActiveCoalition()); - this.hide(); - } - } + }); document.addEventListener("contextMenuDeployHelicopters", () => { - this.#spawnOptions.coalition = getActiveCoalition(); - if (this.#spawnOptions) { - var unitTable = { - unitType: this.#spawnOptions.name, - location: this.#spawnOptions.latlng, - altitude: this.#spawnOptions.altitude, - loadout: this.#spawnOptions.loadout, - liveryID: this.#spawnOptions.liveryID - }; - var units = []; - for (let i = 1; i < parseInt(this.#helicopterCountDropdown.getValue()) + 1; i++) { - units.push(unitTable); - } - if (getUnitsManager().spawnUnits("Helicopter", units, getActiveCoalition(), false, this.#spawnOptions.airbaseName, this.#spawnOptions.country)) { - getMap().addTemporaryMarker(this.#spawnOptions.latlng, this.#spawnOptions.name, getActiveCoalition()); - this.hide(); - } - } + }); document.addEventListener("contextMenuDeployGroundUnits", () => { - this.#spawnOptions.coalition = getActiveCoalition(); - if (this.#spawnOptions) { - var unitTable = { - unitType: this.#spawnOptions.name, - location: this.#spawnOptions.latlng, - liveryID: this.#spawnOptions.liveryID - }; - var units = []; - for (let i = 1; i < parseInt(this.#groundUnitCountDropdown.getValue()) + 1; i++) { - units.push(JSON.parse(JSON.stringify(unitTable))); - unitTable.location.lat += 0.0001; - } - if (getUnitsManager().spawnUnits("GroundUnit", units, getActiveCoalition(), false)) { - getMap().addTemporaryMarker(this.#spawnOptions.latlng, this.#spawnOptions.name, getActiveCoalition()); - this.hide(); - } - } + }); document.addEventListener("contextMenuDeployNavyUnits", () => { - this.#spawnOptions.coalition = getActiveCoalition(); - if (this.#spawnOptions) { - var unitTable = { - unitType: this.#spawnOptions.name, - location: this.#spawnOptions.latlng, - liveryID: this.#spawnOptions.liveryID - }; - var units = []; - for (let i = 1; i < parseInt(this.#navyUnitCountDropdown.getValue()) + 1; i++) { - units.push(JSON.parse(JSON.stringify(unitTable))); - unitTable.location.lat += 0.0001; - } - if (getUnitsManager().spawnUnits("NavyUnit", units, getActiveCoalition(), false)) { - getMap().addTemporaryMarker(this.#spawnOptions.latlng, this.#spawnOptions.name, getActiveCoalition()); - this.hide(); - } - } + }); document.addEventListener("contextMenuDeploySmoke", (e: any) => { @@ -204,7 +71,7 @@ export class MapContextMenu extends ContextMenu { }); document.addEventListener("commandModeOptionsChanged", (e: any) => { - this.#refreshOptions(); + //this.#refreshOptions(); }); document.addEventListener("toggleAdvancedOptions", (e: any) => { @@ -215,19 +82,6 @@ export class MapContextMenu extends ContextMenu { this.clip(); }); - /* Load the country codes from the public folder */ - var xhr = new XMLHttpRequest(); - xhr.open('GET', 'images/countries/codes.json', true); - xhr.responseType = 'json'; - xhr.onload = () => { - var status = xhr.status; - if (status === 200) { - this.#countryCodes = xhr.response; - } else { - console.error(`Error retrieving country codes`) - } - }; - xhr.send(); this.hide(); } @@ -238,8 +92,8 @@ export class MapContextMenu extends ContextMenu { this.showAltitudeSlider(); - this.#spawnOptions.airbaseName = ""; - this.#spawnOptions.latlng = latlng; + //this.#spawnOptions.airbaseName = ""; + //this.#spawnOptions.latlng = latlng; this.getContainer()?.querySelectorAll('[data-coalition]').forEach((element: any) => { element.setAttribute("data-coalition", getActiveCoalition()) }); if (getActiveCoalition() == "blue") @@ -254,7 +108,7 @@ export class MapContextMenu extends ContextMenu { this.getContainer()?.querySelector("#coalition-area-button")?.classList.toggle("hide", true); - this.#setCountries(); + //this.#setCountries(); } showSubMenu(type: string) { @@ -278,25 +132,18 @@ export class MapContextMenu extends ContextMenu { (this.getContainer()?.querySelectorAll(".deploy-unit-button"))?.forEach((element: Node) => {(element as HTMLButtonElement).disabled = true;}) - this.#resetAircraftRole(); - this.#resetAircraftLabel(); - this.#resetHelicopterRole(); - this.#resetHelicopterLabel(); - this.#resetGroundUnitType(); - this.#resetGroundUnitLabel(); - this.#resetNavyUnitType(); - this.#resetNavyUnitLabel(); - this.#aircraftCountDropdown.setValue("1"); - this.#helicopterCountDropdown.setValue("1"); - this.#groundUnitCountDropdown.setValue("1"); + this.#aircraftSpawnMenu.resetUnitRole(); + this.#aircraftSpawnMenu.resetUnitLabel(); + this.#aircraftSpawnMenu.setCountries(); + this.clip(); - if (type === "aircraft") { - this.#spawnOptions.altitude = ftToM(this.#aircraftSpawnAltitudeSlider.getValue()); - } - else if (type === "helicopter") { - this.#spawnOptions.altitude = ftToM(this.#helicopterSpawnAltitudeSlider.getValue()); - } + //if (type === "aircraft") { + // this.#spawnOptions.altitude = ftToM(this.#aircraftSpawnAltitudeSlider.getValue()); + //} + //else if (type === "helicopter") { + // this.#spawnOptions.altitude = ftToM(this.#helicopterSpawnAltitudeSlider.getValue()); + //} this.setVisibleSubMenu(type); } @@ -316,16 +163,9 @@ export class MapContextMenu extends ContextMenu { this.getContainer()?.querySelector("#explosion-menu")?.classList.toggle("hide", true); this.getContainer()?.querySelector("#explosion-spawn-button")?.classList.toggle("is-open", false); - this.#resetAircraftRole(); - this.#resetAircraftLabel(); - this.#resetHelicopterRole(); - this.#resetHelicopterLabel(); - this.#resetHelicopterRole(); - this.#resetHelicopterLabel(); - this.#resetGroundUnitType(); - this.#resetGroundUnitLabel(); - this.#resetNavyUnitType(); - this.#resetNavyUnitLabel(); + this.#aircraftSpawnMenu.resetUnitRole(); + this.#aircraftSpawnMenu.resetUnitLabel(); + this.clip(); this.setVisibleSubMenu(null); @@ -356,11 +196,11 @@ export class MapContextMenu extends ContextMenu { } setAirbaseName(airbaseName: string) { - this.#spawnOptions.airbaseName = airbaseName; + //this.#spawnOptions.airbaseName = airbaseName; } setLatLng(latlng: LatLng) { - this.#spawnOptions.latlng = latlng; + //this.#spawnOptions.latlng = latlng; } setCoalitionArea(coalitionArea: CoalitionArea) { @@ -368,382 +208,16 @@ export class MapContextMenu extends ContextMenu { this.getContainer()?.querySelector("#coalition-area-button")?.classList.toggle("hide", false); } - #setCountries() { - var coalitions = getMissionHandler().getCoalitions(); - var countries = Object.values(coalitions[getActiveCoalition() as keyof typeof coalitions]); - this.#aircraftCountryDropdown.setOptionsElements(this.#createCountryButtons(this.#aircraftCountryDropdown, countries, (country: string) => {this.#setAircraftCountry(country)})); - this.#helicopterCountryDropdown.setOptionsElements(this.#createCountryButtons(this.#helicopterCountryDropdown, countries, (country: string) => {this.#setHelicopterCountry(country)})); - - if (countries.length > 0 && !countries.includes(this.#spawnOptions.country)) { - this.#aircraftCountryDropdown.forceValue(countries[0]); - this.#setAircraftCountry(countries[0]); - this.#helicopterCountryDropdown.forceValue(countries[0]); - this.#setHelicopterCountry(countries[0]); - } - } - - #createCountryButtons(parent: Dropdown, countries: string[], callback: CallableFunction) { - return Object.values(countries).map((country: string) => { - var el = document.createElement("div"); - - var formattedCountry = ""; - if (this.#countryCodes[country] !== undefined && this.#countryCodes[country].displayName !== undefined) - formattedCountry = this.#countryCodes[country].displayName; - else - formattedCountry = country.charAt(0).toUpperCase() + country.slice(1).toLowerCase(); - - var button = document.createElement("button"); - button.classList.add("country-dropdown-element"); - el.appendChild(button); - button.addEventListener("click", () => { - callback(country); - parent.forceValue(formattedCountry); - parent.close(); - }); - - if (this.#countryCodes[country] !== undefined) { - var code = this.#countryCodes[country].flagCode; - if (code !== undefined) { - var img = document.createElement("img"); - img.src = `images/countries/${code.toLowerCase()}.svg`; - button.appendChild(img); - } - } - else { - console.log("Unknown country " + country); - } - - var text = document.createElement("div"); - text.innerText = formattedCountry; - - button.appendChild(text); - return el; - }); - } - #onSwitchClick(value: boolean) { value? setActiveCoalition("red"): setActiveCoalition("blue"); this.getContainer()?.querySelectorAll('[data-coalition]').forEach((element: any) => { element.setAttribute("data-coalition", getActiveCoalition()) }); - this.#setCountries(); + //this.#setCountries(); } #onSwitchRightClick(e: any) { this.#coalitionSwitch.setValue(undefined); setActiveCoalition("neutral"); this.getContainer()?.querySelectorAll('[data-coalition]').forEach((element: any) => { element.setAttribute("data-coalition", getActiveCoalition()) }); - this.#setCountries(); - } - - #refreshOptions() { - if (!aircraftDatabase.getRoles().includes(this.#aircraftRoleDropdown.getValue())) - this.#resetAircraftRole(); - if (!aircraftDatabase.getByRole(this.#aircraftRoleDropdown.getValue()).map((blueprint) => { return blueprint.label }).includes(this.#aircraftLabelDropdown.getValue())) - this.#resetAircraftLabel(); - - if (!helicopterDatabase.getRoles().includes(this.#helicopterRoleDropdown.getValue())) - this.#resetHelicopterRole(); - if (!helicopterDatabase.getByRole(this.#helicopterRoleDropdown.getValue()).map((blueprint) => { return blueprint.label }).includes(this.#helicopterLabelDropdown.getValue())) - this.#resetHelicopterLabel(); - - if (!groundUnitDatabase.getRoles().includes(this.#groundUnitTypeDropdown.getValue())) - this.#resetGroundUnitType(); - if (!groundUnitDatabase.getByType(this.#groundUnitTypeDropdown.getValue()).map((blueprint) => { return blueprint.label }).includes(this.#groundUnitLabelDropdown.getValue())) - this.#resetGroundUnitLabel(); - - if (!navyUnitDatabase.getRoles().includes(this.#navyUnitTypeDropdown.getValue())) - this.#resetNavyUnitType(); - if (!navyUnitDatabase.getByType(this.#navyUnitTypeDropdown.getValue()).map((blueprint) => { return blueprint.label }).includes(this.#aircraftLabelDropdown.getValue())) - this.#resetNavyUnitLabel(); - } - - /********* Aircraft spawn menu *********/ - #setAircraftRole(role: string) { - this.#spawnOptions.role = role; - this.#resetAircraftLabel(); - this.#aircraftLabelDropdown.setOptions(aircraftDatabase.getByRole(role).map((blueprint) => { return blueprint.label })); - this.#aircraftLabelDropdown.selectValue(0); - this.clip(); - this.#computeSpawnPoints(); - } - - #resetAircraftRole() { - (this.getContainer()?.querySelector("#aircraft-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = true; - (this.getContainer()?.querySelector("#aircraft-loadout-list")).replaceChildren(); - this.#aircraftRoleDropdown.reset(); - this.#aircraftLabelDropdown.reset(); - this.#aircraftRoleDropdown.setOptions(aircraftDatabase.getRoles()); - this.clip(); - } - - #setAircraftLabel(label: string) { - this.#resetAircraftLabel(); - var name = aircraftDatabase.getByLabel(label)?.name || null; - if (name != null) { - this.#spawnOptions.name = name; - this.#aircraftLoadoutDropdown.setOptions(aircraftDatabase.getLoadoutNamesByRole(name, this.#spawnOptions.role)); - this.#aircraftLoadoutDropdown.selectValue(0); - var image = (this.getContainer()?.querySelector("#aircraft-unit-image")); - image.src = `images/units/${aircraftDatabase.getByLabel(label)?.filename}`; - image.classList.toggle("hide", false); - - this.#setAircraftLiveryOptions(); - } - this.clip(); - this.#computeSpawnPoints(); - } - - #resetAircraftLabel() { - (this.getContainer()?.querySelector("#aircraft-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = true; - (this.getContainer()?.querySelector("#aircraft-loadout-list")).replaceChildren(); - this.#aircraftLoadoutDropdown.reset(); - this.#aircraftLiveryDropdown.reset(); - (this.getContainer()?.querySelector("#aircraft-unit-image")).classList.toggle("hide", true); - this.clip(); - } - - #setAircraftCount(count: string) { - this.#spawnOptions.count = parseInt(count); - this.clip(); - this.#computeSpawnPoints(); - } - - #setAircraftLoadout(loadoutName: string) { - var loadout = aircraftDatabase.getLoadoutByName(this.#spawnOptions.name, loadoutName); - if (loadout) { - this.#spawnOptions.loadout = loadout.code; - (this.getContainer()?.querySelector("#aircraft-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = false; - var items = loadout.items.map((item: any) => { return `${item.quantity}x ${item.name}`; }); - items.length == 0 ? items.push("Empty loadout") : ""; - (this.getContainer()?.querySelector("#aircraft-loadout-list")).replaceChildren( - ...items.map((item: any) => { - var div = document.createElement('div'); - div.innerText = item; - return div; - }) - ) - } - this.clip(); - } - - #setAircraftLivery(liveryName: string) { - var liveries = aircraftDatabase.getByName(this.#spawnOptions.name)?.liveries; - if (liveries !== undefined) { - for (let liveryID in liveries) - if (liveries[liveryID].name === liveryName) - this.#spawnOptions.liveryID = liveryID; - } - this.clip(); - } - - #setAircraftCountry(country: string) { - this.#spawnOptions.country = country; - this.#setAircraftLiveryOptions(); - } - - #setAircraftLiveryOptions() { - if (this.#spawnOptions.name !== "" && this.#spawnOptions.country !== "") { - var liveries = aircraftDatabase.getLiveryNamesByName(this.#spawnOptions.name); - var countryLiveries: string[] = ["Default"]; - liveries.forEach((livery: any) => { - var nationLiveryCodes = this.#countryCodes[this.#spawnOptions.country].liveryCodes; - if (livery.countries.some((country: string) => {return nationLiveryCodes.includes(country)})) - countryLiveries.push(livery.name); - }); - this.#aircraftLiveryDropdown.setOptions(countryLiveries); - this.#aircraftLiveryDropdown.selectValue(0); - } - } - - /********* Helicopter spawn menu *********/ - #setHelicopterRole(role: string) { - this.#spawnOptions.role = role; - this.#resetHelicopterLabel(); - this.#helicopterLabelDropdown.setOptions(helicopterDatabase.getByRole(role).map((blueprint) => { return blueprint.label })); - this.#helicopterLabelDropdown.selectValue(0); - this.clip(); - this.#computeSpawnPoints(); - } - - #resetHelicopterRole() { - (this.getContainer()?.querySelector("#helicopter-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = true; - (this.getContainer()?.querySelector("#helicopter-loadout-list")).replaceChildren(); - this.#helicopterRoleDropdown.reset(); - this.#helicopterLabelDropdown.reset(); - this.#helicopterRoleDropdown.setOptions(helicopterDatabase.getRoles()); - this.clip(); - } - - #setHelicopterLabel(label: string) { - this.#resetHelicopterLabel(); - var name = helicopterDatabase.getByLabel(label)?.name || null; - if (name != null) { - this.#spawnOptions.name = name; - this.#helicopterLoadoutDropdown.setOptions(helicopterDatabase.getLoadoutNamesByRole(name, this.#spawnOptions.role)); - this.#helicopterLoadoutDropdown.selectValue(0); - //this.#helicopterLiveryDropdown.setOptions(helicopterDatabase.getLiveryNamesByName(name)); - this.#helicopterLiveryDropdown.selectValue(0); - var image = (this.getContainer()?.querySelector("#helicopter-unit-image")); - image.src = `images/units/${helicopterDatabase.getByLabel(label)?.filename}`; - image.classList.toggle("hide", false); - } - this.clip(); - this.#computeSpawnPoints(); - } - - #resetHelicopterLabel() { - (this.getContainer()?.querySelector("#helicopter-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = true; - (this.getContainer()?.querySelector("#helicopter-loadout-list")).replaceChildren(); - this.#helicopterLoadoutDropdown.reset(); - this.#helicopterLiveryDropdown.reset(); - (this.getContainer()?.querySelector("#helicopter-unit-image")).classList.toggle("hide", true); - this.clip(); - } - - #setHelicopterCount(count: string) { - this.#spawnOptions.count = parseInt(count); - this.clip(); - this.#computeSpawnPoints(); - } - - #setHelicopterLoadout(loadoutName: string) { - var loadout = helicopterDatabase.getLoadoutByName(this.#spawnOptions.name, loadoutName); - if (loadout) { - this.#spawnOptions.loadout = loadout.code; - (this.getContainer()?.querySelector("#helicopter-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = false; - var items = loadout.items.map((item: any) => { return `${item.quantity}x ${item.name}`; }); - items.length == 0 ? items.push("Empty loadout") : ""; - (this.getContainer()?.querySelector("#helicopter-loadout-list")).replaceChildren( - ...items.map((item: any) => { - var div = document.createElement('div'); - div.innerText = item; - return div; - }) - ) - } - this.clip(); - } - - #setHelicopterLivery(liveryName: string) { - var liveries = helicopterDatabase.getByName(this.#spawnOptions.name)?.liveries; - if (liveries !== undefined) { - for (let liveryID in liveries) - if (liveries[liveryID].name === liveryName) - this.#spawnOptions.liveryID = liveryID; - } - this.clip(); - } - - #setHelicopterCountry(country: string) { - this.#spawnOptions.country = country; - } - - /********* Groundunit spawn menu *********/ - #setGroundUnitType(role: string) { - this.#resetGroundUnitLabel(); - - const types = groundUnitDatabase.getByType(role).map((blueprint) => { return blueprint.label }); - this.#groundUnitLabelDropdown.setOptions(types); - this.#groundUnitLabelDropdown.selectValue(0); - this.clip(); - this.#computeSpawnPoints(); - } - - #resetGroundUnitType() { - (this.getContainer()?.querySelector("#groundunit-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = true; - this.#groundUnitTypeDropdown.reset(); - this.#groundUnitLabelDropdown.reset(); - - const types = groundUnitDatabase.getTypes(); - this.#groundUnitTypeDropdown.setOptions(types); - this.clip(); - } - - #setGroundUnitLabel(label: string) { - this.#resetGroundUnitLabel(); - var type = groundUnitDatabase.getByLabel(label)?.name || null; - if (type != null) { - this.#spawnOptions.name = type; - (this.getContainer()?.querySelector("#groundunit-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = false; - } - this.clip(); - this.#computeSpawnPoints(); - } - - #resetGroundUnitLabel() { - (this.getContainer()?.querySelector("#groundunit-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = true; - this.clip(); - } - - #setGroundUnitCount(count: string) { - this.#spawnOptions.count = parseInt(count); - this.clip(); - this.#computeSpawnPoints(); - } - - /********* Navyunit spawn menu *********/ - #setNavyUnitType(role: string) { - this.#resetNavyUnitLabel(); - - const types = navyUnitDatabase.getByType(role).map((blueprint) => { return blueprint.label }); - this.#navyUnitLabelDropdown.setOptions(types); - this.#navyUnitLabelDropdown.selectValue(0); - this.clip(); - this.#computeSpawnPoints(); - } - - #resetNavyUnitType() { - (this.getContainer()?.querySelector("#navyunit-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = true; - this.#navyUnitTypeDropdown.reset(); - this.#navyUnitLabelDropdown.reset(); - - const types = navyUnitDatabase.getTypes(); - this.#navyUnitTypeDropdown.setOptions(types); - this.clip(); - } - - #setNavyUnitLabel(label: string) { - this.#resetNavyUnitLabel(); - var type = navyUnitDatabase.getByLabel(label)?.name || null; - if (type != null) { - this.#spawnOptions.name = type; - (this.getContainer()?.querySelector("#navyunit-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = false; - } - this.clip(); - this.#computeSpawnPoints(); - } - - #resetNavyUnitLabel() { - (this.getContainer()?.querySelector("#navyunit-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = true; - this.clip(); - } - - #setNavyUnitCount(count: string) { - this.#spawnOptions.count = parseInt(count); - this.clip(); - this.#computeSpawnPoints(); - } - - #computeSpawnPoints() { - if (getMissionHandler() && getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER){ - var aircraftCount = parseInt(this.#aircraftCountDropdown.getValue()); - var aircraftSpawnPoints = aircraftCount * aircraftDatabase.getSpawnPointsByLabel(this.#aircraftLabelDropdown.getValue()); - (this.getContainer()?.querySelector("#aircraft-spawn-menu")?.querySelector(".deploy-unit-button")).dataset.points = `${aircraftSpawnPoints}`; - (this.getContainer()?.querySelector("#aircraft-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = aircraftSpawnPoints >= getMissionHandler().getAvailableSpawnPoints(); - - var helicopterCount = parseInt(this.#helicopterCountDropdown.getValue()); - var helicopterSpawnPoints = helicopterCount * helicopterDatabase.getSpawnPointsByLabel(this.#helicopterLabelDropdown.getValue()); - (this.getContainer()?.querySelector("#helicopter-spawn-menu")?.querySelector(".deploy-unit-button")).dataset.points = `${helicopterSpawnPoints}`; - (this.getContainer()?.querySelector("#helicopter-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = helicopterSpawnPoints >= getMissionHandler().getAvailableSpawnPoints(); - - var groundUnitCount = parseInt(this.#groundUnitCountDropdown.getValue()); - var groundUnitSpawnPoints = groundUnitCount * groundUnitDatabase.getSpawnPointsByLabel(this.#groundUnitLabelDropdown.getValue()); - (this.getContainer()?.querySelector("#groundunit-spawn-menu")?.querySelector(".deploy-unit-button")).dataset.points = `${groundUnitSpawnPoints}`; - (this.getContainer()?.querySelector("#groundunit-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = groundUnitSpawnPoints >= getMissionHandler().getAvailableSpawnPoints(); - - var navyUnitCount = parseInt(this.#navyUnitCountDropdown.getValue()); - var navyUnitSpawnPoints = navyUnitCount * navyUnitDatabase.getSpawnPointsByLabel(this.#navyUnitLabelDropdown.getValue()); - (this.getContainer()?.querySelector("#navyunit-spawn-menu")?.querySelector(".deploy-unit-button")).dataset.points = `${navyUnitSpawnPoints}`; - (this.getContainer()?.querySelector("#navyunit-spawn-menu")?.querySelector(".deploy-unit-button")).disabled = navyUnitSpawnPoints >= getMissionHandler().getAvailableSpawnPoints(); - } + //this.#setCountries(); } } \ No newline at end of file diff --git a/client/src/controls/unitspawnmenu.ts b/client/src/controls/unitspawnmenu.ts new file mode 100644 index 00000000..07930ef2 --- /dev/null +++ b/client/src/controls/unitspawnmenu.ts @@ -0,0 +1,295 @@ +import { LatLng } from "leaflet"; +import { Dropdown } from "./dropdown"; +import { Slider } from "./slider"; +import { UnitDatabase } from "../unit/unitdatabase"; +import { getActiveCoalition, getMap, getMissionHandler, getUnitsManager } from ".."; +import { GAME_MASTER } from "../constants/constants"; + +export class UnitSpawnMenu { + #unitRoleDropdown: Dropdown; + #unitLabelDropdown: Dropdown; + #unitCountDropdown: Dropdown; + #unitLoadoutDropdown: Dropdown; + #unitCountryDropdown: Dropdown; + #unitLiveryDropdown: Dropdown; + //#unitSpawnAltitudeSlider: Slider; + + #unitRoleDropdownEl: HTMLDivElement; + #unitTypeDropdownEl: HTMLDivElement; + #unitLoadoutDropdownEl: HTMLDivElement; + #unitCountDropdownEl: HTMLDivElement; + #unitCountryDropdownEl: HTMLDivElement; + #unitLiveryDropdownEl: HTMLDivElement; + #deployUnitButtonEl: HTMLButtonElement; + #unitLoadoutPreview: HTMLDivElement; + #unitImage: HTMLImageElement; + #unitLoadoutList: HTMLDivElement; + + #container: HTMLElement; + #spawnOptions = { role: "", name: "", latlng: new LatLng(0, 0), coalition: "blue", loadout: "", airbaseName: "", liveryID: "", altitude: 0, count: 1, country: "" }; + #unitDatabase: UnitDatabase; + #countryCodes: any; + + constructor(id: string, unitDatabase: UnitDatabase, options?: {maxUnitCount: number, showLoadout: boolean}) { + this.#container = document.getElementById(id) as HTMLElement; + this.#unitDatabase = unitDatabase; + + this.#unitRoleDropdownEl = this.#addDropdown("Unit role"); + this.#unitTypeDropdownEl = this.#addDropdown("Unit type"); + this.#unitLoadoutDropdownEl = this.#addDropdown("Unit loadout"); + this.#unitCountDropdownEl = this.#addDropdown("Unit count"); + this.#unitCountryDropdownEl = this.#addDropdown("Unit country"); + this.#unitLiveryDropdownEl = this.#addDropdown("Unit livery"); + + this.#unitRoleDropdown = new Dropdown(this.#unitRoleDropdownEl, (role: string) => this.#setUnitRole(role)); + this.#unitLabelDropdown = new Dropdown(this.#unitTypeDropdownEl, (type: string) => this.#setUnitLabel(type)); + this.#unitLoadoutDropdown = new Dropdown(this.#unitLoadoutDropdownEl, (loadout: string) => this.#setUnitLoadout(loadout)); + this.#unitCountDropdown = new Dropdown(this.#unitCountDropdownEl, (count: string) => this.#setUnitCount(count)); + this.#unitCountDropdown.setOptions(["1", "2", "3", "4"]); + this.#unitCountryDropdown = new Dropdown(this.#unitCountryDropdownEl, () => { /* Custom button implementation */ }); + this.#unitLiveryDropdown = new Dropdown(this.#unitLiveryDropdownEl, (livery: string) => this.#setUnitLivery(livery)); + //this.#unitSpawnAltitudeSlider = new Slider("unit-spawn-altitude-slider", 0, 50000, "ft", (value: number) => {this.#spawnOptions.altitude = ftToM(value);}); + //this.#unitSpawnAltitudeSlider.setIncrement(500); + //this.#unitSpawnAltitudeSlider.setValue(20000); + //this.#unitSpawnAltitudeSlider.setActive(true); + + this.#unitLoadoutPreview = document.createElement("div"); + this.#unitLoadoutPreview.classList.add("unit-loadout-preview"); + this.#unitImage = document.createElement("img"); + this.#unitImage.classList.add("unit-image", "hide"); + this.#unitLoadoutList = document.createElement("div"); + this.#unitLoadoutList.classList.add("unit-loadout-list"); + this.#unitLoadoutPreview.append(this.#unitImage, this.#unitLoadoutList); + + var advancedOptionsDiv = document.createElement("div"); + advancedOptionsDiv.classList.add("contextmenu-advanced-options", "hide"); + var advancedOptionsToggle = document.createElement("div"); + advancedOptionsToggle.classList.add("contextmenu-advanced-options-toggle"); + var advancedOptionsText = document.createElement("div"); + advancedOptionsText.innerText = "Advanced options"; + var advancedOptionsHr = document.createElement("hr"); + advancedOptionsToggle.append(advancedOptionsText, advancedOptionsHr); + advancedOptionsToggle.addEventListener("click", () => {advancedOptionsDiv.classList.toggle("hide")}); + advancedOptionsDiv.append(this.#unitCountryDropdownEl, this.#unitLiveryDropdownEl, this.#unitLoadoutPreview); + + this.#deployUnitButtonEl = document.createElement("button"); + this.#deployUnitButtonEl.classList.add("deploy-unit-button"); + this.#deployUnitButtonEl.disabled = true; + this.#deployUnitButtonEl.innerText = "Deploy unit"; + this.#deployUnitButtonEl.setAttribute("data-coalition", "blue"); + this.#deployUnitButtonEl.addEventListener("click", () => { this.#deployUnits(); }); + + this.#container.append(this.#unitRoleDropdownEl, this.#unitTypeDropdownEl, this.#unitLoadoutDropdownEl, this.#unitCountDropdownEl, + advancedOptionsToggle, advancedOptionsDiv, this.#deployUnitButtonEl); + + /* Load the country codes from the public folder */ + var xhr = new XMLHttpRequest(); + xhr.open('GET', 'images/countries/codes.json', true); + xhr.responseType = 'json'; + xhr.onload = () => { + var status = xhr.status; + if (status === 200) { + this.#countryCodes = xhr.response; + } else { + console.error(`Error retrieving country codes`) + } + }; + xhr.send(); + } + + #addDropdown(defaultText: string) { + var div = document.createElement("div"); + div.classList.add("ol-select"); + + var value = document.createElement("div"); + value.classList.add("ol-select-value"); + value.innerText = defaultText; + + var options = document.createElement("div"); + options.classList.add("ol-select-options"); + + div.append(value, options); + return div; + } + + ///********* Unit spawn menu *********/ + #setUnitRole(role: string) { + this.#spawnOptions.role = role; + this.resetUnitLabel(); + this.#unitLabelDropdown.setOptions(this.#unitDatabase.getByRole(role).map((blueprint) => { return blueprint.label })); + this.#unitLabelDropdown.selectValue(0); + this.#container.dispatchEvent(new Event("resize")); + this.#computeSpawnPoints(); + } + + resetUnitRole() { + this.#deployUnitButtonEl.disabled = true; + //(this.getContainer()?.querySelector("#unit-loadout-list")).replaceChildren(); + this.#unitRoleDropdown.reset(); + this.#unitLabelDropdown.reset(); + this.#unitRoleDropdown.setOptions(this.#unitDatabase.getRoles()); + this.#container.dispatchEvent(new Event("resize")); + } + + #setUnitLabel(label: string) { + this.resetUnitLabel(); + var name = this.#unitDatabase.getByLabel(label)?.name || null; + if (name != null) { + this.#spawnOptions.name = name; + this.#unitLoadoutDropdown.setOptions(this.#unitDatabase.getLoadoutNamesByRole(name, this.#spawnOptions.role)); + this.#unitLoadoutDropdown.selectValue(0); + //var image = (this.getContainer()?.querySelector("#unit-unit-image")); + //image.src = `images/units/${this.#unitDatabase.getByLabel(label)?.filename}`; + //image.classList.toggle("hide", false); + this.#setUnitLiveryOptions(); + } + this.#container.dispatchEvent(new Event("resize")); + this.#computeSpawnPoints(); + } + + resetUnitLabel() { + this.#deployUnitButtonEl.disabled = true; + // //(this.getContainer()?.querySelector("#unit-loadout-list")).replaceChildren(); + this.#unitLoadoutDropdown.reset(); + this.#unitLiveryDropdown.reset(); + //(this.getContainer()?.querySelector("#unit-unit-image")).classList.toggle("hide", true); + this.#container.dispatchEvent(new Event("resize")); + } + + #setUnitCount(count: string) { + this.#spawnOptions.count = parseInt(count); + this.#container.dispatchEvent(new Event("resize")); + this.#computeSpawnPoints(); + } + + #setUnitLoadout(loadoutName: string) { + var loadout = this.#unitDatabase.getLoadoutByName(this.#spawnOptions.name, loadoutName); + if (loadout) { + this.#spawnOptions.loadout = loadout.code; + this.#deployUnitButtonEl.disabled = false; + var items = loadout.items.map((item: any) => { return `${item.quantity}x ${item.name}`; }); + items.length == 0 ? items.push("Empty loadout") : ""; + //(this.getContainer()?.querySelector("#unit-loadout-list")).replaceChildren( + // ...items.map((item: any) => { + // var div = document.createElement('div'); + // div.innerText = item; + // return div; + // }) + //) + } + this.#container.dispatchEvent(new Event("resize")); + } + + #setUnitLivery(liveryName: string) { + var liveries = this.#unitDatabase.getByName(this.#spawnOptions.name)?.liveries; + if (liveries !== undefined) { + for (let liveryID in liveries) + if (liveries[liveryID].name === liveryName) + this.#spawnOptions.liveryID = liveryID; + } + this.#container.dispatchEvent(new Event("resize")); + } + + #setUnitCountry(country: string) { + this.#spawnOptions.country = country; + this.#setUnitLiveryOptions(); + } + + #setUnitLiveryOptions() { + if (this.#spawnOptions.name !== "" && this.#spawnOptions.country !== "") { + var liveries = this.#unitDatabase.getLiveryNamesByName(this.#spawnOptions.name); + var countryLiveries: string[] = ["Default"]; + liveries.forEach((livery: any) => { + var nationLiveryCodes = this.#countryCodes[this.#spawnOptions.country].liveryCodes; + if (livery.countries.some((country: string) => {return nationLiveryCodes.includes(country)})) + countryLiveries.push(livery.name); + }); + this.#unitLiveryDropdown.setOptions(countryLiveries); + this.#unitLiveryDropdown.selectValue(0); + } + } + + #deployUnits() { + this.#spawnOptions.coalition = getActiveCoalition(); + if (this.#spawnOptions) { + var unitTable = { + unitType: this.#spawnOptions.name, + location: this.#spawnOptions.latlng, + altitude: this.#spawnOptions.altitude, + loadout: this.#spawnOptions.loadout, + liveryID: this.#spawnOptions.liveryID + }; + var units = []; + for (let i = 1; i < parseInt(this.#unitCountDropdown.getValue()) + 1; i++) { + units.push(unitTable); + } + if (getUnitsManager().spawnUnits("Unit", units, getActiveCoalition(), false, this.#spawnOptions.airbaseName, this.#spawnOptions.country)) { + getMap().addTemporaryMarker(this.#spawnOptions.latlng, this.#spawnOptions.name, getActiveCoalition()); + getMap().getMapContextMenu().hide(); + } + } + } + + setCountries() { + var coalitions = getMissionHandler().getCoalitions(); + var countries = Object.values(coalitions[getActiveCoalition() as keyof typeof coalitions]); + this.#unitCountryDropdown.setOptionsElements(this.#createCountryButtons(this.#unitCountryDropdown, countries, (country: string) => {this.#setUnitCountry(country)})); + + if (countries.length > 0 && !countries.includes(this.#spawnOptions.country)) { + this.#unitCountryDropdown.forceValue(countries[0]); + this.#setUnitCountry(countries[0]); + } + } + + #createCountryButtons(parent: Dropdown, countries: string[], callback: CallableFunction) { + return Object.values(countries).map((country: string) => { + var el = document.createElement("div"); + + var formattedCountry = ""; + if (this.#countryCodes[country] !== undefined && this.#countryCodes[country].displayName !== undefined) + formattedCountry = this.#countryCodes[country].displayName; + else + formattedCountry = country.charAt(0).toUpperCase() + country.slice(1).toLowerCase(); + + var button = document.createElement("button"); + button.classList.add("country-dropdown-element"); + el.appendChild(button); + button.addEventListener("click", () => { + callback(country); + parent.forceValue(formattedCountry); + parent.close(); + }); + if (this.#countryCodes[country] !== undefined) { + var code = this.#countryCodes[country].flagCode; + if (code !== undefined) { + var img = document.createElement("img"); + img.src = `images/countries/${code.toLowerCase()}.svg`; + button.appendChild(img); + } + } + else { + console.log("Unknown country " + country); + } + var text = document.createElement("div"); + text.innerText = formattedCountry; + button.appendChild(text); + return el; + }); + } + + #computeSpawnPoints() { + if (getMissionHandler() && getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER){ + var unitCount = parseInt(this.#unitCountDropdown.getValue()); + var unitSpawnPoints = unitCount * this.#unitDatabase.getSpawnPointsByLabel(this.#unitLabelDropdown.getValue()); + this.#deployUnitButtonEl.dataset.points = `${unitSpawnPoints}`; + this.#deployUnitButtonEl.disabled = unitSpawnPoints >= getMissionHandler().getAvailableSpawnPoints(); + } + } + + refreshOptions() { + if (!this.#unitDatabase.getRoles().includes(this.#unitRoleDropdown.getValue())) + this.resetUnitRole(); + if (!this.#unitDatabase.getByRole(this.#unitRoleDropdown.getValue()).map((blueprint) => { return blueprint.label }).includes(this.#unitLabelDropdown.getValue())) + this.resetUnitLabel(); + } +} \ No newline at end of file diff --git a/client/views/other/contextmenus.ejs b/client/views/other/contextmenus.ejs index 3a0abf20..65945e34 100644 --- a/client/views/other/contextmenus.ejs +++ b/client/views/other/contextmenus.ejs @@ -25,216 +25,16 @@ data-on-click-params='{"type": "polygon"}' class="ol-contexmenu-button">
-
-
-
Aircraft role
-
- -
-
-
-
-
-
Aircraft name
-
-
Select role first
- -
-
-
-
-
-
Loadout
-
-
Select type first
- -
-
-
-
-
Group members
-
-
-
- -
-
-
-
-
Advanced options
-
-
-
-
-
-
Country
-
-
Select type first
- -
-
-
-
-
-
Livery
-
-
Select type first
- -
-
-
-
-
-
Spawn altitude -
-
-
-
-
- -
-
- -
-
-
-
- +
-
-
-
Helicopter role
-
- -
-
-
-
-
-
Helicopter name
-
-
Select role first
- -
-
-
-
-
-
Loadout
-
-
Select type first
- -
-
-
-
-
Group members
-
-
-
- -
-
-
-
-
Advanced options
-
-
-
-
-
-
Country
-
-
Select type first
- -
-
-
-
-
-
Livery
-
-
Select type first
- -
-
-
-
-
-
Spawn altitude -
-
-
-
-
- -
-
- -
-
-
-
- +
-
-
-
Ground unit type
-
- -
-
-
-
-
-
Ground unit name
-
-
Select role first
- -
-
-
-
-
Group members
-
-
-
- -
-
-
- +
@@ -273,8 +73,7 @@
-
- +