diff --git a/client/src/atc/board/tower.ts b/client/src/atc/board/tower.ts index 5c7a0fb4..c1698966 100644 --- a/client/src/atc/board/tower.ts +++ b/client/src/atc/board/tower.ts @@ -1,5 +1,6 @@ import { getUnitsManager } from "../.."; import { Dropdown } from "../../controls/dropdown"; +import { mToFt, msToKnots } from "../../other/utils"; import { ATC } from "../atc"; import { ATCBoard } from "../atcboard"; @@ -139,7 +140,7 @@ export class ATCBoardTower extends ATCBoard { assignedAltitude.value = flight.assignedAltitude; } - flightData.altitude = Math.floor( flightData.altitude / 0.3048 ); + flightData.altitude = Math.floor( mToFt(flightData.altitude) ); strip.element.querySelectorAll( `[data-point="altitude"]` ).forEach( el => { if ( el instanceof HTMLElement ) { @@ -163,7 +164,7 @@ export class ATCBoardTower extends ATCBoard { assignedSpeed.value = flight.assignedSpeed; } - flightData.speed = Math.floor( flightData.speed * 1.94384 ); + flightData.speed = Math.floor( msToKnots(flightData.speed) ); strip.element.querySelectorAll( `[data-point="speed"]` ).forEach( el => { if ( el instanceof HTMLElement ) { diff --git a/client/src/controls/mapcontextmenu.ts b/client/src/controls/mapcontextmenu.ts index 2a5fc2db..60b415a7 100644 --- a/client/src/controls/mapcontextmenu.ts +++ b/client/src/controls/mapcontextmenu.ts @@ -7,6 +7,7 @@ import { ContextMenu } from "./contextmenu"; import { Dropdown } from "./dropdown"; import { Switch } from "./switch"; import { Slider } from "./slider"; +import { ftToM } from "../other/utils"; export interface SpawnOptions { role: string; @@ -26,7 +27,7 @@ export class MapContextMenu extends ContextMenu { #aircrafSpawnAltitudeSlider: Slider; #groundUnitRoleDropdown: Dropdown; #groundUnitTypeDropdown: Dropdown; - #spawnOptions: SpawnOptions = { role: "", type: "", latlng: new LatLng(0, 0), loadout: null, coalition: "blue", airbaseName: null, altitude: 20000 * 0.3048 }; + #spawnOptions: SpawnOptions = { role: "", type: "", latlng: new LatLng(0, 0), loadout: null, coalition: "blue", airbaseName: null, altitude: ftToM(20000) }; constructor(id: string) { super(id); @@ -37,7 +38,7 @@ export class MapContextMenu extends ContextMenu { this.#aircraftRoleDropdown = new Dropdown("aircraft-role-options", (role: string) => this.#setAircraftRole(role)); this.#aircraftTypeDropdown = new Dropdown("aircraft-type-options", (type: string) => this.#setAircraftType(type)); this.#aircraftLoadoutDropdown = new Dropdown("loadout-options", (loadout: string) => this.#setAircraftLoadout(loadout)); - this.#aircrafSpawnAltitudeSlider = new Slider("aircraft-spawn-altitude-slider", 0, 50000, "ft", (value: number) => {this.#spawnOptions.altitude = value * 0.3048;}); + this.#aircrafSpawnAltitudeSlider = new Slider("aircraft-spawn-altitude-slider", 0, 50000, "ft", (value: number) => {this.#spawnOptions.altitude = ftToM(value);}); this.#groundUnitRoleDropdown = new Dropdown("ground-unit-role-options", (role: string) => this.#setGroundUnitRole(role)); this.#groundUnitTypeDropdown = new Dropdown("ground-unit-type-options", (type: string) => this.#setGroundUnitType(type)); diff --git a/client/src/controls/unitcontextmenu.ts b/client/src/controls/unitcontextmenu.ts index 4acbaf3e..15ce7227 100644 --- a/client/src/controls/unitcontextmenu.ts +++ b/client/src/controls/unitcontextmenu.ts @@ -1,4 +1,4 @@ -import { deg2rad } from "../other/utils"; +import { deg2rad, ftToM } from "../other/utils"; import { ContextMenu } from "./contextmenu"; export class UnitContextMenu extends ContextMenu { @@ -19,8 +19,8 @@ export class UnitContextMenu extends ContextMenu { } var angleDeg = 360 - (clock - 1) * 45; var angleRad = deg2rad(angleDeg); - var distance = parseInt((dialog.querySelector(`#distance`)?.querySelector("input")).value) * 0.3048; - var upDown = parseInt((dialog.querySelector(`#up-down`)?.querySelector("input")).value) * 0.3048; + var distance = ftToM(parseInt((dialog.querySelector(`#distance`)?.querySelector("input")).value)); + var upDown = ftToM(parseInt((dialog.querySelector(`#up-down`)?.querySelector("input")).value)); // X: front-rear, positive front // Y: top-bottom, positive top diff --git a/client/src/other/utils.ts b/client/src/other/utils.ts index ce1ecc1f..994ba120 100644 --- a/client/src/other/utils.ts +++ b/client/src/other/utils.ts @@ -160,4 +160,20 @@ export function createDivWithClass(className: string) { var el = document.createElement("div"); el.classList.add(className); return el; +} + +export function knotsToMs(knots: number) { + return knots / 1.94384; +} + +export function msToKnots(ms: number) { + return ms * 1.94384; +} + +export function ftToM(ft: number) { + return ft * 0.3048; +} + +export function mToFt(m: number) { + return m / 0.3048; } \ No newline at end of file diff --git a/client/src/panels/unitcontrolpanel.ts b/client/src/panels/unitcontrolpanel.ts index 075bdea5..cba59326 100644 --- a/client/src/panels/unitcontrolpanel.ts +++ b/client/src/panels/unitcontrolpanel.ts @@ -7,6 +7,7 @@ import { Unit } from "../units/unit"; import { Panel } from "./panel"; import { Switch } from "../controls/switch"; import { ROEDescriptions, ROEs, altitudeIncrements, emissionsCountermeasures, emissionsCountermeasuresDescriptions, maxAltitudeValues, maxSpeedValues, minAltitudeValues, minSpeedValues, reactionsToThreat, reactionsToThreatDescriptions, speedIncrements } from "../constants/constants"; +import { ftToM, knotsToMs, mToFt, msToKnots } from "../other/utils"; export class UnitControlPanel extends Panel { #altitudeSlider: Slider; @@ -25,10 +26,10 @@ export class UnitControlPanel extends Panel { super(ID); /* Unit control sliders */ - this.#altitudeSlider = new Slider("altitude-slider", 0, 100, "ft", (value: number) => { getUnitsManager().selectedUnitsSetAltitude(value * 0.3048); }); + this.#altitudeSlider = new Slider("altitude-slider", 0, 100, "ft", (value: number) => { getUnitsManager().selectedUnitsSetAltitude(ftToM(value)); }); this.#altitudeTypeSwitch = new Switch("altitude-type-switch", (value: boolean) => { getUnitsManager().selectedUnitsSetAltitudeType(value? "AGL": "ASL"); }); - this.#speedSlider = new Slider("speed-slider", 0, 100, "kts", (value: number) => { getUnitsManager().selectedUnitsSetSpeed(value / 1.94384); }); + this.#speedSlider = new Slider("speed-slider", 0, 100, "kts", (value: number) => { getUnitsManager().selectedUnitsSetSpeed(knotsToMs(value)); }); this.#speedTypeSwitch = new Switch("speed-type-switch", (value: boolean) => { getUnitsManager().selectedUnitsSetSpeedType(value? "GS": "CAS"); }); /* Option buttons */ @@ -156,11 +157,11 @@ export class UnitControlPanel extends Panel { this.#speedSlider.setActive(targetSpeed != undefined); if (targetSpeed != undefined) - this.#speedSlider.setValue(targetSpeed * 1.94384, false); + this.#speedSlider.setValue(msToKnots(targetSpeed), false); this.#altitudeSlider.setActive(targetAltitude != undefined); if (targetAltitude != undefined) - this.#altitudeSlider.setValue(targetAltitude / 0.3048, false); + this.#altitudeSlider.setValue(mToFt(targetAltitude), false); } else { this.#speedSlider.setActive(false); diff --git a/client/src/panels/unitinfopanel.ts b/client/src/panels/unitinfopanel.ts index 3410a983..523f7f10 100644 --- a/client/src/panels/unitinfopanel.ts +++ b/client/src/panels/unitinfopanel.ts @@ -57,15 +57,8 @@ export class UnitInfoPanel extends Panel { this.#unitLabel.innerText = aircraftDatabase.getByName(baseData.name)?.label || baseData.name; this.#unitName.innerText = baseData.unitName; this.#unitControl.innerText = ( ( baseData.AI ) ? "AI" : "Human" ) + " controlled"; - // this.#groupName.innerText = baseData.groupName; - //this.#name.innerText = baseData.name; - //this.#heading.innerText = String(Math.floor(rad2deg(unit.getFlightData().heading)) + " °"); - //this.#altitude.innerText = String(Math.floor(unit.getFlightData().altitude / 0.3048) + " ft"); - //this.#groundSpeed.innerText = String(Math.floor(unit.getFlightData().speed * 1.94384) + " kts"); this.#fuelBar.style.width = String(unit.getMissionData().fuel + "%"); this.#fuelPercentage.dataset.percentage = "" + unit.getMissionData().fuel; - //this.#latitude.innerText = ConvertDDToDMS(unit.getFlightData().latitude, false); - //this.#longitude.innerText = ConvertDDToDMS(unit.getFlightData().longitude, true); this.#currentTask.dataset.currentTask = unit.getTaskData().currentTask !== ""? unit.getTaskData().currentTask: "No task"; this.#currentTask.dataset.coalition = unit.getMissionData().coalition; diff --git a/client/src/units/unit.ts b/client/src/units/unit.ts index 35353fe4..cfa26640 100644 --- a/client/src/units/unit.ts +++ b/client/src/units/unit.ts @@ -1,6 +1,6 @@ import { Marker, LatLng, Polyline, Icon, DivIcon, CircleMarker, Map } from 'leaflet'; import { getMap, getUnitsManager } from '..'; -import { rad2deg } from '../other/utils'; +import { mToFt, msToKnots, rad2deg } from '../other/utils'; import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, getUnits, landAt, setAltitude, setReactionToThreat, setROE, setSpeed, refuel, setAdvacedOptions, followUnit, setEmissionsCountermeasures, setSpeedType, setAltitudeType, setOnOff, setFollowRoads } from '../server/server'; import { aircraftDatabase } from './aircraftdatabase'; import { groundUnitsDatabase } from './groundunitsdatabase'; @@ -668,9 +668,9 @@ export class Unit extends CustomMarker { /* Set altitude and speed */ if (element.querySelector(".unit-altitude")) - (element.querySelector(".unit-altitude")).innerText = "FL" + String(Math.floor(this.getFlightData().altitude / 0.3048 / 100)); + (element.querySelector(".unit-altitude")).innerText = "FL" + String(Math.floor(mToFt(this.getFlightData().altitude) / 100)); if (element.querySelector(".unit-speed")) - (element.querySelector(".unit-speed")).innerText = String(Math.floor(this.getFlightData().speed * 1.94384)); + (element.querySelector(".unit-speed")).innerText = String(Math.floor(msToKnots(this.getFlightData().speed))) + "GS"; /* Rotate elements according to heading */ element.querySelectorAll("[data-rotate-to-heading]").forEach(el => { diff --git a/client/src/units/unitsmanager.ts b/client/src/units/unitsmanager.ts index afa0cc9a..3dc4c985 100644 --- a/client/src/units/unitsmanager.ts +++ b/client/src/units/unitsmanager.ts @@ -3,7 +3,7 @@ import { getHotgroupPanel, getInfoPopup, getMap, getUnitDataTable } from ".."; import { Unit } from "./unit"; import { cloneUnit } from "../server/server"; import { IDLE, MOVE_UNIT } from "../map/map"; -import { deg2rad, keyEventWasInInput, latLngToMercator, mercatorToLatLng } from "../other/utils"; +import { deg2rad, keyEventWasInInput, latLngToMercator, mToFt, mercatorToLatLng, msToKnots } from "../other/utils"; export class UnitsManager { #units: { [ID: number]: Unit }; @@ -250,7 +250,7 @@ export class UnitsManager { for (let idx in selectedUnits) { selectedUnits[idx].setSpeed(speed); } - this.#showActionMessage(selectedUnits, `setting speed to ${speed * 1.94384} kts`); + this.#showActionMessage(selectedUnits, `setting speed to ${msToKnots(speed)} kts`); } selectedUnitsSetSpeedType(speedType: string) { @@ -266,7 +266,7 @@ export class UnitsManager { for (let idx in selectedUnits) { selectedUnits[idx].setAltitude(altitude); } - this.#showActionMessage(selectedUnits, `setting altitude to ${altitude / 0.3048} ft`); + this.#showActionMessage(selectedUnits, `setting altitude to ${mToFt(altitude)} ft`); } selectedUnitsSetAltitudeType(altitudeType: string) { diff --git a/src/core/include/airunit.h b/src/core/include/airunit.h index e9393dc4..cabd7b9e 100644 --- a/src/core/include/airunit.h +++ b/src/core/include/airunit.h @@ -12,19 +12,12 @@ class AirUnit : public Unit public: AirUnit(json::value json, int ID); - virtual wstring getCategory() = 0; - virtual void changeSpeed(wstring change) {}; - virtual void changeAltitude(wstring change) {}; - virtual void setTargetSpeed(double newTargetSpeed); - virtual void setTargetAltitude(double newTargetAltitude); - virtual void setTargetSpeedType(wstring newTargetSpeedType); - virtual void setTargetAltitudeType(wstring newTargetAltitudeType); + virtual void setState(int newState); + virtual wstring getCategory() = 0; + virtual void changeSpeed(wstring change) = 0; + virtual void changeAltitude(wstring change) = 0; + protected: virtual void AIloop(); - virtual void setState(int newState); - bool isDestinationReached(); - bool setActiveDestination(); - bool updateActivePath(bool looping); - void goToDestination(wstring enrouteTask = L"nil"); }; \ No newline at end of file diff --git a/src/core/include/groundunit.h b/src/core/include/groundunit.h index 6fb9b967..6b5930b0 100644 --- a/src/core/include/groundunit.h +++ b/src/core/include/groundunit.h @@ -7,12 +7,14 @@ class GroundUnit : public Unit { public: GroundUnit(json::value json, int ID); - virtual void AIloop(); - virtual wstring getCategory() { return L"GroundUnit"; }; + + virtual void setState(int newState); + virtual void changeSpeed(wstring change); - virtual void changeAltitude(wstring change) {}; virtual void setOnOff(bool newOnOff); virtual void setFollowRoads(bool newFollowRoads); +protected: + virtual void AIloop(); }; \ No newline at end of file diff --git a/src/core/include/navyunit.h b/src/core/include/navyunit.h index b61761c7..a27b5a31 100644 --- a/src/core/include/navyunit.h +++ b/src/core/include/navyunit.h @@ -9,6 +9,5 @@ public: virtual wstring getCategory() { return L"NavyUnit"; }; virtual void changeSpeed(wstring change); - virtual void changeAltitude(wstring change) {}; }; \ No newline at end of file diff --git a/src/core/include/unit.h b/src/core/include/unit.h index c8a02ce1..a34e4345 100644 --- a/src/core/include/unit.h +++ b/src/core/include/unit.h @@ -70,6 +70,7 @@ public: void setAlive(bool newAlive) { alive = newAlive; addMeasure(L"alive", json::value(newAlive));} void setType(json::value newType) { type = newType; addMeasure(L"type", newType);} void setCountry(int newCountry) { country = newCountry; addMeasure(L"country", json::value(newCountry));} + bool getAI() { return AI; } wstring getName() { return name; } wstring getUnitName() { return unitName; } @@ -84,6 +85,7 @@ public: void setAltitude(double newAltitude) {altitude = newAltitude; addMeasure(L"altitude", json::value(newAltitude));} void setHeading(double newHeading) {heading = newHeading; addMeasure(L"heading", json::value(newHeading));} void setSpeed(double newSpeed) {speed = newSpeed; addMeasure(L"speed", json::value(newSpeed));} + double getLatitude() { return latitude; } double getLongitude() { return longitude; } double getAltitude() { return altitude; } @@ -97,6 +99,7 @@ public: void setHasTask(bool newHasTask) { hasTask = newHasTask; addMeasure(L"hasTask", json::value(newHasTask)); } void setCoalitionID(int newCoalitionID); void setFlags(json::value newFlags) { flags = newFlags; addMeasure(L"flags", json::value(newFlags));} + double getFuel() { return fuel; } json::value getAmmo() { return ammo; } json::value getTargets() { return targets; } @@ -108,21 +111,18 @@ public: /********** Formation data **********/ void setLeaderID(int newLeaderID) { leaderID = newLeaderID; addMeasure(L"leaderID", json::value(newLeaderID)); } void setFormationOffset(Offset formationOffset); + int getLeaderID() { return leaderID; } Offset getFormationoffset() { return formationOffset; } /********** Task data **********/ void setCurrentTask(wstring newCurrentTask) { currentTask = newCurrentTask; addMeasure(L"currentTask", json::value(newCurrentTask)); } - virtual void setTargetSpeed(double newTargetSpeed) { targetSpeed = newTargetSpeed; addMeasure(L"targetSpeed", json::value(newTargetSpeed));} - virtual void setTargetAltitude(double newTargetAltitude) { targetAltitude = newTargetAltitude; addMeasure(L"targetAltitude", json::value(newTargetAltitude));} - virtual void setTargetSpeedType(wstring newTargetSpeedType) { targetSpeedType = newTargetSpeedType; addMeasure(L"targetSpeedType", json::value(newTargetSpeedType)); } - virtual void setTargetAltitudeType(wstring newTargetAltitudeType) { targetAltitudeType = newTargetAltitudeType; addMeasure(L"targetAltitudeType", json::value(newTargetAltitudeType)); } + void setTargetSpeed(double newTargetSpeed); + void setTargetAltitude(double newTargetAltitude); + void setTargetSpeedType(wstring newTargetSpeedType); + void setTargetAltitudeType(wstring newTargetAltitudeType); void setActiveDestination(Coords newActiveDestination) { activeDestination = newActiveDestination; addMeasure(L"activeDestination", json::value("")); } // TODO fix void setActivePath(list newActivePath); - void clearActivePath(); - void pushActivePathFront(Coords newActivePathFront); - void pushActivePathBack(Coords newActivePathBack); - void popActivePathFront(); void setTargetID(int newTargetID) { targetID = newTargetID; addMeasure(L"targetID", json::value(newTargetID));} void setIsTanker(bool newIsTanker); void setIsAWACS(bool newIsAWACS); @@ -150,6 +150,7 @@ public: void setRadio(Options::Radio newradio); void setGeneralSettings(Options::GeneralSettings newGeneralSettings); void setEPLRS(bool newEPLRS); + wstring getROE() { return ROE; } wstring getReactionToThreat() { return reactionToThreat; } wstring getEmissionsCountermeasures() { return emissionsCountermeasures; }; @@ -160,11 +161,15 @@ public: /********** Control functions **********/ void landAt(Coords loc); - virtual void changeSpeed(wstring change){}; - virtual void changeAltitude(wstring change){}; + virtual void changeSpeed(wstring change) {}; + virtual void changeAltitude(wstring change) {}; void resetActiveDestination(); virtual void setState(int newState) { state = newState; }; void resetTask(); + void clearActivePath(); + void pushActivePathFront(Coords newActivePathFront); + void pushActivePathBack(Coords newActivePathBack); + void popActivePathFront(); protected: int ID; @@ -236,4 +241,8 @@ protected: bool isLeaderAlive(); virtual void AIloop() = 0; void addMeasure(wstring key, json::value value); + bool isDestinationReached(double threshold); + bool setActiveDestination(); + bool updateActivePath(bool looping); + void goToDestination(wstring enrouteTask = L"nil"); }; diff --git a/src/core/src/aircraft.cpp b/src/core/src/aircraft.cpp index 0d839c39..f03c616b 100644 --- a/src/core/src/aircraft.cpp +++ b/src/core/src/aircraft.cpp @@ -18,8 +18,8 @@ Aircraft::Aircraft(json::value json, int ID) : AirUnit(json, ID) log("New Aircraft created with ID: " + to_string(ID)); addMeasure(L"category", json::value(getCategory())); - double targetSpeed = 300 / 1.94384; - double targetAltitude = 20000 * 0.3048; + double targetSpeed = knotsToMs(300); + double targetAltitude = ftToM(20000); setTargetSpeed(targetSpeed); setTargetAltitude(targetAltitude); }; @@ -27,16 +27,14 @@ Aircraft::Aircraft(json::value json, int ID) : AirUnit(json, ID) void Aircraft::changeSpeed(wstring change) { if (change.compare(L"stop") == 0) - { setState(State::IDLE); - } else if (change.compare(L"slow") == 0) - setTargetSpeed(getTargetSpeed() - 25 / 1.94384); + setTargetSpeed(getTargetSpeed() - knotsToMs(25)); else if (change.compare(L"fast") == 0) - setTargetSpeed(getTargetSpeed() + 25 / 1.94384); + setTargetSpeed(getTargetSpeed() + knotsToMs(25)); - if (getTargetSpeed() < 50 / 1.94384) - setTargetSpeed(50 / 1.94384); + if (getTargetSpeed() < knotsToMs(50)) + setTargetSpeed(knotsToMs(50)); goToDestination(); /* Send the command to reach the destination */ } @@ -46,16 +44,16 @@ void Aircraft::changeAltitude(wstring change) if (change.compare(L"descend") == 0) { if (getTargetAltitude() > 5000) - setTargetAltitude(getTargetAltitude() - 2500 / 3.28084); + setTargetAltitude(getTargetAltitude() - ftToM(2500)); else if (getTargetAltitude() > 0) - setTargetAltitude(getTargetAltitude() - 500 / 3.28084); + setTargetAltitude(getTargetAltitude() - ftToM(500)); } else if (change.compare(L"climb") == 0) { if (getTargetAltitude() > 5000) - setTargetAltitude(getTargetAltitude() + 2500 / 3.28084); + setTargetAltitude(getTargetAltitude() + ftToM(2500)); else if (getTargetAltitude() >= 0) - setTargetAltitude(getTargetAltitude() + 500 / 3.28084); + setTargetAltitude(getTargetAltitude() + ftToM(500)); } if (getTargetAltitude() < 0) setTargetAltitude(0); diff --git a/src/core/src/airunit.cpp b/src/core/src/airunit.cpp index ffcf2395..c63b69c2 100644 --- a/src/core/src/airunit.cpp +++ b/src/core/src/airunit.cpp @@ -20,7 +20,7 @@ AirUnit::AirUnit(json::value json, int ID) : Unit(json, ID) void AirUnit::setState(int newState) { - /************ Perform any action required when LEAVING a certain state ************/ + /************ Perform any action required when LEAVING a state ************/ if (newState != state) { switch (state) { case State::IDLE: { @@ -48,7 +48,7 @@ void AirUnit::setState(int newState) } } - /************ Perform any action required when ENTERING a certain state ************/ + /************ Perform any action required when ENTERING a state ************/ switch (newState) { case State::IDLE: { clearActivePath(); @@ -100,67 +100,6 @@ void AirUnit::setState(int newState) state = newState; } -bool AirUnit::isDestinationReached() -{ - if (activeDestination != NULL) - { - double dist = 0; - Geodesic::WGS84().Inverse(latitude, longitude, activeDestination.lat, activeDestination.lng, dist); - if (dist < AIR_DEST_DIST_THR) - { - log(unitName + L" destination reached"); - return true; - } - else { - return false; - } - } - else - return true; -} - -bool AirUnit::setActiveDestination() -{ - if (activePath.size() > 0) - { - activeDestination = activePath.front(); - log(unitName + L" active destination set to queue front"); - return true; - } - else - { - activeDestination = Coords(0); - log(unitName + L" active destination set to NULL"); - return false; - } -} - -bool AirUnit::updateActivePath(bool looping) -{ - if (activePath.size() > 0) - { - /* Push the next destination in the queue to the front */ - if (looping) - pushActivePathBack(activePath.front()); - popActivePathFront(); - log(unitName + L" active path front popped"); - return true; - } - else { - return false; - } -} - -void AirUnit::goToDestination(wstring enrouteTask) -{ - if (activeDestination != NULL) - { - Command* command = dynamic_cast(new Move(ID, activeDestination, getTargetSpeed(), getTargetSpeedType(), getTargetAltitude(), getTargetAltitudeType(), enrouteTask)); - scheduler->appendCommand(command); - setHasTask(true); - } -} - void AirUnit::AIloop() { /* State machine */ @@ -168,7 +107,7 @@ void AirUnit::AIloop() case State::IDLE: { currentTask = L"Idle"; - if (!hasTask) + if (!getHasTask()) { std::wostringstream taskSS; if (isTanker) { @@ -206,7 +145,7 @@ void AirUnit::AIloop() currentTask = L"Reaching destination"; } - if (activeDestination == NULL || !hasTask) + if (activeDestination == NULL || !getHasTask()) { if (!setActiveDestination()) setState(State::IDLE); @@ -214,7 +153,7 @@ void AirUnit::AIloop() goToDestination(enrouteTask); } else { - if (isDestinationReached()) { + if (isDestinationReached(AIR_DEST_DIST_THR)) { if (updateActivePath(looping) && setActiveDestination()) goToDestination(enrouteTask); else @@ -251,7 +190,7 @@ void AirUnit::AIloop() wstring enrouteTask = enrouteTaskSS.str(); currentTask = L"Attacking " + getTargetName(); - if (!hasTask) + if (!getHasTask()) { setActiveDestination(); goToDestination(enrouteTask); @@ -272,7 +211,7 @@ void AirUnit::AIloop() currentTask = L"Following " + getTargetName(); Unit* leader = unitsManager->getUnit(leaderID); - if (!hasTask) { + if (!getHasTask()) { if (leader != nullptr && leader->getAlive() && formationOffset != NULL) { std::wostringstream taskSS; @@ -295,7 +234,7 @@ void AirUnit::AIloop() case State::REFUEL: { currentTask = L"Refueling"; - if (!hasTask) { + if (!getHasTask()) { if (fuel <= initialFuel) { std::wostringstream taskSS; taskSS << "{" @@ -316,23 +255,3 @@ void AirUnit::AIloop() addMeasure(L"currentTask", json::value(currentTask)); } - -void AirUnit::setTargetSpeed(double newTargetSpeed) { - Unit::setTargetSpeed(newTargetSpeed); - goToDestination(); -} - -void AirUnit::setTargetAltitude(double newTargetAltitude) { - Unit::setTargetAltitude(newTargetAltitude); - goToDestination(); -} - -void AirUnit::setTargetSpeedType(wstring newTargetSpeedType) { - Unit::setTargetSpeedType(newTargetSpeedType); - goToDestination(); -} - -void AirUnit::setTargetAltitudeType(wstring newTargetAltitudeType) { - Unit::setTargetAltitudeType(newTargetAltitudeType); - goToDestination(); -} \ No newline at end of file diff --git a/src/core/src/groundunit.cpp b/src/core/src/groundunit.cpp index 08815b35..c5685d91 100644 --- a/src/core/src/groundunit.cpp +++ b/src/core/src/groundunit.cpp @@ -22,60 +22,98 @@ GroundUnit::GroundUnit(json::value json, int ID) : Unit(json, ID) setTargetSpeed(targetSpeed); }; +void GroundUnit::setState(int newState) +{ + /************ Perform any action required when LEAVING a state ************/ + if (newState != state) { + switch (state) { + case State::IDLE: { + break; + } + case State::REACH_DESTINATION: { + break; + } + default: + break; + } + } + + /************ Perform any action required when ENTERING a state ************/ + switch (newState) { + case State::IDLE: { + clearActivePath(); + resetActiveDestination(); + addMeasure(L"currentState", json::value(L"Idle")); + break; + } + case State::REACH_DESTINATION: { + resetActiveDestination(); + addMeasure(L"currentState", json::value(L"Reach destination")); + break; + } + default: + break; + } + + resetTask(); + + log(unitName + L" setting state from " + to_wstring(state) + L" to " + to_wstring(newState)); + state = newState; +} + void GroundUnit::AIloop() { - /* Set the active destination to be always equal to the first point of the active path. This is in common with all AI units */ - if (activePath.size() > 0) - { - if (activeDestination != activePath.front()) - { - activeDestination = activePath.front(); - std::wostringstream taskSS; - taskSS << "{ id = 'FollowRoads', value = " << (getFollowRoads()? "true" : "false") << " }"; - - Command* command = dynamic_cast(new Move(ID, activeDestination, getTargetSpeed(), getTargetSpeedType(), getTargetAltitude(), getTargetAltitudeType(), taskSS.str())); - scheduler->appendCommand(command); - } + switch (state) { + case State::IDLE: { + currentTask = L"Idle"; + if (getHasTask()) + resetTask(); + break; } - else - { - if (activeDestination != NULL) + case State::REACH_DESTINATION: { + wstring enrouteTask = L""; + bool looping = false; + + std::wostringstream taskSS; + taskSS << "{ id = 'FollowRoads', value = " << (getFollowRoads() ? "true" : "false") << " }"; + enrouteTask = taskSS.str(); + + if (activeDestination == NULL || !getHasTask()) { - log(unitName + L" no more points in active path"); - activeDestination = Coords(0); // Set the active path to NULL - currentTask = L"Idle"; + if (!setActiveDestination()) + setState(State::IDLE); + else + goToDestination(enrouteTask); } + else { + if (isDestinationReached(GROUND_DEST_DIST_THR)) { + if (updateActivePath(looping) && setActiveDestination()) + goToDestination(enrouteTask); + else + setState(State::IDLE); + } + } + break; + } + default: + break; } - /* Ground unit AI Loop */ - if (activeDestination != NULL) - { - double newDist = 0; - Geodesic::WGS84().Inverse(latitude, longitude, activeDestination.lat, activeDestination.lng, newDist); - if (newDist < GROUND_DEST_DIST_THR) - { - /* Destination reached */ - popActivePathFront(); - log(unitName + L" destination reached"); - } - } + addMeasure(L"currentTask", json::value(currentTask)); } void GroundUnit::changeSpeed(wstring change) { if (change.compare(L"stop") == 0) - { - - } + setState(State::IDLE); else if (change.compare(L"slow") == 0) - { - - } + setTargetSpeed(getTargetSpeed() - knotsToMs(5)); else if (change.compare(L"fast") == 0) - { + setTargetSpeed(getTargetSpeed() + knotsToMs(5)); - } + if (getTargetSpeed() < 0) + setTargetSpeed(0); } void GroundUnit::setOnOff(bool newOnOff) diff --git a/src/core/src/helicopter.cpp b/src/core/src/helicopter.cpp index d9f8d444..f952dc4f 100644 --- a/src/core/src/helicopter.cpp +++ b/src/core/src/helicopter.cpp @@ -18,8 +18,8 @@ Helicopter::Helicopter(json::value json, int ID) : AirUnit(json, ID) log("New Helicopter created with ID: " + to_string(ID)); addMeasure(L"category", json::value(getCategory())); - double targetSpeed = 100 / 1.94384; - double targetAltitude = 5000 * 0.3048; + double targetSpeed = knotsToMs(100); + double targetAltitude = ftToM(5000); setTargetSpeed(targetSpeed); setTargetAltitude(targetAltitude); }; @@ -32,9 +32,9 @@ void Helicopter::changeSpeed(wstring change) clearActivePath(); } else if (change.compare(L"slow") == 0) - targetSpeed -= 10 / 1.94384; + targetSpeed -= knotsToMs(10); else if (change.compare(L"fast") == 0) - targetSpeed += 10 / 1.94384; + targetSpeed += knotsToMs(10); if (targetSpeed < 0) targetSpeed = 0; @@ -46,16 +46,16 @@ void Helicopter::changeAltitude(wstring change) if (change.compare(L"descend") == 0) { if (targetAltitude > 100) - targetAltitude -= 100 / 3.28084; + targetAltitude -= ftToM(100); else if (targetAltitude > 0) - targetAltitude -= 10 / 3.28084; + targetAltitude -= ftToM(10); } else if (change.compare(L"climb") == 0) { if (targetAltitude > 100) - targetAltitude += 100 / 3.28084; + targetAltitude += ftToM(100); else if (targetAltitude >= 0) - targetAltitude += 10 / 3.28084; + targetAltitude += ftToM(10); } if (targetAltitude < 0) targetAltitude = 0; diff --git a/src/core/src/unit.cpp b/src/core/src/unit.cpp index 0c29509f..2c70efc6 100644 --- a/src/core/src/unit.cpp +++ b/src/core/src/unit.cpp @@ -324,6 +324,7 @@ void Unit::resetTask() { Command* command = dynamic_cast(new ResetTask(ID)); scheduler->appendCommand(command); + setHasTask(false); } void Unit::setFormationOffset(Offset newFormationOffset) @@ -576,3 +577,87 @@ void Unit::setGeneralSettings(Options::GeneralSettings newGeneralSettings) { } } +void Unit::setTargetSpeed(double newTargetSpeed) { + targetSpeed = newTargetSpeed; + addMeasure(L"targetSpeed", json::value(newTargetSpeed)); + goToDestination(); +} + +void Unit::setTargetAltitude(double newTargetAltitude) { + targetAltitude = newTargetAltitude; + addMeasure(L"targetAltitude", json::value(newTargetAltitude)); + goToDestination(); +} + +void Unit::setTargetSpeedType(wstring newTargetSpeedType) { + targetSpeedType = newTargetSpeedType; + addMeasure(L"targetSpeedType", json::value(newTargetSpeedType)); + goToDestination(); +} + +void Unit::setTargetAltitudeType(wstring newTargetAltitudeType) { + targetAltitudeType = newTargetAltitudeType; + addMeasure(L"targetAltitudeType", json::value(newTargetAltitudeType)); + goToDestination(); +} + +void Unit::goToDestination(wstring enrouteTask) +{ + if (activeDestination != NULL) + { + Command* command = dynamic_cast(new Move(ID, activeDestination, getTargetSpeed(), getTargetSpeedType(), getTargetAltitude(), getTargetAltitudeType(), enrouteTask)); + scheduler->appendCommand(command); + setHasTask(true); + } +} + +bool Unit::isDestinationReached(double threshold) +{ + if (activeDestination != NULL) + { + double dist = 0; + Geodesic::WGS84().Inverse(latitude, longitude, activeDestination.lat, activeDestination.lng, dist); + if (dist < threshold) + { + log(unitName + L" destination reached"); + return true; + } + else { + return false; + } + } + else + return true; +} + +bool Unit::setActiveDestination() +{ + if (activePath.size() > 0) + { + activeDestination = activePath.front(); + log(unitName + L" active destination set to queue front"); + return true; + } + else + { + activeDestination = Coords(0); + log(unitName + L" active destination set to NULL"); + return false; + } +} + +bool Unit::updateActivePath(bool looping) +{ + if (activePath.size() > 0) + { + /* Push the next destination in the queue to the front */ + if (looping) + pushActivePathBack(activePath.front()); + popActivePathFront(); + log(unitName + L" active path front popped"); + return true; + } + else { + return false; + } +} \ No newline at end of file diff --git a/src/utils/include/utils.h b/src/utils/include/utils.h index cd8bd7be..4534a8de 100644 --- a/src/utils/include/utils.h +++ b/src/utils/include/utils.h @@ -29,3 +29,8 @@ bool DllExport operator!= (const Offset& a, const Offset& b); bool DllExport operator== (const Offset& a, const int& b); bool DllExport operator!= (const Offset& a, const int& b); +double DllExport knotsToMs(const double knots); +double DllExport msToKnots(const double ms); +double DllExport ftToM(const double ft); +double DllExport mToFt(const double m); + diff --git a/src/utils/src/utils.cpp b/src/utils/src/utils.cpp index afd8ebf2..9d91fbe7 100644 --- a/src/utils/src/utils.cpp +++ b/src/utils/src/utils.cpp @@ -63,3 +63,20 @@ bool operator== (const Offset& a, const Offset& b) { return a.x == b.x && a.y == bool operator!= (const Offset& a, const Offset& b) { return !(a == b); } bool operator== (const Offset& a, const int& b) { return a.x == b && a.y == b && a.z == b; } bool operator!= (const Offset& a, const int& b) { return !(a == b); } + + +double knotsToMs(const double knots) { + return knots / 1.94384; +} + +double msToKnots(const double ms) { + return ms * 1.94384; +} + +double ftToM(const double ft) { + return ft * 0.3048; +} + +double mToFt(const double m) { + return m / 0.3048; +} \ No newline at end of file