Toggling this disables unit AI completely. It will no longer move, react or emit radio waves.
+
+
+
+
Follow roads
+
+
+
-
-
+
+
+
-
-
-
-
+
+
\ No newline at end of file
diff --git a/client/views/panels/unitinfo.ejs b/client/views/panels/unitinfo.ejs
index 603f4988..3c03ca9c 100644
--- a/client/views/panels/unitinfo.ejs
+++ b/client/views/panels/unitinfo.ejs
@@ -14,7 +14,7 @@
-
+
diff --git a/installer/olympus.iss b/installer/olympus.iss
index dfc937f3..55664142 100644
--- a/installer/olympus.iss
+++ b/installer/olympus.iss
@@ -1,5 +1,5 @@
#define nwjsFolder "C:\Users\dpass\Documents\nwjs\"
-#define version "v0.2.1-alpha"
+#define version "v0.3.0-alpha"
[Setup]
AppName=DCS Olympus
diff --git a/scripts/OlympusCommand.lua b/scripts/OlympusCommand.lua
index bd61f8d2..71007d8d 100644
--- a/scripts/OlympusCommand.lua
+++ b/scripts/OlympusCommand.lua
@@ -1,4 +1,4 @@
-local version = "v0.2.1-alpha"
+local version = "v0.3.0-alpha"
local debug = true
@@ -139,29 +139,73 @@ function Olympus.buildTask(options)
pattern = options['pattern'] or "Circle"
}
}
+ elseif options['id'] == 'Bombing' and options['lat'] and options['lng'] then
+ local point = coord.LLtoLO(options['lat'], options['lng'], 0)
+ task = {
+ id = 'Bombing',
+ params = {
+ point = {x = point.x, y = point.z},
+ attackQty = 1
+ }
+ }
+ elseif options['id'] == 'CarpetBombing' and options['lat'] and options['lng'] then
+ local point = coord.LLtoLO(options['lat'], options['lng'], 0)
+ task = {
+ id = 'CarpetBombing',
+ params = {
+ x = point.x,
+ y = point.z,
+ carpetLength = 1000,
+ attackType = 'Carpet',
+ expend = "All",
+ attackQty = 1,
+ attackQtyLimit = true
+ }
+ }
+ elseif options['id'] == 'AttackMapObject' and options['lat'] and options['lng'] then
+ local point = coord.LLtoLO(options['lat'], options['lng'], 0)
+ task = {
+ id = 'AttackMapObject',
+ params = {
+ point = {x = point.x, y = point.z}
+ }
+ }
+ elseif options['id'] == 'FireAtPoint' and options['lat'] and options['lng'] and options['radius'] then
+ local point = coord.LLtoLO(options['lat'], options['lng'], 0)
+ task = {
+ id = 'FireAtPoint',
+ params = {
+ point = {x = point.x, y = point.z},
+ radius = options['radius']
+ }
+ }
end
end
return task
end
-- Move a unit. Since many tasks in DCS are Enroute tasks, this function is an important way to control the unit AI
-function Olympus.move(ID, lat, lng, altitude, speed, category, taskOptions)
- Olympus.debug("Olympus.move " .. ID .. " (" .. lat .. ", " .. lng ..") " .. altitude .. "m " .. speed .. "m/s " .. category, 2)
- local unit = Olympus.getUnitByID(ID)
- if unit then
+function Olympus.move(groupName, lat, lng, altitude, altitudeType, speed, speedType, category, taskOptions)
+ Olympus.debug("Olympus.move " .. groupName .. " (" .. lat .. ", " .. lng ..") " .. altitude .. "m " .. altitudeType .. " ".. speed .. "m/s " .. category .. " " .. Olympus.serializeTable(taskOptions), 2)
+ local group = Group.getByName(groupName)
+ if group then
if category == "Aircraft" then
- local startPoint = mist.getLeadPos(unit:getGroup())
+ local startPoint = mist.getLeadPos(group)
local endPoint = coord.LLtoLO(lat, lng, 0)
+ if altitudeType == "AGL" then
+ altitude = land.getHeight({x = endPoint.x, y = endPoint.z}) + altitude
+ end
+
local path = {}
if taskOptions and taskOptions['id'] == 'Land' then
path = {
- [1] = mist.fixedWing.buildWP(startPoint, flyOverPoint, speed, altitude, 'BARO'),
+ [1] = mist.fixedWing.buildWP(startPoint, turningPoint, speed, altitude, 'BARO'),
[2] = mist.fixedWing.buildWP(endPoint, landing, speed, 0, 'AGL')
}
else
path = {
- [1] = mist.fixedWing.buildWP(startPoint, flyOverPoint, speed, altitude, 'BARO'),
+ [1] = mist.fixedWing.buildWP(startPoint, turningPoint, speed, altitude, 'BARO'),
[2] = mist.fixedWing.buildWP(endPoint, turningPoint, speed, altitude, 'BARO')
}
end
@@ -184,7 +228,6 @@ function Olympus.move(ID, lat, lng, altitude, speed, category, taskOptions)
},
},
}
- group = unit:getGroup()
local groupCon = group:getController()
if groupCon then
groupCon:setTask(missionTask)
@@ -193,20 +236,26 @@ function Olympus.move(ID, lat, lng, altitude, speed, category, taskOptions)
elseif category == "GroundUnit" then
vars =
{
- group = unit:getGroup(),
+ group = group,
point = coord.LLtoLO(lat, lng, 0),
- form = "Off Road",
heading = 0,
- speed = speed,
- disableRoads = true
+ speed = speed
}
+
+ if taskOptions and taskOptions['id'] == 'FollowRoads' and taskOptions['value'] == true then
+ vars["disableRoads"] = false
+ else
+ vars["form"] = "Off Road"
+ vars["disableRoads"] = true
+ end
+
mist.groupToRandomPoint(vars)
Olympus.debug("Olympus.move executed succesfully on a ground unit", 2)
else
Olympus.debug("Olympus.move not implemented yet for " .. category, 2)
end
else
- Olympus.debug("Error in Olympus.move " .. ID, 2)
+ Olympus.debug("Error in Olympus.move " .. groupName, 2)
end
end
@@ -228,6 +277,12 @@ function Olympus.smoke(color, lat, lng)
trigger.action.smoke(mist.utils.makeVec3GL(coord.LLtoLO(lat, lng, 0)), colorEnum)
end
+-- Creates an explosion on the ground
+function Olympus.explosion(intensity, lat, lng)
+ Olympus.debug("Olympus.explosion " .. intensity .. " (" .. lat .. ", " .. lng ..")", 2)
+ trigger.action.explosion(mist.utils.makeVec3GL(coord.LLtoLO(lat, lng, 0)), intensity)
+end
+
-- Spawns a single ground unit
function Olympus.spawnGroundUnit(coalition, unitType, lat, lng)
Olympus.debug("Olympus.spawnGroundUnit " .. coalition .. " " .. unitType .. " (" .. lat .. ", " .. lng ..")", 2)
@@ -279,12 +334,12 @@ end
-- payloadName: a string, one of the names defined in unitPayloads.lua. Must be compatible with the unitType
-- airbaseName: a string, if present the aircraft will spawn on the ground of the selected airbase
-- payload: a table, if present the unit will receive this specific payload. Overrides payloadName
-function Olympus.spawnAircraft(coalition, unitType, lat, lng, spawnOptions)
+function Olympus.spawnAircraft(coalition, unitType, lat, lng, alt, spawnOptions)
local payloadName = spawnOptions["payloadName"]
local airbaseName = spawnOptions["airbaseName"]
local payload = spawnOptions["payload"]
- Olympus.debug("Olympus.spawnAircraft " .. coalition .. " " .. unitType .. " (" .. lat .. ", " .. lng ..")", 2)
+ Olympus.debug("Olympus.spawnAircraft " .. coalition .. " " .. unitType .. " (" .. lat .. ", " .. lng ..", " .. alt .. ")", 2)
local spawnLocation = mist.utils.makeVec3GL(coord.LLtoLO(lat, lng, 0))
if payload == nil then
@@ -304,7 +359,7 @@ function Olympus.spawnAircraft(coalition, unitType, lat, lng, spawnOptions)
["type"] = unitType,
["x"] = spawnLocation.x,
["y"] = spawnLocation.z,
- ["alt"] = 20000 * 0.3048,
+ ["alt"] = alt,
["alt_type"] = "BARO",
["skill"] = "Excellent",
["payload"] =
@@ -359,8 +414,61 @@ function Olympus.spawnAircraft(coalition, unitType, lat, lng, spawnOptions)
},
}
end
+ else
+ route = {
+ ["points"] =
+ {
+ [1] =
+ {
+ ["alt"] = alt,
+ ["alt_type"] = "BARO",
+ ["task"] =
+ {
+ ["id"] = "ComboTask",
+ ["params"] =
+ {
+ ["tasks"] =
+ {
+ [1] =
+ {
+ ["number"] = 1,
+ ["auto"] = true,
+ ["id"] = "WrappedAction",
+ ["enabled"] = true,
+ ["params"] =
+ {
+ ["action"] =
+ {
+ ["id"] = "EPLRS",
+ ["params"] =
+ {
+ ["value"] = true
+ },
+ },
+ },
+ },
+ [2] =
+ {
+ ["number"] = 2,
+ ["auto"] = false,
+ ["id"] = "Orbit",
+ ["enabled"] = true,
+ ["params"] =
+ {
+ ["pattern"] = "Circle"
+ },
+ },
+ },
+ },
+ },
+ ["type"] = "Turning Point",
+ ["x"] = spawnLocation.x,
+ ["y"] = spawnLocation.z,
+ }, -- end of [1]
+ }, -- end of ["points"]
+ } -- end of ["route"]
end
-
+
local vars =
{
units = unitTable,
@@ -390,7 +498,7 @@ function Olympus.clone(ID, lat, lng, category)
local spawnOptions = {
payload = Olympus.payloadRegistry[unit:getName()]
}
- Olympus.spawnAircraft(coalition, unit:getTypeName(), lat, lng, spawnOptions)
+ Olympus.spawnAircraft(coalition, unit:getTypeName(), lat, lng, unit:getPoint().y, spawnOptions)
elseif category == "GroundUnit" then
Olympus.spawnGroundUnit(coalition, unit:getTypeName(), lat, lng)
end
@@ -398,11 +506,11 @@ function Olympus.clone(ID, lat, lng, category)
Olympus.debug("Olympus.clone completed successfully", 2)
end
-function Olympus.delete(ID, lat, lng)
- Olympus.debug("Olympus.delete " .. ID, 2)
+function Olympus.delete(ID, explosion)
+ Olympus.debug("Olympus.delete " .. ID .. " " .. tostring(explosion), 2)
local unit = Olympus.getUnitByID(ID)
if unit then
- if unit:getPlayerName() then
+ if unit:getPlayerName() or explosion then
trigger.action.explosion(unit:getPoint() , 250 ) --consider replacing with forcibly deslotting the player, however this will work for now
Olympus.debug("Olympus.delete completed successfully", 2)
else
@@ -412,46 +520,55 @@ function Olympus.delete(ID, lat, lng)
end
end
-function Olympus.setTask(ID, taskOptions)
- Olympus.debug("Olympus.setTask " .. ID .. " " .. Olympus.serializeTable(taskOptions), 2)
- local unit = Olympus.getUnitByID(ID)
- if unit then
+function Olympus.setTask(groupName, taskOptions)
+ Olympus.debug("Olympus.setTask " .. groupName .. " " .. Olympus.serializeTable(taskOptions), 2)
+ local group = Group.getByName(groupName)
+ if group then
local task = Olympus.buildTask(taskOptions);
Olympus.debug("Olympus.setTask " .. Olympus.serializeTable(task), 20)
if task then
- unit:getGroup():getController():setTask(task)
+ group:getController():setTask(task)
Olympus.debug("Olympus.setTask completed successfully", 2)
end
end
end
-function Olympus.resetTask(ID)
- Olympus.debug("Olympus.resetTask " .. ID, 2)
- local unit = Olympus.getUnitByID(ID)
- if unit then
- unit:getGroup():getController():resetTask()
+function Olympus.resetTask(groupName)
+ Olympus.debug("Olympus.resetTask " .. groupName, 2)
+ local group = Group.getByName(groupName)
+ if group then
+ group:getController():resetTask()
Olympus.debug("Olympus.resetTask completed successfully", 2)
end
end
-function Olympus.setCommand(ID, command)
- Olympus.debug("Olympus.setCommand " .. ID .. " " .. Olympus.serializeTable(command), 2)
- local unit = Olympus.getUnitByID(ID)
- if unit then
- unit:getGroup():getController():setCommand(command)
+function Olympus.setCommand(groupName, command)
+ Olympus.debug("Olympus.setCommand " .. groupName .. " " .. Olympus.serializeTable(command), 2)
+ local group = Group.getByName(groupName)
+ if group then
+ group:getController():setCommand(command)
Olympus.debug("Olympus.setCommand completed successfully", 2)
end
end
-function Olympus.setOption(ID, optionID, optionValue)
- Olympus.debug("Olympus.setOption " .. ID .. " " .. optionID .. " " .. tostring(optionValue), 2)
- local unit = Olympus.getUnitByID(ID)
- if unit then
- unit:getGroup():getController():setOption(optionID, optionValue)
+function Olympus.setOption(groupName, optionID, optionValue)
+ Olympus.debug("Olympus.setOption " .. groupName .. " " .. optionID .. " " .. tostring(optionValue), 2)
+ local group = Group.getByName(groupName)
+ if group then
+ group:getController():setOption(optionID, optionValue)
Olympus.debug("Olympus.setOption completed successfully", 2)
end
end
+function Olympus.setOnOff(groupName, onOff)
+ Olympus.debug("Olympus.setOnOff " .. groupName .. " " .. tostring(onOff), 2)
+ local group = Group.getByName(groupName)
+ if group then
+ group:getController():setOnOff(onOff)
+ Olympus.debug("Olympus.setOnOff completed successfully", 2)
+ end
+end
+
function Olympus.serializeTable(val, name, skipnewlines, depth)
skipnewlines = skipnewlines or false
depth = depth or 0
diff --git a/scripts/OlympusHook.lua b/scripts/OlympusHook.lua
index 7215d3cd..b87c8926 100644
--- a/scripts/OlympusHook.lua
+++ b/scripts/OlympusHook.lua
@@ -1,4 +1,4 @@
-local version = 'v0.2.1-alpha'
+local version = 'v0.3.0-alpha'
Olympus = {}
Olympus.OlympusDLL = nil
diff --git a/src/core/include/aircraft.h b/src/core/include/aircraft.h
index 6d15e4f6..7fd3f615 100644
--- a/src/core/include/aircraft.h
+++ b/src/core/include/aircraft.h
@@ -10,12 +10,4 @@ public:
virtual void changeSpeed(wstring change);
virtual void changeAltitude(wstring change);
- virtual double getTargetSpeed() { return targetSpeed; };
- virtual double getTargetAltitude() { return targetAltitude; };
- virtual void setTargetSpeed(double newTargetSpeed);
- virtual void setTargetAltitude(double newTargetAltitude);
-
-protected:
- double targetSpeed = 300 / 1.94384;
- double targetAltitude = 20000 * 0.3048;
};
\ No newline at end of file
diff --git a/src/core/include/airunit.h b/src/core/include/airunit.h
index a46e9909..cabd7b9e 100644
--- a/src/core/include/airunit.h
+++ b/src/core/include/airunit.h
@@ -12,17 +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 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/commands.h b/src/core/include/commands.h
index 7752eea8..d4e0bab3 100644
--- a/src/core/include/commands.h
+++ b/src/core/include/commands.h
@@ -81,8 +81,6 @@ namespace ECMUse {
};
}
-
-
/* Base command class */
class Command
{
@@ -99,12 +97,15 @@ protected:
class Move : public Command
{
public:
- Move(int ID, Coords destination, double speed, double altitude, wstring taskOptions):
- ID(ID),
+ Move(wstring groupName, Coords destination, double speed, wstring speedType, double altitude, wstring altitudeType, wstring taskOptions, wstring category):
+ groupName(groupName),
destination(destination),
speed(speed),
+ speedType(speedType),
altitude(altitude),
- taskOptions(taskOptions)
+ altitudeType(altitudeType),
+ taskOptions(taskOptions),
+ category(category)
{
priority = CommandPriority::HIGH;
};
@@ -112,11 +113,14 @@ public:
virtual int getLoad() { return 5; }
private:
- const int ID;
+ const wstring groupName;
const Coords destination;
const double speed;
+ const wstring speedType;
const double altitude;
+ const wstring altitudeType;
const wstring taskOptions;
+ const wstring category;
};
/* Smoke command */
@@ -203,8 +207,9 @@ private:
class Delete : public Command
{
public:
- Delete(int ID) :
- ID(ID)
+ Delete(int ID, bool explosion) :
+ ID(ID),
+ explosion(explosion)
{
priority = CommandPriority::HIGH;
};
@@ -213,14 +218,15 @@ public:
private:
const int ID;
+ const bool explosion;
};
/* Follow command */
class SetTask : public Command
{
public:
- SetTask(int ID, wstring task) :
- ID(ID),
+ SetTask(wstring groupName, wstring task) :
+ groupName(groupName),
task(task)
{
priority = CommandPriority::MEDIUM;
@@ -229,7 +235,7 @@ public:
virtual int getLoad() { return 10; }
private:
- const int ID;
+ const wstring groupName;
const wstring task;
};
@@ -237,8 +243,8 @@ private:
class ResetTask : public Command
{
public:
- ResetTask(int ID) :
- ID(ID)
+ ResetTask(wstring groupName) :
+ groupName(groupName)
{
priority = CommandPriority::HIGH;
};
@@ -246,15 +252,15 @@ public:
virtual int getLoad() { return 10; }
private:
- const int ID;
+ const wstring groupName;
};
/* Set command */
class SetCommand : public Command
{
public:
- SetCommand(int ID, wstring command) :
- ID(ID),
+ SetCommand(wstring groupName, wstring command) :
+ groupName(groupName),
command(command)
{
priority = CommandPriority::HIGH;
@@ -263,7 +269,7 @@ public:
virtual int getLoad() { return 10; }
private:
- const int ID;
+ const wstring groupName;
const wstring command;
};
@@ -271,8 +277,8 @@ private:
class SetOption : public Command
{
public:
- SetOption(int ID, int optionID, int optionValue) :
- ID(ID),
+ SetOption(wstring groupName, int optionID, int optionValue) :
+ groupName(groupName),
optionID(optionID),
optionValue(optionValue),
optionBool(false),
@@ -281,8 +287,8 @@ public:
priority = CommandPriority::HIGH;
};
- SetOption(int ID, int optionID, bool optionBool) :
- ID(ID),
+ SetOption(wstring groupName, int optionID, bool optionBool) :
+ groupName(groupName),
optionID(optionID),
optionValue(0),
optionBool(optionBool),
@@ -294,9 +300,45 @@ public:
virtual int getLoad() { return 10; }
private:
- const int ID;
+ const wstring groupName;
const int optionID;
const int optionValue;
const bool optionBool;
const bool isBoolean;
-};
\ No newline at end of file
+};
+
+/* Set on off */
+class SetOnOff : public Command
+{
+public:
+ SetOnOff(wstring groupName, bool onOff) :
+ groupName(groupName),
+ onOff(onOff)
+ {
+ priority = CommandPriority::HIGH;
+ };
+ virtual wstring getString(lua_State* L);
+ virtual int getLoad() { return 10; }
+
+private:
+ const wstring groupName;
+ const bool onOff;
+};
+
+/* Make a ground explosion */
+class Explosion : public Command
+{
+public:
+ Explosion(int intensity, Coords location) :
+ location(location),
+ intensity(intensity)
+ {
+ priority = CommandPriority::MEDIUM;
+ };
+ virtual wstring getString(lua_State* L);
+ virtual int getLoad() { return 10; }
+
+private:
+ const Coords location;
+ const int intensity;
+};
diff --git a/src/core/include/groundunit.h b/src/core/include/groundunit.h
index 6edb1a3b..6b5930b0 100644
--- a/src/core/include/groundunit.h
+++ b/src/core/include/groundunit.h
@@ -7,13 +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 double getTargetSpeed() { return targetSpeed; };
+ virtual void setOnOff(bool newOnOff);
+ virtual void setFollowRoads(bool newFollowRoads);
protected:
- double targetSpeed = 10;
+ virtual void AIloop();
};
\ No newline at end of file
diff --git a/src/core/include/helicopter.h b/src/core/include/helicopter.h
index 50a0e9c2..097990b3 100644
--- a/src/core/include/helicopter.h
+++ b/src/core/include/helicopter.h
@@ -10,12 +10,4 @@ public:
virtual void changeSpeed(wstring change);
virtual void changeAltitude(wstring change);
- virtual double getTargetSpeed() { return targetSpeed; };
- virtual double getTargetAltitude() { return targetAltitude; };
- virtual void setTargetSpeed(double newTargetSpeed);
- virtual void setTargetAltitude(double newTargetAltitude);
-
-protected:
- double targetSpeed = 100 / 1.94384;
- double targetAltitude = 5000 * 0.3048;
};
\ No newline at end of file
diff --git a/src/core/include/navyunit.h b/src/core/include/navyunit.h
index d70d86d2..a27b5a31 100644
--- a/src/core/include/navyunit.h
+++ b/src/core/include/navyunit.h
@@ -9,9 +9,5 @@ public:
virtual wstring getCategory() { return L"NavyUnit"; };
virtual void changeSpeed(wstring change);
- virtual void changeAltitude(wstring change) {};
- virtual double getTargetSpeed() { return targetSpeed; };
-protected:
- double targetSpeed = 10;
};
\ No newline at end of file
diff --git a/src/core/include/unit.h b/src/core/include/unit.h
index 2d6d6bcf..5d6dafb3 100644
--- a/src/core/include/unit.h
+++ b/src/core/include/unit.h
@@ -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
};
};
@@ -59,7 +65,7 @@ public:
int getID() { return ID; }
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 **********/
@@ -70,6 +76,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 +91,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; }
@@ -94,9 +102,10 @@ public:
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 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; }
@@ -108,31 +117,38 @@ 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 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 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 wstring getTargetSpeedType() { return targetSpeedType; };
+ virtual wstring getTargetAltitudeType() { return targetAltitudeType; };
Coords getActiveDestination() { return activeDestination; }
list 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);
@@ -142,6 +158,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; };
@@ -152,16 +169,21 @@ 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 measures;
+ int taskCheckCounter = 0;
/********** Base data **********/
bool AI = false;
@@ -196,11 +218,16 @@ protected:
wstring currentTask = L"";
double targetSpeed = 0;
double targetAltitude = 0;
+ wstring targetSpeedType = L"GS";
+ wstring targetAltitudeType = L"AGL";
list 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 +251,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();
};
diff --git a/src/core/include/unitsmanager.h b/src/core/include/unitsmanager.h
index a851a388..d3d5d65b 100644
--- a/src/core/include/unitsmanager.h
+++ b/src/core/include/unitsmanager.h
@@ -11,10 +11,15 @@ public:
~UnitsManager();
Unit* getUnit(int ID);
+ bool isUnitInGroup(Unit* unit);
+ bool isUnitGroupLeader(Unit* unit);
+ Unit* getGroupLeader(int ID);
+ Unit* getGroupLeader(Unit* unit);
+ vector getGroupMembers(wstring groupName);
void updateExportData(lua_State* L);
void updateMissionData(json::value missionData);
void getData(json::value& answer, long long time);
- void deleteUnit(int ID);
+ void deleteUnit(int ID, bool explosion);
private:
map units;
diff --git a/src/core/src/aircraft.cpp b/src/core/src/aircraft.cpp
index 79f2694d..f03c616b 100644
--- a/src/core/src/aircraft.cpp
+++ b/src/core/src/aircraft.cpp
@@ -17,6 +17,9 @@ 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 = knotsToMs(300);
+ double targetAltitude = ftToM(20000);
setTargetSpeed(targetSpeed);
setTargetAltitude(targetAltitude);
};
@@ -24,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 */
}
@@ -43,33 +44,19 @@ 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);
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();
}
\ No newline at end of file
diff --git a/src/core/src/airunit.cpp b/src/core/src/airunit.cpp
index 78d87cdf..331e3ff8 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: {
@@ -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(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,7 +131,7 @@ void AirUnit::AIloop()
case State::IDLE: {
currentTask = L"Idle";
- if (!hasTask)
+ if (!getHasTask())
{
std::wostringstream taskSS;
if (isTanker) {
@@ -182,7 +143,7 @@ void AirUnit::AIloop()
else {
taskSS << "{ id = 'Orbit', pattern = 'Circle' }";
}
- Command* command = dynamic_cast(new SetTask(ID, taskSS.str()));
+ Command* command = dynamic_cast(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(new SetTask(ID, taskSS.str()));
+ Command* command = dynamic_cast(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(new SetTask(ID, taskSS.str()));
+ Command* command = dynamic_cast(new SetTask(groupName, taskSS.str()));
scheduler->appendCommand(command);
setHasTask(true);
}
@@ -312,9 +273,45 @@ 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(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(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(new SetTask(groupName, taskSS.str()));
+ scheduler->appendCommand(command);
+ setHasTask(true);
+ }
+ break;
+ }
default:
break;
}
addMeasure(L"currentTask", json::value(currentTask));
-}
+
+}
\ No newline at end of file
diff --git a/src/core/src/commands.cpp b/src/core/src/commands.cpp
index 662e62ab..87f33218 100644
--- a/src/core/src/commands.cpp
+++ b/src/core/src/commands.cpp
@@ -9,25 +9,20 @@ extern UnitsManager* unitsManager;
/* Move command */
wstring Move::getString(lua_State* L)
{
- Unit* unit = unitsManager->getUnit(ID);
- if (unit != nullptr)
- {
- std::wostringstream commandSS;
- commandSS.precision(10);
- commandSS << "Olympus.move, "
- << ID << ", "
- << destination.lat << ", "
- << destination.lng << ", "
- << altitude << ", "
- << speed << ", "
- << "\"" << unit->getCategory() << "\"" << ", "
- << taskOptions;
- return commandSS.str();
- }
- else
- {
- return L"";
- }
+
+ std::wostringstream commandSS;
+ commandSS.precision(10);
+ commandSS << "Olympus.move, "
+ << "\"" << groupName << "\"" << ", "
+ << destination.lat << ", "
+ << destination.lng << ", "
+ << altitude << ", "
+ << "\"" << altitudeType << "\"" << ", "
+ << speed << ", "
+ << "\"" << speedType << "\"" << ", "
+ << "\"" << category << "\"" << ", "
+ << taskOptions;
+ return commandSS.str();
}
/* Smoke command */
@@ -72,6 +67,7 @@ wstring SpawnAircraft::getString(lua_State* L)
<< "\"" << unitType << "\"" << ", "
<< location.lat << ", "
<< location.lng << ", "
+ << location.alt << ", "
<< optionsSS.str();
return commandSS.str();
}
@@ -103,7 +99,8 @@ wstring Delete::getString(lua_State* L)
std::wostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.delete, "
- << ID;
+ << ID << ", "
+ << (explosion ? "true" : "false");
return commandSS.str();
}
@@ -113,7 +110,7 @@ wstring SetTask::getString(lua_State* L)
std::wostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.setTask, "
- << ID << ", "
+ << "\"" << groupName << "\"" << ", "
<< task;
return commandSS.str();
@@ -125,7 +122,7 @@ wstring ResetTask::getString(lua_State* L)
std::wostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.resetTask, "
- << ID;
+ << "\"" << groupName << "\"";
return commandSS.str();
}
@@ -136,7 +133,7 @@ wstring SetCommand::getString(lua_State* L)
std::wostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.setCommand, "
- << ID << ", "
+ << "\"" << groupName << "\"" << ", "
<< command;
return commandSS.str();
@@ -150,14 +147,39 @@ wstring SetOption::getString(lua_State* L)
if (!isBoolean) {
commandSS << "Olympus.setOption, "
- << ID << ", "
+ << "\"" << groupName << "\"" << ", "
<< optionID << ", "
<< optionValue;
} else {
commandSS << "Olympus.setOption, "
- << ID << ", "
+ << "\"" << groupName << "\"" << ", "
<< optionID << ", "
<< (optionBool? "true": "false");
}
return commandSS.str();
+}
+
+/* Set onOff command */
+wstring SetOnOff::getString(lua_State* L)
+{
+ std::wostringstream commandSS;
+ commandSS.precision(10);
+
+ commandSS << "Olympus.setOnOff, "
+ << "\"" << groupName << "\"" << ", "
+ << (onOff ? "true" : "false");
+
+ return commandSS.str();
+}
+
+/* Explosion command */
+wstring Explosion::getString(lua_State* L)
+{
+ std::wostringstream commandSS;
+ commandSS.precision(10);
+ commandSS << "Olympus.explosion, "
+ << intensity << ", "
+ << location.lat << ", "
+ << location.lng;
+ return commandSS.str();
}
\ No newline at end of file
diff --git a/src/core/src/groundunit.cpp b/src/core/src/groundunit.cpp
index 545aefc5..c75ea2c0 100644
--- a/src/core/src/groundunit.cpp
+++ b/src/core/src/groundunit.cpp
@@ -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()));
+
+ double targetSpeed = 10;
setTargetSpeed(targetSpeed);
- setTargetAltitude(targetAltitude);
};
+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(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(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)
- {
-
- }
+ 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)
+{
+ Unit::setOnOff(newOnOff);
+ Command* command = dynamic_cast(new SetOnOff(groupName, onOff));
+ scheduler->appendCommand(command);
+}
+
+void GroundUnit::setFollowRoads(bool newFollowRoads)
+{
+ Unit::setFollowRoads(newFollowRoads);
+ resetActiveDestination(); /* Reset active destination to apply option*/
}
\ No newline at end of file
diff --git a/src/core/src/helicopter.cpp b/src/core/src/helicopter.cpp
index 7d2d1e20..f952dc4f 100644
--- a/src/core/src/helicopter.cpp
+++ b/src/core/src/helicopter.cpp
@@ -17,6 +17,9 @@ 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 = knotsToMs(100);
+ double targetAltitude = ftToM(5000);
setTargetSpeed(targetSpeed);
setTargetAltitude(targetAltitude);
};
@@ -29,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;
@@ -43,32 +46,19 @@ 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;
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();
-}
\ No newline at end of file
diff --git a/src/core/src/navyunit.cpp b/src/core/src/navyunit.cpp
index 25f835a6..9898b24d 100644
--- a/src/core/src/navyunit.cpp
+++ b/src/core/src/navyunit.cpp
@@ -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()));
+
+ double targetSpeed = 10;
setTargetSpeed(targetSpeed);
- setTargetAltitude(targetAltitude);
};
void NavyUnit::AIloop()
diff --git a/src/core/src/scheduler.cpp b/src/core/src/scheduler.cpp
index ad46db11..d6fc9f51 100644
--- a/src/core/src/scheduler.cpp
+++ b/src/core/src/scheduler.cpp
@@ -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);
+ 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")");
@@ -122,7 +118,7 @@ void Scheduler::handleRequest(wstring key, json::value value)
int ID = value[L"ID"].as_integer();
int targetID = value[L"targetID"].as_integer();
- Unit* unit = unitsManager->getUnit(ID);
+ Unit* unit = unitsManager->getGroupLeader(ID);
Unit* target = unitsManager->getUnit(targetID);
wstring unitName;
@@ -150,7 +146,7 @@ void Scheduler::handleRequest(wstring key, json::value value)
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,31 +170,45 @@ 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);
+ 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);
+ 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);
+ Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
unit->setTargetSpeed(value[L"speed"].as_double());
}
+ else if (key.compare(L"setSpeedType") == 0)
+ {
+ int ID = value[L"ID"].as_integer();
+ Unit* unit = unitsManager->getGroupLeader(ID);
+ if (unit != nullptr)
+ unit->setTargetSpeedType(value[L"speedType"].as_string());
+ }
else if (key.compare(L"setAltitude") == 0)
{
int ID = value[L"ID"].as_integer();
- Unit* unit = unitsManager->getUnit(ID);
+ Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
unit->setTargetAltitude(value[L"altitude"].as_double());
}
+ else if (key.compare(L"setAltitudeType") == 0)
+ {
+ int ID = value[L"ID"].as_integer();
+ Unit* unit = unitsManager->getGroupLeader(ID);
+ if (unit != nullptr)
+ unit->setTargetAltitudeType(value[L"altitudeType"].as_string());
+ }
else if (key.compare(L"cloneUnit") == 0)
{
int ID = value[L"ID"].as_integer();
@@ -211,28 +221,28 @@ 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);
+ 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);
+ 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);
+ 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);
+ 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 +251,19 @@ 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);
+ 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);
+ Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr)
{
/* Advanced tasking */
@@ -286,6 +297,69 @@ void Scheduler::handleRequest(wstring key, json::value value)
unit->resetActiveDestination();
}
}
+ else if (key.compare(L"setFollowRoads") == 0)
+ {
+ int ID = value[L"ID"].as_integer();
+ 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();
+ 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(new Explosion(intensity, loc));
+ }
+ else if (key.compare(L"bombPoint") == 0)
+ {
+ int ID = value[L"ID"].as_integer();
+ 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();
+ 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();
+ 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();
+ 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);
diff --git a/src/core/src/unit.cpp b/src/core/src/unit.cpp
index b32dc785..b0a86a73 100644
--- a/src/core/src/unit.cpp
+++ b/src/core/src/unit.cpp
@@ -116,8 +116,21 @@ void Unit::updateExportData(json::value json)
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)
+ // TODO at the moment groups will stop moving correctly if the leader dies
+ const bool isUnitControlledByOlympus = getAI();
+ 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::updateMissionData(json::value json)
@@ -132,10 +145,14 @@ void Unit::updateMissionData(json::value json)
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"})
@@ -146,7 +163,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" })
@@ -177,25 +194,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"targetSpeed", L"targetAltitude", L"targetSpeedType", L"targetAltitudeType", 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 +342,10 @@ void Unit::resetActiveDestination()
void Unit::resetTask()
{
- Command* command = dynamic_cast(new ResetTask(ID));
+ Command* command = dynamic_cast(new ResetTask(groupName));
scheduler->appendCommand(command);
+ setHasTask(false);
+ resetTaskFailedCounter();
}
void Unit::setFormationOffset(Offset newFormationOffset)
@@ -352,7 +374,7 @@ void Unit::setROE(wstring newROE) {
else
return;
- Command* command = dynamic_cast(new SetOption(ID, SetCommandType::ROE, ROEEnum));
+ Command* command = dynamic_cast(new SetOption(groupName, SetCommandType::ROE, ROEEnum));
scheduler->appendCommand(command);
}
}
@@ -377,7 +399,7 @@ void Unit::setReactionToThreat(wstring newReactionToThreat) {
else
return;
- Command* command = dynamic_cast(new SetOption(ID, SetCommandType::REACTION_ON_THREAT, reactionToThreatEnum));
+ Command* command = dynamic_cast(new SetOption(groupName, SetCommandType::REACTION_ON_THREAT, reactionToThreatEnum));
scheduler->appendCommand(command);
}
}
@@ -420,13 +442,13 @@ void Unit::setEmissionsCountermeasures(wstring newEmissionsCountermeasures) {
Command* command;
- command = dynamic_cast(new SetOption(ID, SetCommandType::RADAR_USING, radarEnum));
+ command = dynamic_cast(new SetOption(groupName, SetCommandType::RADAR_USING, radarEnum));
scheduler->appendCommand(command);
- command = dynamic_cast(new SetOption(ID, SetCommandType::FLARE_USING, flareEnum));
+ command = dynamic_cast(new SetOption(groupName, SetCommandType::FLARE_USING, flareEnum));
scheduler->appendCommand(command);
- command = dynamic_cast(new SetOption(ID, SetCommandType::ECM_USING, ECMEnum));
+ command = dynamic_cast(new SetOption(groupName, SetCommandType::ECM_USING, ECMEnum));
scheduler->appendCommand(command);
}
}
@@ -473,7 +495,7 @@ void Unit::setTACAN(Options::TACAN newTACAN) {
<< "frequency = " << TACANChannelToFrequency(TACAN.channel, TACAN.XY) << ","
<< "}"
<< "}";
- Command* command = dynamic_cast(new SetCommand(ID, commandSS.str()));
+ Command* command = dynamic_cast(new SetCommand(groupName, commandSS.str()));
scheduler->appendCommand(command);
}
else {
@@ -483,7 +505,7 @@ void Unit::setTACAN(Options::TACAN newTACAN) {
<< "params = {"
<< "}"
<< "}";
- Command* command = dynamic_cast(new SetCommand(ID, commandSS.str()));
+ Command* command = dynamic_cast(new SetCommand(groupName, commandSS.str()));
scheduler->appendCommand(command);
}
}
@@ -511,7 +533,7 @@ void Unit::setRadio(Options::Radio newRadio) {
<< "frequency = " << radio.frequency << ","
<< "}"
<< "}";
- command = dynamic_cast(new SetCommand(ID, commandSS.str()));
+ command = dynamic_cast(new SetCommand(groupName, commandSS.str()));
scheduler->appendCommand(command);
// Clear the stringstream
@@ -524,7 +546,7 @@ void Unit::setRadio(Options::Radio newRadio) {
<< "number = " << radio.callsignNumber << ","
<< "}"
<< "}";
- command = dynamic_cast(new SetCommand(ID, commandSS.str()));
+ command = dynamic_cast(new SetCommand(groupName, commandSS.str()));
scheduler->appendCommand(command);
}
}
@@ -563,16 +585,131 @@ void Unit::setGeneralSettings(Options::GeneralSettings newGeneralSettings) {
generalSettings = newGeneralSettings;
Command* command;
- command = dynamic_cast(new SetOption(ID, SetCommandType::PROHIBIT_AA, generalSettings.prohibitAA));
+ command = dynamic_cast(new SetOption(groupName, SetCommandType::PROHIBIT_AA, generalSettings.prohibitAA));
scheduler->appendCommand(command);
- command = dynamic_cast(new SetOption(ID, SetCommandType::PROHIBIT_AG, generalSettings.prohibitAG));
+ command = dynamic_cast(new SetOption(groupName, SetCommandType::PROHIBIT_AG, generalSettings.prohibitAG));
scheduler->appendCommand(command);
- command = dynamic_cast(new SetOption(ID, SetCommandType::PROHIBIT_JETT, generalSettings.prohibitJettison));
+ command = dynamic_cast(new SetOption(groupName, SetCommandType::PROHIBIT_JETT, generalSettings.prohibitJettison));
scheduler->appendCommand(command);
- command = dynamic_cast(new SetOption(ID, SetCommandType::PROHIBIT_AB, generalSettings.prohibitAfterburner));
+ command = dynamic_cast(new SetOption(groupName, SetCommandType::PROHIBIT_AB, generalSettings.prohibitAfterburner));
scheduler->appendCommand(command);
- command = dynamic_cast(new SetOption(ID, SetCommandType::ENGAGE_AIR_WEAPONS, !generalSettings.prohibitAirWpn));
+ command = dynamic_cast(new SetOption(groupName, SetCommandType::ENGAGE_AIR_WEAPONS, !generalSettings.prohibitAirWpn));
scheduler->appendCommand(command);
}
}
+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(groupName, activeDestination, getTargetSpeed(), getTargetSpeedType(), getTargetAltitude(), getTargetAltitudeType(), 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));
+}
\ No newline at end of file
diff --git a/src/core/src/unitsmanager.cpp b/src/core/src/unitsmanager.cpp
index 00b1b8cd..b5ec63be 100644
--- a/src/core/src/unitsmanager.cpp
+++ b/src/core/src/unitsmanager.cpp
@@ -32,6 +32,67 @@ Unit* UnitsManager::getUnit(int ID)
}
}
+bool UnitsManager::isUnitInGroup(Unit* unit)
+{
+ if (unit != nullptr) {
+ wstring groupName = unit->getGroupName();
+ for (auto const& p : units)
+ {
+ if (p.second->getGroupName().compare(groupName) == 0 && p.second != unit)
+ return true;
+ }
+ }
+ return false;
+}
+
+bool UnitsManager::isUnitGroupLeader(Unit* unit)
+{
+ if (unit != nullptr)
+ return unit == getGroupLeader(unit);
+ else
+ return false;
+}
+
+// The group leader is the unit with the lowest ID that is part of the group. This is different from DCS's concept of leader, which will change if the leader is destroyed
+Unit* UnitsManager::getGroupLeader(Unit* unit)
+{
+ if (unit != nullptr) {
+ wstring groupName = unit->getGroupName();
+
+ /* Get the unit IDs in order */
+ std::vector keys;
+ for (auto const& p : units)
+ keys.push_back(p.first);
+ sort(keys.begin(), keys.end());
+
+ /* Find the first unit that has the same groupName */
+ for (auto const& tempID : keys)
+ {
+ Unit* tempUnit = getUnit(tempID);
+ if (tempUnit != nullptr && tempUnit->getGroupName().compare(groupName) == 0)
+ return tempUnit;
+ }
+ }
+ return nullptr;
+}
+
+vector UnitsManager::getGroupMembers(wstring groupName)
+{
+ vector members;
+ for (auto const& p : units)
+ {
+ if (p.second->getGroupName().compare(groupName) == 0)
+ members.push_back(p.second);
+ }
+ return members;
+}
+
+Unit* UnitsManager::getGroupLeader(int ID)
+{
+ Unit* unit = getUnit(ID);
+ return getGroupLeader(unit);
+}
+
void UnitsManager::updateExportData(lua_State* L)
{
map unitJSONs = getAllUnits(L);
@@ -107,11 +168,11 @@ void UnitsManager::getData(json::value& answer, long long time)
answer[L"units"] = unitsJson;
}
-void UnitsManager::deleteUnit(int ID)
+void UnitsManager::deleteUnit(int ID, bool explosion)
{
if (getUnit(ID) != nullptr)
{
- Command* command = dynamic_cast(new Delete(ID));
+ Command* command = dynamic_cast(new Delete(ID, explosion));
scheduler->appendCommand(command);
}
}
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