diff --git a/client/@types/olympus/index.d.ts b/client/@types/olympus/index.d.ts
index faa3f853..2b8e73ad 100644
--- a/client/@types/olympus/index.d.ts
+++ b/client/@types/olympus/index.d.ts
@@ -107,6 +107,8 @@ declare module "constants/constants" {
export const ROEDescriptions: string[];
export const reactionsToThreatDescriptions: string[];
export const emissionsCountermeasuresDescriptions: string[];
+ export const shotsScatterDescriptions: string[];
+ export const shotsIntensityDescriptions: string[];
export const minSpeedValues: {
[key: string]: number;
};
@@ -221,31 +223,35 @@ declare module "constants/constants" {
hasTask = 12,
position = 13,
speed = 14,
- heading = 15,
- isActiveTanker = 16,
- isActiveAWACS = 17,
- onOff = 18,
- followRoads = 19,
- fuel = 20,
- desiredSpeed = 21,
- desiredSpeedType = 22,
- desiredAltitude = 23,
- desiredAltitudeType = 24,
- leaderID = 25,
- formationOffset = 26,
- targetID = 27,
- targetPosition = 28,
- ROE = 29,
- reactionToThreat = 30,
- emissionsCountermeasures = 31,
- TACAN = 32,
- radio = 33,
- generalSettings = 34,
- ammo = 35,
- contacts = 36,
- activePath = 37,
- isLeader = 38,
- operateAs = 39,
+ horizontalVelocity = 15,
+ verticalVelocity = 16,
+ heading = 17,
+ isActiveTanker = 18,
+ isActiveAWACS = 19,
+ onOff = 20,
+ followRoads = 21,
+ fuel = 22,
+ desiredSpeed = 23,
+ desiredSpeedType = 24,
+ desiredAltitude = 25,
+ desiredAltitudeType = 26,
+ leaderID = 27,
+ formationOffset = 28,
+ targetID = 29,
+ targetPosition = 30,
+ ROE = 31,
+ reactionToThreat = 32,
+ emissionsCountermeasures = 33,
+ TACAN = 34,
+ radio = 35,
+ generalSettings = 36,
+ ammo = 37,
+ contacts = 38,
+ activePath = 39,
+ isLeader = 40,
+ operateAs = 41,
+ shotsScatter = 42,
+ shotsIntensity = 43,
endOfData = 255
}
export const MGRS_PRECISION_10KM = 2;
@@ -253,6 +259,8 @@ declare module "constants/constants" {
export const MGRS_PRECISION_100M = 4;
export const MGRS_PRECISION_10M = 5;
export const MGRS_PRECISION_1M = 6;
+ export const DELETE_CYCLE_TIME = 0.05;
+ export const DELETE_SLOW_THRESHOLD = 50;
}
declare module "map/markers/custommarker" {
import { Map, Marker } from "leaflet";
@@ -303,7 +311,7 @@ declare module "controls/dropdown" {
#private;
constructor(ID: string | null, callback: CallableFunction, options?: string[] | null, defaultText?: string);
getContainer(): HTMLElement;
- setOptions(optionsList: string[], sortAlphabetically?: boolean): void;
+ setOptions(optionsList: string[], sort?: "" | "string" | "number"): void;
setOptionsElements(optionsElements: HTMLElement[]): void;
getOptionElements(): HTMLCollection;
addOptionElement(optionElement: HTMLElement): void;
@@ -498,6 +506,8 @@ declare module "interfaces" {
hasTask: boolean;
position: LatLng;
speed: number;
+ horizontalVelocity: number;
+ verticalVelocity: number;
heading: number;
isActiveTanker: boolean;
isActiveAWACS: boolean;
@@ -523,6 +533,8 @@ declare module "interfaces" {
activePath: LatLng[];
isLeader: boolean;
operateAs: string;
+ shotsScatter: number;
+ shotsIntensity: number;
}
export interface LoadoutItemBlueprint {
name: string;
@@ -558,12 +570,17 @@ declare module "interfaces" {
muzzleVelocity?: number;
aimTime?: number;
shotsToFire?: number;
+ shotsBaseInterval?: number;
+ shotsBaseScatter?: number;
description?: string;
abilities?: string;
acquisitionRange?: number;
engagementRange?: number;
+ targetingRange?: number;
canTargetPoint?: boolean;
canRearm?: boolean;
+ canAAA?: boolean;
+ indirectFire?: boolean;
}
export interface UnitSpawnOptions {
roleType: string;
@@ -786,9 +803,11 @@ declare module "controls/unitspawnmenu" {
import { UnitSpawnOptions } from "interfaces";
export class UnitSpawnMenu {
#private;
- spawnOptions: UnitSpawnOptions;
+ protected showRangeCircles: boolean;
+ protected spawnOptions: UnitSpawnOptions;
constructor(ID: string, unitDatabase: UnitDatabase, orderByRole: boolean);
getContainer(): HTMLElement;
+ getVisible(): boolean;
reset(): void;
setCountries(): void;
refreshOptions(): void;
@@ -824,6 +843,7 @@ declare module "controls/unitspawnmenu" {
deployUnits(spawnOptions: UnitSpawnOptions, unitsCount: number): void;
}
export class GroundUnitSpawnMenu extends UnitSpawnMenu {
+ protected showRangeCircles: boolean;
/**
*
* @param ID - the ID of the HTML element which will contain the context menu
@@ -1036,6 +1056,8 @@ declare module "unit/unit" {
getHasTask(): boolean;
getPosition(): LatLng;
getSpeed(): number;
+ getHorizontalVelocity(): number;
+ getVerticalVelocity(): number;
getHeading(): number;
getIsActiveTanker(): boolean;
getIsActiveAWACS(): boolean;
@@ -1061,6 +1083,8 @@ declare module "unit/unit" {
getActivePath(): LatLng[];
getIsLeader(): boolean;
getOperateAs(): string;
+ getShotsScatter(): number;
+ getShotsIntensity(): number;
static getConstructor(type: string): typeof GroundUnit | undefined;
constructor(ID: number);
getCategory(): string;
@@ -1097,6 +1121,8 @@ declare module "unit/unit" {
isInViewport(): boolean;
canTargetPoint(): boolean;
canRearm(): boolean;
+ canAAA(): boolean;
+ indirectFire(): boolean;
isTanker(): boolean;
isAWACS(): boolean;
/********************** Unit commands *************************/
@@ -1132,6 +1158,8 @@ declare module "unit/unit" {
scenicAAA(): void;
missOnPurpose(): void;
landAtPoint(latlng: LatLng): void;
+ setShotsScatter(shotsScatter: number): void;
+ setShotsIntensity(shotsIntensity: number): void;
/***********************************************/
getActions(): {
[key: string]: {
@@ -1647,6 +1675,14 @@ declare module "unit/citiesDatabase" {
pop: number;
}[];
}
+declare module "dialog/dialog" {
+ import { Panel } from "panels/panel";
+ export class Dialog extends Panel {
+ constructor(element: string);
+ hide(): void;
+ show(): void;
+ }
+}
declare module "unit/unitsmanager" {
import { LatLng, LatLngBounds } from "leaflet";
import { Unit } from "unit/unit";
@@ -1876,6 +1912,16 @@ declare module "unit/unitsmanager" {
* @param latlng Point where to land
*/
selectedUnitsLandAtPoint(latlng: LatLng): void;
+ /** Set a specific shots scatter to all the selected units
+ *
+ * @param shotsScatter Value to set
+ */
+ selectedUnitsSetShotsScatter(shotsScatter: number): void;
+ /** Set a specific shots intensity to all the selected units
+ *
+ * @param shotsScatter Value to set
+ */
+ selectedUnitsSetShotsIntensity(shotsIntensity: number): void;
/*********************** Control operations on selected units ************************/
/** See getUnitsCategories for more info
*
@@ -2066,6 +2112,8 @@ declare module "server/servermanager" {
scenicAAA(ID: number, coalition: string, callback?: CallableFunction): void;
missOnPurpose(ID: number, coalition: string, callback?: CallableFunction): void;
landAtPoint(ID: number, latlng: LatLng, callback?: CallableFunction): void;
+ setShotsScatter(ID: number, shotsScatter: number, callback?: CallableFunction): void;
+ setShotsIntensity(ID: number, shotsIntensity: number, callback?: CallableFunction): void;
setAdvacedOptions(ID: number, isActiveTanker: boolean, isActiveAWACS: boolean, TACAN: TACAN, radio: Radio, generalSettings: GeneralSettings, callback?: CallableFunction): void;
setCommandModeOptions(restrictSpawns: boolean, restrictToCoalition: boolean, spawnPoints: {
blue: number;
@@ -2106,6 +2154,7 @@ declare module "olympusapp" {
export class OlympusApp {
#private;
constructor();
+ getDialogManager(): Manager;
getMap(): Map;
getServerManager(): ServerManager;
getPanelsManager(): Manager;
diff --git a/client/plugins/databasemanager/index.js b/client/plugins/databasemanager/index.js
index 82738524..432c8142 100644
--- a/client/plugins/databasemanager/index.js
+++ b/client/plugins/databasemanager/index.js
@@ -508,7 +508,7 @@ class GroundUnitEditor extends uniteditor_1.UnitEditor {
* @param blueprint The blueprint to edit
*/
setBlueprint(blueprint) {
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
__classPrivateFieldSet(this, _GroundUnitEditor_blueprint, blueprint, "f");
if (__classPrivateFieldGet(this, _GroundUnitEditor_blueprint, "f") !== null) {
this.contentDiv2.replaceChildren();
@@ -525,14 +525,19 @@ class GroundUnitEditor extends uniteditor_1.UnitEditor {
(0, utils_1.addStringInput)(this.contentDiv2, "Cost", (_b = String(blueprint.cost)) !== null && _b !== void 0 ? _b : "", "number", (value) => { blueprint.cost = parseFloat(value); });
(0, utils_1.addStringInput)(this.contentDiv2, "Acquisition range [m]", (_c = String(blueprint.acquisitionRange)) !== null && _c !== void 0 ? _c : "", "number", (value) => { blueprint.acquisitionRange = parseFloat(value); });
(0, utils_1.addStringInput)(this.contentDiv2, "Engagement range [m]", (_d = String(blueprint.engagementRange)) !== null && _d !== void 0 ? _d : "", "number", (value) => { blueprint.engagementRange = parseFloat(value); });
- (0, utils_1.addStringInput)(this.contentDiv2, "Barrel height [m]", (_e = String(blueprint.barrelHeight)) !== null && _e !== void 0 ? _e : "", "number", (value) => { blueprint.barrelHeight = parseFloat(value); });
- (0, utils_1.addStringInput)(this.contentDiv2, "Muzzle velocity [m/s]", (_f = String(blueprint.muzzleVelocity)) !== null && _f !== void 0 ? _f : "", "number", (value) => { blueprint.muzzleVelocity = parseFloat(value); });
- (0, utils_1.addStringInput)(this.contentDiv2, "Aim time [s]", (_g = String(blueprint.aimTime)) !== null && _g !== void 0 ? _g : "", "number", (value) => { blueprint.aimTime = parseFloat(value); });
- (0, utils_1.addStringInput)(this.contentDiv2, "Burst quantity", (_h = String(blueprint.shotsToFire)) !== null && _h !== void 0 ? _h : "", "number", (value) => { blueprint.shotsToFire = Math.round(parseFloat(value)); });
- (0, utils_1.addCheckboxInput)(this.contentDiv2, "Can target point", (_j = blueprint.canTargetPoint) !== null && _j !== void 0 ? _j : false, (value) => { blueprint.canTargetPoint = value; });
- (0, utils_1.addCheckboxInput)(this.contentDiv2, "Can rearm", (_k = blueprint.canRearm) !== null && _k !== void 0 ? _k : false, (value) => { blueprint.canRearm = value; });
- (0, utils_1.addStringInput)(this.contentDiv2, "Description", (_l = blueprint.description) !== null && _l !== void 0 ? _l : "", "text", (value) => { blueprint.description = value; });
- (0, utils_1.addStringInput)(this.contentDiv2, "Abilities", (_m = blueprint.abilities) !== null && _m !== void 0 ? _m : "", "text", (value) => { blueprint.abilities = value; });
+ (0, utils_1.addStringInput)(this.contentDiv2, "Targeting range [m]", (_e = String(blueprint.targetingRange)) !== null && _e !== void 0 ? _e : "", "number", (value) => { blueprint.targetingRange = parseFloat(value); });
+ (0, utils_1.addStringInput)(this.contentDiv2, "Barrel height [m]", (_f = String(blueprint.barrelHeight)) !== null && _f !== void 0 ? _f : "", "number", (value) => { blueprint.barrelHeight = parseFloat(value); });
+ (0, utils_1.addStringInput)(this.contentDiv2, "Muzzle velocity [m/s]", (_g = String(blueprint.muzzleVelocity)) !== null && _g !== void 0 ? _g : "", "number", (value) => { blueprint.muzzleVelocity = parseFloat(value); });
+ (0, utils_1.addStringInput)(this.contentDiv2, "Aim time [s]", (_h = String(blueprint.aimTime)) !== null && _h !== void 0 ? _h : "", "number", (value) => { blueprint.aimTime = parseFloat(value); });
+ (0, utils_1.addStringInput)(this.contentDiv2, "Burst quantity", (_j = String(blueprint.shotsToFire)) !== null && _j !== void 0 ? _j : "", "number", (value) => { blueprint.shotsToFire = Math.round(parseFloat(value)); });
+ (0, utils_1.addStringInput)(this.contentDiv2, "Burst base interval [s]", (_k = String(blueprint.shotsBaseInterval)) !== null && _k !== void 0 ? _k : "", "number", (value) => { blueprint.shotsBaseInterval = Math.round(parseFloat(value)); });
+ (0, utils_1.addStringInput)(this.contentDiv2, "Base scatter [°]", (_l = String(blueprint.shotsBaseScatter)) !== null && _l !== void 0 ? _l : "", "number", (value) => { blueprint.shotsBaseScatter = Math.round(parseFloat(value)); });
+ (0, utils_1.addCheckboxInput)(this.contentDiv2, "Can target point", (_m = blueprint.canTargetPoint) !== null && _m !== void 0 ? _m : false, (value) => { blueprint.canTargetPoint = value; });
+ (0, utils_1.addCheckboxInput)(this.contentDiv2, "Can rearm", (_o = blueprint.canRearm) !== null && _o !== void 0 ? _o : false, (value) => { blueprint.canRearm = value; });
+ (0, utils_1.addCheckboxInput)(this.contentDiv2, "Can operate as AAA", (_p = blueprint.canAAA) !== null && _p !== void 0 ? _p : false, (value) => { blueprint.canAAA = value; });
+ (0, utils_1.addCheckboxInput)(this.contentDiv2, "Indirect fire (e.g. mortar)", (_q = blueprint.indirectFire) !== null && _q !== void 0 ? _q : false, (value) => { blueprint.indirectFire = value; });
+ (0, utils_1.addStringInput)(this.contentDiv2, "Description", (_r = blueprint.description) !== null && _r !== void 0 ? _r : "", "text", (value) => { blueprint.description = value; });
+ (0, utils_1.addStringInput)(this.contentDiv2, "Abilities", (_s = blueprint.abilities) !== null && _s !== void 0 ? _s : "", "text", (value) => { blueprint.abilities = value; });
}
}
/** Add a new empty blueprint
@@ -613,10 +618,10 @@ class LoadoutEditor {
title.innerText = "Loadout properties";
__classPrivateFieldGet(this, _LoadoutEditor_contentDiv, "f").appendChild(title);
if (__classPrivateFieldGet(this, _LoadoutEditor_loadout, "f")) {
- var laodout = __classPrivateFieldGet(this, _LoadoutEditor_loadout, "f");
- (0, utils_1.addStringInput)(__classPrivateFieldGet(this, _LoadoutEditor_contentDiv, "f"), "Name", laodout.name, "text", (value) => { laodout.name = value; __classPrivateFieldGet(this, _LoadoutEditor_contentDiv, "f").dispatchEvent(new Event("refresh")); });
- (0, utils_1.addStringInput)(__classPrivateFieldGet(this, _LoadoutEditor_contentDiv, "f"), "Code", laodout.code, "text", (value) => { laodout.code = value; });
- (0, utils_1.addStringInput)(__classPrivateFieldGet(this, _LoadoutEditor_contentDiv, "f"), "Roles", (0, utils_1.arrayToString)(laodout.roles), "text", (value) => { laodout.roles = (0, utils_1.stringToArray)(value); });
+ var loadout = __classPrivateFieldGet(this, _LoadoutEditor_loadout, "f");
+ (0, utils_1.addStringInput)(__classPrivateFieldGet(this, _LoadoutEditor_contentDiv, "f"), "Name", loadout.name, "text", (value) => { loadout.name = value; __classPrivateFieldGet(this, _LoadoutEditor_contentDiv, "f").dispatchEvent(new Event("refresh")); });
+ (0, utils_1.addStringInput)(__classPrivateFieldGet(this, _LoadoutEditor_contentDiv, "f"), "Code", loadout.code, "text", (value) => { loadout.code = value; });
+ (0, utils_1.addStringInput)(__classPrivateFieldGet(this, _LoadoutEditor_contentDiv, "f"), "Roles", (0, utils_1.arrayToString)(loadout.roles), "text", (value) => { loadout.roles = (0, utils_1.stringToArray)(value); });
(0, utils_1.addLoadoutItemsEditor)(__classPrivateFieldGet(this, _LoadoutEditor_contentDiv, "f"), __classPrivateFieldGet(this, _LoadoutEditor_loadout, "f"));
}
}
@@ -1034,25 +1039,12 @@ exports.addLoadoutsScroll = addLoadoutsScroll;
* @returns The string
*/
function arrayToString(array) {
- var value = "[";
- var firstRole = true;
- array.forEach((role) => {
- value += firstRole ? "" : ", ";
- firstRole = false;
- value += role;
- });
- value += "]";
- return value;
+ return "[" + array.join(", ") + "]";
}
exports.arrayToString = arrayToString;
function stringToArray(input) {
- input = input.replace("[", "").replace("]", "");
- var values = input.split(",");
- var result = [];
- values.forEach((value) => {
- result.push(value.trim());
- });
- return result;
+ var _a;
+ return (_a = input.match(/(\w)+/g)) !== null && _a !== void 0 ? _a : [];
}
exports.stringToArray = stringToArray;
diff --git a/client/plugins/databasemanager/src/databasemanagerplugin.ts b/client/plugins/databasemanager/src/databasemanagerplugin.ts
index a842acb2..690beba5 100644
--- a/client/plugins/databasemanager/src/databasemanagerplugin.ts
+++ b/client/plugins/databasemanager/src/databasemanagerplugin.ts
@@ -86,7 +86,7 @@ export class DatabaseManagerPlugin implements OlympusPlugin {
/* Create the container for the database editor elements and the elements themselves */
this.#mainContentContainer = document.createElement("div");
this.#mainContentContainer.classList.add("dm-container");
- this.#element.appendChild(this.#mainContentContainer)
+ this.#element.appendChild(this.#mainContentContainer);
this.#contentDiv1 = document.createElement("div");
this.#contentDiv1.classList.add("dm-content-container");
diff --git a/client/plugins/databasemanager/src/grounduniteditor.ts b/client/plugins/databasemanager/src/grounduniteditor.ts
index f5e49d9f..f8172a75 100644
--- a/client/plugins/databasemanager/src/grounduniteditor.ts
+++ b/client/plugins/databasemanager/src/grounduniteditor.ts
@@ -36,12 +36,17 @@ export class GroundUnitEditor extends UnitEditor {
addStringInput(this.contentDiv2, "Cost", String(blueprint.cost)?? "", "number", (value: string) => {blueprint.cost = parseFloat(value); });
addStringInput(this.contentDiv2, "Acquisition range [m]", String(blueprint.acquisitionRange)?? "", "number", (value: string) => {blueprint.acquisitionRange = parseFloat(value); });
addStringInput(this.contentDiv2, "Engagement range [m]", String(blueprint.engagementRange)?? "", "number", (value: string) => {blueprint.engagementRange = parseFloat(value); });
+ addStringInput(this.contentDiv2, "Targeting range [m]", String(blueprint.targetingRange)?? "", "number", (value: string) => {blueprint.targetingRange = parseFloat(value); });
addStringInput(this.contentDiv2, "Barrel height [m]", String(blueprint.barrelHeight)?? "", "number", (value: string) => {blueprint.barrelHeight = parseFloat(value); });
addStringInput(this.contentDiv2, "Muzzle velocity [m/s]", String(blueprint.muzzleVelocity)?? "", "number", (value: string) => {blueprint.muzzleVelocity = parseFloat(value); });
addStringInput(this.contentDiv2, "Aim time [s]", String(blueprint.aimTime)?? "", "number", (value: string) => {blueprint.aimTime = parseFloat(value); });
addStringInput(this.contentDiv2, "Burst quantity", String(blueprint.shotsToFire)?? "", "number", (value: string) => {blueprint.shotsToFire = Math.round(parseFloat(value)); });
+ addStringInput(this.contentDiv2, "Burst base interval [s]", String(blueprint.shotsBaseInterval)?? "", "number", (value: string) => {blueprint.shotsBaseInterval = Math.round(parseFloat(value)); });
+ addStringInput(this.contentDiv2, "Base scatter [°]", String(blueprint.shotsBaseScatter)?? "", "number", (value: string) => {blueprint.shotsBaseScatter = Math.round(parseFloat(value)); });
addCheckboxInput(this.contentDiv2, "Can target point", blueprint.canTargetPoint ?? false, (value: boolean) => {blueprint.canTargetPoint = value;})
addCheckboxInput(this.contentDiv2, "Can rearm", blueprint.canRearm ?? false, (value: boolean) => {blueprint.canRearm = value;})
+ addCheckboxInput(this.contentDiv2, "Can operate as AAA", blueprint.canAAA ?? false, (value: boolean) => {blueprint.canAAA = value;})
+ addCheckboxInput(this.contentDiv2, "Indirect fire (e.g. mortar)", blueprint.indirectFire ?? false, (value: boolean) => {blueprint.indirectFire = value;})
addStringInput(this.contentDiv2, "Description", blueprint.description ?? "", "text", (value: string) => {blueprint.description = value; });
addStringInput(this.contentDiv2, "Abilities", blueprint.abilities ?? "", "text", (value: string) => {blueprint.abilities = value; });
}
diff --git a/client/plugins/databasemanager/src/loadouteditor.ts b/client/plugins/databasemanager/src/loadouteditor.ts
index 73fe32e1..5f07c605 100644
--- a/client/plugins/databasemanager/src/loadouteditor.ts
+++ b/client/plugins/databasemanager/src/loadouteditor.ts
@@ -37,10 +37,10 @@ export class LoadoutEditor {
this.#contentDiv.appendChild(title);
if (this.#loadout) {
- var laodout = this.#loadout;
- addStringInput(this.#contentDiv, "Name", laodout.name, "text", (value: string) => {laodout.name = value; this.#contentDiv.dispatchEvent(new Event("refresh"));});
- addStringInput(this.#contentDiv, "Code", laodout.code, "text", (value: string) => {laodout.code = value; });
- addStringInput(this.#contentDiv, "Roles", arrayToString(laodout.roles), "text", (value: string) => {laodout.roles = stringToArray(value);});
+ var loadout = this.#loadout;
+ addStringInput(this.#contentDiv, "Name", loadout.name, "text", (value: string) => {loadout.name = value; this.#contentDiv.dispatchEvent(new Event("refresh"));});
+ addStringInput(this.#contentDiv, "Code", loadout.code, "text", (value: string) => {loadout.code = value; });
+ addStringInput(this.#contentDiv, "Roles", arrayToString(loadout.roles), "text", (value: string) => {loadout.roles = stringToArray(value);});
addLoadoutItemsEditor(this.#contentDiv, this.#loadout);
}
}
diff --git a/client/plugins/databasemanager/src/uniteditor.ts b/client/plugins/databasemanager/src/uniteditor.ts
index b031a2c4..00c59fc9 100644
--- a/client/plugins/databasemanager/src/uniteditor.ts
+++ b/client/plugins/databasemanager/src/uniteditor.ts
@@ -49,9 +49,9 @@ export abstract class UnitEditor {
}
/** Show the editor
- *
+ * @param filter String filter
*/
- show() {
+ show(filter: string = "") {
this.visible = true;
this.contentDiv1.replaceChildren();
this.contentDiv2.replaceChildren();
@@ -62,20 +62,20 @@ export abstract class UnitEditor {
var title = document.createElement("label");
title.innerText = "Units list";
this.contentDiv1.appendChild(title);
-
- addBlueprintsScroll(this.contentDiv1, this.database, (key: string) => {
- if (this.database != null)
- this.setBlueprint(this.database.blueprints[key])
- })
- addNewElementInput(this.contentDiv1, (ev: MouseEvent, input: HTMLInputElement) => {
- if (input.value != "")
- this.addBlueprint((input).value);
- });
+ var filterInput = document.createElement("input");
+ filterInput.value = filter;
+ this.contentDiv1.appendChild(filterInput);
+
+ filterInput.onchange = (e: Event) => {
+ this.show((e.target as HTMLInputElement).value);
+ }
+
+ this.addBlueprints(filter);
}
}
- /** Hid the editor
+ /** Hide the editor
*
*/
hide() {
@@ -93,6 +93,24 @@ export abstract class UnitEditor {
return this.database;
}
+ /**
+ *
+ * @param filter String filter
+ */
+ addBlueprints(filter: string = "") {
+ if (this.database) {
+ addBlueprintsScroll(this.contentDiv1, this.database, filter, (key: string) => {
+ if (this.database != null)
+ this.setBlueprint(this.database.blueprints[key])
+ });
+
+ addNewElementInput(this.contentDiv1, (ev: MouseEvent, input: HTMLInputElement) => {
+ if (input.value != "")
+ this.addBlueprint((input).value);
+ });
+ }
+ }
+
/* Abstract methods which will depend on the specific type of units */
abstract setBlueprint(blueprint: UnitBlueprint): void;
abstract addBlueprint(key: string): void;
diff --git a/client/plugins/databasemanager/src/utils.ts b/client/plugins/databasemanager/src/utils.ts
index 19cec041..004a8b84 100644
--- a/client/plugins/databasemanager/src/utils.ts
+++ b/client/plugins/databasemanager/src/utils.ts
@@ -174,40 +174,60 @@ export function addNewElementInput(div: HTMLElement, callback: CallableFunction)
*
* @param div The HTMLElement that will contain the list
* @param database The database that will be used to fill the list of blueprints
+ * @param filter A string filter that will be executed to filter the blueprints to add
* @param callback Callback called when the user clicks on one of the elements
*/
-export function addBlueprintsScroll(div: HTMLElement, database: {blueprints: {[key: string]: UnitBlueprint}}, callback: CallableFunction) {
+export function addBlueprintsScroll(div: HTMLElement, database: {blueprints: {[key: string]: UnitBlueprint}}, filter: string, callback: CallableFunction) {
var scrollDiv = document.createElement("div");
scrollDiv.classList.add("dm-scroll-container");
if (database !== null) {
var blueprints: {[key: string]: UnitBlueprint} = database.blueprints;
for (let key of Object.keys(blueprints).sort((a, b) => a.localeCompare(b, undefined, {sensitivity: 'base'}))) {
- var rowDiv = document.createElement("div");
- scrollDiv.appendChild(rowDiv);
-
- var text = document.createElement("label");
- text.textContent = key;
- text.onclick = () => callback(key);
- rowDiv.appendChild(text);
-
- let checkbox = document.createElement("input");
- checkbox.type = "checkbox";
- checkbox.checked = blueprints[key].enabled;
- checkbox.onclick = () => {
- console.log(checkbox.checked);
- blueprints[key].enabled = checkbox.checked;
+ var addKey = true;
+ if (filter !== "") {
+ try {
+ var blueprint = blueprints[key];
+ addKey = eval(filter);
+ } catch {
+ console.error("An error has occurred evaluating the blueprint filter")
+ }
}
- rowDiv.appendChild(checkbox);
- /* This button allows to remove an element from the list. It requires a refresh. */
- var button = document.createElement("button");
- button.innerText = "X";
- button.onclick = () => {
- delete blueprints[key];
- div.dispatchEvent(new Event("refresh"));
+ if (addKey) {
+ var rowDiv = document.createElement("div");
+ scrollDiv.appendChild(rowDiv);
+
+ let text = document.createElement("label");
+ text.textContent = key;
+ text.onclick = () => {
+ callback(key);
+ const collection = document.getElementsByClassName("blueprint-selected");
+ for (let i = 0; i < collection.length; i++) {
+ collection[i].classList.remove("blueprint-selected");
+ }
+ text.classList.add("blueprint-selected");
+ }
+ rowDiv.appendChild(text);
+
+ let checkbox = document.createElement("input");
+ checkbox.type = "checkbox";
+ checkbox.checked = blueprints[key].enabled;
+ checkbox.onclick = () => {
+ console.log(checkbox.checked);
+ blueprints[key].enabled = checkbox.checked;
+ }
+ rowDiv.appendChild(checkbox);
+
+ /* This button allows to remove an element from the list. It requires a refresh. */
+ var button = document.createElement("button");
+ button.innerText = "X";
+ button.onclick = () => {
+ delete blueprints[key];
+ div.dispatchEvent(new Event("refresh"));
+ }
+ rowDiv.appendChild(button);
}
- rowDiv.appendChild(button);
}
}
div.appendChild(scrollDiv);
@@ -269,5 +289,5 @@ export function arrayToString(array: string[]) {
export function stringToArray(input: string) {
- return input.match( /(\w)+/g );
+ return input.match( /(\w)+/g ) ?? [];
}
\ No newline at end of file
diff --git a/client/plugins/databasemanager/style.css b/client/plugins/databasemanager/style.css
index 9ba77136..094ddb22 100644
--- a/client/plugins/databasemanager/style.css
+++ b/client/plugins/databasemanager/style.css
@@ -115,6 +115,10 @@
font-weight: bold;
}
+#database-manager-panel input {
+ font-weight: bold;
+}
+
.dm-scroll-container>div:nth-child(even) {
background-color: gainsboro;
}
@@ -131,11 +135,16 @@
}
.dm-scroll-container>div *:nth-child(1):hover {
- background-color: var(--secondary-blue-text);
+ background-color: var(--accent-dark-blue);
color: white;
cursor: pointer;
}
+.blueprint-selected {
+ background-color: var(--accent-light-blue) !important;
+ color: white;
+}
+
.dm-scroll-container>div {
display: flex;
align-items: center;
diff --git a/client/public/databases/units/groundunitdatabase.json b/client/public/databases/units/groundunitdatabase.json
index cca675d9..cf7ca6af 100644
--- a/client/public/databases/units/groundunitdatabase.json
+++ b/client/public/databases/units/groundunitdatabase.json
@@ -1029,13 +1029,19 @@
}
},
"barrelHeight": 2.35,
- "muzzleVelocity": 1440,
+ "muzzleVelocity": 1000,
"acquisitionRange": 15000,
"engagementRange": 4000,
"description": "Tracked self-propelled anti-aircraft 35mm guns",
"abilities": "",
"canTargetPoint": true,
- "canRearm": false
+ "canRearm": false,
+ "canAAA": true,
+ "aimTime": 5,
+ "shotsToFire": 2,
+ "shotsBaseInterval": 5,
+ "shotsBaseScatter": 2,
+ "targetingRange": 800
},
"Grad-URAL": {
"name": "Grad-URAL",
@@ -2282,7 +2288,8 @@
"description": "Single infantry carrying AK-74",
"abilities": "",
"canTargetPoint": true,
- "canRearm": false
+ "canRearm": false,
+ "canAAA": true
},
"KAMAZ Truck": {
"name": "KAMAZ Truck",
diff --git a/client/public/stylesheets/panels/unitcontrol.css b/client/public/stylesheets/panels/unitcontrol.css
index 770109f6..99509503 100644
--- a/client/public/stylesheets/panels/unitcontrol.css
+++ b/client/public/stylesheets/panels/unitcontrol.css
@@ -166,20 +166,23 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
#unit-control-panel .switch-control {
align-items: center;
- display: grid;
- grid-template-columns: 1.35fr 0.65fr;
-}
-
-#unit-control-panel .switch-control>*:nth-child(2) {
- justify-self: end;
-}
-
-#unit-control-panel .switch-control>*:nth-child(3) {
- color: var(--secondary-semitransparent-white);
+ display: flex;
+ width: 100%;
+ justify-content: space-between;
}
#unit-control-panel .switch-control h4 {
margin: 0px;
+ display: flex;
+ align-items: center;
+}
+
+#unit-control-panel .switch-control h4 img {
+ height: 15px;
+ margin-left: 10px;
+ cursor: pointer;
+ filter: invert(100%);
+ opacity: 80%;
}
#unit-control-panel .switch-control .ol-switch {
diff --git a/client/public/stylesheets/panels/unitinfo.css b/client/public/stylesheets/panels/unitinfo.css
index 50c90faf..b970dfa4 100644
--- a/client/public/stylesheets/panels/unitinfo.css
+++ b/client/public/stylesheets/panels/unitinfo.css
@@ -91,9 +91,9 @@
#loadout-silhouette {
filter: invert(100%);
- height: 100px;
+ height: 75px;
margin-right: 25px;
- width: 100px;
+ width: 75px;
}
#loadout-items {
diff --git a/client/public/stylesheets/style/style.css b/client/public/stylesheets/style/style.css
index 0a49d7a1..e78dfc8a 100644
--- a/client/public/stylesheets/style/style.css
+++ b/client/public/stylesheets/style/style.css
@@ -664,6 +664,7 @@ nav.ol-panel> :last-child {
#unit-control-panel .ol-option-button button.selected svg * {
fill: var(--background-steel);
+ stroke: var(--background-steel);
}
#rapid-controls {
diff --git a/client/public/themes/olympus/images/buttons/emissions/attack.svg b/client/public/themes/olympus/images/buttons/emissions/attack.svg
index 0846e4e6..0e1bd78d 100644
--- a/client/public/themes/olympus/images/buttons/emissions/attack.svg
+++ b/client/public/themes/olympus/images/buttons/emissions/attack.svg
@@ -38,6 +38,7 @@
inkscape:window-maximized="1"
inkscape:current-layer="svg4" />