Started readding old core frontend code

This commit is contained in:
Pax1601
2024-04-03 08:05:36 +02:00
parent 5d5c650162
commit d72a00a005
60 changed files with 16018 additions and 34 deletions

View File

@@ -0,0 +1,60 @@
import { Unit } from "./unit";
export interface ContextActionOptions {
isScenic?: boolean
}
export class ContextAction {
#id: string = "";
#label: string = "";
#description: string = "";
#callback: CallableFunction | null = null;
#units: Unit[] = [];
#hideContextAfterExecution: boolean = true
#options: ContextActionOptions;
constructor(id: string, label: string, description: string, callback: CallableFunction, hideContextAfterExecution: boolean = true, options: ContextActionOptions) {
this.#id = id;
this.#label = label;
this.#description = description;
this.#callback = callback;
this.#hideContextAfterExecution = hideContextAfterExecution;
this.#options = {
"isScenic": false,
...options
}
}
addUnit(unit: Unit) {
this.#units.push(unit);
}
getId() {
return this.#id;
}
getLabel() {
return this.#label;
}
getOptions() {
return this.#options;
}
getDescription() {
return this.#description;
}
getCallback() {
return this.#callback;
}
executeCallback() {
if (this.#callback)
this.#callback(this.#units);
}
getHideContextAfterExecution() {
return this.#hideContextAfterExecution;
}
}

View File

