Merge branch 'main' into 499-spawn-menu-reorganisation

This commit is contained in:
Pax1601
2023-11-06 11:12:46 +01:00
committed by GitHub
58 changed files with 13571 additions and 12498 deletions

View File

@@ -83,6 +83,7 @@ declare module "controls/switch" {
} }
declare module "constants/constants" { declare module "constants/constants" {
import { LatLng, LatLngBounds } from "leaflet"; import { LatLng, LatLngBounds } from "leaflet";
import { MapMarkerControl } from "map/map";
export const UNITS_URI = "units"; export const UNITS_URI = "units";
export const WEAPONS_URI = "weapons"; export const WEAPONS_URI = "weapons";
export const LOGS_URI = "logs"; export const LOGS_URI = "logs";
@@ -107,6 +108,8 @@ declare module "constants/constants" {
export const ROEDescriptions: string[]; export const ROEDescriptions: string[];
export const reactionsToThreatDescriptions: string[]; export const reactionsToThreatDescriptions: string[];
export const emissionsCountermeasuresDescriptions: string[]; export const emissionsCountermeasuresDescriptions: string[];
export const shotsScatterDescriptions: string[];
export const shotsIntensityDescriptions: string[];
export const minSpeedValues: { export const minSpeedValues: {
[key: string]: number; [key: string]: number;
}; };
@@ -192,6 +195,7 @@ declare module "constants/constants" {
export const visibilityControls: string[]; export const visibilityControls: string[];
export const visibilityControlsTypes: string[][]; export const visibilityControlsTypes: string[][];
export const visibilityControlsTooltips: string[]; export const visibilityControlsTooltips: string[];
export const MAP_MARKER_CONTROLS: MapMarkerControl[];
export const IADSTypes: string[]; export const IADSTypes: string[];
export const IADSDensities: { export const IADSDensities: {
[key: string]: number; [key: string]: number;
@@ -221,31 +225,35 @@ declare module "constants/constants" {
hasTask = 12, hasTask = 12,
position = 13, position = 13,
speed = 14, speed = 14,
heading = 15, horizontalVelocity = 15,
isActiveTanker = 16, verticalVelocity = 16,
isActiveAWACS = 17, heading = 17,
onOff = 18, isActiveTanker = 18,
followRoads = 19, isActiveAWACS = 19,
fuel = 20, onOff = 20,
desiredSpeed = 21, followRoads = 21,
desiredSpeedType = 22, fuel = 22,
desiredAltitude = 23, desiredSpeed = 23,
desiredAltitudeType = 24, desiredSpeedType = 24,
leaderID = 25, desiredAltitude = 25,
formationOffset = 26, desiredAltitudeType = 26,
targetID = 27, leaderID = 27,
targetPosition = 28, formationOffset = 28,
ROE = 29, targetID = 29,
reactionToThreat = 30, targetPosition = 30,
emissionsCountermeasures = 31, ROE = 31,
TACAN = 32, reactionToThreat = 32,
radio = 33, emissionsCountermeasures = 33,
generalSettings = 34, TACAN = 34,
ammo = 35, radio = 35,
contacts = 36, generalSettings = 36,
activePath = 37, ammo = 37,
isLeader = 38, contacts = 38,
operateAs = 39, activePath = 39,
isLeader = 40,
operateAs = 41,
shotsScatter = 42,
shotsIntensity = 43,
endOfData = 255 endOfData = 255
} }
export const MGRS_PRECISION_10KM = 2; export const MGRS_PRECISION_10KM = 2;
@@ -253,6 +261,8 @@ declare module "constants/constants" {
export const MGRS_PRECISION_100M = 4; export const MGRS_PRECISION_100M = 4;
export const MGRS_PRECISION_10M = 5; export const MGRS_PRECISION_10M = 5;
export const MGRS_PRECISION_1M = 6; export const MGRS_PRECISION_1M = 6;
export const DELETE_CYCLE_TIME = 0.05;
export const DELETE_SLOW_THRESHOLD = 50;
} }
declare module "map/markers/custommarker" { declare module "map/markers/custommarker" {
import { Map, Marker } from "leaflet"; import { Map, Marker } from "leaflet";
@@ -303,7 +313,7 @@ declare module "controls/dropdown" {
#private; #private;
constructor(ID: string | null, callback: CallableFunction, options?: string[] | null, defaultText?: string); constructor(ID: string | null, callback: CallableFunction, options?: string[] | null, defaultText?: string);
getContainer(): HTMLElement; getContainer(): HTMLElement;
setOptions(optionsList: string[], sortAlphabetically?: boolean): void; setOptions(optionsList: string[], sort?: "" | "string" | "number"): void;
setOptionsElements(optionsElements: HTMLElement[]): void; setOptionsElements(optionsElements: HTMLElement[]): void;
getOptionElements(): HTMLCollection; getOptionElements(): HTMLCollection;
addOptionElement(optionElement: HTMLElement): void; addOptionElement(optionElement: HTMLElement): void;
@@ -498,6 +508,8 @@ declare module "interfaces" {
hasTask: boolean; hasTask: boolean;
position: LatLng; position: LatLng;
speed: number; speed: number;
horizontalVelocity: number;
verticalVelocity: number;
heading: number; heading: number;
isActiveTanker: boolean; isActiveTanker: boolean;
isActiveAWACS: boolean; isActiveAWACS: boolean;
@@ -523,6 +535,8 @@ declare module "interfaces" {
activePath: LatLng[]; activePath: LatLng[];
isLeader: boolean; isLeader: boolean;
operateAs: string; operateAs: string;
shotsScatter: number;
shotsIntensity: number;
} }
export interface LoadoutItemBlueprint { export interface LoadoutItemBlueprint {
name: string; name: string;
@@ -558,12 +572,19 @@ declare module "interfaces" {
muzzleVelocity?: number; muzzleVelocity?: number;
aimTime?: number; aimTime?: number;
shotsToFire?: number; shotsToFire?: number;
shotsBaseInterval?: number;
shotsBaseScatter?: number;
description?: string; description?: string;
abilities?: string; abilities?: string;
acquisitionRange?: number; acquisitionRange?: number;
engagementRange?: number; engagementRange?: number;
targetingRange?: number;
aimMethodRange?: number;
alertnessTimeConstant?: number;
canTargetPoint?: boolean; canTargetPoint?: boolean;
canRearm?: boolean; canRearm?: boolean;
canAAA?: boolean;
indirectFire?: boolean;
} }
export interface UnitSpawnOptions { export interface UnitSpawnOptions {
roleType: string; roleType: string;
@@ -604,6 +625,7 @@ declare module "interfaces" {
export interface ShortcutOptions { export interface ShortcutOptions {
altKey?: boolean; altKey?: boolean;
callback: CallableFunction; callback: CallableFunction;
context?: string;
ctrlKey?: boolean; ctrlKey?: boolean;
name?: string; name?: string;
shiftKey?: boolean; shiftKey?: boolean;
@@ -786,9 +808,11 @@ declare module "controls/unitspawnmenu" {
import { UnitSpawnOptions } from "interfaces"; import { UnitSpawnOptions } from "interfaces";
export class UnitSpawnMenu { export class UnitSpawnMenu {
#private; #private;
spawnOptions: UnitSpawnOptions; protected showRangeCircles: boolean;
protected spawnOptions: UnitSpawnOptions;
constructor(ID: string, unitDatabase: UnitDatabase, orderByRole: boolean); constructor(ID: string, unitDatabase: UnitDatabase, orderByRole: boolean);
getContainer(): HTMLElement; getContainer(): HTMLElement;
getVisible(): boolean;
reset(): void; reset(): void;
setCountries(): void; setCountries(): void;
refreshOptions(): void; refreshOptions(): void;
@@ -824,6 +848,7 @@ declare module "controls/unitspawnmenu" {
deployUnits(spawnOptions: UnitSpawnOptions, unitsCount: number): void; deployUnits(spawnOptions: UnitSpawnOptions, unitsCount: number): void;
} }
export class GroundUnitSpawnMenu extends UnitSpawnMenu { export class GroundUnitSpawnMenu extends UnitSpawnMenu {
protected showRangeCircles: boolean;
/** /**
* *
* @param ID - the ID of the HTML element which will contain the context menu * @param ID - the ID of the HTML element which will contain the context menu
@@ -1036,6 +1061,8 @@ declare module "unit/unit" {
getHasTask(): boolean; getHasTask(): boolean;
getPosition(): LatLng; getPosition(): LatLng;
getSpeed(): number; getSpeed(): number;
getHorizontalVelocity(): number;
getVerticalVelocity(): number;
getHeading(): number; getHeading(): number;
getIsActiveTanker(): boolean; getIsActiveTanker(): boolean;
getIsActiveAWACS(): boolean; getIsActiveAWACS(): boolean;
@@ -1061,6 +1088,8 @@ declare module "unit/unit" {
getActivePath(): LatLng[]; getActivePath(): LatLng[];
getIsLeader(): boolean; getIsLeader(): boolean;
getOperateAs(): string; getOperateAs(): string;
getShotsScatter(): number;
getShotsIntensity(): number;
static getConstructor(type: string): typeof GroundUnit | undefined; static getConstructor(type: string): typeof GroundUnit | undefined;
constructor(ID: number); constructor(ID: number);
getCategory(): string; getCategory(): string;
@@ -1097,6 +1126,9 @@ declare module "unit/unit" {
isInViewport(): boolean; isInViewport(): boolean;
canTargetPoint(): boolean; canTargetPoint(): boolean;
canRearm(): boolean; canRearm(): boolean;
canLandAtPoint(): boolean;
canAAA(): boolean;
indirectFire(): boolean;
isTanker(): boolean; isTanker(): boolean;
isAWACS(): boolean; isAWACS(): boolean;
/********************** Unit commands *************************/ /********************** Unit commands *************************/
@@ -1132,6 +1164,8 @@ declare module "unit/unit" {
scenicAAA(): void; scenicAAA(): void;
missOnPurpose(): void; missOnPurpose(): void;
landAtPoint(latlng: LatLng): void; landAtPoint(latlng: LatLng): void;
setShotsScatter(shotsScatter: number): void;
setShotsIntensity(shotsIntensity: number): void;
/***********************************************/ /***********************************************/
getActions(): { getActions(): {
[key: string]: { [key: string]: {
@@ -1331,6 +1365,20 @@ declare module "contextmenus/airbasespawnmenu" {
setAirbase(airbase: Airbase): void; setAirbase(airbase: Airbase): void;
} }
} }
declare module "context/context" {
export interface ContextInterface {
useSpawnMenu?: boolean;
useUnitControlPanel?: boolean;
useUnitInfoPanel?: boolean;
}
export class Context {
#private;
constructor(config: ContextInterface);
getUseSpawnMenu(): boolean;
getUseUnitControlPanel(): boolean;
getUseUnitInfoPanel(): boolean;
}
}
declare module "other/manager" { declare module "other/manager" {
export class Manager { export class Manager {
#private; #private;
@@ -1406,6 +1454,14 @@ declare module "map/map" {
import { CoalitionArea } from "map/coalitionarea/coalitionarea"; import { CoalitionArea } from "map/coalitionarea/coalitionarea";
import { CoalitionAreaContextMenu } from "contextmenus/coalitionareacontextmenu"; import { CoalitionAreaContextMenu } from "contextmenus/coalitionareacontextmenu";
import { AirbaseSpawnContextMenu } from "contextmenus/airbasespawnmenu"; import { AirbaseSpawnContextMenu } from "contextmenus/airbasespawnmenu";
export type MapMarkerControl = {
"image": string;
"isProtected"?: boolean;
"name": string;
"protectable"?: boolean;
"toggles": string[];
"tooltip": string;
};
export class Map extends L.Map { export class Map extends L.Map {
#private; #private;
/** /**
@@ -1453,6 +1509,7 @@ declare module "map/map" {
getVisibilityOptions(): { getVisibilityOptions(): {
[key: string]: boolean; [key: string]: boolean;
}; };
unitIsProtected(unit: Unit): boolean;
} }
} }
declare module "mission/bullseye" { declare module "mission/bullseye" {
@@ -1569,6 +1626,7 @@ declare module "panels/unitinfopanel" {
export class UnitInfoPanel extends Panel { export class UnitInfoPanel extends Panel {
#private; #private;
constructor(ID: string); constructor(ID: string);
show(): void;
} }
} }
declare module "plugin/pluginmanager" { declare module "plugin/pluginmanager" {
@@ -1647,6 +1705,14 @@ declare module "unit/citiesDatabase" {
pop: number; 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" { declare module "unit/unitsmanager" {
import { LatLng, LatLngBounds } from "leaflet"; import { LatLng, LatLngBounds } from "leaflet";
import { Unit } from "unit/unit"; import { Unit } from "unit/unit";
@@ -1713,7 +1779,9 @@ declare module "unit/unitsmanager" {
*/ */
getSelectedUnits(options?: { getSelectedUnits(options?: {
excludeHumans?: boolean; excludeHumans?: boolean;
excludeProtected?: boolean;
onlyOnePerGroup?: boolean; onlyOnePerGroup?: boolean;
showProtectionReminder?: boolean;
}): Unit[]; }): Unit[];
/** Deselects all currently selected units /** Deselects all currently selected units
* *
@@ -1876,6 +1944,16 @@ declare module "unit/unitsmanager" {
* @param latlng Point where to land * @param latlng Point where to land
*/ */
selectedUnitsLandAtPoint(latlng: LatLng): void; 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 ************************/ /*********************** Control operations on selected units ************************/
/** See getUnitsCategories for more info /** See getUnitsCategories for more info
* *
@@ -2066,6 +2144,8 @@ declare module "server/servermanager" {
scenicAAA(ID: number, coalition: string, callback?: CallableFunction): void; scenicAAA(ID: number, coalition: string, callback?: CallableFunction): void;
missOnPurpose(ID: number, coalition: string, callback?: CallableFunction): void; missOnPurpose(ID: number, coalition: string, callback?: CallableFunction): void;
landAtPoint(ID: number, latlng: LatLng, 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; setAdvacedOptions(ID: number, isActiveTanker: boolean, isActiveAWACS: boolean, TACAN: TACAN, radio: Radio, generalSettings: GeneralSettings, callback?: CallableFunction): void;
setCommandModeOptions(restrictSpawns: boolean, restrictToCoalition: boolean, spawnPoints: { setCommandModeOptions(restrictSpawns: boolean, restrictToCoalition: boolean, spawnPoints: {
blue: number; blue: number;
@@ -2094,6 +2174,18 @@ declare module "panels/unitlistpanel" {
toggle(): void; toggle(): void;
} }
} }
declare module "context/contextmanager" {
import { Manager } from "other/manager";
import { ContextInterface } from "context/context";
export class ContextManager extends Manager {
#private;
constructor();
add(name: string, contextConfig: ContextInterface): this;
currentContextIs(contextName: string): boolean;
getCurrentContext(): any;
setContext(contextName: string): false | undefined;
}
}
declare module "olympusapp" { declare module "olympusapp" {
import { Map } from "map/map"; import { Map } from "map/map";
import { MissionManager } from "mission/missionmanager"; import { MissionManager } from "mission/missionmanager";
@@ -2103,10 +2195,15 @@ declare module "olympusapp" {
import { WeaponsManager } from "weapon/weaponsmanager"; import { WeaponsManager } from "weapon/weaponsmanager";
import { Manager } from "other/manager"; import { Manager } from "other/manager";
import { ServerManager } from "server/servermanager"; import { ServerManager } from "server/servermanager";
import { ContextManager } from "context/contextmanager";
import { Context } from "context/context";
export class OlympusApp { export class OlympusApp {
#private; #private;
constructor(); constructor();
getDialogManager(): Manager;
getMap(): Map; getMap(): Map;
getCurrentContext(): Context;
getContextManager(): ContextManager;
getServerManager(): ServerManager; getServerManager(): ServerManager;
getPanelsManager(): Manager; getPanelsManager(): Manager;
getPopupsManager(): Manager; getPopupsManager(): Manager;
@@ -2158,3 +2255,11 @@ declare module "index" {
import { OlympusApp } from "olympusapp"; import { OlympusApp } from "olympusapp";
export function getApp(): OlympusApp; export function getApp(): OlympusApp;
} }
declare module "context/contextmenumanager" {
import { ContextMenu } from "contextmenus/contextmenu";
import { Manager } from "other/manager";
export class ContextMenuManager extends Manager {
constructor();
add(name: string, contextMenu: ContextMenu): this;
}
}

View File

@@ -4,7 +4,7 @@ var enc = new TextEncoder();
const DEMO_UNIT_DATA = { const DEMO_UNIT_DATA = {
["1"]:{ category: "Aircraft", alive: true, human: false, controlled: true, coalition: 2, country: 0, name: "KC-135", unitName: "Cool guy 1-1 who also has a very long name", groupName: "Cool group 1", state: 1, task: "Being cool!", ["1"]:{ category: "Aircraft", alive: true, human: false, controlled: true, coalition: 2, country: 0, name: "KC-135", unitName: "Cool guy 1-1 who also has a very long name", groupName: "Cool group 1", state: 1, task: "Being cool!",
hasTask: true, position: { lat: 37, lng: -116, alt: 1000 }, speed: 200, heading: 45, isActiveTanker: true, isActiveAWACS: false, onOff: true, followRoads: false, fuel: 50, hasTask: true, position: { lat: 37, lng: -116, alt: 1000 }, speed: 200, horizontalVelocity: 200, verticalVelicity: 0, heading: 45, isActiveTanker: true, isActiveAWACS: false, onOff: true, followRoads: false, fuel: 50,
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0, desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
formationOffset: { x: 0, y: 0, z: 0 }, formationOffset: { x: 0, y: 0, z: 0 },
targetID: 0, targetID: 0,
@@ -20,7 +20,7 @@ const DEMO_UNIT_DATA = {
activePath: [{lat: 38, lng: -115, alt: 0}, {lat: 38, lng: -114, alt: 0}] activePath: [{lat: 38, lng: -115, alt: 0}, {lat: 38, lng: -114, alt: 0}]
}, },
["2"]:{ category: "Aircraft", alive: true, human: false, controlled: true, coalition: 1, country: 0, name: "E-3A", unitName: "Cool guy 1-2", groupName: "Cool group 2", state: 1, task: "Being cool", ["2"]:{ category: "Aircraft", alive: true, human: false, controlled: true, coalition: 1, country: 0, name: "E-3A", unitName: "Cool guy 1-2", groupName: "Cool group 2", state: 1, task: "Being cool",
hasTask: true, position: { lat: 36.9, lng: -116, alt: 1000 }, speed: 200, heading: 315 * Math.PI / 180, isActiveTanker: false, isActiveAWACS: true, onOff: true, followRoads: false, fuel: 50, hasTask: true, position: { lat: 36.9, lng: -116, alt: 1000 }, speed: 200, horizontalVelocity: 200, verticalVelicity: 0, heading: 315 * Math.PI / 180, isActiveTanker: false, isActiveAWACS: true, onOff: true, followRoads: false, fuel: 50,
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0, desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
formationOffset: { x: 0, y: 0, z: 0 }, formationOffset: { x: 0, y: 0, z: 0 },
targetID: 0, targetID: 0,
@@ -34,8 +34,8 @@ const DEMO_UNIT_DATA = {
ammo: [{ quantity: 2, name: "A cool missile", guidance: 0, category: 0, missileCategory: 0 } ], ammo: [{ quantity: 2, name: "A cool missile", guidance: 0, category: 0, missileCategory: 0 } ],
contacts: [{ID: 4, detectionMethod: 1}], contacts: [{ID: 4, detectionMethod: 1}],
activePath: [ ] activePath: [ ]
}, ["3"]:{ category: "Helicopter", alive: true, human: true, controlled: false, coalition: 1, country: 0, name: "AH-64D_BLK_II", unitName: "Cool guy 1-4", groupName: "Cool group 3", state: 1, task: "Being cool", }, ["3"]:{ category: "Helicopter", alive: true, human: false, controlled: false, coalition: 1, country: 0, name: "AH-64D_BLK_II", unitName: "Cool guy 1-4", groupName: "Cool group 3", state: 1, task: "Being cool",
hasTask: false, position: { lat: 37.1, lng: -116.1, alt: 1000 }, speed: 200, heading: 315 * Math.PI / 180, isActiveTanker: false, isActiveAWACS: false, onOff: true, followRoads: false, fuel: 50, hasTask: false, position: { lat: 37.1, lng: -116.1, alt: 1000 }, speed: 200, horizontalVelocity: 200, verticalVelicity: 0, heading: 315 * Math.PI / 180, isActiveTanker: false, isActiveAWACS: false, onOff: true, followRoads: false, fuel: 50,
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0, desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
formationOffset: { x: 0, y: 0, z: 0 }, formationOffset: { x: 0, y: 0, z: 0 },
targetID: 0, targetID: 0,
@@ -50,7 +50,7 @@ const DEMO_UNIT_DATA = {
contacts: [{ID: 1, detectionMethod: 16}], contacts: [{ID: 1, detectionMethod: 16}],
activePath: [ ] activePath: [ ]
}, ["4"]:{ category: "GroundUnit", alive: true, human: false, controlled: true, coalition: 2, country: 0, name: "Tor 9A331", unitName: "Cool guy 2-1", groupName: "Cool group 4", state: 1, task: "Being cool", }, ["4"]:{ category: "GroundUnit", alive: true, human: false, controlled: true, coalition: 2, country: 0, name: "Tor 9A331", unitName: "Cool guy 2-1", groupName: "Cool group 4", state: 1, task: "Being cool",
hasTask: false, position: { lat: 37.2, lng: -116.1, alt: 1000 }, speed: 200, heading: 315 * Math.PI / 180, isActiveTanker: false, isActiveAWACS: false, onOff: false, followRoads: false, fuel: 50, hasTask: false, position: { lat: 37.2, lng: -116.1, alt: 1000 }, speed: 200, horizontalVelocity: 200, verticalVelicity: 0, heading: 315 * Math.PI / 180, isActiveTanker: false, isActiveAWACS: false, onOff: false, followRoads: false, fuel: 50,
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0, desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
formationOffset: { x: 0, y: 0, z: 0 }, formationOffset: { x: 0, y: 0, z: 0 },
targetID: 0, targetID: 0,
@@ -67,7 +67,7 @@ const DEMO_UNIT_DATA = {
isLeader: true, isLeader: true,
operateAs: 2 operateAs: 2
}, ["5"]:{ category: "GroundUnit", alive: true, human: false, controlled: true, coalition: 2, country: 0, name: "Gepard", unitName: "Cool guy 2-2", groupName: "Cool group 4", state: 1, task: "Being cool", }, ["5"]:{ category: "GroundUnit", alive: true, human: false, controlled: true, coalition: 2, country: 0, name: "Gepard", unitName: "Cool guy 2-2", groupName: "Cool group 4", state: 1, task: "Being cool",
hasTask: false, position: { lat: 37.21, lng: -116.1, alt: 1000 }, speed: 200, heading: 315 * Math.PI / 180, isActiveTanker: false, isActiveAWACS: false, onOff: false, followRoads: false, fuel: 50, hasTask: false, position: { lat: 37.21, lng: -116.1, alt: 1000 }, speed: 200, horizontalVelocity: 200, verticalVelicity: 0, heading: 315 * Math.PI / 180, isActiveTanker: false, isActiveAWACS: false, onOff: false, followRoads: false, fuel: 50,
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0, desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
formationOffset: { x: 0, y: 0, z: 0 }, formationOffset: { x: 0, y: 0, z: 0 },
targetID: 0, targetID: 0,
@@ -85,7 +85,7 @@ const DEMO_UNIT_DATA = {
operateAs: 2 operateAs: 2
}, },
["6"]:{ category: "Aircraft", alive: true, human: false, controlled: false, coalition: 1, country: 0, name: "FA-18C_hornet", unitName: "Bad boi 1-2", groupName: "Bad group 1", state: 1, task: "Being bad", ["6"]:{ category: "Aircraft", alive: true, human: false, controlled: false, coalition: 1, country: 0, name: "FA-18C_hornet", unitName: "Bad boi 1-2", groupName: "Bad group 1", state: 1, task: "Being bad",
hasTask: false, position: { lat: 36.8, lng: -116, alt: 1000 }, speed: 200, heading: 315 * Math.PI / 180, isActiveTanker: false, isActiveAWACS: false, onOff: true, followRoads: false, fuel: 50, hasTask: false, position: { lat: 36.8, lng: -116, alt: 1000 }, speed: 200, horizontalVelocity: 200, verticalVelicity: 0, heading: 315 * Math.PI / 180, isActiveTanker: false, isActiveAWACS: false, onOff: true, followRoads: false, fuel: 50,
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0, desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
formationOffset: { x: 0, y: 0, z: 0 }, formationOffset: { x: 0, y: 0, z: 0 },
targetID: 0, targetID: 0,
@@ -100,7 +100,7 @@ const DEMO_UNIT_DATA = {
contacts: [{ID: 1, detectionMethod: 16}], contacts: [{ID: 1, detectionMethod: 16}],
activePath: [ ] activePath: [ ]
}, ["7"]:{ category: "GroundUnit", alive: true, human: false, controlled: true, coalition: 1, country: 0, name: "Tor 9A331", unitName: "Cool guy 2-1", groupName: "Cool group 10", state: 1, task: "Being cool", }, ["7"]:{ category: "GroundUnit", alive: true, human: false, controlled: true, coalition: 1, country: 0, name: "Tor 9A331", unitName: "Cool guy 2-1", groupName: "Cool group 10", state: 1, task: "Being cool",
hasTask: false, position: { lat: 37.2, lng: -116.2, alt: 1000 }, speed: 200, heading: 315 * Math.PI / 180, isActiveTanker: false, isActiveAWACS: false, onOff: true, followRoads: false, fuel: 50, hasTask: false, position: { lat: 37.2, lng: -116.2, alt: 1000 }, speed: 200, horizontalVelocity: 200, verticalVelicity: 0, heading: 315 * Math.PI / 180, isActiveTanker: false, isActiveAWACS: false, onOff: true, followRoads: false, fuel: 50,
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0, desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
formationOffset: { x: 0, y: 0, z: 0 }, formationOffset: { x: 0, y: 0, z: 0 },
targetID: 0, targetID: 0,
@@ -142,26 +142,6 @@ class DemoDataGenerator {
}, },
})) }))
//for (let i = 8; i < 100; i++) {
// var randomUnit = { category: "Aircraft", alive: true, human: false, controlled: true, coalition: 2, country: 0, name: "KC-135", unitName: "Cool guy 1-1 who also has a very long name", groupName: "Cool group 1", state: 1, task: "Being cool!",
// hasTask: true, position: { lat: 37 + Math.random(), lng: -116 + Math.random(), alt: 1000 }, speed: 200, heading: 45, isActiveTanker: true, isActiveAWACS: false, onOff: true, followRoads: false, fuel: 50,
// desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
// formationOffset: { x: 0, y: 0, z: 0 },
// targetID: 0,
// targetPosition: { lat: 0, lng: 0, alt: 0 },
// ROE: 1,
// reactionToThreat: 1,
// emissionsCountermeasures: 1,
// TACAN: { isOn: false, XY: 'Y', callsign: 'TKR', channel: 40 },
// radio: { frequency: 124000000, callsign: 1, callsignNumber: 1 },
// generalSettings: { prohibitAA: false, prohibitAfterburner: false, prohibitAG: false, prohibitAirWpn: false, prohibitJettison: false },
// ammo: [{ quantity: 2, name: "A cool missile\0Ciao", guidance: 0, category: 0, missileCategory: 0 }, { quantity: 2, name: "A cool missile with a longer name\0Ciao", guidance: 0, category: 0, missileCategory: 0 }, { quantity: 2, name: "A cool missile\0Ciao", guidance: 0, category: 0, missileCategory: 0 } , { quantity: 2, name: "A cool missile\0Ciao", guidance: 0, category: 0, missileCategory: 0 } , { quantity: 2, name: "A cool missile\0Ciao", guidance: 0, category: 0, missileCategory: 0 } , { quantity: 2, name: "A cool missile\0Ciao", guidance: 0, category: 0, missileCategory: 0 } , { quantity: 2, name: "A cool missile\0Ciao", guidance: 0, category: 0, missileCategory: 0 } , { quantity: 2, name: "A cool missile\0Ciao", guidance: 0, category: 0, missileCategory: 0 } , { quantity: 2, name: "A cool missile\0Ciao", guidance: 0, category: 0, missileCategory: 0 } ],
// contacts: [{ID: 2, detectionMethod: 1}, {ID: 3, detectionMethod: 4}, {ID: 4, detectionMethod: 1}],
// activePath: []
// }
// DEMO_UNIT_DATA[i.toString()] = randomUnit;
//}
this.startTime = Date.now(); this.startTime = Date.now();
} }
@@ -187,31 +167,33 @@ class DemoDataGenerator {
array = this.appendUint8(array, unit.hasTask, 12); array = this.appendUint8(array, unit.hasTask, 12);
array = this.appendCoordinates(array, unit.position, 13); array = this.appendCoordinates(array, unit.position, 13);
array = this.appendDouble(array, unit.speed, 14); array = this.appendDouble(array, unit.speed, 14);
array = this.appendDouble(array, unit.heading, 15); array = this.appendDouble(array, unit.horizontalVelocity, 15);
array = this.appendUint8(array, unit.isActiveTanker, 16); array = this.appendDouble(array, unit.verticalVelicity, 16);
array = this.appendUint8(array, unit.isActiveAWACS, 17); array = this.appendDouble(array, unit.heading, 17);
array = this.appendUint8(array, unit.onOff, 18); array = this.appendUint8(array, unit.isActiveTanker, 18);
array = this.appendUint8(array, unit.followRoads, 19); array = this.appendUint8(array, unit.isActiveAWACS, 19);
array = this.appendUint16(array, unit.fuel, 20); array = this.appendUint8(array, unit.onOff, 20);
array = this.appendDouble(array, unit.desiredSpeed, 21); array = this.appendUint8(array, unit.followRoads, 21);
array = this.appendUint8(array, unit.desiredSpeedType, 22); array = this.appendUint16(array, unit.fuel, 22);
array = this.appendDouble(array, unit.desiredAltitude, 23); array = this.appendDouble(array, unit.desiredSpeed, 23);
array = this.appendUint8(array, unit.desiredAltitudeType, 24); array = this.appendUint8(array, unit.desiredSpeedType, 24);
array = this.appendUint32(array, unit.leaderID, 25); array = this.appendDouble(array, unit.desiredAltitude, 25);
array = this.appendOffset(array, unit.formationOffset, 26); array = this.appendUint8(array, unit.desiredAltitudeType, 26);
array = this.appendUint32(array, unit.targetID, 27); array = this.appendUint32(array, unit.leaderID, 27);
array = this.appendCoordinates(array, unit.targetPosition, 28); array = this.appendOffset(array, unit.formationOffset, 28);
array = this.appendUint8(array, unit.ROE, 29); array = this.appendUint32(array, unit.targetID, 29);
array = this.appendUint8(array, unit.reactionToThreat, 30); array = this.appendCoordinates(array, unit.targetPosition, 30);
array = this.appendUint8(array, unit.emissionsCountermeasures, 31); array = this.appendUint8(array, unit.ROE, 31);
array = this.appendTACAN(array, unit.TACAN, 32); array = this.appendUint8(array, unit.reactionToThreat, 32);
array = this.appendRadio(array, unit.radio, 33); array = this.appendUint8(array, unit.emissionsCountermeasures, 33);
array = this.appendRadio(array, unit.generalSettings, 34); array = this.appendTACAN(array, unit.TACAN, 34);
array = this.appendAmmo(array, unit.ammo, 35); array = this.appendRadio(array, unit.radio, 35);
array = this.appendContacts(array, unit.contacts, 36); array = this.appendRadio(array, unit.generalSettings, 36);
array = this.appendActivePath(array, unit.activePath, 37); array = this.appendAmmo(array, unit.ammo, 37);
array = this.appendUint8(array, unit.isLeader, 38); array = this.appendContacts(array, unit.contacts, 38);
array = this.appendUint8(array, unit.operateAs, 39); array = this.appendActivePath(array, unit.activePath, 39);
array = this.appendUint8(array, unit.isLeader, 40);
array = this.appendUint8(array, unit.operateAs, 41);
array = this.concat(array, this.uint8ToByteArray(255)); array = this.concat(array, this.uint8ToByteArray(255));
} }
res.end(Buffer.from(array, 'binary')); res.end(Buffer.from(array, 'binary'));

View File

@@ -508,7 +508,7 @@ class GroundUnitEditor extends uniteditor_1.UnitEditor {
* @param blueprint The blueprint to edit * @param blueprint The blueprint to edit
*/ */
setBlueprint(blueprint) { 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"); __classPrivateFieldSet(this, _GroundUnitEditor_blueprint, blueprint, "f");
if (__classPrivateFieldGet(this, _GroundUnitEditor_blueprint, "f") !== null) { if (__classPrivateFieldGet(this, _GroundUnitEditor_blueprint, "f") !== null) {
this.contentDiv2.replaceChildren(); 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, "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, "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, "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, "Targeting range [m]", (_e = String(blueprint.targetingRange)) !== null && _e !== void 0 ? _e : "", "number", (value) => { blueprint.targetingRange = 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, "Barrel height [m]", (_f = String(blueprint.barrelHeight)) !== null && _f !== void 0 ? _f : "", "number", (value) => { blueprint.barrelHeight = 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, "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, "Burst quantity", (_h = String(blueprint.shotsToFire)) !== null && _h !== void 0 ? _h : "", "number", (value) => { blueprint.shotsToFire = Math.round(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.addCheckboxInput)(this.contentDiv2, "Can target point", (_j = blueprint.canTargetPoint) !== null && _j !== void 0 ? _j : false, (value) => { blueprint.canTargetPoint = 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.addCheckboxInput)(this.contentDiv2, "Can rearm", (_k = blueprint.canRearm) !== null && _k !== void 0 ? _k : false, (value) => { blueprint.canRearm = 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, "Description", (_l = blueprint.description) !== null && _l !== void 0 ? _l : "", "text", (value) => { blueprint.description = 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.addStringInput)(this.contentDiv2, "Abilities", (_m = blueprint.abilities) !== null && _m !== void 0 ? _m : "", "text", (value) => { blueprint.abilities = 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 /** Add a new empty blueprint

View File

@@ -86,7 +86,7 @@ export class DatabaseManagerPlugin implements OlympusPlugin {
/* Create the container for the database editor elements and the elements themselves */ /* Create the container for the database editor elements and the elements themselves */
this.#mainContentContainer = document.createElement("div"); this.#mainContentContainer = document.createElement("div");
this.#mainContentContainer.classList.add("dm-container"); this.#mainContentContainer.classList.add("dm-container");
this.#element.appendChild(this.#mainContentContainer) this.#element.appendChild(this.#mainContentContainer);
this.#contentDiv1 = document.createElement("div"); this.#contentDiv1 = document.createElement("div");
this.#contentDiv1.classList.add("dm-content-container"); this.#contentDiv1.classList.add("dm-content-container");

View File

@@ -36,12 +36,19 @@ export class GroundUnitEditor extends UnitEditor {
addStringInput(this.contentDiv2, "Cost", String(blueprint.cost)?? "", "number", (value: string) => {blueprint.cost = parseFloat(value); }); 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, "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, "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, "Aim method range [m]", String(blueprint.aimMethodRange)?? "", "number", (value: string) => {blueprint.aimMethodRange = parseFloat(value); });
addStringInput(this.contentDiv2, "Barrel height [m]", String(blueprint.barrelHeight)?? "", "number", (value: string) => {blueprint.barrelHeight = 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, "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, "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, "Shots to fire", String(blueprint.shotsToFire)?? "", "number", (value: string) => {blueprint.shotsToFire = Math.round(parseFloat(value)); });
addStringInput(this.contentDiv2, "Shots base interval [s]", String(blueprint.shotsBaseInterval)?? "", "number", (value: string) => {blueprint.shotsBaseInterval = Math.round(parseFloat(value)); });
addStringInput(this.contentDiv2, "Shots base scatter [°]", String(blueprint.shotsBaseScatter)?? "", "number", (value: string) => {blueprint.shotsBaseScatter = Math.round(parseFloat(value)); });
addStringInput(this.contentDiv2, "Alertness time constant [s]", String(blueprint.alertnessTimeConstant)?? "", "number", (value: string) => {blueprint.alertnessTimeConstant = Math.round(parseFloat(value)); });
addCheckboxInput(this.contentDiv2, "Can target point", blueprint.canTargetPoint ?? false, (value: boolean) => {blueprint.canTargetPoint = 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 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, "Description", blueprint.description ?? "", "text", (value: string) => {blueprint.description = value; });
addStringInput(this.contentDiv2, "Abilities", blueprint.abilities ?? "", "text", (value: string) => {blueprint.abilities = value; }); addStringInput(this.contentDiv2, "Abilities", blueprint.abilities ?? "", "text", (value: string) => {blueprint.abilities = value; });
} }

View File

@@ -49,9 +49,9 @@ export abstract class UnitEditor {
} }
/** Show the editor /** Show the editor
* * @param filter String filter
*/ */
show() { show(filter: string = "") {
this.visible = true; this.visible = true;
this.contentDiv1.replaceChildren(); this.contentDiv1.replaceChildren();
this.contentDiv2.replaceChildren(); this.contentDiv2.replaceChildren();
@@ -62,20 +62,20 @@ export abstract class UnitEditor {
var title = document.createElement("label"); var title = document.createElement("label");
title.innerText = "Units list"; title.innerText = "Units list";
this.contentDiv1.appendChild(title); 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) => { var filterInput = document.createElement("input");
if (input.value != "") filterInput.value = filter;
this.addBlueprint((input).value); 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() { hide() {
@@ -93,6 +93,24 @@ export abstract class UnitEditor {
return this.database; 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 methods which will depend on the specific type of units */
abstract setBlueprint(blueprint: UnitBlueprint): void; abstract setBlueprint(blueprint: UnitBlueprint): void;
abstract addBlueprint(key: string): void; abstract addBlueprint(key: string): void;

View File

@@ -174,40 +174,60 @@ export function addNewElementInput(div: HTMLElement, callback: CallableFunction)
* *
* @param div The HTMLElement that will contain the list * @param div The HTMLElement that will contain the list
* @param database The database that will be used to fill the list of blueprints * @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 * @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"); var scrollDiv = document.createElement("div");
scrollDiv.classList.add("dm-scroll-container"); scrollDiv.classList.add("dm-scroll-container");
if (database !== null) { if (database !== null) {
var blueprints: {[key: string]: UnitBlueprint} = database.blueprints; var blueprints: {[key: string]: UnitBlueprint} = database.blueprints;
for (let key of Object.keys(blueprints).sort((a, b) => a.localeCompare(b, undefined, {sensitivity: 'base'}))) { for (let key of Object.keys(blueprints).sort((a, b) => a.localeCompare(b, undefined, {sensitivity: 'base'}))) {
var rowDiv = document.createElement("div"); var addKey = true;
scrollDiv.appendChild(rowDiv); if (filter !== "") {
try {
var text = document.createElement("label"); var blueprint = blueprints[key];
text.textContent = key; addKey = eval(filter);
text.onclick = () => callback(key); } catch {
rowDiv.appendChild(text); console.error("An error has occurred evaluating the blueprint filter")
}
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. */ if (addKey) {
var button = document.createElement("button"); var rowDiv = document.createElement("div");
button.innerText = "X"; scrollDiv.appendChild(rowDiv);
button.onclick = () => {
delete blueprints[key]; let text = document.createElement("label");
div.dispatchEvent(new Event("refresh")); 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); div.appendChild(scrollDiv);
@@ -269,5 +289,5 @@ export function arrayToString(array: string[]) {
export function stringToArray(input: string) { export function stringToArray(input: string) {
return input.match( /(\w)+/g ) || []; return input.match( /(\w)+/g ) ?? [];
} }

View File

@@ -115,6 +115,10 @@
font-weight: bold; font-weight: bold;
} }
#database-manager-panel input {
font-weight: bold;
}
.dm-scroll-container>div:nth-child(even) { .dm-scroll-container>div:nth-child(even) {
background-color: gainsboro; background-color: gainsboro;
} }
@@ -131,11 +135,16 @@
} }
.dm-scroll-container>div *:nth-child(1):hover { .dm-scroll-container>div *:nth-child(1):hover {
background-color: var(--secondary-blue-text); background-color: var(--accent-dark-blue);
color: white; color: white;
cursor: pointer; cursor: pointer;
} }
.blueprint-selected {
background-color: var(--accent-light-blue) !important;
color: white;
}
.dm-scroll-container>div { .dm-scroll-container>div {
display: flex; display: flex;
align-items: center; align-items: center;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -166,20 +166,23 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
#unit-control-panel .switch-control { #unit-control-panel .switch-control {
align-items: center; align-items: center;
display: grid; display: flex;
grid-template-columns: 1.35fr 0.65fr; width: 100%;
} justify-content: space-between;
#unit-control-panel .switch-control>*:nth-child(2) {
justify-self: end;
}
#unit-control-panel .switch-control>*:nth-child(3) {
color: var(--secondary-semitransparent-white);
} }
#unit-control-panel .switch-control h4 { #unit-control-panel .switch-control h4 {
margin: 0px; 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 { #unit-control-panel .switch-control .ol-switch {
@@ -239,6 +242,8 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
#unit-control-panel:not([data-show-roe]) #roe, #unit-control-panel:not([data-show-roe]) #roe,
#unit-control-panel:not([data-show-threat]) #threat, #unit-control-panel:not([data-show-threat]) #threat,
#unit-control-panel:not([data-show-emissions-countermeasures]) #emissions-countermeasures, #unit-control-panel:not([data-show-emissions-countermeasures]) #emissions-countermeasures,
#unit-control-panel:not([data-show-shots-scatter]) #shots-scatter,
#unit-control-panel:not([data-show-shots-intensity]) #shots-intensity,
#unit-control-panel:not([data-show-tanker-button]) #tanker-on, #unit-control-panel:not([data-show-tanker-button]) #tanker-on,
#unit-control-panel:not([data-show-AWACS-button]) #AWACS-on, #unit-control-panel:not([data-show-AWACS-button]) #AWACS-on,
#unit-control-panel:not([data-show-on-off]) #ai-on-off, #unit-control-panel:not([data-show-on-off]) #ai-on-off,

View File

@@ -91,9 +91,9 @@
#loadout-silhouette { #loadout-silhouette {
filter: invert(100%); filter: invert(100%);
height: 100px; height: 75px;
margin-right: 25px; margin-right: 25px;
width: 100px; width: 75px;
} }
#loadout-items { #loadout-items {

View File

@@ -72,10 +72,6 @@ form {
padding: 0; padding: 0;
} }
form>div {
margin: 20px 0;
}
.pill { .pill {
background-color: var(--background-steel); background-color: var(--background-steel);
border-radius: 999px; border-radius: 999px;
@@ -669,8 +665,8 @@ nav.ol-panel> :last-child {
width:10px; width:10px;
} }
.ol-navbar-buttons-group > .protectable > button.lock svg.locked { .ol-navbar-buttons-group > .protectable > button.lock svg.locked * {
filter:invert(100); fill:white !important;
} }
.ol-navbar-buttons-group > .protectable > button:not([data-protected]).lock svg.unlocked, .ol-navbar-buttons-group > .protectable > button:not([data-protected]).lock svg.unlocked,
@@ -687,7 +683,9 @@ nav.ol-panel> :last-child {
#roe-buttons-container button, #roe-buttons-container button,
#reaction-to-threat-buttons-container button, #reaction-to-threat-buttons-container button,
#emissions-countermeasures-buttons-container button { #emissions-countermeasures-buttons-container button,
#shots-scatter-buttons-container button
#shots-intensity-buttons-container button {
align-items: center; align-items: center;
background-color: transparent; background-color: transparent;
border: 1px solid var(--accent-light-blue); border: 1px solid var(--accent-light-blue);
@@ -709,6 +707,7 @@ nav.ol-panel> :last-child {
#unit-control-panel .ol-option-button button.selected svg * { #unit-control-panel .ol-option-button button.selected svg * {
fill: var(--background-steel); fill: var(--background-steel);
stroke: var(--background-steel);
} }
#rapid-controls { #rapid-controls {
@@ -850,7 +849,7 @@ nav.ol-panel> :last-child {
column-gap: 10px; column-gap: 10px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
margin: 10px 0px; margin: 20px 0px;
flex-wrap: wrap; flex-wrap: wrap;
width: 100%; width: 100%;
row-gap: 10px; row-gap: 10px;

View File

@@ -38,6 +38,7 @@
inkscape:window-maximized="1" inkscape:window-maximized="1"
inkscape:current-layer="svg4" /> inkscape:current-layer="svg4" />
<path <path
style="stroke: none"
d="m 7.5000002,0 c 0.498,0 0.9375,0.4395 0.9375,0.9375 V 1.2598 C 11.1621,1.6699 13.3301,3.8379002 13.7402,6.5625002 h 0.3223 c 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 H 13.7402 C 13.3301,11.1914 11.1621,13.3594 8.4375002,13.7695 v 0.293 c 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 v -0.293 C 3.8086002,13.3594 1.6406,11.1914 1.2305,8.4375002 h -0.293 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 h 0.293 C 1.6406,3.8379002 3.8086002,1.6699 6.5625002,1.2598 V 0.9375 c 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 z m -4.3652,8.4375002 c 0.3515,1.7284998 1.6992,3.0761998 3.4277,3.4276998 V 11.25 c 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 0.498,0 0.9375,0.4395 0.9375,0.9375 v 0.6152 C 10.1367,11.5137 11.4844,10.166 11.8359,8.4375002 H 11.25 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 h 0.5859 c -0.3515,-1.6992 -1.6992,-3.0469 -3.3983998,-3.3984 v 0.5859 c 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 v -0.5859 c -1.7285,0.3515 -3.0762,1.6992 -3.4277,3.3984 h 0.6152 c 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 z m 4.3652,0 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 z" d="m 7.5000002,0 c 0.498,0 0.9375,0.4395 0.9375,0.9375 V 1.2598 C 11.1621,1.6699 13.3301,3.8379002 13.7402,6.5625002 h 0.3223 c 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 H 13.7402 C 13.3301,11.1914 11.1621,13.3594 8.4375002,13.7695 v 0.293 c 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 v -0.293 C 3.8086002,13.3594 1.6406,11.1914 1.2305,8.4375002 h -0.293 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 h 0.293 C 1.6406,3.8379002 3.8086002,1.6699 6.5625002,1.2598 V 0.9375 c 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 z m -4.3652,8.4375002 c 0.3515,1.7284998 1.6992,3.0761998 3.4277,3.4276998 V 11.25 c 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 0.498,0 0.9375,0.4395 0.9375,0.9375 v 0.6152 C 10.1367,11.5137 11.4844,10.166 11.8359,8.4375002 H 11.25 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 h 0.5859 c -0.3515,-1.6992 -1.6992,-3.0469 -3.3983998,-3.3984 v 0.5859 c 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 v -0.5859 c -1.7285,0.3515 -3.0762,1.6992 -3.4277,3.3984 h 0.6152 c 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 z m 4.3652,0 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 z"
fill="#5ca7ff" fill="#5ca7ff"
id="path2" /> id="path2" />

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -39,5 +39,6 @@
<path <path
d="m 7.0324294,0 c 0.1172,0 0.2637,0.0293 0.3809,0.0879 l 5.5077996,2.3437 c 0.6445,0.293 1.1425,0.9082 1.1425,1.67 -0.0292,2.9296 -1.2304,8.2324 -6.2694996,10.664 -0.498,0.2344 -1.0547,0.2344 -1.5527,0 -5.0391,-2.4316 -6.24020004,-7.7344 -6.24020004,-10.664 -0.0293,-0.7618 0.4687,-1.377 1.11320004,-1.67 l 5.5078,-2.3437 C 6.7394294,0.0293 6.8859294,0 7.0324294,0 Z m 0,1.9629 V 13.0371 C 11.075429,11.0742 12.159429,6.7676 12.188629,4.1602 Z" d="m 7.0324294,0 c 0.1172,0 0.2637,0.0293 0.3809,0.0879 l 5.5077996,2.3437 c 0.6445,0.293 1.1425,0.9082 1.1425,1.67 -0.0292,2.9296 -1.2304,8.2324 -6.2694996,10.664 -0.498,0.2344 -1.0547,0.2344 -1.5527,0 -5.0391,-2.4316 -6.24020004,-7.7344 -6.24020004,-10.664 -0.0293,-0.7618 0.4687,-1.377 1.11320004,-1.67 l 5.5078,-2.3437 C 6.7394294,0.0293 6.8859294,0 7.0324294,0 Z m 0,1.9629 V 13.0371 C 11.075429,11.0742 12.159429,6.7676 12.188629,4.1602 Z"
fill="#5ca7ff" fill="#5ca7ff"
id="path2" /> id="path2"
style="stroke: none"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -39,5 +39,6 @@
<path <path
d="m 10.796771,3.75 c 0,1.31836 -0.7618,2.46094 -1.8750496,3.13476 v 0.61525 c 0,0.5273 -0.43945,0.9375 -0.9375,0.9375 h -2.8125 c -0.52734,0 -0.9375,-0.4102 -0.9375,-0.9375 V 6.88476 c -1.14258,-0.67382 -1.875,-1.8164 -1.875,-3.13476 0,-2.05078 1.875,-3.75 4.21875,-3.75 2.31445,0 4.2187996,1.69922 4.2187996,3.75 z M 4.9373514,5.15625 c 0.49804,0 0.9375,-0.41016 0.9375,-0.9375 0,-0.49805 -0.43946,-0.9375 -0.9375,-0.9375 -0.52735,0 -0.9375,0.43945 -0.9375,0.9375 0,0.52734 0.41015,0.9375 0.9375,0.9375 z m 4.21872,-0.9375 c 0,-0.49805 -0.43943,-0.9375 -0.93748,-0.9375 -0.52734,0 -0.9375,0.43945 -0.9375,0.9375 0,0.52734 0.41016,0.9375 0.9375,0.9375 0.49805,0 0.93748,-0.41016 0.93748,-0.9375 z M 0.10336144,8.02731 c 0.23438,-0.4687 0.79102,-0.6445 1.25976996,-0.4101 l 5.21484,2.6074 5.1854996,-2.6074 c 0.4688,-0.2344 1.0254,-0.0586 1.2598,0.4101 0.2344,0.4688 0.0586,1.0254 -0.4101,1.2598 l -3.9551196,1.9629 3.9551196,1.9922 c 0.4687,0.2344 0.6445,0.791 0.4101,1.2597 -0.2344,0.4688 -0.791,0.6446 -1.2598,0.4102 l -5.1854996,-2.6074 -5.21484,2.6074 c -0.46874996,0.2344 -1.02538996,0.0586 -1.25976996,-0.4102 -0.234374,-0.4687 -0.058593,-1.0253 0.41016,-1.2597 L 4.4685914,11.25001 0.51352144,9.28711 c -0.468753,-0.2344 -0.644534,-0.791 -0.41016,-1.2598 z" d="m 10.796771,3.75 c 0,1.31836 -0.7618,2.46094 -1.8750496,3.13476 v 0.61525 c 0,0.5273 -0.43945,0.9375 -0.9375,0.9375 h -2.8125 c -0.52734,0 -0.9375,-0.4102 -0.9375,-0.9375 V 6.88476 c -1.14258,-0.67382 -1.875,-1.8164 -1.875,-3.13476 0,-2.05078 1.875,-3.75 4.21875,-3.75 2.31445,0 4.2187996,1.69922 4.2187996,3.75 z M 4.9373514,5.15625 c 0.49804,0 0.9375,-0.41016 0.9375,-0.9375 0,-0.49805 -0.43946,-0.9375 -0.9375,-0.9375 -0.52735,0 -0.9375,0.43945 -0.9375,0.9375 0,0.52734 0.41015,0.9375 0.9375,0.9375 z m 4.21872,-0.9375 c 0,-0.49805 -0.43943,-0.9375 -0.93748,-0.9375 -0.52734,0 -0.9375,0.43945 -0.9375,0.9375 0,0.52734 0.41016,0.9375 0.9375,0.9375 0.49805,0 0.93748,-0.41016 0.93748,-0.9375 z M 0.10336144,8.02731 c 0.23438,-0.4687 0.79102,-0.6445 1.25976996,-0.4101 l 5.21484,2.6074 5.1854996,-2.6074 c 0.4688,-0.2344 1.0254,-0.0586 1.2598,0.4101 0.2344,0.4688 0.0586,1.0254 -0.4101,1.2598 l -3.9551196,1.9629 3.9551196,1.9922 c 0.4687,0.2344 0.6445,0.791 0.4101,1.2597 -0.2344,0.4688 -0.791,0.6446 -1.2598,0.4102 l -5.1854996,-2.6074 -5.21484,2.6074 c -0.46874996,0.2344 -1.02538996,0.0586 -1.25976996,-0.4102 -0.234374,-0.4687 -0.058593,-1.0253 0.41016,-1.2597 L 4.4685914,11.25001 0.51352144,9.28711 c -0.468753,-0.2344 -0.644534,-0.791 -0.41016,-1.2598 z"
fill="#5ca7ff" fill="#5ca7ff"
id="path2" /> id="path2"
style="stroke: none"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -39,5 +39,6 @@
<path <path
d="m 9.103975,1.603975 c 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 l -3.0762,3.0761 -3.1055,-3.0761 c -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 -0.3809,0.3515 -0.3809,0.9668 0,1.3183 l 3.0761,3.0762 -3.0761,3.1055 c -0.3809,0.3515 -0.3809,0.9668 0,1.3183 0.3515,0.3809 0.9668,0.3809 1.3183,0 l 3.1055,-3.0761 3.0762,3.0761 c 0.3515,0.3809 0.9668,0.3809 1.3183,0 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 l -3.0761,-3.1055 z" d="m 9.103975,1.603975 c 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 l -3.0762,3.0761 -3.1055,-3.0761 c -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 -0.3809,0.3515 -0.3809,0.9668 0,1.3183 l 3.0761,3.0762 -3.0761,3.1055 c -0.3809,0.3515 -0.3809,0.9668 0,1.3183 0.3515,0.3809 0.9668,0.3809 1.3183,0 l 3.1055,-3.0761 3.0762,3.0761 c 0.3515,0.3809 0.9668,0.3809 1.3183,0 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 l -3.0761,-3.1055 z"
fill="#5ca7ff" fill="#5ca7ff"
id="path2" /> id="path2"
style="stroke: none"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
version="1.1"
id="svg4"
sodipodi:docname="1.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs8" />
<sodipodi:namedview
id="namedview6"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
width="30px"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="16.808938"
inkscape:cx="4.2536893"
inkscape:cy="-1.2195892"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg4"
inkscape:showpageshadow="2"
inkscape:deskcolor="#d1d1d1" />
<rect
style="stroke-width:0.659;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1"
fill="#5ca7ff"
stroke="#5ca7ff"
id="rect1107"
width="2.8299551"
height="3.9513376"
x="1.7056587"
y="9.5718069" />
<rect
style="fill:none;stroke-width:0.659001;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers"
fill="#5ca7ff"
stroke="#5ca7ff"
id="rect1107-7"
width="2.8299551"
height="7.6993432"
x="6.0053182"
y="5.817802" />
<rect
style="fill:none;stroke-width:0.659001;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers"
fill="#5ca7ff"
stroke="#5ca7ff"
id="rect1107-9"
width="2.8299551"
height="11.89354"
x="10.304977"
y="1.7128451" />
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
version="1.1"
id="svg4"
sodipodi:docname="2.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs8" />
<sodipodi:namedview
id="namedview6"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
width="30px"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="16.808938"
inkscape:cx="4.2536893"
inkscape:cy="-1.2195892"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg4"
inkscape:showpageshadow="2"
inkscape:deskcolor="#d1d1d1" />
<rect
style="stroke-width:0.659;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1"
fill="#5ca7ff"
stroke="#5ca7ff"
id="rect1107"
width="2.8299551"
height="3.9513376"
x="1.7056587"
y="9.5718069" />
<rect
style="stroke-width:0.659001;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1"
fill="#5ca7ff"
stroke="#5ca7ff"
id="rect1107-7"
width="2.8299551"
height="7.6993432"
x="6.0053182"
y="5.817802" />
<rect
style="fill:none;stroke-width:0.659001;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers"
fill="#5ca7ff"
stroke="#5ca7ff"
id="rect1107-9"
width="2.8299551"
height="11.89354"
x="10.304977"
y="1.7128451" />
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="15"
height="15"
fill="none"
version="1.1"
viewBox="0 0 15 15"
id="svg8"
sodipodi:docname="3.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs12" />
<sodipodi:namedview
id="namedview10"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="55.466667"
inkscape:cx="7.4909856"
inkscape:cy="7.4909856"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<rect
x="1.7057"
y="9.5718"
width="2.83"
height="3.9513"
style="paint-order:stroke fill markers;stroke-dashoffset:5.6;stroke-linecap:round;stroke-linejoin:bevel;stroke-width:.659;"
id="rect2"
fill="#5ca7ff"
stroke="#5ca7ff" />
<rect
x="6.0053"
y="5.8178"
width="2.83"
height="7.6993"
style="paint-order:stroke fill markers;stroke-dashoffset:5.6;stroke-linecap:round;stroke-linejoin:bevel;stroke-width:.659;"
id="rect4"
fill="#5ca7ff"
stroke="#5ca7ff" />
<rect
x="10.305"
y="1.7128"
width="2.83"
height="11.894"
style="paint-order:stroke fill markers;stroke-dashoffset:5.6;stroke-linecap:round;stroke-linejoin:bevel;stroke-width:.659;"
id="rect6"
fill="#5ca7ff"
stroke="#5ca7ff" />
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -40,5 +40,6 @@
<path <path
d="m 7.5000002,0 c 0.498,0 0.9375,0.4395 0.9375,0.9375 V 1.2598 C 11.1621,1.6699 13.3301,3.8379002 13.7402,6.5625002 h 0.3223 c 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 H 13.7402 C 13.3301,11.1914 11.1621,13.3594 8.4375002,13.7695 v 0.293 c 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 v -0.293 C 3.8086002,13.3594 1.6406,11.1914 1.2305,8.4375002 h -0.293 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 h 0.293 C 1.6406,3.8379002 3.8086002,1.6699 6.5625002,1.2598 V 0.9375 c 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 z m -4.3652,8.4375002 c 0.3515,1.7284998 1.6992,3.0761998 3.4277,3.4276998 V 11.25 c 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 0.498,0 0.9375,0.4395 0.9375,0.9375 v 0.6152 C 10.1367,11.5137 11.4844,10.166 11.8359,8.4375002 H 11.25 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 h 0.5859 c -0.3515,-1.6992 -1.6992,-3.0469 -3.3983998,-3.3984 v 0.5859 c 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 v -0.5859 c -1.7285,0.3515 -3.0762,1.6992 -3.4277,3.3984 h 0.6152 c 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 z m 4.3652,0 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 z" d="m 7.5000002,0 c 0.498,0 0.9375,0.4395 0.9375,0.9375 V 1.2598 C 11.1621,1.6699 13.3301,3.8379002 13.7402,6.5625002 h 0.3223 c 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 H 13.7402 C 13.3301,11.1914 11.1621,13.3594 8.4375002,13.7695 v 0.293 c 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 v -0.293 C 3.8086002,13.3594 1.6406,11.1914 1.2305,8.4375002 h -0.293 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 h 0.293 C 1.6406,3.8379002 3.8086002,1.6699 6.5625002,1.2598 V 0.9375 c 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 z m -4.3652,8.4375002 c 0.3515,1.7284998 1.6992,3.0761998 3.4277,3.4276998 V 11.25 c 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 0.498,0 0.9375,0.4395 0.9375,0.9375 v 0.6152 C 10.1367,11.5137 11.4844,10.166 11.8359,8.4375002 H 11.25 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 h 0.5859 c -0.3515,-1.6992 -1.6992,-3.0469 -3.3983998,-3.3984 v 0.5859 c 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 v -0.5859 c -1.7285,0.3515 -3.0762,1.6992 -3.4277,3.3984 h 0.6152 c 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 z m 4.3652,0 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 z"
fill="#5ca7ff" fill="#5ca7ff"
id="path2" /> id="path2"
style="stroke: none"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -39,5 +39,6 @@
<path <path
d="m 10.796771,3.75 c 0,1.31836 -0.7618,2.46094 -1.8750496,3.13476 v 0.61525 c 0,0.5273 -0.43945,0.9375 -0.9375,0.9375 h -2.8125 c -0.52734,0 -0.9375,-0.4102 -0.9375,-0.9375 V 6.88476 c -1.14258,-0.67382 -1.875,-1.8164 -1.875,-3.13476 0,-2.05078 1.875,-3.75 4.21875,-3.75 2.31445,0 4.2187996,1.69922 4.2187996,3.75 z M 4.9373514,5.15625 c 0.49804,0 0.9375,-0.41016 0.9375,-0.9375 0,-0.49805 -0.43946,-0.9375 -0.9375,-0.9375 -0.52735,0 -0.9375,0.43945 -0.9375,0.9375 0,0.52734 0.41015,0.9375 0.9375,0.9375 z m 4.21872,-0.9375 c 0,-0.49805 -0.43943,-0.9375 -0.93748,-0.9375 -0.52734,0 -0.9375,0.43945 -0.9375,0.9375 0,0.52734 0.41016,0.9375 0.9375,0.9375 0.49805,0 0.93748,-0.41016 0.93748,-0.9375 z M 0.10336144,8.02731 c 0.23438,-0.4687 0.79102,-0.6445 1.25976996,-0.4101 l 5.21484,2.6074 5.1854996,-2.6074 c 0.4688,-0.2344 1.0254,-0.0586 1.2598,0.4101 0.2344,0.4688 0.0586,1.0254 -0.4101,1.2598 l -3.9551196,1.9629 3.9551196,1.9922 c 0.4687,0.2344 0.6445,0.791 0.4101,1.2597 -0.2344,0.4688 -0.791,0.6446 -1.2598,0.4102 l -5.1854996,-2.6074 -5.21484,2.6074 c -0.46874996,0.2344 -1.02538996,0.0586 -1.25976996,-0.4102 -0.234374,-0.4687 -0.058593,-1.0253 0.41016,-1.2597 L 4.4685914,11.25001 0.51352144,9.28711 c -0.468753,-0.2344 -0.644534,-0.791 -0.41016,-1.2598 z" d="m 10.796771,3.75 c 0,1.31836 -0.7618,2.46094 -1.8750496,3.13476 v 0.61525 c 0,0.5273 -0.43945,0.9375 -0.9375,0.9375 h -2.8125 c -0.52734,0 -0.9375,-0.4102 -0.9375,-0.9375 V 6.88476 c -1.14258,-0.67382 -1.875,-1.8164 -1.875,-3.13476 0,-2.05078 1.875,-3.75 4.21875,-3.75 2.31445,0 4.2187996,1.69922 4.2187996,3.75 z M 4.9373514,5.15625 c 0.49804,0 0.9375,-0.41016 0.9375,-0.9375 0,-0.49805 -0.43946,-0.9375 -0.9375,-0.9375 -0.52735,0 -0.9375,0.43945 -0.9375,0.9375 0,0.52734 0.41015,0.9375 0.9375,0.9375 z m 4.21872,-0.9375 c 0,-0.49805 -0.43943,-0.9375 -0.93748,-0.9375 -0.52734,0 -0.9375,0.43945 -0.9375,0.9375 0,0.52734 0.41016,0.9375 0.9375,0.9375 0.49805,0 0.93748,-0.41016 0.93748,-0.9375 z M 0.10336144,8.02731 c 0.23438,-0.4687 0.79102,-0.6445 1.25976996,-0.4101 l 5.21484,2.6074 5.1854996,-2.6074 c 0.4688,-0.2344 1.0254,-0.0586 1.2598,0.4101 0.2344,0.4688 0.0586,1.0254 -0.4101,1.2598 l -3.9551196,1.9629 3.9551196,1.9922 c 0.4687,0.2344 0.6445,0.791 0.4101,1.2597 -0.2344,0.4688 -0.791,0.6446 -1.2598,0.4102 l -5.1854996,-2.6074 -5.21484,2.6074 c -0.46874996,0.2344 -1.02538996,0.0586 -1.25976996,-0.4102 -0.234374,-0.4687 -0.058593,-1.0253 0.41016,-1.2597 L 4.4685914,11.25001 0.51352144,9.28711 c -0.468753,-0.2344 -0.644534,-0.791 -0.41016,-1.2598 z"
fill="#5ca7ff" fill="#5ca7ff"
id="path2" /> id="path2"
style="stroke: none"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -39,5 +39,6 @@
<path <path
d="m 9.103975,1.603975 c 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 l -3.0762,3.0761 -3.1055,-3.0761 c -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 -0.3809,0.3515 -0.3809,0.9668 0,1.3183 l 3.0761,3.0762 -3.0761,3.1055 c -0.3809,0.3515 -0.3809,0.9668 0,1.3183 0.3515,0.3809 0.9668,0.3809 1.3183,0 l 3.1055,-3.0761 3.0762,3.0761 c 0.3515,0.3809 0.9668,0.3809 1.3183,0 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 l -3.0761,-3.1055 z" d="m 9.103975,1.603975 c 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 l -3.0762,3.0761 -3.1055,-3.0761 c -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 -0.3809,0.3515 -0.3809,0.9668 0,1.3183 l 3.0761,3.0762 -3.0761,3.1055 c -0.3809,0.3515 -0.3809,0.9668 0,1.3183 0.3515,0.3809 0.9668,0.3809 1.3183,0 l 3.1055,-3.0761 3.0762,3.0761 c 0.3515,0.3809 0.9668,0.3809 1.3183,0 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 l -3.0761,-3.1055 z"
fill="#5ca7ff" fill="#5ca7ff"
id="path2" /> id="path2"
style="stroke: none"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -39,5 +39,6 @@
<path <path
d="m 7.0324294,0 c 0.1172,0 0.2637,0.0293 0.3809,0.0879 l 5.5077996,2.3437 c 0.6445,0.293 1.1425,0.9082 1.1425,1.67 -0.0292,2.9296 -1.2304,8.2324 -6.2694996,10.664 -0.498,0.2344 -1.0547,0.2344 -1.5527,0 -5.0391,-2.4316 -6.24020004,-7.7344 -6.24020004,-10.664 -0.0293,-0.7618 0.4687,-1.377 1.11320004,-1.67 l 5.5078,-2.3437 C 6.7394294,0.0293 6.8859294,0 7.0324294,0 Z m 0,1.9629 V 13.0371 C 11.075429,11.0742 12.159429,6.7676 12.188629,4.1602 Z" d="m 7.0324294,0 c 0.1172,0 0.2637,0.0293 0.3809,0.0879 l 5.5077996,2.3437 c 0.6445,0.293 1.1425,0.9082 1.1425,1.67 -0.0292,2.9296 -1.2304,8.2324 -6.2694996,10.664 -0.498,0.2344 -1.0547,0.2344 -1.5527,0 -5.0391,-2.4316 -6.24020004,-7.7344 -6.24020004,-10.664 -0.0293,-0.7618 0.4687,-1.377 1.11320004,-1.67 l 5.5078,-2.3437 C 6.7394294,0.0293 6.8859294,0 7.0324294,0 Z m 0,1.9629 V 13.0371 C 11.075429,11.0742 12.159429,6.7676 12.188629,4.1602 Z"
fill="#5ca7ff" fill="#5ca7ff"
id="path2" /> id="path2"
style="stroke: none"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
version="1.1"
id="svg4"
sodipodi:docname="1.svg"
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs8" />
<sodipodi:namedview
id="namedview6"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
width="30px"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="23.771428"
inkscape:cx="2.6712741"
inkscape:cy="12.283654"
inkscape:window-width="2560"
inkscape:window-height="1377"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg4"
inkscape:showpageshadow="2"
inkscape:deskcolor="#d1d1d1" />
<path
style="opacity:1;fill:none;stroke-width:2.13035;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;stroke-dashoffset:0"
id="path940"
sodipodi:type="arc"
sodipodi:cx="7.614182"
sodipodi:cy="12.730443"
sodipodi:rx="11.467682"
sodipodi:ry="10.686775"
sodipodi:start="4.1887902"
sodipodi:end="5.2359878"
sodipodi:arc-type="slice"
d="m 1.880341,3.4754242 a 11.467682,10.686775 0 0 1 11.467682,2e-7 L 7.614182,12.730443 Z"
fill="#5ca7ff"
stroke="#5ca7ff" />
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
version="1.1"
id="svg4"
sodipodi:docname="2.svg"
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs8" />
<sodipodi:namedview
id="namedview6"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
width="30px"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="23.771428"
inkscape:cx="2.6712741"
inkscape:cy="12.283654"
inkscape:window-width="2560"
inkscape:window-height="1377"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg4"
inkscape:showpageshadow="2"
inkscape:deskcolor="#d1d1d1" />
<path
style="opacity:1;fill:none;stroke-width:2.13035;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path940"
sodipodi:type="arc"
sodipodi:cx="7.614182"
sodipodi:cy="12.730443"
sodipodi:rx="11.467682"
sodipodi:ry="10.686775"
sodipodi:start="4.3633231"
sodipodi:end="5.0614548"
sodipodi:arc-type="slice"
d="m 3.6920035,2.6881593 a 11.467682,10.686775 0 0 1 7.8443565,-2e-7 L 7.614182,12.730443 Z"
fill="#5ca7ff"
stroke="#5ca7ff" />
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
version="1.1"
id="svg4"
sodipodi:docname="3.svg"
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs8" />
<sodipodi:namedview
id="namedview6"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
width="30px"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="23.771428"
inkscape:cx="2.6712741"
inkscape:cy="12.283654"
inkscape:window-width="2560"
inkscape:window-height="1377"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg4"
inkscape:showpageshadow="2"
inkscape:deskcolor="#d1d1d1" />
<path
style="opacity:1;fill:none;stroke-width:2.13035;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path940"
sodipodi:type="arc"
sodipodi:cx="7.614182"
sodipodi:cy="12.730443"
sodipodi:rx="11.467682"
sodipodi:ry="10.686775"
sodipodi:start="4.5378561"
sodipodi:end="4.8869219"
sodipodi:arc-type="slice"
d="m 5.6228404,2.2060238 a 11.467682,10.686775 0 0 1 3.9826836,10e-8 L 7.614182,12.730443 Z"
fill="#5ca7ff"
stroke="#5ca7ff" />
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -39,7 +39,8 @@
<path <path
d="m 0.02182384,14.515426 c -0.0453,0.1119 -0.01864,0.2398 0.06662,0.325 0.08526,0.0853 0.21314,0.1119 0.32505,0.0666 l 1.95830996,-0.7833 c 0.15188,-0.0613 0.2891,-0.1505 0.405,-0.2664 l 1.02578,-1.0258 3.03735,0.7993 -0.2504,0.2504 c -0.1772,0.1772 -0.1772,0.4623 0,0.6395 0.1772,0.1772 0.4623,0.1772 0.6394,0 l 0.7461,-0.746 0.4263,-0.4263 0.3197,-0.3198 c 0.1772,-0.1771 0.1772,-0.4622 0,-0.6394 -0.1772,-0.1772 -0.4623,-0.1772 -0.6395,0 l -0.1065,0.1066 -1.9184,-1.9184 0.4356,-0.4356 1.4628,0.0959 c 0.0866,0.0066 0.1718,-0.0253 0.2331,-0.0866 l 0.2132,-0.2130999 c 0.1172,-0.1173 0.1172,-0.3091 0,-0.4263 l -1.2789,-1.2789 -0.8526,0.8526 c -0.1173,0.1172 -0.3091,0.1172 -0.4263,0 -0.1173,-0.1173 -0.1173,-0.3091 0,-0.4263 l 0.8526,-0.8526 -1.2789,-1.2789 c -0.1173,-0.1173 -0.3091,-0.1173 -0.4263,0 l -0.2132,0.2131 c -0.0613,0.0613 -0.0933,0.1465 -0.0866,0.2331 l 0.0959,1.4628 -0.4356,0.4356 -1.91834,-1.9183 0.10657,-0.1066 c 0.17717,-0.1772 0.17717,-0.4623 0,-0.6395 -0.17717,-0.1771 -0.46228,-0.1771 -0.63945,0 l -0.31972,0.3198 -0.4263,0.4263 -0.74602996,0.746 c -0.17717,0.1772 -0.17717,0.4623 0,0.6394 0.17717,0.1772 0.46228,0.1772 0.63944996,0 l 0.25041,-0.2504 0.79936,3.0373999 -1.02578,1.0258 c -0.11590996,0.1159 -0.20516996,0.2531 -0.26644996,0.405 z" d="m 0.02182384,14.515426 c -0.0453,0.1119 -0.01864,0.2398 0.06662,0.325 0.08526,0.0853 0.21314,0.1119 0.32505,0.0666 l 1.95830996,-0.7833 c 0.15188,-0.0613 0.2891,-0.1505 0.405,-0.2664 l 1.02578,-1.0258 3.03735,0.7993 -0.2504,0.2504 c -0.1772,0.1772 -0.1772,0.4623 0,0.6395 0.1772,0.1772 0.4623,0.1772 0.6394,0 l 0.7461,-0.746 0.4263,-0.4263 0.3197,-0.3198 c 0.1772,-0.1771 0.1772,-0.4622 0,-0.6394 -0.1772,-0.1772 -0.4623,-0.1772 -0.6395,0 l -0.1065,0.1066 -1.9184,-1.9184 0.4356,-0.4356 1.4628,0.0959 c 0.0866,0.0066 0.1718,-0.0253 0.2331,-0.0866 l 0.2132,-0.2130999 c 0.1172,-0.1173 0.1172,-0.3091 0,-0.4263 l -1.2789,-1.2789 -0.8526,0.8526 c -0.1173,0.1172 -0.3091,0.1172 -0.4263,0 -0.1173,-0.1173 -0.1173,-0.3091 0,-0.4263 l 0.8526,-0.8526 -1.2789,-1.2789 c -0.1173,-0.1173 -0.3091,-0.1173 -0.4263,0 l -0.2132,0.2131 c -0.0613,0.0613 -0.0933,0.1465 -0.0866,0.2331 l 0.0959,1.4628 -0.4356,0.4356 -1.91834,-1.9183 0.10657,-0.1066 c 0.17717,-0.1772 0.17717,-0.4623 0,-0.6395 -0.17717,-0.1771 -0.46228,-0.1771 -0.63945,0 l -0.31972,0.3198 -0.4263,0.4263 -0.74602996,0.746 c -0.17717,0.1772 -0.17717,0.4623 0,0.6394 0.17717,0.1772 0.46228,0.1772 0.63944996,0 l 0.25041,-0.2504 0.79936,3.0373999 -1.02578,1.0258 c -0.11590996,0.1159 -0.20516996,0.2531 -0.26644996,0.405 z"
fill="#5ca7ff" fill="#5ca7ff"
id="path2" /> id="path2"
style="stroke: none"/>
<path <path
d="m 9.0916338,5.3111261 c 2.5638002,-2.3307 8.3905002,-6.43275 11.1873002,-4.19528 3.4961,2.79688 4.1953,9.0895799 -2.7968,16.7808799" d="m 9.0916338,5.3111261 c 2.5638002,-2.3307 8.3905002,-6.43275 11.1873002,-4.19528 3.4961,2.79688 4.1953,9.0895799 -2.7968,16.7808799"
stroke="#5ca7ff" stroke="#5ca7ff"
@@ -50,13 +51,16 @@
<path <path
d="m 14.783034,12.805026 -0.1001,0.8985 0.9106,-0.2539 0.0806,0.6152 -0.8301,0.0586 0.5444,0.7251 -0.5542,0.2954 -0.3808,-0.7642 -0.3345,0.7593 -0.5762,-0.2905 0.5396,-0.7251 -0.8252,-0.0635 0.0952,-0.6103 0.8911,0.2539 -0.1001,-0.8985 z" d="m 14.783034,12.805026 -0.1001,0.8985 0.9106,-0.2539 0.0806,0.6152 -0.8301,0.0586 0.5444,0.7251 -0.5542,0.2954 -0.3808,-0.7642 -0.3345,0.7593 -0.5762,-0.2905 0.5396,-0.7251 -0.8252,-0.0635 0.0952,-0.6103 0.8911,0.2539 -0.1001,-0.8985 z"
fill="#5ca7ff" fill="#5ca7ff"
id="path6" /> id="path6"
style="stroke: none"/>
<path <path
d="m 13.384534,7.2113261 -0.1001,0.8984 0.9107,-0.2539 0.0805,0.6152 -0.83,0.0586 0.5444,0.7251 -0.5542,0.2954 -0.3809,-0.7641 -0.3344,0.7593 -0.5762,-0.2906 0.5395,-0.7251 -0.8252,-0.0634 0.0953,-0.6104 0.8911,0.2539 -0.1001,-0.8984 z" d="m 13.384534,7.2113261 -0.1001,0.8984 0.9107,-0.2539 0.0805,0.6152 -0.83,0.0586 0.5444,0.7251 -0.5542,0.2954 -0.3809,-0.7641 -0.3344,0.7593 -0.5762,-0.2906 0.5395,-0.7251 -0.8252,-0.0634 0.0953,-0.6104 0.8911,0.2539 -0.1001,-0.8984 z"
fill="#5ca7ff" fill="#5ca7ff"
id="path8" /> id="path8"
style="stroke: none"/>
<path <path
d="m 18.977834,7.2113261 -0.1001,0.8984 0.9106,-0.2539 0.0806,0.6152 -0.8301,0.0586 0.5445,0.7251 -0.5542,0.2954 -0.3809,-0.7641 -0.3345,0.7593 -0.5761,-0.2906 0.5395,-0.7251 -0.8252,-0.0634 0.0952,-0.6104 0.8911,0.2539 -0.1001,-0.8984 z" d="m 18.977834,7.2113261 -0.1001,0.8984 0.9106,-0.2539 0.0806,0.6152 -0.8301,0.0586 0.5445,0.7251 -0.5542,0.2954 -0.3809,-0.7641 -0.3345,0.7593 -0.5761,-0.2906 0.5395,-0.7251 -0.8252,-0.0634 0.0952,-0.6104 0.8911,0.2539 -0.1001,-0.8984 z"
fill="#5ca7ff" fill="#5ca7ff"
id="path10" /> id="path10"
style="stroke: none"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -39,7 +39,8 @@
<path <path
d="m 0.02182384,14.515426 c -0.0453,0.1119 -0.01864,0.2398 0.06662,0.325 0.08526,0.0853 0.21314,0.1119 0.32505,0.0666 l 1.95830996,-0.7833 c 0.15188,-0.0613 0.2891,-0.1505 0.405,-0.2664 l 1.02578,-1.0258 3.03735,0.7993 -0.2504,0.2504 c -0.1772,0.1772 -0.1772,0.4623 0,0.6395 0.1772,0.1772 0.4623,0.1772 0.6394,0 l 0.7461,-0.746 0.4263,-0.4263 0.3197,-0.3198 c 0.1772,-0.1771 0.1772,-0.4622 0,-0.6394 -0.1772,-0.1772 -0.4623,-0.1772 -0.6395,0 l -0.1065,0.1066 -1.9184,-1.9184 0.4356,-0.4356 1.4628,0.0959 c 0.0866,0.0066 0.1718,-0.0253 0.2331,-0.0866 l 0.2132,-0.2130999 c 0.1172,-0.1173 0.1172,-0.3091 0,-0.4263 l -1.2789,-1.2789 -0.8526,0.8526 c -0.1173,0.1172 -0.3091,0.1172 -0.4263,0 -0.1173,-0.1173 -0.1173,-0.3091 0,-0.4263 l 0.8526,-0.8526 -1.2789,-1.2789 c -0.1173,-0.1173 -0.3091,-0.1173 -0.4263,0 l -0.2132,0.2131 c -0.0613,0.0613 -0.0933,0.1465 -0.0866,0.2331 l 0.0959,1.4628 -0.4356,0.4356 -1.91834,-1.9183 0.10657,-0.1066 c 0.17717,-0.1772 0.17717,-0.4623 0,-0.6395 -0.17717,-0.1771 -0.46228,-0.1771 -0.63945,0 l -0.31972,0.3198 -0.4263,0.4263 -0.74602996,0.746 c -0.17717,0.1772 -0.17717,0.4623 0,0.6394 0.17717,0.1772 0.46228,0.1772 0.63944996,0 l 0.25041,-0.2504 0.79936,3.0373999 -1.02578,1.0258 c -0.11590996,0.1159 -0.20516996,0.2531 -0.26644996,0.405 z" d="m 0.02182384,14.515426 c -0.0453,0.1119 -0.01864,0.2398 0.06662,0.325 0.08526,0.0853 0.21314,0.1119 0.32505,0.0666 l 1.95830996,-0.7833 c 0.15188,-0.0613 0.2891,-0.1505 0.405,-0.2664 l 1.02578,-1.0258 3.03735,0.7993 -0.2504,0.2504 c -0.1772,0.1772 -0.1772,0.4623 0,0.6395 0.1772,0.1772 0.4623,0.1772 0.6394,0 l 0.7461,-0.746 0.4263,-0.4263 0.3197,-0.3198 c 0.1772,-0.1771 0.1772,-0.4622 0,-0.6394 -0.1772,-0.1772 -0.4623,-0.1772 -0.6395,0 l -0.1065,0.1066 -1.9184,-1.9184 0.4356,-0.4356 1.4628,0.0959 c 0.0866,0.0066 0.1718,-0.0253 0.2331,-0.0866 l 0.2132,-0.2130999 c 0.1172,-0.1173 0.1172,-0.3091 0,-0.4263 l -1.2789,-1.2789 -0.8526,0.8526 c -0.1173,0.1172 -0.3091,0.1172 -0.4263,0 -0.1173,-0.1173 -0.1173,-0.3091 0,-0.4263 l 0.8526,-0.8526 -1.2789,-1.2789 c -0.1173,-0.1173 -0.3091,-0.1173 -0.4263,0 l -0.2132,0.2131 c -0.0613,0.0613 -0.0933,0.1465 -0.0866,0.2331 l 0.0959,1.4628 -0.4356,0.4356 -1.91834,-1.9183 0.10657,-0.1066 c 0.17717,-0.1772 0.17717,-0.4623 0,-0.6395 -0.17717,-0.1771 -0.46228,-0.1771 -0.63945,0 l -0.31972,0.3198 -0.4263,0.4263 -0.74602996,0.746 c -0.17717,0.1772 -0.17717,0.4623 0,0.6394 0.17717,0.1772 0.46228,0.1772 0.63944996,0 l 0.25041,-0.2504 0.79936,3.0373999 -1.02578,1.0258 c -0.11590996,0.1159 -0.20516996,0.2531 -0.26644996,0.405 z"
fill="#5ca7ff" fill="#5ca7ff"
id="path2" /> id="path2"
style="stroke: none"/>
<path <path
d="m 9.0916338,5.3111261 c 2.5638002,-2.3307 8.3905002,-6.43275 11.1873002,-4.19528 3.4961,2.79688 4.1953,9.0895799 -2.7968,16.7808799" d="m 9.0916338,5.3111261 c 2.5638002,-2.3307 8.3905002,-6.43275 11.1873002,-4.19528 3.4961,2.79688 4.1953,9.0895799 -2.7968,16.7808799"
stroke="#5ca7ff" stroke="#5ca7ff"

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -39,5 +39,6 @@
<path <path
d="m 9.103975,1.603975 c 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 l -3.0762,3.0761 -3.1055,-3.0761 c -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 -0.3809,0.3515 -0.3809,0.9668 0,1.3183 l 3.0761,3.0762 -3.0761,3.1055 c -0.3809,0.3515 -0.3809,0.9668 0,1.3183 0.3515,0.3809 0.9668,0.3809 1.3183,0 l 3.1055,-3.0761 3.0762,3.0761 c 0.3515,0.3809 0.9668,0.3809 1.3183,0 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 l -3.0761,-3.1055 z" d="m 9.103975,1.603975 c 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 l -3.0762,3.0761 -3.1055,-3.0761 c -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 -0.3809,0.3515 -0.3809,0.9668 0,1.3183 l 3.0761,3.0762 -3.0761,3.1055 c -0.3809,0.3515 -0.3809,0.9668 0,1.3183 0.3515,0.3809 0.9668,0.3809 1.3183,0 l 3.1055,-3.0761 3.0762,3.0761 c 0.3515,0.3809 0.9668,0.3809 1.3183,0 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 l -3.0761,-3.1055 z"
fill="#5ca7ff" fill="#5ca7ff"
id="path2" /> id="path2"
style="stroke: none"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -39,7 +39,8 @@
<path <path
d="M 0.1977,6.4546 C 0.07745,6.5055 0,6.6237 0,6.7542 0,6.8846 0.07745,7.0028 0.1977,7.0538 l 2.09719,0.8987 c 0.16304,0.0694 0.33629,0.106 0.51361,0.106 h 1.5693 l 1.712,2.9349 H 5.7067 c -0.2711,0 -0.4892,0.2181 -0.4892,0.4891 0,0.2711 0.2181,0.4892 0.4892,0.4892 H 6.848 7.5002 7.9893 c 0.2711,0 0.4892,-0.2181 0.4892,-0.4892 0,-0.271 -0.2181,-0.4891 -0.4892,-0.4891 H 7.8263 V 8.0585 h 0.6664 l 1.0456,1.1923 c 0.0611,0.0713 0.1508,0.1121 0.2445,0.1121 h 0.3261 c 0.1794,0 0.3261,-0.1467 0.3261,-0.3261 V 7.0802 H 9.1306 c -0.1793,0 -0.326,-0.1467 -0.326,-0.326 0,-0.1794 0.1467,-0.3261 0.326,-0.3261 H 10.435 V 4.4715 c 0,-0.1794 -0.1467,-0.3261 -0.3261,-0.3261 H 9.7828 c -0.0937,0 -0.1834,0.0407 -0.2445,0.112 L 8.4927,5.4498 H 7.8263 V 2.5149 h 0.163 c 0.2711,0 0.4892,-0.2181 0.4892,-0.4891 0,-0.2711 -0.2181,-0.4892 -0.4892,-0.4892 H 7.5002 6.848 5.7067 c -0.2711,0 -0.4892,0.2181 -0.4892,0.4892 0,0.271 0.2181,0.4891 0.4892,0.4891 H 6.0898 L 4.3778,5.4498 H 2.8085 c -0.17732,0 -0.35057,0.0367 -0.51361,0.106 z" d="M 0.1977,6.4546 C 0.07745,6.5055 0,6.6237 0,6.7542 0,6.8846 0.07745,7.0028 0.1977,7.0538 l 2.09719,0.8987 c 0.16304,0.0694 0.33629,0.106 0.51361,0.106 h 1.5693 l 1.712,2.9349 H 5.7067 c -0.2711,0 -0.4892,0.2181 -0.4892,0.4891 0,0.2711 0.2181,0.4892 0.4892,0.4892 H 6.848 7.5002 7.9893 c 0.2711,0 0.4892,-0.2181 0.4892,-0.4892 0,-0.271 -0.2181,-0.4891 -0.4892,-0.4891 H 7.8263 V 8.0585 h 0.6664 l 1.0456,1.1923 c 0.0611,0.0713 0.1508,0.1121 0.2445,0.1121 h 0.3261 c 0.1794,0 0.3261,-0.1467 0.3261,-0.3261 V 7.0802 H 9.1306 c -0.1793,0 -0.326,-0.1467 -0.326,-0.326 0,-0.1794 0.1467,-0.3261 0.326,-0.3261 H 10.435 V 4.4715 c 0,-0.1794 -0.1467,-0.3261 -0.3261,-0.3261 H 9.7828 c -0.0937,0 -0.1834,0.0407 -0.2445,0.112 L 8.4927,5.4498 H 7.8263 V 2.5149 h 0.163 c 0.2711,0 0.4892,-0.2181 0.4892,-0.4891 0,-0.2711 -0.2181,-0.4892 -0.4892,-0.4892 H 7.5002 6.848 5.7067 c -0.2711,0 -0.4892,0.2181 -0.4892,0.4892 0,0.271 0.2181,0.4891 0.4892,0.4891 H 6.0898 L 4.3778,5.4498 H 2.8085 c -0.17732,0 -0.35057,0.0367 -0.51361,0.106 z"
fill="#5ca7ff" fill="#5ca7ff"
id="path2" /> id="path2"
style="stroke: none"/>
<path <path
d="M 12.8398,6.5498 H 23.2749" d="M 12.8398,6.5498 H 23.2749"
stroke="#5ca7ff" stroke="#5ca7ff"
@@ -48,17 +49,21 @@
<path <path
d="m 16.4116,9 -0.1,0.8984 0.9106,-0.2539 0.0806,0.6152 -0.8301,0.0586 0.5444,0.7251 -0.5542,0.2955 L 16.0821,10.5747 15.7476,11.334 15.1714,11.0434 15.711,10.3183 14.8858,10.2549 14.981,9.6445 15.8721,9.8984 15.772,9 Z" d="m 16.4116,9 -0.1,0.8984 0.9106,-0.2539 0.0806,0.6152 -0.8301,0.0586 0.5444,0.7251 -0.5542,0.2955 L 16.0821,10.5747 15.7476,11.334 15.1714,11.0434 15.711,10.3183 14.8858,10.2549 14.981,9.6445 15.8721,9.8984 15.772,9 Z"
fill="#5ca7ff" fill="#5ca7ff"
id="path6" /> id="path6"
style="stroke: none"/>
<path <path
d="m 21.4116,10.6582 -0.1,0.8984 0.9106,-0.2539 0.0806,0.6153 -0.8301,0.0585 0.5444,0.7251 -0.5542,0.2955 -0.3808,-0.7642 -0.3345,0.7593 -0.5762,-0.2906 0.5396,-0.7251 -0.8252,-0.0634 0.0952,-0.6104 0.8911,0.2539 -0.1001,-0.8984 z" d="m 21.4116,10.6582 -0.1,0.8984 0.9106,-0.2539 0.0806,0.6153 -0.8301,0.0585 0.5444,0.7251 -0.5542,0.2955 -0.3808,-0.7642 -0.3345,0.7593 -0.5762,-0.2906 0.5396,-0.7251 -0.8252,-0.0634 0.0952,-0.6104 0.8911,0.2539 -0.1001,-0.8984 z"
fill="#5ca7ff" fill="#5ca7ff"
id="path8" /> id="path8"
style="stroke: none"/>
<path <path
d="m 21.4116,0 -0.1,0.8984 0.9106,-0.2539 0.0806,0.6152 -0.8301,0.0586 0.5444,0.7251 L 21.4629,2.3389 21.0821,1.5747 20.7476,2.334 20.1714,2.0434 20.711,1.3183 19.8858,1.2549 19.981,0.6445 20.8721,0.8984 20.772,0 Z" d="m 21.4116,0 -0.1,0.8984 0.9106,-0.2539 0.0806,0.6152 -0.8301,0.0586 0.5444,0.7251 L 21.4629,2.3389 21.0821,1.5747 20.7476,2.334 20.1714,2.0434 20.711,1.3183 19.8858,1.2549 19.981,0.6445 20.8721,0.8984 20.772,0 Z"
fill="#5ca7ff" fill="#5ca7ff"
id="path10" /> id="path10"
style="stroke: none"/>
<path <path
d="m 16.4116,1.6582 -0.1,0.8984 0.9106,-0.2539 0.0806,0.6153 -0.8301,0.0585 0.5444,0.7251 L 16.4629,3.9971 16.0821,3.2329 15.7476,3.9922 15.1714,3.7016 15.711,2.9765 14.8858,2.9131 14.981,2.3027 15.8721,2.5566 15.772,1.6582 Z" d="m 16.4116,1.6582 -0.1,0.8984 0.9106,-0.2539 0.0806,0.6153 -0.8301,0.0585 0.5444,0.7251 L 16.4629,3.9971 16.0821,3.2329 15.7476,3.9922 15.1714,3.7016 15.711,2.9765 14.8858,2.9131 14.981,2.3027 15.8721,2.5566 15.772,1.6582 Z"
fill="#5ca7ff" fill="#5ca7ff"
id="path12" /> id="path12"
style="stroke: none"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm169.8-90.7c7.9-22.3 29.1-37.3 52.8-37.3h58.3c34.9 0 63.1 28.3 63.1 63.1c0 22.6-12.1 43.5-31.7 54.8L280 264.4c-.2 13-10.9 23.6-24 23.6c-13.3 0-24-10.7-24-24V250.5c0-8.6 4.6-16.5 12.1-20.8l44.3-25.4c4.7-2.7 7.6-7.7 7.6-13.1c0-8.4-6.8-15.1-15.1-15.1H222.6c-3.4 0-6.4 2.1-7.5 5.3l-.4 1.2c-4.4 12.5-18.2 19-30.6 14.6s-19-18.2-14.6-30.6l.4-1.2zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"/></svg>

After

Width:  |  Height:  |  Size: 728 B

View File

@@ -23,6 +23,7 @@
--accent-amber: #ffd828; --accent-amber: #ffd828;
--accent-green: #8bff63; --accent-green: #8bff63;
--accent-light-blue: #5ca7ff; --accent-light-blue: #5ca7ff;
--accent-dark-blue: #017DC1;
--transparent-accent-light-blue: rgba(92, 167, 255, .33); --transparent-accent-light-blue: rgba(92, 167, 255, .33);
--accent-light-red: #F5B6B6; --accent-light-red: #F5B6B6;

View File

@@ -48,6 +48,18 @@ export const emissionsCountermeasuresDescriptions: string[] = [
"Always on (Radar and ECM always on)" "Always on (Radar and ECM always on)"
]; ];
export const shotsScatterDescriptions: string[] = [
"When performing scenic shooting tasks like simulated firefights, will shoot with a large scatter",
"When performing scenic shooting tasks like simulated firefights, will shoot with a medium scatter",
"When performing scenic shooting tasks like simulated firefights, will shoot with a small scatter (Radar guided units will track shots when the enemy unit is close)"
];
export const shotsIntensityDescriptions: string[] = [
"When performing scenic shooting tasks like simulated firefights, will shoot with a low rate of fire",
"When performing scenic shooting tasks like simulated firefights, will shoot with a medium rate of fire",
"When performing scenic shooting tasks like simulated firefights, will shoot with a high rate of fire"
];
export const minSpeedValues: { [key: string]: number } = { Aircraft: 100, Helicopter: 0, NavyUnit: 0, GroundUnit: 0 }; export const minSpeedValues: { [key: string]: number } = { Aircraft: 100, Helicopter: 0, NavyUnit: 0, GroundUnit: 0 };
export const maxSpeedValues: { [key: string]: number } = { Aircraft: 800, Helicopter: 300, NavyUnit: 60, GroundUnit: 60 }; export const maxSpeedValues: { [key: string]: number } = { Aircraft: 800, Helicopter: 300, NavyUnit: 60, GroundUnit: 60 };
export const speedIncrements: { [key: string]: number } = { Aircraft: 25, Helicopter: 10, NavyUnit: 5, GroundUnit: 5 }; export const speedIncrements: { [key: string]: number } = { Aircraft: 25, Helicopter: 10, NavyUnit: 5, GroundUnit: 5 };
@@ -221,6 +233,8 @@ export enum DataIndexes {
hasTask, hasTask,
position, position,
speed, speed,
horizontalVelocity,
verticalVelocity,
heading, heading,
isActiveTanker, isActiveTanker,
isActiveAWACS, isActiveAWACS,
@@ -246,6 +260,8 @@ export enum DataIndexes {
activePath, activePath,
isLeader, isLeader,
operateAs, operateAs,
shotsScatter,
shotsIntensity,
endOfData = 255 endOfData = 255
}; };

View File

@@ -1,11 +1,31 @@
export interface ContextInterface { export interface ContextInterface {
useSpawnMenu?: boolean;
useUnitControlPanel?: boolean;
useUnitInfoPanel?: boolean;
} }
export class Context { export class Context {
constructor( config:ContextInterface ) { #useSpawnMenu:boolean;
#useUnitControlPanel:boolean;
#useUnitInfoPanel:boolean;
constructor( config:ContextInterface ) {
this.#useSpawnMenu = ( config.useSpawnMenu !== false );
this.#useUnitControlPanel = ( config.useUnitControlPanel !== false );
this.#useUnitInfoPanel = ( config.useUnitInfoPanel !== false );
}
getUseSpawnMenu() {
return this.#useSpawnMenu;
}
getUseUnitControlPanel() {
return this.#useUnitControlPanel;
}
getUseUnitInfoPanel() {
return this.#useUnitInfoPanel;
} }
} }

View File

@@ -105,6 +105,9 @@ export class MapContextMenu extends ContextMenu {
* @param latlng Leaflet latlng object of the mouse click * @param latlng Leaflet latlng object of the mouse click
*/ */
show(x: number, y: number, latlng: LatLng) { show(x: number, y: number, latlng: LatLng) {
if (!getApp().getCurrentContext().getUseSpawnMenu())
return false;
super.show(x, y, latlng); super.show(x, y, latlng);
this.#aircraftSpawnMenu.setLatLng(latlng); this.#aircraftSpawnMenu.setLatLng(latlng);

View File

@@ -152,6 +152,8 @@ export interface UnitData {
hasTask: boolean; hasTask: boolean;
position: LatLng; position: LatLng;
speed: number; speed: number;
horizontalVelocity: number;
verticalVelocity: number;
heading: number; heading: number;
isActiveTanker: boolean; isActiveTanker: boolean;
isActiveAWACS: boolean; isActiveAWACS: boolean;
@@ -177,6 +179,8 @@ export interface UnitData {
activePath: LatLng[]; activePath: LatLng[];
isLeader: boolean; isLeader: boolean;
operateAs: string; operateAs: string;
shotsScatter: number;
shotsIntensity: number;
} }
export interface LoadoutItemBlueprint { export interface LoadoutItemBlueprint {
@@ -210,12 +214,19 @@ export interface UnitBlueprint {
muzzleVelocity?: number; muzzleVelocity?: number;
aimTime?: number; aimTime?: number;
shotsToFire?: number; shotsToFire?: number;
shotsBaseInterval?: number;
shotsBaseScatter?: number;
description?: string; description?: string;
abilities?: string; abilities?: string;
acquisitionRange?: number; acquisitionRange?: number;
engagementRange?: number; engagementRange?: number;
targetingRange?: number;
aimMethodRange?: number;
alertnessTimeConstant?: number;
canTargetPoint?: boolean; canTargetPoint?: boolean;
canRearm?: boolean; canRearm?: boolean;
canAAA?: boolean;
indirectFire?: boolean;
} }
export interface UnitSpawnOptions { export interface UnitSpawnOptions {

View File

@@ -734,7 +734,7 @@ export class Map extends L.Map {
const makeTitle = (isProtected:boolean) => { const makeTitle = (isProtected:boolean) => {
return ( isProtected ) ? "Unit type is protected and will ignore orders" : "Unit is NOT protected and will respond to orders"; return ( isProtected ) ? "Unit type is protected and will ignore orders" : "Unit is NOT protected and will respond to orders";
} }
this.#mapMarkerControls.forEach( (control:MapMarkerControl) => { this.getMapMarkerControls().forEach( (control:MapMarkerControl) => {
const toggles = `["${control.toggles.join('","')}"]`; const toggles = `["${control.toggles.join('","')}"]`;
const div = document.createElement("div"); const div = document.createElement("div");
div.className = control.protectable === true ? "protectable" : ""; div.className = control.protectable === true ? "protectable" : "";
@@ -901,5 +901,9 @@ export class Map extends L.Map {
this.#visibilityOptions[option] = ev.currentTarget.checked; this.#visibilityOptions[option] = ev.currentTarget.checked;
document.dispatchEvent(new CustomEvent("mapVisibilityOptionsChanged")); document.dispatchEvent(new CustomEvent("mapVisibilityOptionsChanged"));
} }
getMapMarkerControls() {
return this.#mapMarkerControls;
}
} }

View File

@@ -403,19 +403,26 @@ export class OlympusApp {
}); });
/* Try and connect with the Olympus REST server */ /* Try and connect with the Olympus REST server */
document.addEventListener("tryConnection", () => { const loginForm = document.getElementById("authentication-form");
const form = document.querySelector("#splash-content")?.querySelector("#authentication-form"); if (loginForm instanceof HTMLFormElement) {
const username = (form?.querySelector("#username") as HTMLInputElement).value; loginForm.addEventListener("submit", (ev:SubmitEvent) => {
const password = (form?.querySelector("#password") as HTMLInputElement).value; ev.preventDefault();
ev.stopPropagation();
const username = (loginForm.querySelector("#username") as HTMLInputElement).value;
const password = (loginForm.querySelector("#password") as HTMLInputElement).value;
/* Update the user credentials */ // Update the user credentials
this.getServerManager().setCredentials(username, password); this.getServerManager().setCredentials(username, password);
/* Start periodically requesting updates */ // Start periodically requesting updates
this.getServerManager().startUpdate(); this.getServerManager().startUpdate();
this.setLoginStatus("connecting");
});
} else {
console.error("Unable to find login form.");
}
this.setLoginStatus("connecting");
})
/* Reload the page, used to mimic a restart of the app */ /* Reload the page, used to mimic a restart of the app */
document.addEventListener("reloadPage", () => { document.addEventListener("reloadPage", () => {

View File

@@ -6,7 +6,7 @@ import { aircraftDatabase } from "../unit/databases/aircraftdatabase";
import { Unit } from "../unit/unit"; import { Unit } from "../unit/unit";
import { Panel } from "./panel"; import { Panel } from "./panel";
import { Switch } from "../controls/switch"; import { Switch } from "../controls/switch";
import { ROEDescriptions, ROEs, altitudeIncrements, emissionsCountermeasures, emissionsCountermeasuresDescriptions, maxAltitudeValues, maxSpeedValues, minAltitudeValues, minSpeedValues, reactionsToThreat, reactionsToThreatDescriptions, speedIncrements } from "../constants/constants"; import { ROEDescriptions, ROEs, altitudeIncrements, emissionsCountermeasures, emissionsCountermeasuresDescriptions, maxAltitudeValues, maxSpeedValues, minAltitudeValues, minSpeedValues, reactionsToThreat, reactionsToThreatDescriptions, shotsIntensityDescriptions, shotsScatterDescriptions, speedIncrements } from "../constants/constants";
import { ftToM, knotsToMs, mToFt, msToKnots } from "../other/utils"; import { ftToM, knotsToMs, mToFt, msToKnots } from "../other/utils";
import { GeneralSettings, Radio, TACAN } from "../interfaces"; import { GeneralSettings, Radio, TACAN } from "../interfaces";
@@ -56,9 +56,19 @@ export class UnitControlPanel extends Panel {
return this.#createOptionButton(option, `emissions/${option.toLowerCase()}.svg`, emissionsCountermeasuresDescriptions[index],() => { getApp().getUnitsManager().selectedUnitsSetEmissionsCountermeasures(option); }); return this.#createOptionButton(option, `emissions/${option.toLowerCase()}.svg`, emissionsCountermeasuresDescriptions[index],() => { getApp().getUnitsManager().selectedUnitsSetEmissionsCountermeasures(option); });
}); });
this.#optionButtons["shotsScatter"] = [1, 2, 3].map((option: number, index: number) => {
return this.#createOptionButton(option.toString(), `scatter/${option.toString().toLowerCase()}.svg`, shotsScatterDescriptions[index],() => { getApp().getUnitsManager().selectedUnitsSetShotsScatter(option); });
});
this.#optionButtons["shotsIntensity"] = [1, 2, 3].map((option: number, index: number) => {
return this.#createOptionButton(option.toString(), `intensity/${option.toString().toLowerCase()}.svg`, shotsIntensityDescriptions[index],() => { getApp().getUnitsManager().selectedUnitsSetShotsIntensity(option); });
});
this.getElement().querySelector("#roe-buttons-container")?.append(...this.#optionButtons["ROE"]); this.getElement().querySelector("#roe-buttons-container")?.append(...this.#optionButtons["ROE"]);
this.getElement().querySelector("#reaction-to-threat-buttons-container")?.append(...this.#optionButtons["reactionToThreat"]); this.getElement().querySelector("#reaction-to-threat-buttons-container")?.append(...this.#optionButtons["reactionToThreat"]);
this.getElement().querySelector("#emissions-countermeasures-buttons-container")?.append(...this.#optionButtons["emissionsCountermeasures"]); this.getElement().querySelector("#emissions-countermeasures-buttons-container")?.append(...this.#optionButtons["emissionsCountermeasures"]);
this.getElement().querySelector("#shots-scatter-buttons-container")?.append(...this.#optionButtons["shotsScatter"]);
this.getElement().querySelector("#shots-intensity-buttons-container")?.append(...this.#optionButtons["shotsIntensity"]);
/* Tanker */ /* Tanker */
this.#tankerSwitch = new Switch("tanker-on-switch", (value: boolean) => { this.#tankerSwitch = new Switch("tanker-on-switch", (value: boolean) => {
@@ -131,6 +141,10 @@ export class UnitControlPanel extends Panel {
} }
show() { show() {
const context = getApp().getCurrentContext();
if ( !context.getUseUnitControlPanel() )
return;
super.show(); super.show();
this.#speedTypeSwitch.resetExpectedValue(); this.#speedTypeSwitch.resetExpectedValue();
this.#altitudeTypeSwitch.resetExpectedValue(); this.#altitudeTypeSwitch.resetExpectedValue();
@@ -195,6 +209,8 @@ export class UnitControlPanel extends Panel {
element.toggleAttribute("data-show-roe", !isTanker && !isAWACS); element.toggleAttribute("data-show-roe", !isTanker && !isAWACS);
element.toggleAttribute("data-show-threat", (this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter")) && !(this.#selectedUnitsTypes.includes("GroundUnit") || this.#selectedUnitsTypes.includes("NavyUnit"))); element.toggleAttribute("data-show-threat", (this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter")) && !(this.#selectedUnitsTypes.includes("GroundUnit") || this.#selectedUnitsTypes.includes("NavyUnit")));
element.toggleAttribute("data-show-emissions-countermeasures", (this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter")) && !(this.#selectedUnitsTypes.includes("GroundUnit") || this.#selectedUnitsTypes.includes("NavyUnit"))); element.toggleAttribute("data-show-emissions-countermeasures", (this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter")) && !(this.#selectedUnitsTypes.includes("GroundUnit") || this.#selectedUnitsTypes.includes("NavyUnit")));
element.toggleAttribute("data-show-shots-scatter", this.#selectedUnitsTypes.includes("GroundUnit")); //TODO: more refined
element.toggleAttribute("data-show-shots-intensity", this.#selectedUnitsTypes.includes("GroundUnit")); //TODO: more refined
element.toggleAttribute("data-show-tanker-button", getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.isTanker();}) === true); element.toggleAttribute("data-show-tanker-button", getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.isTanker();}) === true);
element.toggleAttribute("data-show-AWACS-button", getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.isAWACS();}) === true); element.toggleAttribute("data-show-AWACS-button", getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.isAWACS();}) === true);
element.toggleAttribute("data-show-on-off", (this.#selectedUnitsTypes.includes("GroundUnit") || this.#selectedUnitsTypes.includes("NavyUnit")) && !(this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter"))); element.toggleAttribute("data-show-on-off", (this.#selectedUnitsTypes.includes("GroundUnit") || this.#selectedUnitsTypes.includes("NavyUnit")) && !(this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter")));
@@ -256,6 +272,14 @@ export class UnitControlPanel extends Panel {
button.classList.toggle("selected", this.#units.every((unit: Unit) => unit.getEmissionsCountermeasures() === button.value)) button.classList.toggle("selected", this.#units.every((unit: Unit) => unit.getEmissionsCountermeasures() === button.value))
}); });
this.#optionButtons["shotsScatter"].forEach((button: HTMLButtonElement) => {
button.classList.toggle("selected", this.#units.every((unit: Unit) => unit.getShotsScatter().toString() === button.value))
});
this.#optionButtons["shotsIntensity"].forEach((button: HTMLButtonElement) => {
button.classList.toggle("selected", this.#units.every((unit: Unit) => unit.getShotsIntensity().toString() === button.value))
});
this.#tankerSwitch.setValue(isActiveTanker, false); this.#tankerSwitch.setValue(isActiveTanker, false);
this.#AWACSSwitch.setValue(isActiveAWACAS, false); this.#AWACSSwitch.setValue(isActiveAWACAS, false);
this.#onOffSwitch.setValue(onOff, false); this.#onOffSwitch.setValue(onOff, false);

View File

@@ -1,3 +1,4 @@
import { getApp } from "..";
import { Ammo } from "../interfaces"; import { Ammo } from "../interfaces";
import { aircraftDatabase } from "../unit/databases/aircraftdatabase"; import { aircraftDatabase } from "../unit/databases/aircraftdatabase";
import { Unit } from "../unit/unit"; import { Unit } from "../unit/unit";
@@ -92,4 +93,12 @@ export class UnitInfoPanel extends Panel {
else else
this.hide(); this.hide();
} }
show() {
const context = getApp().getCurrentContext();
if ( !context.getUseUnitInfoPanel() )
return;
super.show();
}
} }

View File

@@ -357,6 +357,18 @@ export class ServerManager {
this.PUT(data, callback); this.PUT(data, callback);
} }
setShotsScatter(ID: number, shotsScatter: number, callback: CallableFunction = () => {}) {
var command = { "ID": ID, "shotsScatter": shotsScatter }
var data = { "setShotsScatter": command }
this.PUT(data, callback);
}
setShotsIntensity(ID: number, shotsIntensity: number, callback: CallableFunction = () => {}) {
var command = { "ID": ID, "shotsIntensity": shotsIntensity }
var data = { "setShotsIntensity": command }
this.PUT(data, callback);
}
setAdvacedOptions(ID: number, isActiveTanker: boolean, isActiveAWACS: boolean, TACAN: TACAN, radio: Radio, generalSettings: GeneralSettings, callback: CallableFunction = () => {}) { setAdvacedOptions(ID: number, isActiveTanker: boolean, isActiveAWACS: boolean, TACAN: TACAN, radio: Radio, generalSettings: GeneralSettings, callback: CallableFunction = () => {}) {
var command = { var command = {
"ID": ID, "ID": ID,

View File

@@ -34,6 +34,8 @@ export class Unit extends CustomMarker {
#hasTask: boolean = false; #hasTask: boolean = false;
#position: LatLng = new LatLng(0, 0, 0); #position: LatLng = new LatLng(0, 0, 0);
#speed: number = 0; #speed: number = 0;
#horizontalVelocity: number = 0;
#verticalVelocity: number = 0;
#heading: number = 0; #heading: number = 0;
#isActiveTanker: boolean = false; #isActiveTanker: boolean = false;
#isActiveAWACS: boolean = false; #isActiveAWACS: boolean = false;
@@ -78,6 +80,8 @@ export class Unit extends CustomMarker {
#activePath: LatLng[] = []; #activePath: LatLng[] = [];
#isLeader: boolean = false; #isLeader: boolean = false;
#operateAs: string = "blue"; #operateAs: string = "blue";
#shotsScatter: number = 2;
#shotsIntensity: number = 2;
#selectable: boolean; #selectable: boolean;
#selected: boolean = false; #selected: boolean = false;
@@ -95,47 +99,49 @@ export class Unit extends CustomMarker {
#doubleClickTimer: number = 0; #doubleClickTimer: number = 0;
#hotgroup: number | null = null; #hotgroup: number | null = null;
#detectionMethods: number[] = []; #detectionMethods: number[] = [];
#isProtected:boolean = false;
getActivePath() { return this.#activePath };
getAlive() { return this.#alive }; getAlive() { return this.#alive };
getAmmo() { return this.#ammo }; getHuman() { return this.#human };
getCoalition() { return this.#coalition };
getContacts() { return this.#contacts };
getControlled() { return this.#controlled }; getControlled() { return this.#controlled };
getCoalition() { return this.#coalition };
getCountry() { return this.#country }; getCountry() { return this.#country };
getDesiredAltitude() { return this.#desiredAltitude }; getName() { return this.#name };
getDesiredAltitudeType() { return this.#desiredAltitudeType }; getUnitName() { return this.#unitName };
getGroupName() { return this.#groupName };
getState() { return this.#state };
getTask() { return this.#task };
getHasTask() { return this.#hasTask };
getPosition() { return this.#position };
getSpeed() { return this.#speed };
getHorizontalVelocity() { return this.#horizontalVelocity };
getVerticalVelocity() { return this.#verticalVelocity };
getHeading() { return this.#heading };
getIsActiveTanker() { return this.#isActiveTanker };
getIsActiveAWACS() { return this.#isActiveAWACS };
getOnOff() { return this.#onOff };
getFollowRoads() { return this.#followRoads };
getFuel() { return this.#fuel };
getDesiredSpeed() { return this.#desiredSpeed }; getDesiredSpeed() { return this.#desiredSpeed };
getDesiredSpeedType() { return this.#desiredSpeedType }; getDesiredSpeedType() { return this.#desiredSpeedType };
getEmissionsCountermeasures() { return this.#emissionsCountermeasures }; getDesiredAltitude() { return this.#desiredAltitude };
getFollowRoads() { return this.#followRoads }; getDesiredAltitudeType() { return this.#desiredAltitudeType };
getFormationOffset() { return this.#formationOffset };
getFuel() { return this.#fuel };
getGeneralSettings() { return this.#generalSettings };
getGroupName() { return this.#groupName };
getHasTask() { return this.#hasTask };
getHeading() { return this.#heading };
getHuman() { return this.#human };
getIsActiveAWACS() { return this.#isActiveAWACS };
getIsActiveTanker() { return this.#isActiveTanker };
getIsLeader() { return this.#isLeader };
getLeaderID() { return this.#leaderID }; getLeaderID() { return this.#leaderID };
getName() { return this.#name }; getFormationOffset() { return this.#formationOffset };
getOnOff() { return this.#onOff };
getOperateAs() { return this.#operateAs };
getPosition() { return this.#position };
getIsProtected() { return this.#isProtected };
getRadio() { return this.#radio };
getReactionToThreat() { return this.#reactionToThreat };
getROE() { return this.#ROE };
getSpeed() { return this.#speed };
getState() { return this.#state };
getTACAN() { return this.#TACAN };
getTargetID() { return this.#targetID }; getTargetID() { return this.#targetID };
getTargetPosition() { return this.#targetPosition }; getTargetPosition() { return this.#targetPosition };
getTask() { return this.#task }; getROE() { return this.#ROE };
getUnitName() { return this.#unitName }; getReactionToThreat() { return this.#reactionToThreat };
getEmissionsCountermeasures() { return this.#emissionsCountermeasures };
getTACAN() { return this.#TACAN };
getRadio() { return this.#radio };
getGeneralSettings() { return this.#generalSettings };
getAmmo() { return this.#ammo };
getContacts() { return this.#contacts };
getActivePath() { return this.#activePath };
getIsLeader() { return this.#isLeader };
getOperateAs() { return this.#operateAs };
getShotsScatter() { return this.#shotsScatter};
getShotsIntensity() { return this.#shotsIntensity};
static getConstructor(type: string) { static getConstructor(type: string) {
if (type === "GroundUnit") return GroundUnit; if (type === "GroundUnit") return GroundUnit;
@@ -222,6 +228,8 @@ export class Unit extends CustomMarker {
case DataIndexes.hasTask: this.#hasTask = dataExtractor.extractBool(); break; case DataIndexes.hasTask: this.#hasTask = dataExtractor.extractBool(); break;
case DataIndexes.position: this.#position = dataExtractor.extractLatLng(); updateMarker = true; break; case DataIndexes.position: this.#position = dataExtractor.extractLatLng(); updateMarker = true; break;
case DataIndexes.speed: this.#speed = dataExtractor.extractFloat64(); updateMarker = true; break; case DataIndexes.speed: this.#speed = dataExtractor.extractFloat64(); updateMarker = true; break;
case DataIndexes.horizontalVelocity: this.#horizontalVelocity = dataExtractor.extractFloat64(); break;
case DataIndexes.verticalVelocity: this.#verticalVelocity = dataExtractor.extractFloat64(); break;
case DataIndexes.heading: this.#heading = dataExtractor.extractFloat64(); updateMarker = true; break; case DataIndexes.heading: this.#heading = dataExtractor.extractFloat64(); updateMarker = true; break;
case DataIndexes.isActiveTanker: this.#isActiveTanker = dataExtractor.extractBool(); break; case DataIndexes.isActiveTanker: this.#isActiveTanker = dataExtractor.extractBool(); break;
case DataIndexes.isActiveAWACS: this.#isActiveAWACS = dataExtractor.extractBool(); break; case DataIndexes.isActiveAWACS: this.#isActiveAWACS = dataExtractor.extractBool(); break;
@@ -247,6 +255,8 @@ export class Unit extends CustomMarker {
case DataIndexes.activePath: this.#activePath = dataExtractor.extractActivePath(); break; case DataIndexes.activePath: this.#activePath = dataExtractor.extractActivePath(); break;
case DataIndexes.isLeader: this.#isLeader = dataExtractor.extractBool(); updateMarker = true; break; case DataIndexes.isLeader: this.#isLeader = dataExtractor.extractBool(); updateMarker = true; break;
case DataIndexes.operateAs: this.#operateAs = enumToCoalition(dataExtractor.extractUInt8()); break; case DataIndexes.operateAs: this.#operateAs = enumToCoalition(dataExtractor.extractUInt8()); break;
case DataIndexes.shotsScatter: this.#shotsScatter = dataExtractor.extractUInt8(); break;
case DataIndexes.shotsIntensity: this.#shotsIntensity = dataExtractor.extractUInt8(); break;
} }
} }
@@ -286,6 +296,8 @@ export class Unit extends CustomMarker {
hasTask: this.#hasTask, hasTask: this.#hasTask,
position: this.#position, position: this.#position,
speed: this.#speed, speed: this.#speed,
horizontalVelocity: this.#horizontalVelocity,
verticalVelocity: this.#verticalVelocity,
heading: this.#heading, heading: this.#heading,
isActiveTanker: this.#isActiveTanker, isActiveTanker: this.#isActiveTanker,
isActiveAWACS: this.#isActiveAWACS, isActiveAWACS: this.#isActiveAWACS,
@@ -310,7 +322,9 @@ export class Unit extends CustomMarker {
contacts: this.#contacts, contacts: this.#contacts,
activePath: this.#activePath, activePath: this.#activePath,
isLeader: this.#isLeader, isLeader: this.#isLeader,
operateAs: this.#operateAs operateAs: this.#operateAs,
shotsScatter: this.#shotsScatter,
shotsIntensity: this.#shotsIntensity
} }
} }
@@ -338,10 +352,6 @@ export class Unit extends CustomMarker {
} }
} }
setIsProtected(isProtected:boolean) {
this.#isProtected = isProtected;
}
setAlive(newAlive: boolean) { setAlive(newAlive: boolean) {
if (newAlive != this.#alive) if (newAlive != this.#alive)
document.dispatchEvent(new CustomEvent("unitDeath", { detail: this })); document.dispatchEvent(new CustomEvent("unitDeath", { detail: this }));
@@ -437,7 +447,6 @@ export class Unit extends CustomMarker {
return this.getDatabase()?.getSpawnPointsByName(this.getName()); return this.getDatabase()?.getSpawnPointsByName(this.getName());
} }
/********************** Icon *************************/ /********************** Icon *************************/
createIcon(): void { createIcon(): void {
/* Set the icon */ /* Set the icon */
@@ -636,10 +645,6 @@ export class Unit extends CustomMarker {
return getApp().getMap().getBounds().contains(this.getPosition()); return getApp().getMap().getBounds().contains(this.getPosition());
} }
canLandAtPoint() {
return this.getCategory() === "Helicopter"; // Only choppers can do this currently
}
canTargetPoint() { canTargetPoint() {
return this.getDatabase()?.getByName(this.#name)?.canTargetPoint === true; return this.getDatabase()?.getByName(this.#name)?.canTargetPoint === true;
} }
@@ -648,6 +653,18 @@ export class Unit extends CustomMarker {
return this.getDatabase()?.getByName(this.#name)?.canRearm === true; return this.getDatabase()?.getByName(this.#name)?.canRearm === true;
} }
canLandAtPoint() {
return this.getCategory() === "Helicopter";
}
canAAA() {
return this.getDatabase()?.getByName(this.#name)?.canAAA === true;
}
indirectFire() {
return this.getDatabase()?.getByName(this.#name)?.indirectFire === true;
}
isTanker() { isTanker() {
return this.canFulfillRole("Tanker"); return this.canFulfillRole("Tanker");
} }
@@ -823,6 +840,16 @@ export class Unit extends CustomMarker {
getApp().getServerManager().landAtPoint(this.ID, latlng); getApp().getServerManager().landAtPoint(this.ID, latlng);
} }
setShotsScatter(shotsScatter: number) {
if (!this.#human)
getApp().getServerManager().setShotsScatter(this.ID, shotsScatter);
}
setShotsIntensity(shotsIntensity: number) {
if (!this.#human)
getApp().getServerManager().setShotsIntensity(this.ID, shotsIntensity);
}
/***********************************************/ /***********************************************/
getActions(): { [key: string]: { text: string, tooltip: string, type: string } } { getActions(): { [key: string]: { text: string, tooltip: string, type: string } } {
/* To be implemented by child classes */ // TODO make Unit an abstract class /* To be implemented by child classes */ // TODO make Unit an abstract class
@@ -1446,7 +1473,7 @@ export class GroundUnit extends Unit {
options["group-ground"] = { text: "Create group", tooltip: "Create a group from the selected units", type: "and" }; options["group-ground"] = { text: "Create group", tooltip: "Create a group from the selected units", type: "and" };
} }
if (["AAA", "flak"].includes(this.getType())) { if (this.canAAA()) {
options["scenic-aaa"] = { text: "Scenic AAA", tooltip: "Shoot AAA in the air without aiming at any target, when a enemy unit gets close enough. WARNING: works correctly only on neutral units, blue or red units will aim", type: "and" }; options["scenic-aaa"] = { text: "Scenic AAA", tooltip: "Shoot AAA in the air without aiming at any target, when a enemy unit gets close enough. WARNING: works correctly only on neutral units, blue or red units will aim", type: "and" };
options["miss-aaa"] = { text: "Miss on purpose AAA", tooltip: "Shoot AAA towards the closest enemy unit, but don't aim precisely. WARNING: works correctly only on neutral units, blue or red units will aim", type: "and" }; options["miss-aaa"] = { text: "Miss on purpose AAA", tooltip: "Shoot AAA towards the closest enemy unit, but don't aim precisely. WARNING: works correctly only on neutral units, blue or red units will aim", type: "and" };
} }

View File

@@ -708,6 +708,30 @@ export class UnitsManager {
this.#showActionMessage(selectedUnits, `unit landing at point`); this.#showActionMessage(selectedUnits, `unit landing at point`);
} }
/** Set a specific shots scatter to all the selected units
*
* @param shotsScatter Value to set
*/
selectedUnitsSetShotsScatter(shotsScatter: number) {
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
for (let idx in selectedUnits) {
selectedUnits[idx].setShotsScatter(shotsScatter);
}
this.#showActionMessage(selectedUnits, `shots scatter set to ${shotsScatter}`);
}
/** Set a specific shots intensity to all the selected units
*
* @param shotsScatter Value to set
*/
selectedUnitsSetShotsIntensity(shotsIntensity: number) {
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
for (let idx in selectedUnits) {
selectedUnits[idx].setShotsIntensity(shotsIntensity);
}
this.#showActionMessage(selectedUnits, `shots intensity set to ${shotsIntensity}`);
}
/*********************** Control operations on selected units ************************/ /*********************** Control operations on selected units ************************/
/** See getUnitsCategories for more info /** See getUnitsCategories for more info
* *

View File

@@ -6,11 +6,11 @@
<div class="app-version">Version <span class="app-version-number">v0.4.5-alpha</span></div> <div class="app-version">Version <span class="app-version-number">v0.4.5-alpha</span></div>
</div> </div>
<div id="authentication-form"> <form id="authentication-form">
<div><h5>Username</h5> <input type="text" id="username" name="username" required autocomplete="username" placeholder="Enter username..."></div> <div><h5>Username</h5> <input type="text" id="username" name="username" required autocomplete="username" placeholder="Enter username..."></div>
<div><h5>Password</h5> <input type="password" id="password" name="password" minlength="8" required autocomplete="current-password" placeholder="Enter password..."></div> <div><h5>Password</h5> <input type="password" id="password" name="password" minlength="8" required autocomplete="current-password" placeholder="Enter password..."></div>
<button id="connection-button" class="ol-button-apply" data-on-click="tryConnection">Connect</button> <button type="submit" id="connection-button" class="ol-button-apply">Connect</button>
</div> </form>
<h5 id="login-status"><br></h5> <h5 id="login-status"><br></h5>

View File

@@ -61,32 +61,42 @@
</div> </div>
</div> </div>
<div id="shots-scatter">
<h4>Shots scatter</h4>
<div id="shots-scatter-buttons-container" class="ol-group ol-button-box ol-option-button">
<!-- This is where the shots scatter buttons will be shown -->
</div>
</div>
<div id="shots-intensity">
<h4>Shots intensity</h4>
<div id="shots-intensity-buttons-container" class="ol-group ol-button-box ol-option-button">
<!-- This is where the shots intensity buttons will be shown -->
</div>
</div>
<div id="tanker-on" class="switch-control"> <div id="tanker-on" class="switch-control">
<h4>Enable tanker</h4> <h4>Enable tanker <img src="/resources/theme/images/icons/circle-question-regular.svg" title="Instructs the unit to operate as AAR tanker. A/A TACAN, radio frequency and callsign set in Settings dialog."></h4>
<div id="tanker-on-switch" class="ol-switch"></div> <div id="tanker-on-switch" class="ol-switch"></div>
<div>Instructs the unit to operate as AAR tanker. A/A TACAN, radio frequency and callsign set in Settings dialog.</div>
</div> </div>
<div id="AWACS-on" class="switch-control"> <div id="AWACS-on" class="switch-control">
<h4>Airborne Early Warning</h4> <h4>Airborne Early Warning <img src="/resources/theme/images/icons/circle-question-regular.svg" title="Enables datalink and AI radio calls. Radio frequency and callsign set in Settings dialog."></h4>
<div id="AWACS-on-switch" class="ol-switch"></div> <div id="AWACS-on-switch" class="ol-switch"></div>
<div>Enables datalink and AI radio calls. Radio frequency and callsign set in Settings dialog.</div>
</div> </div>
<div id="operate-as" class="switch-control"> <div id="operate-as" class="switch-control">
<h4>Operate as</h4> <h4>Operate as <img src="/resources/theme/images/icons/circle-question-regular.svg" title="Determines if the unit will target red or blue units when performing scenic tasks."></h4>
<div id="operate-as-switch" class="ol-switch"></div> <div id="operate-as-switch" class="ol-switch"></div>
<div>Determines if the unit will target red or blue units when performing scenic tasks.</div>
</div> </div>
<div id="ai-on-off" class="switch-control"> <div id="ai-on-off" class="switch-control">
<h4>Unit active</h4> <h4>Unit active <img src="/resources/theme/images/icons/circle-question-regular.svg" title="Toggling this disables unit AI completely. It will no longer move, react or emit radio waves."></h4>
<div id="on-off-switch" class="ol-switch"></div> <div id="on-off-switch" class="ol-switch" title=""></div>
<div>Toggling this disables unit AI completely. It will no longer move, react or emit radio waves.</div>
</div> </div>
<div id="follow-roads" class="switch-control"> <div id="follow-roads" class="switch-control">
<h4>Follow roads</h4> <h4>Follow roads <img src="/resources/theme/images/icons/circle-question-regular.svg" title=""></h4>
<div id="follow-roads-switch" class="ol-switch"></div> <div id="follow-roads-switch" class="ol-switch"></div>
</div> </div>

View File

@@ -269,6 +269,14 @@ function Olympus.buildTask(groupName, options)
point = {x = point.x, y = point.z}, point = {x = point.x, y = point.z},
} }
} }
-- Attack unit
elseif options['id'] == 'AttackUnit' and options['unitID'] then
task = {
id = 'AttackUnit',
params = {
unitId = options['unitID'],
}
}
end end
end end
return task return task
@@ -888,6 +896,7 @@ function Olympus.setUnitsData(arg, time)
local lat, lng, alt = coord.LOtoLL(unit:getPoint()) local lat, lng, alt = coord.LOtoLL(unit:getPoint())
local position = unit:getPosition() local position = unit:getPosition()
local heading = math.atan2( position.x.z, position.x.x ) local heading = math.atan2( position.x.z, position.x.x )
local velocity = unit:getVelocity();
-- Fill the data table -- Fill the data table
table["name"] = unit:getTypeName() table["name"] = unit:getTypeName()
@@ -896,7 +905,9 @@ function Olympus.setUnitsData(arg, time)
table["position"]["lat"] = lat table["position"]["lat"] = lat
table["position"]["lng"] = lng table["position"]["lng"] = lng
table["position"]["alt"] = alt table["position"]["alt"] = alt
table["speed"] = mist.vec.mag(unit:getVelocity()) table["speed"] = mist.vec.mag(velocity)
table["horizontalVelocity"] = math.sqrt(velocity.x * velocity.x + velocity.z * velocity.z)
table["verticalVelocity"] = velocity.y
table["heading"] = heading table["heading"] = heading
table["isAlive"] = unit:isExist() and unit:isActive() and unit:getLife() >= 1 table["isAlive"] = unit:isExist() and unit:isActive() and unit:getLife() >= 1

View File

@@ -19,6 +19,8 @@ namespace DataIndex {
hasTask, hasTask,
position, position,
speed, speed,
horizontalVelocity,
verticalVelocity,
heading, heading,
isActiveTanker, isActiveTanker,
isActiveAWACS, isActiveAWACS,
@@ -44,6 +46,8 @@ namespace DataIndex {
activePath, activePath,
isLeader, isLeader,
operateAs, operateAs,
shotsScatter,
shotsIntensity,
lastIndex, lastIndex,
endOfData = 255 endOfData = 255
}; };
@@ -73,6 +77,28 @@ namespace State
}; };
}; };
namespace ShotsScatter
{
enum ShotsScatters
{
NONE = 0,
HIGH,
MEDIUM,
LOW
};
};
namespace ShotsIntensity
{
enum ShotsIntensities
{
NONE = 0,
LOW,
MEDIUM,
HIGH
};
};
#pragma pack(push, 1) #pragma pack(push, 1)
namespace DataTypes { namespace DataTypes {
struct TACAN struct TACAN

View File

@@ -17,6 +17,8 @@ public:
virtual void setOnOff(bool newOnOff, bool force = false); virtual void setOnOff(bool newOnOff, bool force = false);
virtual void setFollowRoads(bool newFollowRoads, bool force = false); virtual void setFollowRoads(bool newFollowRoads, bool force = false);
void aimAtPoint(Coords aimTarget, double horizontalScatterMultiplier = 1, double verticalScatterMultiplier = 1);
protected: protected:
virtual void AIloop(); virtual void AIloop();
static json::value database; static json::value database;

View File

@@ -55,6 +55,8 @@ public:
bool checkTaskFailed(); bool checkTaskFailed();
void resetTaskFailedCounter(); void resetTaskFailedCounter();
void setHasTaskAssigned(bool newHasTaskAssigned); void setHasTaskAssigned(bool newHasTaskAssigned);
void setEnableTaskCheckFailed(bool newEnableTaskCheckFailed) { enableTaskFailedCheck = newEnableTaskCheckFailed; }
bool getEnableTaskCheckFailed() { return enableTaskFailedCheck; }
void triggerUpdate(unsigned char datumIndex); void triggerUpdate(unsigned char datumIndex);
@@ -73,9 +75,11 @@ public:
virtual void setGroupName(string newValue) { updateValue(groupName, newValue, DataIndex::groupName); } virtual void setGroupName(string newValue) { updateValue(groupName, newValue, DataIndex::groupName); }
virtual void setState(unsigned char newValue) { updateValue(state, newValue, DataIndex::state); }; virtual void setState(unsigned char newValue) { updateValue(state, newValue, DataIndex::state); };
virtual void setTask(string newValue) { updateValue(task, newValue, DataIndex::task); } virtual void setTask(string newValue) { updateValue(task, newValue, DataIndex::task); }
virtual void setHasTask(bool newValue) { updateValue(hasTask, newValue, DataIndex::hasTask); } virtual void setHasTask(bool newValue);
virtual void setPosition(Coords newValue) { updateValue(position, newValue, DataIndex::position); } virtual void setPosition(Coords newValue) { updateValue(position, newValue, DataIndex::position); }
virtual void setSpeed(double newValue) { updateValue(speed, newValue, DataIndex::speed); } virtual void setSpeed(double newValue) { updateValue(speed, newValue, DataIndex::speed); }
virtual void setHorizontalVelocity(double newValue) { updateValue(horizontalVelocity, newValue, DataIndex::horizontalVelocity); }
virtual void setVerticalVelocity(double newValue) { updateValue(verticalVelocity, newValue, DataIndex::verticalVelocity); }
virtual void setHeading(double newValue) { updateValue(heading, newValue, DataIndex::heading); } virtual void setHeading(double newValue) { updateValue(heading, newValue, DataIndex::heading); }
virtual void setIsActiveTanker(bool newValue); virtual void setIsActiveTanker(bool newValue);
virtual void setIsActiveAWACS(bool newValue); virtual void setIsActiveAWACS(bool newValue);
@@ -101,6 +105,8 @@ public:
virtual void setActivePath(list<Coords> newValue); virtual void setActivePath(list<Coords> newValue);
virtual void setIsLeader(bool newValue) { updateValue(isLeader, newValue, DataIndex::isLeader); } virtual void setIsLeader(bool newValue) { updateValue(isLeader, newValue, DataIndex::isLeader); }
virtual void setOperateAs(unsigned char newValue) { updateValue(operateAs, newValue, DataIndex::operateAs); } virtual void setOperateAs(unsigned char newValue) { updateValue(operateAs, newValue, DataIndex::operateAs); }
virtual void setShotsScatter(unsigned char newValue) { updateValue(shotsScatter, newValue, DataIndex::shotsScatter); }
virtual void setShotsIntensity(unsigned char newValue) { updateValue(shotsIntensity, newValue, DataIndex::shotsIntensity); }
/********** Getters **********/ /********** Getters **********/
virtual string getCategory() { return category; }; virtual string getCategory() { return category; };
@@ -117,6 +123,8 @@ public:
virtual bool getHasTask() { return hasTask; } virtual bool getHasTask() { return hasTask; }
virtual Coords getPosition() { return position; } virtual Coords getPosition() { return position; }
virtual double getSpeed() { return speed; } virtual double getSpeed() { return speed; }
virtual double getHorizontalVelocity() { return horizontalVelocity; }
virtual double getVerticalVelocity() { return verticalVelocity; }
virtual double getHeading() { return heading; } virtual double getHeading() { return heading; }
virtual bool getIsActiveTanker() { return isActiveTanker; } virtual bool getIsActiveTanker() { return isActiveTanker; }
virtual bool getIsActiveAWACS() { return isActiveAWACS; } virtual bool getIsActiveAWACS() { return isActiveAWACS; }
@@ -142,6 +150,8 @@ public:
virtual list<Coords> getActivePath() { return activePath; } virtual list<Coords> getActivePath() { return activePath; }
virtual bool getIsLeader() { return isLeader; } virtual bool getIsLeader() { return isLeader; }
virtual unsigned char getOperateAs() { return operateAs; } virtual unsigned char getOperateAs() { return operateAs; }
virtual unsigned char getShotsScatter() { return shotsScatter; }
virtual unsigned char getShotsIntensity() { return shotsIntensity; }
protected: protected:
unsigned int ID; unsigned int ID;
@@ -160,6 +170,8 @@ protected:
bool hasTask = false; bool hasTask = false;
Coords position = Coords(NULL); Coords position = Coords(NULL);
double speed = NULL; double speed = NULL;
double horizontalVelocity = NULL;
double verticalVelocity = NULL;
double heading = NULL; double heading = NULL;
bool isActiveTanker = false; bool isActiveTanker = false;
bool isActiveAWACS = false; bool isActiveAWACS = false;
@@ -186,14 +198,18 @@ protected:
bool isLeader = false; bool isLeader = false;
unsigned char operateAs = 2; unsigned char operateAs = 2;
Coords activeDestination = Coords(NULL); Coords activeDestination = Coords(NULL);
unsigned char shotsScatter = 2;
unsigned char shotsIntensity = 2;
/********** Other **********/ /********** Other **********/
unsigned int taskCheckCounter = 0; unsigned int taskCheckCounter = 0;
unsigned int internalCounter = 0; unsigned int internalCounter = 0;
Unit* missOnPurposeTarget = nullptr;
bool hasTaskAssigned = false; bool hasTaskAssigned = false;
double initialFuel = 0; double initialFuel = 0;
map<unsigned char, unsigned long long> updateTimeMap; map<unsigned char, unsigned long long> updateTimeMap;
unsigned long long lastLoopTime = 0; unsigned long long lastLoopTime = 0;
bool enableTaskFailedCheck = false;
/********** Private methods **********/ /********** Private methods **********/
virtual void AIloop() = 0; virtual void AIloop() = 0;

View File

@@ -24,6 +24,7 @@ public:
void acquireControl(unsigned int ID); void acquireControl(unsigned int ID);
void loadDatabases(); void loadDatabases();
Unit* getClosestUnit(Unit* unit, unsigned char coalition, vector<string> categories, double &distance); Unit* getClosestUnit(Unit* unit, unsigned char coalition, vector<string> categories, double &distance);
map<Unit*, double> getUnitsInRange(Unit* unit, unsigned char coalition, vector<string> categories, double range);
private: private:
map<unsigned int, Unit*> units; map<unsigned int, Unit*> units;

View File

@@ -80,15 +80,18 @@ void AirUnit::setState(unsigned char newState)
/************ Perform any action required when ENTERING a state ************/ /************ Perform any action required when ENTERING a state ************/
switch (newState) { switch (newState) {
case State::IDLE: { case State::IDLE: {
setEnableTaskCheckFailed(false);
clearActivePath(); clearActivePath();
resetActiveDestination(); resetActiveDestination();
break; break;
} }
case State::REACH_DESTINATION: { case State::REACH_DESTINATION: {
setEnableTaskCheckFailed(true);
resetActiveDestination(); resetActiveDestination();
break; break;
} }
case State::ATTACK: { case State::ATTACK: {
setEnableTaskCheckFailed(true);
if (isTargetAlive()) { if (isTargetAlive()) {
Unit* target = unitsManager->getUnit(targetID); Unit* target = unitsManager->getUnit(targetID);
Coords targetPosition = Coords(target->getPosition().lat, target->getPosition().lng, 0); Coords targetPosition = Coords(target->getPosition().lat, target->getPosition().lng, 0);
@@ -99,36 +102,43 @@ void AirUnit::setState(unsigned char newState)
break; break;
} }
case State::FOLLOW: { case State::FOLLOW: {
setEnableTaskCheckFailed(true);
clearActivePath(); clearActivePath();
resetActiveDestination(); resetActiveDestination();
break; break;
} }
case State::LAND: { case State::LAND: {
setEnableTaskCheckFailed(false);
resetActiveDestination(); resetActiveDestination();
break; break;
} }
case State::REFUEL: { case State::REFUEL: {
setEnableTaskCheckFailed(true);
initialFuel = fuel; initialFuel = fuel;
clearActivePath(); clearActivePath();
resetActiveDestination(); resetActiveDestination();
break; break;
} }
case State::BOMB_POINT: { case State::BOMB_POINT: {
setEnableTaskCheckFailed(true);
clearActivePath(); clearActivePath();
resetActiveDestination(); resetActiveDestination();
break; break;
} }
case State::CARPET_BOMB: { case State::CARPET_BOMB: {
setEnableTaskCheckFailed(true);
clearActivePath(); clearActivePath();
resetActiveDestination(); resetActiveDestination();
break; break;
} }
case State::BOMB_BUILDING: { case State::BOMB_BUILDING: {
setEnableTaskCheckFailed(true);
clearActivePath(); clearActivePath();
resetActiveDestination(); resetActiveDestination();
break; break;
} }
case State::LAND_AT_POINT: { case State::LAND_AT_POINT: {
setEnableTaskCheckFailed(true);
resetActiveDestination(); resetActiveDestination();
break; break;
} }

View File

@@ -13,6 +13,9 @@ extern Scheduler* scheduler;
extern UnitsManager* unitsManager; extern UnitsManager* unitsManager;
json::value GroundUnit::database = json::value(); json::value GroundUnit::database = json::value();
#define RANDOM_ZERO_TO_ONE (double)(rand()) / (double)(RAND_MAX)
#define RANDOM_MINUS_ONE_TO_ONE (((double)(rand()) / (double)(RAND_MAX) - 0.5) * 2)
void GroundUnit::loadDatabase(string path) { void GroundUnit::loadDatabase(string path) {
char* buf = nullptr; char* buf = nullptr;
size_t sz = 0; size_t sz = 0;
@@ -89,30 +92,36 @@ void GroundUnit::setState(unsigned char newState)
/************ Perform any action required when ENTERING a state ************/ /************ Perform any action required when ENTERING a state ************/
switch (newState) { switch (newState) {
case State::IDLE: { case State::IDLE: {
setEnableTaskCheckFailed(false);
clearActivePath(); clearActivePath();
resetActiveDestination(); resetActiveDestination();
break; break;
} }
case State::REACH_DESTINATION: { case State::REACH_DESTINATION: {
setEnableTaskCheckFailed(true);
resetActiveDestination(); resetActiveDestination();
break; break;
} }
case State::FIRE_AT_AREA: { case State::FIRE_AT_AREA: {
setEnableTaskCheckFailed(true);
clearActivePath(); clearActivePath();
resetActiveDestination(); resetActiveDestination();
break; break;
} }
case State::SIMULATE_FIRE_FIGHT: { case State::SIMULATE_FIRE_FIGHT: {
setEnableTaskCheckFailed(true);
clearActivePath(); clearActivePath();
resetActiveDestination(); resetActiveDestination();
break; break;
} }
case State::SCENIC_AAA: { case State::SCENIC_AAA: {
setEnableTaskCheckFailed(false);
clearActivePath(); clearActivePath();
resetActiveDestination(); resetActiveDestination();
break; break;
} }
case State::MISS_ON_PURPOSE: { case State::MISS_ON_PURPOSE: {
setEnableTaskCheckFailed(false);
clearActivePath(); clearActivePath();
resetActiveDestination(); resetActiveDestination();
break; break;
@@ -139,6 +148,8 @@ void GroundUnit::AIloop()
break; break;
} }
case State::REACH_DESTINATION: { case State::REACH_DESTINATION: {
setTask("Reaching destination");
string enrouteTask = ""; string enrouteTask = "";
bool looping = false; bool looping = false;
@@ -180,41 +191,12 @@ void GroundUnit::AIloop()
case State::SIMULATE_FIRE_FIGHT: { case State::SIMULATE_FIRE_FIGHT: {
setTask("Simulating fire fight"); setTask("Simulating fire fight");
if (!getHasTask() || internalCounter == 0) { if (internalCounter == 0) {
double dist; aimAtPoint(targetPosition, 3.0, 0.0);
double bearing1;
double bearing2;
Geodesic::WGS84().Inverse(position.lat, position.lng, targetPosition.lat, targetPosition.lng, dist, bearing1, bearing2);
double r = 15; /* m */
/* Default gun values */
double barrelHeight = 1.0; /* m */
double muzzleVelocity = 860; /* m/s */
if (database.has_object_field(to_wstring(name))) {
json::value databaseEntry = database[to_wstring(name)];
if (databaseEntry.has_number_field(L"barrelHeight") && databaseEntry.has_number_field(L"muzzleVelocity")) {
barrelHeight = databaseEntry[L"barrelHeight"].as_number().to_double();
muzzleVelocity = databaseEntry[L"muzzleVelocity"].as_number().to_double();
}
}
double barrelElevation = r * (9.81 * dist / (2 * muzzleVelocity * muzzleVelocity) + (targetPosition.alt - (position.alt + barrelHeight)) / dist); /* m */
double lat = 0;
double lng = 0;
double randomBearing = bearing1 + (((double)(rand()) / (double)(RAND_MAX) - 0.5) * 2) * 0; // TODO put defined constant here
Geodesic::WGS84().Direct(position.lat, position.lng, randomBearing, r, lat, lng);
std::ostringstream taskSS;
taskSS.precision(10);
taskSS << "{id = 'FireAtPoint', lat = " << lat << ", lng = " << lng << ", alt = " << position.alt + barrelElevation + barrelHeight << ", radius = 0.001}";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
} }
if (internalCounter == 0) if (internalCounter == 0)
internalCounter = 20 / 0.05; // TODO make defined constant internalCounter = 20 / FRAMERATE_TIME_INTERVAL;
internalCounter--; internalCounter--;
break; break;
@@ -247,7 +229,7 @@ void GroundUnit::AIloop()
} }
if (internalCounter == 0) if (internalCounter == 0)
internalCounter = 20 / 0.05; internalCounter = 20 / FRAMERATE_TIME_INTERVAL;
internalCounter--; internalCounter--;
break; break;
@@ -255,20 +237,32 @@ void GroundUnit::AIloop()
case State::MISS_ON_PURPOSE: { case State::MISS_ON_PURPOSE: {
setTask("Missing on purpose"); setTask("Missing on purpose");
/* Only run this when the internal counter reaches 0 to avoid excessive computations when no nearby target */ /* Check that the unit can perform AAA duties */
if (internalCounter == 0 && getOperateAs() > 0) { bool canAAA = false;
double distance = 0; if (database.has_object_field(to_wstring(name))) {
unsigned char targetCoalition = getOperateAs() == 2 ? 1 : 2; json::value databaseEntry = database[to_wstring(name)];
Unit* target = unitsManager->getClosestUnit(this, targetCoalition, {"Aircraft", "Helicopter"}, distance); if (databaseEntry.has_boolean_field(L"canAAA"))
canAAA = databaseEntry[L"canAAA"].as_bool();
}
/* Only do if we have a valid target close enough for AAA */ if (canAAA) {
if (target != nullptr && distance < 10000 /* m */) { /* Only run this when the internal counter reaches 0 to avoid excessive computations when no nearby target */
if (internalCounter == 0 && getOperateAs() > 0) {
double distance = 0;
unsigned char targetCoalition = getOperateAs() == 2 ? 1 : 2;
/* Default gun values */ /* Default gun values */
double barrelHeight = 1.0; /* m */ double barrelHeight = 1.0; /* m */
double muzzleVelocity = 860; /* m/s */ double muzzleVelocity = 860; /* m/s */
double aimTime = 10; /* s */ double aimTime = 10; /* s */
unsigned int shotsToFire = 10; unsigned int shotsToFire = 10;
double shotsBaseInterval = 15; /* s */
double shotsBaseScatter = 2; /* degs */
double engagementRange = 10000; /* m */
double targetingRange = 0; /* m */
double aimMethodRange = 0; /* m */
/* Load gun values from database */
if (database.has_object_field(to_wstring(name))) { if (database.has_object_field(to_wstring(name))) {
json::value databaseEntry = database[to_wstring(name)]; json::value databaseEntry = database[to_wstring(name)];
if (databaseEntry.has_number_field(L"barrelHeight")) if (databaseEntry.has_number_field(L"barrelHeight"))
@@ -279,45 +273,104 @@ void GroundUnit::AIloop()
aimTime = databaseEntry[L"aimTime"].as_number().to_double(); aimTime = databaseEntry[L"aimTime"].as_number().to_double();
if (databaseEntry.has_number_field(L"shotsToFire")) if (databaseEntry.has_number_field(L"shotsToFire"))
shotsToFire = databaseEntry[L"shotsToFire"].as_number().to_uint32(); shotsToFire = databaseEntry[L"shotsToFire"].as_number().to_uint32();
if (databaseEntry.has_number_field(L"engagementRange"))
engagementRange = databaseEntry[L"engagementRange"].as_number().to_double();
if (databaseEntry.has_number_field(L"shotsBaseInterval"))
shotsBaseInterval = databaseEntry[L"shotsBaseInterval"].as_number().to_double();
if (databaseEntry.has_number_field(L"shotsBaseScatter"))
shotsBaseScatter = databaseEntry[L"shotsBaseScatter"].as_number().to_double();
if (databaseEntry.has_number_field(L"targetingRange"))
targetingRange = databaseEntry[L"targetingRange"].as_number().to_double();
if (databaseEntry.has_number_field(L"aimMethodRange"))
aimMethodRange = databaseEntry[L"aimMethodRange"].as_number().to_double();
} }
/* Approximate the flight time */ /* Get all the units in range and select one at random */
if (muzzleVelocity != 0) double range = aimMethodRange > engagementRange ? aimMethodRange : engagementRange;
aimTime += distance / muzzleVelocity; map<Unit*, double> targets = unitsManager->getUnitsInRange(this, targetCoalition, { "Aircraft", "Helicopter" }, range);
Unit* target = nullptr;
unsigned int index = static_cast<unsigned int>((RANDOM_ZERO_TO_ONE * (targets.size() - 1)));
for (auto const& p : targets) {
if (index-- == 0) {
target = p.first;
distance = p.second;
}
}
internalCounter = (aimTime + 2) / 0.05; // TODO fix me you fucking monster /* Only do if we have a valid target close enough for AAA */
if (target != nullptr) {
/* Approximate the flight time */
if (muzzleVelocity != 0)
aimTime += distance / muzzleVelocity;
/* Compute where the target will be in aimTime seconds. We don't consider vertical velocity atm, since after all we are not really tring to hit */ internalCounter = (aimTime + (ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + 2) / FRAMERATE_TIME_INTERVAL;
double aimDistance = target->getSpeed() * aimTime;
double aimLat = 0;
double aimLng = 0;
Geodesic::WGS84().Direct(target->getPosition().lat, target->getPosition().lng, target->getHeading() * 57.29577, aimDistance, aimLat, aimLng); /* TODO make util function */
/* Compute distance to the aim point */ // TODO: why am I here? /* If the target is in targeting range and we are in highest precision mode, target it */
double dist; if (distance < targetingRange && shotsScatter == ShotsScatter::LOW) {
double bearing1; /* Send the command */
double bearing2; std::ostringstream taskSS;
Geodesic::WGS84().Inverse(position.lat, position.lng, aimLat, aimLng, dist, bearing1, bearing2); taskSS.precision(10);
taskSS << "{id = 'AttackUnit', unitID = " << target->getID() << " }";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
/* Else, do miss on purpose */
else {
/* Compute where the target will be in aimTime seconds. */
double aimDistance = target->getHorizontalVelocity() * aimTime;
double aimLat = 0;
double aimLng = 0;
Geodesic::WGS84().Direct(target->getPosition().lat, target->getPosition().lng, target->getHeading() * 57.29577, aimDistance, aimLat, aimLng); /* TODO make util to convert degrees and radians function */
double aimAlt = target->getPosition().alt + target->getVerticalVelocity() * aimTime;
/* Send the command */ /* Send the command */
std::ostringstream taskSS; if (distance > engagementRange) {
taskSS.precision(10); aimAtPoint(Coords(aimLat, aimLng, aimAlt));
taskSS << "{id = 'FireAtPoint', lat = " << aimLat << ", lng = " << aimLng << ", alt = " << target->getPosition().alt << ", radius = 0.001, expendQty = " << shotsToFire << " }"; }
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); })); else {
scheduler->appendCommand(command); /* Compute a random scattering depending on the distance and the selected shots scatter */
setHasTask(true); double scatterDistance = distance * tan(shotsBaseScatter * (ShotsScatter::LOW - shotsScatter) / 57.29577) * RANDOM_MINUS_ONE_TO_ONE;
double scatterAngle = 180 * RANDOM_MINUS_ONE_TO_ONE;
Geodesic::WGS84().Direct(aimLat, aimLng, scatterAngle, scatterDistance, aimLat, aimLng); /* TODO make util function */
aimAlt = aimAlt + distance * tan(shotsBaseScatter * (ShotsScatter::LOW - shotsScatter) / 57.29577) * RANDOM_MINUS_ONE_TO_ONE;
setTargetPosition(Coords(aimLat, aimLng, target->getPosition().alt)); std::ostringstream taskSS;
} taskSS.precision(10);
else { taskSS << "{id = 'FireAtPoint', lat = " << aimLat << ", lng = " << aimLng << ", alt = " << aimAlt << ", radius = 0.001, expendQty = " << shotsToFire << " }";
if (getHasTask()) Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
resetTask(); scheduler->appendCommand(command);
setHasTask(true);
}
setTargetPosition(Coords(aimLat, aimLng, target->getPosition().alt));
}
missOnPurposeTarget = target;
}
else {
if (getHasTask())
resetTask();
}
} }
}
if (internalCounter == 0) /* If no valid target was detected */
internalCounter = 5 / 0.05; if (internalCounter == 0) {
internalCounter--; double alertnessTimeConstant = 10; /* s */
if (database.has_object_field(to_wstring(name))) {
json::value databaseEntry = database[to_wstring(name)];
if (databaseEntry.has_number_field(L"alertnessTimeConstant"))
alertnessTimeConstant = databaseEntry[L"alertnessTimeConstant"].as_number().to_double();
}
internalCounter = (5 + RANDOM_ZERO_TO_ONE * alertnessTimeConstant) / FRAMERATE_TIME_INTERVAL;
missOnPurposeTarget = nullptr;
setTargetPosition(Coords(NULL));
}
internalCounter--;
}
else {
setState(State::IDLE);
}
break; break;
} }
@@ -326,6 +379,57 @@ void GroundUnit::AIloop()
} }
} }
void GroundUnit::aimAtPoint(Coords aimTarget, double horizontalScatterMultiplier, double verticalScatterMultiplier) {
double dist;
double bearing1;
double bearing2;
Geodesic::WGS84().Inverse(position.lat, position.lng, aimTarget.lat, aimTarget.lng, dist, bearing1, bearing2);
/* Aim point distance */
double r = 15; /* m */
/* Default gun values */
double barrelHeight = 1.0; /* m */
double muzzleVelocity = 860; /* m/s */
double shotsBaseScatter = 5; /* degs */
if (database.has_object_field(to_wstring(name))) {
json::value databaseEntry = database[to_wstring(name)];
if (databaseEntry.has_number_field(L"barrelHeight") && databaseEntry.has_number_field(L"muzzleVelocity")) {
barrelHeight = databaseEntry[L"barrelHeight"].as_number().to_double();
muzzleVelocity = databaseEntry[L"muzzleVelocity"].as_number().to_double();
}
if (databaseEntry.has_number_field(L"shotsBaseScatter"))
shotsBaseScatter = databaseEntry[L"shotsBaseScatter"].as_number().to_double();
}
/* Compute the elevation angle of the gun*/
double deltaHeight = (aimTarget.alt - (position.alt + barrelHeight));
double alpha = 9.81 / 2 * dist * dist / (muzzleVelocity * muzzleVelocity);
double inner = dist * dist - 4 * alpha * (alpha + deltaHeight);
/* Check we can reach the target*/
if (inner > 0) {
/* Compute elevation and bearing */
double barrelElevation = r * tan(atan((dist - sqrt(inner)) / (2 * alpha)) + RANDOM_MINUS_ONE_TO_ONE * (ShotsScatter::LOW - shotsScatter) * verticalScatterMultiplier);
double lat = 0;
double lng = 0;
double randomBearing = bearing1 + RANDOM_MINUS_ONE_TO_ONE * (ShotsScatter::LOW - shotsScatter) * horizontalScatterMultiplier;
Geodesic::WGS84().Direct(position.lat, position.lng, randomBearing, r, lat, lng);
std::ostringstream taskSS;
taskSS.precision(10);
taskSS << "{id = 'FireAtPoint', lat = " << lat << ", lng = " << lng << ", alt = " << position.alt + barrelElevation + barrelHeight << ", radius = 0.001}";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
else {
log("Target out of range for " + unitName + "(" + name + ")");
}
}
void GroundUnit::changeSpeed(string change) void GroundUnit::changeSpeed(string change)
{ {
if (change.compare("stop") == 0) if (change.compare("stop") == 0)

View File

@@ -81,21 +81,25 @@ void NavyUnit::setState(unsigned char newState)
/************ Perform any action required when ENTERING a state ************/ /************ Perform any action required when ENTERING a state ************/
switch (newState) { switch (newState) {
case State::IDLE: { case State::IDLE: {
setEnableTaskCheckFailed(false);
clearActivePath(); clearActivePath();
resetActiveDestination(); resetActiveDestination();
break; break;
} }
case State::REACH_DESTINATION: { case State::REACH_DESTINATION: {
setEnableTaskCheckFailed(true);
resetActiveDestination(); resetActiveDestination();
break; break;
} }
case State::FIRE_AT_AREA: { case State::FIRE_AT_AREA: {
setEnableTaskCheckFailed(true);
clearActivePath(); clearActivePath();
resetActiveDestination(); resetActiveDestination();
resetTask(); resetTask();
break; break;
} }
case State::SIMULATE_FIRE_FIGHT: { case State::SIMULATE_FIRE_FIGHT: {
setEnableTaskCheckFailed(true);
clearActivePath(); clearActivePath();
resetActiveDestination(); resetActiveDestination();
resetTask(); resetTask();

View File

@@ -632,6 +632,30 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
} }
} }
/************************/ /************************/
else if (key.compare("setShotsScatter") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unsigned char shotsScatter = value[L"shotsScatter"].as_number().to_uint32();
unit->setShotsScatter(shotsScatter);
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") shots scatter to " + to_string(shotsScatter), true);
}
}
/************************/
else if (key.compare("setShotsIntensity") == 0)
{
unsigned int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unsigned char shotsIntensity = value[L"shotsIntensity"].as_number().to_uint32();
unit->setShotsIntensity(shotsIntensity);
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") shots intensity to " + to_string(shotsIntensity), true);
}
}
/************************/
else if (key.compare("setCommandModeOptions") == 0) else if (key.compare("setCommandModeOptions") == 0)
{ {
setCommandModeOptions(value); setCommandModeOptions(value);

View File

@@ -69,6 +69,12 @@ void Unit::update(json::value json, double dt)
if (json.has_number_field(L"speed")) if (json.has_number_field(L"speed"))
setSpeed(json[L"speed"].as_number().to_double()); setSpeed(json[L"speed"].as_number().to_double());
if (json.has_number_field(L"horizontalVelocity"))
setHorizontalVelocity(json[L"horizontalVelocity"].as_number().to_double());
if (json.has_number_field(L"verticalVelocity"))
setVerticalVelocity(json[L"verticalVelocity"].as_number().to_double());
if (json.has_boolean_field(L"isAlive")) if (json.has_boolean_field(L"isAlive"))
setAlive(json[L"isAlive"].as_bool()); setAlive(json[L"isAlive"].as_bool());
@@ -146,7 +152,7 @@ void Unit::runAILoop() {
/* If the unit is alive, controlled, is the leader of the group and it is not a human, run the AI Loop that performs the requested commands and instructions (moving, attacking, etc) */ /* If the unit is alive, controlled, is the leader of the group and it is not a human, run the AI Loop that performs the requested commands and instructions (moving, attacking, etc) */
if (getAlive() && getControlled() && !getHuman() && getIsLeader()) { if (getAlive() && getControlled() && !getHuman() && getIsLeader()) {
if (checkTaskFailed() && state != State::IDLE && state != State::LAND) { if (getEnableTaskCheckFailed() && checkTaskFailed()) {
log(unitName + " has no task, switching to IDLE state"); log(unitName + " has no task, switching to IDLE state");
setState(State::IDLE); setState(State::IDLE);
} }
@@ -192,6 +198,8 @@ void Unit::refreshLeaderData(unsigned long long time) {
case DataIndex::generalSettings: updateValue(generalSettings, leader->generalSettings, datumIndex); break; case DataIndex::generalSettings: updateValue(generalSettings, leader->generalSettings, datumIndex); break;
case DataIndex::activePath: updateValue(activePath, leader->activePath, datumIndex); break; case DataIndex::activePath: updateValue(activePath, leader->activePath, datumIndex); break;
case DataIndex::operateAs: updateValue(operateAs, leader->operateAs, datumIndex); break; case DataIndex::operateAs: updateValue(operateAs, leader->operateAs, datumIndex); break;
case DataIndex::shotsScatter: updateValue(shotsScatter, leader->shotsScatter, datumIndex); break;
case DataIndex::shotsIntensity: updateValue(shotsIntensity, leader->shotsIntensity, datumIndex); break;
} }
} }
} }
@@ -247,9 +255,11 @@ void Unit::getData(stringstream& ss, unsigned long long time)
case DataIndex::hasTask: appendNumeric(ss, datumIndex, hasTask); break; case DataIndex::hasTask: appendNumeric(ss, datumIndex, hasTask); break;
case DataIndex::position: appendNumeric(ss, datumIndex, position); break; case DataIndex::position: appendNumeric(ss, datumIndex, position); break;
case DataIndex::speed: appendNumeric(ss, datumIndex, speed); break; case DataIndex::speed: appendNumeric(ss, datumIndex, speed); break;
case DataIndex::horizontalVelocity: appendNumeric(ss, datumIndex, horizontalVelocity); break;
case DataIndex::verticalVelocity: appendNumeric(ss, datumIndex, verticalVelocity); break;
case DataIndex::heading: appendNumeric(ss, datumIndex, heading); break; case DataIndex::heading: appendNumeric(ss, datumIndex, heading); break;
case DataIndex::isActiveTanker: appendNumeric(ss, datumIndex, isActiveTanker); break; case DataIndex::isActiveTanker: appendNumeric(ss, datumIndex, isActiveTanker); break;
case DataIndex::isActiveAWACS: appendNumeric(ss, datumIndex, isActiveAWACS); break; case DataIndex::isActiveAWACS: appendNumeric(ss, datumIndex, isActiveAWACS); break;
case DataIndex::onOff: appendNumeric(ss, datumIndex, onOff); break; case DataIndex::onOff: appendNumeric(ss, datumIndex, onOff); break;
case DataIndex::followRoads: appendNumeric(ss, datumIndex, followRoads); break; case DataIndex::followRoads: appendNumeric(ss, datumIndex, followRoads); break;
case DataIndex::fuel: appendNumeric(ss, datumIndex, fuel); break; case DataIndex::fuel: appendNumeric(ss, datumIndex, fuel); break;
@@ -272,6 +282,8 @@ void Unit::getData(stringstream& ss, unsigned long long time)
case DataIndex::activePath: appendList(ss, datumIndex, activePath); break; case DataIndex::activePath: appendList(ss, datumIndex, activePath); break;
case DataIndex::isLeader: appendNumeric(ss, datumIndex, isLeader); break; case DataIndex::isLeader: appendNumeric(ss, datumIndex, isLeader); break;
case DataIndex::operateAs: appendNumeric(ss, datumIndex, operateAs); break; case DataIndex::operateAs: appendNumeric(ss, datumIndex, operateAs); break;
case DataIndex::shotsScatter: appendNumeric(ss, datumIndex, shotsScatter); break;
case DataIndex::shotsIntensity: appendNumeric(ss, datumIndex, shotsIntensity); break;
} }
} }
} }
@@ -730,6 +742,10 @@ bool Unit::updateActivePath(bool looping)
} }
} }
void Unit::setHasTask(bool newValue) {
updateValue(hasTask, newValue, DataIndex::hasTask);
}
bool Unit::checkTaskFailed() bool Unit::checkTaskFailed()
{ {
if (getHasTask()) if (getHasTask())

View File

@@ -172,19 +172,20 @@ Unit* UnitsManager::getClosestUnit(Unit* unit, unsigned char coalition, vector<s
double bearing1; double bearing1;
double bearing2; double bearing2;
Geodesic::WGS84().Inverse(unit->getPosition().lat, unit->getPosition().lng, p.second->getPosition().lat, p.second->getPosition().lng, dist, bearing1, bearing2); Geodesic::WGS84().Inverse(unit->getPosition().lat, unit->getPosition().lng, p.second->getPosition().lat, p.second->getPosition().lng, dist, bearing1, bearing2);
double altDelta = unit->getPosition().alt - p.second->getPosition().alt;
/* If the closest unit has not been assigned yet, assign it to this unit */ /* If the closest unit has not been assigned yet, assign it to this unit */
if (closestUnit == nullptr) if (closestUnit == nullptr)
{ {
closestUnit = p.second; closestUnit = p.second;
distance = dist; distance = sqrt(dist * dist + altDelta * altDelta);
} }
else { else {
/* Check if the unit is closer than the one already selected */ /* Check if the unit is closer than the one already selected */
if (dist < distance) { if (dist < distance) {
closestUnit = p.second; closestUnit = p.second;
distance = dist; distance = sqrt(dist * dist + altDelta * altDelta);
} }
} }
} }
@@ -193,6 +194,35 @@ Unit* UnitsManager::getClosestUnit(Unit* unit, unsigned char coalition, vector<s
return closestUnit; return closestUnit;
} }
map<Unit*, double> UnitsManager::getUnitsInRange(Unit* unit, unsigned char coalition, vector<string> categories, double range) {
map<Unit*, double> unitsInRange;
for (auto const& p : units) {
/* Check if the units category is of the correct type */
bool requestedCategory = false;
for (auto const& category : categories) {
if (p.second->getCategory().compare(category) == 0) {
requestedCategory = true;
break;
}
}
/* Check if the unit belongs to the desired coalition, is alive, and is of the category requested */
if (requestedCategory && p.second->getCoalition() == coalition && p.second->getAlive()) {
/* Compute the distance from the unit to the tested unit */
double dist;
double bearing1;
double bearing2;
Geodesic::WGS84().Inverse(unit->getPosition().lat, unit->getPosition().lng, p.second->getPosition().lat, p.second->getPosition().lng, dist, bearing1, bearing2);
if (dist <= range)
unitsInRange[p.second] = dist;
}
}
return unitsInRange;
}
void UnitsManager::acquireControl(unsigned int ID) { void UnitsManager::acquireControl(unsigned int ID) {
Unit* leader = getGroupLeader(ID); Unit* leader = getGroupLeader(ID);
if (leader != nullptr) { if (leader != nullptr) {