diff --git a/client/public/stylesheets/other/contextmenus.css b/client/public/stylesheets/other/contextmenus.css
index 877dac63..fe9e5837 100644
--- a/client/public/stylesheets/other/contextmenus.css
+++ b/client/public/stylesheets/other/contextmenus.css
@@ -369,6 +369,10 @@
content: url("/resources/theme/images/icons/crosshairs-solid.svg");
}
+#simulate-fire-fight::before {
+ content: url("/resources/theme/images/icons/crosshairs-solid.svg");
+}
+
#follow::before {
content: url("/resources/theme/images/icons/follow.svg");
}
diff --git a/client/src/constants/constants.ts b/client/src/constants/constants.ts
index d1124434..6e6a35fa 100644
--- a/client/src/constants/constants.ts
+++ b/client/src/constants/constants.ts
@@ -20,7 +20,7 @@ export const IRST = 8;
export const RWR = 16;
export const DLINK = 32;
-export const states: string[] = ["none", "idle", "reach-destination", "attack", "follow", "land", "refuel", "AWACS", "tanker", "bomb-point", "carpet-bomb", "bomb-building", "fire-at-area"];
+export const states: string[] = ["none", "idle", "reach-destination", "attack", "follow", "land", "refuel", "AWACS", "tanker", "bomb-point", "carpet-bomb", "bomb-building", "fire-at-area", "simulate-fire-fight"];
export const ROEs: string[] = ["free", "designated", "", "return", "hold"];
export const reactionsToThreat: string[] = ["none", "manoeuvre", "passive", "evade"];
export const emissionsCountermeasures: string[] = ["silent", "attack", "defend", "free"];
diff --git a/client/src/map/map.ts b/client/src/map/map.ts
index 93f86408..c2575192 100644
--- a/client/src/map/map.ts
+++ b/client/src/map/map.ts
@@ -579,8 +579,10 @@ export class Map extends L.Map {
}
}
else if (selectedUnitTypes.length === 1 && ["GroundUnit", "NavyUnit"].includes(selectedUnitTypes[0])) {
- if (selectedUnits.every((unit: Unit) => { return ["Gun Artillery", "Rocket Artillery", "Infantry", "IFV", "Tank", "Cruiser", "Destroyer", "Frigate"].includes(unit.getType()) }))
+ if (selectedUnits.every((unit: Unit) => { return ["Gun Artillery", "Rocket Artillery", "Infantry", "IFV", "Tank", "Cruiser", "Destroyer", "Frigate"].includes(unit.getType()) })) {
options["fire-at-area"] = { text: "Fire at area", tooltip: "Fire at a large area" };
+ options["simulate-fire-fight"] = { text: "Simulate fire fight", tooltip: "Simulate a fire fight by shooting randomly in a certain large area" };
+ }
else
getInfoPopup().setText(`Selected units can not perform point actions.`);
}
@@ -604,6 +606,10 @@ export class Map extends L.Map {
getUnitsManager().getSelectedUnits().length > 0 ? this.setState(MOVE_UNIT) : this.setState(IDLE);
getUnitsManager().selectedUnitsFireAtArea(this.getMouseCoordinates());
}
+ else if (option === "simulate-fire-fight") {
+ getUnitsManager().getSelectedUnits().length > 0 ? this.setState(MOVE_UNIT) : this.setState(IDLE);
+ getUnitsManager().selectedUnitsSimulateFireFight(this.getMouseCoordinates());
+ }
});
}
}, 150);
diff --git a/client/src/server/server.ts b/client/src/server/server.ts
index 05695c86..9938d026 100644
--- a/client/src/server/server.ts
+++ b/client/src/server/server.ts
@@ -319,6 +319,12 @@ export function fireAtArea(ID: number, latlng: LatLng, callback: CallableFunctio
POST(data, callback);
}
+export function simulateFireFight(ID: number, latlng: LatLng, callback: CallableFunction = () => {}) {
+ var command = { "ID": ID, "location": latlng }
+ var data = { "simulateFireFight": command }
+ POST(data, callback);
+}
+
export function setAdvacedOptions(ID: number, isTanker: boolean, isAWACS: boolean, TACAN: TACAN, radio: Radio, generalSettings: GeneralSettings, callback: CallableFunction = () => {}) {
var command = {
"ID": ID,
diff --git a/client/src/unit/unit.ts b/client/src/unit/unit.ts
index 540ee7b7..e077187e 100644
--- a/client/src/unit/unit.ts
+++ b/client/src/unit/unit.ts
@@ -1,7 +1,7 @@
import { Marker, LatLng, Polyline, Icon, DivIcon, CircleMarker, Map, Point } from 'leaflet';
import { getMap, getMissionHandler, getUnitsManager, getWeaponsManager } from '..';
import { enumToCoalition, enumToEmissioNCountermeasure, getMarkerCategoryByName, enumToROE, enumToReactionToThreat, enumToState, getUnitDatabaseByCategory, mToFt, msToKnots, rad2deg, bearing, deg2rad, ftToM } from '../other/utils';
-import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, landAt, setAltitude, setReactionToThreat, setROE, setSpeed, refuel, setAdvacedOptions, followUnit, setEmissionsCountermeasures, setSpeedType, setAltitudeType, setOnOff, setFollowRoads, bombPoint, carpetBomb, bombBuilding, fireAtArea } from '../server/server';
+import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, landAt, setAltitude, setReactionToThreat, setROE, setSpeed, refuel, setAdvacedOptions, followUnit, setEmissionsCountermeasures, setSpeedType, setAltitudeType, setOnOff, setFollowRoads, bombPoint, carpetBomb, bombBuilding, fireAtArea, simulateFireFight } from '../server/server';
import { CustomMarker } from '../map/markers/custommarker';
import { SVGInjector } from '@tanem/svg-injector';
import { UnitDatabase } from './databases/unitdatabase';
@@ -717,6 +717,10 @@ export class Unit extends CustomMarker {
fireAtArea(this.ID, latlng);
}
+ simulateFireFight(latlng: LatLng) {
+ simulateFireFight(this.ID, latlng);
+ }
+
/***********************************************/
onAdd(map: Map): this {
super.onAdd(map);
diff --git a/client/src/unit/unitsmanager.ts b/client/src/unit/unitsmanager.ts
index cf1808a3..ba877ea3 100644
--- a/client/src/unit/unitsmanager.ts
+++ b/client/src/unit/unitsmanager.ts
@@ -605,6 +605,18 @@ export class UnitsManager {
this.#showActionMessage(selectedUnits, `unit bombing point`);
}
+ /** Instruct the selected units to simulate a fire fight at specific coordinates
+ *
+ * @param latlng Location to fire at
+ */
+ selectedUnitsSimulateFireFight(latlng: LatLng) {
+ var selectedUnits = this.getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true });
+ for (let idx in selectedUnits) {
+ selectedUnits[idx].simulateFireFight(latlng);
+ }
+ this.#showActionMessage(selectedUnits, `unit simulating fire fight`);
+ }
+
/*********************** Control operations on selected units ************************/
/** See getUnitsCategories for more info
*
diff --git a/scripts/OlympusCommand.lua b/scripts/OlympusCommand.lua
index 6518d6ca..d38f380e 100644
--- a/scripts/OlympusCommand.lua
+++ b/scripts/OlympusCommand.lua
@@ -1,6 +1,6 @@
local version = "v0.4.4-alpha"
-local debug = false -- True enables debug printing using DCS messages
+local debug = true -- True enables debug printing using DCS messages
-- .dll related variables
Olympus.OlympusDLL = nil
@@ -229,13 +229,24 @@ function Olympus.buildTask(groupName, options)
-- Fire at a specific point
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']
- }
- }
+ if options['alt'] then
+ task = {
+ id = 'FireAtPoint',
+ params = {
+ point = {x = point.x, y = point.z},
+ radius = options['radius'],
+ altitude = options['alt']
+ }
+ }
+ else
+ task = {
+ id = 'FireAtPoint',
+ params = {
+ point = {x = point.x, y = point.z},
+ radius = options['radius']
+ }
+ }
+ end
end
end
return task
diff --git a/scripts/python/generateGunData.py b/scripts/python/generateGunData.py
new file mode 100644
index 00000000..858cc28e
--- /dev/null
+++ b/scripts/python/generateGunData.py
@@ -0,0 +1,21 @@
+import sys
+import json
+import inspect
+import difflib
+from slpp import slpp as lua
+
+SEARCH_FOLDER = "D:\\Eagle Dynamics\\DCS World OpenBeta"
+
+sys.path.append("..\\..\\..\\dcs-master\\dcs-master")
+
+from dcs.vehicles import *
+
+with open("gundata.h", "w") as f:
+ for unit in vehicle_map.values():
+ if unit in Artillery.__dict__.values() or unit in Armor.__dict__.values() or unit in Infantry.__dict__.values():
+ f.write('{"' + unit.id + '", {0.9, 860}}, \n')
+
+# Done!
+print("Done!")
+
+
\ No newline at end of file
diff --git a/scripts/python/gundata.h b/scripts/python/gundata.h
new file mode 100644
index 00000000..d28a26e5
--- /dev/null
+++ b/scripts/python/gundata.h
@@ -0,0 +1,109 @@
+{"2B11 mortar", {0.9, 860}},
+{"SAU Gvozdika", {0.9, 860}},
+{"SAU Msta", {0.9, 860}},
+{"SAU Akatsia", {0.9, 860}},
+{"SAU 2-C9", {0.9, 860}},
+{"M-109", {0.9, 860}},
+{"SpGH_Dana", {0.9, 860}},
+{"AAV7", {0.9, 860}},
+{"BMD-1", {0.9, 860}},
+{"BMP-1", {0.9, 860}},
+{"BMP-2", {0.9, 860}},
+{"BMP-3", {0.9, 860}},
+{"BRDM-2", {0.9, 860}},
+{"BTR_D", {0.9, 860}},
+{"Cobra", {0.9, 860}},
+{"LAV-25", {0.9, 860}},
+{"M1043 HMMWV Armament", {0.9, 860}},
+{"M1045 HMMWV TOW", {0.9, 860}},
+{"M1126 Stryker ICV", {0.9, 860}},
+{"M-113", {0.9, 860}},
+{"M1134 Stryker ATGM", {0.9, 860}},
+{"M-2 Bradley", {0.9, 860}},
+{"MCV-80", {0.9, 860}},
+{"MTLB", {0.9, 860}},
+{"Marder", {0.9, 860}},
+{"TPZ", {0.9, 860}},
+{"Grad_FDDM", {0.9, 860}},
+{"Paratrooper RPG-16", {0.9, 860}},
+{"Paratrooper AKS-74", {0.9, 860}},
+{"Infantry AK Ins", {0.9, 860}},
+{"Soldier AK", {0.9, 860}},
+{"Infantry AK", {0.9, 860}},
+{"Soldier M249", {0.9, 860}},
+{"Soldier M4", {0.9, 860}},
+{"Soldier M4 GRG", {0.9, 860}},
+{"Soldier RPG", {0.9, 860}},
+{"MLRS FDDM", {0.9, 860}},
+{"Infantry AK ver2", {0.9, 860}},
+{"Infantry AK ver3", {0.9, 860}},
+{"Grad-URAL", {0.9, 860}},
+{"Uragan_BM-27", {0.9, 860}},
+{"Smerch", {0.9, 860}},
+{"Smerch_HE", {0.9, 860}},
+{"MLRS", {0.9, 860}},
+{"Challenger2", {0.9, 860}},
+{"Leclerc", {0.9, 860}},
+{"M-60", {0.9, 860}},
+{"M1128 Stryker MGS", {0.9, 860}},
+{"M-1 Abrams", {0.9, 860}},
+{"T-55", {0.9, 860}},
+{"T-72B", {0.9, 860}},
+{"T-80UD", {0.9, 860}},
+{"T-90", {0.9, 860}},
+{"Leopard1A3", {0.9, 860}},
+{"Merkava_Mk4", {0.9, 860}},
+{"JTAC", {0.9, 860}},
+{"Infantry Animated", {0.9, 860}},
+{"HL_DSHK", {0.9, 860}},
+{"HL_KORD", {0.9, 860}},
+{"tt_DSHK", {0.9, 860}},
+{"tt_KORD", {0.9, 860}},
+{"HL_B8M1", {0.9, 860}},
+{"tt_B8M1", {0.9, 860}},
+{"M4_Sherman", {0.9, 860}},
+{"M2A1_halftrack", {0.9, 860}},
+{"BTR-80", {0.9, 860}},
+{"T-72B3", {0.9, 860}},
+{"PT_76", {0.9, 860}},
+{"BTR-82A", {0.9, 860}},
+{"Chieftain_mk3", {0.9, 860}},
+{"Pz_IV_H", {0.9, 860}},
+{"Leopard-2A5", {0.9, 860}},
+{"Leopard-2", {0.9, 860}},
+{"leopard-2A4", {0.9, 860}},
+{"leopard-2A4_trs", {0.9, 860}},
+{"Sd_Kfz_251", {0.9, 860}},
+{"T155_Firtina", {0.9, 860}},
+{"VAB_Mephisto", {0.9, 860}},
+{"ZTZ96B", {0.9, 860}},
+{"ZBD04A", {0.9, 860}},
+{"PLZ05", {0.9, 860}},
+{"TYPE-59", {0.9, 860}},
+{"Tiger_I", {0.9, 860}},
+{"Tiger_II_H", {0.9, 860}},
+{"Pz_V_Panther_G", {0.9, 860}},
+{"Jagdpanther_G1", {0.9, 860}},
+{"JagdPz_IV", {0.9, 860}},
+{"Stug_IV", {0.9, 860}},
+{"SturmPzIV", {0.9, 860}},
+{"Wespe124", {0.9, 860}},
+{"Sd_Kfz_234_2_Puma", {0.9, 860}},
+{"soldier_mauser98", {0.9, 860}},
+{"Stug_III", {0.9, 860}},
+{"Elefant_SdKfz_184", {0.9, 860}},
+{"Pak40", {0.9, 860}},
+{"LeFH_18-40-105", {0.9, 860}},
+{"Cromwell_IV", {0.9, 860}},
+{"M4A4_Sherman_FF", {0.9, 860}},
+{"soldier_wwii_br_01", {0.9, 860}},
+{"Centaur_IV", {0.9, 860}},
+{"Churchill_VII", {0.9, 860}},
+{"Daimler_AC", {0.9, 860}},
+{"Tetrarch", {0.9, 860}},
+{"M12_GMC", {0.9, 860}},
+{"soldier_wwii_us", {0.9, 860}},
+{"M10_GMC", {0.9, 860}},
+{"M8_Greyhound", {0.9, 860}},
+{"M2A1-105", {0.9, 860}},
+{"M4_Tractor", {0.9, 860}},
diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj
index 7c46020d..da1d2d5e 100644
--- a/src/core/core.vcxproj
+++ b/src/core/core.vcxproj
@@ -37,6 +37,7 @@
+
diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters
index 56fade36..cfb10c59 100644
--- a/src/core/core.vcxproj.filters
+++ b/src/core/core.vcxproj.filters
@@ -54,6 +54,9 @@
Header Files
+
+ Header Files
+
diff --git a/src/core/include/commands.h b/src/core/include/commands.h
index 58279826..6bf3da9d 100644
--- a/src/core/include/commands.h
+++ b/src/core/include/commands.h
@@ -95,21 +95,26 @@ namespace ECMUse {
class Command
{
public:
+ Command(function callback) : callback(callback) {};
unsigned int getPriority() { return priority; }
virtual string getString() = 0;
virtual unsigned int getLoad() = 0;
const string getHash() { return hash; }
+ void executeCallback() { callback(); }
protected:
unsigned int priority = CommandPriority::LOW;
const string hash = random_string(16);
+ function callback;
};
/* Simple low priority move command (from user click) */
class Move : public Command
{
public:
- Move(string groupName, Coords destination, double speed, string speedType, double altitude, string altitudeType, string taskOptions, string category):
+ Move(string groupName, Coords destination, double speed, string speedType, double altitude,
+ string altitudeType, string taskOptions, string category, function callback = []() {}) :
+ Command(callback),
groupName(groupName),
destination(destination),
speed(speed),
@@ -139,7 +144,8 @@ private:
class Smoke : public Command
{
public:
- Smoke(string color, Coords location) :
+ Smoke(string color, Coords location, function callback = [](){}) :
+ Command(callback),
color(color),
location(location)
{
@@ -157,7 +163,8 @@ private:
class SpawnGroundUnits : public Command
{
public:
- SpawnGroundUnits(string coalition, vector spawnOptions, string country, bool immediate) :
+ SpawnGroundUnits(string coalition, vector spawnOptions, string country, bool immediate, function callback = [](){}) :
+ Command(callback),
coalition(coalition),
spawnOptions(spawnOptions),
country(country),
@@ -179,7 +186,8 @@ private:
class SpawnNavyUnits : public Command
{
public:
- SpawnNavyUnits(string coalition, vector spawnOptions, string country, bool immediate) :
+ SpawnNavyUnits(string coalition, vector spawnOptions, string country, bool immediate, function callback = [](){}) :
+ Command(callback),
coalition(coalition),
spawnOptions(spawnOptions),
country(country),
@@ -201,7 +209,8 @@ private:
class SpawnAircrafts : public Command
{
public:
- SpawnAircrafts(string coalition, vector spawnOptions, string airbaseName, string country, bool immediate) :
+ SpawnAircrafts(string coalition, vector spawnOptions, string airbaseName, string country, bool immediate, function callback = [](){}) :
+ Command(callback),
coalition(coalition),
spawnOptions(spawnOptions),
airbaseName(airbaseName),
@@ -221,12 +230,12 @@ private:
const bool immediate;
};
-
/* Spawn helicopter command */
class SpawnHelicopters : public Command
{
public:
- SpawnHelicopters(string coalition, vector spawnOptions, string airbaseName, string country, bool immediate) :
+ SpawnHelicopters(string coalition, vector spawnOptions, string airbaseName, string country, bool immediate, function callback = [](){}) :
+ Command(callback),
coalition(coalition),
spawnOptions(spawnOptions),
airbaseName(airbaseName),
@@ -250,7 +259,8 @@ private:
class Clone : public Command
{
public:
- Clone(vector cloneOptions, bool deleteOriginal) :
+ Clone(vector cloneOptions, bool deleteOriginal, function callback = [](){}) :
+ Command(callback),
cloneOptions(cloneOptions),
deleteOriginal(deleteOriginal)
{
@@ -268,7 +278,8 @@ private:
class Delete : public Command
{
public:
- Delete(unsigned int ID, bool explosion, bool immediate ) :
+ Delete(unsigned int ID, bool explosion, bool immediate, function callback = [](){}) :
+ Command(callback),
ID(ID),
explosion(explosion),
immediate(immediate)
@@ -289,7 +300,8 @@ private:
class SetTask : public Command
{
public:
- SetTask(string groupName, string task) :
+ SetTask(string groupName, string task, function callback = [](){}) :
+ Command(callback),
groupName(groupName),
task(task)
{
@@ -307,7 +319,8 @@ private:
class ResetTask : public Command
{
public:
- ResetTask(string groupName) :
+ ResetTask(string groupName, function callback = [](){}) :
+ Command(callback),
groupName(groupName)
{
priority = CommandPriority::HIGH;
@@ -323,7 +336,8 @@ private:
class SetCommand : public Command
{
public:
- SetCommand(string groupName, string command) :
+ SetCommand(string groupName, string command, function callback = [](){}) :
+ Command(callback),
groupName(groupName),
command(command)
{
@@ -341,7 +355,8 @@ private:
class SetOption : public Command
{
public:
- SetOption(string groupName, unsigned int optionID, unsigned int optionValue) :
+ SetOption(string groupName, unsigned int optionID, unsigned int optionValue, function callback = [](){}) :
+ Command(callback),
groupName(groupName),
optionID(optionID),
optionValue(optionValue),
@@ -351,7 +366,8 @@ public:
priority = CommandPriority::HIGH;
};
- SetOption(string groupName, unsigned int optionID, bool optionBool) :
+ SetOption(string groupName, unsigned int optionID, bool optionBool, function callback = [](){}) :
+ Command(callback),
groupName(groupName),
optionID(optionID),
optionValue(0),
@@ -375,7 +391,8 @@ private:
class SetOnOff : public Command
{
public:
- SetOnOff(string groupName, bool onOff) :
+ SetOnOff(string groupName, bool onOff, function callback = [](){}) :
+ Command(callback),
groupName(groupName),
onOff(onOff)
{
@@ -393,7 +410,8 @@ private:
class Explosion : public Command
{
public:
- Explosion(unsigned int intensity, Coords location) :
+ Explosion(unsigned int intensity, Coords location, function callback = [](){}) :
+ Command(callback),
location(location),
intensity(intensity)
{
diff --git a/src/core/include/datatypes.h b/src/core/include/datatypes.h
index f3859456..f8be70fa 100644
--- a/src/core/include/datatypes.h
+++ b/src/core/include/datatypes.h
@@ -64,7 +64,8 @@ namespace State
BOMB_POINT,
CARPET_BOMB,
BOMB_BUILDING,
- FIRE_AT_AREA
+ FIRE_AT_AREA,
+ SIMULATE_FIRE_FIGHT
};
};
@@ -125,4 +126,9 @@ struct SpawnOptions {
struct CloneOptions {
unsigned int ID;
Coords location;
+};
+
+struct GunDataItem {
+ double barrelHeight;
+ double muzzleVelocity;
};
\ No newline at end of file
diff --git a/src/core/include/gundata.h b/src/core/include/gundata.h
new file mode 100644
index 00000000..b463f423
--- /dev/null
+++ b/src/core/include/gundata.h
@@ -0,0 +1,116 @@
+#pragma once
+
+#include "framework.h"
+#include "datatypes.h"
+
+map gunData = {
+{"2B11 mortar", {0.9, 860}},
+{"SAU Gvozdika", {0.9, 860}},
+{"SAU Msta", {0.9, 860}},
+{"SAU Akatsia", {0.9, 860}},
+{"SAU 2-C9", {0.9, 860}},
+{"M-109", {0.9, 860}},
+{"SpGH_Dana", {0.9, 860}},
+{"AAV7", {0.9, 860}},
+{"BMD-1", {0.9, 860}},
+{"BMP-1", {0.9, 860}},
+{"BMP-2", {0.9, 860}},
+{"BMP-3", {0.9, 860}},
+{"BRDM-2", {0.9, 860}},
+{"BTR_D", {0.9, 860}},
+{"Cobra", {0.9, 860}},
+{"LAV-25", {0.9, 860}},
+{"M1043 HMMWV Armament", {0.9, 860}},
+{"M1045 HMMWV TOW", {0.9, 860}},
+{"M1126 Stryker ICV", {0.9, 860}},
+{"M-113", {0.9, 860}},
+{"M1134 Stryker ATGM", {0.9, 860}},
+{"M-2 Bradley", {0.9, 860}},
+{"MCV-80", {0.9, 860}},
+{"MTLB", {0.9, 860}},
+{"Marder", {0.9, 860}},
+{"TPZ", {0.9, 860}},
+{"Grad_FDDM", {0.9, 860}},
+{"Paratrooper RPG-16", {0.9, 860}},
+{"Paratrooper AKS-74", {0.9, 860}},
+{"Infantry AK Ins", {0.9, 860}},
+{"Soldier AK", {0.4, 860}},
+{"Infantry AK", {0.9, 860}},
+{"Soldier M249", {0.9, 860}},
+{"Soldier M4", {0.9, 860}},
+{"Soldier M4 GRG", {0.9, 860}},
+{"Soldier RPG", {0.9, 860}},
+{"MLRS FDDM", {0.9, 860}},
+{"Infantry AK ver2", {0.9, 860}},
+{"Infantry AK ver3", {0.9, 860}},
+{"Grad-URAL", {0.9, 860}},
+{"Uragan_BM-27", {0.9, 860}},
+{"Smerch", {0.9, 860}},
+{"Smerch_HE", {0.9, 860}},
+{"MLRS", {0.9, 860}},
+{"Challenger2", {0.9, 860}},
+{"Leclerc", {0.9, 860}},
+{"M-60", {0.9, 860}},
+{"M1128 Stryker MGS", {0.9, 860}},
+{"M-1 Abrams", {0.9, 860}},
+{"T-55", {0.9, 860}},
+{"T-72B", {0.9, 860}},
+{"T-80UD", {0.9, 860}},
+{"T-90", {0.9, 860}},
+{"Leopard1A3", {0.9, 860}},
+{"Merkava_Mk4", {0.9, 860}},
+{"JTAC", {0.9, 860}},
+{"Infantry Animated", {0.9, 860}},
+{"HL_DSHK", {0.9, 860}},
+{"HL_KORD", {0.9, 860}},
+{"tt_DSHK", {0.9, 860}},
+{"tt_KORD", {0.9, 860}},
+{"HL_B8M1", {0.9, 860}},
+{"tt_B8M1", {0.9, 860}},
+{"M4_Sherman", {0.9, 860}},
+{"M2A1_halftrack", {0.9, 860}},
+{"BTR-80", {0.9, 860}},
+{"T-72B3", {0.9, 860}},
+{"PT_76", {0.9, 860}},
+{"BTR-82A", {0.9, 860}},
+{"Chieftain_mk3", {0.9, 860}},
+{"Pz_IV_H", {0.9, 860}},
+{"Leopard-2A5", {0.9, 860}},
+{"Leopard-2", {0.9, 860}},
+{"leopard-2A4", {0.9, 860}},
+{"leopard-2A4_trs", {0.9, 860}},
+{"Sd_Kfz_251", {0.9, 860}},
+{"T155_Firtina", {0.9, 860}},
+{"VAB_Mephisto", {0.9, 860}},
+{"ZTZ96B", {0.9, 860}},
+{"ZBD04A", {0.9, 860}},
+{"PLZ05", {0.9, 860}},
+{"TYPE-59", {0.9, 860}},
+{"Tiger_I", {0.9, 860}},
+{"Tiger_II_H", {0.9, 860}},
+{"Pz_V_Panther_G", {0.9, 860}},
+{"Jagdpanther_G1", {0.9, 860}},
+{"JagdPz_IV", {0.9, 860}},
+{"Stug_IV", {0.9, 860}},
+{"SturmPzIV", {0.9, 860}},
+{"Wespe124", {0.9, 860}},
+{"Sd_Kfz_234_2_Puma", {0.9, 860}},
+{"soldier_mauser98", {0.9, 860}},
+{"Stug_III", {0.9, 860}},
+{"Elefant_SdKfz_184", {0.9, 860}},
+{"Pak40", {0.9, 860}},
+{"LeFH_18-40-105", {0.9, 860}},
+{"Cromwell_IV", {0.9, 860}},
+{"M4A4_Sherman_FF", {0.9, 860}},
+{"soldier_wwii_br_01", {0.9, 860}},
+{"Centaur_IV", {0.9, 860}},
+{"Churchill_VII", {0.9, 860}},
+{"Daimler_AC", {0.9, 860}},
+{"Tetrarch", {0.9, 860}},
+{"M12_GMC", {0.9, 860}},
+{"soldier_wwii_us", {0.9, 860}},
+{"M10_GMC", {0.9, 860}},
+{"M8_Greyhound", {0.9, 860}},
+{"M2A1-105", {0.9, 860}},
+{"M4_Tractor", {0.9, 860}},
+};
\ No newline at end of file
diff --git a/src/core/include/unit.h b/src/core/include/unit.h
index b0fdc56e..b36b4d9b 100644
--- a/src/core/include/unit.h
+++ b/src/core/include/unit.h
@@ -54,6 +54,7 @@ public:
void resetTask();
bool checkTaskFailed();
void resetTaskFailedCounter();
+ void setHasTaskAssigned(bool newHasTaskAssigned);
void triggerUpdate(unsigned char datumIndex);
@@ -185,6 +186,7 @@ protected:
/********** Other **********/
unsigned int taskCheckCounter = 0;
+ bool hasTaskAssigned = false;
double initialFuel = 0;
map updateTimeMap;
unsigned long long lastLoopTime = 0;
diff --git a/src/core/src/airunit.cpp b/src/core/src/airunit.cpp
index 2ea3e1c9..875f64d4 100644
--- a/src/core/src/airunit.cpp
+++ b/src/core/src/airunit.cpp
@@ -162,7 +162,7 @@ void AirUnit::AIloop()
desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" <<
(desiredAltitudeType ? "AGL" : "ASL") << "', speedType = '" << (desiredSpeedType ? "GS" : "CAS") << "'}";
}
- Command* command = dynamic_cast(new SetTask(groupName, taskSS.str()));
+ Command* command = dynamic_cast(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
@@ -267,7 +267,7 @@ void AirUnit::AIloop()
<< "z = " << formationOffset.z
<< "},"
<< "}";
- Command* command = dynamic_cast(new SetTask(groupName, taskSS.str()));
+ Command* command = dynamic_cast(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
@@ -283,7 +283,7 @@ void AirUnit::AIloop()
taskSS << "{"
<< "id = 'Refuel'"
<< "}";
- Command* command = dynamic_cast(new SetTask(groupName, taskSS.str()));
+ Command* command = dynamic_cast(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
@@ -297,8 +297,10 @@ void AirUnit::AIloop()
if (!getHasTask()) {
std::ostringstream taskSS;
+ taskSS.precision(10);
+
taskSS << "{id = 'Bombing', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << "}";
- Command* command = dynamic_cast(new SetTask(groupName, taskSS.str()));
+ Command* command = dynamic_cast(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
@@ -308,8 +310,10 @@ void AirUnit::AIloop()
if (!getHasTask()) {
std::ostringstream taskSS;
+ taskSS.precision(10);
+
taskSS << "{id = 'CarpetBombing', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << "}";
- Command* command = dynamic_cast(new SetTask(groupName, taskSS.str()));
+ Command* command = dynamic_cast(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
@@ -320,8 +324,10 @@ void AirUnit::AIloop()
if (!getHasTask()) {
std::ostringstream taskSS;
+ taskSS.precision(10);
+
taskSS << "{id = 'AttackMapObject', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << "}";
- Command* command = dynamic_cast(new SetTask(groupName, taskSS.str()));
+ Command* command = dynamic_cast(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
diff --git a/src/core/src/groundunit.cpp b/src/core/src/groundunit.cpp
index 693f8091..69e76b83 100644
--- a/src/core/src/groundunit.cpp
+++ b/src/core/src/groundunit.cpp
@@ -4,7 +4,8 @@
#include "commands.h"
#include "scheduler.h"
#include "defines.h"
-#include "unitsManager.h"
+#include "unitsmanager.h"
+#include "gundata.h"
#include
using namespace GeographicLib;
@@ -49,6 +50,10 @@ void GroundUnit::setState(unsigned char newState)
setTargetPosition(Coords(NULL));
break;
}
+ case State::SIMULATE_FIRE_FIGHT: {
+ setTargetPosition(Coords(NULL));
+ break;
+ }
default:
break;
}
@@ -70,12 +75,16 @@ void GroundUnit::setState(unsigned char newState)
resetActiveDestination();
break;
}
+ case State::SIMULATE_FIRE_FIGHT: {
+ clearActivePath();
+ resetActiveDestination();
+ break;
+ }
default:
break;
}
- if (newState != state)
- resetTask();
+ resetTask();
log(unitName + " setting state from " + to_string(state) + " to " + to_string(newState));
state = newState;
@@ -122,8 +131,42 @@ void GroundUnit::AIloop()
if (!getHasTask()) {
std::ostringstream taskSS;
+ taskSS.precision(10);
taskSS << "{id = 'FireAtPoint', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << ", radius = 1000}";
- Command* command = dynamic_cast(new SetTask(groupName, taskSS.str()));
+ Command* command = dynamic_cast(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
+ scheduler->appendCommand(command);
+ setHasTask(true);
+ }
+ }
+ case State::SIMULATE_FIRE_FIGHT: {
+ setTask("Simulating fire fight");
+
+ if (!getHasTask() || ((double)(rand()) / (double)(RAND_MAX)) < 0.01) {
+ double dist;
+ double bearing1;
+ double bearing2;
+ Geodesic::WGS84().Inverse(position.lat, position.lng, targetPosition.lat, targetPosition.lng, dist, bearing1, bearing2);
+
+ double r = 5; /* m */
+ /* Default gun values */
+ double barrelHeight = 1.0; /* m */
+ double muzzleVelocity = 860; /* m/s */
+ if (gunData.find(name) != gunData.end()) {
+ barrelHeight = gunData[name].barrelHeight;
+ muzzleVelocity = gunData[name].muzzleVelocity;
+ }
+
+ double barrelElevation = r * (9.81 * dist / (2 * muzzleVelocity * muzzleVelocity) - barrelHeight / dist); /* m */
+
+ double lat = 0;
+ double lng = 0;
+ double randomBearing = bearing1 + (((double)(rand()) / (double)(RAND_MAX) - 0.5) * 2) * 45;
+ Geodesic::WGS84().Direct(position.lat, position.lng, randomBearing, r, lat, lng);
+
+ std::ostringstream taskSS;
+ taskSS.precision(10);
+ taskSS << "{id = 'FireAtPoint', lat = " << lat << ", lng = " << lng << ", alt = " << barrelElevation + barrelHeight << ", radius = 0.001}";
+ Command* command = dynamic_cast(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
@@ -161,4 +204,4 @@ void GroundUnit::setFollowRoads(bool newFollowRoads, bool force)
Unit::setFollowRoads(newFollowRoads, force);
resetActiveDestination(); /* Reset active destination to apply option*/
}
-}
\ No newline at end of file
+}
diff --git a/src/core/src/navyunit.cpp b/src/core/src/navyunit.cpp
index 1892a8ca..d2c68a3d 100644
--- a/src/core/src/navyunit.cpp
+++ b/src/core/src/navyunit.cpp
@@ -49,6 +49,10 @@ void NavyUnit::setState(unsigned char newState)
setTargetPosition(Coords(NULL));
break;
}
+ case State::SIMULATE_FIRE_FIGHT: {
+ setTargetPosition(Coords(NULL));
+ break;
+ }
default:
break;
}
@@ -68,6 +72,13 @@ void NavyUnit::setState(unsigned char newState)
case State::FIRE_AT_AREA: {
clearActivePath();
resetActiveDestination();
+ resetTask();
+ break;
+ }
+ case State::SIMULATE_FIRE_FIGHT: {
+ clearActivePath();
+ resetActiveDestination();
+ resetTask();
break;
}
default:
@@ -118,8 +129,23 @@ void NavyUnit::AIloop()
if (!getHasTask()) {
std::ostringstream taskSS;
+ taskSS.precision(10);
+
taskSS << "{id = 'FireAtPoint', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << ", radius = 1000}";
- Command* command = dynamic_cast(new SetTask(groupName, taskSS.str()));
+ Command* command = dynamic_cast(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
+ scheduler->appendCommand(command);
+ setHasTask(true);
+ }
+ }
+ case State::SIMULATE_FIRE_FIGHT: {
+ setTask("Simulating fire fight");
+
+ if (!getHasTask()) {
+ std::ostringstream taskSS;
+ taskSS.precision(10);
+
+ taskSS << "{id = 'FireAtPoint', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << ", radius = 1}";
+ Command* command = dynamic_cast(new SetTask(groupName, taskSS.str(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
diff --git a/src/core/src/scheduler.cpp b/src/core/src/scheduler.cpp
index 742f5c5b..182318bd 100644
--- a/src/core/src/scheduler.cpp
+++ b/src/core/src/scheduler.cpp
@@ -61,6 +61,7 @@ void Scheduler::execute(lua_State* L)
load = command->getLoad();
commands.remove(command);
executedCommandsHashes.push_back(command->getHash());
+ command->executeCallback(); /* Execute the command callback (this is a lambda function that can be used to execute a function when the command is run) */
delete command;
return;
}
@@ -561,6 +562,18 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
unit->setTargetPosition(loc);
log(username + " tasked unit " + unit->getName() + " to fire at area", true);
}
+ else if (key.compare("simulateFireFight") == 0)
+ {
+ unsigned int ID = value[L"ID"].as_integer();
+ unitsManager->acquireControl(ID);
+ double lat = value[L"location"][L"lat"].as_double();
+ double lng = value[L"location"][L"lng"].as_double();
+ Coords loc; loc.lat = lat; loc.lng = lng;
+ Unit* unit = unitsManager->getGroupLeader(ID);
+ unit->setState(State::SIMULATE_FIRE_FIGHT);
+ unit->setTargetPosition(loc);
+ log(username + " tasked unit " + unit->getName() + " to simulate a fire fight", true);
+ }
else if (key.compare("setCommandModeOptions") == 0) {
setCommandModeOptions(value);
log(username + " updated the Command Mode Options", true);
diff --git a/src/core/src/unit.cpp b/src/core/src/unit.cpp
index 4b2f2fa0..4aaf5d8a 100644
--- a/src/core/src/unit.cpp
+++ b/src/core/src/unit.cpp
@@ -146,8 +146,10 @@ void Unit::runAILoop() {
/* If the unit is alive, controlled, is the leader of the group and it is not a human, run the AI Loop that performs the requested commands and instructions (moving, attacking, etc) */
if (getAlive() && getControlled() && !getHuman() && getIsLeader()) {
- if (checkTaskFailed() && state != State::IDLE && state != State::LAND)
+ if (checkTaskFailed() && state != State::IDLE && state != State::LAND) {
+ log(unitName + " has no task, switching to IDLE state");
setState(State::IDLE);
+ }
AIloop();
}
@@ -397,7 +399,7 @@ void Unit::resetActiveDestination()
void Unit::resetTask()
{
- Command* command = dynamic_cast(new ResetTask(groupName));
+ Command* command = dynamic_cast(new ResetTask(groupName, [this]() { this->setHasTaskAssigned(false); }));
scheduler->appendCommand(command);
setHasTask(false);
resetTaskFailedCounter();
@@ -660,7 +662,7 @@ void Unit::goToDestination(string enrouteTask)
{
if (activeDestination != NULL)
{
- Command* command = dynamic_cast(new Move(groupName, activeDestination, getDesiredSpeed(), getDesiredSpeedType() ? "GS" : "CAS", getDesiredAltitude(), getDesiredAltitudeType() ? "AGL" : "ASL", enrouteTask, getCategory()));
+ Command* command = dynamic_cast(new Move(groupName, activeDestination, getDesiredSpeed(), getDesiredSpeedType() ? "GS" : "CAS", getDesiredAltitude(), getDesiredAltitudeType() ? "AGL" : "ASL", enrouteTask, getCategory(), [this]() { this->setHasTaskAssigned(true); }));
scheduler->appendCommand(command);
setHasTask(true);
}
@@ -732,7 +734,7 @@ bool Unit::checkTaskFailed()
return false;
else {
if (taskCheckCounter > 0)
- taskCheckCounter--;
+ taskCheckCounter -= hasTaskAssigned;
return taskCheckCounter == 0;
}
}
@@ -741,6 +743,14 @@ void Unit::resetTaskFailedCounter() {
taskCheckCounter = TASK_CHECK_INIT_VALUE;
}
+void Unit::setHasTaskAssigned(bool newHasTaskAssigned) {
+ hasTaskAssigned = newHasTaskAssigned;
+ if (hasTaskAssigned)
+ log(unitName + " was assigned a new task");
+ else
+ log(unitName + " no task assigned");
+}
+
void Unit::triggerUpdate(unsigned char datumIndex) {
updateTimeMap[datumIndex] = duration_cast(system_clock::now().time_since_epoch()).count();
}