From 1f51d6912671437b4dcb1b9139a15c0339e968bf Mon Sep 17 00:00:00 2001 From: Pax1601 Date: Tue, 11 Apr 2023 15:20:17 +0200 Subject: [PATCH] Added basic tanker and AWACS enroute tasks Tanker not working propertly yet, frequency setting still needed --- client/src/@types/unit.d.ts | 2 ++ client/src/server/server.ts | 18 ++++++++++++ client/src/units/unit.ts | 50 +++++++++++++++++++++++++++++--- client/src/units/unitsmanager.ts | 27 +++++++++++++++++ scripts/OlympusCommand.lua | 21 ++++++++++++-- src/core/include/unit.h | 6 ++++ src/core/src/airunit.cpp | 40 +++++++++++++++++++++++-- src/core/src/scheduler.cpp | 20 +++++++++++++ 8 files changed, 176 insertions(+), 8 deletions(-) diff --git a/client/src/@types/unit.d.ts b/client/src/@types/unit.d.ts index b14a00b3..ad14a6ec 100644 --- a/client/src/@types/unit.d.ts +++ b/client/src/@types/unit.d.ts @@ -41,6 +41,8 @@ interface TaskData { activePath: any; targetSpeed: number; targetAltitude: number; + isTanker: boolean; + isAWACS: boolean; } interface OptionsData { diff --git a/client/src/server/server.ts b/client/src/server/server.ts index f45989fe..4e4c4e02 100644 --- a/client/src/server/server.ts +++ b/client/src/server/server.ts @@ -176,3 +176,21 @@ export function setReactionToThreat(ID: number, reactionToThreat: string) { var data = {"setReactionToThreat": command} POST(data, () => { }); } + +export function refuel(ID: number) { + var command = { "ID": ID }; + var data = { "refuel": command } + POST(data, () => { }); +} + +export function setTanker(ID: number, state: boolean) { + var command = { "ID": ID, "state": state }; + var data = { "setIsTanker": command } + POST(data, () => { }); +} + +export function setAWACS(ID: number, state: boolean) { + var command = { "ID": ID, "state": state }; + var data = { "setIsAWACS": command } + POST(data, () => { }); +} diff --git a/client/src/units/unit.ts b/client/src/units/unit.ts index 616d098c..41efeeb5 100644 --- a/client/src/units/unit.ts +++ b/client/src/units/unit.ts @@ -1,7 +1,7 @@ import { Marker, LatLng, Polyline, Icon, DivIcon } from 'leaflet'; import { getMap, getUnitsManager } from '..'; import { rad2deg } from '../other/utils'; -import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, getUnits, landAt, setAltitude, setReactionToThreat, setROE, setSpeed } from '../server/server'; +import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, getUnits, landAt, setAltitude, setReactionToThreat, setROE, setSpeed, refuel, setTanker, setAWACS } from '../server/server'; import { aircraftDatabase } from './aircraftdatabase'; import { groundUnitsDatabase } from './groundunitsdatabase'; @@ -50,6 +50,8 @@ export class Unit extends Marker { activePath: {}, targetSpeed: 0, targetAltitude: 0, + isTanker: false, + isAWACS: false, }, optionsData: { ROE: "", @@ -363,6 +365,18 @@ export class Unit extends Marker { deleteUnit(this.ID); } + refuel() { + refuel(this.ID); + } + + toggleTanker() { + setTanker(this.ID, !this.getTaskData().isTanker); + } + + toggleAWACS() { + setAWACS(this.ID, !this.getTaskData().isAWACS); + } + #onClick(e: any) { this.#timer = setTimeout(() => { if (!this.#preventClick) { @@ -383,10 +397,32 @@ export class Unit extends Marker { } #onContextMenu(e: any) { - var options = [ - 'Attack' - ] + var options: string[] = []; if (getUnitsManager().getSelectedUnits().length > 0 && !(getUnitsManager().getSelectedUnits().includes(this))) + { + options = [ + 'Attack' + ] + } + else if (getUnitsManager().getSelectedUnits().length > 0 && (getUnitsManager().getSelectedUnits().includes(this))) + { + if (this.getBaseData().category == "Aircraft") + { + options.push("Refuel"); // TODO Add some way of knowing which aircraft can AAR + + if (getUnitsManager().getSelectedUnits().length == 1){ + var roles = aircraftDatabase.getByName(this.getBaseData().name)?.loadouts.map((loadout) => {return loadout.roles}) + if (roles != undefined && Array.prototype.concat.apply([], roles)?.includes("Tanker")){ + options.push(this.getTaskData().isTanker? "Stop tanker": "Start tanker"); + } + if (roles != undefined && Array.prototype.concat.apply([], roles)?.includes("AWACS")){ + options.push(this.getTaskData().isAWACS? "Stop AWACS": "Start AWACS"); + } + } + } + } + + if (options.length > 0) { getMap().showUnitContextMenu(e); getMap().getUnitContextMenu().setOptions(options, (option: string) => { @@ -399,6 +435,12 @@ export class Unit extends Marker { #executeAction(action: string) { if (action === "Attack") getUnitsManager().selectedUnitsAttackUnit(this.ID); + if (action === "Refuel") + getUnitsManager().selectedUnitsRefuel(); + if (action === "Start tanker" || action === "Stop tanker") + getUnitsManager().selectedUnitsToggleTanker(); + if (action === "Start AWACS" || action === "Stop AWACS") + getUnitsManager().selectedUnitsToggleAWACS(); } #updateMarker() { diff --git a/client/src/units/unitsmanager.ts b/client/src/units/unitsmanager.ts index b8badd5e..754705b6 100644 --- a/client/src/units/unitsmanager.ts +++ b/client/src/units/unitsmanager.ts @@ -325,6 +325,33 @@ export class UnitsManager { } } + selectedUnitsRefuel() + { + var selectedUnits = this.getSelectedUnits(); + for (let idx in selectedUnits) + { + selectedUnits[idx].refuel(); + } + } + + selectedUnitsToggleTanker() + { + var selectedUnits = this.getSelectedUnits(); + for (let idx in selectedUnits) + { + selectedUnits[idx].toggleTanker(); + } + } + + selectedUnitsToggleAWACS() + { + var selectedUnits = this.getSelectedUnits(); + for (let idx in selectedUnits) + { + selectedUnits[idx].toggleAWACS(); + } + } + copyUnits() { this.#copiedUnits = this.getSelectedUnits(); diff --git a/scripts/OlympusCommand.lua b/scripts/OlympusCommand.lua index 429b6bb2..1563ebfb 100644 --- a/scripts/OlympusCommand.lua +++ b/scripts/OlympusCommand.lua @@ -1,6 +1,6 @@ local version = "v0.1.1-alpha" -local debug = false +local debug = true Olympus.unitCounter = 1 Olympus.payloadRegistry = {} @@ -79,6 +79,18 @@ function Olympus.buildEnrouteTask(options) } } end + -- Start being an active tanker + elseif options['id'] == 'Tanker' then + task = { + id = 'Tanker', + params = {}, + } + -- Start being an active AWACS + elseif options['id'] == 'AWACS' then + task = { + id = 'AWACS', + params = {}, + } end return task end @@ -86,7 +98,6 @@ end -- Builds a valid task depending on the provided options function Olympus.buildTask(options) local task = nil - -- Engage specific target by ID. Checks if target exists. if options['id'] == 'FollowUnit' and options['leaderID'] and options['offset'] then local leader = Olympus.getUnitByID(options['leaderID']) if leader and leader:isExist() then @@ -100,6 +111,11 @@ function Olympus.buildTask(options) } } end + elseif options['id'] == 'Refuel' then + task = { + id = 'Refueling', + params = {} + } end return task end @@ -356,6 +372,7 @@ function Olympus.setTask(ID, taskOptions) local unit = Olympus.getUnitByID(ID) if unit then local task = Olympus.buildTask(taskOptions); + Olympus.debug("Olympus.setTask " .. Olympus.serializeTable(task), 20) if task then unit:getGroup():getController():setTask(task) Olympus.debug("Olympus.setTask completed successfully", 2) diff --git a/src/core/include/unit.h b/src/core/include/unit.h index e5e27ef0..5dc3913f 100644 --- a/src/core/include/unit.h +++ b/src/core/include/unit.h @@ -103,12 +103,16 @@ public: void pushActivePathBack(Coords newActivePathBack); void popActivePathFront(); void setTargetID(int newTargetID) { targetID = newTargetID; addMeasure(L"targetID", json::value(newTargetID));} + void setIsTanker(bool newIsTanker) { isTanker = newIsTanker; addMeasure(L"isTanker", json::value(newIsTanker));} + void setIsAWACS(bool newIsAWACS) { isAWACS = newIsAWACS; addMeasure(L"isAWACS", json::value(newIsAWACS));} wstring getCurrentTask() { return currentTask; } virtual double getTargetSpeed() { return targetSpeed; }; virtual double getTargetAltitude() { return targetAltitude; }; Coords getActiveDestination() { return activeDestination; } list getActivePath() { return activePath; } int getTargetID() { return targetID; } + bool getIsTanker() { return isTanker; } + bool getIsAWACS() { return isAWACS; } /********** Options data **********/ void setROE(wstring newROE); @@ -168,6 +172,8 @@ protected: list activePath; Coords activeDestination = Coords(0); int targetID = NULL; + bool isTanker = false; + bool isAWACS = false; /********** Options data **********/ wstring ROE = L""; diff --git a/src/core/src/airunit.cpp b/src/core/src/airunit.cpp index 08922240..00214acc 100644 --- a/src/core/src/airunit.cpp +++ b/src/core/src/airunit.cpp @@ -22,6 +22,7 @@ void AirUnit::setState(int newState) { if (state != newState) { + /* Perform any action required when LEAVING a certain state */ switch (state) { case State::IDLE: { break; @@ -44,10 +45,14 @@ void AirUnit::setState(int newState) case State::LAND: { break; } + case State::REFUEL: { + break; + } default: break; } + /* Perform any action required when ENTERING a certain state */ switch (newState) { case State::IDLE: { resetActiveDestination(); @@ -79,6 +84,11 @@ void AirUnit::setState(int newState) resetActiveDestination(); break; } + case State::REFUEL: { + clearActivePath(); + resetActiveDestination(); + break; + } default: break; } @@ -225,8 +235,23 @@ void AirUnit::AIloop() break; } case State::REACH_DESTINATION: { - wstring enrouteTask = L"nil"; - currentTask = L"Reaching destination"; + wstring enrouteTask = L""; + + if (isTanker) + { + enrouteTask = L"{" "id = 'Tanker' }"; + currentTask = L"Tanker"; + } + else if (isAWACS) + { + enrouteTask = L"{" "id = 'AWACS' }"; + currentTask = L"AWACS"; + } + else + { + enrouteTask = L"nil"; + currentTask = L"Reaching destination"; + } if (activeDestination == NULL || !hasTask) { @@ -338,6 +363,17 @@ void AirUnit::AIloop() } break; } + case State::REFUEL: { + if (!hasTask) { + std::wostringstream taskSS; + taskSS << "{" + << "id = 'Refuel'" + << "}"; + Command* command = dynamic_cast(new SetTask(ID, taskSS.str())); + scheduler->appendCommand(command); + hasTask = true; + } + } default: break; } diff --git a/src/core/src/scheduler.cpp b/src/core/src/scheduler.cpp index 8e80f9bf..db4e83f1 100644 --- a/src/core/src/scheduler.cpp +++ b/src/core/src/scheduler.cpp @@ -250,6 +250,26 @@ void Scheduler::handleRequest(wstring key, json::value value) int ID = value[L"ID"].as_integer(); unitsManager->deleteUnit(ID); } + else if (key.compare(L"refuel") == 0) + { + int ID = value[L"ID"].as_integer(); + Unit* unit = unitsManager->getUnit(ID); + unit->setState(State::REFUEL); + } + else if (key.compare(L"setIsTanker") == 0) + { + int ID = value[L"ID"].as_integer(); + bool state = value[L"state"].as_bool(); + Unit* unit = unitsManager->getUnit(ID); + unit->setIsTanker(state); + } + else if (key.compare(L"setIsAWACS") == 0) + { + int ID = value[L"ID"].as_integer(); + bool state = value[L"state"].as_bool(); + Unit* unit = unitsManager->getUnit(ID); + unit->setIsAWACS(state); + } else { log(L"Unknown command: " + key);