@@ -0,0 +1,25 @@
import { ContextAction, ContextActionOptions } from "./contextaction";
import { Unit } from "./unit";
export class ContextActionSet {
#contextActions: {[key: string]: ContextAction} = {};
constructor() {
}
addContextAction(unit: Unit, id: string, label: string, description: string, callback: CallableFunction, hideContextAfterExecution: boolean = true, options?:ContextActionOptions) {
options = options || {};
if (!(id in this.#contextActions)) {
this.#contextActions[id] = new ContextAction(id, label, description, callback, hideContextAfterExecution, options);
}
this.#contextActions[id].addUnit(unit);
}
getContextActions() {
return this.#contextActions;
}
}

View File

@@ -0,0 +1,37 @@
import { getApp } from "../../olympusapp";
import { GAME_MASTER } from "../../constants/constants";
import { UnitDatabase } from "./unitdatabase"
export class AircraftDatabase extends UnitDatabase {
constructor() {
super('api/databases/units/aircraftdatabase');
}
getCategory() {
return "Aircraft";
}
getSpawnPointsByName(name: string) {
if (getApp().getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER || !getApp().getMissionManager().getCommandModeOptions().restrictSpawns)
return 0;
const blueprint = this.getByName(name);
if (blueprint?.cost != undefined)
return blueprint?.cost;
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;
}
}
export var aircraftDatabase = new AircraftDatabase();

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,36 @@
import { getApp } from "../../olympusapp";
import { GAME_MASTER } from "../../constants/constants";
import { UnitDatabase } from "./unitdatabase"
export class GroundUnitDatabase extends UnitDatabase {
constructor() {
super('api/databases/units/groundunitdatabase');
}
getSpawnPointsByName(name: string) {
if (getApp().getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER || !getApp().getMissionManager().getCommandModeOptions().restrictSpawns)
return 0;
const blueprint = this.getByName(name);
if (blueprint?.cost != undefined)
return blueprint?.cost;
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 "GroundUnit";
}
}
export var groundUnitDatabase = new GroundUnitDatabase();

View File

@@ -0,0 +1,37 @@
import { getApp } from "../../olympusapp";
import { GAME_MASTER } from "../../constants/constants";
import { UnitDatabase } from "./unitdatabase"
export class HelicopterDatabase extends UnitDatabase {
constructor() {
super('api/databases/units/helicopterdatabase');
}
getSpawnPointsByName(name: string) {
if (getApp().getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER || !getApp().getMissionManager().getCommandModeOptions().restrictSpawns)
return 0;
const blueprint = this.getByName(name);
if (blueprint?.cost != undefined)
return blueprint?.cost;
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();

View File

@@ -0,0 +1,36 @@
import { getApp } from "../../olympusapp";
import { GAME_MASTER } from "../../constants/constants";
import { UnitDatabase } from "./unitdatabase"
export class NavyUnitDatabase extends UnitDatabase {
constructor() {
super('api/databases/units/navyunitdatabase');
}
getSpawnPointsByName(name: string) {
if (getApp().getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER || !getApp().getMissionManager().getCommandModeOptions().restrictSpawns)
return 0;
const blueprint = this.getByName(name);
if (blueprint?.cost != undefined)
return blueprint?.cost;
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();

View File

@@ -0,0 +1,239 @@
import { LatLng } from "leaflet";
import { getApp } from "../../olympusapp";
import { GAME_MASTER } from "../../constants/constants";
import { UnitBlueprint } from "../../interfaces";
export abstract class UnitDatabase {
blueprints: { [key: string]: UnitBlueprint } = {};
#url: string;
constructor(url: string = "") {
this.#url = url;
this.load(() => {});
}
load(callback: CallableFunction) {
if (this.#url !== "") {
var xhr = new XMLHttpRequest();
xhr.open('GET', this.#url, true);
xhr.setRequestHeader("Cache-Control", "no-cache, no-store, max-age=0");
xhr.responseType = 'json';
xhr.onload = () => {
var status = xhr.status;
if (status === 200) {
this.blueprints = xhr.response;
callback();
} else {
console.error(`Error retrieving database from ${this.#url}`)
}
};
xhr.send();
}
}
abstract getCategory(): string;
/* 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(includeDisabled: boolean = false) {
if (getApp().getMissionManager().getCommandModeOptions().commandMode == GAME_MASTER || !getApp().getMissionManager().getCommandModeOptions().restrictSpawns) {
var filteredBlueprints: { [key: string]: UnitBlueprint } = {};
for (let unit in this.blueprints) {
const blueprint = this.blueprints[unit];
if (blueprint.enabled || includeDisabled)
filteredBlueprints[unit] = blueprint;
}
return filteredBlueprints;
}
else {
var filteredBlueprints: { [key: string]: UnitBlueprint } = {};
for (let unit in this.blueprints) {
const blueprint = this.blueprints[unit];
if ((blueprint.enabled || includeDisabled) && this.getSpawnPointsByName(blueprint.name) <= getApp().getMissionManager().getAvailableSpawnPoints() &&
getApp().getMissionManager().getCommandModeOptions().eras.includes(blueprint.era) &&
(!getApp().getMissionManager().getCommandModeOptions().restrictToCoalition || blueprint.coalition === getApp().getMissionManager().getCommandedCoalition() || blueprint.coalition === undefined)) {
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(unitFilter?:CallableFunction) {
var filteredBlueprints = this.getBlueprints();
var types: string[] = [];
for (let unit in filteredBlueprints) {
if ( typeof unitFilter === "function" && !unitFilter(filteredBlueprints[unit]))
continue;
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;
}
/* Get all blueprints by range */
getByRange(range: string) {
var filteredBlueprints = this.getBlueprints();
var unitswithrange = [];
var minRange = 0;
var maxRange = 0;
if (range === "Short range") {
minRange = 0;
maxRange = 10000;
}
else if (range === "Medium range") {
minRange = 10000;
maxRange = 100000;
}
else {
minRange = 100000;
maxRange = 999999;
}
for (let unit in filteredBlueprints) {
var engagementRange = filteredBlueprints[unit].engagementRange;
if (engagementRange !== undefined) {
if (engagementRange >= minRange && engagementRange < maxRange) {
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 livery names for a specific unit */
getLiveryNamesByName(name: string) {
var liveries = this.blueprints[name].liveries;
if (liveries !== undefined)
return Object.values(liveries);
else
return [];
}
/* 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;
}
getSpawnPointsByLabel(label: string) {
var blueprint = this.getByLabel(label);
if (blueprint)
return this.getSpawnPointsByName(blueprint.name);
else
return Infinity;
}
getSpawnPointsByName(name: string) {
return Infinity;
}
getUnkownUnit(name: string): UnitBlueprint {
return {
name: name,
enabled: true,
coalition: 'neutral',
era: 'N/A',
label: name,
shortLabel: ''
}
}
}

View File

@@ -0,0 +1,45 @@
import { Unit } from "./unit";
export class Group {
#members: Unit[] = [];
#name: string;
constructor(name: string) {
this.#name = name;
document.addEventListener("unitDeath", (e: any) => {
if (this.#members.includes(e.detail))
this.getLeader()?.onGroupChanged(e.detail);
});
}
getName() {
return this.#name;
}
addMember(member: Unit) {
if (!this.#members.includes(member)) {
this.#members.push(member);
member.setGroup(this);
this.getLeader()?.onGroupChanged(member);
}
}
removeMember(member: Unit) {
if (this.#members.includes(member)) {
delete this.#members[this.#members.indexOf(member)];
member.setGroup(null);
this.getLeader()?.onGroupChanged(member);
}
}
getMembers() {
return this.#members;
}
getLeader() {
return this.#members.find((unit: Unit) => { return (unit.getIsLeader() && unit.getAlive())})
}
}

View File

@@ -0,0 +1,66 @@
//import { Dialog } from "../../dialog/dialog";
//import { createCheckboxOption } from "../../other/utils";
var categoryMap = {
"Aircraft": "Aircraft",
"Helicopter": "Helicopter",
"GroundUnit": "Ground units",
"NavyUnit": "Naval units"
}
export abstract class UnitDataFile {
protected data: any;
//protected dialog!: Dialog;
constructor() { }
buildCategoryCoalitionTable() {
const categories = this.#getCategoriesFromData();
const coalitions = ["blue", "neutral", "red"];
let headersHTML: string = ``;
let matrixHTML: string = ``;
//categories.forEach((category: string, index) => {
// matrixHTML += `<tr><td>${categoryMap[category as keyof typeof categoryMap]}</td>`;
//
// coalitions.forEach((coalition: string) => {
// if (index === 0)
// headersHTML += `<th data-coalition="${coalition}">${coalition[0].toUpperCase() + coalition.substring(1)}</th>`;
//
// const optionIsValid = this.data[category].hasOwnProperty(coalition);
// let checkboxHTML = createCheckboxOption(``, category, optionIsValid, () => { }, {
// "disabled": !optionIsValid,
// "name": "category-coalition-selection",
// "readOnly": !optionIsValid,
// "value" : `${category}:${coalition}`
// }).outerHTML;
//
// if (optionIsValid)
// checkboxHTML = checkboxHTML.replace(`"checkbox"`, `"checkbox" checked`); // inner and outerHTML screw default checked up
//
// matrixHTML += `<td data-coalition="${coalition}">${checkboxHTML}</td>`;
//
// });
// matrixHTML += "</tr>";
//});
//
//const table = <HTMLTableElement>this.dialog.getElement().querySelector("table.categories-coalitions");
//(<HTMLElement>table.tHead).innerHTML = `<tr><td>&nbsp;</td>${headersHTML}</tr>`;
//(<HTMLElement>table.querySelector(`tbody`)).innerHTML = matrixHTML;
}
#getCategoriesFromData() {
const categories = Object.keys(this.data);
categories.sort();
return categories;
}
getData() {
return this.data;
}
}

View File

@@ -0,0 +1,101 @@
import { getApp } from "../../olympusapp";
//import { Dialog } from "../../dialog/dialog";
import { zeroAppend } from "../../other/utils";
import { Unit } from "../unit";
import { UnitDataFile } from "./unitdatafile";
export class UnitDataFileExport extends UnitDataFile {
protected data!: any;
//protected dialog: Dialog;
#element!: HTMLElement;
#filename: string = "export.json";
constructor(elementId: string) {
super();
//this.dialog = new Dialog(elementId);
//this.#element = this.dialog.getElement();
this.#element.querySelector(".start-transfer")?.addEventListener("click", (ev: MouseEventInit) => {
this.#doExport();
});
}
/**
* Show the form to start the export journey
*/
showForm(units: Unit[]) {
//this.dialog.getElement().querySelectorAll("[data-on-error]").forEach((el:Element) => {
// el.classList.toggle("hide", el.getAttribute("data-on-error") === "show");
//});
//
//const data: any = {};
//const unitCanBeExported = (unit: Unit) => !["Aircraft", "Helicopter"].includes(unit.getCategory());
//
//units.filter((unit: Unit) => unit.getAlive() && unitCanBeExported(unit)).forEach((unit: Unit) => {
// const category = unit.getCategory();
// const coalition = unit.getCoalition();
//
// if (!data.hasOwnProperty(category)) {
// data[category] = {};
// }
//
// if (!data[category].hasOwnProperty(coalition))
// data[category][coalition] = [];
//
// data[category][coalition].push(unit);
//});
//
//this.data = data;
//this.buildCategoryCoalitionTable();
//this.dialog.show();
//
//const date = new Date();
//this.#filename = `olympus_${getApp().getMissionManager().getTheatre().replace(/[^\w]/gi, "").toLowerCase()}_${date.getFullYear()}${zeroAppend(date.getMonth() + 1, 2)}${zeroAppend(date.getDate(), 2)}_${zeroAppend(date.getHours(), 2)}${zeroAppend(date.getMinutes(), 2)}${zeroAppend(date.getSeconds(), 2)}.json`;
//var input = this.#element.querySelector("#export-filename") as HTMLInputElement;
//input.onchange = (ev: Event) => {
// this.#filename = (ev.currentTarget as HTMLInputElement).value;
//}
//if (input)
// input.value = this.#filename;
}
#doExport() {
let selectedUnits: Unit[] = [];
this.#element.querySelectorAll(`input[type="checkbox"][name="category-coalition-selection"]:checked`).forEach(<HTMLInputElement>(checkbox: HTMLInputElement) => {
if (checkbox instanceof HTMLInputElement) {
const [category, coalition] = checkbox.value.split(":"); // e.g. "category:coalition"
selectedUnits = selectedUnits.concat(this.data[category][coalition]);
}
});
if (selectedUnits.length === 0) {
alert("Please select at least one option for export.");
return;
}
var unitsToExport: { [key: string]: any } = {};
selectedUnits.forEach((unit: Unit) => {
var data: any = unit.getData();
if (unit.getGroupName() in unitsToExport)
unitsToExport[unit.getGroupName()].push(data);
else
unitsToExport[unit.getGroupName()] = [data];
});
const a = document.createElement("a");
const file = new Blob([JSON.stringify(unitsToExport)], { type: 'text/plain' });
a.href = URL.createObjectURL(file);
var filename = this.#filename;
if (!this.#filename.toLowerCase().endsWith(".json"))
filename += ".json";
a.download = filename;
a.click();
//this.dialog.hide();
}
}

View File

@@ -0,0 +1,150 @@
import { getApp } from "../../olympusapp";
//import { Dialog } from "../../dialog/dialog";
import { UnitData } from "../../interfaces";
//import { ImportFileJSONSchemaValidator } from "../../schemas/schema";
import { UnitDataFile } from "./unitdatafile";
export class UnitDataFileImport extends UnitDataFile {
protected data!: any;
//protected dialog: Dialog;
#fileData!: { [key: string]: UnitData[] };
constructor(elementId: string) {
super();
//this.dialog = new Dialog(elementId);
//this.dialog.getElement().querySelector(".start-transfer")?.addEventListener("click", (ev: MouseEventInit) => {
// this.#doImport();
// this.dialog.hide();
//});
}
#doImport() {
//let selectedCategories: any = {};
//const unitsManager = getApp().getUnitsManager();
//
//this.dialog.getElement().querySelectorAll(`input[type="checkbox"][name="category-coalition-selection"]:checked`).forEach(<HTMLInputElement>(checkbox: HTMLInputElement) => {
// if (checkbox instanceof HTMLInputElement) {
// const [category, coalition] = checkbox.value.split(":"); // e.g. "category:coalition"
// selectedCategories[category] = selectedCategories[category] || {};
// selectedCategories[category][coalition] = true;
// }
//});
//
//for (const [groupName, groupData] of Object.entries(this.#fileData)) {
// if (groupName === "" || groupData.length === 0 || !this.#unitGroupDataCanBeImported(groupData))
// continue;
//
// let { category, coalition } = groupData[0];
//
// if (!selectedCategories.hasOwnProperty(category)
// || !selectedCategories[category].hasOwnProperty(coalition)
// || selectedCategories[category][coalition] !== true)
// continue;
//
// let unitsToSpawn = groupData.filter((unitData: UnitData) => this.#unitDataCanBeImported(unitData)).map((unitData: UnitData) => {
// return { unitType: unitData.name, location: unitData.position, liveryID: "", skill: "High" }
// });
//
// unitsManager.spawnUnits(category, unitsToSpawn, coalition, false);
//}
}
selectFile() {
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 = (e: any) => {
try {
this.#fileData = JSON.parse(e.target.result);
//const validator = new ImportFileJSONSchemaValidator();
//if (!validator.validate(this.#fileData)) {
// const errors = validator.getErrors().reduce((acc:any, error:any) => {
// let errorString = error.instancePath.substring(1) + ": " + error.message;
// if (error.params) {
// const {allowedValues} = error.params;
// if (allowedValues)
// errorString += ": " + allowedValues.join(', ');
// }
// acc.push(errorString);
// return acc;
// }, [] as string[]);
// this.#showFileDataErrors(errors);
//} else {
// this.#showForm();
//}
} catch(e:any) {
this.#showFileDataErrors([e]);
}
};
reader.readAsText(file);
})
input.click();
}
#showFileDataErrors( reasons:string[]) {
//this.dialog.getElement().querySelectorAll("[data-on-error]").forEach((el:Element) => {
// el.classList.toggle("hide", el.getAttribute("data-on-error") === "hide");
//});
//
//const reasonsList = this.dialog.getElement().querySelector(".import-error-reasons");
//if (reasonsList instanceof HTMLElement)
// reasonsList.innerHTML = `<li>${reasons.join("</li><li>")}</li>`;
//
//this.dialog.show();
}
#showForm() {
//this.dialog.getElement().querySelectorAll("[data-on-error]").forEach((el:Element) => {
// el.classList.toggle("hide", el.getAttribute("data-on-error") === "show");
//});
//
//const data: any = {};
//
//for (const [group, units] of Object.entries(this.#fileData)) {
// if (group === "" || units.length === 0)
// continue;
//
// if (units.some((unit: UnitData) => !this.#unitDataCanBeImported(unit)))
// continue;
//
// const category = units[0].category;
//
// if (!data.hasOwnProperty(category)) {
// data[category] = {};
// }
//
// units.forEach((unit: UnitData) => {
// if (!data[category].hasOwnProperty(unit.coalition))
// data[category][unit.coalition] = [];
//
// data[category][unit.coalition].push(unit);
// });
//
//}
//
//this.data = data;
//this.buildCategoryCoalitionTable();
//this.dialog.show();
}
#unitDataCanBeImported(unitData: UnitData) {
return unitData.alive && this.#unitGroupDataCanBeImported([unitData]);
}
#unitGroupDataCanBeImported(unitGroupData: UnitData[]) {
return unitGroupData.every((unitData: UnitData) => {
return !["Aircraft", "Helicopter"].includes(unitData.category);
}) && unitGroupData.some((unitData: UnitData) => unitData.alive);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff