Merge branch 'main' into 499-spawn-menu-reorganisation
159
client/@types/olympus/index.d.ts
vendored
@ -83,6 +83,7 @@ declare module "controls/switch" {
|
||||
}
|
||||
declare module "constants/constants" {
|
||||
import { LatLng, LatLngBounds } from "leaflet";
|
||||
import { MapMarkerControl } from "map/map";
|
||||
export const UNITS_URI = "units";
|
||||
export const WEAPONS_URI = "weapons";
|
||||
export const LOGS_URI = "logs";
|
||||
@ -107,6 +108,8 @@ declare module "constants/constants" {
|
||||
export const ROEDescriptions: string[];
|
||||
export const reactionsToThreatDescriptions: string[];
|
||||
export const emissionsCountermeasuresDescriptions: string[];
|
||||
export const shotsScatterDescriptions: string[];
|
||||
export const shotsIntensityDescriptions: string[];
|
||||
export const minSpeedValues: {
|
||||
[key: string]: number;
|
||||
};
|
||||
@ -192,6 +195,7 @@ declare module "constants/constants" {
|
||||
export const visibilityControls: string[];
|
||||
export const visibilityControlsTypes: string[][];
|
||||
export const visibilityControlsTooltips: string[];
|
||||
export const MAP_MARKER_CONTROLS: MapMarkerControl[];
|
||||
export const IADSTypes: string[];
|
||||
export const IADSDensities: {
|
||||
[key: string]: number;
|
||||
@ -221,31 +225,35 @@ declare module "constants/constants" {
|
||||
hasTask = 12,
|
||||
position = 13,
|
||||
speed = 14,
|
||||
heading = 15,
|
||||
isActiveTanker = 16,
|
||||
isActiveAWACS = 17,
|
||||
onOff = 18,
|
||||
followRoads = 19,
|
||||
fuel = 20,
|
||||
desiredSpeed = 21,
|
||||
desiredSpeedType = 22,
|
||||
desiredAltitude = 23,
|
||||
desiredAltitudeType = 24,
|
||||
leaderID = 25,
|
||||
formationOffset = 26,
|
||||
targetID = 27,
|
||||
targetPosition = 28,
|
||||
ROE = 29,
|
||||
reactionToThreat = 30,
|
||||
emissionsCountermeasures = 31,
|
||||
TACAN = 32,
|
||||
radio = 33,
|
||||
generalSettings = 34,
|
||||
ammo = 35,
|
||||
contacts = 36,
|
||||
activePath = 37,
|
||||
isLeader = 38,
|
||||
operateAs = 39,
|
||||
horizontalVelocity = 15,
|
||||
verticalVelocity = 16,
|
||||
heading = 17,
|
||||
isActiveTanker = 18,
|
||||
isActiveAWACS = 19,
|
||||
onOff = 20,
|
||||
followRoads = 21,
|
||||
fuel = 22,
|
||||
desiredSpeed = 23,
|
||||
desiredSpeedType = 24,
|
||||
desiredAltitude = 25,
|
||||
desiredAltitudeType = 26,
|
||||
leaderID = 27,
|
||||
formationOffset = 28,
|
||||
targetID = 29,
|
||||
targetPosition = 30,
|
||||
ROE = 31,
|
||||
reactionToThreat = 32,
|
||||
emissionsCountermeasures = 33,
|
||||
TACAN = 34,
|
||||
radio = 35,
|
||||
generalSettings = 36,
|
||||
ammo = 37,
|
||||
contacts = 38,
|
||||
activePath = 39,
|
||||
isLeader = 40,
|
||||
operateAs = 41,
|
||||
shotsScatter = 42,
|
||||
shotsIntensity = 43,
|
||||
endOfData = 255
|
||||
}
|
||||
export const MGRS_PRECISION_10KM = 2;
|
||||
@ -253,6 +261,8 @@ declare module "constants/constants" {
|
||||
export const MGRS_PRECISION_100M = 4;
|
||||
export const MGRS_PRECISION_10M = 5;
|
||||
export const MGRS_PRECISION_1M = 6;
|
||||
export const DELETE_CYCLE_TIME = 0.05;
|
||||
export const DELETE_SLOW_THRESHOLD = 50;
|
||||
}
|
||||
declare module "map/markers/custommarker" {
|
||||
import { Map, Marker } from "leaflet";
|
||||
@ -303,7 +313,7 @@ declare module "controls/dropdown" {
|
||||
#private;
|
||||
constructor(ID: string | null, callback: CallableFunction, options?: string[] | null, defaultText?: string);
|
||||
getContainer(): HTMLElement;
|
||||
setOptions(optionsList: string[], sortAlphabetically?: boolean): void;
|
||||
setOptions(optionsList: string[], sort?: "" | "string" | "number"): void;
|
||||
setOptionsElements(optionsElements: HTMLElement[]): void;
|
||||
getOptionElements(): HTMLCollection;
|
||||
addOptionElement(optionElement: HTMLElement): void;
|
||||
@ -498,6 +508,8 @@ declare module "interfaces" {
|
||||
hasTask: boolean;
|
||||
position: LatLng;
|
||||
speed: number;
|
||||
horizontalVelocity: number;
|
||||
verticalVelocity: number;
|
||||
heading: number;
|
||||
isActiveTanker: boolean;
|
||||
isActiveAWACS: boolean;
|
||||
@ -523,6 +535,8 @@ declare module "interfaces" {
|
||||
activePath: LatLng[];
|
||||
isLeader: boolean;
|
||||
operateAs: string;
|
||||
shotsScatter: number;
|
||||
shotsIntensity: number;
|
||||
}
|
||||
export interface LoadoutItemBlueprint {
|
||||
name: string;
|
||||
@ -558,12 +572,19 @@ declare module "interfaces" {
|
||||
muzzleVelocity?: number;
|
||||
aimTime?: number;
|
||||
shotsToFire?: number;
|
||||
shotsBaseInterval?: number;
|
||||
shotsBaseScatter?: number;
|
||||
description?: string;
|
||||
abilities?: string;
|
||||
acquisitionRange?: number;
|
||||
engagementRange?: number;
|
||||
targetingRange?: number;
|
||||
aimMethodRange?: number;
|
||||
alertnessTimeConstant?: number;
|
||||
canTargetPoint?: boolean;
|
||||
canRearm?: boolean;
|
||||
canAAA?: boolean;
|
||||
indirectFire?: boolean;
|
||||
}
|
||||
export interface UnitSpawnOptions {
|
||||
roleType: string;
|
||||
@ -604,6 +625,7 @@ declare module "interfaces" {
|
||||
export interface ShortcutOptions {
|
||||
altKey?: boolean;
|
||||
callback: CallableFunction;
|
||||
context?: string;
|
||||
ctrlKey?: boolean;
|
||||
name?: string;
|
||||
shiftKey?: boolean;
|
||||
@ -786,9 +808,11 @@ declare module "controls/unitspawnmenu" {
|
||||
import { UnitSpawnOptions } from "interfaces";
|
||||
export class UnitSpawnMenu {
|
||||
#private;
|
||||
spawnOptions: UnitSpawnOptions;
|
||||
protected showRangeCircles: boolean;
|
||||
protected spawnOptions: UnitSpawnOptions;
|
||||
constructor(ID: string, unitDatabase: UnitDatabase, orderByRole: boolean);
|
||||
getContainer(): HTMLElement;
|
||||
getVisible(): boolean;
|
||||
reset(): void;
|
||||
setCountries(): void;
|
||||
refreshOptions(): void;
|
||||
@ -824,6 +848,7 @@ declare module "controls/unitspawnmenu" {
|
||||
deployUnits(spawnOptions: UnitSpawnOptions, unitsCount: number): void;
|
||||
}
|
||||
export class GroundUnitSpawnMenu extends UnitSpawnMenu {
|
||||
protected showRangeCircles: boolean;
|
||||
/**
|
||||
*
|
||||
* @param ID - the ID of the HTML element which will contain the context menu
|
||||
@ -1036,6 +1061,8 @@ declare module "unit/unit" {
|
||||
getHasTask(): boolean;
|
||||
getPosition(): LatLng;
|
||||
getSpeed(): number;
|
||||
getHorizontalVelocity(): number;
|
||||
getVerticalVelocity(): number;
|
||||
getHeading(): number;
|
||||
getIsActiveTanker(): boolean;
|
||||
getIsActiveAWACS(): boolean;
|
||||
@ -1061,6 +1088,8 @@ declare module "unit/unit" {
|
||||
getActivePath(): LatLng[];
|
||||
getIsLeader(): boolean;
|
||||
getOperateAs(): string;
|
||||
getShotsScatter(): number;
|
||||
getShotsIntensity(): number;
|
||||
static getConstructor(type: string): typeof GroundUnit | undefined;
|
||||
constructor(ID: number);
|
||||
getCategory(): string;
|
||||
@ -1097,6 +1126,9 @@ declare module "unit/unit" {
|
||||
isInViewport(): boolean;
|
||||
canTargetPoint(): boolean;
|
||||
canRearm(): boolean;
|
||||
canLandAtPoint(): boolean;
|
||||
canAAA(): boolean;
|
||||
indirectFire(): boolean;
|
||||
isTanker(): boolean;
|
||||
isAWACS(): boolean;
|
||||
/********************** Unit commands *************************/
|
||||
@ -1132,6 +1164,8 @@ declare module "unit/unit" {
|
||||
scenicAAA(): void;
|
||||
missOnPurpose(): void;
|
||||
landAtPoint(latlng: LatLng): void;
|
||||
setShotsScatter(shotsScatter: number): void;
|
||||
setShotsIntensity(shotsIntensity: number): void;
|
||||
/***********************************************/
|
||||
getActions(): {
|
||||
[key: string]: {
|
||||
@ -1331,6 +1365,20 @@ declare module "contextmenus/airbasespawnmenu" {
|
||||
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" {
|
||||
export class Manager {
|
||||
#private;
|
||||
@ -1406,6 +1454,14 @@ declare module "map/map" {
|
||||
import { CoalitionArea } from "map/coalitionarea/coalitionarea";
|
||||
import { CoalitionAreaContextMenu } from "contextmenus/coalitionareacontextmenu";
|
||||
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 {
|
||||
#private;
|
||||
/**
|
||||
@ -1453,6 +1509,7 @@ declare module "map/map" {
|
||||
getVisibilityOptions(): {
|
||||
[key: string]: boolean;
|
||||
};
|
||||
unitIsProtected(unit: Unit): boolean;
|
||||
}
|
||||
}
|
||||
declare module "mission/bullseye" {
|
||||
@ -1569,6 +1626,7 @@ declare module "panels/unitinfopanel" {
|
||||
export class UnitInfoPanel extends Panel {
|
||||
#private;
|
||||
constructor(ID: string);
|
||||
show(): void;
|
||||
}
|
||||
}
|
||||
declare module "plugin/pluginmanager" {
|
||||
@ -1647,6 +1705,14 @@ declare module "unit/citiesDatabase" {
|
||||
pop: number;
|
||||
}[];
|
||||
}
|
||||
declare module "dialog/dialog" {
|
||||
import { Panel } from "panels/panel";
|
||||
export class Dialog extends Panel {
|
||||
constructor(element: string);
|
||||
hide(): void;
|
||||
show(): void;
|
||||
}
|
||||
}
|
||||
declare module "unit/unitsmanager" {
|
||||
import { LatLng, LatLngBounds } from "leaflet";
|
||||
import { Unit } from "unit/unit";
|
||||
@ -1713,7 +1779,9 @@ declare module "unit/unitsmanager" {
|
||||
*/
|
||||
getSelectedUnits(options?: {
|
||||
excludeHumans?: boolean;
|
||||
excludeProtected?: boolean;
|
||||
onlyOnePerGroup?: boolean;
|
||||
showProtectionReminder?: boolean;
|
||||
}): Unit[];
|
||||
/** Deselects all currently selected units
|
||||
*
|
||||
@ -1876,6 +1944,16 @@ declare module "unit/unitsmanager" {
|
||||
* @param latlng Point where to land
|
||||
*/
|
||||
selectedUnitsLandAtPoint(latlng: LatLng): void;
|
||||
/** Set a specific shots scatter to all the selected units
|
||||
*
|
||||
* @param shotsScatter Value to set
|
||||
*/
|
||||
selectedUnitsSetShotsScatter(shotsScatter: number): void;
|
||||
/** Set a specific shots intensity to all the selected units
|
||||
*
|
||||
* @param shotsScatter Value to set
|
||||
*/
|
||||
selectedUnitsSetShotsIntensity(shotsIntensity: number): void;
|
||||
/*********************** Control operations on selected units ************************/
|
||||
/** See getUnitsCategories for more info
|
||||
*
|
||||
@ -2066,6 +2144,8 @@ declare module "server/servermanager" {
|
||||
scenicAAA(ID: number, coalition: string, callback?: CallableFunction): void;
|
||||
missOnPurpose(ID: number, coalition: string, callback?: CallableFunction): void;
|
||||
landAtPoint(ID: number, latlng: LatLng, callback?: CallableFunction): void;
|
||||
setShotsScatter(ID: number, shotsScatter: number, callback?: CallableFunction): void;
|
||||
setShotsIntensity(ID: number, shotsIntensity: number, callback?: CallableFunction): void;
|
||||
setAdvacedOptions(ID: number, isActiveTanker: boolean, isActiveAWACS: boolean, TACAN: TACAN, radio: Radio, generalSettings: GeneralSettings, callback?: CallableFunction): void;
|
||||
setCommandModeOptions(restrictSpawns: boolean, restrictToCoalition: boolean, spawnPoints: {
|
||||
blue: number;
|
||||
@ -2094,6 +2174,18 @@ declare module "panels/unitlistpanel" {
|
||||
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" {
|
||||
import { Map } from "map/map";
|
||||
import { MissionManager } from "mission/missionmanager";
|
||||
@ -2103,10 +2195,15 @@ declare module "olympusapp" {
|
||||
import { WeaponsManager } from "weapon/weaponsmanager";
|
||||
import { Manager } from "other/manager";
|
||||
import { ServerManager } from "server/servermanager";
|
||||
import { ContextManager } from "context/contextmanager";
|
||||
import { Context } from "context/context";
|
||||
export class OlympusApp {
|
||||
#private;
|
||||
constructor();
|
||||
getDialogManager(): Manager;
|
||||
getMap(): Map;
|
||||
getCurrentContext(): Context;
|
||||
getContextManager(): ContextManager;
|
||||
getServerManager(): ServerManager;
|
||||
getPanelsManager(): Manager;
|
||||
getPopupsManager(): Manager;
|
||||
@ -2158,3 +2255,11 @@ declare module "index" {
|
||||
import { OlympusApp } from "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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ var enc = new TextEncoder();
|
||||
|
||||
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!",
|
||||
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,
|
||||
formationOffset: { x: 0, y: 0, z: 0 },
|
||||
targetID: 0,
|
||||
@ -20,7 +20,7 @@ const DEMO_UNIT_DATA = {
|
||||
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",
|
||||
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,
|
||||
formationOffset: { x: 0, y: 0, z: 0 },
|
||||
targetID: 0,
|
||||
@ -34,8 +34,8 @@ const DEMO_UNIT_DATA = {
|
||||
ammo: [{ quantity: 2, name: "A cool missile", guidance: 0, category: 0, missileCategory: 0 } ],
|
||||
contacts: [{ID: 4, detectionMethod: 1}],
|
||||
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",
|
||||
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,
|
||||
}, ["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, 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,
|
||||
formationOffset: { x: 0, y: 0, z: 0 },
|
||||
targetID: 0,
|
||||
@ -50,7 +50,7 @@ const DEMO_UNIT_DATA = {
|
||||
contacts: [{ID: 1, detectionMethod: 16}],
|
||||
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",
|
||||
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,
|
||||
formationOffset: { x: 0, y: 0, z: 0 },
|
||||
targetID: 0,
|
||||
@ -67,7 +67,7 @@ const DEMO_UNIT_DATA = {
|
||||
isLeader: true,
|
||||
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",
|
||||
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,
|
||||
formationOffset: { x: 0, y: 0, z: 0 },
|
||||
targetID: 0,
|
||||
@ -85,7 +85,7 @@ const DEMO_UNIT_DATA = {
|
||||
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",
|
||||
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,
|
||||
formationOffset: { x: 0, y: 0, z: 0 },
|
||||
targetID: 0,
|
||||
@ -100,7 +100,7 @@ const DEMO_UNIT_DATA = {
|
||||
contacts: [{ID: 1, detectionMethod: 16}],
|
||||
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",
|
||||
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,
|
||||
formationOffset: { x: 0, y: 0, z: 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();
|
||||
}
|
||||
@ -187,31 +167,33 @@ class DemoDataGenerator {
|
||||
array = this.appendUint8(array, unit.hasTask, 12);
|
||||
array = this.appendCoordinates(array, unit.position, 13);
|
||||
array = this.appendDouble(array, unit.speed, 14);
|
||||
array = this.appendDouble(array, unit.heading, 15);
|
||||
array = this.appendUint8(array, unit.isActiveTanker, 16);
|
||||
array = this.appendUint8(array, unit.isActiveAWACS, 17);
|
||||
array = this.appendUint8(array, unit.onOff, 18);
|
||||
array = this.appendUint8(array, unit.followRoads, 19);
|
||||
array = this.appendUint16(array, unit.fuel, 20);
|
||||
array = this.appendDouble(array, unit.desiredSpeed, 21);
|
||||
array = this.appendUint8(array, unit.desiredSpeedType, 22);
|
||||
array = this.appendDouble(array, unit.desiredAltitude, 23);
|
||||
array = this.appendUint8(array, unit.desiredAltitudeType, 24);
|
||||
array = this.appendUint32(array, unit.leaderID, 25);
|
||||
array = this.appendOffset(array, unit.formationOffset, 26);
|
||||
array = this.appendUint32(array, unit.targetID, 27);
|
||||
array = this.appendCoordinates(array, unit.targetPosition, 28);
|
||||
array = this.appendUint8(array, unit.ROE, 29);
|
||||
array = this.appendUint8(array, unit.reactionToThreat, 30);
|
||||
array = this.appendUint8(array, unit.emissionsCountermeasures, 31);
|
||||
array = this.appendTACAN(array, unit.TACAN, 32);
|
||||
array = this.appendRadio(array, unit.radio, 33);
|
||||
array = this.appendRadio(array, unit.generalSettings, 34);
|
||||
array = this.appendAmmo(array, unit.ammo, 35);
|
||||
array = this.appendContacts(array, unit.contacts, 36);
|
||||
array = this.appendActivePath(array, unit.activePath, 37);
|
||||
array = this.appendUint8(array, unit.isLeader, 38);
|
||||
array = this.appendUint8(array, unit.operateAs, 39);
|
||||
array = this.appendDouble(array, unit.horizontalVelocity, 15);
|
||||
array = this.appendDouble(array, unit.verticalVelicity, 16);
|
||||
array = this.appendDouble(array, unit.heading, 17);
|
||||
array = this.appendUint8(array, unit.isActiveTanker, 18);
|
||||
array = this.appendUint8(array, unit.isActiveAWACS, 19);
|
||||
array = this.appendUint8(array, unit.onOff, 20);
|
||||
array = this.appendUint8(array, unit.followRoads, 21);
|
||||
array = this.appendUint16(array, unit.fuel, 22);
|
||||
array = this.appendDouble(array, unit.desiredSpeed, 23);
|
||||
array = this.appendUint8(array, unit.desiredSpeedType, 24);
|
||||
array = this.appendDouble(array, unit.desiredAltitude, 25);
|
||||
array = this.appendUint8(array, unit.desiredAltitudeType, 26);
|
||||
array = this.appendUint32(array, unit.leaderID, 27);
|
||||
array = this.appendOffset(array, unit.formationOffset, 28);
|
||||
array = this.appendUint32(array, unit.targetID, 29);
|
||||
array = this.appendCoordinates(array, unit.targetPosition, 30);
|
||||
array = this.appendUint8(array, unit.ROE, 31);
|
||||
array = this.appendUint8(array, unit.reactionToThreat, 32);
|
||||
array = this.appendUint8(array, unit.emissionsCountermeasures, 33);
|
||||
array = this.appendTACAN(array, unit.TACAN, 34);
|
||||
array = this.appendRadio(array, unit.radio, 35);
|
||||
array = this.appendRadio(array, unit.generalSettings, 36);
|
||||
array = this.appendAmmo(array, unit.ammo, 37);
|
||||
array = this.appendContacts(array, unit.contacts, 38);
|
||||
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));
|
||||
}
|
||||
res.end(Buffer.from(array, 'binary'));
|
||||
|
||||
@ -508,7 +508,7 @@ class GroundUnitEditor extends uniteditor_1.UnitEditor {
|
||||
* @param blueprint The blueprint to edit
|
||||
*/
|
||||
setBlueprint(blueprint) {
|
||||
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
||||
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
||||
__classPrivateFieldSet(this, _GroundUnitEditor_blueprint, blueprint, "f");
|
||||
if (__classPrivateFieldGet(this, _GroundUnitEditor_blueprint, "f") !== null) {
|
||||
this.contentDiv2.replaceChildren();
|
||||
@ -525,14 +525,19 @@ class GroundUnitEditor extends uniteditor_1.UnitEditor {
|
||||
(0, utils_1.addStringInput)(this.contentDiv2, "Cost", (_b = String(blueprint.cost)) !== null && _b !== void 0 ? _b : "", "number", (value) => { blueprint.cost = parseFloat(value); });
|
||||
(0, utils_1.addStringInput)(this.contentDiv2, "Acquisition range [m]", (_c = String(blueprint.acquisitionRange)) !== null && _c !== void 0 ? _c : "", "number", (value) => { blueprint.acquisitionRange = parseFloat(value); });
|
||||
(0, utils_1.addStringInput)(this.contentDiv2, "Engagement range [m]", (_d = String(blueprint.engagementRange)) !== null && _d !== void 0 ? _d : "", "number", (value) => { blueprint.engagementRange = parseFloat(value); });
|
||||
(0, utils_1.addStringInput)(this.contentDiv2, "Barrel height [m]", (_e = String(blueprint.barrelHeight)) !== null && _e !== void 0 ? _e : "", "number", (value) => { blueprint.barrelHeight = parseFloat(value); });
|
||||
(0, utils_1.addStringInput)(this.contentDiv2, "Muzzle velocity [m/s]", (_f = String(blueprint.muzzleVelocity)) !== null && _f !== void 0 ? _f : "", "number", (value) => { blueprint.muzzleVelocity = parseFloat(value); });
|
||||
(0, utils_1.addStringInput)(this.contentDiv2, "Aim time [s]", (_g = String(blueprint.aimTime)) !== null && _g !== void 0 ? _g : "", "number", (value) => { blueprint.aimTime = parseFloat(value); });
|
||||
(0, utils_1.addStringInput)(this.contentDiv2, "Burst quantity", (_h = String(blueprint.shotsToFire)) !== null && _h !== void 0 ? _h : "", "number", (value) => { blueprint.shotsToFire = Math.round(parseFloat(value)); });
|
||||
(0, utils_1.addCheckboxInput)(this.contentDiv2, "Can target point", (_j = blueprint.canTargetPoint) !== null && _j !== void 0 ? _j : false, (value) => { blueprint.canTargetPoint = value; });
|
||||
(0, utils_1.addCheckboxInput)(this.contentDiv2, "Can rearm", (_k = blueprint.canRearm) !== null && _k !== void 0 ? _k : false, (value) => { blueprint.canRearm = value; });
|
||||
(0, utils_1.addStringInput)(this.contentDiv2, "Description", (_l = blueprint.description) !== null && _l !== void 0 ? _l : "", "text", (value) => { blueprint.description = value; });
|
||||
(0, utils_1.addStringInput)(this.contentDiv2, "Abilities", (_m = blueprint.abilities) !== null && _m !== void 0 ? _m : "", "text", (value) => { blueprint.abilities = value; });
|
||||
(0, utils_1.addStringInput)(this.contentDiv2, "Targeting range [m]", (_e = String(blueprint.targetingRange)) !== null && _e !== void 0 ? _e : "", "number", (value) => { blueprint.targetingRange = parseFloat(value); });
|
||||
(0, utils_1.addStringInput)(this.contentDiv2, "Barrel height [m]", (_f = String(blueprint.barrelHeight)) !== null && _f !== void 0 ? _f : "", "number", (value) => { blueprint.barrelHeight = parseFloat(value); });
|
||||
(0, utils_1.addStringInput)(this.contentDiv2, "Muzzle velocity [m/s]", (_g = String(blueprint.muzzleVelocity)) !== null && _g !== void 0 ? _g : "", "number", (value) => { blueprint.muzzleVelocity = parseFloat(value); });
|
||||
(0, utils_1.addStringInput)(this.contentDiv2, "Aim time [s]", (_h = String(blueprint.aimTime)) !== null && _h !== void 0 ? _h : "", "number", (value) => { blueprint.aimTime = parseFloat(value); });
|
||||
(0, utils_1.addStringInput)(this.contentDiv2, "Burst quantity", (_j = String(blueprint.shotsToFire)) !== null && _j !== void 0 ? _j : "", "number", (value) => { blueprint.shotsToFire = Math.round(parseFloat(value)); });
|
||||
(0, utils_1.addStringInput)(this.contentDiv2, "Burst base interval [s]", (_k = String(blueprint.shotsBaseInterval)) !== null && _k !== void 0 ? _k : "", "number", (value) => { blueprint.shotsBaseInterval = Math.round(parseFloat(value)); });
|
||||
(0, utils_1.addStringInput)(this.contentDiv2, "Base scatter [°]", (_l = String(blueprint.shotsBaseScatter)) !== null && _l !== void 0 ? _l : "", "number", (value) => { blueprint.shotsBaseScatter = Math.round(parseFloat(value)); });
|
||||
(0, utils_1.addCheckboxInput)(this.contentDiv2, "Can target point", (_m = blueprint.canTargetPoint) !== null && _m !== void 0 ? _m : false, (value) => { blueprint.canTargetPoint = value; });
|
||||
(0, utils_1.addCheckboxInput)(this.contentDiv2, "Can rearm", (_o = blueprint.canRearm) !== null && _o !== void 0 ? _o : false, (value) => { blueprint.canRearm = value; });
|
||||
(0, utils_1.addCheckboxInput)(this.contentDiv2, "Can operate as AAA", (_p = blueprint.canAAA) !== null && _p !== void 0 ? _p : false, (value) => { blueprint.canAAA = value; });
|
||||
(0, utils_1.addCheckboxInput)(this.contentDiv2, "Indirect fire (e.g. mortar)", (_q = blueprint.indirectFire) !== null && _q !== void 0 ? _q : false, (value) => { blueprint.indirectFire = value; });
|
||||
(0, utils_1.addStringInput)(this.contentDiv2, "Description", (_r = blueprint.description) !== null && _r !== void 0 ? _r : "", "text", (value) => { blueprint.description = value; });
|
||||
(0, utils_1.addStringInput)(this.contentDiv2, "Abilities", (_s = blueprint.abilities) !== null && _s !== void 0 ? _s : "", "text", (value) => { blueprint.abilities = value; });
|
||||
}
|
||||
}
|
||||
/** Add a new empty blueprint
|
||||
|
||||
@ -86,7 +86,7 @@ export class DatabaseManagerPlugin implements OlympusPlugin {
|
||||
/* Create the container for the database editor elements and the elements themselves */
|
||||
this.#mainContentContainer = document.createElement("div");
|
||||
this.#mainContentContainer.classList.add("dm-container");
|
||||
this.#element.appendChild(this.#mainContentContainer)
|
||||
this.#element.appendChild(this.#mainContentContainer);
|
||||
|
||||
this.#contentDiv1 = document.createElement("div");
|
||||
this.#contentDiv1.classList.add("dm-content-container");
|
||||
|
||||
@ -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, "Acquisition range [m]", String(blueprint.acquisitionRange)?? "", "number", (value: string) => {blueprint.acquisitionRange = parseFloat(value); });
|
||||
addStringInput(this.contentDiv2, "Engagement range [m]", String(blueprint.engagementRange)?? "", "number", (value: string) => {blueprint.engagementRange = parseFloat(value); });
|
||||
addStringInput(this.contentDiv2, "Targeting range [m]", String(blueprint.targetingRange)?? "", "number", (value: string) => {blueprint.targetingRange = parseFloat(value); });
|
||||
addStringInput(this.contentDiv2, "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, "Muzzle velocity [m/s]", String(blueprint.muzzleVelocity)?? "", "number", (value: string) => {blueprint.muzzleVelocity = parseFloat(value); });
|
||||
addStringInput(this.contentDiv2, "Aim time [s]", String(blueprint.aimTime)?? "", "number", (value: string) => {blueprint.aimTime = parseFloat(value); });
|
||||
addStringInput(this.contentDiv2, "Burst quantity", String(blueprint.shotsToFire)?? "", "number", (value: string) => {blueprint.shotsToFire = Math.round(parseFloat(value)); });
|
||||
addStringInput(this.contentDiv2, "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 rearm", blueprint.canRearm ?? false, (value: boolean) => {blueprint.canRearm = value;})
|
||||
addCheckboxInput(this.contentDiv2, "Can operate as AAA", blueprint.canAAA ?? false, (value: boolean) => {blueprint.canAAA = value;})
|
||||
addCheckboxInput(this.contentDiv2, "Indirect fire (e.g. mortar)", blueprint.indirectFire ?? false, (value: boolean) => {blueprint.indirectFire = value;})
|
||||
addStringInput(this.contentDiv2, "Description", blueprint.description ?? "", "text", (value: string) => {blueprint.description = value; });
|
||||
addStringInput(this.contentDiv2, "Abilities", blueprint.abilities ?? "", "text", (value: string) => {blueprint.abilities = value; });
|
||||
}
|
||||
|
||||
@ -49,9 +49,9 @@ export abstract class UnitEditor {
|
||||
}
|
||||
|
||||
/** Show the editor
|
||||
*
|
||||
* @param filter String filter
|
||||
*/
|
||||
show() {
|
||||
show(filter: string = "") {
|
||||
this.visible = true;
|
||||
this.contentDiv1.replaceChildren();
|
||||
this.contentDiv2.replaceChildren();
|
||||
@ -62,20 +62,20 @@ export abstract class UnitEditor {
|
||||
var title = document.createElement("label");
|
||||
title.innerText = "Units list";
|
||||
this.contentDiv1.appendChild(title);
|
||||
|
||||
addBlueprintsScroll(this.contentDiv1, this.database, (key: string) => {
|
||||
if (this.database != null)
|
||||
this.setBlueprint(this.database.blueprints[key])
|
||||
})
|
||||
|
||||
addNewElementInput(this.contentDiv1, (ev: MouseEvent, input: HTMLInputElement) => {
|
||||
if (input.value != "")
|
||||
this.addBlueprint((input).value);
|
||||
});
|
||||
var filterInput = document.createElement("input");
|
||||
filterInput.value = filter;
|
||||
this.contentDiv1.appendChild(filterInput);
|
||||
|
||||
filterInput.onchange = (e: Event) => {
|
||||
this.show((e.target as HTMLInputElement).value);
|
||||
}
|
||||
|
||||
this.addBlueprints(filter);
|
||||
}
|
||||
}
|
||||
|
||||
/** Hid the editor
|
||||
/** Hide the editor
|
||||
*
|
||||
*/
|
||||
hide() {
|
||||
@ -93,6 +93,24 @@ export abstract class UnitEditor {
|
||||
return this.database;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param filter String filter
|
||||
*/
|
||||
addBlueprints(filter: string = "") {
|
||||
if (this.database) {
|
||||
addBlueprintsScroll(this.contentDiv1, this.database, filter, (key: string) => {
|
||||
if (this.database != null)
|
||||
this.setBlueprint(this.database.blueprints[key])
|
||||
});
|
||||
|
||||
addNewElementInput(this.contentDiv1, (ev: MouseEvent, input: HTMLInputElement) => {
|
||||
if (input.value != "")
|
||||
this.addBlueprint((input).value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* Abstract methods which will depend on the specific type of units */
|
||||
abstract setBlueprint(blueprint: UnitBlueprint): void;
|
||||
abstract addBlueprint(key: string): void;
|
||||
|
||||
@ -174,40 +174,60 @@ export function addNewElementInput(div: HTMLElement, callback: CallableFunction)
|
||||
*
|
||||
* @param div The HTMLElement that will contain the list
|
||||
* @param database The database that will be used to fill the list of blueprints
|
||||
* @param filter A string filter that will be executed to filter the blueprints to add
|
||||
* @param callback Callback called when the user clicks on one of the elements
|
||||
*/
|
||||
export function addBlueprintsScroll(div: HTMLElement, database: {blueprints: {[key: string]: UnitBlueprint}}, callback: CallableFunction) {
|
||||
export function addBlueprintsScroll(div: HTMLElement, database: {blueprints: {[key: string]: UnitBlueprint}}, filter: string, callback: CallableFunction) {
|
||||
var scrollDiv = document.createElement("div");
|
||||
scrollDiv.classList.add("dm-scroll-container");
|
||||
if (database !== null) {
|
||||
var blueprints: {[key: string]: UnitBlueprint} = database.blueprints;
|
||||
|
||||
for (let key of Object.keys(blueprints).sort((a, b) => a.localeCompare(b, undefined, {sensitivity: 'base'}))) {
|
||||
var rowDiv = document.createElement("div");
|
||||
scrollDiv.appendChild(rowDiv);
|
||||
|
||||
var text = document.createElement("label");
|
||||
text.textContent = key;
|
||||
text.onclick = () => callback(key);
|
||||
rowDiv.appendChild(text);
|
||||
|
||||
let checkbox = document.createElement("input");
|
||||
checkbox.type = "checkbox";
|
||||
checkbox.checked = blueprints[key].enabled;
|
||||
checkbox.onclick = () => {
|
||||
console.log(checkbox.checked);
|
||||
blueprints[key].enabled = checkbox.checked;
|
||||
var addKey = true;
|
||||
if (filter !== "") {
|
||||
try {
|
||||
var blueprint = blueprints[key];
|
||||
addKey = eval(filter);
|
||||
} catch {
|
||||
console.error("An error has occurred evaluating the blueprint filter")
|
||||
}
|
||||
}
|
||||
rowDiv.appendChild(checkbox);
|
||||
|
||||
/* This button allows to remove an element from the list. It requires a refresh. */
|
||||
var button = document.createElement("button");
|
||||
button.innerText = "X";
|
||||
button.onclick = () => {
|
||||
delete blueprints[key];
|
||||
div.dispatchEvent(new Event("refresh"));
|
||||
if (addKey) {
|
||||
var rowDiv = document.createElement("div");
|
||||
scrollDiv.appendChild(rowDiv);
|
||||
|
||||
let text = document.createElement("label");
|
||||
text.textContent = key;
|
||||
text.onclick = () => {
|
||||
callback(key);
|
||||
const collection = document.getElementsByClassName("blueprint-selected");
|
||||
for (let i = 0; i < collection.length; i++) {
|
||||
collection[i].classList.remove("blueprint-selected");
|
||||
}
|
||||
text.classList.add("blueprint-selected");
|
||||
}
|
||||
rowDiv.appendChild(text);
|
||||
|
||||
let checkbox = document.createElement("input");
|
||||
checkbox.type = "checkbox";
|
||||
checkbox.checked = blueprints[key].enabled;
|
||||
checkbox.onclick = () => {
|
||||
console.log(checkbox.checked);
|
||||
blueprints[key].enabled = checkbox.checked;
|
||||
}
|
||||
rowDiv.appendChild(checkbox);
|
||||
|
||||
/* This button allows to remove an element from the list. It requires a refresh. */
|
||||
var button = document.createElement("button");
|
||||
button.innerText = "X";
|
||||
button.onclick = () => {
|
||||
delete blueprints[key];
|
||||
div.dispatchEvent(new Event("refresh"));
|
||||
}
|
||||
rowDiv.appendChild(button);
|
||||
}
|
||||
rowDiv.appendChild(button);
|
||||
}
|
||||
}
|
||||
div.appendChild(scrollDiv);
|
||||
@ -269,5 +289,5 @@ export function arrayToString(array: string[]) {
|
||||
|
||||
|
||||
export function stringToArray(input: string) {
|
||||
return input.match( /(\w)+/g ) || [];
|
||||
return input.match( /(\w)+/g ) ?? [];
|
||||
}
|
||||
@ -115,6 +115,10 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#database-manager-panel input {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.dm-scroll-container>div:nth-child(even) {
|
||||
background-color: gainsboro;
|
||||
}
|
||||
@ -131,11 +135,16 @@
|
||||
}
|
||||
|
||||
.dm-scroll-container>div *:nth-child(1):hover {
|
||||
background-color: var(--secondary-blue-text);
|
||||
background-color: var(--accent-dark-blue);
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.blueprint-selected {
|
||||
background-color: var(--accent-light-blue) !important;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.dm-scroll-container>div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@ -166,20 +166,23 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
|
||||
|
||||
#unit-control-panel .switch-control {
|
||||
align-items: center;
|
||||
display: grid;
|
||||
grid-template-columns: 1.35fr 0.65fr;
|
||||
}
|
||||
|
||||
#unit-control-panel .switch-control>*:nth-child(2) {
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
#unit-control-panel .switch-control>*:nth-child(3) {
|
||||
color: var(--secondary-semitransparent-white);
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#unit-control-panel .switch-control h4 {
|
||||
margin: 0px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#unit-control-panel .switch-control h4 img {
|
||||
height: 15px;
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
filter: invert(100%);
|
||||
opacity: 80%;
|
||||
}
|
||||
|
||||
#unit-control-panel .switch-control .ol-switch {
|
||||
@ -239,6 +242,8 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
|
||||
#unit-control-panel:not([data-show-roe]) #roe,
|
||||
#unit-control-panel:not([data-show-threat]) #threat,
|
||||
#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-AWACS-button]) #AWACS-on,
|
||||
#unit-control-panel:not([data-show-on-off]) #ai-on-off,
|
||||
|
||||
@ -91,9 +91,9 @@
|
||||
|
||||
#loadout-silhouette {
|
||||
filter: invert(100%);
|
||||
height: 100px;
|
||||
height: 75px;
|
||||
margin-right: 25px;
|
||||
width: 100px;
|
||||
width: 75px;
|
||||
}
|
||||
|
||||
#loadout-items {
|
||||
|
||||
@ -72,10 +72,6 @@ form {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
form>div {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.pill {
|
||||
background-color: var(--background-steel);
|
||||
border-radius: 999px;
|
||||
@ -669,8 +665,8 @@ nav.ol-panel> :last-child {
|
||||
width:10px;
|
||||
}
|
||||
|
||||
.ol-navbar-buttons-group > .protectable > button.lock svg.locked {
|
||||
filter:invert(100);
|
||||
.ol-navbar-buttons-group > .protectable > button.lock svg.locked * {
|
||||
fill:white !important;
|
||||
}
|
||||
|
||||
.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,
|
||||
#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;
|
||||
background-color: transparent;
|
||||
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 * {
|
||||
fill: var(--background-steel);
|
||||
stroke: var(--background-steel);
|
||||
}
|
||||
|
||||
#rapid-controls {
|
||||
@ -850,7 +849,7 @@ nav.ol-panel> :last-child {
|
||||
column-gap: 10px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: 10px 0px;
|
||||
margin: 20px 0px;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
row-gap: 10px;
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg4" />
|
||||
<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"
|
||||
fill="#5ca7ff"
|
||||
id="path2" />
|
||||
|
||||
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.6 KiB |
@ -39,5 +39,6 @@
|
||||
<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"
|
||||
fill="#5ca7ff"
|
||||
id="path2" />
|
||||
id="path2"
|
||||
style="stroke: none"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
@ -39,5 +39,6 @@
|
||||
<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"
|
||||
fill="#5ca7ff"
|
||||
id="path2" />
|
||||
id="path2"
|
||||
style="stroke: none"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
@ -39,5 +39,6 @@
|
||||
<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"
|
||||
fill="#5ca7ff"
|
||||
id="path2" />
|
||||
id="path2"
|
||||
style="stroke: none"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
69
client/public/themes/olympus/images/buttons/intensity/1.svg
Normal 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 |
69
client/public/themes/olympus/images/buttons/intensity/2.svg
Normal 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 |
62
client/public/themes/olympus/images/buttons/intensity/3.svg
Normal 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 |
@ -40,5 +40,6 @@
|
||||
<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"
|
||||
fill="#5ca7ff"
|
||||
id="path2" />
|
||||
id="path2"
|
||||
style="stroke: none"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.6 KiB |
@ -39,5 +39,6 @@
|
||||
<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"
|
||||
fill="#5ca7ff"
|
||||
id="path2" />
|
||||
id="path2"
|
||||
style="stroke: none"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
@ -39,5 +39,6 @@
|
||||
<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"
|
||||
fill="#5ca7ff"
|
||||
id="path2" />
|
||||
id="path2"
|
||||
style="stroke: none"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
@ -39,5 +39,6 @@
|
||||
<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"
|
||||
fill="#5ca7ff"
|
||||
id="path2" />
|
||||
id="path2"
|
||||
style="stroke: none"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
56
client/public/themes/olympus/images/buttons/scatter/1.svg
Normal 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 |
56
client/public/themes/olympus/images/buttons/scatter/2.svg
Normal 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 |
56
client/public/themes/olympus/images/buttons/scatter/3.svg
Normal 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 |
@ -39,7 +39,8 @@
|
||||
<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"
|
||||
fill="#5ca7ff"
|
||||
id="path2" />
|
||||
id="path2"
|
||||
style="stroke: none"/>
|
||||
<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"
|
||||
stroke="#5ca7ff"
|
||||
@ -50,13 +51,16 @@
|
||||
<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"
|
||||
fill="#5ca7ff"
|
||||
id="path6" />
|
||||
id="path6"
|
||||
style="stroke: none"/>
|
||||
<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"
|
||||
fill="#5ca7ff"
|
||||
id="path8" />
|
||||
id="path8"
|
||||
style="stroke: none"/>
|
||||
<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"
|
||||
fill="#5ca7ff"
|
||||
id="path10" />
|
||||
id="path10"
|
||||
style="stroke: none"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.6 KiB |
@ -39,7 +39,8 @@
|
||||
<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"
|
||||
fill="#5ca7ff"
|
||||
id="path2" />
|
||||
id="path2"
|
||||
style="stroke: none"/>
|
||||
<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"
|
||||
stroke="#5ca7ff"
|
||||
|
||||
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
@ -39,5 +39,6 @@
|
||||
<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"
|
||||
fill="#5ca7ff"
|
||||
id="path2" />
|
||||
id="path2"
|
||||
style="stroke: none"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
@ -39,7 +39,8 @@
|
||||
<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"
|
||||
fill="#5ca7ff"
|
||||
id="path2" />
|
||||
id="path2"
|
||||
style="stroke: none"/>
|
||||
<path
|
||||
d="M 12.8398,6.5498 H 23.2749"
|
||||
stroke="#5ca7ff"
|
||||
@ -48,17 +49,21 @@
|
||||
<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"
|
||||
fill="#5ca7ff"
|
||||
id="path6" />
|
||||
id="path6"
|
||||
style="stroke: none"/>
|
||||
<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"
|
||||
fill="#5ca7ff"
|
||||
id="path8" />
|
||||
id="path8"
|
||||
style="stroke: none"/>
|
||||
<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"
|
||||
fill="#5ca7ff"
|
||||
id="path10" />
|
||||
id="path10"
|
||||
style="stroke: none"/>
|
||||
<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"
|
||||
fill="#5ca7ff"
|
||||
id="path12" />
|
||||
id="path12"
|
||||
style="stroke: none"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.5 KiB |
@ -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 |
@ -23,6 +23,7 @@
|
||||
--accent-amber: #ffd828;
|
||||
--accent-green: #8bff63;
|
||||
--accent-light-blue: #5ca7ff;
|
||||
--accent-dark-blue: #017DC1;
|
||||
--transparent-accent-light-blue: rgba(92, 167, 255, .33);
|
||||
--accent-light-red: #F5B6B6;
|
||||
|
||||
|
||||
@ -48,6 +48,18 @@ export const emissionsCountermeasuresDescriptions: string[] = [
|
||||
"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 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 };
|
||||
@ -221,6 +233,8 @@ export enum DataIndexes {
|
||||
hasTask,
|
||||
position,
|
||||
speed,
|
||||
horizontalVelocity,
|
||||
verticalVelocity,
|
||||
heading,
|
||||
isActiveTanker,
|
||||
isActiveAWACS,
|
||||
@ -246,6 +260,8 @@ export enum DataIndexes {
|
||||
activePath,
|
||||
isLeader,
|
||||
operateAs,
|
||||
shotsScatter,
|
||||
shotsIntensity,
|
||||
endOfData = 255
|
||||
};
|
||||
|
||||
|
||||
@ -1,11 +1,31 @@
|
||||
export interface ContextInterface {
|
||||
|
||||
useSpawnMenu?: boolean;
|
||||
useUnitControlPanel?: boolean;
|
||||
useUnitInfoPanel?: boolean;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -105,6 +105,9 @@ export class MapContextMenu extends ContextMenu {
|
||||
* @param latlng Leaflet latlng object of the mouse click
|
||||
*/
|
||||
show(x: number, y: number, latlng: LatLng) {
|
||||
if (!getApp().getCurrentContext().getUseSpawnMenu())
|
||||
return false;
|
||||
|
||||
super.show(x, y, latlng);
|
||||
|
||||
this.#aircraftSpawnMenu.setLatLng(latlng);
|
||||
|
||||
@ -152,6 +152,8 @@ export interface UnitData {
|
||||
hasTask: boolean;
|
||||
position: LatLng;
|
||||
speed: number;
|
||||
horizontalVelocity: number;
|
||||
verticalVelocity: number;
|
||||
heading: number;
|
||||
isActiveTanker: boolean;
|
||||
isActiveAWACS: boolean;
|
||||
@ -177,6 +179,8 @@ export interface UnitData {
|
||||
activePath: LatLng[];
|
||||
isLeader: boolean;
|
||||
operateAs: string;
|
||||
shotsScatter: number;
|
||||
shotsIntensity: number;
|
||||
}
|
||||
|
||||
export interface LoadoutItemBlueprint {
|
||||
@ -210,12 +214,19 @@ export interface UnitBlueprint {
|
||||
muzzleVelocity?: number;
|
||||
aimTime?: number;
|
||||
shotsToFire?: number;
|
||||
shotsBaseInterval?: number;
|
||||
shotsBaseScatter?: number;
|
||||
description?: string;
|
||||
abilities?: string;
|
||||
acquisitionRange?: number;
|
||||
engagementRange?: number;
|
||||
targetingRange?: number;
|
||||
aimMethodRange?: number;
|
||||
alertnessTimeConstant?: number;
|
||||
canTargetPoint?: boolean;
|
||||
canRearm?: boolean;
|
||||
canAAA?: boolean;
|
||||
indirectFire?: boolean;
|
||||
}
|
||||
|
||||
export interface UnitSpawnOptions {
|
||||
|
||||
@ -734,7 +734,7 @@ export class Map extends L.Map {
|
||||
const makeTitle = (isProtected:boolean) => {
|
||||
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 div = document.createElement("div");
|
||||
div.className = control.protectable === true ? "protectable" : "";
|
||||
@ -901,5 +901,9 @@ export class Map extends L.Map {
|
||||
this.#visibilityOptions[option] = ev.currentTarget.checked;
|
||||
document.dispatchEvent(new CustomEvent("mapVisibilityOptionsChanged"));
|
||||
}
|
||||
|
||||
getMapMarkerControls() {
|
||||
return this.#mapMarkerControls;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -403,19 +403,26 @@ export class OlympusApp {
|
||||
});
|
||||
|
||||
/* Try and connect with the Olympus REST server */
|
||||
document.addEventListener("tryConnection", () => {
|
||||
const form = document.querySelector("#splash-content")?.querySelector("#authentication-form");
|
||||
const username = (form?.querySelector("#username") as HTMLInputElement).value;
|
||||
const password = (form?.querySelector("#password") as HTMLInputElement).value;
|
||||
const loginForm = document.getElementById("authentication-form");
|
||||
if (loginForm instanceof HTMLFormElement) {
|
||||
loginForm.addEventListener("submit", (ev:SubmitEvent) => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
const username = (loginForm.querySelector("#username") as HTMLInputElement).value;
|
||||
const password = (loginForm.querySelector("#password") as HTMLInputElement).value;
|
||||
|
||||
/* Update the user credentials */
|
||||
this.getServerManager().setCredentials(username, password);
|
||||
// Update the user credentials
|
||||
this.getServerManager().setCredentials(username, password);
|
||||
|
||||
/* Start periodically requesting updates */
|
||||
this.getServerManager().startUpdate();
|
||||
// Start periodically requesting updates
|
||||
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 */
|
||||
document.addEventListener("reloadPage", () => {
|
||||
|
||||
@ -6,7 +6,7 @@ import { aircraftDatabase } from "../unit/databases/aircraftdatabase";
|
||||
import { Unit } from "../unit/unit";
|
||||
import { Panel } from "./panel";
|
||||
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 { 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); });
|
||||
});
|
||||
|
||||
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("#reaction-to-threat-buttons-container")?.append(...this.#optionButtons["reactionToThreat"]);
|
||||
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 */
|
||||
this.#tankerSwitch = new Switch("tanker-on-switch", (value: boolean) => {
|
||||
@ -131,6 +141,10 @@ export class UnitControlPanel extends Panel {
|
||||
}
|
||||
|
||||
show() {
|
||||
const context = getApp().getCurrentContext();
|
||||
if ( !context.getUseUnitControlPanel() )
|
||||
return;
|
||||
|
||||
super.show();
|
||||
this.#speedTypeSwitch.resetExpectedValue();
|
||||
this.#altitudeTypeSwitch.resetExpectedValue();
|
||||
@ -195,6 +209,8 @@ export class UnitControlPanel extends Panel {
|
||||
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-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-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")));
|
||||
@ -256,6 +272,14 @@ export class UnitControlPanel extends Panel {
|
||||
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.#AWACSSwitch.setValue(isActiveAWACAS, false);
|
||||
this.#onOffSwitch.setValue(onOff, false);
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { getApp } from "..";
|
||||
import { Ammo } from "../interfaces";
|
||||
import { aircraftDatabase } from "../unit/databases/aircraftdatabase";
|
||||
import { Unit } from "../unit/unit";
|
||||
@ -92,4 +93,12 @@ export class UnitInfoPanel extends Panel {
|
||||
else
|
||||
this.hide();
|
||||
}
|
||||
|
||||
show() {
|
||||
const context = getApp().getCurrentContext();
|
||||
if ( !context.getUseUnitInfoPanel() )
|
||||
return;
|
||||
|
||||
super.show();
|
||||
}
|
||||
}
|
||||
@ -357,6 +357,18 @@ export class ServerManager {
|
||||
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 = () => {}) {
|
||||
var command = {
|
||||
"ID": ID,
|
||||
|
||||
@ -34,6 +34,8 @@ export class Unit extends CustomMarker {
|
||||
#hasTask: boolean = false;
|
||||
#position: LatLng = new LatLng(0, 0, 0);
|
||||
#speed: number = 0;
|
||||
#horizontalVelocity: number = 0;
|
||||
#verticalVelocity: number = 0;
|
||||
#heading: number = 0;
|
||||
#isActiveTanker: boolean = false;
|
||||
#isActiveAWACS: boolean = false;
|
||||
@ -78,6 +80,8 @@ export class Unit extends CustomMarker {
|
||||
#activePath: LatLng[] = [];
|
||||
#isLeader: boolean = false;
|
||||
#operateAs: string = "blue";
|
||||
#shotsScatter: number = 2;
|
||||
#shotsIntensity: number = 2;
|
||||
|
||||
#selectable: boolean;
|
||||
#selected: boolean = false;
|
||||
@ -95,47 +99,49 @@ export class Unit extends CustomMarker {
|
||||
#doubleClickTimer: number = 0;
|
||||
#hotgroup: number | null = null;
|
||||
#detectionMethods: number[] = [];
|
||||
#isProtected:boolean = false;
|
||||
|
||||
getActivePath() { return this.#activePath };
|
||||
getAlive() { return this.#alive };
|
||||
getAmmo() { return this.#ammo };
|
||||
getCoalition() { return this.#coalition };
|
||||
getContacts() { return this.#contacts };
|
||||
getHuman() { return this.#human };
|
||||
getControlled() { return this.#controlled };
|
||||
getCoalition() { return this.#coalition };
|
||||
getCountry() { return this.#country };
|
||||
getDesiredAltitude() { return this.#desiredAltitude };
|
||||
getDesiredAltitudeType() { return this.#desiredAltitudeType };
|
||||
getName() { return this.#name };
|
||||
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 };
|
||||
getDesiredSpeedType() { return this.#desiredSpeedType };
|
||||
getEmissionsCountermeasures() { return this.#emissionsCountermeasures };
|
||||
getFollowRoads() { return this.#followRoads };
|
||||
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 };
|
||||
getDesiredAltitude() { return this.#desiredAltitude };
|
||||
getDesiredAltitudeType() { return this.#desiredAltitudeType };
|
||||
getLeaderID() { return this.#leaderID };
|
||||
getName() { return this.#name };
|
||||
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 };
|
||||
getFormationOffset() { return this.#formationOffset };
|
||||
getTargetID() { return this.#targetID };
|
||||
getTargetPosition() { return this.#targetPosition };
|
||||
getTask() { return this.#task };
|
||||
getUnitName() { return this.#unitName };
|
||||
getROE() { return this.#ROE };
|
||||
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) {
|
||||
if (type === "GroundUnit") return GroundUnit;
|
||||
@ -222,6 +228,8 @@ export class Unit extends CustomMarker {
|
||||
case DataIndexes.hasTask: this.#hasTask = dataExtractor.extractBool(); break;
|
||||
case DataIndexes.position: this.#position = dataExtractor.extractLatLng(); 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.isActiveTanker: this.#isActiveTanker = 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.isLeader: this.#isLeader = dataExtractor.extractBool(); updateMarker = true; 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,
|
||||
position: this.#position,
|
||||
speed: this.#speed,
|
||||
horizontalVelocity: this.#horizontalVelocity,
|
||||
verticalVelocity: this.#verticalVelocity,
|
||||
heading: this.#heading,
|
||||
isActiveTanker: this.#isActiveTanker,
|
||||
isActiveAWACS: this.#isActiveAWACS,
|
||||
@ -310,7 +322,9 @@ export class Unit extends CustomMarker {
|
||||
contacts: this.#contacts,
|
||||
activePath: this.#activePath,
|
||||
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) {
|
||||
if (newAlive != this.#alive)
|
||||
document.dispatchEvent(new CustomEvent("unitDeath", { detail: this }));
|
||||
@ -437,7 +447,6 @@ export class Unit extends CustomMarker {
|
||||
return this.getDatabase()?.getSpawnPointsByName(this.getName());
|
||||
}
|
||||
|
||||
|
||||
/********************** Icon *************************/
|
||||
createIcon(): void {
|
||||
/* Set the icon */
|
||||
@ -636,10 +645,6 @@ export class Unit extends CustomMarker {
|
||||
return getApp().getMap().getBounds().contains(this.getPosition());
|
||||
}
|
||||
|
||||
canLandAtPoint() {
|
||||
return this.getCategory() === "Helicopter"; // Only choppers can do this currently
|
||||
}
|
||||
|
||||
canTargetPoint() {
|
||||
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;
|
||||
}
|
||||
|
||||
canLandAtPoint() {
|
||||
return this.getCategory() === "Helicopter";
|
||||
}
|
||||
|
||||
canAAA() {
|
||||
return this.getDatabase()?.getByName(this.#name)?.canAAA === true;
|
||||
}
|
||||
|
||||
indirectFire() {
|
||||
return this.getDatabase()?.getByName(this.#name)?.indirectFire === true;
|
||||
}
|
||||
|
||||
isTanker() {
|
||||
return this.canFulfillRole("Tanker");
|
||||
}
|
||||
@ -823,6 +840,16 @@ export class Unit extends CustomMarker {
|
||||
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 } } {
|
||||
/* 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" };
|
||||
}
|
||||
|
||||
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["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" };
|
||||
}
|
||||
|
||||
@ -708,6 +708,30 @@ export class UnitsManager {
|
||||
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 ************************/
|
||||
/** See getUnitsCategories for more info
|
||||
*
|
||||
|
||||
@ -6,11 +6,11 @@
|
||||
<div class="app-version">Version <span class="app-version-number">v0.4.5-alpha</span></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>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>
|
||||
</div>
|
||||
<button type="submit" id="connection-button" class="ol-button-apply">Connect</button>
|
||||
</form>
|
||||
|
||||
<h5 id="login-status"><br></h5>
|
||||
|
||||
|
||||
@ -61,32 +61,42 @@
|
||||
</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">
|
||||
<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>Instructs the unit to operate as AAR tanker. A/A TACAN, radio frequency and callsign set in Settings dialog.</div>
|
||||
</div>
|
||||
|
||||
<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>Enables datalink and AI radio calls. Radio frequency and callsign set in Settings dialog.</div>
|
||||
</div>
|
||||
|
||||
<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>Determines if the unit will target red or blue units when performing scenic tasks.</div>
|
||||
</div>
|
||||
|
||||
<div id="ai-on-off" class="switch-control">
|
||||
<h4>Unit active</h4>
|
||||
<div id="on-off-switch" class="ol-switch"></div>
|
||||
<div>Toggling this disables unit AI completely. It will no longer move, react or emit radio waves.</div>
|
||||
<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" title=""></div>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
|
||||
|
||||
@ -269,6 +269,14 @@ function Olympus.buildTask(groupName, options)
|
||||
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
|
||||
return task
|
||||
@ -888,6 +896,7 @@ function Olympus.setUnitsData(arg, time)
|
||||
local lat, lng, alt = coord.LOtoLL(unit:getPoint())
|
||||
local position = unit:getPosition()
|
||||
local heading = math.atan2( position.x.z, position.x.x )
|
||||
local velocity = unit:getVelocity();
|
||||
|
||||
-- Fill the data table
|
||||
table["name"] = unit:getTypeName()
|
||||
@ -896,7 +905,9 @@ function Olympus.setUnitsData(arg, time)
|
||||
table["position"]["lat"] = lat
|
||||
table["position"]["lng"] = lng
|
||||
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["isAlive"] = unit:isExist() and unit:isActive() and unit:getLife() >= 1
|
||||
|
||||
|
||||
@ -19,6 +19,8 @@ namespace DataIndex {
|
||||
hasTask,
|
||||
position,
|
||||
speed,
|
||||
horizontalVelocity,
|
||||
verticalVelocity,
|
||||
heading,
|
||||
isActiveTanker,
|
||||
isActiveAWACS,
|
||||
@ -44,6 +46,8 @@ namespace DataIndex {
|
||||
activePath,
|
||||
isLeader,
|
||||
operateAs,
|
||||
shotsScatter,
|
||||
shotsIntensity,
|
||||
lastIndex,
|
||||
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)
|
||||
namespace DataTypes {
|
||||
struct TACAN
|
||||
|
||||
@ -17,6 +17,8 @@ public:
|
||||
virtual void setOnOff(bool newOnOff, bool force = false);
|
||||
virtual void setFollowRoads(bool newFollowRoads, bool force = false);
|
||||
|
||||
void aimAtPoint(Coords aimTarget, double horizontalScatterMultiplier = 1, double verticalScatterMultiplier = 1);
|
||||
|
||||
protected:
|
||||
virtual void AIloop();
|
||||
static json::value database;
|
||||
|
||||
@ -55,6 +55,8 @@ public:
|
||||
bool checkTaskFailed();
|
||||
void resetTaskFailedCounter();
|
||||
void setHasTaskAssigned(bool newHasTaskAssigned);
|
||||
void setEnableTaskCheckFailed(bool newEnableTaskCheckFailed) { enableTaskFailedCheck = newEnableTaskCheckFailed; }
|
||||
bool getEnableTaskCheckFailed() { return enableTaskFailedCheck; }
|
||||
|
||||
void triggerUpdate(unsigned char datumIndex);
|
||||
|
||||
@ -73,9 +75,11 @@ public:
|
||||
virtual void setGroupName(string newValue) { updateValue(groupName, newValue, DataIndex::groupName); }
|
||||
virtual void setState(unsigned char newValue) { updateValue(state, newValue, DataIndex::state); };
|
||||
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 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 setIsActiveTanker(bool newValue);
|
||||
virtual void setIsActiveAWACS(bool newValue);
|
||||
@ -101,6 +105,8 @@ public:
|
||||
virtual void setActivePath(list<Coords> newValue);
|
||||
virtual void setIsLeader(bool newValue) { updateValue(isLeader, newValue, DataIndex::isLeader); }
|
||||
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 **********/
|
||||
virtual string getCategory() { return category; };
|
||||
@ -117,6 +123,8 @@ public:
|
||||
virtual bool getHasTask() { return hasTask; }
|
||||
virtual Coords getPosition() { return position; }
|
||||
virtual double getSpeed() { return speed; }
|
||||
virtual double getHorizontalVelocity() { return horizontalVelocity; }
|
||||
virtual double getVerticalVelocity() { return verticalVelocity; }
|
||||
virtual double getHeading() { return heading; }
|
||||
virtual bool getIsActiveTanker() { return isActiveTanker; }
|
||||
virtual bool getIsActiveAWACS() { return isActiveAWACS; }
|
||||
@ -142,6 +150,8 @@ public:
|
||||
virtual list<Coords> getActivePath() { return activePath; }
|
||||
virtual bool getIsLeader() { return isLeader; }
|
||||
virtual unsigned char getOperateAs() { return operateAs; }
|
||||
virtual unsigned char getShotsScatter() { return shotsScatter; }
|
||||
virtual unsigned char getShotsIntensity() { return shotsIntensity; }
|
||||
|
||||
protected:
|
||||
unsigned int ID;
|
||||
@ -160,6 +170,8 @@ protected:
|
||||
bool hasTask = false;
|
||||
Coords position = Coords(NULL);
|
||||
double speed = NULL;
|
||||
double horizontalVelocity = NULL;
|
||||
double verticalVelocity = NULL;
|
||||
double heading = NULL;
|
||||
bool isActiveTanker = false;
|
||||
bool isActiveAWACS = false;
|
||||
@ -186,14 +198,18 @@ protected:
|
||||
bool isLeader = false;
|
||||
unsigned char operateAs = 2;
|
||||
Coords activeDestination = Coords(NULL);
|
||||
unsigned char shotsScatter = 2;
|
||||
unsigned char shotsIntensity = 2;
|
||||
|
||||
/********** Other **********/
|
||||
unsigned int taskCheckCounter = 0;
|
||||
unsigned int internalCounter = 0;
|
||||
Unit* missOnPurposeTarget = nullptr;
|
||||
bool hasTaskAssigned = false;
|
||||
double initialFuel = 0;
|
||||
map<unsigned char, unsigned long long> updateTimeMap;
|
||||
unsigned long long lastLoopTime = 0;
|
||||
bool enableTaskFailedCheck = false;
|
||||
|
||||
/********** Private methods **********/
|
||||
virtual void AIloop() = 0;
|
||||
|
||||
@ -24,6 +24,7 @@ public:
|
||||
void acquireControl(unsigned int ID);
|
||||
void loadDatabases();
|
||||
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:
|
||||
map<unsigned int, Unit*> units;
|
||||
|
||||
@ -80,15 +80,18 @@ void AirUnit::setState(unsigned char newState)
|
||||
/************ Perform any action required when ENTERING a state ************/
|
||||
switch (newState) {
|
||||
case State::IDLE: {
|
||||
setEnableTaskCheckFailed(false);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::REACH_DESTINATION: {
|
||||
setEnableTaskCheckFailed(true);
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::ATTACK: {
|
||||
setEnableTaskCheckFailed(true);
|
||||
if (isTargetAlive()) {
|
||||
Unit* target = unitsManager->getUnit(targetID);
|
||||
Coords targetPosition = Coords(target->getPosition().lat, target->getPosition().lng, 0);
|
||||
@ -99,36 +102,43 @@ void AirUnit::setState(unsigned char newState)
|
||||
break;
|
||||
}
|
||||
case State::FOLLOW: {
|
||||
setEnableTaskCheckFailed(true);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::LAND: {
|
||||
setEnableTaskCheckFailed(false);
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::REFUEL: {
|
||||
setEnableTaskCheckFailed(true);
|
||||
initialFuel = fuel;
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::BOMB_POINT: {
|
||||
setEnableTaskCheckFailed(true);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::CARPET_BOMB: {
|
||||
setEnableTaskCheckFailed(true);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::BOMB_BUILDING: {
|
||||
setEnableTaskCheckFailed(true);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::LAND_AT_POINT: {
|
||||
setEnableTaskCheckFailed(true);
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -13,6 +13,9 @@ extern Scheduler* scheduler;
|
||||
extern UnitsManager* unitsManager;
|
||||
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) {
|
||||
char* buf = nullptr;
|
||||
size_t sz = 0;
|
||||
@ -89,30 +92,36 @@ void GroundUnit::setState(unsigned char newState)
|
||||
/************ Perform any action required when ENTERING a state ************/
|
||||
switch (newState) {
|
||||
case State::IDLE: {
|
||||
setEnableTaskCheckFailed(false);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::REACH_DESTINATION: {
|
||||
setEnableTaskCheckFailed(true);
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::FIRE_AT_AREA: {
|
||||
setEnableTaskCheckFailed(true);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::SIMULATE_FIRE_FIGHT: {
|
||||
setEnableTaskCheckFailed(true);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::SCENIC_AAA: {
|
||||
setEnableTaskCheckFailed(false);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::MISS_ON_PURPOSE: {
|
||||
setEnableTaskCheckFailed(false);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
@ -139,6 +148,8 @@ void GroundUnit::AIloop()
|
||||
break;
|
||||
}
|
||||
case State::REACH_DESTINATION: {
|
||||
setTask("Reaching destination");
|
||||
|
||||
string enrouteTask = "";
|
||||
bool looping = false;
|
||||
|
||||
@ -180,41 +191,12 @@ void GroundUnit::AIloop()
|
||||
case State::SIMULATE_FIRE_FIGHT: {
|
||||
setTask("Simulating fire fight");
|
||||
|
||||
if (!getHasTask() || internalCounter == 0) {
|
||||
double dist;
|
||||
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) {
|
||||
aimAtPoint(targetPosition, 3.0, 0.0);
|
||||
}
|
||||
|
||||
if (internalCounter == 0)
|
||||
internalCounter = 20 / 0.05; // TODO make defined constant
|
||||
internalCounter = 20 / FRAMERATE_TIME_INTERVAL;
|
||||
internalCounter--;
|
||||
|
||||
break;
|
||||
@ -247,7 +229,7 @@ void GroundUnit::AIloop()
|
||||
}
|
||||
|
||||
if (internalCounter == 0)
|
||||
internalCounter = 20 / 0.05;
|
||||
internalCounter = 20 / FRAMERATE_TIME_INTERVAL;
|
||||
internalCounter--;
|
||||
|
||||
break;
|
||||
@ -255,20 +237,32 @@ void GroundUnit::AIloop()
|
||||
case State::MISS_ON_PURPOSE: {
|
||||
setTask("Missing on purpose");
|
||||
|
||||
/* 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;
|
||||
Unit* target = unitsManager->getClosestUnit(this, targetCoalition, {"Aircraft", "Helicopter"}, distance);
|
||||
/* Check that the unit can perform AAA duties */
|
||||
bool canAAA = false;
|
||||
if (database.has_object_field(to_wstring(name))) {
|
||||
json::value databaseEntry = database[to_wstring(name)];
|
||||
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 (target != nullptr && distance < 10000 /* m */) {
|
||||
if (canAAA) {
|
||||
/* 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 */
|
||||
double barrelHeight = 1.0; /* m */
|
||||
double muzzleVelocity = 860; /* m/s */
|
||||
double aimTime = 10; /* s */
|
||||
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))) {
|
||||
json::value databaseEntry = database[to_wstring(name)];
|
||||
if (databaseEntry.has_number_field(L"barrelHeight"))
|
||||
@ -279,45 +273,104 @@ void GroundUnit::AIloop()
|
||||
aimTime = databaseEntry[L"aimTime"].as_number().to_double();
|
||||
if (databaseEntry.has_number_field(L"shotsToFire"))
|
||||
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 */
|
||||
if (muzzleVelocity != 0)
|
||||
aimTime += distance / muzzleVelocity;
|
||||
/* Get all the units in range and select one at random */
|
||||
double range = aimMethodRange > engagementRange ? aimMethodRange : engagementRange;
|
||||
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 */
|
||||
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 */
|
||||
internalCounter = (aimTime + (ShotsIntensity::HIGH - shotsIntensity) * shotsBaseInterval + 2) / FRAMERATE_TIME_INTERVAL;
|
||||
|
||||
/* Compute distance to the aim point */ // TODO: why am I here?
|
||||
double dist;
|
||||
double bearing1;
|
||||
double bearing2;
|
||||
Geodesic::WGS84().Inverse(position.lat, position.lng, aimLat, aimLng, dist, bearing1, bearing2);
|
||||
/* If the target is in targeting range and we are in highest precision mode, target it */
|
||||
if (distance < targetingRange && shotsScatter == ShotsScatter::LOW) {
|
||||
/* Send the command */
|
||||
std::ostringstream taskSS;
|
||||
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 */
|
||||
std::ostringstream taskSS;
|
||||
taskSS.precision(10);
|
||||
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); }));
|
||||
scheduler->appendCommand(command);
|
||||
setHasTask(true);
|
||||
/* Send the command */
|
||||
if (distance > engagementRange) {
|
||||
aimAtPoint(Coords(aimLat, aimLng, aimAlt));
|
||||
}
|
||||
else {
|
||||
/* Compute a random scattering depending on the distance and the selected shots scatter */
|
||||
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));
|
||||
}
|
||||
else {
|
||||
if (getHasTask())
|
||||
resetTask();
|
||||
std::ostringstream taskSS;
|
||||
taskSS.precision(10);
|
||||
taskSS << "{id = 'FireAtPoint', lat = " << aimLat << ", lng = " << aimLng << ", alt = " << aimAlt << ", radius = 0.001, expendQty = " << shotsToFire << " }";
|
||||
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
|
||||
scheduler->appendCommand(command);
|
||||
setHasTask(true);
|
||||
}
|
||||
|
||||
setTargetPosition(Coords(aimLat, aimLng, target->getPosition().alt));
|
||||
}
|
||||
|
||||
missOnPurposeTarget = target;
|
||||
}
|
||||
else {
|
||||
if (getHasTask())
|
||||
resetTask();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (internalCounter == 0)
|
||||
internalCounter = 5 / 0.05;
|
||||
internalCounter--;
|
||||
/* If no valid target was detected */
|
||||
if (internalCounter == 0) {
|
||||
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;
|
||||
}
|
||||
@ -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)
|
||||
{
|
||||
if (change.compare("stop") == 0)
|
||||
|
||||
@ -81,21 +81,25 @@ void NavyUnit::setState(unsigned char newState)
|
||||
/************ Perform any action required when ENTERING a state ************/
|
||||
switch (newState) {
|
||||
case State::IDLE: {
|
||||
setEnableTaskCheckFailed(false);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::REACH_DESTINATION: {
|
||||
setEnableTaskCheckFailed(true);
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::FIRE_AT_AREA: {
|
||||
setEnableTaskCheckFailed(true);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
resetTask();
|
||||
break;
|
||||
}
|
||||
case State::SIMULATE_FIRE_FIGHT: {
|
||||
setEnableTaskCheckFailed(true);
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
resetTask();
|
||||
|
||||
@ -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)
|
||||
{
|
||||
setCommandModeOptions(value);
|
||||
|
||||
@ -69,6 +69,12 @@ void Unit::update(json::value json, double dt)
|
||||
if (json.has_number_field(L"speed"))
|
||||
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"))
|
||||
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 (getAlive() && getControlled() && !getHuman() && getIsLeader()) {
|
||||
if (checkTaskFailed() && state != State::IDLE && state != State::LAND) {
|
||||
if (getEnableTaskCheckFailed() && checkTaskFailed()) {
|
||||
log(unitName + " has no task, switching to IDLE state");
|
||||
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::activePath: updateValue(activePath, leader->activePath, 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::position: appendNumeric(ss, datumIndex, position); 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::isActiveTanker: appendNumeric(ss, datumIndex, isActiveTanker); break;
|
||||
case DataIndex::isActiveAWACS: appendNumeric(ss, datumIndex, isActiveAWACS); break;
|
||||
case DataIndex::isActiveTanker: appendNumeric(ss, datumIndex, isActiveTanker); break;
|
||||
case DataIndex::isActiveAWACS: appendNumeric(ss, datumIndex, isActiveAWACS); break;
|
||||
case DataIndex::onOff: appendNumeric(ss, datumIndex, onOff); break;
|
||||
case DataIndex::followRoads: appendNumeric(ss, datumIndex, followRoads); 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::isLeader: appendNumeric(ss, datumIndex, isLeader); 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()
|
||||
{
|
||||
if (getHasTask())
|
||||
|
||||
@ -172,19 +172,20 @@ Unit* UnitsManager::getClosestUnit(Unit* unit, unsigned char coalition, vector<s
|
||||
double bearing1;
|
||||
double 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 (closestUnit == nullptr)
|
||||
{
|
||||
closestUnit = p.second;
|
||||
distance = dist;
|
||||
distance = sqrt(dist * dist + altDelta * altDelta);
|
||||
|
||||
}
|
||||
else {
|
||||
/* Check if the unit is closer than the one already selected */
|
||||
if (dist < distance) {
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
Unit* leader = getGroupLeader(ID);
|
||||
if (leader != nullptr) {
|
||||
|
||||