Added ability to take control of units

And bugfixes
This commit is contained in:
Pax1601
2023-06-13 17:03:04 +02:00
parent 156c730352
commit 4f2debeb4f
20 changed files with 1266 additions and 666 deletions

View File

@@ -6,6 +6,8 @@
#include "measure.h"
#include "logger.h"
#define TASK_CHECK_INIT_VALUE 10
namespace State
{
enum States
@@ -18,7 +20,11 @@ namespace State
LAND,
REFUEL,
AWACS,
TANKER
TANKER,
BOMB_POINT,
CARPET_BOMB,
BOMB_BUILDING,
FIRE_AT_AREA
};
};
@@ -56,21 +62,24 @@ public:
/********** Public methods **********/
void initialize(json::value json);
void setDefaults(bool force = false);
int getID() { return ID; }
void runAILoop();
void updateExportData(json::value json);
void updateMissionData(json::value json);
json::value getData(long long time);
json::value getData(long long time, bool getAll = false);
virtual wstring getCategory() { return L"No category"; };
/********** Base data **********/
void setAI(bool newAI) { AI = newAI; addMeasure(L"AI", json::value(newAI)); }
void setControlled(bool newControlled) { controlled = newControlled; addMeasure(L"controlled", json::value(newControlled)); }
void setName(wstring newName) { name = newName; addMeasure(L"name", json::value(newName));}
void setUnitName(wstring newUnitName) { unitName = newUnitName; addMeasure(L"unitName", json::value(newUnitName));}
void setGroupName(wstring newGroupName) { groupName = newGroupName; addMeasure(L"groupName", json::value(newGroupName));}
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; }
bool getControlled() { return controlled; }
wstring getName() { return name; }
wstring getUnitName() { return unitName; }
wstring getGroupName() { return groupName; }
@@ -84,6 +93,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; }
@@ -93,13 +103,14 @@ public:
/********** Mission data **********/
void setFuel(double newFuel) { fuel = newFuel; addMeasure(L"fuel", json::value(newFuel));}
void setAmmo(json::value newAmmo) { ammo = newAmmo; addMeasure(L"ammo", json::value(newAmmo));}
void setTargets(json::value newTargets) {targets = newTargets; addMeasure(L"targets", json::value(newTargets));}
void setHasTask(bool newHasTask) { hasTask = newHasTask; addMeasure(L"hasTask", json::value(newHasTask)); }
void setContacts(json::value newContacts) {contacts = newContacts; addMeasure(L"contacts", json::value(newContacts));}
void setHasTask(bool 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; }
json::value getTargets() { return contacts; }
bool getHasTask() { return hasTask; }
wstring getCoalition() { return coalition; }
int getCoalitionID();
@@ -108,40 +119,48 @@ 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));} //TODO fix, double definition
void setCurrentTask(wstring newCurrentTask) { currentTask = newCurrentTask; addMeasure(L"currentTask", json::value(newCurrentTask)); }
void setDesiredSpeed(double newDesiredSpeed);
void setDesiredAltitude(double newDesiredAltitude);
void setDesiredSpeedType(wstring newDesiredSpeedType);
void setDesiredAltitudeType(wstring newDesiredAltitudeType);
void setActiveDestination(Coords newActiveDestination) { activeDestination = newActiveDestination; addMeasure(L"activeDestination", json::value("")); } // TODO fix
void setActivePath(list<Coords> 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 setTargetLocation(Coords newTargetLocation);
void setIsTanker(bool newIsTanker);
void setIsAWACS(bool newIsAWACS);
virtual void setOnOff(bool newOnOff) { onOff = newOnOff; addMeasure(L"onOff", json::value(newOnOff));};
virtual void setFollowRoads(bool newFollowRoads) { followRoads = newFollowRoads; addMeasure(L"followRoads", json::value(newFollowRoads)); };
wstring getCurrentTask() { return currentTask; }
virtual double getTargetSpeed() { return targetSpeed; };
virtual double getTargetAltitude() { return targetAltitude; };
virtual double getDesiredSpeed() { return desiredSpeed; };
virtual double getDesiredAltitude() { return desiredAltitude; };
virtual wstring getDesiredSpeedType() { return desiredSpeedType; };
virtual wstring getDesiredAltitudeType() { return desiredAltitudeType; };
Coords getActiveDestination() { return activeDestination; }
list<Coords> getActivePath() { return activePath; }
int getTargetID() { return targetID; }
Coords getTargetLocation() { return targetLocation; }
bool getIsTanker() { return isTanker; }
bool getIsAWACS() { return isAWACS; }
bool getOnOff() { return onOff; };
bool getFollowRoads() { return followRoads; };
/********** Options data **********/
void setROE(wstring newROE);
void setReactionToThreat(wstring newReactionToThreat);
void setEmissionsCountermeasures(wstring newEmissionsCountermeasures);
void setTACAN(Options::TACAN newTACAN);
void setRadio(Options::Radio newradio);
void setGeneralSettings(Options::GeneralSettings newGeneralSettings);
void setEPLRS(bool newEPLRS);
void setROE(wstring newROE, bool force = false);
void setReactionToThreat(wstring newReactionToThreat, bool force = false);
void setEmissionsCountermeasures(wstring newEmissionsCountermeasures, bool force = false);
void setTACAN(Options::TACAN newTACAN, bool force = false);
void setRadio(Options::Radio newradio, bool force = false);
void setGeneralSettings(Options::GeneralSettings newGeneralSettings, bool force = false);
void setEPLRS(bool newEPLRS, bool force = false);
wstring getROE() { return ROE; }
wstring getReactionToThreat() { return reactionToThreat; }
wstring getEmissionsCountermeasures() { return emissionsCountermeasures; };
@@ -152,19 +171,24 @@ 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;
map<wstring, Measure*> measures;
int taskCheckCounter = 0;
/********** Base data **********/
bool AI = false;
bool controlled = false;
wstring name = L"undefined";
wstring unitName = L"undefined";
wstring groupName = L"undefined";
@@ -183,7 +207,7 @@ protected:
double fuel = 0;
double initialFuel = 0; // Used internally to detect refueling completed
json::value ammo = json::value::null();
json::value targets = json::value::null();
json::value contacts = json::value::null();
bool hasTask = false;
wstring coalition = L"";
json::value flags = json::value::null();
@@ -194,13 +218,18 @@ protected:
/********** Task data **********/
wstring currentTask = L"";
double targetSpeed = 0;
double targetAltitude = 0;
double desiredSpeed = 0;
double desiredAltitude = 0;
wstring desiredSpeedType = L"GS";
wstring desiredAltitudeType = L"AGL";
list<Coords> activePath;
Coords activeDestination = Coords(0);
Coords activeDestination = Coords(NULL);
int targetID = NULL;
Coords targetLocation = Coords(NULL);
bool isTanker = false;
bool isAWACS = false;
bool onOff = true;
bool followRoads = false;
/********** Options data **********/
wstring ROE = L"Designated";
@@ -224,4 +253,10 @@ 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");
bool checkTaskFailed();
void resetTaskFailedCounter();
};

View File

@@ -11,10 +11,17 @@ public:
~UnitsManager();
Unit* getUnit(int ID);
bool isUnitInGroup(Unit* unit);
bool isUnitGroupLeader(Unit* unit);
Unit* getGroupLeader(int ID);
Unit* getGroupLeader(Unit* unit);
vector<Unit*> getGroupMembers(wstring groupName);
void updateExportData(lua_State* L);
void updateMissionData(json::value missionData);
void runAILoop();
void getData(json::value& answer, long long time);
void deleteUnit(int ID);
void deleteUnit(int ID, bool explosion);
void acquireControl(int ID);
private:
map<int, Unit*> units;

View File

@@ -17,59 +17,52 @@ 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()));
setTargetSpeed(targetSpeed);
setTargetAltitude(targetAltitude);
double desiredSpeed = knotsToMs(300);
double desiredAltitude = ftToM(20000);
setDesiredSpeed(desiredSpeed);
setDesiredAltitude(desiredAltitude);
};
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);
setDesiredSpeed(getDesiredSpeed() - knotsToMs(25));
else if (change.compare(L"fast") == 0)
setTargetSpeed(getTargetSpeed() + 25 / 1.94384);
setDesiredSpeed(getDesiredSpeed() + knotsToMs(25));
if (getTargetSpeed() < 50 / 1.94384)
setTargetSpeed(50 / 1.94384);
if (getDesiredSpeed() < knotsToMs(50))
setDesiredSpeed(knotsToMs(50));
goToDestination(); /* Send the command to reach the destination */
if (state == State::IDLE)
resetTask();
else
goToDestination(); /* Send the command to reach the destination */
}
void Aircraft::changeAltitude(wstring change)
{
if (change.compare(L"descend") == 0)
{
if (getTargetAltitude() > 5000)
setTargetAltitude(getTargetAltitude() - 2500 / 3.28084);
else if (getTargetAltitude() > 0)
setTargetAltitude(getTargetAltitude() - 500 / 3.28084);
if (getDesiredAltitude() > 5000)
setDesiredAltitude(getDesiredAltitude() - ftToM(2500));
else if (getDesiredAltitude() > 0)
setDesiredAltitude(getDesiredAltitude() - ftToM(500));
}
else if (change.compare(L"climb") == 0)
{
if (getTargetAltitude() > 5000)
setTargetAltitude(getTargetAltitude() + 2500 / 3.28084);
else if (getTargetAltitude() >= 0)
setTargetAltitude(getTargetAltitude() + 500 / 3.28084);
if (getDesiredAltitude() > 5000)
setDesiredAltitude(getDesiredAltitude() + ftToM(2500));
else if (getDesiredAltitude() >= 0)
setDesiredAltitude(getDesiredAltitude() + ftToM(500));
}
if (getTargetAltitude() < 0)
setTargetAltitude(0);
if (getDesiredAltitude() < 0)
setDesiredAltitude(0);
goToDestination(); /* Send the command to reach the destination */
}
void Aircraft::setTargetSpeed(double newTargetSpeed) {
targetSpeed = newTargetSpeed;
addMeasure(L"targetSpeed", json::value(targetSpeed));
if (activeDestination != NULL)
goToDestination();
}
void Aircraft::setTargetAltitude(double newTargetAltitude) {
targetAltitude = newTargetAltitude;
addMeasure(L"targetAltitude", json::value(targetAltitude));
if (activeDestination != NULL)
goToDestination();
if (state == State::IDLE)
resetTask();
else
goToDestination(); /* Send the command to reach the destination */
}

View File

