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

@ -343,7 +343,7 @@ class DemoDataGenerator {
};
mission(req, res){
var ret = {mission: {theatre: "Nevada"}};
var ret = {mission: {theatre: "Syria"}};
ret.time = Date.now();
var auth = req.get("Authorization");
if (auth) {

View File

@ -1195,14 +1195,6 @@ input[type=number]::-webkit-outer-spin-button {
background-color: var(--primary-neutral);
}
.ol-context-menu>div:nth-child(2) {
align-items: center;
display: flex;
flex-direction: row;
justify-content: space-between;
padding-right: 0px;
}
.ol-context-menu>ul {
max-height: 200px;
overflow-x: hidden;
@ -1218,21 +1210,12 @@ input[type=number]::-webkit-outer-spin-button {
margin: 0px;
}
.ol-context-menu>div:nth-child(n+3) {
align-items: center;
display: flex;
flex-direction: column;
justify-content: space-between;
row-gap: 5px;
}
.ol-context-menu .ol-select-container {
align-self: stretch;
flex: 0 0 auto;
width: 100%;
}
.ol-contexmenu-button {
border: none;
border-radius: 0px;

View File

@ -4,10 +4,34 @@
height: fit-content;
position: absolute;
row-gap: 5px;
width: 280px;
width: 300px;
z-index: 9999;
}
#map-contextmenu>div:nth-child(2) {
align-items: center;
display: flex;
flex-direction: row;
justify-content: space-between;
padding-right: 0px;
}
#map-contextmenu>div:nth-child(3) {
align-items: center;
display: flex;
flex-direction: row;
justify-content: space-between;
padding-right: 0px;
}
#map-contextmenu>div:nth-child(n+4) {
align-items: center;
display: flex;
flex-direction: column;
justify-content: space-between;
row-gap: 5px;
}
#aircraft-spawn-menu,
#helicopter-spawn-menu,
#groundunit-spawn-menu,
@ -40,6 +64,7 @@
}
.deploy-unit-button {
margin-top: 5px;
text-align: center;
width: 100%;
}
@ -180,16 +205,14 @@
background-color: orange;
}
#aircraft-spawn-menu .ol-slider-value,
#helicopter-spawn-menu .ol-slider-value {
.ol-context-menu .ol-slider-value {
color: var(--accent-light-blue);
cursor: pointer;
font-size: 14px;
font-weight: bold;
}
#aircraft-spawn-altitude-slider,
#helicopter-spawn-altitude-slider {
.ol-context-menu .ol-slider-container {
padding: 0px 10px;
}
@ -357,7 +380,7 @@
height: fit-content;
position: absolute;
row-gap: 5px;
width: 250px;
width: 300px;
z-index: 9999;
}
@ -371,6 +394,10 @@
align-self: flex-start;
}
#coalition-units-checkbox {
padding: 10px 10px;
}
#iads-menu .ol-select-options>* {
padding-top: 8px;
padding-bottom: 8px;
@ -391,3 +418,25 @@
#iads-menu {
row-gap: 10px;
}
#coalition-area-contextmenu>div:nth-child(2) {
align-items: center;
display: flex;
flex-direction: row;
justify-content: space-between;
padding-right: 0px;
}
#coalition-area-contextmenu>div:nth-child(n+3) {
align-items: center;
display: flex;
flex-direction: column;
justify-content: space-between;
row-gap: 5px;
}
.create-iads-button {
margin-top: 5px;
text-align: center;
width: 100%;
}

