mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Splitted weapons and units managers
This commit is contained in:
4004
client/src/unit/aircraftdatabase.ts
Normal file
4004
client/src/unit/aircraftdatabase.ts
Normal file
File diff suppressed because it is too large
Load Diff
7137
client/src/unit/citiesDatabase.ts
Normal file
7137
client/src/unit/citiesDatabase.ts
Normal file
File diff suppressed because it is too large
Load Diff
1488
client/src/unit/groundunitdatabase.ts
Normal file
1488
client/src/unit/groundunitdatabase.ts
Normal file
File diff suppressed because it is too large
Load Diff
621
client/src/unit/helicopterdatabase.ts
Normal file
621
client/src/unit/helicopterdatabase.ts
Normal file
@@ -0,0 +1,621 @@
|
||||
import { getMissionHandler } from "..";
|
||||
import { GAME_MASTER } from "../constants/constants";
|
||||
import { UnitDatabase } from "./unitdatabase"
|
||||
|
||||
export class HelicopterDatabase extends UnitDatabase {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.blueprints = {
|
||||
"AH-64D_BLK_II": {
|
||||
"name": "AH-64D_BLK_II",
|
||||
"coalition": "blue",
|
||||
"era": "Modern",
|
||||
"label": "AH-64D Apache",
|
||||
"shortLabel": "AH64",
|
||||
"loadouts": [
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "AGM-114k Hellfire",
|
||||
"quantity": 8
|
||||
},
|
||||
{
|
||||
"name": "M151 Rocket Pod",
|
||||
"quantity": 2
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"CAS"
|
||||
],
|
||||
"code": "2 * M261: M151 (6PD), 2 * Hellfire station: 4*AGM-114K",
|
||||
"name": "Gun / ATGM / Rocket"
|
||||
},
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "AGM-114K Hellfire",
|
||||
"quantity": 16
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"CAS"
|
||||
],
|
||||
"code": "4 * Hellfire station: 4*AGM-114K",
|
||||
"name": "Gun / ATGM"
|
||||
},
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
|
||||
],
|
||||
"roles": [
|
||||
""
|
||||
],
|
||||
"code": "",
|
||||
"name": "Empty Loadout"
|
||||
}
|
||||
],
|
||||
"filename": "ah-64.png"
|
||||
},
|
||||
"Ka-50_3": {
|
||||
"name": "Ka-50_3",
|
||||
"coalition": "red",
|
||||
"era": "Late Cold War",
|
||||
"label": "Ka-50 Hokum A",
|
||||
"shortLabel": "K50",
|
||||
"loadouts": [
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "Igla",
|
||||
"quantity": 4
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"CAP"
|
||||
],
|
||||
"code": "4xIgla",
|
||||
"name": "Gun / Fox 2"
|
||||
},
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "Igla",
|
||||
"quantity": 4
|
||||
},
|
||||
{
|
||||
"name": "S-13",
|
||||
"quantity": 10
|
||||
},
|
||||
{
|
||||
"name": "Kh-25ML",
|
||||
"quantity": 2
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"Anti-Ship"
|
||||
],
|
||||
"code": "2xKh-25ML, 10xS-13, 4xIgla",
|
||||
"name": "Gun / ASM / Rockets / Fox 2"
|
||||
},
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "Igla",
|
||||
"quantity": 4
|
||||
},
|
||||
{
|
||||
"name": "S-80FP",
|
||||
"quantity": 40
|
||||
},
|
||||
{
|
||||
"name": "Vikhr-M",
|
||||
"quantity": 12
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"CAS"
|
||||
],
|
||||
"code": "12x9A4172, 40xS-8OFP, 4xIgla",
|
||||
"name": "Gun / ATGM / Rockets / Fox 2"
|
||||
},
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "Igla",
|
||||
"quantity": 4
|
||||
},
|
||||
{
|
||||
"name": "S-80FP",
|
||||
"quantity": 40
|
||||
},
|
||||
{
|
||||
"name": "Vikhr-M",
|
||||
"quantity": 12
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"CAS"
|
||||
],
|
||||
"code": "12x9A4172, 40xS-8OFP, 4xIgla",
|
||||
"name": "Gun / ATGM"
|
||||
},
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "Igla",
|
||||
"quantity": 4
|
||||
},
|
||||
{
|
||||
"name": "FAB-500",
|
||||
"quantity": 2
|
||||
},
|
||||
{
|
||||
"name": "S-13",
|
||||
"quantity": 10
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"Strike"
|
||||
],
|
||||
"code": "10xS-13, 2xFAB-500, 4xIgla",
|
||||
"name": "Gun / Bombs / Rockets / Fox 2"
|
||||
},
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
|
||||
],
|
||||
"roles": [
|
||||
""
|
||||
],
|
||||
"code": "",
|
||||
"name": "Empty Loadout"
|
||||
}
|
||||
],
|
||||
"filename": "ka-50.png"
|
||||
},
|
||||
"Mi-24P": {
|
||||
"name": "Mi-24P",
|
||||
"coalition": "red",
|
||||
"era": "Mid Cold War",
|
||||
"label": "Mi-24P Hind",
|
||||
"shortLabel": "Mi24",
|
||||
"loadouts": [
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "S-8KOM",
|
||||
"quantity": 40
|
||||
},
|
||||
{
|
||||
"name": "9M114 ATGM",
|
||||
"quantity": 8
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"CAS"
|
||||
],
|
||||
"code": "2xB8V20 (S-8KOM)+8xATGM 9M114",
|
||||
"name": "Gun / ATGM / Rockets"
|
||||
},
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "S-24B",
|
||||
"quantity": 4
|
||||
},
|
||||
{
|
||||
"name": "9M114 ATGM",
|
||||
"quantity": 4
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"Strike"
|
||||
],
|
||||
"code": "4xS-24B+4xATGM 9M114",
|
||||
"name": "Gun / ATGM / Rockets"
|
||||
},
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "GUV-1 Grenade Launcher",
|
||||
"quantity": 4
|
||||
},
|
||||
{
|
||||
"name": "9M114 ATGM",
|
||||
"quantity": 4
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"CAS"
|
||||
],
|
||||
"code": "4xGUV-1 AP30+4xATGM 9M114",
|
||||
"name": "Gun / ATGM / Grenade Launcher"
|
||||
},
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
|
||||
],
|
||||
"roles": [
|
||||
""
|
||||
],
|
||||
"code": "",
|
||||
"name": "Empty Loadout"
|
||||
}
|
||||
],
|
||||
"filename": "mi-24.png"
|
||||
},
|
||||
"SA342L": {
|
||||
"name": "SA342L",
|
||||
"coalition": "blue",
|
||||
"era": "Mid Cold War",
|
||||
"label": "SA342L Gazelle",
|
||||
"shortLabel": "342",
|
||||
"loadouts": [
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "20mm Cannon",
|
||||
"quantity": 1
|
||||
},
|
||||
{
|
||||
"name": "SNEB68",
|
||||
"quantity": 8
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"Recon"
|
||||
],
|
||||
"code": "M621, 8xSNEB68 EAP",
|
||||
"name": "Gun / ATGM / Rockets"
|
||||
}
|
||||
],
|
||||
"filename": "sa-342.png"
|
||||
},
|
||||
"SA342M": {
|
||||
"name": "SA342M",
|
||||
"coalition": "blue",
|
||||
"era": "Mid Cold War",
|
||||
"label": "SA342M Gazelle",
|
||||
"shortLabel": "342",
|
||||
"loadouts": [
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "HOT3",
|
||||
"quantity": 4
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"CAS"
|
||||
],
|
||||
"code": "HOT3x4",
|
||||
"name": "ATGM"
|
||||
}
|
||||
],
|
||||
"filename": "sa-342.png"
|
||||
},
|
||||
"SA342Mistral": {
|
||||
"name": "SA342Mistral",
|
||||
"coalition": "blue",
|
||||
"era": "Mid Cold War",
|
||||
"label": "SA342Mistral Gazelle",
|
||||
"shortLabel": "342",
|
||||
"loadouts": [
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "Mistral",
|
||||
"quantity": 4
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"CAP"
|
||||
],
|
||||
"code": "Mistral x 4",
|
||||
"name": "Fox 2"
|
||||
},
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
|
||||
],
|
||||
"roles": [
|
||||
""
|
||||
],
|
||||
"code": "",
|
||||
"name": "Empty Loadout"
|
||||
}
|
||||
],
|
||||
"filename": "sa-342.png"
|
||||
},
|
||||
"AH-1W": {
|
||||
"name": "AH-1W",
|
||||
"coalition": "blue",
|
||||
"era": "Mid Cold War",
|
||||
"label": "AH-1W Cobra",
|
||||
"shortLabel": "AH1",
|
||||
"loadouts": [
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "BGM-71 TOW",
|
||||
"quantity": 8
|
||||
},
|
||||
{
|
||||
"name": "Hydra-70 WP",
|
||||
"quantity": 38
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"CAS"
|
||||
],
|
||||
"code": "8xBGM-71, 38xHYDRA-70 WP",
|
||||
"name": "TOW / Hydra"
|
||||
},
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "Hydra-70",
|
||||
"quantity": 76
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"CAS"
|
||||
],
|
||||
"code": "76xHYDRA-70",
|
||||
"name": "Hydra"
|
||||
},
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
|
||||
],
|
||||
"roles": [
|
||||
""
|
||||
],
|
||||
"code": "",
|
||||
"name": "Empty Loadout"
|
||||
}
|
||||
],
|
||||
"filename": "ah-1.png"
|
||||
},
|
||||
"Mi-26": {
|
||||
"name": "Mi-26",
|
||||
"coalition": "red",
|
||||
"era": "Late Cold War",
|
||||
"label": "Mi-26 Halo",
|
||||
"shortLabel": "M26",
|
||||
"loadouts": [
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
|
||||
],
|
||||
"roles": [
|
||||
"Transport"
|
||||
],
|
||||
"code": "",
|
||||
"name": "Empty Loadout"
|
||||
}
|
||||
],
|
||||
"filename": "mi-26.png"
|
||||
},
|
||||
"Mi-28N": {
|
||||
"name": "Mi-28N",
|
||||
"coalition": "red",
|
||||
"era": "Modern",
|
||||
"label": "Mi-28N Havoc",
|
||||
"shortLabel": "M28",
|
||||
"loadouts": [
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "9M114 Shturm",
|
||||
"quantity": 16
|
||||
},
|
||||
{
|
||||
"name": "S-8",
|
||||
"quantity": 40
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"CAS"
|
||||
],
|
||||
"code": "16x9M114, 40xS-8",
|
||||
"name": "ATGM / S-8"
|
||||
},
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
|
||||
],
|
||||
"roles": [
|
||||
""
|
||||
],
|
||||
"code": "",
|
||||
"name": "Empty Loadout"
|
||||
}
|
||||
],
|
||||
"filename": "mi-28.png"
|
||||
},
|
||||
"Mi-8MT": {
|
||||
"name": "Mi-8MT",
|
||||
"coalition": "red",
|
||||
"era": "Mid Cold War",
|
||||
"label": "Mi-8MT Hip",
|
||||
"shortLabel": "Mi8",
|
||||
"loadouts": [
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "UPK",
|
||||
"quantity": 2
|
||||
},
|
||||
{
|
||||
"name": "B8",
|
||||
"quantity": 2
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"CAS"
|
||||
],
|
||||
"code": "2 x UPK +2 x B8",
|
||||
"name": "Rockets / Gunpods"
|
||||
},
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
|
||||
],
|
||||
"roles": [
|
||||
"Transport"
|
||||
],
|
||||
"code": "",
|
||||
"name": "Empty Loadout"
|
||||
}
|
||||
],
|
||||
"filename": "mi-8.png"
|
||||
},
|
||||
"SH-60B": {
|
||||
"name": "SH-60B",
|
||||
"coalition": "blue",
|
||||
"era": "Mid Cold War",
|
||||
"label": "SH-60B Seahawk",
|
||||
"shortLabel": "S60",
|
||||
"loadouts": [
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "AGM-119 ASM",
|
||||
"quantity": 1
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"CAS"
|
||||
],
|
||||
"code": "AGM-119",
|
||||
"name": "ASM"
|
||||
},
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
|
||||
],
|
||||
"roles": [
|
||||
"Transport"
|
||||
],
|
||||
"code": "",
|
||||
"name": "Empty Loadout"
|
||||
}
|
||||
],
|
||||
"filename": "uh-60.png"
|
||||
},
|
||||
"UH-60A": {
|
||||
"name": "UH-60A",
|
||||
"coalition": "blue",
|
||||
"era": "Mid Cold War",
|
||||
"label": "UH-60A Blackhawk",
|
||||
"shortLabel": "U60",
|
||||
"loadouts": [
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
|
||||
],
|
||||
"roles": [
|
||||
"Transport"
|
||||
],
|
||||
"code": "",
|
||||
"name": "Empty Loadout"
|
||||
}
|
||||
],
|
||||
"filename": "uh-60.png"
|
||||
},
|
||||
"UH-1H": {
|
||||
"name": "UH-1H",
|
||||
"coalition": "blue",
|
||||
"era": "Early Cold War",
|
||||
"label": "UH-1H Huey",
|
||||
"shortLabel": "UH1",
|
||||
"loadouts": [
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
{
|
||||
"name": "M134 Minigun",
|
||||
"quantity": 2
|
||||
},
|
||||
{
|
||||
"name": "XM-158",
|
||||
"quantity": 2
|
||||
}
|
||||
],
|
||||
"roles": [
|
||||
"CAS"
|
||||
],
|
||||
"code": "M134 Minigun*2, XM158*2",
|
||||
"name": "Miniguns / XM158"
|
||||
},
|
||||
{
|
||||
"fuel": 1,
|
||||
"items": [
|
||||
],
|
||||
"roles": [
|
||||
"Transport"
|
||||
],
|
||||
"code": "",
|
||||
"name": "Empty Loadout"
|
||||
}
|
||||
],
|
||||
"filename": "uh-1.png"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getSpawnPointsByName(name: string) {
|
||||
if (getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER || !getMissionHandler().getCommandModeOptions().restrictSpawns)
|
||||
return 0;
|
||||
|
||||
const blueprint = this.getByName(name);
|
||||
if (blueprint?.era == "WW2")
|
||||
return 20;
|
||||
else if (blueprint?.era == "Early Cold War")
|
||||
return 50;
|
||||
else if (blueprint?.era == "Mid Cold War")
|
||||
return 100;
|
||||
else if (blueprint?.era == "Late Cold War")
|
||||
return 200;
|
||||
else if (blueprint?.era == "Modern")
|
||||
return 400;
|
||||
return 0;
|
||||
}
|
||||
|
||||
getCategory() {
|
||||
return "Helicopter";
|
||||
}
|
||||
}
|
||||
|
||||
export var helicopterDatabase = new HelicopterDatabase();
|
||||
|
||||
486
client/src/unit/navyunitdatabase.ts
Normal file
486
client/src/unit/navyunitdatabase.ts
Normal file
@@ -0,0 +1,486 @@
|
||||
import { getMissionHandler } from "..";
|
||||
import { GAME_MASTER } from "../constants/constants";
|
||||
import { UnitDatabase } from "./unitdatabase"
|
||||
|
||||
export class NavyUnitDatabase extends UnitDatabase {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.blueprints = {
|
||||
"Type_052B": {
|
||||
"name": "Type_052B",
|
||||
"coalition": "red",
|
||||
"type": "Destroyer",
|
||||
"era": "Modern",
|
||||
"label": "052B DDG-168 Guangzhou",
|
||||
"shortLabel": "Type 52B",
|
||||
"range": "Short",
|
||||
"filename": ""
|
||||
},
|
||||
"Type_052C": {
|
||||
"name": "Type_052C",
|
||||
"coalition": "red",
|
||||
"type": "Destroyer",
|
||||
"era": "Modern",
|
||||
"label": "052C DDG-171 Haikou",
|
||||
"shortLabel": "Type 52C",
|
||||
"range": "Short",
|
||||
"filename": ""
|
||||
},
|
||||
"Type_054A": {
|
||||
"name": "",
|
||||
"coalition": "red",
|
||||
"type": "Frigate",
|
||||
"era": "Modern",
|
||||
"label": "054A FFG-538 Yantai",
|
||||
"shortLabel": "Type 54A",
|
||||
"range": "Medium",
|
||||
"filename": ""
|
||||
},
|
||||
"Type_071": {
|
||||
"name": "Type_071",
|
||||
"coalition": "red",
|
||||
"type": "Transport",
|
||||
"era": "Modern",
|
||||
"label": "Type 071",
|
||||
"shortLabel": "Type 071",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"Type_093": {
|
||||
"name": "Type_093",
|
||||
"coalition": "red",
|
||||
"type": "Submarine",
|
||||
"era": "Modern",
|
||||
"label": "Type 093",
|
||||
"shortLabel": "Type 093",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"santafe": {
|
||||
"name": "santafe",
|
||||
"coalition": "",
|
||||
"type": "Submarine",
|
||||
"era": "Early Cold War",
|
||||
"label": "ARA Santa Fe S-21",
|
||||
"shortLabel": "ARA Santa",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"ara_vdm": {
|
||||
"name": "ara_vdm",
|
||||
"coalition": "",
|
||||
"type": "Aircraft Carrier",
|
||||
"era": "Mid Cold War",
|
||||
"label": "ARA Vienticinco de Mayo",
|
||||
"shortLabel": "ARA Vienticinco de Mayo",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"kuznecow": {
|
||||
"name": "kuznecow",
|
||||
"coalition": "red",
|
||||
"type": "Aircraft Carrier",
|
||||
"era": "Late Cold War",
|
||||
"label": "Admiral Kuznetsov",
|
||||
"shortLabel": "Admiral Kuznetsov",
|
||||
"range": "Medium",
|
||||
"filename": ""
|
||||
},
|
||||
"albatros": {
|
||||
"name": "albatros",
|
||||
"coalition": "red",
|
||||
"type": "Aircraft Carrier",
|
||||
"era": "Early Cold War",
|
||||
"label": "Albatros (Grisha-5)",
|
||||
"shortLabel": "Albatros",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"leander-gun-condell": {
|
||||
"name": "leander-gun-condell",
|
||||
"coalition": "",
|
||||
"type": "Frigate",
|
||||
"era": "Mid Cold War",
|
||||
"label": "Almirante Condell PFG-06",
|
||||
"shortLabel": "Almirante Condell",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"Boat Armed Hi-Speed": {
|
||||
"name": "Boat Armed Hi-Speed",
|
||||
"coalition": "",
|
||||
"type": "Fast Attack Craft",
|
||||
"era": "Mid Cold War",
|
||||
"label": "Boat Armed Hi-Speed",
|
||||
"shortLabel": "Boat Armed Hi-Speed",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"HandyWind": {
|
||||
"name": "HandyWind",
|
||||
"coalition": "blue",
|
||||
"type": "Cargoship",
|
||||
"era": "Late Cold War",
|
||||
"label": "Bulker Handy Wind",
|
||||
"shortLabel": "Bulker Handy Wind",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"CV_1143_5": {
|
||||
"name": "CV_1143_5",
|
||||
"coalition": "red",
|
||||
"type": "Aircraft Carrier",
|
||||
"era": "Modern",
|
||||
"label": "CV Admiral Kuznetsov(2017)",
|
||||
"shortLabel": "Admiral Kuznetsov(2017)",
|
||||
"range": "Medium",
|
||||
"filename": ""
|
||||
},
|
||||
"CV_59": {
|
||||
"name": "CV_59",
|
||||
"coalition": "blue",
|
||||
"type": "Aircraft Carrier",
|
||||
"era": "Early Cold War",
|
||||
"label": "CV-59 Forrestal",
|
||||
"shortLabel": "CV-59",
|
||||
"range": "Short",
|
||||
"filename": ""
|
||||
},
|
||||
"CVN_71": {
|
||||
"name": "CVN_71",
|
||||
"coalition": "blue",
|
||||
"type": "Super Aircraft Carrier",
|
||||
"era": "Late Cold War",
|
||||
"label": "CVN-71 Theodore Roosevelt",
|
||||
"shortLabel": "CVN-71",
|
||||
"range": "Short",
|
||||
"filename": ""
|
||||
},
|
||||
"CVN_72": {
|
||||
"name": "CVN_72",
|
||||
"coalition": "blue",
|
||||
"type": "Super Aircraft Carrier",
|
||||
"era": "Late Cold War",
|
||||
"label": "CVN-72 Abraham Lincoln",
|
||||
"shortLabel": "CVN-72",
|
||||
"range": "Short",
|
||||
"filename": ""
|
||||
},
|
||||
"CVN_73": {
|
||||
"name": "CVN_73",
|
||||
"coalition": "blue",
|
||||
"type": "Super Aircraft Carrier",
|
||||
"era": "Late Cold War",
|
||||
"label": "CVN-73 George Washington",
|
||||
"shortLabel": "CVN-73",
|
||||
"range": "Medium",
|
||||
"filename": ""
|
||||
},
|
||||
"Stennis": {
|
||||
"name": "Stennis",
|
||||
"coalition": "blue",
|
||||
"type": "Aircraft Carrier",
|
||||
"era": "Late Cold War",
|
||||
"label": "CVN-74 John C. Stennis",
|
||||
"shortLabel": "CVN-74",
|
||||
"range": "Medium",
|
||||
"filename": ""
|
||||
},
|
||||
"CVN_75": {
|
||||
"name": "CVN_75",
|
||||
"coalition": "blue",
|
||||
"type": "Aircraft Carrier",
|
||||
"era": "Late Cold War",
|
||||
"label": "CVN-75 Harry S. Truman",
|
||||
"shortLabel": "CVN-75",
|
||||
"range": "Medium",
|
||||
"filename": ""
|
||||
},
|
||||
"CastleClass_01": {
|
||||
"name": "CastleClass_01",
|
||||
"coalition": "blue",
|
||||
"type": "Patrol",
|
||||
"era": "Mid Cold War",
|
||||
"label": "HMS Leeds Castle (P-258)",
|
||||
"shortLabel": "HMS Leeds Castle (P-258)",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"USS_Arleigh_Burke_IIa": {
|
||||
"name": "USS_Arleigh_Burke_IIa",
|
||||
"coalition": "blue",
|
||||
"type": "Destroyer",
|
||||
"era": "Late Cold War",
|
||||
"label": "DDG Arleigh Burke lla",
|
||||
"shortLabel": "DDG Arleigh Burke",
|
||||
"range": "Medium",
|
||||
"filename": ""
|
||||
},
|
||||
"barge-1": {
|
||||
"name": "barge-1",
|
||||
"coalition": "red",
|
||||
"type": "Cargoship",
|
||||
"era": "Late Cold War",
|
||||
"label": "Dry cargo ship Ivanov",
|
||||
"shortLabel": "Dry cargo ship Ivanov",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"barge-2": {
|
||||
"name": "barge-2",
|
||||
"coalition": "red",
|
||||
"type": "Cargoship",
|
||||
"era": "Late Cold War",
|
||||
"label": "Dry cargo ship Yakushev",
|
||||
"shortLabel": "Dry cargo ship Yakushev",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"elnya": {
|
||||
"name": "elnya",
|
||||
"coalition": "red",
|
||||
"type": "Tanker",
|
||||
"era": "Late Cold War",
|
||||
"label": "Elnya tanker",
|
||||
"shortLabel": "Elnya tanker",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"La_Combattante_II": {
|
||||
"name": "La_Combattante_II",
|
||||
"coalition": "blue",
|
||||
"type": "Fast Attack Craft",
|
||||
"era": "Mid Cold War",
|
||||
"label": "FAC La Combattante lla",
|
||||
"shortLabel": "FAC La Combattante",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"leander-gun-achilles": {
|
||||
"name": "leander-gun-achilles",
|
||||
"coalition": "blue",
|
||||
"type": "Frigate",
|
||||
"era": "Mid Cold War",
|
||||
"label": "HMS Achilles (F12)",
|
||||
"shortLabel": "HMS Achilles",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"leander-gun-andromeda": {
|
||||
"name": "leander-gun-andromeda",
|
||||
"coalition": "blue",
|
||||
"type": "Frigate",
|
||||
"era": "Mid Cold War",
|
||||
"label": "HMS Andromeda (F57)",
|
||||
"shortLabel": "HMS Andromeda",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"leander-gun-ariadne": {
|
||||
"name": "leander-gun-ariadne",
|
||||
"coalition": "blue",
|
||||
"type": "Frigate",
|
||||
"era": "Mid Cold War",
|
||||
"label": "HMS Ariadne (F72)",
|
||||
"shortLabel": "HMS Ariadne",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"leander-gun-lynch": {
|
||||
"name": "leander-gun-lynch",
|
||||
"coalition": "",
|
||||
"type": "Frigate",
|
||||
"era": "Mid Cold War",
|
||||
"label": "CNS Almirante Lynch (PFG-07)",
|
||||
"shortLabel": "CNS Almirante Lynch",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"hms_invincible": {
|
||||
"name": "hms_invincible",
|
||||
"coalition": "blue",
|
||||
"type": "Aircraft Carrier",
|
||||
"era": "Mid Cold War",
|
||||
"label": "HMS Invincible (R05)",
|
||||
"shortLabel": "HMS Invincible",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"HarborTug": {
|
||||
"name": "HarborTug",
|
||||
"coalition": "",
|
||||
"type": "Tug",
|
||||
"era": "Mid Cold War",
|
||||
"label": "Harbor Tug",
|
||||
"shortLabel": "Harbor Tug",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"kilo_636": {
|
||||
"name": "kilo_636",
|
||||
"coalition": "red",
|
||||
"type": "Submarine",
|
||||
"era": "Late Cold War",
|
||||
"label": "Project 636 Varshavyanka Improved",
|
||||
"shortLabel": "Varshavyanka Improved",
|
||||
"range": "Medium",
|
||||
"filename": ""
|
||||
},
|
||||
"kilo": {
|
||||
"name": "kilo",
|
||||
"coalition": "red",
|
||||
"type": "Submarine",
|
||||
"era": "Late Cold War",
|
||||
"label": "Project 636 Varshavyanka Basic",
|
||||
"shortLabel": "Varshavyanka Basic",
|
||||
"range": "Medium",
|
||||
"filename": ""
|
||||
},
|
||||
"LHA_Tarawa": {
|
||||
"name": "LHA_Tarawa",
|
||||
"coalition": "blue",
|
||||
"type": "Aircraft Carrier",
|
||||
"era": "Mid Cold War",
|
||||
"label": "LHA-1 Tarawa",
|
||||
"shortLabel": "LHA-1 Tarawa",
|
||||
"range": "Short",
|
||||
"filename": ""
|
||||
},
|
||||
"BDK-775": {
|
||||
"name": "BDK-775",
|
||||
"coalition": "blue",
|
||||
"type": "Landing Craft",
|
||||
"era": "Mid Cold War",
|
||||
"label": "LS Ropucha",
|
||||
"shortLabel": "LS Ropucha",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"molniya": {
|
||||
"name": "molniya",
|
||||
"coalition": "",
|
||||
"type": "Fast Attack Craft",
|
||||
"era": "Late Cold War",
|
||||
"label": "Molniya (Tarantul-3)",
|
||||
"shortLabel": "Molniya",
|
||||
"range": "Short",
|
||||
"filename": ""
|
||||
},
|
||||
"moscow": {
|
||||
"name": "moscow",
|
||||
"coalition": "red",
|
||||
"type": "Cruiser",
|
||||
"era": "Late Cold War",
|
||||
"label": "Moscow",
|
||||
"shortLabel": "Moscow",
|
||||
"range": "Medium",
|
||||
"filename": ""
|
||||
},
|
||||
"neustrash": {
|
||||
"name": "neustrash",
|
||||
"coalition": "red",
|
||||
"type": "Frigate",
|
||||
"era": "Late Cold War",
|
||||
"label": "Neustrashimy",
|
||||
"shortLabel": "Neustrashimy",
|
||||
"range": "Short",
|
||||
"filename": ""
|
||||
},
|
||||
"perry": {
|
||||
"name": "perry",
|
||||
"coalition": "blue",
|
||||
"type": "Frigate",
|
||||
"era": "Mid Cold War",
|
||||
"label": "Oliver H. Perry",
|
||||
"shortLabel": "Oliver H. Perry",
|
||||
"range": "Medium",
|
||||
"filename": ""
|
||||
},
|
||||
"piotr_velikiy": {
|
||||
"name": "piotr_velikiy",
|
||||
"coalition": "red",
|
||||
"type": "Cruiser",
|
||||
"era": "Late Cold War",
|
||||
"label": "Pyotr Velikiy",
|
||||
"shortLabel": "Pyotr Velikiy",
|
||||
"range": "Medium",
|
||||
"filename": ""
|
||||
},
|
||||
"rezky": {
|
||||
"name": "Rezky (Krivak-2)",
|
||||
"coalition": "red",
|
||||
"type": "Frigate",
|
||||
"era": "Early Cold War",
|
||||
"label": "Rezky (Krivak-2)",
|
||||
"shortLabel": "Rezky",
|
||||
"range": "Short",
|
||||
"filename": ""
|
||||
},
|
||||
"Ship_Tilde_Supply": {
|
||||
"name": "Ship_Tilde_Supply",
|
||||
"coalition": "blue",
|
||||
"type": "Transport",
|
||||
"era": "Late Cold War",
|
||||
"label": "Supply Ship MV Tilde",
|
||||
"shortLabel": "Supply Ship Tilde",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"Seawise_Giant": {
|
||||
"name": "Seawise_Giant",
|
||||
"coalition": "blue",
|
||||
"type": "Tanker",
|
||||
"era": "Late Cold War",
|
||||
"label": "Tanker Seawise Giant",
|
||||
"shortLabel": "Seawise Giant",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
},
|
||||
"TICONDEROG": {
|
||||
"name": "TICONDEROG",
|
||||
"coalition": "blue",
|
||||
"type": "Cruiser",
|
||||
"era": "Late Cold War",
|
||||
"label": "Ticonderoga",
|
||||
"shortLabel": "Ticonderoga",
|
||||
"range": "Medium",
|
||||
"filename": ""
|
||||
},
|
||||
"zwezdny": {
|
||||
"name": "zwezdny",
|
||||
"coalition": "",
|
||||
"type": "Civilian Boat",
|
||||
"era": "Modern",
|
||||
"label": "Zwezdny",
|
||||
"shortLabel": "Zwezdny",
|
||||
"range": "",
|
||||
"filename": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getSpawnPointsByName(name: string) {
|
||||
if (getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER || !getMissionHandler().getCommandModeOptions().restrictSpawns)
|
||||
return 0;
|
||||
|
||||
const blueprint = this.getByName(name);
|
||||
if (blueprint?.era == "WW2")
|
||||
return 20;
|
||||
else if (blueprint?.era == "Early Cold War")
|
||||
return 50;
|
||||
else if (blueprint?.era == "Mid Cold War")
|
||||
return 100;
|
||||
else if (blueprint?.era == "Late Cold War")
|
||||
return 200;
|
||||
else if (blueprint?.era == "Modern")
|
||||
return 400;
|
||||
return 0;
|
||||
}
|
||||
|
||||
getCategory() {
|
||||
return "NavyUnit";
|
||||
}
|
||||
}
|
||||
|
||||
export var navyUnitDatabase = new NavyUnitDatabase();
|
||||
1149
client/src/unit/unit.ts
Normal file
1149
client/src/unit/unit.ts
Normal file
File diff suppressed because it is too large
Load Diff
196
client/src/unit/unitdatabase.ts
Normal file
196
client/src/unit/unitdatabase.ts
Normal file
@@ -0,0 +1,196 @@
|
||||
import { LatLng } from "leaflet";
|
||||
import { getMissionHandler, getUnitsManager } from "..";
|
||||
import { GAME_MASTER } from "../constants/constants";
|
||||
|
||||
export class UnitDatabase {
|
||||
blueprints: { [key: string]: UnitBlueprint } = {};
|
||||
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
getCategory() {
|
||||
return "";
|
||||
}
|
||||
|
||||
/* Gets a specific blueprint by name */
|
||||
getByName(name: string) {
|
||||
if (name in this.blueprints)
|
||||
return this.blueprints[name];
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Gets a specific blueprint by label */
|
||||
getByLabel(label: string) {
|
||||
for (let unit in this.blueprints) {
|
||||
if (this.blueprints[unit].label === label)
|
||||
return this.blueprints[unit];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
getBlueprints() {
|
||||
if (getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER || !getMissionHandler().getCommandModeOptions().restrictSpawns)
|
||||
return this.blueprints;
|
||||
else {
|
||||
var filteredBlueprints: { [key: string]: UnitBlueprint } = {};
|
||||
for (let unit in this.blueprints) {
|
||||
const blueprint = this.blueprints[unit];
|
||||
if (this.getSpawnPointsByName(blueprint.name) <= getMissionHandler().getAvailableSpawnPoints() &&
|
||||
getMissionHandler().getCommandModeOptions().eras.includes(blueprint.era) &&
|
||||
(!getMissionHandler().getCommandModeOptions().restrictToCoalition || blueprint.coalition === getMissionHandler().getCommandedCoalition())) {
|
||||
filteredBlueprints[unit] = blueprint;
|
||||
}
|
||||
}
|
||||
return filteredBlueprints;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns a list of all possible roles in a database */
|
||||
getRoles() {
|
||||
var roles: string[] = [];
|
||||
var filteredBlueprints = this.getBlueprints();
|
||||
for (let unit in filteredBlueprints) {
|
||||
var loadouts = filteredBlueprints[unit].loadouts;
|
||||
if (loadouts) {
|
||||
for (let loadout of loadouts) {
|
||||
for (let role of loadout.roles) {
|
||||
if (role !== "" && !roles.includes(role))
|
||||
roles.push(role);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return roles;
|
||||
}
|
||||
|
||||
/* Returns a list of all possible types in a database */
|
||||
getTypes() {
|
||||
var filteredBlueprints = this.getBlueprints();
|
||||
var types: string[] = [];
|
||||
for (let unit in filteredBlueprints) {
|
||||
var type = filteredBlueprints[unit].type;
|
||||
if (type && type !== "" && !types.includes(type))
|
||||
types.push(type);
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
/* Returns a list of all possible periods in a database */
|
||||
getEras() {
|
||||
var filteredBlueprints = this.getBlueprints();
|
||||
var eras: string[] = [];
|
||||
for (let unit in filteredBlueprints) {
|
||||
var era = filteredBlueprints[unit].era;
|
||||
if (era && era !== "" && !eras.includes(era))
|
||||
eras.push(era);
|
||||
}
|
||||
return eras;
|
||||
}
|
||||
|
||||
/* Returns a list of all possible ranges in a database */
|
||||
getRanges() {
|
||||
var filteredBlueprints = this.getBlueprints();
|
||||
var ranges: string[] = [];
|
||||
for (let unit in filteredBlueprints) {
|
||||
var range = filteredBlueprints[unit].range;
|
||||
if (range && range !== "" && !ranges.includes(range))
|
||||
ranges.push(range);
|
||||
}
|
||||
return ranges;
|
||||
}
|
||||
|
||||
/* Get all blueprints by range */
|
||||
getByRange(range: string) {
|
||||
var filteredBlueprints = this.getBlueprints();
|
||||
var unitswithrange = [];
|
||||
for (let unit in filteredBlueprints) {
|
||||
if (filteredBlueprints[unit].range === range) {
|
||||
unitswithrange.push(filteredBlueprints[unit]);
|
||||
}
|
||||
}
|
||||
return unitswithrange;
|
||||
}
|
||||
|
||||
/* Get all blueprints by type */
|
||||
getByType(type: string) {
|
||||
var filteredBlueprints = this.getBlueprints();
|
||||
var units = [];
|
||||
for (let unit in filteredBlueprints) {
|
||||
if (filteredBlueprints[unit].type === type) {
|
||||
units.push(filteredBlueprints[unit]);
|
||||
}
|
||||
}
|
||||
return units;
|
||||
}
|
||||
|
||||
/* Get all blueprints by role */
|
||||
getByRole(role: string) {
|
||||
var filteredBlueprints = this.getBlueprints();
|
||||
var units = [];
|
||||
for (let unit in filteredBlueprints) {
|
||||
var loadouts = filteredBlueprints[unit].loadouts;
|
||||
if (loadouts) {
|
||||
for (let loadout of loadouts) {
|
||||
if (loadout.roles.includes(role) || loadout.roles.includes(role.toLowerCase())) {
|
||||
units.push(filteredBlueprints[unit])
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return units;
|
||||
}
|
||||
|
||||
/* Get the names of all the loadouts for a specific unit and for a specific role */
|
||||
getLoadoutNamesByRole(name: string, role: string) {
|
||||
var filteredBlueprints = this.getBlueprints();
|
||||
var loadoutsByRole = [];
|
||||
var loadouts = filteredBlueprints[name].loadouts;
|
||||
if (loadouts) {
|
||||
for (let loadout of loadouts) {
|
||||
if (loadout.roles.includes(role) || loadout.roles.includes("")) {
|
||||
loadoutsByRole.push(loadout.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
return loadoutsByRole;
|
||||
}
|
||||
|
||||
/* Get the loadout content from the unit name and loadout name */
|
||||
getLoadoutByName(name: string, loadoutName: string) {
|
||||
var loadouts = this.blueprints[name].loadouts;
|
||||
if (loadouts) {
|
||||
for (let loadout of loadouts) {
|
||||
if (loadout.name === loadoutName)
|
||||
return loadout;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
generateTestGrid(initialPosition: LatLng) {
|
||||
var filteredBlueprints = this.getBlueprints();
|
||||
const step = 0.01;
|
||||
var nUnits = Object.values(filteredBlueprints).length;
|
||||
var gridSize = Math.ceil(Math.sqrt(nUnits));
|
||||
Object.values(filteredBlueprints).forEach((unitBlueprint: UnitBlueprint, idx: number) => {
|
||||
var row = Math.floor(idx / gridSize);
|
||||
var col = idx - row * gridSize;
|
||||
var location = new LatLng(initialPosition.lat + col * step, initialPosition.lng + row * step)
|
||||
getUnitsManager().spawnUnits(this.getCategory(), [{unitType: unitBlueprint.name, location: location, altitude: 1000, loadout: ""}]);
|
||||
})
|
||||
}
|
||||
|
||||
getSpawnPointsByLabel(label: string) {
|
||||
var blueprint = this.getByLabel(label);
|
||||
if (blueprint)
|
||||
return this.getSpawnPointsByName(blueprint.name);
|
||||
else
|
||||
return Infinity;
|
||||
}
|
||||
|
||||
getSpawnPointsByName(name: string) {
|
||||
return Infinity;
|
||||
}
|
||||
}
|
||||
748
client/src/unit/unitsmanager.ts
Normal file
748
client/src/unit/unitsmanager.ts
Normal file
@@ -0,0 +1,748 @@
|
||||
import { LatLng, LatLngBounds } from "leaflet";
|
||||
import { getHotgroupPanel, getInfoPopup, getMap, getMissionHandler, getUnitsManager } from "..";
|
||||
import { Unit } from "./unit";
|
||||
import { cloneUnit, deleteUnit, spawnAircrafts, spawnGroundUnits, spawnHelicopters, spawnNavyUnits } from "../server/server";
|
||||
import { bearingAndDistanceToLatLng, deg2rad, keyEventWasInInput, latLngToMercator, mToFt, mercatorToLatLng, msToKnots, polyContains, polygonArea, randomPointInPoly, randomUnitBlueprint } from "../other/utils";
|
||||
import { CoalitionArea } from "../map/coalitionarea";
|
||||
import { groundUnitDatabase } from "./groundunitdatabase";
|
||||
import { DataIndexes, GAME_MASTER, IADSDensities, IDLE, MOVE_UNIT, NONE } from "../constants/constants";
|
||||
import { DataExtractor } from "../server/dataextractor";
|
||||
import { Contact } from "../@types/unit";
|
||||
import { citiesDatabase } from "./citiesDatabase";
|
||||
import { aircraftDatabase } from "./aircraftdatabase";
|
||||
import { helicopterDatabase } from "./helicopterdatabase";
|
||||
import { navyUnitDatabase } from "./navyunitdatabase";
|
||||
|
||||
export class UnitsManager {
|
||||
#units: { [ID: number]: Unit };
|
||||
#copiedUnits: any[];
|
||||
#selectionEventDisabled: boolean = false;
|
||||
#pasteDisabled: boolean = false;
|
||||
#hiddenTypes: string[] = [];
|
||||
#requestDetectionUpdate: boolean = false;
|
||||
|
||||
constructor() {
|
||||
this.#units = {};
|
||||
this.#copiedUnits = [];
|
||||
|
||||
document.addEventListener('copy', () => this.copyUnits());
|
||||
document.addEventListener('paste', () => this.pasteUnits());
|
||||
document.addEventListener('unitSelection', (e: CustomEvent) => this.#onUnitSelection(e.detail));
|
||||
document.addEventListener('unitDeselection', (e: CustomEvent) => this.#onUnitDeselection(e.detail));
|
||||
document.addEventListener('deleteSelectedUnits', () => this.selectedUnitsDelete());
|
||||
document.addEventListener('explodeSelectedUnits', () => this.selectedUnitsDelete(true));
|
||||
document.addEventListener('keyup', (event) => this.#onKeyUp(event));
|
||||
document.addEventListener('exportToFile', () => this.exportToFile());
|
||||
document.addEventListener('importFromFile', () => this.importFromFile());
|
||||
document.addEventListener('contactsUpdated', (e: CustomEvent) => {this.#requestDetectionUpdate = true});
|
||||
document.addEventListener("commandModeOptionsChanged", () => {Object.values(this.#units).forEach((unit: Unit) => unit.updateVisibility())});
|
||||
}
|
||||
|
||||
getSelectableAircraft() {
|
||||
const units = this.getUnits();
|
||||
return Object.keys(units).reduce((acc: { [key: number]: Unit }, unitId: any) => {
|
||||
if (units[unitId].getCategory() === "Aircraft" && units[unitId].getAlive() === true) {
|
||||
acc[unitId] = units[unitId];
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
getUnits() {
|
||||
return this.#units;
|
||||
}
|
||||
|
||||
getUnitByID(ID: number) {
|
||||
if (ID in this.#units)
|
||||
return this.#units[ID];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
getUnitsByHotgroup(hotgroup: number) {
|
||||
return Object.values(this.#units).filter((unit: Unit) => { return unit.getAlive() && unit.getHotgroup() == hotgroup });
|
||||
}
|
||||
|
||||
addUnit(ID: number, category: string) {
|
||||
if (category){
|
||||
/* The name of the unit category is exactly the same as the constructor name */
|
||||
var constructor = Unit.getConstructor(category);
|
||||
if (constructor != undefined) {
|
||||
this.#units[ID] = new constructor(ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update(buffer: ArrayBuffer) {
|
||||
var dataExtractor = new DataExtractor(buffer);
|
||||
var updateTime = Number(dataExtractor.extractUInt64());
|
||||
var requestRefresh = false;
|
||||
while (dataExtractor.getSeekPosition() < buffer.byteLength) {
|
||||
const ID = dataExtractor.extractUInt32();
|
||||
if (!(ID in this.#units)) {
|
||||
const datumIndex = dataExtractor.extractUInt8();
|
||||
if (datumIndex == DataIndexes.category) {
|
||||
const category = dataExtractor.extractString();
|
||||
this.addUnit(ID, category);
|
||||
}
|
||||
else {
|
||||
requestRefresh = true;
|
||||
}
|
||||
}
|
||||
this.#units[ID]?.setData(dataExtractor);
|
||||
}
|
||||
|
||||
if (this.#requestDetectionUpdate && getMissionHandler().getCommandModeOptions().commandMode != GAME_MASTER) {
|
||||
for (let ID in this.#units) {
|
||||
var unit = this.#units[ID];
|
||||
if (!unit.belongsToCommandedCoalition())
|
||||
unit.setDetectionMethods(this.getUnitDetectedMethods(unit));
|
||||
}
|
||||
this.#requestDetectionUpdate = false;
|
||||
}
|
||||
|
||||
for (let ID in this.#units) {
|
||||
if (this.#units[ID].getSelected())
|
||||
this.#units[ID].drawLines();
|
||||
};
|
||||
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
setHiddenType(key: string, value: boolean) {
|
||||
if (value) {
|
||||
if (this.#hiddenTypes.includes(key))
|
||||
delete this.#hiddenTypes[this.#hiddenTypes.indexOf(key)];
|
||||
}
|
||||
else
|
||||
this.#hiddenTypes.push(key);
|
||||
Object.values(this.getUnits()).forEach((unit: Unit) => unit.updateVisibility());
|
||||
}
|
||||
|
||||
getHiddenTypes() {
|
||||
return this.#hiddenTypes;
|
||||
}
|
||||
|
||||
selectUnit(ID: number, deselectAllUnits: boolean = true) {
|
||||
if (deselectAllUnits)
|
||||
this.getSelectedUnits().filter((unit: Unit) => unit.ID !== ID).forEach((unit: Unit) => unit.setSelected(false));
|
||||
this.#units[ID]?.setSelected(true);
|
||||
}
|
||||
|
||||
selectFromBounds(bounds: LatLngBounds) {
|
||||
this.deselectAllUnits();
|
||||
for (let ID in this.#units) {
|
||||
if (this.#units[ID].getHidden() == false) {
|
||||
var latlng = new LatLng(this.#units[ID].getPosition().lat, this.#units[ID].getPosition().lng);
|
||||
if (bounds.contains(latlng)) {
|
||||
this.#units[ID].setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getSelectedUnits(options?: { excludeHumans?: boolean, onlyOnePerGroup?: boolean }) {
|
||||
var selectedUnits = [];
|
||||
for (let ID in this.#units) {
|
||||
if (this.#units[ID].getSelected()) {
|
||||
selectedUnits.push(this.#units[ID]);
|
||||
}
|
||||
}
|
||||
if (options) {
|
||||
if (options.excludeHumans)
|
||||
selectedUnits = selectedUnits.filter((unit: Unit) => { return !unit.getHuman() });
|
||||
if (options.onlyOnePerGroup) {
|
||||
var temp: Unit[] = [];
|
||||
for (let unit of selectedUnits) {
|
||||
if (!temp.some((otherUnit: Unit) => unit.getGroupName() == otherUnit.getGroupName()))
|
||||
temp.push(unit);
|
||||
}
|
||||
selectedUnits = temp;
|
||||
}
|
||||
}
|
||||
return selectedUnits;
|
||||
}
|
||||
|
||||
deselectAllUnits() {
|
||||
for (let ID in this.#units) {
|
||||
this.#units[ID].setSelected(false);
|
||||
}
|
||||
}
|
||||
|
||||
selectUnitsByHotgroup(hotgroup: number) {
|
||||
this.deselectAllUnits();
|
||||
this.getUnitsByHotgroup(hotgroup).forEach((unit: Unit) => unit.setSelected(true))
|
||||
}
|
||||
|
||||
getSelectedUnitsTypes() {
|
||||
const selectedUnits = this.getSelectedUnits();
|
||||
if (selectedUnits.length == 0)
|
||||
return [];
|
||||
return selectedUnits.map((unit: Unit) => {
|
||||
return unit.getCategory();
|
||||
})?.filter((value: any, index: any, array: string[]) => {
|
||||
return array.indexOf(value) === index;
|
||||
});
|
||||
};
|
||||
|
||||
/* Gets the value of a variable from the selected units. If all the units have the same value, returns the value, else returns undefined */
|
||||
getSelectedUnitsVariable(variableGetter: CallableFunction) {
|
||||
const selectedUnits = this.getSelectedUnits();
|
||||
if (selectedUnits.length == 0)
|
||||
return undefined;
|
||||
return selectedUnits.map((unit: Unit) => {
|
||||
return variableGetter(unit);
|
||||
})?.reduce((a: any, b: any) => {
|
||||
return a === b ? a : undefined
|
||||
});
|
||||
};
|
||||
|
||||
getSelectedUnitsCoalition() {
|
||||
const selectedUnits = this.getSelectedUnits();
|
||||
if (selectedUnits.length == 0)
|
||||
return undefined;
|
||||
return selectedUnits.map((unit: Unit) => {
|
||||
return unit.getCoalition()
|
||||
})?.reduce((a: any, b: any) => {
|
||||
return a == b ? a : undefined
|
||||
});
|
||||
};
|
||||
|
||||
getByType(type: string) {
|
||||
Object.values(this.getUnits()).filter((unit: Unit) => {
|
||||
return unit.getType() === type;
|
||||
})
|
||||
}
|
||||
|
||||
getUnitDetectedMethods(unit: Unit) {
|
||||
var detectionMethods: number[] = [];
|
||||
for (let idx in this.#units) {
|
||||
if (this.#units[idx].getAlive() && this.#units[idx].getIsLeader() && this.#units[idx].getCoalition() !== "neutral" && this.#units[idx].getCoalition() != unit.getCoalition())
|
||||
{
|
||||
this.#units[idx].getContacts().forEach((contact: Contact) => {
|
||||
if (contact.ID == unit.ID && !detectionMethods.includes(contact.detectionMethod))
|
||||
detectionMethods.push(contact.detectionMethod);
|
||||
});
|
||||
}
|
||||
}
|
||||
return detectionMethods;
|
||||
}
|
||||
|
||||
/*********************** Actions on selected units ************************/
|
||||
selectedUnitsAddDestination(latlng: L.LatLng, mantainRelativePosition: boolean, rotation: number) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
|
||||
/* Compute the destination for each unit. If mantainRelativePosition is true, compute the destination so to hold the relative distances */
|
||||
var unitDestinations: { [key: number]: LatLng } = {};
|
||||
if (mantainRelativePosition)
|
||||
unitDestinations = this.selectedUnitsComputeGroupDestination(latlng, rotation);
|
||||
else
|
||||
selectedUnits.forEach((unit: Unit) => { unitDestinations[unit.ID] = latlng; });
|
||||
|
||||
for (let idx in selectedUnits) {
|
||||
const unit = selectedUnits[idx];
|
||||
/* If a unit is following another unit, and that unit is also selected, send the command to the followed unit */
|
||||
if (unit.getState() === "Follow") {
|
||||
const leader = this.getUnitByID(unit.getLeaderID())
|
||||
if (leader && leader.getSelected())
|
||||
leader.addDestination(latlng);
|
||||
else
|
||||
unit.addDestination(latlng);
|
||||
}
|
||||
else {
|
||||
if (unit.ID in unitDestinations)
|
||||
unit.addDestination(unitDestinations[unit.ID]);
|
||||
}
|
||||
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, " new destination added");
|
||||
}
|
||||
|
||||
selectedUnitsClearDestinations() {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
const unit = selectedUnits[idx];
|
||||
if (unit.getState() === "Follow") {
|
||||
const leader = this.getUnitByID(unit.getLeaderID())
|
||||
if (leader && leader.getSelected())
|
||||
leader.clearDestinations();
|
||||
else
|
||||
unit.clearDestinations();
|
||||
}
|
||||
else
|
||||
unit.clearDestinations();
|
||||
}
|
||||
}
|
||||
|
||||
selectedUnitsLandAt(latlng: LatLng) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].landAt(latlng);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, " landing");
|
||||
}
|
||||
|
||||
selectedUnitsChangeSpeed(speedChange: string) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].changeSpeed(speedChange);
|
||||
}
|
||||
}
|
||||
|
||||
selectedUnitsChangeAltitude(altitudeChange: string) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].changeAltitude(altitudeChange);
|
||||
}
|
||||
}
|
||||
|
||||
selectedUnitsSetSpeed(speed: number) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].setSpeed(speed);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `setting speed to ${msToKnots(speed)} kts`);
|
||||
}
|
||||
|
||||
selectedUnitsSetSpeedType(speedType: string) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].setSpeedType(speedType);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `setting speed type to ${speedType}`);
|
||||
}
|
||||
|
||||
selectedUnitsSetAltitude(altitude: number) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].setAltitude(altitude);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `setting altitude to ${mToFt(altitude)} ft`);
|
||||
}
|
||||
|
||||
selectedUnitsSetAltitudeType(altitudeType: string) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].setAltitudeType(altitudeType);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `setting altitude type to ${altitudeType}`);
|
||||
}
|
||||
|
||||
selectedUnitsSetROE(ROE: string) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].setROE(ROE);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `ROE set to ${ROE}`);
|
||||
}
|
||||
|
||||
selectedUnitsSetReactionToThreat(reactionToThreat: string) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].setReactionToThreat(reactionToThreat);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `reaction to threat set to ${reactionToThreat}`);
|
||||
}
|
||||
|
||||
selectedUnitsSetEmissionsCountermeasures(emissionCountermeasure: string) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].setEmissionsCountermeasures(emissionCountermeasure);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `emissions & countermeasures set to ${emissionCountermeasure}`);
|
||||
}
|
||||
|
||||
selectedUnitsSetOnOff(onOff: boolean) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].setOnOff(onOff);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `unit active set to ${onOff}`);
|
||||
}
|
||||
|
||||
selectedUnitsSetFollowRoads(followRoads: boolean) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].setFollowRoads(followRoads);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `follow roads set to ${followRoads}`);
|
||||
}
|
||||
|
||||
|
||||
selectedUnitsAttackUnit(ID: number) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].attackUnit(ID);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `attacking unit ${this.getUnitByID(ID)?.getUnitName()}`);
|
||||
}
|
||||
|
||||
selectedUnitsDelete(explosion: boolean = false) {
|
||||
var selectedUnits = this.getSelectedUnits(); /* Can be applied to humans too */
|
||||
const selectionContainsAHuman = selectedUnits.some( ( unit:Unit ) => {
|
||||
return unit.getHuman() === true;
|
||||
});
|
||||
|
||||
if (selectionContainsAHuman && !confirm( "Your selection includes a human player. Deleting humans causes their vehicle to crash.\n\nAre you sure you want to do this?" ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var immediate = false;
|
||||
if (selectedUnits.length > 20)
|
||||
immediate = confirm(`You are trying to delete ${selectedUnits.length} units, do you want to delete them immediately? This may cause lag for players.`)
|
||||
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].delete(explosion, immediate);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `deleted`);
|
||||
}
|
||||
|
||||
selectedUnitsRefuel() {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].refuel();
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `sent to nearest tanker`);
|
||||
}
|
||||
|
||||
selectedUnitsFollowUnit(ID: number, offset?: { "x": number, "y": number, "z": number }, formation?: string) {
|
||||
if (offset == undefined) {
|
||||
/* Simple formations with fixed offsets */
|
||||
// X: front-rear, positive front
|
||||
// Y: top-bottom, positive top
|
||||
// Z: left-right, positive right
|
||||
offset = { "x": 0, "y": 0, "z": 0 };
|
||||
if (formation === "trail") { offset.x = -50; offset.y = -30; offset.z = 0; }
|
||||
else if (formation === "echelon-lh") { offset.x = -50; offset.y = -10; offset.z = -50; }
|
||||
else if (formation === "echelon-rh") { offset.x = -50; offset.y = -10; offset.z = 50; }
|
||||
else if (formation === "line-abreast-rh") { offset.x = 0; offset.y = 0; offset.z = 50; }
|
||||
else if (formation === "line-abreast-lh") { offset.x = 0; offset.y = 0; offset.z = -50; }
|
||||
else if (formation === "front") { offset.x = 100; offset.y = 0; offset.z = 0; }
|
||||
else offset = undefined;
|
||||
}
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
var count = 1;
|
||||
var xr = 0; var yr = 1; var zr = -1;
|
||||
var layer = 1;
|
||||
for (let idx in selectedUnits) {
|
||||
var unit = selectedUnits[idx];
|
||||
if (offset != undefined)
|
||||
/* Offset is set, apply it */
|
||||
unit.followUnit(ID, { "x": offset.x * count, "y": offset.y * count, "z": offset.z * count });
|
||||
else {
|
||||
/* More complex formations with variable offsets */
|
||||
if (formation === "diamond") {
|
||||
var xl = xr * Math.cos(Math.PI / 4) - yr * Math.sin(Math.PI / 4);
|
||||
var yl = xr * Math.sin(Math.PI / 4) + yr * Math.cos(Math.PI / 4);
|
||||
unit.followUnit(ID, { "x": -yl * 50, "y": zr * 10, "z": xl * 50 });
|
||||
|
||||
if (yr == 0) { layer++; xr = 0; yr = layer; zr = -layer; }
|
||||
else {
|
||||
if (xr < layer) { xr++; zr--; }
|
||||
else { yr--; zr++; }
|
||||
}
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `following unit ${this.getUnitByID(ID)?.getUnitName()}`);
|
||||
}
|
||||
|
||||
selectedUnitsSetHotgroup(hotgroup: number) {
|
||||
this.getUnitsByHotgroup(hotgroup).forEach((unit: Unit) => unit.setHotgroup(null));
|
||||
this.selectedUnitsAddToHotgroup(hotgroup);
|
||||
}
|
||||
|
||||
selectedUnitsAddToHotgroup(hotgroup: number) {
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].setHotgroup(hotgroup);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `added to hotgroup ${hotgroup}`);
|
||||
getHotgroupPanel().refreshHotgroups();
|
||||
}
|
||||
|
||||
selectedUnitsComputeGroupDestination(latlng: LatLng, rotation: number) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
/* Compute the center of the group */
|
||||
var center = { x: 0, y: 0 };
|
||||
selectedUnits.forEach((unit: Unit) => {
|
||||
var mercator = latLngToMercator(unit.getPosition().lat, unit.getPosition().lng);
|
||||
center.x += mercator.x / selectedUnits.length;
|
||||
center.y += mercator.y / selectedUnits.length;
|
||||
});
|
||||
|
||||
/* Compute the distances from the center of the group */
|
||||
var unitDestinations: { [key: number]: LatLng } = {};
|
||||
selectedUnits.forEach((unit: Unit) => {
|
||||
var mercator = latLngToMercator(unit.getPosition().lat, unit.getPosition().lng);
|
||||
var distancesFromCenter = { dx: mercator.x - center.x, dy: mercator.y - center.y };
|
||||
|
||||
/* Rotate the distance according to the group rotation */
|
||||
var rotatedDistancesFromCenter: { dx: number, dy: number } = { dx: 0, dy: 0 };
|
||||
rotatedDistancesFromCenter.dx = distancesFromCenter.dx * Math.cos(deg2rad(rotation)) - distancesFromCenter.dy * Math.sin(deg2rad(rotation));
|
||||
rotatedDistancesFromCenter.dy = distancesFromCenter.dx * Math.sin(deg2rad(rotation)) + distancesFromCenter.dy * Math.cos(deg2rad(rotation));
|
||||
|
||||
/* Compute the final position of the unit */
|
||||
var destMercator = latLngToMercator(latlng.lat, latlng.lng); // Convert destination point to mercator
|
||||
var unitMercator = { x: destMercator.x + rotatedDistancesFromCenter.dx, y: destMercator.y + rotatedDistancesFromCenter.dy }; // Compute final position of this unit in mercator coordinates
|
||||
var unitLatLng = mercatorToLatLng(unitMercator.x, unitMercator.y);
|
||||
unitDestinations[unit.ID] = new LatLng(unitLatLng.lat, unitLatLng.lng);
|
||||
});
|
||||
|
||||
return unitDestinations;
|
||||
}
|
||||
|
||||
selectedUnitsBombPoint(mouseCoordinates: LatLng) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].bombPoint(mouseCoordinates);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `unit bombing point`);
|
||||
}
|
||||
|
||||
selectedUnitsCarpetBomb(mouseCoordinates: LatLng) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].carpetBomb(mouseCoordinates);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `unit bombing point`);
|
||||
}
|
||||
|
||||
selectedUnitsBombBuilding(mouseCoordinates: LatLng) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].bombBuilding(mouseCoordinates);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `unit bombing point`);
|
||||
}
|
||||
|
||||
selectedUnitsFireAtArea(mouseCoordinates: LatLng) {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].fireAtArea(mouseCoordinates);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `unit bombing point`);
|
||||
}
|
||||
|
||||
// TODO add undo group
|
||||
selectedUnitsCreateGroup() {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: false });
|
||||
var units = [];
|
||||
var coalition = "neutral";
|
||||
for (let idx in selectedUnits) {
|
||||
var unit = selectedUnits[idx];
|
||||
coalition = unit.getCoalition();
|
||||
deleteUnit(unit.ID, false, true);
|
||||
units.push({unitType: unit.getName(), location: unit.getPosition()});
|
||||
}
|
||||
const category = this.getSelectedUnitsTypes()[0];
|
||||
this.spawnUnits(category, units, coalition, true);
|
||||
}
|
||||
|
||||
/***********************************************/
|
||||
copyUnits() {
|
||||
this.#copiedUnits = JSON.parse(JSON.stringify(this.getSelectedUnits().map((unit: Unit) => {return unit.getData()}))); /* Can be applied to humans too */
|
||||
getInfoPopup().setText(`${this.#copiedUnits.length} units copied`);
|
||||
}
|
||||
|
||||
pasteUnits() {
|
||||
if (!this.#pasteDisabled && getMissionHandler().getCommandModeOptions().commandMode == GAME_MASTER) {
|
||||
/* Compute the position of the center of the copied units */
|
||||
var nUnits = this.#copiedUnits.length;
|
||||
var avgLat = 0;
|
||||
var avgLng = 0;
|
||||
for (let idx in this.#copiedUnits) {
|
||||
var unit = this.#copiedUnits[idx];
|
||||
avgLat += unit.position.lat / nUnits;
|
||||
avgLng += unit.position.lng / nUnits;
|
||||
}
|
||||
|
||||
/* Organize the copied units in groups */
|
||||
var groups: {[key: string]: any} = {};
|
||||
this.#copiedUnits.forEach((unit: any) => {
|
||||
if (!(unit.groupName in groups))
|
||||
groups[unit.groupName] = [];
|
||||
groups[unit.groupName].push(unit);
|
||||
});
|
||||
|
||||
for (let groupName in groups) {
|
||||
/* Paste the units as groups. Only for ground and navy units because of loadouts, TODO: find a better solution so it works for them too*/
|
||||
if (!["Aircraft", "Helicopter"].includes(groups[groupName][0].category)) {
|
||||
var units = groups[groupName].map((unit: any) => {
|
||||
var position = new LatLng(getMap().getMouseCoordinates().lat + unit.position.lat - avgLat, getMap().getMouseCoordinates().lng + unit.position.lng - avgLng);
|
||||
getMap().addTemporaryMarker(position, unit.name, unit.coalition);
|
||||
return {unitType: unit.name, location: position};
|
||||
});
|
||||
this.spawnUnits(groups[groupName][0].category, units, groups[groupName][0].coalition, true);
|
||||
}
|
||||
else {
|
||||
groups[groupName].forEach((unit: any) => {
|
||||
var position = new LatLng(getMap().getMouseCoordinates().lat + unit.position.lat - avgLat, getMap().getMouseCoordinates().lng + unit.position.lng - avgLng);
|
||||
getMap().addTemporaryMarker(position, unit.name, unit.coalition);
|
||||
cloneUnit(unit.ID, position);
|
||||
});
|
||||
}
|
||||
}
|
||||
getInfoPopup().setText(`${this.#copiedUnits.length - 1} units pasted`);
|
||||
}
|
||||
else {
|
||||
getInfoPopup().setText(`Unit cloning is disabled in ${getMissionHandler().getCommandModeOptions().commandMode} mode`);
|
||||
}
|
||||
}
|
||||
|
||||
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]; });
|
||||
|
||||
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) {
|
||||
this.spawnUnits("GroundUnit", [{unitType: unitBlueprint.name, location: latlng}], coalitionArea.getCoalition(), true);
|
||||
getMap().addTemporaryMarker(latlng, unitBlueprint.name, coalitionArea.getCoalition());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
exportToFile() {
|
||||
var unitsToExport: {[key: string]: any} = {};
|
||||
for (let ID in this.#units) {
|
||||
var unit = this.#units[ID];
|
||||
if (!["Aircraft", "Helicopter"].includes(unit.getCategory())) {
|
||||
var data: any = unit.getData();
|
||||
if (unit.getGroupName() in unitsToExport)
|
||||
unitsToExport[unit.getGroupName()].push(data);
|
||||
else
|
||||
unitsToExport[unit.getGroupName()] = [data];
|
||||
}
|
||||
}
|
||||
var a = document.createElement("a");
|
||||
var file = new Blob([JSON.stringify(unitsToExport)], {type: 'text/plain'});
|
||||
a.href = URL.createObjectURL(file);
|
||||
a.download = 'export.json';
|
||||
a.click();
|
||||
}
|
||||
|
||||
importFromFile() {
|
||||
var input = document.createElement("input");
|
||||
input.type = "file";
|
||||
input.addEventListener("change", (e: any) => {
|
||||
var file = e.target.files[0];
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e: any) {
|
||||
var contents = e.target.result;
|
||||
var groups = JSON.parse(contents);
|
||||
for (let groupName in groups) {
|
||||
if (groupName !== "" && groups[groupName].length > 0 && groups[groupName].every((unit: any) => {return unit.category == "GroundUnit";})) {
|
||||
var units = groups[groupName].map((unit: any) => {return {unitType: unit.name, location: unit.position}});
|
||||
getUnitsManager().spawnUnits("GroundUnit", units, groups[groupName][0].coalition, true);
|
||||
}
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
})
|
||||
input.click();
|
||||
}
|
||||
|
||||
spawnUnits(category: string, units: any, coalition: string = "blue", immediate: boolean = true, airbase: string = "") {
|
||||
var spawnPoints = 0;
|
||||
if (category === "Aircraft") {
|
||||
if (airbase == "" && getMissionHandler().getRemainingSetupTime() < 0 && getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER) {
|
||||
getInfoPopup().setText("Aircrafts can be air spawned during the SETUP phase only");
|
||||
return false;
|
||||
}
|
||||
spawnPoints = units.reduce((points: number, unit: any) => {return points + aircraftDatabase.getSpawnPointsByName(unit.unitType)}, 0);
|
||||
spawnAircrafts(units, coalition, airbase, immediate, spawnPoints);
|
||||
} else if (category === "Helicopter") {
|
||||
if (airbase == "" && getMissionHandler().getRemainingSetupTime() < 0 && getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER) {
|
||||
getInfoPopup().setText("Helicopters can be air spawned during the SETUP phase only");
|
||||
return false;
|
||||
}
|
||||
spawnPoints = units.reduce((points: number, unit: any) => {return points + helicopterDatabase.getSpawnPointsByName(unit.unitType)}, 0);
|
||||
spawnHelicopters(units, coalition, airbase, immediate, spawnPoints);
|
||||
} else if (category === "GroundUnit") {
|
||||
if (getMissionHandler().getRemainingSetupTime() < 0 && getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER) {
|
||||
getInfoPopup().setText("Ground units can be spawned during the SETUP phase only");
|
||||
return false;
|
||||
}
|
||||
spawnPoints = units.reduce((points: number, unit: any) => {return points + groundUnitDatabase.getSpawnPointsByName(unit.unitType)}, 0);
|
||||
spawnGroundUnits(units, coalition, immediate, spawnPoints);
|
||||
} else if (category === "NavyUnit") {
|
||||
if (getMissionHandler().getRemainingSetupTime() < 0 && getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER) {
|
||||
getInfoPopup().setText("Navy units can be spawned during the SETUP phase only");
|
||||
return false;
|
||||
}
|
||||
spawnPoints = units.reduce((points: number, unit: any) => {return points + navyUnitDatabase.getSpawnPointsByName(unit.unitType)}, 0);
|
||||
spawnNavyUnits(units, coalition, immediate, spawnPoints);
|
||||
}
|
||||
|
||||
if (spawnPoints <= getMissionHandler().getAvailableSpawnPoints()) {
|
||||
getMissionHandler().setSpentSpawnPoints(spawnPoints);
|
||||
return true;
|
||||
} else {
|
||||
getInfoPopup().setText("Not enough spawn points available!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************/
|
||||
#onKeyUp(event: KeyboardEvent) {
|
||||
if (!keyEventWasInInput(event)) {
|
||||
if (event.key === "Delete")
|
||||
this.selectedUnitsDelete();
|
||||
else if (event.key === "a" && event.ctrlKey)
|
||||
Object.values(this.getUnits()).filter((unit: Unit) => {return !unit.getHidden()}).forEach((unit: Unit) => unit.setSelected(true));
|
||||
}
|
||||
}
|
||||
|
||||
#onUnitSelection(unit: Unit) {
|
||||
if (this.getSelectedUnits().length > 0) {
|
||||
getMap().setState(MOVE_UNIT);
|
||||
/* Disable the firing of the selection event for a certain amount of time. This avoids firing many events if many units are selected */
|
||||
if (!this.#selectionEventDisabled) {
|
||||
window.setTimeout(() => {
|
||||
document.dispatchEvent(new CustomEvent("unitsSelection", { detail: this.getSelectedUnits() }));
|
||||
this.#selectionEventDisabled = false;
|
||||
}, 100);
|
||||
this.#selectionEventDisabled = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
getMap().setState(IDLE);
|
||||
document.dispatchEvent(new CustomEvent("clearSelection"));
|
||||
}
|
||||
}
|
||||
|
||||
#onUnitDeselection(unit: Unit) {
|
||||
if (this.getSelectedUnits().length == 0) {
|
||||
getMap().setState(IDLE);
|
||||
document.dispatchEvent(new CustomEvent("clearSelection"));
|
||||
}
|
||||
else
|
||||
document.dispatchEvent(new CustomEvent("unitsDeselection", { detail: this.getSelectedUnits() }));
|
||||
}
|
||||
|
||||
#showActionMessage(units: any[], message: string) {
|
||||
if (units.length == 1)
|
||||
getInfoPopup().setText(`${units[0].getUnitName()} ${message}`);
|
||||
else if (units.length > 1)
|
||||
getInfoPopup().setText(`${units[0].getUnitName()} and ${units.length - 1} other units ${message}`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user