@@ -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: {
@@ -43,12 +43,18 @@ void AirUnit::setState(int newState)
case State::REFUEL: {
break;
}
case State::BOMB_POINT:
case State::CARPET_BOMB:
case State::BOMB_BUILDING: {
setTargetLocation(Coords(NULL));
break;
}
default:
break;
}
}
/************ Perform any action required when ENTERING a certain state ************/
/************ Perform any action required when ENTERING a state ************/
switch (newState) {
case State::IDLE: {
clearActivePath();
@@ -90,6 +96,24 @@ void AirUnit::setState(int newState)
addMeasure(L"currentState", json::value(L"Refuel"));
break;
}
case State::BOMB_POINT: {
addMeasure(L"currentState", json::value(L"Bombing point"));
clearActivePath();
resetActiveDestination();
break;
}
case State::CARPET_BOMB: {
addMeasure(L"currentState", json::value(L"Carpet bombing"));
clearActivePath();
resetActiveDestination();
break;
}
case State::BOMB_BUILDING: {
addMeasure(L"currentState", json::value(L"Bombing building"));
clearActivePath();
resetActiveDestination();
break;
}
default:
break;
}
@@ -100,69 +124,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<Command*>(new Move(ID, activeDestination, getTargetSpeed(), getTargetAltitude(), enrouteTask));
scheduler->appendCommand(command);
setHasTask(true);
}
else
log(unitName + L" error, no active destination!");
}
void AirUnit::AIloop()
{
/* State machine */
@@ -170,19 +131,19 @@ void AirUnit::AIloop()
case State::IDLE: {
currentTask = L"Idle";
if (!hasTask)
if (!getHasTask())
{
std::wostringstream taskSS;
if (isTanker) {
taskSS << "{ [1] = { id = 'Tanker' }, [2] = { id = 'Orbit', pattern = 'Race-Track' } }";
taskSS << "{ [1] = { id = 'Tanker' }, [2] = { id = 'Orbit', pattern = 'Race-Track', altitude = " << desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" << desiredAltitudeType << "' } }";
}
else if (isAWACS) {
taskSS << "{ [1] = { id = 'AWACS' }, [2] = { id = 'Orbit', pattern = 'Circle' } }";
taskSS << "{ [1] = { id = 'AWACS' }, [2] = { id = 'Orbit', pattern = 'Circle', altitude = " << desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" << desiredAltitudeType << "' } }";
}
else {
taskSS << "{ id = 'Orbit', pattern = 'Circle' }";
taskSS << "{ id = 'Orbit', pattern = 'Circle', altitude = " << desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" << desiredAltitudeType << "' }";
}
Command* command = dynamic_cast<Command*>(new SetTask(ID, taskSS.str()));
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str()));
scheduler->appendCommand(command);
setHasTask(true);
}
@@ -208,7 +169,7 @@ void AirUnit::AIloop()
currentTask = L"Reaching destination";
}
if (activeDestination == NULL || !hasTask)
if (activeDestination == NULL || !getHasTask())
{
if (!setActiveDestination())
setState(State::IDLE);
@@ -216,7 +177,7 @@ void AirUnit::AIloop()
goToDestination(enrouteTask);
}
else {
if (isDestinationReached()) {
if (isDestinationReached(AIR_DEST_DIST_THR)) {
if (updateActivePath(looping) && setActiveDestination())
goToDestination(enrouteTask);
else
@@ -253,7 +214,7 @@ void AirUnit::AIloop()
wstring enrouteTask = enrouteTaskSS.str();
currentTask = L"Attacking " + getTargetName();
if (!hasTask)
if (!getHasTask())
{
setActiveDestination();
goToDestination(enrouteTask);
@@ -274,7 +235,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;
@@ -287,7 +248,7 @@ void AirUnit::AIloop()
<< "z = " << formationOffset.z
<< "},"
<< "}";
Command* command = dynamic_cast<Command*>(new SetTask(ID, taskSS.str()));
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str()));
scheduler->appendCommand(command);
setHasTask(true);
}
@@ -297,13 +258,13 @@ void AirUnit::AIloop()
case State::REFUEL: {
currentTask = L"Refueling";
if (!hasTask) {
if (!getHasTask()) {
if (fuel <= initialFuel) {
std::wostringstream taskSS;
taskSS << "{"
<< "id = 'Refuel'"
<< "}";
Command* command = dynamic_cast<Command*>(new SetTask(ID, taskSS.str()));
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str()));
scheduler->appendCommand(command);
setHasTask(true);
}
@@ -312,9 +273,44 @@ void AirUnit::AIloop()
}
}
}
case State::BOMB_POINT: {
currentTask = L"Bombing point";
if (!getHasTask()) {
std::wostringstream taskSS;
taskSS << "{id = 'Bombing', lat = " << targetLocation.lat << ", lng = " << targetLocation.lng << "}";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str()));
scheduler->appendCommand(command);
setHasTask(true);
}
}
case State::CARPET_BOMB: {
currentTask = L"Carpet bombing";
if (!getHasTask()) {
std::wostringstream taskSS;
taskSS << "{id = 'CarpetBombing', lat = " << targetLocation.lat << ", lng = " << targetLocation.lng << "}";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str()));
scheduler->appendCommand(command);
setHasTask(true);
}
break;
}
case State::BOMB_BUILDING: {
currentTask = L"Bombing building";
if (!getHasTask()) {
std::wostringstream taskSS;
taskSS << "{id = 'AttackMapObject', lat = " << targetLocation.lat << ", lng = " << targetLocation.lng << "}";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str()));
scheduler->appendCommand(command);
setHasTask(true);
}
break;
}
default:
break;
}
addMeasure(L"currentTask", json::value(currentTask));
}
}

View File

@@ -69,6 +69,7 @@ extern "C" DllExport int coreFrame(lua_State* L)
if (unitsManager != nullptr)
{
unitsManager->updateExportData(L);
unitsManager->runAILoop();
}
before = std::chrono::system_clock::now();
}

View File

@@ -17,58 +17,134 @@ GroundUnit::GroundUnit(json::value json, int ID) : Unit(json, ID)
{
log("New Ground Unit created with ID: " + to_string(ID));
addMeasure(L"category", json::value(getCategory()));
setTargetSpeed(targetSpeed);
setTargetAltitude(targetAltitude);
double desiredSpeed = 10;
setDesiredSpeed(desiredSpeed);
};
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;
}
case State::FIRE_AT_AREA: {
setTargetLocation(Coords(NULL));
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;
}
case State::FIRE_AT_AREA: {
addMeasure(L"currentState", json::value(L"Firing at area"));
clearActivePath();
resetActiveDestination();
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())
switch (state) {
case State::IDLE: {
currentTask = L"Idle";
if (getHasTask())
resetTask();
break;
}
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())
{
activeDestination = activePath.front();
Command* command = dynamic_cast<Command*>(new Move(ID, activeDestination, getTargetSpeed(), getTargetAltitude(), L"nil"));
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;
}
case State::FIRE_AT_AREA: {
currentTask = L"Firing at area";
if (!getHasTask()) {
std::wostringstream taskSS;
taskSS << "{id = 'FireAtPoint', lat = " << targetLocation.lat << ", lng = " << targetLocation.lng << ", radius = 1000}";
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str()));
scheduler->appendCommand(command);
setHasTask(true);
}
}
else
{
if (activeDestination != NULL)
{
log(unitName + L" no more points in active path");
activeDestination = Coords(0); // Set the active path to NULL
currentTask = L"Idle";
}
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)
{
}
setDesiredSpeed(getDesiredSpeed() - knotsToMs(5));
else if (change.compare(L"fast") == 0)
{
setDesiredSpeed(getDesiredSpeed() + knotsToMs(5));
}
if (getDesiredSpeed() < 0)
setDesiredSpeed(0);
}
void GroundUnit::setOnOff(bool newOnOff)
{
Unit::setOnOff(newOnOff);
Command* command = dynamic_cast<Command*>(new SetOnOff(groupName, onOff));
scheduler->appendCommand(command);
}
void GroundUnit::setFollowRoads(bool newFollowRoads)
{
Unit::setFollowRoads(newFollowRoads);
resetActiveDestination(); /* Reset active destination to apply option*/
}

