Tweaks to IADS creation and menus

This commit is contained in:
Pax1601
2023-07-11 17:30:05 +02:00
parent 439111f7a0
commit f379f6b998
19 changed files with 7511 additions and 118 deletions

View File

@@ -14,7 +14,7 @@ interface LoadoutBlueprint {
interface UnitBlueprint {
name: string;
era?: string[];
era: string[];
label: string;
shortLabel: string;
type?: string;

View File

@@ -142,7 +142,8 @@ export const COALITIONAREA_DRAW_POLYGON = "Draw Coalition Area";
export const visibilityControls: string[] = ["human", "dcs", "aircraft", "groundunit-sam", "groundunit-other", "navyunit", "airbase"];
export const visibilityControlsTootlips: string[] = ["Toggle human players visibility", "Toggle DCS controlled units visibility", "Toggle aircrafts visibility", "Toggle SAM units visibility", "Toggle ground units (not SAM) visibility", "Toggle navy units visibility", "Toggle airbases visibility"];
export const IADSRoles: {[key: string]: number}= {"AAA": 0.8, "MANPADS": 0.3, "SAM Sites": 0.1, "Radar": 0.05};
export const IADSTypes = ["AAA", "MANPADS", "SAM Sites", "Radar"];
export const IADSDensities: {[key: string]: number}= {"AAA": 0.8, "MANPADS": 0.3, "SAM Sites": 0.1, "Radar": 0.05};
export enum DataIndexes {
startOfData = 0,

View File

@@ -62,6 +62,7 @@ export class AirbaseContextMenu extends ContextMenu {
setActiveCoalition(this.#airbase.getCoalition());
getMap().showMapContextMenu(this.getX(), this.getY(), this.getLatLng());
getMap().getMapContextMenu().hideUpperBar();
getMap().getMapContextMenu().hideLowerBar();
getMap().getMapContextMenu().hideAltitudeSlider();
getMap().getMapContextMenu().showSubMenu("aircraft");
getMap().getMapContextMenu().setAirbaseName(this.#airbase.getName());

View File

@@ -1,31 +1,38 @@
import { LatLng } from "leaflet";
import { getMap, getUnitsManager } from "..";
import { GAME_MASTER, IADSRoles } from "../constants/constants";
import { GAME_MASTER, IADSTypes } from "../constants/constants";
import { CoalitionArea } from "../map/coalitionarea";
import { ContextMenu } from "./contextmenu";
import { Dropdown } from "./dropdown";
import { Slider } from "./slider";
import { Switch } from "./switch";
import { groundUnitDatabase } from "../units/groundunitdatabase";
export class CoalitionAreaContextMenu extends ContextMenu {
#coalitionSwitch: Switch;
#coalitionArea: CoalitionArea | null = null;
#iadsDensitySlider: Slider;
#iadsRoleDropdown: Dropdown;
//#iadsPeriodDropdown: Dropdown;
#iadsDistributionSlider: Slider;
#iadsTypesDropdown: Dropdown;
#iadsErasDropdown: Dropdown;
#iadsRangesDropdown: Dropdown;
constructor(id: string) {
super(id);
this.#coalitionSwitch = new Switch("coalition-area-switch", (value: boolean) => this.#onSwitchClick(value));
this.#coalitionSwitch.setValue(false);
this.#iadsRoleDropdown = new Dropdown("iads-units-role-options", () => { });
//this.#iadsPeriodDropdown = new Dropdown("iads-period-options", () => {});
this.#iadsTypesDropdown = new Dropdown("iads-units-type-options", () => { });
this.#iadsErasDropdown = new Dropdown("iads-era-options", () => {});
this.#iadsRangesDropdown = new Dropdown("iads-range-options", () => {});
this.#iadsDensitySlider = new Slider("iads-density-slider", 5, 100, "%", (value: number) => { });
this.#iadsDistributionSlider = new Slider("iads-distribution-slider", 5, 100, "%", (value: number) => { });
this.#iadsDensitySlider.setIncrement(5);
this.#iadsDensitySlider.setValue(50);
this.#iadsDensitySlider.setActive(true);
this.#iadsDistributionSlider.setIncrement(5);
this.#iadsDistributionSlider.setValue(50);
this.#iadsDistributionSlider.setActive(true);
document.addEventListener("coalitionAreaContextMenuShow", (e: any) => {
if (this.getVisibleSubMenu() !== e.detail.type)
@@ -34,6 +41,12 @@ export class CoalitionAreaContextMenu extends ContextMenu {
this.hideSubMenus();
});
document.addEventListener("coalitionAreaBringToBack", (e: any) => {
if (this.#coalitionArea)
getMap().bringCoalitionAreaToBack(this.#coalitionArea);
getMap().hideCoalitionAreaContextMenu();
});
document.addEventListener("coalitionAreaDelete", (e: any) => {
if (this.#coalitionArea)
getMap().deleteCoalitionArea(this.#coalitionArea);
@@ -41,36 +54,25 @@ export class CoalitionAreaContextMenu extends ContextMenu {
});
document.addEventListener("contextMenuCreateIads", (e: any) => {
const values: { [key: string]: boolean } = {};
const element = this.#iadsRoleDropdown.getOptionElements();
for (let idx = 0; idx < element.length; idx++) {
const option = element.item(idx) as HTMLElement;
const key = option.querySelector("span")?.innerText;
const value = option.querySelector("input")?.checked;
if (key !== undefined && value !== undefined)
values[key] = value;
}
const area = this.getCoalitionArea();
if (area)
getUnitsManager().createIADS(area, values, this.#iadsDensitySlider.getValue());
getUnitsManager().createIADS(area, this.#getCheckboxOptions(this.#iadsTypesDropdown), this.#getCheckboxOptions(this.#iadsErasDropdown), this.#getCheckboxOptions(this.#iadsRangesDropdown), this.#iadsDensitySlider.getValue(), this.#iadsDistributionSlider.getValue());
})
/* Create the checkboxes to select the unit roles */
this.#iadsRoleDropdown.setOptionsElements(Object.keys(IADSRoles).map((unitRole: string) => {
var div = document.createElement("div");
div.classList.add("ol-checkbox");
var label = document.createElement("label");
label.title = `Add ${unitRole}s to the IADS`;
var input = document.createElement("input");
input.type = "checkbox";
input.checked = true;
var span = document.createElement("span");
span.innerText = unitRole;
label.appendChild(input);
label.appendChild(span);
div.appendChild(label);
return div as HTMLElement;
this.#iadsTypesDropdown.setOptionsElements(IADSTypes.map((role: string) => {
return this.#createCheckboxOption(role);
}));
/* Create the checkboxes to select the unit periods */
this.#iadsErasDropdown.setOptionsElements(groundUnitDatabase.getEras().map((era: string) => {
return this.#createCheckboxOption(era);
}));
/* Create the checkboxes to select the unit ranges */
this.#iadsRangesDropdown.setOptionsElements(groundUnitDatabase.getRanges().map((range: string) => {
return this.#createCheckboxOption(range);
}));
this.hide();
@@ -118,4 +120,33 @@ export class CoalitionAreaContextMenu extends ContextMenu {
});
}
}
#createCheckboxOption(text: string) {
var div = document.createElement("div");
div.classList.add("ol-checkbox");
var label = document.createElement("label");
label.title = `Add ${text}s to the IADS`;
var input = document.createElement("input");
input.type = "checkbox";
input.checked = true;
var span = document.createElement("span");
span.innerText = text;
label.appendChild(input);
label.appendChild(span);
div.appendChild(label);
return div as HTMLElement;
}
#getCheckboxOptions(dropdown: Dropdown) {
var values: { [key: string]: boolean } = {};
const element = dropdown.getOptionElements();
for (let idx = 0; idx < element.length; idx++) {
const option = element.item(idx) as HTMLElement;
const key = option.querySelector("span")?.innerText;
const value = option.querySelector("input")?.checked;
if (key !== undefined && value !== undefined)
values[key] = value;
}
return values;
}
}

View File

@@ -86,7 +86,7 @@ export class MapContextMenu extends ContextMenu {
if (this.getVisibleSubMenu() !== e.detail.type)
this.showSubMenu(e.detail.type);
else
this.hideSubMenus();
this.hideSubMenus(e.detail.type);
});
document.addEventListener("contextMenuDeployAircraft", () => {
@@ -191,6 +191,11 @@ export class MapContextMenu extends ContextMenu {
}
showSubMenu(type: string) {
if (type === "more")
this.getContainer()?.querySelector("#more-options-button-bar")?.classList.toggle("hide");
else if (["aircraft", "groundunit"].includes(type))
this.getContainer()?.querySelector("#more-options-button-bar")?.classList.toggle("hide", true);
this.getContainer()?.querySelector("#aircraft-spawn-menu")?.classList.toggle("hide", type !== "aircraft");
this.getContainer()?.querySelector("#aircraft-spawn-button")?.classList.toggle("is-open", type === "aircraft");
this.getContainer()?.querySelector("#helicopter-spawn-menu")?.classList.toggle("hide", type !== "helicopter");
@@ -220,7 +225,8 @@ export class MapContextMenu extends ContextMenu {
this.setVisibleSubMenu(type);
}
hideSubMenus() {
hideSubMenus(type: string) {
this.getContainer()?.querySelector("#more-options-button-bar")?.classList.toggle("hide", ["aircraft", "groundunit"].includes(type));
this.getContainer()?.querySelector("#aircraft-spawn-menu")?.classList.toggle("hide", true);
this.getContainer()?.querySelector("#aircraft-spawn-button")?.classList.toggle("is-open", false);
this.getContainer()?.querySelector("#helicopter-spawn-menu")?.classList.toggle("hide", true);
@@ -257,6 +263,14 @@ export class MapContextMenu extends ContextMenu {
this.getContainer()?.querySelector(".upper-bar")?.classList.toggle("hide", true);
}
showLowerBar() {
this.getContainer()?.querySelector("#more-options-button-bar")?.classList.toggle("hide", false);
}
hideLowerBar() {
this.getContainer()?.querySelector("#more-optionsbutton-bar")?.classList.toggle("hide", true);
}
showAltitudeSlider() {
this.getContainer()?.querySelector("#aircraft-spawn-altitude-slider")?.classList.toggle("hide", false);
}
@@ -430,8 +444,8 @@ export class MapContextMenu extends ContextMenu {
this.#groundUnitTypeDropdown.reset();
this.#groundUnitNameDropdown.reset();
const roles = groundUnitDatabase.getTypes();
this.#groundUnitTypeDropdown.setOptions(roles);
const types = groundUnitDatabase.getTypes();
this.#groundUnitTypeDropdown.setOptions(types);
this.clip();
}
@@ -470,8 +484,8 @@ export class MapContextMenu extends ContextMenu {
this.#navyUnitTypeDropdown.reset();
this.#navyUnitNameDropdown.reset();
const roles = navyUnitDatabase.getTypes();
this.#navyUnitTypeDropdown.setOptions(roles);
const types = navyUnitDatabase.getTypes();
this.#navyUnitTypeDropdown.setOptions(types);
this.clip();
}

View File

@@ -17,7 +17,6 @@ import { Dropdown } from "./controls/dropdown";
import { HotgroupPanel } from "./panels/hotgrouppanel";
import { SVGInjector } from "@tanem/svg-injector";
import { BLUE_COMMANDER, GAME_MASTER, RED_COMMANDER } from "./constants/constants";
import { NavyUnitDatabase, navyUnitDatabase } from "./units/navyunitdatabase";
var map: Map;
@@ -206,7 +205,6 @@ function setupEvents() {
else
img.onload = () => SVGInjector(img);
})
}
export function getMap() {

View File

@@ -27,6 +27,7 @@ export class CoalitionArea extends Polygon {
this.setCoalition("blue");
else if (getUnitsManager().getCommandMode() == RED_COMMANDER)
this.setCoalition("red");
}
setCoalition(coalition: string) {
@@ -89,6 +90,12 @@ export class CoalitionArea extends Polygon {
this.setStyle({opacity: opacity, fillOpacity: opacity * 0.25});
}
onRemove(map: Map): this {
super.onRemove(map);
this.#handles.concat(this.#middleHandles).forEach((handle: CoalitionAreaHandle | CoalitionAreaMiddleHandle) => handle.removeFrom(getMap()));
return this;
}
#setColors() {
const coalitionColor = this.getCoalition() === "blue" ? "#247be2" : "#ff5858";
this.setStyle({ color: this.getSelected() ? "white" : coalitionColor, fillColor: coalitionColor });
@@ -159,10 +166,4 @@ export class CoalitionArea extends Polygon {
this.setEditing(false);
});
}
onRemove(map: Map): this {
super.onRemove(map);
this.#handles.concat(this.#middleHandles).forEach((handle: CoalitionAreaHandle | CoalitionAreaMiddleHandle) => handle.removeFrom(getMap()));
return this;
}
}

View File

@@ -392,6 +392,12 @@ export class Map extends L.Map {
return this.#coalitionAreas.find((area: CoalitionArea) => { return area.getSelected() });
}
bringCoalitionAreaToBack(coalitionArea: CoalitionArea) {
coalitionArea.bringToBack();
this.#coalitionAreas.splice(this.#coalitionAreas.indexOf(coalitionArea), 1);
this.#coalitionAreas.unshift(coalitionArea);
}
/* Event handlers */
#onClick(e: any) {
if (!this.#preventLeftClick) {
@@ -423,14 +429,18 @@ export class Map extends L.Map {
if (this.#state === IDLE) {
if (this.#state == IDLE) {
this.showMapContextMenu(e.originalEvent.x, e.originalEvent.y, e.latlng);
var clickedCoalitionArea = null;
/* Coalition areas are ordered in the #coalitionAreas array according to their zindex. Select the upper one */
for (let coalitionArea of this.#coalitionAreas) {
if (coalitionArea.getBounds().contains(e.latlng)) {
if (coalitionArea.getSelected())
this.showCoalitionAreaContextMenu(e.originalEvent.x, e.originalEvent.y, e.latlng, coalitionArea);
if (coalitionArea.getSelected())
clickedCoalitionArea = coalitionArea;
else
this.getMapContextMenu().setCoalitionArea(coalitionArea);
}
}
if (clickedCoalitionArea)
this.showCoalitionAreaContextMenu(e.originalEvent.x, e.originalEvent.y, e.latlng, clickedCoalitionArea);
}
}
else if (this.#state === MOVE_UNIT) {

View File

@@ -35,14 +35,14 @@ export function distance(lat1: number, lon1: number, lat2: number, lon2: number)
return d;
}
export function coordinatesFromBearingAndDistance(lat1: number, lon1: number, brng: number, dist: number) {
export function bearingAndDistanceToLatLng(lat: number, lon: number, brng: number, dist: number) {
const R = 6371e3; // metres
const φ1 = deg2rad(lat1); // φ, λ in radians
const λ1 = deg2rad(lon1);
const φ1 = deg2rad(lat); // φ, λ in radians
const λ1 = deg2rad(lon);
const φ2 = Math.asin( Math.sin(φ1)*Math.cos(dist/R) + Math.cos(φ1)*Math.sin(dist/R)*Math.cos(brng) );
const λ2 = λ1 + Math.atan2(Math.sin(brng)*Math.sin(dist/R)*Math.cos(φ1), Math.cos(dist/R)-Math.sin(φ1)*Math.sin(φ2));
return {lat: rad2deg(φ2), lng: rad2deg(λ2)};
return new LatLng(rad2deg(φ2), rad2deg(λ2));
}
export function ConvertDDToDMS(D: number, lng: boolean) {
@@ -205,6 +205,11 @@ export function nmToFt(nm: number) {
return nm * 6076.12;
}
export function polyContains(latlng: LatLng, polygon: Polygon) {
var poly = polygon.toGeoJSON();
return turf.inside(turf.point([latlng.lng, latlng.lat]), poly);
}
export function randomPointInPoly(polygon: Polygon): LatLng {
var bounds = polygon.getBounds();
var x_min = bounds.getEast();
@@ -226,12 +231,45 @@ export function randomPointInPoly(polygon: Polygon): LatLng {
}
export function polygonArea(polygon: Polygon) {
var poly = polygon.toGeoJSON();
var poly = polygon.toGeoJSON();
return turf.area(poly);
}
export function randomUnitBlueprintByRole(unitDatabse: UnitDatabase, role: string) {
const unitBlueprints = unitDatabse.getByRole(role);
export function randomUnitBlueprint(unitDatabase: UnitDatabase, options: {type?: string, role?: string, ranges?: string[], eras?: string[]} ) {
/* Start from all the unit blueprints in the database */
var unitBlueprints = Object.values(unitDatabase.getBlueprints());
/* If a specific type or role is provided, use only the blueprints of that type or role */
if (options.type && options.role) {
console.error("Can't create random unit if both type and role are provided. Either create by type or by role.")
return null;
}
if (options.type) {
unitBlueprints = unitDatabase.getByType(options.type);
}
else if (options.role) {
unitBlueprints = unitDatabase.getByType(options.role);
}
/* Keep only the units that have a range included in the requested values */
if (options.ranges) {
unitBlueprints = unitBlueprints.filter((unitBlueprint: UnitBlueprint) => {
//@ts-ignore
return unitBlueprint.range? options.ranges.includes(unitBlueprint.range): true;
});
}
/* Keep only the units that have an era included in the requested values */
if (options.eras) {
unitBlueprints = unitBlueprints.filter((unitBlueprint: UnitBlueprint) => {
//@ts-ignore
return options.eras.reduce((value, era) => {
return value? value: unitBlueprint.era.includes(era);
}, false);
});
}
var index = Math.floor(Math.random() * unitBlueprints.length);
return unitBlueprints[index];
}

File diff suppressed because it is too large Load Diff

View File

@@ -233,6 +233,7 @@ export class GroundUnitDatabase extends UnitDatabase {
},
"Bunker": {
"name": "Bunker",
"era": ["Early Cold War", "Mid Cold War", "Late Cold War", "Modern"],
"label": "Bunker",
"shortLabel": "Bunker",
"filename": "",
@@ -370,6 +371,7 @@ export class GroundUnitDatabase extends UnitDatabase {
},
"Sandbox": {
"name": "Sandbox",
"era": ["Early Cold War", "Mid Cold War", "Late Cold War", "Modern"],
"label": "Sandbox",
"shortLabel": "Sandbox",
"filename": "",
@@ -1085,6 +1087,7 @@ export class GroundUnitDatabase extends UnitDatabase {
},
"house1arm": {
"name": "house1arm",
"era": ["Early Cold War", "Mid Cold War", "Late Cold War", "Modern"],
"label": "house1arm",
"shortLabel": "house1arm",
"filename": "",
@@ -1092,6 +1095,7 @@ export class GroundUnitDatabase extends UnitDatabase {
},
"house2arm": {
"name": "house2arm",
"era": ["Early Cold War", "Mid Cold War", "Late Cold War", "Modern"],
"label": "house2arm",
"shortLabel": "house2arm",
"filename": "",
@@ -1099,6 +1103,7 @@ export class GroundUnitDatabase extends UnitDatabase {
},
"outpost_road": {
"name": "outpost_road",
"era": ["Early Cold War", "Mid Cold War", "Late Cold War", "Modern"],
"label": "outpost_road",
"shortLabel": "outpost_road",
"filename": "",
@@ -1106,6 +1111,7 @@ export class GroundUnitDatabase extends UnitDatabase {
},
"outpost": {
"name": "outpost",
"era": ["Early Cold War", "Mid Cold War", "Late Cold War", "Modern"],
"label": "outpost",
"shortLabel": "outpost",
"filename": "",
@@ -1113,6 +1119,7 @@ export class GroundUnitDatabase extends UnitDatabase {
},
"houseA_arm": {
"name": "houseA_arm",
"era": ["Early Cold War", "Mid Cold War", "Late Cold War", "Modern"],
"label": "houseA_arm",
"shortLabel": "houseA_arm",
"filename": "",

View File

@@ -1,7 +1,7 @@
import { Marker, LatLng, Polyline, Icon, DivIcon, CircleMarker, Map, Point } from 'leaflet';
import { getMap, getUnitsManager } from '..';
import { enumToCoalition, enumToEmissioNCountermeasure, getMarkerCategoryByName, enumToROE, enumToReactionToThreat, enumToState, getUnitDatabaseByCategory, mToFt, msToKnots, rad2deg, bearing, coordinatesFromBearingAndDistance, deg2rad } from '../other/utils';
import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, getUnits, landAt, setAltitude, setReactionToThreat, setROE, setSpeed, refuel, setAdvacedOptions, followUnit, setEmissionsCountermeasures, setSpeedType, setAltitudeType, setOnOff, setFollowRoads, bombPoint, carpetBomb, bombBuilding, fireAtArea } from '../server/server';
import { enumToCoalition, enumToEmissioNCountermeasure, getMarkerCategoryByName, enumToROE, enumToReactionToThreat, enumToState, getUnitDatabaseByCategory, mToFt, msToKnots, rad2deg, bearing, deg2rad } from '../other/utils';
import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, landAt, setAltitude, setReactionToThreat, setROE, setSpeed, refuel, setAdvacedOptions, followUnit, setEmissionsCountermeasures, setSpeedType, setAltitudeType, setOnOff, setFollowRoads, bombPoint, carpetBomb, bombBuilding, fireAtArea } from '../server/server';
import { CustomMarker } from '../map/custommarker';
import { SVGInjector } from '@tanem/svg-injector';
import { UnitDatabase } from './unitdatabase';

View File

@@ -5,6 +5,10 @@ export class UnitDatabase {
}
getBlueprints() {
return this.blueprints;
}
/* Returns a list of all possible roles in a database */
getRoles() {
var roles: string[] = [];
@@ -33,6 +37,32 @@ export class UnitDatabase {
return types;
}
/* Returns a list of all possible periods in a database */
getEras() {
var eras: string[] = [];
for (let unit in this.blueprints) {
var unitEras = this.blueprints[unit].era;
if (unitEras) {
for (let era of unitEras) {
if (era !== "" && !eras.includes(era))
eras.push(era);
}
}
}
return eras;
}
/* Returns a list of all possible ranges in a database */
getRanges() {
var ranges: string[] = [];
for (let unit in this.blueprints) {
var range = this.blueprints[unit].range;
if (range && range !== "" && !ranges.includes(range))
ranges.push(range);
}
return ranges;
}
/* Gets a specific blueprint by name */
getByName(name: string) {
if (name in this.blueprints)

View File

@@ -2,13 +2,14 @@ import { LatLng, LatLngBounds } from "leaflet";
import { getHotgroupPanel, getInfoPopup, getMap, getMissionHandler } from "..";
import { Unit } from "./unit";
import { cloneUnit, setLastUpdateTime, spawnGroundUnits } from "../server/server";
import { deg2rad, keyEventWasInInput, latLngToMercator, mToFt, mercatorToLatLng, msToKnots, polygonArea, randomPointInPoly, randomUnitBlueprintByRole } from "../other/utils";
import { bearingAndDistanceToLatLng, deg2rad, keyEventWasInInput, latLngToMercator, mToFt, mercatorToLatLng, msToKnots, polyContains, polygonArea, randomPointInPoly, randomUnitBlueprint } from "../other/utils";
import { CoalitionArea } from "../map/coalitionarea";
import { Airbase } from "../missionhandler/airbase";
import { groundUnitDatabase } from "./groundunitdatabase";
import { DataIndexes, HIDE_ALL, IADSRoles, IDLE, MOVE_UNIT } from "../constants/constants";
import { DataIndexes, HIDE_ALL, IADSDensities, IDLE, MOVE_UNIT } from "../constants/constants";
import { DataExtractor } from "./dataextractor";
import { Contact } from "../@types/unit";
import { citiesDatabase } from "./citiesDatabase";
export class UnitsManager {
#units: { [ID: number]: Unit };
@@ -544,28 +545,31 @@ export class UnitsManager {
}
}
createIADS(coalitionArea: CoalitionArea, options: {[key: string]: boolean}, density: number) {
const activeRoles = Object.keys(options).filter((key: string) => { return options[key]; });
const airbases = getMissionHandler().getAirbases();
const pointsNumber = polygonArea(coalitionArea) / 1e7 * density / 100;
for (let i = 0; i < pointsNumber; i++) {
const latlng = randomPointInPoly(coalitionArea);
var minDistance: number = Infinity;
var maxDistance: number = 0;
Object.values(airbases).forEach((airbase: Airbase) => {
var distance = airbase.getLatLng().distanceTo(latlng);
if (distance < minDistance) minDistance = distance;
if (distance > maxDistance) maxDistance = distance;
});
createIADS(coalitionArea: CoalitionArea, types: {[key: string]: boolean}, eras: {[key: string]: boolean}, ranges: {[key: string]: boolean}, density: number, distribution: number) {
const activeTypes = Object.keys(types).filter((key: string) => { return types[key]; });
const activeEras = Object.keys(eras).filter((key: string) => { return eras[key]; });
const activeRanges = Object.keys(ranges).filter((key: string) => { return ranges[key]; });
const role = activeRoles[Math.floor(Math.random() * activeRoles.length)];
const probability = Math.pow(1 - minDistance / 50e3, 5) * IADSRoles[role];
if (Math.random() < probability){
const unitBlueprint = randomUnitBlueprintByRole(groundUnitDatabase, role);
spawnGroundUnits([{unitType: unitBlueprint.name, location: latlng}], coalitionArea.getCoalition(), true);
getMap().addTemporaryMarker(latlng, unitBlueprint.name, coalitionArea.getCoalition());
citiesDatabase.forEach((city: {lat: number, lng: number, pop: number}) => {
if (polyContains(new LatLng(city.lat, city.lng), coalitionArea)) {
var pointsNumber = 2 + Math.pow(city.pop, 0.2) * density / 100;
for (let i = 0; i < pointsNumber; i++) {
var bearing = Math.random() * 360;
var distance = Math.random() * distribution * 100;
const latlng = bearingAndDistanceToLatLng(city.lat, city.lng, bearing, distance);
if (polyContains(latlng, coalitionArea)) {
const type = activeTypes[Math.floor(Math.random() * activeTypes.length)];
if (Math.random() < IADSDensities[type]) {
const unitBlueprint = randomUnitBlueprint(groundUnitDatabase, {type: type, eras: activeEras, ranges: activeRanges});
if (unitBlueprint) {
spawnGroundUnits([{unitType: unitBlueprint.name, location: latlng}], coalitionArea.getCoalition(), true);
getMap().addTemporaryMarker(latlng, unitBlueprint.name, coalitionArea.getCoalition());
}
}
}
}
}
}
})
}
exportToFile() {