From 8977ba9b6d8e465bef664badda1b44db514e6c2a Mon Sep 17 00:00:00 2001 From: Pax1601 Date: Fri, 15 Sep 2023 09:36:27 +0200 Subject: [PATCH] Added basic simulated firefight state --- .../public/stylesheets/other/contextmenus.css | 4 + client/src/constants/constants.ts | 2 +- client/src/map/map.ts | 8 +- client/src/server/server.ts | 6 + client/src/unit/unit.ts | 6 +- client/src/unit/unitsmanager.ts | 12 ++ scripts/OlympusCommand.lua | 27 ++-- scripts/python/generateGunData.py | 21 ++++ scripts/python/gundata.h | 109 ++++++++++++++++ src/core/core.vcxproj | 1 + src/core/core.vcxproj.filters | 3 + src/core/include/commands.h | 50 +++++--- src/core/include/datatypes.h | 8 +- src/core/include/gundata.h | 116 ++++++++++++++++++ src/core/include/unit.h | 2 + src/core/src/airunit.cpp | 18 ++- src/core/src/groundunit.cpp | 53 +++++++- src/core/src/navyunit.cpp | 28 ++++- src/core/src/scheduler.cpp | 13 ++ src/core/src/unit.cpp | 18 ++- 20 files changed, 461 insertions(+), 44 deletions(-) create mode 100644 scripts/python/generateGunData.py create mode 100644 scripts/python/gundata.h create mode 100644 src/core/include/gundata.h 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(); }