From a038d6e9994468474f86c59172a93bbe085cb094 Mon Sep 17 00:00:00 2001 From: Pax1601 Date: Tue, 10 Oct 2023 17:10:29 +0200 Subject: [PATCH] Added "land at point" state for helicopters --- client/public/stylesheets/markers/units.css | 10 ++- .../public/stylesheets/other/contextmenus.css | 4 ++ .../olympus/images/icons/land-at-point.svg | 61 +++++++++++++++++++ .../olympus/images/states/land-at-point.svg | 51 ++++++++++++++++ client/src/constants/constants.ts | 2 +- client/src/map/map.ts | 12 +++- client/src/server/servermanager.ts | 6 ++ client/src/unit/unit.ts | 4 ++ client/src/unit/unitsmanager.ts | 13 ++++ scripts/OlympusCommand.lua | 11 +++- src/core/include/datatypes.h | 3 +- src/core/src/airunit.cpp | 25 ++++++++ src/core/src/scheduler.cpp | 16 +++++ 13 files changed, 210 insertions(+), 8 deletions(-) create mode 100644 client/public/themes/olympus/images/icons/land-at-point.svg create mode 100644 client/public/themes/olympus/images/states/land-at-point.svg diff --git a/client/public/stylesheets/markers/units.css b/client/public/stylesheets/markers/units.css index d4f88333..bb1a88ad 100644 --- a/client/public/stylesheets/markers/units.css +++ b/client/public/stylesheets/markers/units.css @@ -265,9 +265,9 @@ } [data-object|="unit"][data-state="attack"] .unit-state, -[data-object|="unit"][data-state="bombing point"] .unit-state, -[data-object|="unit"][data-state="carpet bombing"] .unit-state, -[data-object|="unit"][data-state="firing at area"] .unit-state { +[data-object|="unit"][data-state="bomb-point"] .unit-state, +[data-object|="unit"][data-state="carpet-bombing"] .unit-state, +[data-object|="unit"][data-state="fire-at-area"] .unit-state { background-image: url("/resources/theme/images/states/attack.svg"); } @@ -287,6 +287,10 @@ background-image: url("/resources/theme/images/states/dcs.svg"); } +[data-object|="unit"][data-state="land-at-point"] .unit-state { + background-image: url("/resources/theme/images/states/land-at-point.svg"); +} + [data-object|="unit"][data-state="no-task"] .unit-state { background-image: url("/resources/theme/images/states/no-task.svg"); } diff --git a/client/public/stylesheets/other/contextmenus.css b/client/public/stylesheets/other/contextmenus.css index 1e2c0843..53ddb6ed 100644 --- a/client/public/stylesheets/other/contextmenus.css +++ b/client/public/stylesheets/other/contextmenus.css @@ -420,6 +420,10 @@ content: url("/resources/theme/images/icons/group-navy.svg"); } +#land-at-point::before { + content: url("/resources/theme/images/icons/land-at-point.svg"); +} + #trail::before { content: url("/resources/theme/images/icons/trail.svg"); } diff --git a/client/public/themes/olympus/images/icons/land-at-point.svg b/client/public/themes/olympus/images/icons/land-at-point.svg new file mode 100644 index 00000000..8ed58233 --- /dev/null +++ b/client/public/themes/olympus/images/icons/land-at-point.svg @@ -0,0 +1,61 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/client/public/themes/olympus/images/states/land-at-point.svg b/client/public/themes/olympus/images/states/land-at-point.svg new file mode 100644 index 00000000..23bec41f --- /dev/null +++ b/client/public/themes/olympus/images/states/land-at-point.svg @@ -0,0 +1,51 @@ + + + + + + + + + diff --git a/client/src/constants/constants.ts b/client/src/constants/constants.ts index 0d602826..bd5b5532 100644 --- a/client/src/constants/constants.ts +++ b/client/src/constants/constants.ts @@ -20,7 +20,7 @@ export const IRST = 8; export const RWR = 16; export const DLINK = 32; -export const states: string[] = ["none", "idle", "reach-destination", "attack", "follow", "land", "refuel", "AWACS", "tanker", "bomb-point", "carpet-bomb", "bomb-building", "fire-at-area", "simulate-fire-fight"]; +export const states: string[] = ["none", "idle", "reach-destination", "attack", "follow", "land", "refuel", "AWACS", "tanker", "bomb-point", "carpet-bomb", "bomb-building", "fire-at-area", "simulate-fire-fight", "scenic-aaa", "miss-on-purpose", "land-at-point"]; export const ROEs: string[] = ["free", "designated", "", "return", "hold"]; export const reactionsToThreat: string[] = ["none", "manoeuvre", "passive", "evade"]; export const emissionsCountermeasures: string[] = ["silent", "attack", "defend", "free"]; diff --git a/client/src/map/map.ts b/client/src/map/map.ts index fc4d2fdb..7e9d51ab 100644 --- a/client/src/map/map.ts +++ b/client/src/map/map.ts @@ -24,8 +24,8 @@ import { TouchBoxSelect } from "./touchboxselect"; import { DestinationPreviewHandle } from "./markers/destinationpreviewHandle"; var hasTouchScreen = false; -if ("maxTouchPoints" in navigator) - hasTouchScreen = navigator.maxTouchPoints > 0; +//if ("maxTouchPoints" in navigator) +// hasTouchScreen = navigator.maxTouchPoints > 0; if (hasTouchScreen) L.Map.addInitHook('addHandler', 'boxSelect', TouchBoxSelect); @@ -607,6 +607,10 @@ export class Map extends L.Map { const selectedUnitTypes = getApp().getUnitsManager().getSelectedUnitsCategories(); if (selectedUnitTypes.length === 1 && ["Aircraft", "Helicopter"].includes(selectedUnitTypes[0])) { + if (selectedUnitTypes[0] === "Helicopter") { + options["land-at-point"] = { text: "Land here", tooltip: "Land at this precise location" }; + } + if (selectedUnits.every((unit: Unit) => { return unit.canFulfillRole(["CAS", "Strike"]) })) { options["bomb"] = { text: "Precision bombing", tooltip: "Precision bombing of a specific point" }; options["carpet-bomb"] = { text: "Carpet bombing", tooltip: "Carpet bombing close to a point" }; @@ -646,6 +650,10 @@ export class Map extends L.Map { getApp().getUnitsManager().getSelectedUnits().length > 0 ? this.setState(MOVE_UNIT) : this.setState(IDLE); getApp().getUnitsManager().selectedUnitsSimulateFireFight(this.getMouseCoordinates()); } + else if (option === "land-at-point") { + getApp().getUnitsManager().getSelectedUnits().length > 0 ? this.setState(MOVE_UNIT) : this.setState(IDLE); + getApp().getUnitsManager().selectedUnitsLandAtPoint(this.getMouseCoordinates()); + } }); } }, 150); diff --git a/client/src/server/servermanager.ts b/client/src/server/servermanager.ts index be2bfb5e..cf600561 100644 --- a/client/src/server/servermanager.ts +++ b/client/src/server/servermanager.ts @@ -351,6 +351,12 @@ export class ServerManager { this.PUT(data, callback); } + landAtPoint(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) { + var command = { "ID": ID, "location": latlng } + var data = { "landAtPoint": command } + this.PUT(data, callback); + } + setAdvacedOptions(ID: number, isTanker: boolean, isAWACS: boolean, TACAN: TACAN, radio: Radio, generalSettings: GeneralSettings, callback: CallableFunction = () => {}) { var command = { "ID": ID, diff --git a/client/src/unit/unit.ts b/client/src/unit/unit.ts index cb8ed83d..c849c49b 100644 --- a/client/src/unit/unit.ts +++ b/client/src/unit/unit.ts @@ -779,6 +779,10 @@ export class Unit extends CustomMarker { getApp().getServerManager().missOnPurpose(this.ID, coalition); } + landAtPoint(latlng: LatLng) { + getApp().getServerManager().landAtPoint(this.ID, latlng); + } + /***********************************************/ getActions(): { [key: string]: { text: string, tooltip: string, type: string } } { /* To be implemented by child classes */ // TODO make Unit an abstract class diff --git a/client/src/unit/unitsmanager.ts b/client/src/unit/unitsmanager.ts index 65696f21..f03e0fbd 100644 --- a/client/src/unit/unitsmanager.ts +++ b/client/src/unit/unitsmanager.ts @@ -666,6 +666,19 @@ export class UnitsManager { this.#showActionMessage(selectedUnits, `unit set to perform miss on purpose AAA`); } + /** Instruct units to land at specific point + * + * @param latlng Point where to land + */ + selectedUnitsLandAtPoint(latlng: LatLng) { + var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true }); + + for (let idx in selectedUnits) { + selectedUnits[idx].landAtPoint(latlng); + } + this.#showActionMessage(selectedUnits, `unit simulating fire fight`); + } + /*********************** Control operations on selected units ************************/ /** See getUnitsCategories for more info * diff --git a/scripts/OlympusCommand.lua b/scripts/OlympusCommand.lua index 28f4fe00..f1aa896e 100644 --- a/scripts/OlympusCommand.lua +++ b/scripts/OlympusCommand.lua @@ -1,6 +1,6 @@ local version = "v0.4.4-alpha" -local debug = false -- True enables debug printing using DCS messages +local debug = true -- True enables debug printing using DCS messages -- .dll related variables Olympus.OlympusDLL = nil @@ -260,6 +260,15 @@ function Olympus.buildTask(groupName, options) } } end + -- Land at a specific point + elseif options['id'] == 'LandAtPoint' then + local point = coord.LLtoLO(options['lat'], options['lng'], 0) + task = { + id = 'Land', + params = { + point = {x = point.x, y = point.z}, + } + } end end return task diff --git a/src/core/include/datatypes.h b/src/core/include/datatypes.h index dd098232..81a767af 100644 --- a/src/core/include/datatypes.h +++ b/src/core/include/datatypes.h @@ -68,7 +68,8 @@ namespace State FIRE_AT_AREA, SIMULATE_FIRE_FIGHT, SCENIC_AAA, - MISS_ON_PURPOSE + MISS_ON_PURPOSE, + LAND_AT_POINT }; }; diff --git a/src/core/src/airunit.cpp b/src/core/src/airunit.cpp index 2a5ced5a..3f1950e8 100644 --- a/src/core/src/airunit.cpp +++ b/src/core/src/airunit.cpp @@ -69,6 +69,9 @@ void AirUnit::setState(unsigned char newState) setTargetPosition(Coords(NULL)); break; } + case State::LAND_AT_POINT: { + break; + } default: break; } @@ -125,6 +128,10 @@ void AirUnit::setState(unsigned char newState) resetActiveDestination(); break; } + case State::LAND_AT_POINT: { + resetActiveDestination(); + break; + } default: break; } @@ -340,6 +347,24 @@ void AirUnit::AIloop() } break; } + case State::LAND_AT_POINT: { + setTask("Landing at point"); + + if (!getHasTask()) { + setActiveDestination(); + std::ostringstream taskSS; + taskSS.precision(10), + taskSS << "{" + << "id = 'LandAtPoint', " + << "lat = " << activeDestination.lat << ", " + << "lng = " << activeDestination.lng + << "}"; + Command* command = dynamic_cast(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); })); + scheduler->appendCommand(command); + setHasTask(true); + } + break; + } default: break; } diff --git a/src/core/src/scheduler.cpp b/src/core/src/scheduler.cpp index df480c32..28ad9459 100644 --- a/src/core/src/scheduler.cpp +++ b/src/core/src/scheduler.cpp @@ -600,6 +600,22 @@ void Scheduler::handleRequest(string key, json::value value, string username, js Unit* unit = unitsManager->getGroupLeader(ID); unit->setOperateAs(operateAs); } + else if (key.compare("landAtPoint") == 0) + { + unsigned int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); + double lat = value[L"location"][L"lat"].as_double(); + double lng = value[L"location"][L"lng"].as_double(); + Coords loc; loc.lat = lat; loc.lng = lng; + Unit* unit = unitsManager->getGroupLeader(ID); + + list newPath; + newPath.push_back(loc); + unit->setActivePath(newPath); + unit->setState(State::LAND_AT_POINT); + + log(username + " tasked unit " + unit->getName() + " to land at point", true); + } else if (key.compare("setCommandModeOptions") == 0) { setCommandModeOptions(value);