View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="32"
height="32"
viewBox="0 0 32 32"
version="1.1"
id="svg8"
sodipodi:docname="unit.svg"
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata
id="metadata14">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs12" />
<sodipodi:namedview
inkscape:document-rotation="0"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview10"
showgrid="false"
inkscape:zoom="9.391262"
inkscape:cx="25.715394"
inkscape:cy="24.171405"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg8"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1" />
<rect
id="rect894"
width="5.696785"
height="22.699497"
x="13.203763"
y="4.5254831"
ry="1.6436043" />
<rect
id="rect894-7"
width="5.696785"
height="22.699497"
x="12.751214"
y="-27.588247"
ry="1.6436043"
transform="rotate(90)" />
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

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() {

View File

@ -1,21 +1,27 @@
<div id="map-contextmenu" class="ol-context-menu" oncontextmenu="return false;">
<div id="active-coalition-label" data-coalition="blue"></div>
<div class="upper-bar ol-panel">
<div id="coalition-switch" class="ol-switch ol-coalition-switch"></div>
<div id="coalition-switch" class="ol-switch ol-coalition-switch"></div>
<button data-coalition="blue" id="aircraft-spawn-button" title="Spawn aircraft" data-on-click="mapContextMenuShow"
data-on-click-params='{ "type": "aircraft" }' class="ol-contexmenu-button"><img src="/resources/theme/images/buttons/spawn/aircraft.svg" inject-svg></button>
<button data-coalition="blue" id="helicopter-spawn-button" title="Spawn helicopter" data-on-click="mapContextMenuShow"
data-on-click-params='{ "type": "helicopter" }' class="ol-contexmenu-button"><img src="/resources/theme/images/buttons/spawn/helicopter.svg" inject-svg></button>
<button data-coalition="blue" id="groundunit-spawn-button" title="Spawn ground unit" data-on-click="mapContextMenuShow"
data-on-click-params='{ "type": "groundunit" }' class="ol-contexmenu-button"><img src="/resources/theme/images/buttons/spawn/groundunit.svg" inject-svg></button>
<button data-coalition="blue" id="navyunit-spawn-button" title="Spawn navy unit" data-on-click="mapContextMenuShow"
<button data-coalition="blue" id="coalition-area-button" title="Edit coalition area" data-on-click="editCoalitionArea"
class="ol-contexmenu-button"><img src="/resources/theme/images/buttons/other/edit.svg" inject-svg></button>
<button data-coalition="blue" id="more-options-button" title="More options" data-on-click="mapContextMenuShow"
data-on-click-params='{ "type": "more" }' class="ol-contexmenu-button"><img src="/resources/theme/images/buttons/spawn/more.svg" inject-svg></button>
</div>
<div id="more-options-button-bar" class="upper-bar ol-panel hide">
<div id="coalition-switch" class="ol-switch ol-coalition-switch"></div>
<button data-coalition="blue" id="navyunit-spawn-button" title="Spawn navy unit" data-on-click="mapContextMenuShow"
data-on-click-params='{ "type": "navyunit" }' class="ol-contexmenu-button"><img src="/resources/theme/images/buttons/spawn/navyunit.svg" inject-svg></button>
<button data-coalition="blue" id="smoke-spawn-button" title="Spawn smoke" data-on-click="mapContextMenuShow"
data-on-click-params='{ "type": "smoke" }' class="ol-contexmenu-button"><img src="/resources/theme/images/buttons/spawn/smoke.svg" inject-svg></button>
<button data-coalition="blue" id="explosion-spawn-button" title="Explosion" data-on-click="mapContextMenuShow"
data-on-click-params='{ "type": "explosion" }' class="ol-contexmenu-button"><img src="/resources/theme/images/buttons/spawn/explosion.svg" inject-svg></button>
<button data-coalition="blue" id="coalition-area-button" title="Edit coalition area" data-on-click="editCoalitionArea"
class="ol-contexmenu-button"><img src="/resources/theme/images/buttons/other/edit.svg" inject-svg></button>
</div>
<div id="aircraft-spawn-menu" class="ol-contexmenu-panel ol-panel hide">
<div class="ol-select-container">
@ -229,36 +235,49 @@
class="ol-contexmenu-button"><img src="/resources/theme/images/buttons/other/delete.svg" inject-svg></button>
</div>
<div id="iads-menu" class="ol-panel ol-contexmenu-panel hide">
<div id="iads-units-role-options" class="ol-select">
<div id="iads-units-type-options" class="ol-select">
<div class="ol-select-value">Unit types</div>
<div class="ol-select-options">
<!-- This is where all the iads unit roles checkboxes will be shown-->
<!-- This is where all the iads unit types checkboxes will be shown-->
</div>
</div>
<!--
<div class="ol-select-container">
<div id="iads-period-options" class="ol-select">
<div class="ol-select-value">Units period</div>
<div id="iads-era-options" class="ol-select">
<div class="ol-select-value">Units eras</div>
<div class="ol-select-options">
<!-- This is where all the iads unit period buttons will be shown--><!--
<!-- This is where all the iads unit era buttons will be shown-->
</div>
</div>
</div>
<div class="ol-select-container">
<div id="iads-range-options" class="ol-select">
<div class="ol-select-value">Units ranges</div>
<div class="ol-select-options">
<!-- This is where all the iads unit range buttons will be shown-->
</div>
</div>
</div>
<!--
<div id="coalition-units-checkbox" class="ol-checkbox">
<label title="Use coalition specific units only (e.g. Patriot sites for blue coalition, SA-2s for red coalition)">
<input type="checkbox"/>
Coalition specific units
</label>
</div>
-->
-->
<div id="iads-density-slider" class="ol-slider-container">
<dl class="ol-data-grid">
<dt> IADS density </dt> <dd> <div class="ol-slider-value"></div> </dd>
</dl>
<input type="range" min="0" max="100" value="0" class="ol-slider">
<input title="An high density value will cause more units to be deployed" type="range" min="0" max="100" value="0" class="ol-slider">
</div>
<div id="iads-distribution-slider" class="ol-slider-container">
<dl class="ol-data-grid">
<dt> IADS distribution </dt> <dd> <div class="ol-slider-value"></div> </dd>
</dl>
<input title="If distrubution is low units will be concentrated around towns, otherwise they will spread around the map more evenly" type="range" min="0" max="100" value="0" class="ol-slider">
</div>
<button class="create-iads-button" title="" data-coalition="blue" data-on-click="contextMenuCreateIads">Add units to IADS</button>
</div>