mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Tweaks to IADS creation and menus
This commit is contained in:
parent
439111f7a0
commit
f379f6b998
@ -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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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%;
|
||||
}
|
||||
70
client/public/themes/olympus/images/buttons/spawn/more.svg
Normal file
70
client/public/themes/olympus/images/buttons/spawn/more.svg
Normal 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 |
2
client/src/@types/unitdatabase.d.ts
vendored
2
client/src/@types/unitdatabase.d.ts
vendored
@ -14,7 +14,7 @@ interface LoadoutBlueprint {
|
||||
|
||||
interface UnitBlueprint {
|
||||
name: string;
|
||||
era?: string[];
|
||||
era: string[];
|
||||
label: string;
|
||||
shortLabel: string;
|
||||
type?: string;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
|
||||
@ -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];
|
||||
}
|
||||
|
||||
7137
client/src/units/citiesDatabase.ts
Normal file
7137
client/src/units/citiesDatabase.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -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": "",
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user