View File

@@ -17,8 +17,11 @@ 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()));
setTargetSpeed(targetSpeed);
setTargetAltitude(targetAltitude);
double desiredSpeed = knotsToMs(100);
double desiredAltitude = ftToM(5000);
setDesiredSpeed(desiredSpeed);
setDesiredAltitude(desiredAltitude);
};
void Helicopter::changeSpeed(wstring change)
@@ -29,11 +32,11 @@ void Helicopter::changeSpeed(wstring change)
clearActivePath();
}
else if (change.compare(L"slow") == 0)
targetSpeed -= 10 / 1.94384;
desiredSpeed -= knotsToMs(10);
else if (change.compare(L"fast") == 0)
targetSpeed += 10 / 1.94384;
if (targetSpeed < 0)
targetSpeed = 0;
desiredSpeed += knotsToMs(10);
if (desiredSpeed < 0)
desiredSpeed = 0;
goToDestination(); /* Send the command to reach the destination */
}
@@ -42,33 +45,20 @@ void Helicopter::changeAltitude(wstring change)
{
if (change.compare(L"descend") == 0)
{
if (targetAltitude > 100)
targetAltitude -= 100 / 3.28084;
else if (targetAltitude > 0)
targetAltitude -= 10 / 3.28084;
if (desiredAltitude > 100)
desiredAltitude -= ftToM(100);
else if (desiredAltitude > 0)
desiredAltitude -= ftToM(10);
}
else if (change.compare(L"climb") == 0)
{
if (targetAltitude > 100)
targetAltitude += 100 / 3.28084;
else if (targetAltitude >= 0)
targetAltitude += 10 / 3.28084;
if (desiredAltitude > 100)
desiredAltitude += ftToM(100);
else if (desiredAltitude >= 0)
desiredAltitude += ftToM(10);
}
if (targetAltitude < 0)
targetAltitude = 0;
if (desiredAltitude < 0)
desiredAltitude = 0;
goToDestination(); /* Send the command to reach the destination */
}
void Helicopter::setTargetSpeed(double newTargetSpeed) {
targetSpeed = newTargetSpeed;
addMeasure(L"targetSpeed", json::value(targetSpeed));
goToDestination();
}
void Helicopter::setTargetAltitude(double newTargetAltitude) {
targetAltitude = newTargetAltitude;
addMeasure(L"targetAltitude", json::value(targetAltitude));
goToDestination();
}

View File

@@ -17,8 +17,9 @@ NavyUnit::NavyUnit(json::value json, int ID) : Unit(json, ID)
{
log("New Navy Unit created with ID: " + to_string(ID));
addMeasure(L"category", json::value(getCategory()));
setTargetSpeed(targetSpeed);
setTargetAltitude(targetAltitude);
double desiredSpeed = 10;
setDesiredSpeed(desiredSpeed);
};
void NavyUnit::AIloop()

View File

