Merge pull request #436 from Pax1601/328-add-simple-miss-on-purpose-mode-for-aaa
328 add simple miss on purpose mode for aaa
83
client/@types/olympus/index.d.ts
vendored
@ -241,6 +241,7 @@ declare module "constants/constants" {
|
||||
contacts = 36,
|
||||
activePath = 37,
|
||||
isLeader = 38,
|
||||
operateAs = 39,
|
||||
endOfData = 255
|
||||
}
|
||||
}
|
||||
@ -512,6 +513,7 @@ declare module "interfaces" {
|
||||
contacts: Contact[];
|
||||
activePath: LatLng[];
|
||||
isLeader: boolean;
|
||||
operateAs: string;
|
||||
}
|
||||
export interface LoadoutItemBlueprint {
|
||||
name: string;
|
||||
@ -532,7 +534,7 @@ declare module "interfaces" {
|
||||
label: string;
|
||||
shortLabel: string;
|
||||
type?: string;
|
||||
range?: string;
|
||||
rangeType?: string;
|
||||
loadouts?: LoadoutBlueprint[];
|
||||
filename?: string;
|
||||
liveries?: {
|
||||
@ -544,6 +546,14 @@ declare module "interfaces" {
|
||||
cost?: number;
|
||||
barrelHeight?: number;
|
||||
muzzleVelocity?: number;
|
||||
aimTime?: number;
|
||||
shotsToFire?: number;
|
||||
description?: string;
|
||||
abilities?: string;
|
||||
acquisitionRange?: number;
|
||||
engagementRange?: number;
|
||||
refuelsFrom?: string;
|
||||
refuelingType?: string;
|
||||
}
|
||||
export interface UnitSpawnOptions {
|
||||
roleType: string;
|
||||
@ -721,6 +731,7 @@ declare module "other/utils" {
|
||||
export function enumToReactionToThreat(reactionToThreat: number): string;
|
||||
export function enumToEmissioNCountermeasure(emissionCountermeasure: number): string;
|
||||
export function enumToCoalition(coalitionID: number): "" | "blue" | "red" | "neutral";
|
||||
export function coalitionToEnum(coalition: string): 0 | 1 | 2;
|
||||
export function convertDateAndTimeToDate(dateAndTime: DateAndTime): Date;
|
||||
export function createCheckboxOption(value: string, text: string, checked?: boolean, callback?: CallableFunction): HTMLElement;
|
||||
export function getCheckboxOptions(dropdown: Dropdown): {
|
||||
@ -752,6 +763,7 @@ declare module "controls/unitspawnmenu" {
|
||||
import { UnitSpawnOptions } from "interfaces";
|
||||
export class UnitSpawnMenu {
|
||||
#private;
|
||||
spawnOptions: UnitSpawnOptions;
|
||||
constructor(ID: string, unitDatabase: UnitDatabase, orderByRole: boolean);
|
||||
getContainer(): HTMLElement;
|
||||
reset(): void;
|
||||
@ -1023,6 +1035,7 @@ declare module "unit/unit" {
|
||||
getContacts(): Contact[];
|
||||
getActivePath(): LatLng[];
|
||||
getIsLeader(): boolean;
|
||||
getOperateAs(): string;
|
||||
static getConstructor(type: string): typeof GroundUnit | undefined;
|
||||
constructor(ID: number);
|
||||
getCategory(): string;
|
||||
@ -1078,6 +1091,7 @@ declare module "unit/unit" {
|
||||
setEmissionsCountermeasures(emissionCountermeasure: string): void;
|
||||
setOnOff(onOff: boolean): void;
|
||||
setFollowRoads(followRoads: boolean): void;
|
||||
setOperateAs(operateAs: string): void;
|
||||
delete(explosion: boolean, immediate: boolean): void;
|
||||
refuel(): void;
|
||||
setAdvancedOptions(isTanker: boolean, isAWACS: boolean, TACAN: TACAN, radio: Radio, generalSettings: GeneralSettings): void;
|
||||
@ -1086,8 +1100,20 @@ declare module "unit/unit" {
|
||||
bombBuilding(latlng: LatLng): void;
|
||||
fireAtArea(latlng: LatLng): void;
|
||||
simulateFireFight(latlng: LatLng, targetGroundElevation: number | null): void;
|
||||
scenicAAA(): void;
|
||||
missOnPurpose(): void;
|
||||
/***********************************************/
|
||||
getActions(): {
|
||||
[key: string]: {
|
||||
text: string;
|
||||
tooltip: string;
|
||||
type: string;
|
||||
};
|
||||
};
|
||||
executeAction(e: any, action: string): void;
|
||||
/***********************************************/
|
||||
onAdd(map: Map): this;
|
||||
getActionOptions(): {};
|
||||
}
|
||||
export class AirUnit extends Unit {
|
||||
getIconOptions(): {
|
||||
@ -1102,6 +1128,13 @@ declare module "unit/unit" {
|
||||
showCallsign: boolean;
|
||||
rotateToHeading: boolean;
|
||||
};
|
||||
getActions(): {
|
||||
[key: string]: {
|
||||
text: string;
|
||||
tooltip: string;
|
||||
type: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
export class Aircraft extends AirUnit {
|
||||
constructor(ID: number);
|
||||
@ -1125,6 +1158,13 @@ declare module "unit/unit" {
|
||||
showCallsign: boolean;
|
||||
rotateToHeading: boolean;
|
||||
};
|
||||
getActions(): {
|
||||
[key: string]: {
|
||||
text: string;
|
||||
tooltip: string;
|
||||
type: string;
|
||||
};
|
||||
};
|
||||
getCategory(): string;
|
||||
getType(): string;
|
||||
}
|
||||
@ -1142,6 +1182,13 @@ declare module "unit/unit" {
|
||||
showCallsign: boolean;
|
||||
rotateToHeading: boolean;
|
||||
};
|
||||
getActions(): {
|
||||
[key: string]: {
|
||||
text: string;
|
||||
tooltip: string;
|
||||
type: string;
|
||||
};
|
||||
};
|
||||
getMarkerCategory(): string;
|
||||
getCategory(): string;
|
||||
getType(): string;
|
||||
@ -1310,6 +1357,14 @@ declare module "popups/popup" {
|
||||
declare module "map/touchboxselect" {
|
||||
export var TouchBoxSelect: (new (...args: any[]) => any) & typeof import("leaflet").Class;
|
||||
}
|
||||
declare module "map/markers/destinationpreviewHandle" {
|
||||
import { LatLng } from "leaflet";
|
||||
import { CustomMarker } from "map/markers/custommarker";
|
||||
export class DestinationPreviewHandle extends CustomMarker {
|
||||
constructor(latlng: LatLng);
|
||||
createIcon(): void;
|
||||
}
|
||||
}
|
||||
declare module "map/map" {
|
||||
import * as L from "leaflet";
|
||||
import { MapContextMenu } from "contextmenus/mapcontextmenu";
|
||||
@ -1414,7 +1469,9 @@ declare module "panels/connectionstatuspanel" {
|
||||
import { Panel } from "panels/panel";
|
||||
export class ConnectionStatusPanel extends Panel {
|
||||
constructor(ID: string);
|
||||
update(connected: boolean): void;
|
||||
showDisconnected(): void;
|
||||
showConnected(): void;
|
||||
showServerPaused(): void;
|
||||
}
|
||||
}
|
||||
declare module "panels/hotgrouppanel" {
|
||||
@ -1615,7 +1672,7 @@ declare module "unit/unitsmanager" {
|
||||
*
|
||||
* @param hotgroup The hotgroup number
|
||||
*/
|
||||
selectUnitsByHotgroup(hotgroup: number): void;
|
||||
selectUnitsByHotgroup(hotgroup: number, deselectAllUnits?: boolean): void;
|
||||
/** Get all the currently selected units
|
||||
*
|
||||
* @param options Selection options
|
||||
@ -1728,6 +1785,11 @@ declare module "unit/unitsmanager" {
|
||||
* @param followRoads If true, units will follow roads
|
||||
*/
|
||||
selectedUnitsSetFollowRoads(followRoads: boolean): void;
|
||||
/** Instruct selected units to operate as a certain coalition
|
||||
*
|
||||
* @param operateAsBool If true, units will operate as blue
|
||||
*/
|
||||
selectedUnitsSetOperateAs(operateAsBool: boolean): void;
|
||||
/** Instruct units to attack a specific unit
|
||||
*
|
||||
* @param ID ID of the unit to attack
|
||||
@ -1768,6 +1830,14 @@ declare module "unit/unitsmanager" {
|
||||
* @param latlng Location to fire at
|
||||
*/
|
||||
selectedUnitsSimulateFireFight(latlng: LatLng): void;
|
||||
/** Instruct units to enter into scenic AAA mode. Units will shoot in the air without aiming
|
||||
*
|
||||
*/
|
||||
selectedUnitsScenicAAA(): void;
|
||||
/** Instruct units to enter into miss on purpose mode. Units will aim to the nearest enemy unit but not precisely.
|
||||
*
|
||||
*/
|
||||
selectedUnitsMissOnPurpose(): void;
|
||||
/*********************** Control operations on selected units ************************/
|
||||
/** See getUnitsCategories for more info
|
||||
*
|
||||
@ -1948,12 +2018,15 @@ declare module "server/servermanager" {
|
||||
setEmissionsCountermeasures(ID: number, emissionCountermeasure: string, callback?: CallableFunction): void;
|
||||
setOnOff(ID: number, onOff: boolean, callback?: CallableFunction): void;
|
||||
setFollowRoads(ID: number, followRoads: boolean, callback?: CallableFunction): void;
|
||||
setOperateAs(ID: number, operateAs: number, callback?: CallableFunction): void;
|
||||
refuel(ID: number, callback?: CallableFunction): void;
|
||||
bombPoint(ID: number, latlng: LatLng, callback?: CallableFunction): void;
|
||||
carpetBomb(ID: number, latlng: LatLng, callback?: CallableFunction): void;
|
||||
bombBuilding(ID: number, latlng: LatLng, callback?: CallableFunction): void;
|
||||
fireAtArea(ID: number, latlng: LatLng, callback?: CallableFunction): void;
|
||||
simulateFireFight(ID: number, latlng: LatLng, altitude: number, callback?: CallableFunction): void;
|
||||
scenicAAA(ID: number, coalition: string, callback?: CallableFunction): void;
|
||||
missOnPurpose(ID: number, coalition: string, callback?: CallableFunction): void;
|
||||
setAdvacedOptions(ID: number, isTanker: boolean, isAWACS: boolean, TACAN: TACAN, radio: Radio, generalSettings: GeneralSettings, callback?: CallableFunction): void;
|
||||
setCommandModeOptions(restrictSpawns: boolean, restrictToCoalition: boolean, spawnPoints: {
|
||||
blue: number;
|
||||
@ -1967,14 +2040,14 @@ declare module "server/servermanager" {
|
||||
getConnected(): boolean;
|
||||
setPaused(newPaused: boolean): void;
|
||||
getPaused(): boolean;
|
||||
getServerIsPaused(): boolean;
|
||||
}
|
||||
}
|
||||
declare module "panels/unitlistpanel" {
|
||||
import { OlympusApp } from "olympusapp";
|
||||
import { Panel } from "panels/panel";
|
||||
export class UnitListPanel extends Panel {
|
||||
#private;
|
||||
constructor(olympusApp: OlympusApp, panelElement: string, contentElement: string);
|
||||
constructor(panelElement: string, contentElement: string);
|
||||
doUpdate(): void;
|
||||
getContentElement(): HTMLElement;
|
||||
startUpdates(): void;
|
||||
|
||||
@ -48,7 +48,7 @@ const DEMO_UNIT_DATA = {
|
||||
ammo: [{ quantity: 2, name: "A cool missile", guidance: 0, category: 0, missileCategory: 0 } ],
|
||||
contacts: [{ID: 1, detectionMethod: 16}],
|
||||
activePath: [ ]
|
||||
}, ["4"]:{ category: "GroundUnit", alive: true, human: false, controlled: true, coalition: 1, country: 0, name: "Gepard", unitName: "Cool guy 2-1", groupName: "Cool group 4", state: 1, task: "Being cool",
|
||||
}, ["4"]:{ category: "GroundUnit", alive: true, human: false, controlled: true, coalition: 0, country: 0, name: "Gepard", 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, isTanker: false, isAWACS: false, onOff: true, followRoads: false, fuel: 50,
|
||||
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
|
||||
formationOffset: { x: 0, y: 0, z: 0 },
|
||||
@ -63,8 +63,9 @@ const DEMO_UNIT_DATA = {
|
||||
ammo: [{ quantity: 2, name: "A cool missile\0Ciao", guidance: 0, category: 0, missileCategory: 0 } ],
|
||||
contacts: [{ID: 1001, detectionMethod: 16}],
|
||||
activePath: [ ],
|
||||
isLeader: true
|
||||
}, ["5"]:{ category: "GroundUnit", alive: true, human: false, controlled: true, coalition: 1, country: 0, name: "S_75M_Volhov", unitName: "Cool guy 2-2", groupName: "Cool group 4", state: 1, task: "Being cool",
|
||||
isLeader: true,
|
||||
operateAs: 2
|
||||
}, ["5"]:{ category: "GroundUnit", alive: true, human: false, controlled: true, coalition: 0, 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, isTanker: false, isAWACS: false, onOff: true, followRoads: false, fuel: 50,
|
||||
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
|
||||
formationOffset: { x: 0, y: 0, z: 0 },
|
||||
@ -79,7 +80,8 @@ const DEMO_UNIT_DATA = {
|
||||
ammo: [{ quantity: 2, name: "A cool missile", guidance: 0, category: 0, missileCategory: 0 } ],
|
||||
contacts: [],
|
||||
activePath: [ ],
|
||||
isLeader: false
|
||||
isLeader: false,
|
||||
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, isTanker: false, isAWACS: false, onOff: true, followRoads: false, fuel: 50,
|
||||
@ -187,6 +189,7 @@ class DemoDataGenerator {
|
||||
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.concat(array, this.uint8ToByteArray(255));
|
||||
}
|
||||
res.end(Buffer.from(array, 'binary'));
|
||||
|
||||
@ -44,6 +44,8 @@ export class AirUnitEditor extends UnitEditor {
|
||||
addDropdownInput(this.contentDiv2, "Era", blueprint.era, ["WW2", "Early Cold War", "Mid Cold War", "Late Cold War", "Modern"]);
|
||||
addStringInput(this.contentDiv2, "Filename", blueprint.filename ?? "", "text", (value: string) => { blueprint.filename = value; });
|
||||
addStringInput(this.contentDiv2, "Cost", String(blueprint.cost) ?? "", "number", (value: string) => { blueprint.cost = parseFloat(value); });
|
||||
addStringInput(this.contentDiv2, "Rufels from", String(blueprint.refuelsFrom) ?? "", "text", (value: string) => { blueprint.refuelsFrom = value; });
|
||||
addStringInput(this.contentDiv2, "Refueling type", String(blueprint.refuelingType) ?? "", "text", (value: string) => { blueprint.refuelingType = value; });
|
||||
|
||||
/* Add a scrollable list of loadouts that the user can edit */
|
||||
var title = document.createElement("label");
|
||||
|
||||
@ -157,7 +157,7 @@ export class DatabaseManagerPlugin implements OlympusPlugin {
|
||||
*/
|
||||
initialize(app: any) {
|
||||
this.#app = app;
|
||||
|
||||
|
||||
/* Load the databases and initialize the editors */
|
||||
this.#loadDatabases();
|
||||
|
||||
@ -173,9 +173,10 @@ export class DatabaseManagerPlugin implements OlympusPlugin {
|
||||
toolbar.getMainDropdown().setOptionsElements(arr);
|
||||
mainButton.onclick = () => {
|
||||
toolbar.getMainDropdown().close();
|
||||
this.toggle();
|
||||
if (this.#app?.getMissionManager().getCommandModeOptions().commandMode === "Game master")
|
||||
this.toggle();
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -34,8 +34,12 @@ export class GroundUnitEditor extends UnitEditor {
|
||||
addDropdownInput(this.contentDiv2, "Era", blueprint.era, ["WW2", "Early Cold War", "Mid Cold War", "Late Cold War", "Modern"]);
|
||||
//addStringInput(this.contentDiv2, "Filename", blueprint.filename?? "", "text", (value: string) => {blueprint.filename = value; });
|
||||
addStringInput(this.contentDiv2, "Cost", String(blueprint.cost)?? "", "number", (value: string) => {blueprint.cost = parseFloat(value); });
|
||||
addStringInput(this.contentDiv2, "Acquisition range [NM]", String(blueprint.acquisitionRange)?? "", "number", (value: string) => {blueprint.acquisitionRange = parseFloat(value); });
|
||||
addStringInput(this.contentDiv2, "Engagement range [NM]", String(blueprint.engagementRange)?? "", "number", (value: string) => {blueprint.engagementRange = 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)); });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -9,15 +9,16 @@
|
||||
z-index: 9999999;
|
||||
}
|
||||
|
||||
@media (orientation: landscape) {
|
||||
@media (min-width: 1200px) {
|
||||
.dm-container {
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
|
||||
@media (orientation: portrait) {
|
||||
@media (max-width: 1200px) {
|
||||
.dm-container {
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,14 +57,6 @@
|
||||
border-radius: 0px 5px 5px 5px;
|
||||
}
|
||||
|
||||
.dm-container>div:nth-child(2) {
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
.dm-container>div:nth-child(3) {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.dm-content-container {
|
||||
position: relative;
|
||||
margin: 10px;
|
||||
@ -72,19 +65,40 @@
|
||||
row-gap: 5px;
|
||||
}
|
||||
|
||||
@media (orientation: landscape) {
|
||||
@media (min-width: 1200px) {
|
||||
.dm-content-container {
|
||||
height: calc(100% - 20px);
|
||||
min-width: 200px;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.dm-content-container:nth-of-type(1) {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.dm-content-container:nth-of-type(2) {
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
.dm-content-container:nth-of-type(3) {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (orientation: portrait) {
|
||||
@media (max-width: 1200px) {
|
||||
.dm-content-container {
|
||||
width: 100% - calc(20px);
|
||||
width: calc(100% - 20px);
|
||||
}
|
||||
|
||||
.dm-content-container:nth-of-type(1) {
|
||||
height: 30%;
|
||||
}
|
||||
|
||||
.dm-content-container:nth-of-type(2) {
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
.dm-content-container:nth-of-type(3) {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.dm-content-container>label {
|
||||
@ -95,7 +109,7 @@
|
||||
.dm-scroll-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
overflow-y: scroll;
|
||||
max-height: 100%;
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
@ -113,7 +127,6 @@
|
||||
height: 100%;
|
||||
width: calc(100% - 25px);
|
||||
padding: 2px;
|
||||
text-wrap: wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
@ -141,6 +154,15 @@
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.dm-content-container label {
|
||||
width: 100%;
|
||||
}
|
||||
.input-row {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.input-row>dt {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
@ -3485,7 +3485,24 @@
|
||||
"shortLabel": "S60",
|
||||
"loadouts": [
|
||||
{
|
||||
"items": [],
|
||||
"items": [
|
||||
{
|
||||
"name": "",
|
||||
"quantity": 1
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"quantity": 1
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"quantity": 1
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"quantity": 1
|
||||
}
|
||||
],
|
||||
"enabled": true,
|
||||
"code": "",
|
||||
"name": "Empty loadout",
|
||||
@ -3498,6 +3515,30 @@
|
||||
{
|
||||
"name": "AGM-119B Penguin ASM",
|
||||
"quantity": 1
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"quantity": 1
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"quantity": 1
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"quantity": 1
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"quantity": 1
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"quantity": 1
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"quantity": 1
|
||||
}
|
||||
],
|
||||
"enabled": true,
|
||||
@ -3506,6 +3547,20 @@
|
||||
"roles": [
|
||||
"Antiship Strike"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "asd",
|
||||
"code": "",
|
||||
"fuel": 1,
|
||||
"items": [],
|
||||
"roles": []
|
||||
},
|
||||
{
|
||||
"name": "asd",
|
||||
"code": "",
|
||||
"fuel": 1,
|
||||
"items": [],
|
||||
"roles": []
|
||||
}
|
||||
],
|
||||
"filename": "uh-60.png",
|
||||
|
||||
@ -10,17 +10,6 @@
|
||||
"filename": "",
|
||||
"enabled": true
|
||||
},
|
||||
"Boat Armed Hi-Speed": {
|
||||
"name": "Boat Armed Hi-Speed",
|
||||
"coalition": "",
|
||||
"type": "Fast Attack Craft",
|
||||
"era": "Mid Cold War",
|
||||
"label": "Boat Armed Hi-Speed",
|
||||
"shortLabel": "Boat Armed Hi-Speed",
|
||||
"range": "",
|
||||
"filename": "",
|
||||
"enabled": true
|
||||
},
|
||||
"CVN_71": {
|
||||
"name": "CVN_71",
|
||||
"coalition": "blue",
|
||||
@ -98,17 +87,6 @@
|
||||
"filename": "",
|
||||
"enabled": true
|
||||
},
|
||||
"CV_59": {
|
||||
"name": "CV_59",
|
||||
"coalition": "blue",
|
||||
"type": "Aircraft Carrier",
|
||||
"era": "Early Cold War",
|
||||
"label": "CV-59 Forrestal",
|
||||
"shortLabel": "CV-59",
|
||||
"range": "Short",
|
||||
"filename": "",
|
||||
"enabled": true
|
||||
},
|
||||
"CastleClass_01": {
|
||||
"name": "CastleClass_01",
|
||||
"coalition": "blue",
|
||||
@ -966,55 +944,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"albatros": {
|
||||
"name": "albatros",
|
||||
"coalition": "red",
|
||||
"type": "Aircraft Carrier",
|
||||
"era": "Early Cold War",
|
||||
"label": "Albatros (Grisha-5)",
|
||||
"shortLabel": "Albatros",
|
||||
"range": "",
|
||||
"filename": "",
|
||||
"enabled": true,
|
||||
"liveries": {
|
||||
"141": {
|
||||
"name": "141",
|
||||
"countries": "All"
|
||||
},
|
||||
"142": {
|
||||
"name": "142",
|
||||
"countries": "All"
|
||||
},
|
||||
"143": {
|
||||
"name": "143",
|
||||
"countries": "All"
|
||||
},
|
||||
"144": {
|
||||
"name": "144",
|
||||
"countries": "All"
|
||||
},
|
||||
"145": {
|
||||
"name": "145",
|
||||
"countries": "All"
|
||||
},
|
||||
"146": {
|
||||
"name": "146",
|
||||
"countries": "All"
|
||||
},
|
||||
"147": {
|
||||
"name": "147",
|
||||
"countries": "All"
|
||||
},
|
||||
"148": {
|
||||
"name": "148",
|
||||
"countries": "All"
|
||||
},
|
||||
"149": {
|
||||
"name": "149",
|
||||
"countries": "All"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ara_vdm": {
|
||||
"name": "ara_vdm",
|
||||
"coalition": "",
|
||||
@ -1026,53 +955,6 @@
|
||||
"filename": "",
|
||||
"enabled": true
|
||||
},
|
||||
"barge-1": {
|
||||
"name": "barge-1",
|
||||
"coalition": "red",
|
||||
"type": "Cargoship",
|
||||
"era": "Late Cold War",
|
||||
"label": "Dry cargo ship Ivanov",
|
||||
"shortLabel": "Dry cargo ship Ivanov",
|
||||
"range": "",
|
||||
"filename": "",
|
||||
"enabled": true
|
||||
},
|
||||
"barge-2": {
|
||||
"name": "barge-2",
|
||||
"coalition": "red",
|
||||
"type": "Cargoship",
|
||||
"era": "Late Cold War",
|
||||
"label": "Dry cargo ship Yakushev",
|
||||
"shortLabel": "Dry cargo ship Yakushev",
|
||||
"range": "",
|
||||
"filename": "",
|
||||
"enabled": true
|
||||
},
|
||||
"elnya": {
|
||||
"name": "elnya",
|
||||
"coalition": "red",
|
||||
"type": "Tanker",
|
||||
"era": "Late Cold War",
|
||||
"label": "Elnya tanker",
|
||||
"shortLabel": "Elnya tanker",
|
||||
"range": "",
|
||||
"filename": "",
|
||||
"enabled": true,
|
||||
"liveries": {
|
||||
"952": {
|
||||
"name": "952",
|
||||
"countries": "All"
|
||||
},
|
||||
"953": {
|
||||
"name": "953",
|
||||
"countries": "All"
|
||||
},
|
||||
"954": {
|
||||
"name": "954",
|
||||
"countries": "All"
|
||||
}
|
||||
}
|
||||
},
|
||||
"hms_invincible": {
|
||||
"name": "hms_invincible",
|
||||
"coalition": "blue",
|
||||
@ -1084,39 +966,6 @@
|
||||
"filename": "",
|
||||
"enabled": true
|
||||
},
|
||||
"kilo": {
|
||||
"name": "kilo",
|
||||
"coalition": "red",
|
||||
"type": "Submarine",
|
||||
"era": "Late Cold War",
|
||||
"label": "Project 636 Varshavyanka Basic",
|
||||
"shortLabel": "Varshavyanka Basic",
|
||||
"range": "Medium",
|
||||
"filename": "",
|
||||
"enabled": true
|
||||
},
|
||||
"kilo_636": {
|
||||
"name": "kilo_636",
|
||||
"coalition": "red",
|
||||
"type": "Submarine",
|
||||
"era": "Late Cold War",
|
||||
"label": "Project 636 Varshavyanka Improved",
|
||||
"shortLabel": "Varshavyanka Improved",
|
||||
"range": "Medium",
|
||||
"filename": "",
|
||||
"enabled": true
|
||||
},
|
||||
"kuznecow": {
|
||||
"name": "kuznecow",
|
||||
"coalition": "red",
|
||||
"type": "Aircraft Carrier",
|
||||
"era": "Late Cold War",
|
||||
"label": "Admiral Kuznetsov",
|
||||
"shortLabel": "Admiral Kuznetsov",
|
||||
"range": "Medium",
|
||||
"filename": "",
|
||||
"enabled": true
|
||||
},
|
||||
"leander-gun-achilles": {
|
||||
"name": "leander-gun-achilles",
|
||||
"coalition": "blue",
|
||||
@ -1172,72 +1021,38 @@
|
||||
"filename": "",
|
||||
"enabled": true
|
||||
},
|
||||
"molniya": {
|
||||
"name": "molniya",
|
||||
"santafe": {
|
||||
"name": "santafe",
|
||||
"coalition": "",
|
||||
"type": "Fast Attack Craft",
|
||||
"era": "Late Cold War",
|
||||
"label": "Molniya (Tarantul-3)",
|
||||
"shortLabel": "Molniya",
|
||||
"range": "Short",
|
||||
"filename": "",
|
||||
"enabled": true,
|
||||
"liveries": {
|
||||
"952": {
|
||||
"name": "952",
|
||||
"countries": "All"
|
||||
},
|
||||
"953": {
|
||||
"name": "953",
|
||||
"countries": "All"
|
||||
},
|
||||
"954": {
|
||||
"name": "954",
|
||||
"countries": "All"
|
||||
}
|
||||
}
|
||||
},
|
||||
"moscow": {
|
||||
"name": "moscow",
|
||||
"coalition": "red",
|
||||
"type": "Cruiser",
|
||||
"era": "Late Cold War",
|
||||
"label": "Moscow",
|
||||
"shortLabel": "Moscow",
|
||||
"range": "Medium",
|
||||
"filename": "",
|
||||
"enabled": true,
|
||||
"liveries": {
|
||||
"default": {
|
||||
"name": "default",
|
||||
"countries": "All"
|
||||
},
|
||||
"cow1": {
|
||||
"name": "cow1",
|
||||
"countries": "All"
|
||||
},
|
||||
"cow3": {
|
||||
"name": "cow3",
|
||||
"countries": "All"
|
||||
},
|
||||
"cow2": {
|
||||
"name": "cow2",
|
||||
"countries": "All"
|
||||
}
|
||||
}
|
||||
},
|
||||
"neustrash": {
|
||||
"name": "neustrash",
|
||||
"coalition": "red",
|
||||
"type": "Frigate",
|
||||
"era": "Late Cold War",
|
||||
"label": "Neustrashimy",
|
||||
"shortLabel": "Neustrashimy",
|
||||
"range": "Short",
|
||||
"type": "Submarine",
|
||||
"era": "Early Cold War",
|
||||
"label": "ARA Santa Fe S-21",
|
||||
"shortLabel": "ARA Santa",
|
||||
"range": "",
|
||||
"filename": "",
|
||||
"enabled": true
|
||||
},
|
||||
"perry": {
|
||||
"speedboat": {
|
||||
"name": "speedboat",
|
||||
"coalition": "",
|
||||
"era": "",
|
||||
"label": "Boat Armed Hi-speed",
|
||||
"shortLabel": "Boat Armed Hi-speed",
|
||||
"type": "Speedboat",
|
||||
"enabled": true,
|
||||
"liveries": {}
|
||||
},
|
||||
"VINSON": {
|
||||
"name": "VINSON",
|
||||
"coalition": "",
|
||||
"era": "",
|
||||
"label": "CVN-70 Carl Vinson",
|
||||
"shortLabel": "CVN-70 Carl Vinson",
|
||||
"type": "Aircraft Carrier",
|
||||
"enabled": true,
|
||||
"liveries": {}
|
||||
},
|
||||
"PERRY": {
|
||||
"name": "perry",
|
||||
"coalition": "blue",
|
||||
"type": "Frigate",
|
||||
@ -1290,18 +1105,142 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"piotr_velikiy": {
|
||||
"name": "piotr_velikiy",
|
||||
"ALBATROS": {
|
||||
"name": "albatros",
|
||||
"coalition": "red",
|
||||
"type": "Cruiser",
|
||||
"type": "Frigade",
|
||||
"era": "Early Cold War",
|
||||
"label": "Albatros (Grisha-5)",
|
||||
"shortLabel": "Albatros",
|
||||
"range": "",
|
||||
"filename": "",
|
||||
"enabled": true,
|
||||
"liveries": {
|
||||
"141": {
|
||||
"name": "141",
|
||||
"countries": "All"
|
||||
},
|
||||
"142": {
|
||||
"name": "142",
|
||||
"countries": "All"
|
||||
},
|
||||
"143": {
|
||||
"name": "143",
|
||||
"countries": "All"
|
||||
},
|
||||
"144": {
|
||||
"name": "144",
|
||||
"countries": "All"
|
||||
},
|
||||
"145": {
|
||||
"name": "145",
|
||||
"countries": "All"
|
||||
},
|
||||
"146": {
|
||||
"name": "146",
|
||||
"countries": "All"
|
||||
},
|
||||
"147": {
|
||||
"name": "147",
|
||||
"countries": "All"
|
||||
},
|
||||
"148": {
|
||||
"name": "148",
|
||||
"countries": "All"
|
||||
},
|
||||
"149": {
|
||||
"name": "149",
|
||||
"countries": "All"
|
||||
}
|
||||
}
|
||||
},
|
||||
"KUZNECOW": {
|
||||
"name": "kuznecow",
|
||||
"coalition": "red",
|
||||
"type": "Aircraft Carrier",
|
||||
"era": "Late Cold War",
|
||||
"label": "Pyotr Velikiy",
|
||||
"shortLabel": "Pyotr Velikiy",
|
||||
"label": "Admiral Kuznetsov",
|
||||
"shortLabel": "Admiral Kuznetsov",
|
||||
"range": "Medium",
|
||||
"filename": "",
|
||||
"enabled": true
|
||||
},
|
||||
"rezky": {
|
||||
"MOLNIYA": {
|
||||
"name": "molniya",
|
||||
"coalition": "",
|
||||
"type": "Corvette",
|
||||
"era": "Late Cold War",
|
||||
"label": "Molniya (Tarantul-3)",
|
||||
"shortLabel": "Molniya",
|
||||
"range": "Short",
|
||||
"filename": "",
|
||||
"enabled": true,
|
||||
"liveries": {
|
||||
"952": {
|
||||
"name": "952",
|
||||
"countries": "All"
|
||||
},
|
||||
"953": {
|
||||
"name": "953",
|
||||
"countries": "All"
|
||||
},
|
||||
"954": {
|
||||
"name": "954",
|
||||
"countries": "All"
|
||||
}
|
||||
}
|
||||
},
|
||||
"MOSCOW": {
|
||||
"name": "moscow",
|
||||
"coalition": "red",
|
||||
"type": "Cruiser",
|
||||
"era": "Late Cold War",
|
||||
"label": "Moscow",
|
||||
"shortLabel": "Moscow",
|
||||
"range": "Medium",
|
||||
"filename": "",
|
||||
"enabled": true,
|
||||
"liveries": {
|
||||
"default": {
|
||||
"name": "default",
|
||||
"countries": "All"
|
||||
},
|
||||
"cow1": {
|
||||
"name": "cow1",
|
||||
"countries": "All"
|
||||
},
|
||||
"cow3": {
|
||||
"name": "cow3",
|
||||
"countries": "All"
|
||||
},
|
||||
"cow2": {
|
||||
"name": "cow2",
|
||||
"countries": "All"
|
||||
}
|
||||
}
|
||||
},
|
||||
"NEUSTRASH": {
|
||||
"name": "neustrash",
|
||||
"coalition": "red",
|
||||
"type": "Frigate",
|
||||
"era": "Late Cold War",
|
||||
"label": "Neustrashimy",
|
||||
"shortLabel": "Neustrashimy",
|
||||
"range": "Short",
|
||||
"filename": "",
|
||||
"enabled": true
|
||||
},
|
||||
"PIOTR": {
|
||||
"name": "PIOTR",
|
||||
"coalition": "",
|
||||
"era": "",
|
||||
"label": "Battlecruiser 1144.2 Pyotr Velikiy",
|
||||
"shortLabel": "Battlecruiser 1144.2 Pyotr Velikiy",
|
||||
"type": "Cruiser",
|
||||
"enabled": true,
|
||||
"liveries": {}
|
||||
},
|
||||
"REZKY": {
|
||||
"name": "Rezky (Krivak-2)",
|
||||
"coalition": "red",
|
||||
"type": "Frigate",
|
||||
@ -1312,18 +1251,52 @@
|
||||
"filename": "",
|
||||
"enabled": true
|
||||
},
|
||||
"santafe": {
|
||||
"name": "santafe",
|
||||
"coalition": "",
|
||||
"type": "Submarine",
|
||||
"era": "Early Cold War",
|
||||
"label": "ARA Santa Fe S-21",
|
||||
"shortLabel": "ARA Santa",
|
||||
"ELNYA": {
|
||||
"name": "elnya",
|
||||
"coalition": "red",
|
||||
"type": "Tanker",
|
||||
"era": "Late Cold War",
|
||||
"label": "Elnya tanker",
|
||||
"shortLabel": "Elnya tanker",
|
||||
"range": "",
|
||||
"filename": "",
|
||||
"enabled": true
|
||||
"enabled": true,
|
||||
"liveries": {
|
||||
"952": {
|
||||
"name": "952",
|
||||
"countries": "All"
|
||||
},
|
||||
"953": {
|
||||
"name": "953",
|
||||
"countries": "All"
|
||||
},
|
||||
"954": {
|
||||
"name": "954",
|
||||
"countries": "All"
|
||||
}
|
||||
}
|
||||
},
|
||||
"zwezdny": {
|
||||
"Dry-cargo ship-2": {
|
||||
"name": "Dry-cargo ship-2",
|
||||
"coalition": "",
|
||||
"era": "",
|
||||
"label": "Cargo Ivanov",
|
||||
"shortLabel": "Cargo Ivanov",
|
||||
"type": "Cargo",
|
||||
"enabled": true,
|
||||
"liveries": {}
|
||||
},
|
||||
"Dry-cargo ship-1": {
|
||||
"name": "Dry-cargo ship-1",
|
||||
"coalition": "",
|
||||
"era": "",
|
||||
"label": "Bulker Yakushev",
|
||||
"shortLabel": "Bulker Yakushev",
|
||||
"type": "Cargo",
|
||||
"enabled": true,
|
||||
"liveries": {}
|
||||
},
|
||||
"ZWEZDNY": {
|
||||
"name": "zwezdny",
|
||||
"coalition": "",
|
||||
"type": "Civilian Boat",
|
||||
@ -1333,5 +1306,96 @@
|
||||
"range": "",
|
||||
"filename": "",
|
||||
"enabled": true
|
||||
},
|
||||
"KILO": {
|
||||
"name": "kilo",
|
||||
"coalition": "red",
|
||||
"type": "Submarine",
|
||||
"era": "Late Cold War",
|
||||
"label": "Project 636 Varshavyanka Basic",
|
||||
"shortLabel": "Varshavyanka Basic",
|
||||
"range": "Medium",
|
||||
"filename": "",
|
||||
"enabled": true
|
||||
},
|
||||
"IMPROVED_KILO": {
|
||||
"name": "IMPROVED_KILO",
|
||||
"coalition": "",
|
||||
"era": "",
|
||||
"label": "SSK 636 Improved Kilo",
|
||||
"shortLabel": "SSK 636 Improved Kilo",
|
||||
"type": "Submarine",
|
||||
"enabled": true,
|
||||
"liveries": {}
|
||||
},
|
||||
"SOM": {
|
||||
"name": "SOM",
|
||||
"coalition": "",
|
||||
"era": "",
|
||||
"label": "SSK 641B Tango",
|
||||
"shortLabel": "SSK 641B Tango",
|
||||
"type": "SOM",
|
||||
"enabled": true,
|
||||
"liveries": {}
|
||||
},
|
||||
"Forrestal": {
|
||||
"name": "Forrestal",
|
||||
"coalition": "",
|
||||
"era": "",
|
||||
"label": "CV-59 Forrestal",
|
||||
"shortLabel": "CV-59 Forrestal",
|
||||
"type": "Forrestal",
|
||||
"enabled": true,
|
||||
"liveries": {}
|
||||
},
|
||||
"LST_Mk2": {
|
||||
"name": "LST_Mk2",
|
||||
"coalition": "",
|
||||
"era": "",
|
||||
"label": "LST Mk.II",
|
||||
"shortLabel": "LST Mk.II",
|
||||
"type": "LST_Mk2",
|
||||
"enabled": true,
|
||||
"liveries": {}
|
||||
},
|
||||
"USS_Samuel_Chase": {
|
||||
"name": "USS_Samuel_Chase",
|
||||
"coalition": "",
|
||||
"era": "",
|
||||
"label": "LS Samuel Chase",
|
||||
"shortLabel": "LS Samuel Chase",
|
||||
"type": "USS_Samuel_Chase",
|
||||
"enabled": true,
|
||||
"liveries": {}
|
||||
},
|
||||
"Higgins_boat": {
|
||||
"name": "Higgins_boat",
|
||||
"coalition": "",
|
||||
"era": "",
|
||||
"label": "Boat LCVP Higgins",
|
||||
"shortLabel": "Boat LCVP Higgins",
|
||||
"type": "Higgins_boat",
|
||||
"enabled": true,
|
||||
"liveries": {}
|
||||
},
|
||||
"Uboat_VIIC": {
|
||||
"name": "Uboat_VIIC",
|
||||
"coalition": "",
|
||||
"era": "",
|
||||
"label": "U-boat VIIC U-flak",
|
||||
"shortLabel": "U-boat VIIC U-flak",
|
||||
"type": "Uboat_VIIC",
|
||||
"enabled": true,
|
||||
"liveries": {}
|
||||
},
|
||||
"Schnellboot_type_S130": {
|
||||
"name": "Schnellboot_type_S130",
|
||||
"coalition": "",
|
||||
"era": "",
|
||||
"label": "Boat Schnellboot type S130",
|
||||
"shortLabel": "Boat Schnellboot type S130",
|
||||
"type": "Schnellboot_type_S130",
|
||||
"enabled": true,
|
||||
"liveries": {}
|
||||
}
|
||||
}
|
||||
@ -326,9 +326,9 @@
|
||||
#unit-contextmenu div:before {
|
||||
display: inline-block;
|
||||
filter: invert(100%);
|
||||
height: 16px;
|
||||
height: 20px;
|
||||
margin-right: 15px;
|
||||
width: 16px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.ol-select>.ol-select-options>div button.country-dropdown-element {
|
||||
@ -377,6 +377,22 @@
|
||||
content: url("/resources/theme/images/icons/follow.svg");
|
||||
}
|
||||
|
||||
#scenic-aaa::before {
|
||||
content: url("/resources/theme/images/icons/scenic.svg");
|
||||
}
|
||||
|
||||
#miss-aaa::before {
|
||||
content: url("/resources/theme/images/icons/miss.svg");
|
||||
}
|
||||
|
||||
#group-ground::before {
|
||||
content: url("/resources/theme/images/icons/group-ground.svg");
|
||||
}
|
||||
|
||||
#group-navy::before {
|
||||
content: url("/resources/theme/images/icons/group-navy.svg");
|
||||
}
|
||||
|
||||
#trail::before {
|
||||
content: url("/resources/theme/images/icons/trail.svg");
|
||||
}
|
||||
|
||||
@ -203,6 +203,22 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
|
||||
content: "NO";
|
||||
}
|
||||
|
||||
#operate-as-switch[data-value="true"] .ol-switch-fill {
|
||||
background-color: var(--accent-light-blue);
|
||||
}
|
||||
|
||||
#operate-as-switch[data-value="false"] .ol-switch-fill {
|
||||
background-color: var(--primary-red);
|
||||
}
|
||||
|
||||
#operate-as-switch[data-value="true"]>.ol-switch-fill::before {
|
||||
content: "BLUE" !important;
|
||||
}
|
||||
|
||||
#operate-as-switch[data-value="false"]>.ol-switch-fill::before {
|
||||
content: "RED" !important;
|
||||
}
|
||||
|
||||
#advanced-settings-div {
|
||||
column-gap: 5px;
|
||||
display: flex;
|
||||
@ -225,6 +241,7 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
|
||||
#unit-control-panel:not([data-show-emissions-countermeasures]) #emissions-countermeasures,
|
||||
#unit-control-panel:not([data-show-on-off]) #ai-on-off,
|
||||
#unit-control-panel:not([data-show-follow-roads]) #follow-roads,
|
||||
#unit-control-panel:not([data-show-operate-as]) #operate-as,
|
||||
#unit-control-panel:not([data-show-advanced-settings-button]) #advanced-settings-button,
|
||||
#advanced-settings-dialog:not([data-show-settings]) #general-settings,
|
||||
#advanced-settings-dialog:not([data-show-tasking]) #tasking,
|
||||
|
||||
@ -678,6 +678,13 @@ nav.ol-panel> :last-child {
|
||||
stroke: white;
|
||||
}
|
||||
|
||||
#rapid-controls button:before {
|
||||
display: inline-block;
|
||||
filter: invert(100%);
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
/****************************************************************************************/
|
||||
#splash-screen {
|
||||
border-radius: var(--border-radius-md);
|
||||
|
||||
@ -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="M37.6 4.2C28-2.3 15.2-1.1 7 7s-9.4 21-2.8 30.5l112 163.3L16.6 233.2C6.7 236.4 0 245.6 0 256s6.7 19.6 16.6 22.8l103.1 33.4L66.8 412.8c-4.9 9.3-3.2 20.7 4.3 28.1s18.8 9.2 28.1 4.3l100.6-52.9 33.4 103.1c3.2 9.9 12.4 16.6 22.8 16.6s19.6-6.7 22.8-16.6l33.4-103.1 100.6 52.9c9.3 4.9 20.7 3.2 28.1-4.3s9.2-18.8 4.3-28.1L392.3 312.2l103.1-33.4c9.9-3.2 16.6-12.4 16.6-22.8s-6.7-19.6-16.6-22.8L388.9 198.7l25.7-70.4c3.2-8.8 1-18.6-5.6-25.2s-16.4-8.8-25.2-5.6l-70.4 25.7L278.8 16.6C275.6 6.7 266.4 0 256 0s-19.6 6.7-22.8 16.6l-32.3 99.6L37.6 4.2z"/></svg>
|
||||
|
After Width: | Height: | Size: 783 B |
76
client/public/themes/olympus/images/icons/group-ground.svg
Normal file
@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 0 512 512"
|
||||
version="1.1"
|
||||
id="svg1156"
|
||||
sodipodi:docname="group-ground.svg"
|
||||
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
|
||||
xml:space="preserve"
|
||||
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="defs1160" /><sodipodi:namedview
|
||||
id="namedview1158"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.3838301"
|
||||
inkscape:cx="350.83787"
|
||||
inkscape:cy="229.07436"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1377"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1156" /><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><g
|
||||
id="g17054"
|
||||
transform="matrix(1.0569047,0,0,1.0569047,-16.868728,-5.190059)"><rect
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:10;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect13768"
|
||||
width="162.59222"
|
||||
height="162.59222"
|
||||
x="200.25279"
|
||||
y="-165.09651"
|
||||
ry="1.6436043"
|
||||
transform="rotate(45)" /><circle
|
||||
style="fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:10;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path15109"
|
||||
cx="258.34097"
|
||||
cy="139.82932"
|
||||
r="52.56604" /></g><g
|
||||
id="g17054-1"
|
||||
transform="matrix(1.0569047,0,0,1.0569047,110.67584,204.85819)"><rect
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:10;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect13768-9"
|
||||
width="162.59222"
|
||||
height="162.59222"
|
||||
x="200.25279"
|
||||
y="-165.09651"
|
||||
ry="1.6436043"
|
||||
transform="rotate(45)" /><circle
|
||||
style="fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:10;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path15109-6"
|
||||
cx="258.34097"
|
||||
cy="139.82932"
|
||||
r="52.56604" /></g><g
|
||||
id="g17054-3"
|
||||
transform="matrix(1.0569047,0,0,1.0569047,-141.52275,204.13556)"><rect
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:10;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect13768-7"
|
||||
width="162.59222"
|
||||
height="162.59222"
|
||||
x="200.25279"
|
||||
y="-165.09651"
|
||||
ry="1.6436043"
|
||||
transform="rotate(45)" /><circle
|
||||
style="fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:10;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path15109-8"
|
||||
cx="258.34097"
|
||||
cy="139.82932"
|
||||
r="52.56604" /></g></svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
64
client/public/themes/olympus/images/icons/group-navy.svg
Normal file
@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 0 512 512"
|
||||
version="1.1"
|
||||
id="svg1156"
|
||||
sodipodi:docname="group-navy.svg"
|
||||
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
|
||||
xml:space="preserve"
|
||||
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="defs1160" /><sodipodi:namedview
|
||||
id="namedview1158"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.9570312"
|
||||
inkscape:cx="262.38723"
|
||||
inkscape:cy="288.19162"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1377"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1156" /><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:65.39;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path15424"
|
||||
sodipodi:type="arc"
|
||||
sodipodi:cx="259.66818"
|
||||
sodipodi:cy="230.83046"
|
||||
sodipodi:rx="226.81407"
|
||||
sodipodi:ry="212.6382"
|
||||
sodipodi:start="4.1887902"
|
||||
sodipodi:end="5.2359878"
|
||||
sodipodi:arc-type="slice"
|
||||
d="m 146.26115,46.680378 a 226.81407,212.6382 0 0 1 226.81408,4e-6 L 259.66818,230.83046 Z" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:65.39;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path15424-9"
|
||||
sodipodi:type="arc"
|
||||
sodipodi:cx="386.81033"
|
||||
sodipodi:cy="495.42886"
|
||||
sodipodi:rx="226.81407"
|
||||
sodipodi:ry="212.6382"
|
||||
sodipodi:start="4.1887902"
|
||||
sodipodi:end="5.2359878"
|
||||
sodipodi:arc-type="slice"
|
||||
d="m 273.4033,311.27878 a 226.81407,212.6382 0 0 1 226.81408,1e-5 L 386.81033,495.42886 Z" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:65.39;stroke-linecap:round;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path15424-4"
|
||||
sodipodi:type="arc"
|
||||
sodipodi:cx="127.74452"
|
||||
sodipodi:cy="495.42886"
|
||||
sodipodi:rx="226.81407"
|
||||
sodipodi:ry="212.6382"
|
||||
sodipodi:start="4.1887902"
|
||||
sodipodi:end="5.2359878"
|
||||
sodipodi:arc-type="slice"
|
||||
d="m 14.337485,311.27878 a 226.81407,212.6382 0 0 1 226.814085,1e-5 L 127.74452,495.42886 Z" /></svg>
|
||||
|
After Width: | Height: | Size: 2.6 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="M270.7 9.7C268.2 3.8 262.4 0 256 0s-12.2 3.8-14.7 9.7L197.2 112.6c-3.4 8-5.2 16.5-5.2 25.2v77l-144 84V280c0-13.3-10.7-24-24-24s-24 10.7-24 24v56 32 24c0 13.3 10.7 24 24 24s24-10.7 24-24v-8H192v32.7L133.5 468c-3.5 3-5.5 7.4-5.5 12v16c0 8.8 7.2 16 16 16h96V448c0-8.8 7.2-16 16-16s16 7.2 16 16v64h96c8.8 0 16-7.2 16-16V480c0-4.6-2-9-5.5-12L320 416.7V384H464v8c0 13.3 10.7 24 24 24s24-10.7 24-24V368 336 280c0-13.3-10.7-24-24-24s-24 10.7-24 24v18.8l-144-84v-77c0-8.7-1.8-17.2-5.2-25.2L270.7 9.7z"/></svg>
|
||||
|
After Width: | Height: | Size: 739 B |
42
client/public/themes/olympus/images/icons/miss-blue.svg
Normal file
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 0 512 512"
|
||||
version="1.1"
|
||||
id="svg1156"
|
||||
sodipodi:docname="miss-blue.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="defs1160" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1158"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.3838301"
|
||||
inkscape:cx="310.37048"
|
||||
inkscape:cy="217.51226"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1377"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1156" />
|
||||
<!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
|
||||
<path
|
||||
d="m 376.91839,231.41639 c -1.31238,-3.09721 -4.35709,-5.09202 -7.71677,-5.09202 -3.35968,0 -6.40439,1.99481 -7.71677,5.09202 l -23.1503,54.01737 c -1.78483,4.1996 -2.72974,8.66167 -2.72974,13.22874 v 40.42116 l -75.59281,44.0958 v -9.86906 c 0,-6.98183 -5.61697,-12.5988 -12.5988,-12.5988 -6.98184,0 -12.59881,5.61697 -12.59881,12.5988 v 29.39721 16.7984 12.5988 c 0,6.98184 5.61697,12.59881 12.59881,12.59881 6.98183,0 12.5988,-5.61697 12.5988,-12.59881 v -4.1996 h 75.59281 v 17.16587 l -30.70958,26.92994 c -1.83732,1.57485 -2.88722,3.88463 -2.88722,6.2994 v 8.3992 c 0,4.61956 3.77964,8.39921 8.3992,8.39921 h 50.39521 v -33.59681 c 0,-4.61956 3.77964,-8.3992 8.3992,-8.3992 4.61956,0 8.3992,3.77964 8.3992,8.3992 v 33.59681 h 50.39521 c 4.61956,0 8.3992,-3.77965 8.3992,-8.39921 v -8.3992 c 0,-2.41477 -1.0499,-4.72455 -2.88722,-6.2994 l -30.70958,-26.92994 v -17.16587 h 75.59281 v 4.1996 c 0,6.98184 5.61697,12.59881 12.5988,12.59881 6.98184,0 12.59881,-5.61697 12.59881,-12.59881 v -12.5988 -16.7984 -29.39721 c 0,-6.98183 -5.61697,-12.5988 -12.59881,-12.5988 -6.98183,0 -12.5988,5.61697 -12.5988,12.5988 v 9.86906 l -75.59281,-44.0958 V 298.6625 c 0,-4.56707 -0.94491,-9.02914 -2.72974,-13.22874 z"
|
||||
id="path1154"
|
||||
style="fill:#db841d;fill-opacity:1;stroke:none;stroke-width:0.52495;stroke-opacity:1" />
|
||||
<path
|
||||
d="m 184.66044,8.5185895 c 12.17907,0 22.01865,9.8395825 22.01865,22.0186445 v 7.15606 C 271.15243,47.257643 322.07055,98.244571 331.6349,162.6491 h 7.15606 c 12.17906,0 22.01864,9.83958 22.01864,22.01864 0,12.17907 -9.83958,22.01865 -22.01864,22.01865 h -7.15606 c -9.56435,64.47334 -60.55128,115.39146 -124.95581,124.95581 v 7.15606 c 0,12.17906 -9.83958,22.01864 -22.01865,22.01864 -12.17906,0 -22.01864,-9.83958 -22.01864,-22.01864 V 331.6422 C 98.168455,322.07785 47.250339,271.15973 37.68599,206.68639 h -7.156059 c -12.179063,0 -22.0186444,-9.83958 -22.0186444,-22.01865 0,-12.17906 9.8395814,-22.01864 22.0186444,-22.01864 H 37.68599 C 47.250339,98.175761 98.168455,47.257643 162.6418,37.693294 v -7.15606 c 0,-12.179062 9.83958,-22.0186445 22.01864,-22.0186445 z M 82.411363,206.68639 c 8.601033,40.11522 40.184027,71.6294 80.230437,80.23043 v -14.1745 c 0,-12.17906 9.83958,-22.01864 22.01864,-22.01864 12.17907,0 22.01865,9.83958 22.01865,22.01864 v 14.1745 c 40.11522,-8.60103 71.6294,-40.18402 80.23044,-80.23043 h -14.17451 c -12.17906,0 -22.01864,-9.83958 -22.01864,-22.01865 0,-12.17906 9.83958,-22.01864 22.01864,-22.01864 h 14.17451 C 278.30849,122.53388 246.79431,91.019701 206.67909,82.418665 v 14.174506 c 0,12.179059 -9.83958,22.018639 -22.01865,22.018639 -12.17906,0 -22.01864,-9.83958 -22.01864,-22.018639 V 82.418665 C 122.52658,91.019701 91.012396,122.53388 82.411363,162.6491 h 14.174502 c 12.179065,0 22.018645,9.83958 22.018645,22.01864 0,12.17907 -9.83958,22.01865 -22.018645,22.01865 z M 184.66044,162.6491 a 22.018645,22.018645 0 1 1 0,44.03729 22.018645,22.018645 0 1 1 0,-44.03729 z"
|
||||
id="path2"
|
||||
style="stroke-width:0.688083" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
42
client/public/themes/olympus/images/icons/miss-red.svg
Normal file
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 0 512 512"
|
||||
version="1.1"
|
||||
id="svg1156"
|
||||
sodipodi:docname="miss-red.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="defs1160" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1158"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.3838301"
|
||||
inkscape:cx="310.37048"
|
||||
inkscape:cy="217.51226"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1377"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1156" />
|
||||
<!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
|
||||
<path
|
||||
d="m 376.91839,231.41639 c -1.31238,-3.09721 -4.35709,-5.09202 -7.71677,-5.09202 -3.35968,0 -6.40439,1.99481 -7.71677,5.09202 l -23.1503,54.01737 c -1.78483,4.1996 -2.72974,8.66167 -2.72974,13.22874 v 40.42116 l -75.59281,44.0958 v -9.86906 c 0,-6.98183 -5.61697,-12.5988 -12.5988,-12.5988 -6.98184,0 -12.59881,5.61697 -12.59881,12.5988 v 29.39721 16.7984 12.5988 c 0,6.98184 5.61697,12.59881 12.59881,12.59881 6.98183,0 12.5988,-5.61697 12.5988,-12.59881 v -4.1996 h 75.59281 v 17.16587 l -30.70958,26.92994 c -1.83732,1.57485 -2.88722,3.88463 -2.88722,6.2994 v 8.3992 c 0,4.61956 3.77964,8.39921 8.3992,8.39921 h 50.39521 v -33.59681 c 0,-4.61956 3.77964,-8.3992 8.3992,-8.3992 4.61956,0 8.3992,3.77964 8.3992,8.3992 v 33.59681 h 50.39521 c 4.61956,0 8.3992,-3.77965 8.3992,-8.39921 v -8.3992 c 0,-2.41477 -1.0499,-4.72455 -2.88722,-6.2994 l -30.70958,-26.92994 v -17.16587 h 75.59281 v 4.1996 c 0,6.98184 5.61697,12.59881 12.5988,12.59881 6.98184,0 12.59881,-5.61697 12.59881,-12.59881 v -12.5988 -16.7984 -29.39721 c 0,-6.98183 -5.61697,-12.5988 -12.59881,-12.5988 -6.98183,0 -12.5988,5.61697 -12.5988,12.5988 v 9.86906 l -75.59281,-44.0958 V 298.6625 c 0,-4.56707 -0.94491,-9.02914 -2.72974,-13.22874 z"
|
||||
id="path1154"
|
||||
style="fill:#00a7a7;fill-opacity:1;stroke:none;stroke-width:0.52495;stroke-opacity:1" />
|
||||
<path
|
||||
d="m 184.66044,8.5185895 c 12.17907,0 22.01865,9.8395825 22.01865,22.0186445 v 7.15606 C 271.15243,47.257643 322.07055,98.244571 331.6349,162.6491 h 7.15606 c 12.17906,0 22.01864,9.83958 22.01864,22.01864 0,12.17907 -9.83958,22.01865 -22.01864,22.01865 h -7.15606 c -9.56435,64.47334 -60.55128,115.39146 -124.95581,124.95581 v 7.15606 c 0,12.17906 -9.83958,22.01864 -22.01865,22.01864 -12.17906,0 -22.01864,-9.83958 -22.01864,-22.01864 V 331.6422 C 98.168455,322.07785 47.250339,271.15973 37.68599,206.68639 h -7.156059 c -12.179063,0 -22.0186444,-9.83958 -22.0186444,-22.01865 0,-12.17906 9.8395814,-22.01864 22.0186444,-22.01864 H 37.68599 C 47.250339,98.175761 98.168455,47.257643 162.6418,37.693294 v -7.15606 c 0,-12.179062 9.83958,-22.0186445 22.01864,-22.0186445 z M 82.411363,206.68639 c 8.601033,40.11522 40.184027,71.6294 80.230437,80.23043 v -14.1745 c 0,-12.17906 9.83958,-22.01864 22.01864,-22.01864 12.17907,0 22.01865,9.83958 22.01865,22.01864 v 14.1745 c 40.11522,-8.60103 71.6294,-40.18402 80.23044,-80.23043 h -14.17451 c -12.17906,0 -22.01864,-9.83958 -22.01864,-22.01865 0,-12.17906 9.83958,-22.01864 22.01864,-22.01864 h 14.17451 C 278.30849,122.53388 246.79431,91.019701 206.67909,82.418665 v 14.174506 c 0,12.179059 -9.83958,22.018639 -22.01865,22.018639 -12.17906,0 -22.01864,-9.83958 -22.01864,-22.018639 V 82.418665 C 122.52658,91.019701 91.012396,122.53388 82.411363,162.6491 h 14.174502 c 12.179065,0 22.018645,9.83958 22.018645,22.01864 0,12.17907 -9.83958,22.01865 -22.018645,22.01865 z M 184.66044,162.6491 a 22.018645,22.018645 0 1 1 0,44.03729 22.018645,22.018645 0 1 1 0,-44.03729 z"
|
||||
id="path2"
|
||||
style="stroke-width:0.688083" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
42
client/public/themes/olympus/images/icons/miss.svg
Normal file
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 0 512 512"
|
||||
version="1.1"
|
||||
id="svg1156"
|
||||
sodipodi:docname="miss.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="defs1160" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1158"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.3838301"
|
||||
inkscape:cx="311.0931"
|
||||
inkscape:cy="217.51225"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1377"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1156" />
|
||||
<!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. -->
|
||||
<path
|
||||
d="m 376.91839,231.41639 c -1.31238,-3.09721 -4.35709,-5.09202 -7.71677,-5.09202 -3.35968,0 -6.40439,1.99481 -7.71677,5.09202 l -23.1503,54.01737 c -1.78483,4.1996 -2.72974,8.66167 -2.72974,13.22874 v 40.42116 l -75.59281,44.0958 v -9.86906 c 0,-6.98183 -5.61697,-12.5988 -12.5988,-12.5988 -6.98184,0 -12.59881,5.61697 -12.59881,12.5988 v 29.39721 16.7984 12.5988 c 0,6.98184 5.61697,12.59881 12.59881,12.59881 6.98183,0 12.5988,-5.61697 12.5988,-12.59881 v -4.1996 h 75.59281 v 17.16587 l -30.70958,26.92994 c -1.83732,1.57485 -2.88722,3.88463 -2.88722,6.2994 v 8.3992 c 0,4.61956 3.77964,8.39921 8.3992,8.39921 h 50.39521 v -33.59681 c 0,-4.61956 3.77964,-8.3992 8.3992,-8.3992 4.61956,0 8.3992,3.77964 8.3992,8.3992 v 33.59681 h 50.39521 c 4.61956,0 8.3992,-3.77965 8.3992,-8.39921 v -8.3992 c 0,-2.41477 -1.0499,-4.72455 -2.88722,-6.2994 l -30.70958,-26.92994 v -17.16587 h 75.59281 v 4.1996 c 0,6.98184 5.61697,12.59881 12.5988,12.59881 6.98184,0 12.59881,-5.61697 12.59881,-12.59881 v -12.5988 -16.7984 -29.39721 c 0,-6.98183 -5.61697,-12.5988 -12.59881,-12.5988 -6.98183,0 -12.5988,5.61697 -12.5988,12.5988 v 9.86906 l -75.59281,-44.0958 V 298.6625 c 0,-4.56707 -0.94491,-9.02914 -2.72974,-13.22874 z"
|
||||
id="path1154"
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.52495;stroke-opacity:1" />
|
||||
<path
|
||||
d="m 184.66044,8.5185895 c 12.17907,0 22.01865,9.8395825 22.01865,22.0186445 v 7.15606 C 271.15243,47.257643 322.07055,98.244571 331.6349,162.6491 h 7.15606 c 12.17906,0 22.01864,9.83958 22.01864,22.01864 0,12.17907 -9.83958,22.01865 -22.01864,22.01865 h -7.15606 c -9.56435,64.47334 -60.55128,115.39146 -124.95581,124.95581 v 7.15606 c 0,12.17906 -9.83958,22.01864 -22.01865,22.01864 -12.17906,0 -22.01864,-9.83958 -22.01864,-22.01864 V 331.6422 C 98.168455,322.07785 47.250339,271.15973 37.68599,206.68639 h -7.156059 c -12.179063,0 -22.0186444,-9.83958 -22.0186444,-22.01865 0,-12.17906 9.8395814,-22.01864 22.0186444,-22.01864 H 37.68599 C 47.250339,98.175761 98.168455,47.257643 162.6418,37.693294 v -7.15606 c 0,-12.179062 9.83958,-22.0186445 22.01864,-22.0186445 z M 82.411363,206.68639 c 8.601033,40.11522 40.184027,71.6294 80.230437,80.23043 v -14.1745 c 0,-12.17906 9.83958,-22.01864 22.01864,-22.01864 12.17907,0 22.01865,9.83958 22.01865,22.01864 v 14.1745 c 40.11522,-8.60103 71.6294,-40.18402 80.23044,-80.23043 h -14.17451 c -12.17906,0 -22.01864,-9.83958 -22.01864,-22.01865 0,-12.17906 9.83958,-22.01864 22.01864,-22.01864 h 14.17451 C 278.30849,122.53388 246.79431,91.019701 206.67909,82.418665 v 14.174506 c 0,12.179059 -9.83958,22.018639 -22.01865,22.018639 -12.17906,0 -22.01864,-9.83958 -22.01864,-22.018639 V 82.418665 C 122.52658,91.019701 91.012396,122.53388 82.411363,162.6491 h 14.174502 c 12.179065,0 22.018645,9.83958 22.018645,22.01864 0,12.17907 -9.83958,22.01865 -22.018645,22.01865 z M 184.66044,162.6491 a 22.018645,22.018645 0 1 1 0,44.03729 22.018645,22.018645 0 1 1 0,-44.03729 z"
|
||||
id="path2"
|
||||
style="stroke-width:0.688083" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
49
client/public/themes/olympus/images/icons/scenic-blue.svg
Normal file
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 0 512 512"
|
||||
version="1.1"
|
||||
id="svg1156"
|
||||
sodipodi:docname="scenic-blue.svg"
|
||||
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
|
||||
xml:space="preserve"
|
||||
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="defs1160" /><sodipodi:namedview
|
||||
id="namedview1158"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.3838301"
|
||||
inkscape:cx="350.11524"
|
||||
inkscape:cy="229.07437"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1377"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1156" /><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path
|
||||
d="m 376.91839,231.41639 c -1.31238,-3.09721 -4.35709,-5.09202 -7.71677,-5.09202 -3.35968,0 -6.40439,1.99481 -7.71677,5.09202 l -23.1503,54.01737 c -1.78483,4.1996 -2.72974,8.66167 -2.72974,13.22874 v 40.42116 l -75.59281,44.0958 v -9.86906 c 0,-6.98183 -5.61697,-12.5988 -12.5988,-12.5988 -6.98184,0 -12.59881,5.61697 -12.59881,12.5988 v 29.39721 16.7984 12.5988 c 0,6.98184 5.61697,12.59881 12.59881,12.59881 6.98183,0 12.5988,-5.61697 12.5988,-12.59881 v -4.1996 h 75.59281 v 17.16587 l -30.70958,26.92994 c -1.83732,1.57485 -2.88722,3.88463 -2.88722,6.2994 v 8.3992 c 0,4.61956 3.77964,8.39921 8.3992,8.39921 h 50.39521 v -33.59681 c 0,-4.61956 3.77964,-8.3992 8.3992,-8.3992 4.61956,0 8.3992,3.77964 8.3992,8.3992 v 33.59681 h 50.39521 c 4.61956,0 8.3992,-3.77965 8.3992,-8.39921 v -8.3992 c 0,-2.41477 -1.0499,-4.72455 -2.88722,-6.2994 l -30.70958,-26.92994 v -17.16587 h 75.59281 v 4.1996 c 0,6.98184 5.61697,12.59881 12.5988,12.59881 6.98184,0 12.59881,-5.61697 12.59881,-12.59881 v -12.5988 -16.7984 -29.39721 c 0,-6.98183 -5.61697,-12.5988 -12.59881,-12.5988 -6.98183,0 -12.5988,5.61697 -12.5988,12.5988 v 9.86906 l -75.59281,-44.0958 V 298.6625 c 0,-4.56707 -0.94491,-9.02914 -2.72974,-13.22874 z"
|
||||
id="path1154"
|
||||
style="fill:#db841d;fill-opacity:1;stroke:none;stroke-width:0.52495;stroke-opacity:1" /><path
|
||||
style="fill:none;stroke:#000000;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 90.329008,471.87874 294.83388,138.74536"
|
||||
id="path9928"
|
||||
sodipodi:nodetypes="cc" /><path
|
||||
style="fill:none;stroke:#000000;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 37.215553,461.40058 33.602384,51.668198"
|
||||
id="path9928-3"
|
||||
sodipodi:nodetypes="cc" /><path
|
||||
style="fill:none;stroke:#000000;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 61.785043,466.45901 134.77088,205.58883"
|
||||
id="path9928-31"
|
||||
sodipodi:nodetypes="cc" /><path
|
||||
d="m 97.776883,46.496287 c -2.69052,-1.821707 -6.27788,-1.485392 -8.576032,0.784735 -2.298159,2.270126 -2.634474,5.885513 -0.784735,8.548007 l 31.389404,45.766871 -27.914144,9.08052 c -2.774607,0.89684 -4.652369,3.47525 -4.652369,6.38998 0,2.91473 1.877762,5.49315 4.652369,6.38999 l 28.895064,9.36076 -14.82589,28.19441 c -1.37329,2.60645 -0.89684,5.80143 1.20513,7.87538 2.10197,2.07394 5.26893,2.57842 7.87538,1.20513 l 28.19442,-14.82589 9.36076,28.89507 c 0.89684,2.7746 3.47525,4.65236 6.38998,4.65236 2.91474,0 5.49316,-1.87776 6.39,-4.65236 l 9.36076,-28.89507 28.19441,14.82589 c 2.60645,1.37329 5.80144,0.89684 7.87539,-1.20513 2.07393,-2.10197 2.57841,-5.26893 1.20512,-7.87538 l -14.82589,-28.19441 28.89507,-9.36076 c 2.7746,-0.89684 4.65236,-3.47526 4.65236,-6.38999 0,-2.91473 -1.87776,-5.49314 -4.65236,-6.38998 l -29.84797,-9.66907 7.20276,-19.730481 c 0.89684,-2.466311 0.28026,-5.212883 -1.56947,-7.062617 -1.84974,-1.849732 -4.59631,-2.46631 -7.06262,-1.56947 l -19.73049,7.202748 -9.69707,-29.875988 c -0.89684,-2.7746 -3.47526,-4.652359 -6.39,-4.652359 -2.91473,0 -5.49314,1.877759 -6.38998,4.652359 l -9.05248,27.91415 z"
|
||||
id="path10424"
|
||||
style="stroke-width:0.280262" /></svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
49
client/public/themes/olympus/images/icons/scenic-red.svg
Normal file
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 0 512 512"
|
||||
version="1.1"
|
||||
id="svg1156"
|
||||
sodipodi:docname="scenic-red.svg"
|
||||
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
|
||||
xml:space="preserve"
|
||||
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="defs1160" /><sodipodi:namedview
|
||||
id="namedview1158"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.3838301"
|
||||
inkscape:cx="350.11524"
|
||||
inkscape:cy="229.07437"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1377"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1156" /><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path
|
||||
d="m 376.91839,231.41639 c -1.31238,-3.09721 -4.35709,-5.09202 -7.71677,-5.09202 -3.35968,0 -6.40439,1.99481 -7.71677,5.09202 l -23.1503,54.01737 c -1.78483,4.1996 -2.72974,8.66167 -2.72974,13.22874 v 40.42116 l -75.59281,44.0958 v -9.86906 c 0,-6.98183 -5.61697,-12.5988 -12.5988,-12.5988 -6.98184,0 -12.59881,5.61697 -12.59881,12.5988 v 29.39721 16.7984 12.5988 c 0,6.98184 5.61697,12.59881 12.59881,12.59881 6.98183,0 12.5988,-5.61697 12.5988,-12.59881 v -4.1996 h 75.59281 v 17.16587 l -30.70958,26.92994 c -1.83732,1.57485 -2.88722,3.88463 -2.88722,6.2994 v 8.3992 c 0,4.61956 3.77964,8.39921 8.3992,8.39921 h 50.39521 v -33.59681 c 0,-4.61956 3.77964,-8.3992 8.3992,-8.3992 4.61956,0 8.3992,3.77964 8.3992,8.3992 v 33.59681 h 50.39521 c 4.61956,0 8.3992,-3.77965 8.3992,-8.39921 v -8.3992 c 0,-2.41477 -1.0499,-4.72455 -2.88722,-6.2994 l -30.70958,-26.92994 v -17.16587 h 75.59281 v 4.1996 c 0,6.98184 5.61697,12.59881 12.5988,12.59881 6.98184,0 12.59881,-5.61697 12.59881,-12.59881 v -12.5988 -16.7984 -29.39721 c 0,-6.98183 -5.61697,-12.5988 -12.59881,-12.5988 -6.98183,0 -12.5988,5.61697 -12.5988,12.5988 v 9.86906 l -75.59281,-44.0958 V 298.6625 c 0,-4.56707 -0.94491,-9.02914 -2.72974,-13.22874 z"
|
||||
id="path1154"
|
||||
style="fill:#00a7a7;fill-opacity:1;stroke:none;stroke-width:0.52495;stroke-opacity:1" /><path
|
||||
style="fill:none;stroke:#000000;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 90.329008,471.87874 294.83388,138.74536"
|
||||
id="path9928"
|
||||
sodipodi:nodetypes="cc" /><path
|
||||
style="fill:none;stroke:#000000;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 37.215553,461.40058 33.602384,51.668198"
|
||||
id="path9928-3"
|
||||
sodipodi:nodetypes="cc" /><path
|
||||
style="fill:none;stroke:#000000;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 61.785043,466.45901 134.77088,205.58883"
|
||||
id="path9928-31"
|
||||
sodipodi:nodetypes="cc" /><path
|
||||
d="m 97.776883,46.496287 c -2.69052,-1.821707 -6.27788,-1.485392 -8.576032,0.784735 -2.298159,2.270126 -2.634474,5.885513 -0.784735,8.548007 l 31.389404,45.766871 -27.914144,9.08052 c -2.774607,0.89684 -4.652369,3.47525 -4.652369,6.38998 0,2.91473 1.877762,5.49315 4.652369,6.38999 l 28.895064,9.36076 -14.82589,28.19441 c -1.37329,2.60645 -0.89684,5.80143 1.20513,7.87538 2.10197,2.07394 5.26893,2.57842 7.87538,1.20513 l 28.19442,-14.82589 9.36076,28.89507 c 0.89684,2.7746 3.47525,4.65236 6.38998,4.65236 2.91474,0 5.49316,-1.87776 6.39,-4.65236 l 9.36076,-28.89507 28.19441,14.82589 c 2.60645,1.37329 5.80144,0.89684 7.87539,-1.20513 2.07393,-2.10197 2.57841,-5.26893 1.20512,-7.87538 l -14.82589,-28.19441 28.89507,-9.36076 c 2.7746,-0.89684 4.65236,-3.47526 4.65236,-6.38999 0,-2.91473 -1.87776,-5.49314 -4.65236,-6.38998 l -29.84797,-9.66907 7.20276,-19.730481 c 0.89684,-2.466311 0.28026,-5.212883 -1.56947,-7.062617 -1.84974,-1.849732 -4.59631,-2.46631 -7.06262,-1.56947 l -19.73049,7.202748 -9.69707,-29.875988 c -0.89684,-2.7746 -3.47526,-4.652359 -6.39,-4.652359 -2.91473,0 -5.49314,1.877759 -6.38998,4.652359 l -9.05248,27.91415 z"
|
||||
id="path10424"
|
||||
style="stroke-width:0.280262" /></svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
49
client/public/themes/olympus/images/icons/scenic.svg
Normal file
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 0 512 512"
|
||||
version="1.1"
|
||||
id="svg1156"
|
||||
sodipodi:docname="scenic.svg"
|
||||
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
|
||||
xml:space="preserve"
|
||||
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="defs1160" /><sodipodi:namedview
|
||||
id="namedview1158"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.3838301"
|
||||
inkscape:cx="350.83787"
|
||||
inkscape:cy="229.07436"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1377"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1156" /><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path
|
||||
d="m 376.91839,231.41639 c -1.31238,-3.09721 -4.35709,-5.09202 -7.71677,-5.09202 -3.35968,0 -6.40439,1.99481 -7.71677,5.09202 l -23.1503,54.01737 c -1.78483,4.1996 -2.72974,8.66167 -2.72974,13.22874 v 40.42116 l -75.59281,44.0958 v -9.86906 c 0,-6.98183 -5.61697,-12.5988 -12.5988,-12.5988 -6.98184,0 -12.59881,5.61697 -12.59881,12.5988 v 29.39721 16.7984 12.5988 c 0,6.98184 5.61697,12.59881 12.59881,12.59881 6.98183,0 12.5988,-5.61697 12.5988,-12.59881 v -4.1996 h 75.59281 v 17.16587 l -30.70958,26.92994 c -1.83732,1.57485 -2.88722,3.88463 -2.88722,6.2994 v 8.3992 c 0,4.61956 3.77964,8.39921 8.3992,8.39921 h 50.39521 v -33.59681 c 0,-4.61956 3.77964,-8.3992 8.3992,-8.3992 4.61956,0 8.3992,3.77964 8.3992,8.3992 v 33.59681 h 50.39521 c 4.61956,0 8.3992,-3.77965 8.3992,-8.39921 v -8.3992 c 0,-2.41477 -1.0499,-4.72455 -2.88722,-6.2994 l -30.70958,-26.92994 v -17.16587 h 75.59281 v 4.1996 c 0,6.98184 5.61697,12.59881 12.5988,12.59881 6.98184,0 12.59881,-5.61697 12.59881,-12.59881 v -12.5988 -16.7984 -29.39721 c 0,-6.98183 -5.61697,-12.5988 -12.59881,-12.5988 -6.98183,0 -12.5988,5.61697 -12.5988,12.5988 v 9.86906 l -75.59281,-44.0958 V 298.6625 c 0,-4.56707 -0.94491,-9.02914 -2.72974,-13.22874 z"
|
||||
id="path1154"
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.52495;stroke-opacity:1" /><path
|
||||
style="fill:none;stroke:#000000;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 90.329008,471.87874 294.83388,138.74536"
|
||||
id="path9928"
|
||||
sodipodi:nodetypes="cc" /><path
|
||||
style="fill:none;stroke:#000000;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 37.215553,461.40058 33.602384,51.668198"
|
||||
id="path9928-3"
|
||||
sodipodi:nodetypes="cc" /><path
|
||||
style="fill:none;stroke:#000000;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 61.785043,466.45901 134.77088,205.58883"
|
||||
id="path9928-31"
|
||||
sodipodi:nodetypes="cc" /><path
|
||||
d="m 97.776883,46.496287 c -2.69052,-1.821707 -6.27788,-1.485392 -8.576032,0.784735 -2.298159,2.270126 -2.634474,5.885513 -0.784735,8.548007 l 31.389404,45.766871 -27.914144,9.08052 c -2.774607,0.89684 -4.652369,3.47525 -4.652369,6.38998 0,2.91473 1.877762,5.49315 4.652369,6.38999 l 28.895064,9.36076 -14.82589,28.19441 c -1.37329,2.60645 -0.89684,5.80143 1.20513,7.87538 2.10197,2.07394 5.26893,2.57842 7.87538,1.20513 l 28.19442,-14.82589 9.36076,28.89507 c 0.89684,2.7746 3.47525,4.65236 6.38998,4.65236 2.91474,0 5.49316,-1.87776 6.39,-4.65236 l 9.36076,-28.89507 28.19441,14.82589 c 2.60645,1.37329 5.80144,0.89684 7.87539,-1.20513 2.07393,-2.10197 2.57841,-5.26893 1.20512,-7.87538 l -14.82589,-28.19441 28.89507,-9.36076 c 2.7746,-0.89684 4.65236,-3.47526 4.65236,-6.38999 0,-2.91473 -1.87776,-5.49314 -4.65236,-6.38998 l -29.84797,-9.66907 7.20276,-19.730481 c 0.89684,-2.466311 0.28026,-5.212883 -1.56947,-7.062617 -1.84974,-1.849732 -4.59631,-2.46631 -7.06262,-1.56947 l -19.73049,7.202748 -9.69707,-29.875988 c -0.89684,-2.7746 -3.47526,-4.652359 -6.39,-4.652359 -2.91473,0 -5.49314,1.877759 -6.38998,4.652359 l -9.05248,27.91415 z"
|
||||
id="path10424"
|
||||
style="stroke-width:0.280262" /></svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
@ -197,5 +197,6 @@ export enum DataIndexes {
|
||||
contacts,
|
||||
activePath,
|
||||
isLeader,
|
||||
operateAs,
|
||||
endOfData = 255
|
||||
};
|
||||
@ -176,6 +176,7 @@ export interface UnitData {
|
||||
contacts: Contact[];
|
||||
activePath: LatLng[];
|
||||
isLeader: boolean;
|
||||
operateAs: string;
|
||||
}
|
||||
|
||||
export interface LoadoutItemBlueprint {
|
||||
@ -199,13 +200,21 @@ export interface UnitBlueprint {
|
||||
label: string;
|
||||
shortLabel: string;
|
||||
type?: string;
|
||||
range?: string;
|
||||
rangeType?: string;
|
||||
loadouts?: LoadoutBlueprint[];
|
||||
filename?: string;
|
||||
liveries?: { [key: string]: { name: string, countries: string[] } };
|
||||
cost?: number;
|
||||
barrelHeight?: number;
|
||||
muzzleVelocity?: number;
|
||||
aimTime?: number;
|
||||
shotsToFire?: number;
|
||||
description?: string;
|
||||
abilities?: string;
|
||||
acquisitionRange?: number;
|
||||
engagementRange?: number;
|
||||
refuelsFrom?: string;
|
||||
refuelingType?: string;
|
||||
}
|
||||
|
||||
export interface UnitSpawnOptions {
|
||||
|
||||
@ -259,7 +259,7 @@ export function randomUnitBlueprint(unitDatabase: UnitDatabase, options: {type?:
|
||||
if (options.ranges) {
|
||||
unitBlueprints = unitBlueprints.filter((unitBlueprint: UnitBlueprint) => {
|
||||
//@ts-ignore
|
||||
return unitBlueprint.range? options.ranges.includes(unitBlueprint.range): true;
|
||||
return unitBlueprint.rangeType? options.ranges.includes(unitBlueprint.rangeType): true;
|
||||
});
|
||||
}
|
||||
|
||||
@ -351,6 +351,16 @@ export function enumToCoalition(coalitionID: number) {
|
||||
return "";
|
||||
}
|
||||
|
||||
export function coalitionToEnum(coalition: string) {
|
||||
switch (coalition){
|
||||
case "neutral": return 0;
|
||||
case "red": return 1;
|
||||
case "blue": return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
export function convertDateAndTimeToDate(dateAndTime: DateAndTime) {
|
||||
const date = dateAndTime.date;
|
||||
const time = dateAndTime.time;
|
||||
|
||||
@ -17,6 +17,7 @@ export class UnitControlPanel extends Panel {
|
||||
#speedTypeSwitch: Switch;
|
||||
#onOffSwitch: Switch;
|
||||
#followRoadsSwitch: Switch;
|
||||
#operateAsSwitch: Switch;
|
||||
#TACANXYDropdown: Dropdown;
|
||||
#radioDecimalsDropdown: Dropdown;
|
||||
#radioCallsignDropdown: Dropdown;
|
||||
@ -67,6 +68,11 @@ export class UnitControlPanel extends Panel {
|
||||
getApp().getUnitsManager().selectedUnitsSetFollowRoads(value);
|
||||
});
|
||||
|
||||
/* Operate as */
|
||||
this.#operateAsSwitch = new Switch("operate-as-switch", (value: boolean) => {
|
||||
getApp().getUnitsManager().selectedUnitsSetOperateAs(value);
|
||||
});
|
||||
|
||||
/* Advanced settings dialog */
|
||||
this.#advancedSettingsDialog = <HTMLElement> document.querySelector("#advanced-settings-dialog");
|
||||
|
||||
@ -80,21 +86,28 @@ export class UnitControlPanel extends Panel {
|
||||
/* Events and timer */
|
||||
window.setInterval(() => {this.update();}, 25);
|
||||
|
||||
document.addEventListener("unitsSelection", (e: CustomEvent<Unit[]>) => { this.show(); this.addButtons();});
|
||||
document.addEventListener("clearSelection", () => { this.hide() });
|
||||
document.addEventListener("unitsSelection", (e: CustomEvent<Unit[]>) => {
|
||||
this.show();
|
||||
this.addButtons();
|
||||
this.#updateRapidControls();
|
||||
});
|
||||
document.addEventListener("clearSelection", () => {
|
||||
this.hide();
|
||||
this.#updateRapidControls();
|
||||
});
|
||||
document.addEventListener("applyAdvancedSettings", () => {this.#applyAdvancedSettings();})
|
||||
document.addEventListener("showAdvancedSettings", () => {
|
||||
this.#updateAdvancedSettingsDialog(getApp().getUnitsManager().getSelectedUnits());
|
||||
this.#advancedSettingsDialog.classList.remove("hide");
|
||||
});
|
||||
|
||||
this.hide();
|
||||
|
||||
// This is for when a ctrl-click happens on the map for deselection and we need to remove the selected unit from the panel
|
||||
/* This is for when a ctrl-click happens on the map for deselection and we need to remove the selected unit from the panel */
|
||||
document.addEventListener( "unitDeselection", ( ev:CustomEventInit ) => {
|
||||
this.getElement().querySelector( `button[data-unit-id="${ev.detail.ID}"]` )?.remove();
|
||||
this.#updateRapidControls();
|
||||
});
|
||||
|
||||
|
||||
this.hide();
|
||||
}
|
||||
|
||||
show() {
|
||||
@ -157,6 +170,7 @@ export class UnitControlPanel extends Panel {
|
||||
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-on-off", (this.#selectedUnitsTypes.includes("GroundUnit") || this.#selectedUnitsTypes.includes("NavyUnit")) && !(this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter")));
|
||||
element.toggleAttribute("data-show-follow-roads", (this.#selectedUnitsTypes.length == 1 && this.#selectedUnitsTypes.includes("GroundUnit")));
|
||||
element.toggleAttribute("data-show-operate-as", getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getCoalition()}) === "neutral");
|
||||
element.toggleAttribute("data-show-advanced-settings-button", this.#units.length == 1);
|
||||
|
||||
if (this.#selectedUnitsTypes.length == 1) {
|
||||
@ -167,6 +181,7 @@ export class UnitControlPanel extends Panel {
|
||||
var desiredSpeedType = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredSpeedType()});
|
||||
var onOff = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getOnOff()});
|
||||
var followRoads = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getFollowRoads()});
|
||||
var operateAs = getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getOperateAs()});
|
||||
|
||||
this.#altitudeTypeSwitch.setValue(desiredAltitudeType != undefined? desiredAltitudeType == "ASL": undefined, false);
|
||||
this.#speedTypeSwitch.setValue(desiredSpeedType != undefined? desiredSpeedType == "CAS": undefined, false);
|
||||
@ -204,6 +219,60 @@ export class UnitControlPanel extends Panel {
|
||||
|
||||
this.#onOffSwitch.setValue(onOff, false);
|
||||
this.#followRoadsSwitch.setValue(followRoads, false);
|
||||
this.#operateAsSwitch.setValue(operateAs? operateAs === "blue": undefined, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#updateRapidControls() {
|
||||
var options: { [key: string]: { text: string, tooltip: string, type: string } } | null = null;
|
||||
|
||||
var selectedUnits = getApp().getUnitsManager().getSelectedUnits();
|
||||
|
||||
var showAltitudeChange = selectedUnits.some((unit: Unit) => {return ["Aircraft", "Helicopter"].includes(unit.getCategory());});
|
||||
this.getElement().querySelector("#climb")?.classList.toggle("hide", !showAltitudeChange);
|
||||
this.getElement().querySelector("#descend")?.classList.toggle("hide", !showAltitudeChange);
|
||||
|
||||
/* Keep only the common "and" options, unless a single unit is selected */
|
||||
selectedUnits.forEach((unit: Unit) => {
|
||||
var unitOptions = unit.getActions();
|
||||
if (options === null) {
|
||||
options = unitOptions;
|
||||
} else {
|
||||
/* Delete all the "or" type options */
|
||||
for (let optionKey in options) {
|
||||
if (options[optionKey].type == "or") {
|
||||
delete options[optionKey];
|
||||
}
|
||||
}
|
||||
|
||||
/* Options of "and" type get shown if ALL units have it */
|
||||
for (let optionKey in options) {
|
||||
if (!(optionKey in unitOptions)) {
|
||||
delete options[optionKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
options = options ?? {};
|
||||
|
||||
const rapidControlsContainer = this.getElement().querySelector("#rapid-controls") as HTMLElement;
|
||||
const unitActionButtons = rapidControlsContainer.querySelectorAll(".unit-action-button");
|
||||
for (let button of unitActionButtons) {
|
||||
rapidControlsContainer.removeChild(button);
|
||||
}
|
||||
|
||||
for (let option in options) {
|
||||
let button = document.createElement("button");
|
||||
button.title = options[option].tooltip;
|
||||
button.classList.add("ol-button", "unit-action-button");
|
||||
button.id = option;
|
||||
rapidControlsContainer.appendChild(button);
|
||||
button.onclick = () => {
|
||||
/* Since only common actions are shown in the rapid controls, we execute it only on the first unit */
|
||||
if (selectedUnits.length > 0)
|
||||
selectedUnits[0].executeAction(null, option);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -295,6 +295,13 @@ export class ServerManager {
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setOperateAs(ID: number, operateAs: number, callback: CallableFunction = () => {}) {
|
||||
var command = { "ID": ID, "operateAs": operateAs }
|
||||
var data = { "setOperateAs": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
|
||||
refuel(ID: number, callback: CallableFunction = () => {}) {
|
||||
var command = { "ID": ID };
|
||||
var data = { "refuel": command }
|
||||
@ -331,6 +338,18 @@ export class ServerManager {
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
scenicAAA(ID: number, coalition: string, callback: CallableFunction = () => {}) {
|
||||
var command = { "ID": ID, "coalition": coalition }
|
||||
var data = { "scenicAAA": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
missOnPurpose(ID: number, coalition: string, callback: CallableFunction = () => {}) {
|
||||
var command = { "ID": ID, "coalition": coalition }
|
||||
var data = { "missOnPurpose": command }
|
||||
this.PUT(data, callback);
|
||||
}
|
||||
|
||||
setAdvacedOptions(ID: number, isTanker: boolean, isAWACS: boolean, TACAN: TACAN, radio: Radio, generalSettings: GeneralSettings, callback: CallableFunction = () => {}) {
|
||||
var command = {
|
||||
"ID": ID,
|
||||
|
||||
@ -115,7 +115,7 @@ export class UnitDatabase {
|
||||
var filteredBlueprints = this.getBlueprints();
|
||||
var ranges: string[] = [];
|
||||
for (let unit in filteredBlueprints) {
|
||||
var range = filteredBlueprints[unit].range;
|
||||
var range = filteredBlueprints[unit].rangeType;
|
||||
if (range && range !== "" && !ranges.includes(range))
|
||||
ranges.push(range);
|
||||
}
|
||||
@ -127,7 +127,7 @@ export class UnitDatabase {
|
||||
var filteredBlueprints = this.getBlueprints();
|
||||
var unitswithrange = [];
|
||||
for (let unit in filteredBlueprints) {
|
||||
if (filteredBlueprints[unit].range === range) {
|
||||
if (filteredBlueprints[unit].rangeType === range) {
|
||||
unitswithrange.push(filteredBlueprints[unit]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Marker, LatLng, Polyline, Icon, DivIcon, CircleMarker, Map, Point } from 'leaflet';
|
||||
import { getApp } from '..';
|
||||
import { enumToCoalition, enumToEmissioNCountermeasure, getMarkerCategoryByName, enumToROE, enumToReactionToThreat, enumToState, getUnitDatabaseByCategory, mToFt, msToKnots, rad2deg, bearing, deg2rad, ftToM, getGroundElevation } from '../other/utils';
|
||||
import { enumToCoalition, enumToEmissioNCountermeasure, getMarkerCategoryByName, enumToROE, enumToReactionToThreat, enumToState, getUnitDatabaseByCategory, mToFt, msToKnots, rad2deg, bearing, deg2rad, ftToM, getGroundElevation, coalitionToEnum } from '../other/utils';
|
||||
import { CustomMarker } from '../map/markers/custommarker';
|
||||
import { SVGInjector } from '@tanem/svg-injector';
|
||||
import { UnitDatabase } from './databases/unitdatabase';
|
||||
@ -77,6 +77,7 @@ export class Unit extends CustomMarker {
|
||||
#contacts: Contact[] = [];
|
||||
#activePath: LatLng[] = [];
|
||||
#isLeader: boolean = false;
|
||||
#operateAs: string = "blue";
|
||||
|
||||
#selectable: boolean;
|
||||
#selected: boolean = false;
|
||||
@ -130,6 +131,7 @@ export class Unit extends CustomMarker {
|
||||
getContacts() { return this.#contacts };
|
||||
getActivePath() { return this.#activePath };
|
||||
getIsLeader() { return this.#isLeader };
|
||||
getOperateAs() { return this.#operateAs };
|
||||
|
||||
static getConstructor(type: string) {
|
||||
if (type === "GroundUnit") return GroundUnit;
|
||||
@ -232,6 +234,7 @@ export class Unit extends CustomMarker {
|
||||
case DataIndexes.contacts: this.#contacts = dataExtractor.extractContacts(); document.dispatchEvent(new CustomEvent("contactsUpdated", { detail: this })); break;
|
||||
case DataIndexes.activePath: this.#activePath = dataExtractor.extractActivePath(); break;
|
||||
case DataIndexes.isLeader: this.#isLeader = dataExtractor.extractBool(); break;
|
||||
case DataIndexes.operateAs: this.#operateAs = enumToCoalition(dataExtractor.extractUInt8()); break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -291,7 +294,8 @@ export class Unit extends CustomMarker {
|
||||
ammo: this.#ammo,
|
||||
contacts: this.#contacts,
|
||||
activePath: this.#activePath,
|
||||
isLeader: this.#isLeader
|
||||
isLeader: this.#isLeader,
|
||||
operateAs: this.#operateAs
|
||||
}
|
||||
}
|
||||
|
||||
@ -588,15 +592,7 @@ export class Unit extends CustomMarker {
|
||||
}
|
||||
|
||||
isInViewport() {
|
||||
|
||||
const mapBounds = getApp().getMap().getBounds();
|
||||
const unitPos = this.getPosition();
|
||||
|
||||
return (unitPos.lng > mapBounds.getWest()
|
||||
&& unitPos.lng < mapBounds.getEast()
|
||||
&& unitPos.lat > mapBounds.getSouth()
|
||||
&& unitPos.lat < mapBounds.getNorth());
|
||||
|
||||
return getApp().getMap().getBounds().contains(this.getPosition());
|
||||
}
|
||||
|
||||
/********************** Unit commands *************************/
|
||||
@ -693,6 +689,11 @@ export class Unit extends CustomMarker {
|
||||
getApp().getServerManager().setFollowRoads(this.ID, followRoads);
|
||||
}
|
||||
|
||||
setOperateAs(operateAs: string) {
|
||||
if (!this.#human)
|
||||
getApp().getServerManager().setOperateAs(this.ID, coalitionToEnum(operateAs));
|
||||
}
|
||||
|
||||
delete(explosion: boolean, immediate: boolean) {
|
||||
getApp().getServerManager().deleteUnit(this.ID, explosion, immediate);
|
||||
}
|
||||
@ -739,6 +740,49 @@ export class Unit extends CustomMarker {
|
||||
});
|
||||
}
|
||||
|
||||
scenicAAA() {
|
||||
var coalition = "neutral";
|
||||
if (this.getCoalition() === "red")
|
||||
coalition = "blue";
|
||||
else if (this.getCoalition() == "blue")
|
||||
coalition = "red";
|
||||
//TODO
|
||||
getApp().getServerManager().scenicAAA(this.ID, coalition);
|
||||
}
|
||||
|
||||
missOnPurpose() {
|
||||
var coalition = "neutral";
|
||||
if (this.getCoalition() === "red")
|
||||
coalition = "blue";
|
||||
else if (this.getCoalition() == "blue")
|
||||
coalition = "red";
|
||||
//TODO
|
||||
getApp().getServerManager().missOnPurpose(this.ID, coalition);
|
||||
}
|
||||
|
||||
/***********************************************/
|
||||
getActions(): { [key: string]: { text: string, tooltip: string, type: string } } {
|
||||
/* To be implemented by child classes */ // TODO make Unit an abstract class
|
||||
return {};
|
||||
}
|
||||
|
||||
executeAction(e: any, action: string) {
|
||||
if (action === "center-map")
|
||||
getApp().getMap().centerOnUnit(this.ID);
|
||||
if (action === "attack")
|
||||
getApp().getUnitsManager().selectedUnitsAttackUnit(this.ID);
|
||||
else if (action === "refuel")
|
||||
getApp().getUnitsManager().selectedUnitsRefuel();
|
||||
else if (action === "group-ground" || action === "group-navy")
|
||||
getApp().getUnitsManager().selectedUnitsCreateGroup();
|
||||
else if (action === "scenic-aaa")
|
||||
getApp().getUnitsManager().selectedUnitsScenicAAA();
|
||||
else if (action === "miss-aaa")
|
||||
getApp().getUnitsManager().selectedUnitsMissOnPurpose();
|
||||
else if (action === "follow")
|
||||
this.#showFollowOptions(e);
|
||||
}
|
||||
|
||||
/***********************************************/
|
||||
onAdd(map: Map): this {
|
||||
super.onAdd(map);
|
||||
@ -752,18 +796,18 @@ export class Unit extends CustomMarker {
|
||||
if (this.#waitingForDoubleClick) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// We'll wait for a doubleclick
|
||||
this.#waitingForDoubleClick = true;
|
||||
|
||||
this.#doubleClickTimer = window.setTimeout(() => {
|
||||
this.#doubleClickTimer = window.setTimeout(() => {
|
||||
|
||||
// Still waiting so no doubleclick; do the click action
|
||||
if (this.#waitingForDoubleClick) {
|
||||
if (getApp().getMap().getState() === IDLE || getApp().getMap().getState() === MOVE_UNIT || e.originalEvent.ctrlKey) {
|
||||
if (!e.originalEvent.ctrlKey)
|
||||
getApp().getUnitsManager().deselectAllUnits();
|
||||
|
||||
|
||||
this.setSelected(!this.getSelected());
|
||||
const detail = { "detail": { "unit": this } };
|
||||
if (this.getSelected())
|
||||
@ -779,7 +823,6 @@ export class Unit extends CustomMarker {
|
||||
}
|
||||
|
||||
#onDoubleClick(e: any) {
|
||||
|
||||
// Let single clicks work again
|
||||
this.#waitingForDoubleClick = false;
|
||||
clearTimeout(this.#doubleClickTimer);
|
||||
@ -792,49 +835,49 @@ export class Unit extends CustomMarker {
|
||||
});
|
||||
}
|
||||
|
||||
#onContextMenu(e: any) {
|
||||
var options: { [key: string]: { text: string, tooltip: string } } = {};
|
||||
const selectedUnits = getApp().getUnitsManager().getSelectedUnits();
|
||||
const selectedUnitTypes = getApp().getUnitsManager().getSelectedUnitsCategories();
|
||||
getActionOptions() {
|
||||
var options: { [key: string]: { text: string, tooltip: string, type: string } } | null = null;
|
||||
|
||||
options["center-map"] = { text: "Center map", tooltip: "Center the map on the unit and follow it" };
|
||||
var units = getApp().getUnitsManager().getSelectedUnits();
|
||||
units.push(this);
|
||||
|
||||
if (selectedUnits.length > 0 && !(selectedUnits.length == 1 && (selectedUnits.includes(this)))) {
|
||||
options["attack"] = { text: "Attack", tooltip: "Attack the unit using A/A or A/G weapons" };
|
||||
if (getApp().getUnitsManager().getSelectedUnitsCategories().length == 1 && getApp().getUnitsManager().getSelectedUnitsCategories()[0] === "Aircraft")
|
||||
options["follow"] = { text: "Follow", tooltip: "Follow the unit at a user defined distance and position" };;
|
||||
}
|
||||
else if ((selectedUnits.length > 0 && (selectedUnits.includes(this))) || selectedUnits.length == 0) {
|
||||
if (this.getCategory() == "Aircraft") {
|
||||
options["refuel"] = { text: "Air to air refuel", tooltip: "Refuel units at the nearest AAR Tanker. If no tanker is available the unit will RTB." }; // TODO Add some way of knowing which aircraft can AAR
|
||||
/* Keep only the common "or" options or any "and" option */
|
||||
units.forEach((unit: Unit) => {
|
||||
var unitOptions = unit.getActions();
|
||||
if (options === null) {
|
||||
options = unitOptions;
|
||||
} else {
|
||||
/* Options of "or" type get shown if any one unit has it*/
|
||||
for (let optionKey in unitOptions) {
|
||||
if (unitOptions[optionKey].type == "or") {
|
||||
options[optionKey] = unitOptions[optionKey];
|
||||
}
|
||||
}
|
||||
|
||||
/* Options of "and" type get shown if ALL units have it */
|
||||
for (let optionKey in options) {
|
||||
if (!(optionKey in unitOptions)) {
|
||||
delete options[optionKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (selectedUnitTypes.length === 1 && ["NavyUnit", "GroundUnit"].includes(selectedUnitTypes[0]) && getApp().getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getCoalition()}) !== undefined)
|
||||
options["group"] = { text: "Create group", tooltip: "Create a group from the selected units." };
|
||||
return options ?? {};
|
||||
}
|
||||
|
||||
#onContextMenu(e: any) {
|
||||
var options = this.getActionOptions();
|
||||
|
||||
if (Object.keys(options).length > 0) {
|
||||
getApp().getMap().showUnitContextMenu(e.originalEvent.x, e.originalEvent.y, e.latlng);
|
||||
getApp().getMap().getUnitContextMenu().setOptions(options, (option: string) => {
|
||||
getApp().getMap().hideUnitContextMenu();
|
||||
this.#executeAction(e, option);
|
||||
this.executeAction(e, option);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#executeAction(e: any, action: string) {
|
||||
if (action === "center-map")
|
||||
getApp().getMap().centerOnUnit(this.ID);
|
||||
if (action === "attack")
|
||||
getApp().getUnitsManager().selectedUnitsAttackUnit(this.ID);
|
||||
else if (action === "refuel")
|
||||
getApp().getUnitsManager().selectedUnitsRefuel();
|
||||
else if (action === "group")
|
||||
getApp().getUnitsManager().selectedUnitsCreateGroup();
|
||||
else if (action === "follow")
|
||||
this.#showFollowOptions(e);
|
||||
}
|
||||
|
||||
#showFollowOptions(e: any) {
|
||||
var options: { [key: string]: { text: string, tooltip: string } } = {};
|
||||
|
||||
@ -874,14 +917,14 @@ export class Unit extends CustomMarker {
|
||||
var angleRad = deg2rad(angleDeg);
|
||||
var distance = ftToM(parseInt((<HTMLInputElement>dialog.querySelector(`#distance`)?.querySelector("input")).value));
|
||||
var upDown = ftToM(parseInt((<HTMLInputElement>dialog.querySelector(`#up-down`)?.querySelector("input")).value));
|
||||
|
||||
|
||||
// X: front-rear, positive front
|
||||
// Y: top-bottom, positive top
|
||||
// Z: left-right, positive right
|
||||
var x = distance * Math.cos(angleRad);
|
||||
var y = upDown;
|
||||
var z = distance * Math.sin(angleRad);
|
||||
|
||||
|
||||
getApp().getUnitsManager().selectedUnitsFollowUnit(this.ID, { "x": x, "y": y, "z": z });
|
||||
}
|
||||
});
|
||||
@ -1148,6 +1191,37 @@ export class AirUnit extends Unit {
|
||||
rotateToHeading: false
|
||||
};
|
||||
}
|
||||
|
||||
getActions() {
|
||||
var options: { [key: string]: { text: string, tooltip: string, type: string } } = {};
|
||||
|
||||
/* Options if this unit is not selected */
|
||||
if (!this.getSelected()) {
|
||||
/* Someone else is selected */
|
||||
if (getApp().getUnitsManager().getSelectedUnits().length > 0) {
|
||||
options["attack"] = { text: "Attack", tooltip: "Attack the unit using A/A or A/G weapons", type: "or" };
|
||||
options["follow"] = { text: "Follow", tooltip: "Follow the unit at a user defined distance and position", type: "or" };
|
||||
} else {
|
||||
options["center-map"] = { text: "Center map", tooltip: "Center the map on the unit and follow it", type: "and" };
|
||||
}
|
||||
}
|
||||
/* Options if this unit is selected*/
|
||||
else if (this.getSelected()) {
|
||||
/* This is the only selected unit */
|
||||
if (getApp().getUnitsManager().getSelectedUnits().length == 1) {
|
||||
options["center-map"] = { text: "Center map", tooltip: "Center the map on the unit and follow it", type: "and" };
|
||||
} else {
|
||||
/* Provision */
|
||||
}
|
||||
|
||||
options["refuel"] = { text: "Air to air refuel", tooltip: "Refuel units at the nearest AAR Tanker. If no tanker is available the unit will RTB.", type: "and" }; // TODO Add some way of knowing which aircraft can AAR
|
||||
}
|
||||
/* All other options */
|
||||
else {
|
||||
/* Provision */
|
||||
}
|
||||
return options;
|
||||
}
|
||||
}
|
||||
|
||||
export class Aircraft extends AirUnit {
|
||||
@ -1191,6 +1265,39 @@ export class GroundUnit extends Unit {
|
||||
};
|
||||
}
|
||||
|
||||
getActions() {
|
||||
var options: { [key: string]: { text: string, tooltip: string, type: string } } = {};
|
||||
|
||||
/* Options if this unit is not selected */
|
||||
if (!this.getSelected()) {
|
||||
/* Someone else is selected */
|
||||
if (getApp().getUnitsManager().getSelectedUnits().length > 0) {
|
||||
options["attack"] = { text: "Attack", tooltip: "Attack the unit using A/A or A/G weapons", type: "or" };
|
||||
} else {
|
||||
options["center-map"] = { text: "Center map", tooltip: "Center the map on the unit and follow it", type: "and" };
|
||||
}
|
||||
}
|
||||
/* Options if this unit is selected*/
|
||||
else if (this.getSelected()) {
|
||||
/* This is the only selected unit */
|
||||
if (getApp().getUnitsManager().getSelectedUnits().length == 1) {
|
||||
options["center-map"] = { text: "Center map", tooltip: "Center the map on the unit and follow it", type: "and" };
|
||||
} else {
|
||||
options["group-ground"] = { text: "Create group", tooltip: "Create a group from the selected units", type: "and" };
|
||||
}
|
||||
|
||||
if (["AAA", "flak"].includes(this.getType())) {
|
||||
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" };
|
||||
}
|
||||
}
|
||||
/* All other options */
|
||||
else {
|
||||
/* Provision */
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
getCategory() {
|
||||
return "GroundUnit";
|
||||
}
|
||||
@ -1222,6 +1329,34 @@ export class NavyUnit extends Unit {
|
||||
};
|
||||
}
|
||||
|
||||
getActions() {
|
||||
var options: { [key: string]: { text: string, tooltip: string, type: string } } = {};
|
||||
|
||||
/* Options if this unit is not selected */
|
||||
if (!this.getSelected()) {
|
||||
/* Someone else is selected */
|
||||
if (getApp().getUnitsManager().getSelectedUnits().length > 0) {
|
||||
options["attack"] = { text: "Attack", tooltip: "Attack the unit using A/A or A/G weapons", type: "or" };
|
||||
} else {
|
||||
options["center-map"] = { text: "Center map", tooltip: "Center the map on the unit and follow it", type: "and" };
|
||||
}
|
||||
}
|
||||
/* Options if this unit is selected */
|
||||
else if (this.getSelected()) {
|
||||
/* This is the only selected unit */
|
||||
if (getApp().getUnitsManager().getSelectedUnits().length == 1) {
|
||||
options["center-map"] = { text: "Center map", tooltip: "Center the map on the unit and follow it", type: "and" };
|
||||
} else {
|
||||
options["group-navy"] = { text: "Create group", tooltip: "Create a group from the selected units", type: "and" };
|
||||
}
|
||||
}
|
||||
/* All other options */
|
||||
else {
|
||||
/* Provision */
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
getMarkerCategory() {
|
||||
return "navyunit";
|
||||
}
|
||||
|
||||
@ -504,6 +504,19 @@ export class UnitsManager {
|
||||
this.#showActionMessage(selectedUnits, `follow roads set to ${followRoads}`);
|
||||
}
|
||||
|
||||
/** Instruct selected units to operate as a certain coalition
|
||||
*
|
||||
* @param operateAsBool If true, units will operate as blue
|
||||
*/
|
||||
selectedUnitsSetOperateAs(operateAsBool: boolean) {
|
||||
var operateAs = operateAsBool? "blue": "red";
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].setOperateAs(operateAs);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `operate as set to ${operateAs}`);
|
||||
}
|
||||
|
||||
/** Instruct units to attack a specific unit
|
||||
*
|
||||
* @param ID ID of the unit to attack
|
||||
@ -629,6 +642,28 @@ export class UnitsManager {
|
||||
});
|
||||
this.#showActionMessage(selectedUnits, `unit simulating fire fight`);
|
||||
}
|
||||
|
||||
/** Instruct units to enter into scenic AAA mode. Units will shoot in the air without aiming
|
||||
*
|
||||
*/
|
||||
selectedUnitsScenicAAA() {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].scenicAAA();
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `unit set to perform scenic AAA`);
|
||||
}
|
||||
|
||||
/** Instruct units to enter into miss on purpose mode. Units will aim to the nearest enemy unit but not precisely.
|
||||
*
|
||||
*/
|
||||
selectedUnitsMissOnPurpose() {
|
||||
var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
|
||||
for (let idx in selectedUnits) {
|
||||
selectedUnits[idx].missOnPurpose();
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `unit set to perform miss on purpose AAA`);
|
||||
}
|
||||
|
||||
/*********************** Control operations on selected units ************************/
|
||||
/** See getUnitsCategories for more info
|
||||
|
||||
@ -61,6 +61,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="operate-as" class="switch-control">
|
||||
<h4>Operate as</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>
|
||||
@ -81,11 +87,11 @@
|
||||
</div>
|
||||
|
||||
<div id="rapid-controls" class="ol-panel">
|
||||
<button title="Increase altitude" class="ol-button" data-on-click="selectedUnitsChangeAltitude" data-on-click-params='{ "type": "climb" }'><img src="/resources/theme/images/icons/climb.svg" inject-svg></button>
|
||||
<button title="Decrease altitude" class="ol-button" data-on-click="selectedUnitsChangeAltitude" data-on-click-params='{ "type": "descend" }'><img src="/resources/theme/images/icons/descent.svg" inject-svg></button>
|
||||
<button title="Increase speed" class="ol-button" data-on-click="selectedUnitsChangeSpeed" data-on-click-params='{ "type": "fast" }'><img src="/resources/theme/images/icons/speed-increase.svg" inject-svg></button>
|
||||
<button title="Decrease speed" class="ol-button" data-on-click="selectedUnitsChangeSpeed" data-on-click-params='{ "type": "slow" }'><img src="/resources/theme/images/icons/speed-decrease.svg" inject-svg></button>
|
||||
<button title="Stop unit and go back to idle state" class="ol-button" data-on-click="selectedUnitsChangeSpeed" data-on-click-params='{ "type": "stop" }'><img src="/resources/theme/images/icons/hand-solid.svg" inject-svg></button>
|
||||
<button id="climb" title="Increase units altitude" class="ol-button" data-on-click="selectedUnitsChangeAltitude" data-on-click-params='{ "type": "climb" }'><img src="/resources/theme/images/icons/climb.svg" inject-svg></button>
|
||||
<button id="descend" title="Descrease units altitude" class="ol-button" data-on-click="selectedUnitsChangeAltitude" data-on-click-params='{ "type": "descend" }'><img src="/resources/theme/images/icons/descent.svg" inject-svg></button>
|
||||
<button id="fast" title="Increase units speed" class="ol-button" data-on-click="selectedUnitsChangeSpeed" data-on-click-params='{ "type": "fast" }'><img src="/resources/theme/images/icons/speed-increase.svg" inject-svg></button>
|
||||
<button id="slow" title="Decrease units speed" class="ol-button" data-on-click="selectedUnitsChangeSpeed" data-on-click-params='{ "type": "slow" }'><img src="/resources/theme/images/icons/speed-decrease.svg" inject-svg></button>
|
||||
<button id="stop" title="Stop unit and go back to idle state" class="ol-button" data-on-click="selectedUnitsChangeSpeed" data-on-click-params='{ "type": "stop" }'><img src="/resources/theme/images/icons/hand-solid.svg" inject-svg></button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -1,6 +1,6 @@
|
||||
local version = "v0.4.4-alpha"
|
||||
|
||||
local debug = true -- True enables debug printing using DCS messages
|
||||
local debug = false -- True enables debug printing using DCS messages
|
||||
|
||||
-- .dll related variables
|
||||
Olympus.OlympusDLL = nil
|
||||
@ -229,6 +229,14 @@ function Olympus.buildTask(groupName, options)
|
||||
-- Fire at a specific point
|
||||
elseif options['id'] == 'FireAtPoint' and options['lat'] and options['lng'] and options['radius'] then
|
||||
local point = coord.LLtoLO(options['lat'], options['lng'], 0)
|
||||
local expendQtyEnabled = false
|
||||
local expendQty = 0
|
||||
|
||||
if options['expendQty'] then
|
||||
expendQtyEnabled = true
|
||||
expendQty = options['expendQty']
|
||||
end
|
||||
|
||||
if options['alt'] then
|
||||
task = {
|
||||
id = 'FireAtPoint',
|
||||
@ -236,7 +244,9 @@ function Olympus.buildTask(groupName, options)
|
||||
point = {x = point.x, y = point.z},
|
||||
radius = options['radius'],
|
||||
altitude = options['alt'],
|
||||
alt_type = 0 -- ASL
|
||||
alt_type = 0, -- ASL
|
||||
expendQtyEnabled = expendQtyEnabled,
|
||||
expendQty = expendQty
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -244,7 +254,9 @@ function Olympus.buildTask(groupName, options)
|
||||
id = 'FireAtPoint',
|
||||
params = {
|
||||
point = {x = point.x, y = point.z},
|
||||
radius = options['radius']
|
||||
radius = options['radius'],
|
||||
expendQtyEnabled = expendQtyEnabled,
|
||||
expendQty = expendQty
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
77
scripts/python/addMissingUnits.py
Normal file
@ -0,0 +1,77 @@
|
||||
import sys
|
||||
import json
|
||||
import inspect
|
||||
import difflib
|
||||
from slpp import slpp as lua
|
||||
|
||||
SEARCH_FOLDER = "D:\\Eagle Dynamics\\DCS World OpenBeta"
|
||||
|
||||
sys.path.append("D:\\Documents\\dcs")
|
||||
|
||||
from dcs.vehicles import *
|
||||
from dcs.ships import *
|
||||
from dcs.planes import *
|
||||
from dcs.helicopters import *
|
||||
|
||||
# The database file on which to operate is the first standard argument of the call
|
||||
if len(sys.argv) > 1:
|
||||
if (sys.argv[1] == "aircraft"):
|
||||
filename = '..\\..\\client\\public\\databases\\units\\aircraftdatabase.json'
|
||||
units_map = plane_map
|
||||
elif (sys.argv[1] == "helicopter"):
|
||||
filename = '..\\..\\client\\public\\databases\\units\\helicopterdatabase.json'
|
||||
units_map = helicopter_map
|
||||
elif (sys.argv[1] == "groundunit"):
|
||||
filename = '..\\..\\client\\public\\databases\\units\\groundunitdatabase.json'
|
||||
units_map = vehicle_map
|
||||
elif (sys.argv[1] == "navyunit"):
|
||||
filename = '..\\..\\client\\public\\databases\\units\\navyunitdatabase.json'
|
||||
units_map = ship_map
|
||||
|
||||
# Loads the database
|
||||
with open(filename) as f:
|
||||
database = json.load(f)
|
||||
|
||||
for unit in units_map.values():
|
||||
if unit.id not in database:
|
||||
database[unit.id] = {
|
||||
"name": unit.id,
|
||||
"coalition": "",
|
||||
"era": "",
|
||||
"label": unit.name,
|
||||
"shortLabel": unit.name,
|
||||
"type": unit.__qualname__.split(".")[0],
|
||||
"enabled": True,
|
||||
"liveries": {}
|
||||
}
|
||||
print("Added missing unit " + unit.id)
|
||||
|
||||
to_remove = []
|
||||
to_change_case = {}
|
||||
for id in database:
|
||||
found = False
|
||||
for unit in units_map.values():
|
||||
if unit.id == id:
|
||||
found = True
|
||||
elif unit.id.lower() == id.lower() :
|
||||
to_change_case[unit.id] = database[id]
|
||||
|
||||
if not found:
|
||||
to_remove.append(id)
|
||||
|
||||
for id in to_remove:
|
||||
if database[id]["type"] == "SAM Site":
|
||||
print("Skipping " + id + ", it is a SAM Site")
|
||||
else:
|
||||
del database[id]
|
||||
print("Removed unit " + id)
|
||||
|
||||
for id in to_change_case:
|
||||
database[id] = to_change_case[id]
|
||||
print("Changed case of unit " + id)
|
||||
|
||||
# Dump everything in the database
|
||||
with open(filename, "w") as f:
|
||||
json.dump(database, f, indent=2)
|
||||
|
||||
print("Done!")
|
||||
@ -1,21 +0,0 @@
|
||||
import sys
|
||||
import json
|
||||
import inspect
|
||||
import difflib
|
||||
from slpp import slpp as lua
|
||||
|
||||
SEARCH_FOLDER = "D:\\Eagle Dynamics\\DCS World OpenBeta"
|
||||
|
||||
sys.path.append("..\\..\\..\\dcs-master\\dcs-master")
|
||||
|
||||
from dcs.vehicles import *
|
||||
|
||||
with open("gundata.h", "w") as f:
|
||||
for unit in vehicle_map.values():
|
||||
if unit in Artillery.__dict__.values() or unit in Armor.__dict__.values() or unit in Infantry.__dict__.values():
|
||||
f.write('{"' + unit.id + '", {0.9, 860}}, \n')
|
||||
|
||||
# Done!
|
||||
print("Done!")
|
||||
|
||||
|
||||
@ -1,109 +0,0 @@
|
||||
{"2B11 mortar", {0.9, 860}},
|
||||
{"SAU Gvozdika", {0.9, 860}},
|
||||
{"SAU Msta", {0.9, 860}},
|
||||
{"SAU Akatsia", {0.9, 860}},
|
||||
{"SAU 2-C9", {0.9, 860}},
|
||||
{"M-109", {0.9, 860}},
|
||||
{"SpGH_Dana", {0.9, 860}},
|
||||
{"AAV7", {0.9, 860}},
|
||||
{"BMD-1", {0.9, 860}},
|
||||
{"BMP-1", {0.9, 860}},
|
||||
{"BMP-2", {0.9, 860}},
|
||||
{"BMP-3", {0.9, 860}},
|
||||
{"BRDM-2", {0.9, 860}},
|
||||
{"BTR_D", {0.9, 860}},
|
||||
{"Cobra", {0.9, 860}},
|
||||
{"LAV-25", {0.9, 860}},
|
||||
{"M1043 HMMWV Armament", {0.9, 860}},
|
||||
{"M1045 HMMWV TOW", {0.9, 860}},
|
||||
{"M1126 Stryker ICV", {0.9, 860}},
|
||||
{"M-113", {0.9, 860}},
|
||||
{"M1134 Stryker ATGM", {0.9, 860}},
|
||||
{"M-2 Bradley", {0.9, 860}},
|
||||
{"MCV-80", {0.9, 860}},
|
||||
{"MTLB", {0.9, 860}},
|
||||
{"Marder", {0.9, 860}},
|
||||
{"TPZ", {0.9, 860}},
|
||||
{"Grad_FDDM", {0.9, 860}},
|
||||
{"Paratrooper RPG-16", {0.9, 860}},
|
||||
{"Paratrooper AKS-74", {0.9, 860}},
|
||||
{"Infantry AK Ins", {0.9, 860}},
|
||||
{"Soldier AK", {0.9, 860}},
|
||||
{"Infantry AK", {0.9, 860}},
|
||||
{"Soldier M249", {0.9, 860}},
|
||||
{"Soldier M4", {0.9, 860}},
|
||||
{"Soldier M4 GRG", {0.9, 860}},
|
||||
{"Soldier RPG", {0.9, 860}},
|
||||
{"MLRS FDDM", {0.9, 860}},
|
||||
{"Infantry AK ver2", {0.9, 860}},
|
||||
{"Infantry AK ver3", {0.9, 860}},
|
||||
{"Grad-URAL", {0.9, 860}},
|
||||
{"Uragan_BM-27", {0.9, 860}},
|
||||
{"Smerch", {0.9, 860}},
|
||||
{"Smerch_HE", {0.9, 860}},
|
||||
{"MLRS", {0.9, 860}},
|
||||
{"Challenger2", {0.9, 860}},
|
||||
{"Leclerc", {0.9, 860}},
|
||||
{"M-60", {0.9, 860}},
|
||||
{"M1128 Stryker MGS", {0.9, 860}},
|
||||
{"M-1 Abrams", {0.9, 860}},
|
||||
{"T-55", {0.9, 860}},
|
||||
{"T-72B", {0.9, 860}},
|
||||
{"T-80UD", {0.9, 860}},
|
||||
{"T-90", {0.9, 860}},
|
||||
{"Leopard1A3", {0.9, 860}},
|
||||
{"Merkava_Mk4", {0.9, 860}},
|
||||
{"JTAC", {0.9, 860}},
|
||||
{"Infantry Animated", {0.9, 860}},
|
||||
{"HL_DSHK", {0.9, 860}},
|
||||
{"HL_KORD", {0.9, 860}},
|
||||
{"tt_DSHK", {0.9, 860}},
|
||||
{"tt_KORD", {0.9, 860}},
|
||||
{"HL_B8M1", {0.9, 860}},
|
||||
{"tt_B8M1", {0.9, 860}},
|
||||
{"M4_Sherman", {0.9, 860}},
|
||||
{"M2A1_halftrack", {0.9, 860}},
|
||||
{"BTR-80", {0.9, 860}},
|
||||
{"T-72B3", {0.9, 860}},
|
||||
{"PT_76", {0.9, 860}},
|
||||
{"BTR-82A", {0.9, 860}},
|
||||
{"Chieftain_mk3", {0.9, 860}},
|
||||
{"Pz_IV_H", {0.9, 860}},
|
||||
{"Leopard-2A5", {0.9, 860}},
|
||||
{"Leopard-2", {0.9, 860}},
|
||||
{"leopard-2A4", {0.9, 860}},
|
||||
{"leopard-2A4_trs", {0.9, 860}},
|
||||
{"Sd_Kfz_251", {0.9, 860}},
|
||||
{"T155_Firtina", {0.9, 860}},
|
||||
{"VAB_Mephisto", {0.9, 860}},
|
||||
{"ZTZ96B", {0.9, 860}},
|
||||
{"ZBD04A", {0.9, 860}},
|
||||
{"PLZ05", {0.9, 860}},
|
||||
{"TYPE-59", {0.9, 860}},
|
||||
{"Tiger_I", {0.9, 860}},
|
||||
{"Tiger_II_H", {0.9, 860}},
|
||||
{"Pz_V_Panther_G", {0.9, 860}},
|
||||
{"Jagdpanther_G1", {0.9, 860}},
|
||||
{"JagdPz_IV", {0.9, 860}},
|
||||
{"Stug_IV", {0.9, 860}},
|
||||
{"SturmPzIV", {0.9, 860}},
|
||||
{"Wespe124", {0.9, 860}},
|
||||
{"Sd_Kfz_234_2_Puma", {0.9, 860}},
|
||||
{"soldier_mauser98", {0.9, 860}},
|
||||
{"Stug_III", {0.9, 860}},
|
||||
{"Elefant_SdKfz_184", {0.9, 860}},
|
||||
{"Pak40", {0.9, 860}},
|
||||
{"LeFH_18-40-105", {0.9, 860}},
|
||||
{"Cromwell_IV", {0.9, 860}},
|
||||
{"M4A4_Sherman_FF", {0.9, 860}},
|
||||
{"soldier_wwii_br_01", {0.9, 860}},
|
||||
{"Centaur_IV", {0.9, 860}},
|
||||
{"Churchill_VII", {0.9, 860}},
|
||||
{"Daimler_AC", {0.9, 860}},
|
||||
{"Tetrarch", {0.9, 860}},
|
||||
{"M12_GMC", {0.9, 860}},
|
||||
{"soldier_wwii_us", {0.9, 860}},
|
||||
{"M10_GMC", {0.9, 860}},
|
||||
{"M8_Greyhound", {0.9, 860}},
|
||||
{"M2A1-105", {0.9, 860}},
|
||||
{"M4_Tractor", {0.9, 860}},
|
||||
@ -43,6 +43,7 @@ namespace DataIndex {
|
||||
contacts,
|
||||
activePath,
|
||||
isLeader,
|
||||
operateAs,
|
||||
lastIndex,
|
||||
endOfData = 255
|
||||
};
|
||||
@ -65,7 +66,9 @@ namespace State
|
||||
CARPET_BOMB,
|
||||
BOMB_BUILDING,
|
||||
FIRE_AT_AREA,
|
||||
SIMULATE_FIRE_FIGHT
|
||||
SIMULATE_FIRE_FIGHT,
|
||||
SCENIC_AAA,
|
||||
MISS_ON_PURPOSE
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -100,6 +100,7 @@ public:
|
||||
virtual void setContacts(vector<DataTypes::Contact> newValue);
|
||||
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); }
|
||||
|
||||
/********** Getters **********/
|
||||
virtual string getCategory() { return category; };
|
||||
@ -140,6 +141,7 @@ public:
|
||||
virtual vector<DataTypes::Contact> getTargets() { return contacts; }
|
||||
virtual list<Coords> getActivePath() { return activePath; }
|
||||
virtual bool getIsLeader() { return isLeader; }
|
||||
virtual unsigned char getOperateAs() { return operateAs; }
|
||||
|
||||
protected:
|
||||
unsigned int ID;
|
||||
@ -182,10 +184,12 @@ protected:
|
||||
vector<DataTypes::Contact> contacts;
|
||||
list<Coords> activePath;
|
||||
bool isLeader = false;
|
||||
unsigned char operateAs = 2;
|
||||
Coords activeDestination = Coords(NULL);
|
||||
|
||||
/********** Other **********/
|
||||
unsigned int taskCheckCounter = 0;
|
||||
unsigned int internalCounter = 0;
|
||||
bool hasTaskAssigned = false;
|
||||
double initialFuel = 0;
|
||||
map<unsigned char, unsigned long long> updateTimeMap;
|
||||
|
||||
@ -23,7 +23,8 @@ public:
|
||||
void deleteUnit(unsigned int ID, bool explosion, bool immediate);
|
||||
void acquireControl(unsigned int ID);
|
||||
void loadDatabases();
|
||||
|
||||
Unit* getClosestUnit(Unit* unit, unsigned char coalition, vector<string> categories, double &distance);
|
||||
|
||||
private:
|
||||
map<unsigned int, Unit*> units;
|
||||
json::value missionDB;
|
||||
|
||||
@ -73,6 +73,12 @@ void GroundUnit::setState(unsigned char newState)
|
||||
setTargetPosition(Coords(NULL));
|
||||
break;
|
||||
}
|
||||
case State::SCENIC_AAA: {
|
||||
break;
|
||||
}
|
||||
case State::MISS_ON_PURPOSE: {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -99,6 +105,16 @@ void GroundUnit::setState(unsigned char newState)
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::SCENIC_AAA: {
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
case State::MISS_ON_PURPOSE: {
|
||||
clearActivePath();
|
||||
resetActiveDestination();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -156,11 +172,13 @@ void GroundUnit::AIloop()
|
||||
scheduler->appendCommand(command);
|
||||
setHasTask(true);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case State::SIMULATE_FIRE_FIGHT: {
|
||||
setTask("Simulating fire fight");
|
||||
|
||||
if (!getHasTask() || (((double)(rand()) / (double)(RAND_MAX)) < 0.002)) {
|
||||
if (!getHasTask() || internalCounter == 0) {
|
||||
double dist;
|
||||
double bearing1;
|
||||
double bearing2;
|
||||
@ -175,7 +193,6 @@ void GroundUnit::AIloop()
|
||||
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();
|
||||
log(to_string(barrelHeight) + " " + to_string(muzzleVelocity));
|
||||
}
|
||||
}
|
||||
|
||||
@ -193,6 +210,114 @@ void GroundUnit::AIloop()
|
||||
scheduler->appendCommand(command);
|
||||
setHasTask(true);
|
||||
}
|
||||
|
||||
if (internalCounter == 0)
|
||||
internalCounter = 20 / 0.05;
|
||||
internalCounter--;
|
||||
|
||||
break;
|
||||
}
|
||||
case State::SCENIC_AAA: {
|
||||
setTask("Scenic AAA");
|
||||
|
||||
if ((!getHasTask() || internalCounter == 0) && getOperateAs() > 0) {
|
||||
double distance = 0;
|
||||
unsigned char targetCoalition = getOperateAs() == 2 ? 1 : 2;
|
||||
Unit* target = unitsManager->getClosestUnit(this, targetCoalition, { "Aircraft", "Helicopter" }, distance);
|
||||
|
||||
/* Only run if an enemy air unit is closer than 20km to avoid useless load */
|
||||
if (distance < 20000 /* m */) {
|
||||
double r = 15; /* m */
|
||||
double barrelElevation = r * tan(acos(((double)(rand()) / (double)(RAND_MAX))));
|
||||
|
||||
double lat = 0;
|
||||
double lng = 0;
|
||||
double randomBearing = ((double)(rand()) / (double)(RAND_MAX)) * 360;
|
||||
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 << ", 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)
|
||||
internalCounter = 20 / 0.05;
|
||||
internalCounter--;
|
||||
|
||||
break;
|
||||
}
|
||||
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);
|
||||
|
||||
/* Only do if we have a valid target close enough for AAA */
|
||||
if (target != nullptr && distance < 10000 /* m */) {
|
||||
/* Default gun values */
|
||||
double barrelHeight = 1.0; /* m */
|
||||
double muzzleVelocity = 860; /* m/s */
|
||||
double aimTime = 10; /* s */
|
||||
unsigned int shotsToFire = 10;
|
||||
|
||||
if (database.has_object_field(to_wstring(name))) {
|
||||
json::value databaseEntry = database[to_wstring(name)];
|
||||
if (databaseEntry.has_number_field(L"barrelHeight"))
|
||||
barrelHeight = databaseEntry[L"barrelHeight"].as_number().to_double();
|
||||
if (databaseEntry.has_number_field(L"muzzleVelocity"))
|
||||
muzzleVelocity = databaseEntry[L"muzzleVelocity"].as_number().to_double();
|
||||
if (databaseEntry.has_number_field(L"aimTime"))
|
||||
aimTime = databaseEntry[L"aimTime"].as_number().to_double();
|
||||
if (databaseEntry.has_number_field(L"shotsToFire"))
|
||||
shotsToFire = databaseEntry[L"shotsToFire"].as_number().to_uint32();
|
||||
}
|
||||
|
||||
/* Approximate the flight time */
|
||||
if (muzzleVelocity != 0)
|
||||
aimTime += distance / muzzleVelocity;
|
||||
|
||||
internalCounter = (aimTime + 2) / 0.05;
|
||||
|
||||
/* 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 */
|
||||
|
||||
/* Compute distance to the aim point */
|
||||
double dist;
|
||||
double bearing1;
|
||||
double bearing2;
|
||||
Geodesic::WGS84().Inverse(position.lat, position.lng, aimLat, aimLng, dist, bearing1, bearing2);
|
||||
|
||||
/* 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);
|
||||
|
||||
setTargetPosition(Coords(aimLat, aimLng, target->getPosition().alt));
|
||||
}
|
||||
else {
|
||||
if (getHasTask())
|
||||
resetTask();
|
||||
}
|
||||
}
|
||||
|
||||
if (internalCounter == 0)
|
||||
internalCounter = 5 / 0.05;
|
||||
internalCounter--;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
|
||||
@ -390,6 +390,7 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
|
||||
Coords location; location.lat = lat; location.lng = lng;
|
||||
cloneOptions.push_back({ ID, location });
|
||||
log(username + " cloning unit with ID " + to_string(ID), true);
|
||||
}
|
||||
|
||||
command = dynamic_cast<Command*>(new Clone(cloneOptions, deleteOriginal));
|
||||
@ -575,7 +576,32 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
|
||||
unit->setTargetPosition(loc);
|
||||
log(username + " tasked unit " + unit->getName() + " to simulate a fire fight", true);
|
||||
}
|
||||
else if (key.compare("setCommandModeOptions") == 0) {
|
||||
else if (key.compare("scenicAAA") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unit->setState(State::SCENIC_AAA);
|
||||
log(username + " tasked unit " + unit->getName() + " to enter scenic AAA state", true);
|
||||
}
|
||||
else if (key.compare("missOnPurpose") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unit->setState(State::MISS_ON_PURPOSE);
|
||||
log(username + " tasked unit " + unit->getName() + " to enter Miss On Purpose state", true);
|
||||
}
|
||||
else if (key.compare("setOperateAs") == 0)
|
||||
{
|
||||
unsigned int ID = value[L"ID"].as_integer();
|
||||
unitsManager->acquireControl(ID);
|
||||
unsigned char operateAs = value[L"operateAs"].as_number().to_uint32();
|
||||
Unit* unit = unitsManager->getGroupLeader(ID);
|
||||
unit->setOperateAs(operateAs);
|
||||
}
|
||||
else if (key.compare("setCommandModeOptions") == 0)
|
||||
{
|
||||
setCommandModeOptions(value);
|
||||
log(username + " updated the Command Mode Options", true);
|
||||
}
|
||||
|
||||
@ -191,6 +191,7 @@ void Unit::refreshLeaderData(unsigned long long time) {
|
||||
case DataIndex::radio: updateValue(radio, leader->radio, datumIndex); break;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -270,6 +271,7 @@ void Unit::getData(stringstream& ss, unsigned long long time)
|
||||
case DataIndex::contacts: appendVector(ss, datumIndex, contacts); break;
|
||||
case DataIndex::activePath: appendList(ss, datumIndex, activePath); break;
|
||||
case DataIndex::isLeader: appendNumeric(ss, datumIndex, isLeader); break;
|
||||
case DataIndex::operateAs: appendNumeric(ss, datumIndex, operateAs); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,6 +11,9 @@
|
||||
#include "scheduler.h"
|
||||
#include "defines.h"
|
||||
|
||||
#include <GeographicLib/Geodesic.hpp>
|
||||
using namespace GeographicLib;
|
||||
|
||||
#include "base64.hpp"
|
||||
using namespace base64;
|
||||
|
||||
@ -148,6 +151,48 @@ void UnitsManager::deleteUnit(unsigned int ID, bool explosion, bool immediate)
|
||||
}
|
||||
}
|
||||
|
||||
Unit* UnitsManager::getClosestUnit(Unit* unit, unsigned char coalition, vector<string> categories, double &distance) {
|
||||
Unit* closestUnit = nullptr;
|
||||
distance = 0;
|
||||
|
||||
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 the closest unit has not been assigned yet, assign it to this unit */
|
||||
if (closestUnit == nullptr)
|
||||
{
|
||||
closestUnit = p.second;
|
||||
distance = dist;
|
||||
|
||||
}
|
||||
else {
|
||||
/* Check if the unit is closer than the one already selected */
|
||||
if (dist < distance) {
|
||||
closestUnit = p.second;
|
||||
distance = dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return closestUnit;
|
||||
}
|
||||
|
||||
void UnitsManager::acquireControl(unsigned int ID) {
|
||||
Unit* leader = getGroupLeader(ID);
|
||||
if (leader != nullptr) {
|
||||
|
||||