Merge pull request #436 from Pax1601/328-add-simple-miss-on-purpose-mode-for-aaa

328 add simple miss on purpose mode for aaa
This commit is contained in:
Pax1601 2023-10-05 10:04:52 +02:00 committed by GitHub
commit ace0908d84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 3028 additions and 568 deletions

View File

@ -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;

View File

@ -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'));

View File

@ -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");

View File

@ -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;
}

View File

@ -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)); });
}
}

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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",

View File

@ -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": {}
}
}

View File

@ -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");
}

View File

@ -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,

View File

@ -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);

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="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

View 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

View 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

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="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

View 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

View 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

View 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

View 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

View 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

View 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

View File

@ -197,5 +197,6 @@ export enum DataIndexes {
contacts,
activePath,
isLeader,
operateAs,
endOfData = 255
};

View File

@ -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 {

View File

@ -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;

View File

@ -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);
}
}
}

View File

@ -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,

View File

@ -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]);
}
}

View File

@ -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";
}

View File

@ -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

View File

@ -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>

View File

@ -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

View 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!")

View File

@ -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!")

View File

@ -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}},

View File

@ -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
};
};

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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;
}
}
}

View File

@ -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) {