@@ -59,7 +59,8 @@ void Scheduler::handleRequest(wstring key, json::value value)
if (key.compare(L"setPath") == 0)
{
int ID = value[L"ID"].as_integer();
Unit* unit = unitsManager->getUnit(ID);
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
{
wstring unitName = unit->getUnitName();
@@ -75,15 +76,9 @@ void Scheduler::handleRequest(wstring key, json::value value)
newPath.push_back(dest);
}
Unit* unit = unitsManager->getUnit(ID);
if (unit != nullptr)
{
unit->setActivePath(newPath);
unit->setState(State::REACH_DESTINATION);
log(unitName + L" new path set successfully");
}
else
log(unitName + L" not found, request will be discarded");
unit->setActivePath(newPath);
unit->setState(State::REACH_DESTINATION);
log(unitName + L" new path set successfully");
}
}
else if (key.compare(L"smoke") == 0)
@@ -111,7 +106,8 @@ void Scheduler::handleRequest(wstring key, json::value value)
wstring type = value[L"type"].as_string();
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;
double altitude = value[L"altitude"].as_double();
Coords loc; loc.lat = lat; loc.lng = lng; loc.alt = altitude;
wstring payloadName = value[L"payloadName"].as_string();
wstring airbaseName = value[L"airbaseName"].as_string();
log(L"Spawning " + coalition + L" air unit of type " + type + L" with payload " + payloadName + L" at (" + to_wstring(lat) + L", " + to_wstring(lng) + L" " + airbaseName + L")");
@@ -120,9 +116,10 @@ void Scheduler::handleRequest(wstring key, json::value value)
else if (key.compare(L"attackUnit") == 0)
{
int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
int targetID = value[L"targetID"].as_integer();
Unit* unit = unitsManager->getUnit(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
Unit* target = unitsManager->getUnit(targetID);
wstring unitName;
@@ -145,12 +142,13 @@ void Scheduler::handleRequest(wstring key, json::value value)
else if (key.compare(L"followUnit") == 0)
{
int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
int leaderID = value[L"targetID"].as_integer();
int offsetX = value[L"offsetX"].as_integer();
int offsetY = value[L"offsetY"].as_integer();
int offsetZ = value[L"offsetZ"].as_integer();
Unit* unit = unitsManager->getUnit(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
Unit* leader = unitsManager->getUnit(leaderID);
wstring unitName;
@@ -174,30 +172,50 @@ void Scheduler::handleRequest(wstring key, json::value value)
else if (key.compare(L"changeSpeed") == 0)
{
int ID = value[L"ID"].as_integer();
Unit* unit = unitsManager->getUnit(ID);
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
unit->changeSpeed(value[L"change"].as_string());
}
else if (key.compare(L"changeAltitude") == 0)
{
int ID = value[L"ID"].as_integer();
Unit* unit = unitsManager->getUnit(ID);
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
unit->changeAltitude(value[L"change"].as_string());
}
else if (key.compare(L"setSpeed") == 0)
{
int ID = value[L"ID"].as_integer();
Unit* unit = unitsManager->getUnit(ID);
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
unit->setTargetSpeed(value[L"speed"].as_double());
unit->setDesiredSpeed(value[L"speed"].as_double());
}
else if (key.compare(L"setSpeedType") == 0)
{
int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
unit->setDesiredSpeedType(value[L"speedType"].as_string());
}
else if (key.compare(L"setAltitude") == 0)
{
int ID = value[L"ID"].as_integer();
Unit* unit = unitsManager->getUnit(ID);
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
unit->setTargetAltitude(value[L"altitude"].as_double());
unit->setDesiredAltitude(value[L"altitude"].as_double());
}
else if (key.compare(L"setAltitudeType") == 0)
{
int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
unit->setDesiredAltitudeType(value[L"altitudeType"].as_string());
}
else if (key.compare(L"cloneUnit") == 0)
{
@@ -211,28 +229,32 @@ void Scheduler::handleRequest(wstring key, json::value value)
else if (key.compare(L"setROE") == 0)
{
int ID = value[L"ID"].as_integer();
Unit* unit = unitsManager->getUnit(ID);
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
wstring ROE = value[L"ROE"].as_string();
unit->setROE(ROE);
}
else if (key.compare(L"setReactionToThreat") == 0)
{
int ID = value[L"ID"].as_integer();
Unit* unit = unitsManager->getUnit(ID);
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
wstring reactionToThreat = value[L"reactionToThreat"].as_string();
unit->setReactionToThreat(reactionToThreat);
}
else if (key.compare(L"setEmissionsCountermeasures") == 0)
{
int ID = value[L"ID"].as_integer();
Unit* unit = unitsManager->getUnit(ID);
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
wstring emissionsCountermeasures = value[L"emissionsCountermeasures"].as_string();
unit->setEmissionsCountermeasures(emissionsCountermeasures);
}
else if (key.compare(L"landAt") == 0)
{
int ID = value[L"ID"].as_integer();
Unit* unit = unitsManager->getUnit(ID);
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(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;
@@ -241,18 +263,21 @@ void Scheduler::handleRequest(wstring key, json::value value)
else if (key.compare(L"deleteUnit") == 0)
{
int ID = value[L"ID"].as_integer();
unitsManager->deleteUnit(ID);
bool explosion = value[L"explosion"].as_bool();
unitsManager->deleteUnit(ID, explosion);
}
else if (key.compare(L"refuel") == 0)
{
int ID = value[L"ID"].as_integer();
Unit* unit = unitsManager->getUnit(ID);
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
unit->setState(State::REFUEL);
}
else if (key.compare(L"setAdvancedOptions") == 0)
{
int ID = value[L"ID"].as_integer();
Unit* unit = unitsManager->getUnit(ID);
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
{
/* Advanced tasking */
@@ -286,6 +311,75 @@ void Scheduler::handleRequest(wstring key, json::value value)
unit->resetActiveDestination();
}
}
else if (key.compare(L"setFollowRoads") == 0)
{
int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
bool followRoads = value[L"followRoads"].as_bool();
Unit* unit = unitsManager->getGroupLeader(ID);
unit->setFollowRoads(followRoads);
}
else if (key.compare(L"setOnOff") == 0)
{
int ID = value[L"ID"].as_integer();
unitsManager->acquireControl(ID);
bool onOff = value[L"onOff"].as_bool();
Unit* unit = unitsManager->getGroupLeader(ID);
unit->setOnOff(onOff);
}
else if (key.compare(L"explosion") == 0)
{
int intensity = value[L"intensity"].as_integer();
double lat = value[L"location"][L"lat"].as_double();
double lng = value[L"location"][L"lng"].as_double();
log(L"Adding " + to_wstring(intensity) + L" explosion at (" + to_wstring(lat) + L", " + to_wstring(lng) + L")");
Coords loc; loc.lat = lat; loc.lng = lng;
command = dynamic_cast<Command*>(new Explosion(intensity, loc));
}
else if (key.compare(L"bombPoint") == 0)
{
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);
unit->setState(State::BOMB_POINT);
unit->setTargetLocation(loc);
}
else if (key.compare(L"carpetBomb") == 0)
{
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);
unit->setState(State::CARPET_BOMB);
unit->setTargetLocation(loc);
}
else if (key.compare(L"bombBuilding") == 0)
{
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);
unit->setState(State::BOMB_BUILDING);
unit->setTargetLocation(loc);
}
else if (key.compare(L"fireAtArea") == 0)
{
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);
unit->setState(State::FIRE_AT_AREA);
unit->setTargetLocation(loc);
}
else
{
log(L"Unknown command: " + key);

View File

@@ -46,19 +46,30 @@ Unit::~Unit()
void Unit::initialize(json::value json)
{
updateExportData(json);
setDefaults();
}
if (getAI()) {
void Unit::setDefaults(bool force)
{
const bool isUnitControlledByOlympus = getControlled();
const bool isUnitAlive = getAlive();
const bool isUnitLeader = unitsManager->isUnitGroupLeader(this);
const bool isUnitLeaderOfAGroupWithOtherUnits = unitsManager->isUnitInGroup(this) && unitsManager->isUnitGroupLeader(this);
const bool isUnitHuman = getFlags()[L"Human"].as_bool();
if (isUnitControlledByOlympus && (isUnitAlive || isUnitLeaderOfAGroupWithOtherUnits) && isUnitLeader && !isUnitHuman) {
/* Set the default IDLE state */
setState(State::IDLE);
/* Set the default options (these are all defaults so will only affect the export data, no DCS command will be sent) */
setROE(L"Designated");
setReactionToThreat(L"Evade");
setEmissionsCountermeasures(L"Defend");
setTACAN(TACAN);
setRadio(radio);
setEPLRS(EPLRS);
setGeneralSettings(generalSettings);
setROE(L"Designated", force);
setReactionToThreat(L"Evade", force);
setEmissionsCountermeasures(L"Defend", force);
setTACAN(TACAN, force);
setRadio(radio, force);
setEPLRS(EPLRS, force);
setGeneralSettings(generalSettings, force);
setOnOff(onOff);
setFollowRoads(followRoads);
}
}
@@ -77,6 +88,24 @@ void Unit::addMeasure(wstring key, json::value value)
}
}
void Unit::runAILoop() {
/* If the unit is alive and it is not a human, run the AI Loop that performs the requested commands and instructions (moving, attacking, etc) */
const bool isUnitControlledByOlympus = getControlled();
const bool isUnitAlive = getAlive();
const bool isUnitLeader = unitsManager->isUnitGroupLeader(this);
const bool isUnitLeaderOfAGroupWithOtherUnits = unitsManager->isUnitInGroup(this) && unitsManager->isUnitGroupLeader(this);
const bool isUnitHuman = getFlags()[L"Human"].as_bool();
// Keep running the AI loop even if the unit is dead if it is the leader of a group which has other members in it
if (isUnitControlledByOlympus && (isUnitAlive || isUnitLeaderOfAGroupWithOtherUnits) && isUnitLeader && !isUnitHuman)
{
if (checkTaskFailed() && state != State::IDLE && State::LAND)
setState(State::IDLE);
AIloop();
}
}
void Unit::updateExportData(json::value json)
{
/* Compute speed (loGetWorldObjects does not provide speed, we compute it for better performance instead of relying on many lua calls) */
@@ -112,12 +141,8 @@ void Unit::updateExportData(json::value json)
setFlags(json[L"Flags"]);
/* All units which contain the name "Olympus" are automatically under AI control */
/* TODO: I don't really like using this method */
setAI(getUnitName().find(L"Olympus") != wstring::npos);
/* If the unit is alive and it is not a human, run the AI Loop that performs the requested commands and instructions (moving, attacking, etc) */
if (getAI() && getAlive() && getFlags()[L"Human"].as_bool() == false)
AIloop();
if (getUnitName().find(L"Olympus") != wstring::npos)
setControlled(true);
}
void Unit::updateMissionData(json::value json)
@@ -126,19 +151,23 @@ void Unit::updateMissionData(json::value json)
setFuel(int(json[L"fuel"].as_number().to_double() * 100));
if (json.has_object_field(L"ammo"))
setAmmo(json[L"ammo"]);
if (json.has_object_field(L"targets"))
setTargets(json[L"targets"]);
if (json.has_object_field(L"contacts"))
setContacts(json[L"contacts"]);
if (json.has_boolean_field(L"hasTask"))
setHasTask(json[L"hasTask"].as_bool());
}
json::value Unit::getData(long long time)
json::value Unit::getData(long long time, bool sendAll)
{
auto json = json::value::object();
/* If the unit is in a group, task & option data is given by the group leader */
if (unitsManager->isUnitInGroup(this) && !unitsManager->isUnitGroupLeader(this))
json = unitsManager->getGroupLeader(this)->getData(time, true);
/********** Base data **********/
json[L"baseData"] = json::value::object();
for (auto key : { L"AI", L"name", L"unitName", L"groupName", L"alive", L"category"})
for (auto key : { L"controlled", L"name", L"unitName", L"groupName", L"alive", L"category"})
{
if (measures.find(key) != measures.end() && measures[key]->getTime() > time)
json[L"baseData"][key] = measures[key]->getValue();
@@ -146,7 +175,7 @@ json::value Unit::getData(long long time)
if (json[L"baseData"].size() == 0)
json.erase(L"baseData");
if (alive) {
if (alive || sendAll) {
/********** Flight data **********/
json[L"flightData"] = json::value::object();
for (auto key : { L"latitude", L"longitude", L"altitude", L"speed", L"heading" })
@@ -159,7 +188,7 @@ json::value Unit::getData(long long time)
/********** Mission data **********/
json[L"missionData"] = json::value::object();
for (auto key : { L"fuel", L"ammo", L"targets", L"hasTask", L"coalition", L"flags" })
for (auto key : { L"fuel", L"ammo", L"contacts", L"hasTask", L"coalition", L"flags" })
{
if (measures.find(key) != measures.end() && measures[key]->getTime() > time)
json[L"missionData"][key] = measures[key]->getValue();
@@ -177,25 +206,28 @@ json::value Unit::getData(long long time)
if (json[L"formationData"].size() == 0)
json.erase(L"formationData");
/********** Task data **********/
json[L"taskData"] = json::value::object();
for (auto key : { L"currentState", L"currentTask", L"targetSpeed", L"targetAltitude", L"activePath", L"isTanker", L"isAWACS" })
{
if (measures.find(key) != measures.end() && measures[key]->getTime() > time)
json[L"taskData"][key] = measures[key]->getValue();
}
if (json[L"taskData"].size() == 0)
json.erase(L"taskData");
/* If the unit is in a group, task & option data is given by the group leader */
if (unitsManager->isUnitGroupLeader(this)) {
/********** Task data **********/
json[L"taskData"] = json::value::object();
for (auto key : { L"currentState", L"currentTask", L"desiredSpeed", L"desiredAltitude", L"desiredSpeedType", L"desiredAltitudeType", L"activePath", L"isTanker", L"isAWACS", L"onOff", L"followRoads", L"targetID", L"targetLocation" })
{
if (measures.find(key) != measures.end() && measures[key]->getTime() > time)
json[L"taskData"][key] = measures[key]->getValue();
}
if (json[L"taskData"].size() == 0)
json.erase(L"taskData");
/********** Options data **********/
json[L"optionsData"] = json::value::object();
for (auto key : { L"ROE", L"reactionToThreat", L"emissionsCountermeasures", L"TACAN", L"radio", L"generalSettings"})
{
if (measures.find(key) != measures.end() && measures[key]->getTime() > time)
json[L"optionsData"][key] = measures[key]->getValue();
/********** Options data **********/
json[L"optionsData"] = json::value::object();
for (auto key : { L"ROE", L"reactionToThreat", L"emissionsCountermeasures", L"TACAN", L"radio", L"generalSettings" })
{
if (measures.find(key) != measures.end() && measures[key]->getTime() > time)
json[L"optionsData"][key] = measures[key]->getValue();
}
if (json[L"optionsData"].size() == 0)
json.erase(L"optionsData");
}
if (json[L"optionsData"].size() == 0)
json.erase(L"optionsData");
}
return json;
@@ -322,8 +354,10 @@ void Unit::resetActiveDestination()
void Unit::resetTask()
{
Command* command = dynamic_cast<Command*>(new ResetTask(ID));
Command* command = dynamic_cast<Command*>(new ResetTask(groupName));
scheduler->appendCommand(command);
setHasTask(false);
resetTaskFailedCounter();
}
void Unit::setFormationOffset(Offset newFormationOffset)
@@ -332,10 +366,10 @@ void Unit::setFormationOffset(Offset newFormationOffset)
resetTask();
}
void Unit::setROE(wstring newROE) {
void Unit::setROE(wstring newROE, bool force) {
addMeasure(L"ROE", json::value(newROE));
if (ROE != newROE) {
if (ROE != newROE || force) {
ROE = newROE;
int ROEEnum;
@@ -352,15 +386,15 @@ void Unit::setROE(wstring newROE) {
else
return;
Command* command = dynamic_cast<Command*>(new SetOption(ID, SetCommandType::ROE, ROEEnum));
Command* command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::ROE, ROEEnum));
scheduler->appendCommand(command);
}
}
void Unit::setReactionToThreat(wstring newReactionToThreat) {
void Unit::setReactionToThreat(wstring newReactionToThreat, bool force) {
addMeasure(L"reactionToThreat", json::value(newReactionToThreat));
if (reactionToThreat != newReactionToThreat) {
if (reactionToThreat != newReactionToThreat || force) {
reactionToThreat = newReactionToThreat;
int reactionToThreatEnum;
@@ -377,15 +411,15 @@ void Unit::setReactionToThreat(wstring newReactionToThreat) {
else
return;
Command* command = dynamic_cast<Command*>(new SetOption(ID, SetCommandType::REACTION_ON_THREAT, reactionToThreatEnum));
Command* command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::REACTION_ON_THREAT, reactionToThreatEnum));
scheduler->appendCommand(command);
}
}
void Unit::setEmissionsCountermeasures(wstring newEmissionsCountermeasures) {
void Unit::setEmissionsCountermeasures(wstring newEmissionsCountermeasures, bool force) {
addMeasure(L"emissionsCountermeasures", json::value(newEmissionsCountermeasures));
if (emissionsCountermeasures != newEmissionsCountermeasures) {
if (emissionsCountermeasures != newEmissionsCountermeasures || force) {
emissionsCountermeasures = newEmissionsCountermeasures;
int radarEnum;
@@ -420,13 +454,13 @@ void Unit::setEmissionsCountermeasures(wstring newEmissionsCountermeasures) {
Command* command;
command = dynamic_cast<Command*>(new SetOption(ID, SetCommandType::RADAR_USING, radarEnum));
command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::RADAR_USING, radarEnum));
scheduler->appendCommand(command);
command = dynamic_cast<Command*>(new SetOption(ID, SetCommandType::FLARE_USING, flareEnum));
command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::FLARE_USING, flareEnum));
scheduler->appendCommand(command);
command = dynamic_cast<Command*>(new SetOption(ID, SetCommandType::ECM_USING, ECMEnum));
command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::ECM_USING, ECMEnum));
scheduler->appendCommand(command);
}
}
@@ -450,7 +484,7 @@ void Unit::setIsAWACS(bool newIsAWACS) {
setEPLRS(isAWACS);
}
void Unit::setTACAN(Options::TACAN newTACAN) {
void Unit::setTACAN(Options::TACAN newTACAN, bool force) {
auto json = json::value();
json[L"isOn"] = json::value(newTACAN.isOn);
json[L"channel"] = json::value(newTACAN.channel);
@@ -458,7 +492,7 @@ void Unit::setTACAN(Options::TACAN newTACAN) {
json[L"callsign"] = json::value(newTACAN.callsign);
addMeasure(L"TACAN", json);
if (TACAN != newTACAN)
if (TACAN != newTACAN || force)
{
TACAN = newTACAN;
if (TACAN.isOn) {
@@ -473,7 +507,7 @@ void Unit::setTACAN(Options::TACAN newTACAN) {
<< "frequency = " << TACANChannelToFrequency(TACAN.channel, TACAN.XY) << ","
<< "}"
<< "}";
Command* command = dynamic_cast<Command*>(new SetCommand(ID, commandSS.str()));
Command* command = dynamic_cast<Command*>(new SetCommand(groupName, commandSS.str()));
scheduler->appendCommand(command);
}
else {
@@ -483,13 +517,13 @@ void Unit::setTACAN(Options::TACAN newTACAN) {
<< "params = {"
<< "}"
<< "}";
Command* command = dynamic_cast<Command*>(new SetCommand(ID, commandSS.str()));
Command* command = dynamic_cast<Command*>(new SetCommand(groupName, commandSS.str()));
scheduler->appendCommand(command);
}
}
}
void Unit::setRadio(Options::Radio newRadio) {
void Unit::setRadio(Options::Radio newRadio, bool force) {
auto json = json::value();
json[L"frequency"] = json::value(newRadio.frequency);
@@ -497,7 +531,7 @@ void Unit::setRadio(Options::Radio newRadio) {
json[L"callsignNumber"] = json::value(newRadio.callsignNumber);
addMeasure(L"radio", json);
if (radio != newRadio)
if (radio != newRadio || force)
{
radio = newRadio;
@@ -511,7 +545,7 @@ void Unit::setRadio(Options::Radio newRadio) {
<< "frequency = " << radio.frequency << ","
<< "}"
<< "}";
command = dynamic_cast<Command*>(new SetCommand(ID, commandSS.str()));
command = dynamic_cast<Command*>(new SetCommand(groupName, commandSS.str()));
scheduler->appendCommand(command);
// Clear the stringstream
@@ -524,16 +558,16 @@ void Unit::setRadio(Options::Radio newRadio) {
<< "number = " << radio.callsignNumber << ","
<< "}"
<< "}";
command = dynamic_cast<Command*>(new SetCommand(ID, commandSS.str()));
command = dynamic_cast<Command*>(new SetCommand(groupName, commandSS.str()));
scheduler->appendCommand(command);
}
}
void Unit::setEPLRS(bool newEPLRS)
void Unit::setEPLRS(bool newEPLRS, bool force)
{
//addMeasure(L"EPLRS", json::value(newEPLRS));
//
//if (EPLRS != newEPLRS) {
//if (EPLRS != newEPLRS || force) {
// EPLRS = newEPLRS;
//
// std::wostringstream commandSS;
@@ -548,7 +582,7 @@ void Unit::setEPLRS(bool newEPLRS)
//}
}
void Unit::setGeneralSettings(Options::GeneralSettings newGeneralSettings) {
void Unit::setGeneralSettings(Options::GeneralSettings newGeneralSettings, bool force) {
auto json = json::value();
json[L"prohibitJettison"] = json::value(newGeneralSettings.prohibitJettison);
@@ -563,16 +597,143 @@ void Unit::setGeneralSettings(Options::GeneralSettings newGeneralSettings) {
generalSettings = newGeneralSettings;
Command* command;
command = dynamic_cast<Command*>(new SetOption(ID, SetCommandType::PROHIBIT_AA, generalSettings.prohibitAA));
command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::PROHIBIT_AA, generalSettings.prohibitAA));
scheduler->appendCommand(command);
command = dynamic_cast<Command*>(new SetOption(ID, SetCommandType::PROHIBIT_AG, generalSettings.prohibitAG));
command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::PROHIBIT_AG, generalSettings.prohibitAG));
scheduler->appendCommand(command);
command = dynamic_cast<Command*>(new SetOption(ID, SetCommandType::PROHIBIT_JETT, generalSettings.prohibitJettison));
command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::PROHIBIT_JETT, generalSettings.prohibitJettison));
scheduler->appendCommand(command);
command = dynamic_cast<Command*>(new SetOption(ID, SetCommandType::PROHIBIT_AB, generalSettings.prohibitAfterburner));
command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::PROHIBIT_AB, generalSettings.prohibitAfterburner));
scheduler->appendCommand(command);
command = dynamic_cast<Command*>(new SetOption(ID, SetCommandType::ENGAGE_AIR_WEAPONS, !generalSettings.prohibitAirWpn));
command = dynamic_cast<Command*>(new SetOption(groupName, SetCommandType::ENGAGE_AIR_WEAPONS, !generalSettings.prohibitAirWpn));
scheduler->appendCommand(command);
}
}
void Unit::setDesiredSpeed(double newDesiredSpeed) {
desiredSpeed = newDesiredSpeed;
addMeasure(L"desiredSpeed", json::value(newDesiredSpeed));
if (state == State::IDLE)
resetTask();
else
goToDestination(); /* Send the command to reach the destination */
}
void Unit::setDesiredAltitude(double newDesiredAltitude) {
desiredAltitude = newDesiredAltitude;
addMeasure(L"desiredAltitude", json::value(newDesiredAltitude));
if (state == State::IDLE)
resetTask();
else
goToDestination(); /* Send the command to reach the destination */
}
void Unit::setDesiredSpeedType(wstring newDesiredSpeedType) {
desiredSpeedType = newDesiredSpeedType;
addMeasure(L"desiredSpeedType", json::value(newDesiredSpeedType));
if (state == State::IDLE)
resetTask();
else
goToDestination(); /* Send the command to reach the destination */
}
void Unit::setDesiredAltitudeType(wstring newDesiredAltitudeType) {
desiredAltitudeType = newDesiredAltitudeType;
addMeasure(L"desiredAltitudeType", json::value(newDesiredAltitudeType));
if (state == State::IDLE)
resetTask();
else
goToDestination(); /* Send the command to reach the destination */
}
void Unit::goToDestination(wstring enrouteTask)
{
if (activeDestination != NULL)
{
Command* command = dynamic_cast<Command*>(new Move(groupName, activeDestination, getDesiredSpeed(), getDesiredSpeedType(), getDesiredAltitude(), getDesiredAltitudeType(), enrouteTask, getCategory()));
scheduler->appendCommand(command);
setHasTask(true);
}
}
bool Unit::isDestinationReached(double threshold)
{
if (activeDestination != NULL)
{
/* Check if any unit in the group has reached the point */
for (auto const& p: unitsManager->getGroupMembers(groupName))
{
double dist = 0;
Geodesic::WGS84().Inverse(p->getLatitude(), p->getLongitude(), 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;
}
}
void Unit::setTargetLocation(Coords newTargetLocation) {
targetLocation = newTargetLocation;
auto json = json::value();
json[L"latitude"] = json::value(newTargetLocation.lat);
json[L"longitude"] = json::value(newTargetLocation.lng);
addMeasure(L"targetLocation", json::value(json));
}
bool Unit::checkTaskFailed() {
if (getHasTask())
return false;
else {
if (taskCheckCounter > 0)
taskCheckCounter--;
return taskCheckCounter == 0;
}
}
void Unit::resetTaskFailedCounter() {
taskCheckCounter = TASK_CHECK_INIT_VALUE;
}
void Unit::setHasTask(bool newHasTask) {
hasTask = newHasTask;
addMeasure(L"hasTask", json::value(newHasTask));
}

View File

@@ -95,6 +95,14 @@ void UnitsManager::updateMissionData(json::value missionData)
}
}
void UnitsManager::runAILoop() {
/* Run the AI Loop on all units */
for (auto const& unit : units)
{
unit.second->runAILoop();
}
}
void UnitsManager::getData(json::value& answer, long long time)
{
auto unitsJson = json::value::object();
@@ -116,3 +124,17 @@ void UnitsManager::deleteUnit(int ID)
}
}
void UnitsManager::acquireControl(int ID) {
Unit* unit = getUnit(ID);
if (unit != nullptr) {
for (auto const& groupMember : getGroupMembers(unit->getGroupName())) {
if (!groupMember->getControlled()) {
groupMember->setControlled(true);
groupMember->setState(State::IDLE);
groupMember->setDefaults(true);
}
}
}
}