diff --git a/client/demo.js b/client/demo.js index 63e7940c..5a76f8d1 100644 --- a/client/demo.js +++ b/client/demo.js @@ -49,10 +49,10 @@ const DEMO_UNIT_DATA = { currentTask: "Holding", currentState: "Idle", activePath: undefined, - targetSpeed: 400, - targetSpeedType: "CAS", - targetAltitude: 3000, - targetAltitudeType: "ASL", + desiredSpeed: 400, + desiredSpeedType: "CAS", + desiredAltitude: 3000, + desiredAltitudeType: "ASL", isTanker: false, }, @@ -96,8 +96,8 @@ const DEMO_UNIT_DATA = { taskData: { currentTask: "Example task", activePath: undefined, - targetSpeed: 300, - targetAltitude: 3000 + desiredSpeed: 300, + desiredAltitude: 3000 }, optionsData: { ROE: "Designated", @@ -139,8 +139,8 @@ const DEMO_UNIT_DATA = { taskData: { currentTask: "Example task", activePath: undefined, - targetSpeed: 400, - targetAltitude: 3000, + desiredSpeed: 400, + desiredAltitude: 3000, onOff: false }, optionsData: { @@ -182,8 +182,8 @@ const DEMO_UNIT_DATA = { taskData: { currentTask: "Example task", activePath: undefined, - targetSpeed: 400, - targetAltitude: 3000 + desiredSpeed: 400, + desiredAltitude: 3000 }, optionsData: { ROE: "None", @@ -225,8 +225,8 @@ const DEMO_UNIT_DATA = { taskData: { currentTask: "Example task", activePath: undefined, - targetSpeed: 400, - targetAltitude: 3000 + desiredSpeed: 400, + desiredAltitude: 3000 }, optionsData: { ROE: "None", @@ -268,8 +268,8 @@ const DEMO_UNIT_DATA = { taskData: { currentTask: "Example task", activePath: undefined, - targetSpeed: 400, - targetAltitude: 3000 + desiredSpeed: 400, + desiredAltitude: 3000 }, optionsData: { ROE: "None", @@ -311,8 +311,8 @@ const DEMO_UNIT_DATA = { taskData: { currentTask: "Example task", activePath: undefined, - targetSpeed: 400, - targetAltitude: 3000 + desiredSpeed: 400, + desiredAltitude: 3000 }, optionsData: { ROE: "None", @@ -354,8 +354,8 @@ const DEMO_UNIT_DATA = { taskData: { currentTask: "Example task", activePath: undefined, - targetSpeed: 400, - targetAltitude: 3000 + desiredSpeed: 400, + desiredAltitude: 3000 }, optionsData: { ROE: "None", @@ -397,8 +397,8 @@ const DEMO_UNIT_DATA = { taskData: { currentTask: "Example task", activePath: undefined, - targetSpeed: 400, - targetAltitude: 3000 + desiredSpeed: 400, + desiredAltitude: 3000 }, optionsData: { ROE: "None", @@ -440,8 +440,8 @@ const DEMO_UNIT_DATA = { taskData: { currentTask: "Example task", activePath: undefined, - targetSpeed: 400, - targetAltitude: 3000 + desiredSpeed: 400, + desiredAltitude: 3000 }, optionsData: { ROE: "None", @@ -483,8 +483,8 @@ const DEMO_UNIT_DATA = { taskData: { currentTask: "Example task", activePath: undefined, - targetSpeed: 400, - targetAltitude: 3000 + desiredSpeed: 400, + desiredAltitude: 3000 }, optionsData: { ROE: "None", @@ -526,8 +526,8 @@ const DEMO_UNIT_DATA = { taskData: { currentTask: "Example task", activePath: undefined, - targetSpeed: 400, - targetAltitude: 3000 + desiredSpeed: 400, + desiredAltitude: 3000 }, optionsData: { ROE: "None", @@ -569,8 +569,8 @@ const DEMO_UNIT_DATA = { taskData: { currentTask: "Example task", activePath: undefined, - targetSpeed: 400, - targetAltitude: 3000 + desiredSpeed: 400, + desiredAltitude: 3000 }, optionsData: { ROE: "None", @@ -612,8 +612,8 @@ const DEMO_UNIT_DATA = { taskData: { currentTask: "Example task", activePath: undefined, - targetSpeed: 400, - targetAltitude: 3000 + desiredSpeed: 400, + desiredAltitude: 3000 }, optionsData: { ROE: "None", diff --git a/client/src/@types/unit.d.ts b/client/src/@types/unit.d.ts index 9f70f291..0a7847b9 100644 --- a/client/src/@types/unit.d.ts +++ b/client/src/@types/unit.d.ts @@ -3,7 +3,7 @@ interface UpdateData { } interface BaseData { - AI: boolean; + controlled: boolean; name: string; unitName: string; groupName: string; @@ -23,7 +23,7 @@ interface MissionData { fuel: number; flags: any; ammo: any; - targets: any; + contacts: any; hasTask: boolean; coalition: string; } @@ -36,10 +36,10 @@ interface TaskData { currentState: string; currentTask: string; activePath: any; - targetSpeed: number; - targetSpeedType: string; - targetAltitude: number; - targetAltitudeType: string; + desiredSpeed: number; + desiredSpeedType: string; + desiredAltitude: number; + desiredAltitudeType: string; targetLocation: any; isTanker: boolean; isAWACS: boolean; diff --git a/client/src/atc/atcboard.ts b/client/src/atc/atcboard.ts index 959874ab..2edcbc9e 100644 --- a/client/src/atc/atcboard.ts +++ b/client/src/atc/atcboard.ts @@ -123,7 +123,7 @@ export abstract class ATCBoard { return false; } - if ( baseData.AI === true ) { + if ( baseData.controlled === true ) { // return false; } diff --git a/client/src/atc/unitdatatable.ts b/client/src/atc/unitdatatable.ts index 3b0b97b8..1ef21f2c 100644 --- a/client/src/atc/unitdatatable.ts +++ b/client/src/atc/unitdatatable.ts @@ -48,7 +48,7 @@ export class UnitDataTable extends Panel { for (const unit of unitsArray) { - const dataset = [unit.getBaseData().unitName, unit.getBaseData().name, unit.getBaseData().category, (unit.getBaseData().AI) ? "AI" : "Human"]; + const dataset = [unit.getBaseData().unitName, unit.getBaseData().name, unit.getBaseData().category, (unit.getBaseData().controlled) ? "AI" : "Human"]; addRow(el, dataset); } diff --git a/client/src/panels/unitcontrolpanel.ts b/client/src/panels/unitcontrolpanel.ts index cba59326..c5d6f489 100644 --- a/client/src/panels/unitcontrolpanel.ts +++ b/client/src/panels/unitcontrolpanel.ts @@ -139,29 +139,29 @@ export class UnitControlPanel extends Panel { element.toggleAttribute("data-show-advanced-settings-button", units.length == 1); /* Flight controls */ - var targetAltitude: number | undefined = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getTaskData().targetAltitude}); - var targetAltitudeType = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getTaskData().targetAltitudeType}); - var targetSpeed = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getTaskData().targetSpeed}); - var targetSpeedType = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getTaskData().targetSpeedType}); + var desiredAltitude: number | undefined = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getTaskData().desiredAltitude}); + var desiredAltitudeType = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getTaskData().desiredAltitudeType}); + var desiredSpeed = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getTaskData().desiredSpeed}); + var desiredSpeedType = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getTaskData().desiredSpeedType}); var onOff = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getTaskData().onOff}); var followRoads = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getTaskData().followRoads}); if (selectedUnitsTypes.length == 1) { - this.#altitudeTypeSwitch.setValue(targetAltitudeType != undefined? targetAltitudeType == "AGL": undefined, false); - this.#speedTypeSwitch.setValue(targetSpeedType != undefined? targetSpeedType == "GS": undefined, false); + this.#altitudeTypeSwitch.setValue(desiredAltitudeType != undefined? desiredAltitudeType == "AGL": undefined, false); + this.#speedTypeSwitch.setValue(desiredSpeedType != undefined? desiredSpeedType == "GS": undefined, false); this.#speedSlider.setMinMax(minSpeedValues[selectedUnitsTypes[0]], maxSpeedValues[selectedUnitsTypes[0]]); this.#altitudeSlider.setMinMax(minAltitudeValues[selectedUnitsTypes[0]], maxAltitudeValues[selectedUnitsTypes[0]]); this.#speedSlider.setIncrement(speedIncrements[selectedUnitsTypes[0]]); this.#altitudeSlider.setIncrement(altitudeIncrements[selectedUnitsTypes[0]]); - this.#speedSlider.setActive(targetSpeed != undefined); - if (targetSpeed != undefined) - this.#speedSlider.setValue(msToKnots(targetSpeed), false); + this.#speedSlider.setActive(desiredSpeed != undefined); + if (desiredSpeed != undefined) + this.#speedSlider.setValue(msToKnots(desiredSpeed), false); - this.#altitudeSlider.setActive(targetAltitude != undefined); - if (targetAltitude != undefined) - this.#altitudeSlider.setValue(mToFt(targetAltitude), false); + this.#altitudeSlider.setActive(desiredAltitude != undefined); + if (desiredAltitude != undefined) + this.#altitudeSlider.setValue(mToFt(desiredAltitude), false); } else { this.#speedSlider.setActive(false); diff --git a/client/src/panels/unitinfopanel.ts b/client/src/panels/unitinfopanel.ts index 523f7f10..91e18920 100644 --- a/client/src/panels/unitinfopanel.ts +++ b/client/src/panels/unitinfopanel.ts @@ -24,21 +24,21 @@ export class UnitInfoPanel extends Panel { constructor(ID: string) { super(ID); - this.#altitude = (this.getElement().querySelector("#altitude")) as HTMLElement; - this.#currentTask = (this.getElement().querySelector("#current-task")) as HTMLElement; - this.#groundSpeed = (this.getElement().querySelector("#ground-speed")) as HTMLElement; - this.#fuelBar = (this.getElement().querySelector("#fuel-bar")) as HTMLElement; - this.#fuelPercentage = (this.getElement().querySelector("#fuel-percentage")) as HTMLElement; - this.#groupName = (this.getElement().querySelector("#group-name")) as HTMLElement; - this.#heading = (this.getElement().querySelector("#heading")) as HTMLElement; - this.#name = (this.getElement().querySelector("#name")) as HTMLElement; - this.#latitude = (this.getElement().querySelector("#latitude")) as HTMLElement; + this.#altitude = (this.getElement().querySelector("#altitude")) as HTMLElement; + this.#currentTask = (this.getElement().querySelector("#current-task")) as HTMLElement; + this.#groundSpeed = (this.getElement().querySelector("#ground-speed")) as HTMLElement; + this.#fuelBar = (this.getElement().querySelector("#fuel-bar")) as HTMLElement; + this.#fuelPercentage = (this.getElement().querySelector("#fuel-percentage")) as HTMLElement; + this.#groupName = (this.getElement().querySelector("#group-name")) as HTMLElement; + this.#heading = (this.getElement().querySelector("#heading")) as HTMLElement; + this.#name = (this.getElement().querySelector("#name")) as HTMLElement; + this.#latitude = (this.getElement().querySelector("#latitude")) as HTMLElement; this.#loadoutContainer = (this.getElement().querySelector("#loadout-container")) as HTMLElement; - this.#longitude = (this.getElement().querySelector("#longitude")) as HTMLElement; - this.#silhouette = (this.getElement().querySelector("#loadout-silhouette")) as HTMLImageElement; - this.#unitControl = (this.getElement().querySelector("#unit-control")) as HTMLElement; - this.#unitLabel = (this.getElement().querySelector("#unit-label")) as HTMLElement; - this.#unitName = (this.getElement().querySelector("#unit-name")) as HTMLElement; + this.#longitude = (this.getElement().querySelector("#longitude")) as HTMLElement; + this.#silhouette = (this.getElement().querySelector("#loadout-silhouette")) as HTMLImageElement; + this.#unitControl = (this.getElement().querySelector("#unit-control")) as HTMLElement; + this.#unitLabel = (this.getElement().querySelector("#unit-label")) as HTMLElement; + this.#unitName = (this.getElement().querySelector("#unit-name")) as HTMLElement; document.addEventListener("unitsSelection", (e: CustomEvent) => this.#onUnitsSelection(e.detail)); document.addEventListener("unitsDeselection", (e: CustomEvent) => this.#onUnitsDeselection(e.detail)); @@ -47,49 +47,53 @@ export class UnitInfoPanel extends Panel { this.hide(); } - + #onUnitUpdate(unit: Unit) { if (this.getElement() != null && this.getVisible() && unit.getSelected()) { const baseData = unit.getBaseData(); /* Set the unit info */ - this.#unitLabel.innerText = aircraftDatabase.getByName(baseData.name)?.label || baseData.name; - this.#unitName.innerText = baseData.unitName; - this.#unitControl.innerText = ( ( baseData.AI ) ? "AI" : "Human" ) + " controlled"; + this.#unitLabel.innerText = aircraftDatabase.getByName(baseData.name)?.label || baseData.name; + this.#unitName.innerText = baseData.unitName; + if (unit.getMissionData().flags.Human) + this.#unitControl.innerText = "Human"; + else if (baseData.controlled) + this.#unitControl.innerText = "Olympus controlled"; + else + this.#unitControl.innerText = "DCS Controlled"; this.#fuelBar.style.width = String(unit.getMissionData().fuel + "%"); this.#fuelPercentage.dataset.percentage = "" + unit.getMissionData().fuel; - this.#currentTask.dataset.currentTask = unit.getTaskData().currentTask !== ""? unit.getTaskData().currentTask: "No task"; + this.#currentTask.dataset.currentTask = unit.getTaskData().currentTask !== "" ? unit.getTaskData().currentTask : "No task"; this.#currentTask.dataset.coalition = unit.getMissionData().coalition; - + this.#silhouette.src = `/images/units/${unit.getDatabase()?.getByName(baseData.name)?.filename}`; this.#silhouette.classList.toggle("hide", unit.getDatabase()?.getByName(baseData.name)?.filename == undefined || unit.getDatabase()?.getByName(baseData.name)?.filename == ''); - - /* Add the loadout elements */ - const items = this.#loadoutContainer.querySelector( "#loadout-items" ); - if ( items ) { - const ammo = Object.values( unit.getMissionData().ammo ); - if ( ammo.length > 0 ) { + /* Add the loadout elements */ + const items = this.#loadoutContainer.querySelector("#loadout-items"); + + if (items) { + const ammo = Object.values(unit.getMissionData().ammo); + if (ammo.length > 0) { items.replaceChildren(...Object.values(unit.getMissionData().ammo).map( (ammo: any) => { var el = document.createElement("div"); - el.dataset.qty = ammo.count; + el.dataset.qty = ammo.count; el.dataset.item = ammo.desc.displayName; return el; } )); } else { - items.innerText = "No loadout"; + items.innerText = "No loadout"; } } } } - #onUnitsSelection(units: Unit[]){ - if (units.length == 1) - { + #onUnitsSelection(units: Unit[]) { + if (units.length == 1) { this.show(); this.#onUnitUpdate(units[0]); } @@ -97,9 +101,8 @@ export class UnitInfoPanel extends Panel { this.hide(); } - #onUnitsDeselection(units: Unit[]){ - if (units.length == 1) - { + #onUnitsDeselection(units: Unit[]) { + if (units.length == 1) { this.show(); this.#onUnitUpdate(units[0]); } diff --git a/client/src/units/aircraftdatabase.ts b/client/src/units/aircraftdatabase.ts index 845f5aba..6092ed81 100644 --- a/client/src/units/aircraftdatabase.ts +++ b/client/src/units/aircraftdatabase.ts @@ -2456,8 +2456,8 @@ export class AircraftDatabase extends UnitDatabase { ], "filename": "kc-135.png" }, - "KC-135MPRS": { - "name": "KC-135MPRS", + "KC135MPRS": { + "name": "KC135MPRS", "label": "KC-135 MPRS Stratotanker", "era": ["Early Cold War", "Mid Cold War", "Late Cold War", "Modern"], "shortLabel": "135M", @@ -2476,6 +2476,26 @@ export class AircraftDatabase extends UnitDatabase { ], "filename": "kc-135.png" }, + "S-3B Tanker": { + "name": "S-3B Tanker", + "label": "S-3B Tanker", + "era": ["Early Cold War", "Mid Cold War", "Late Cold War", "Modern"], + "shortLabel": "S3B", + "loadouts": [ + { + "fuel": 1, + "items": [ + + ], + "roles": [ + "Tanker" + ], + "code": "", + "name": "Default Tanker" + } + ], + "filename": "s-3.png" + }, "MiG-15bis": { "name": "MiG-15bis", "label": "MiG-15 Fagot", diff --git a/client/src/units/unit.ts b/client/src/units/unit.ts index 0fd1d761..54e9d37b 100644 --- a/client/src/units/unit.ts +++ b/client/src/units/unit.ts @@ -21,7 +21,7 @@ export class Unit extends CustomMarker { #data: UnitData = { baseData: { - AI: false, + controlled: false, name: "", unitName: "", groupName: "", @@ -39,7 +39,7 @@ export class Unit extends CustomMarker { fuel: 0, flags: {}, ammo: {}, - targets: {}, + contacts: {}, hasTask: false, coalition: "", }, @@ -50,10 +50,10 @@ export class Unit extends CustomMarker { currentState: "NONE", currentTask: "", activePath: {}, - targetSpeed: 0, - targetSpeedType: "GS", - targetAltitude: 0, - targetAltitudeType: "AGL", + desiredSpeed: 0, + desiredSpeedType: "GS", + desiredAltitude: 0, + desiredAltitudeType: "AGL", targetLocation: {}, isTanker: false, isAWACS: false, @@ -80,7 +80,7 @@ export class Unit extends CustomMarker { #pathMarkers: Marker[] = []; #pathPolyline: Polyline; - #targetsPolylines: Polyline[]; + #contactsPolylines: Polyline[]; #miniMapMarker: CircleMarker | null = null; #targetLocationMarker: TargetMarker; #targetLocationPolyline: Polyline; @@ -113,7 +113,7 @@ export class Unit extends CustomMarker { this.#pathPolyline = new Polyline([], { color: '#2d3e50', weight: 3, opacity: 0.5, smoothFactor: 1 }); this.#pathPolyline.addTo(getMap()); - this.#targetsPolylines = []; + this.#contactsPolylines = []; this.#targetLocationMarker = new TargetMarker(new LatLng(0, 0)); this.#targetLocationPolyline = new Polyline([], { color: '#FF0000', weight: 3, opacity: 0.5, smoothFactor: 1 }); @@ -217,7 +217,9 @@ export class Unit extends CustomMarker { const positionChanged = (data.flightData != undefined && data.flightData.latitude != undefined && data.flightData.longitude != undefined && (this.getFlightData().latitude != data.flightData.latitude || this.getFlightData().longitude != data.flightData.longitude)); const headingChanged = (data.flightData != undefined && data.flightData.heading != undefined && this.getFlightData().heading != data.flightData.heading); const aliveChanged = (data.baseData != undefined && data.baseData.alive != undefined && this.getBaseData().alive != data.baseData.alive); - var updateMarker = (positionChanged || headingChanged || aliveChanged || !getMap().hasLayer(this)); + const stateChanged = (data.taskData != undefined && data.taskData.currentState != undefined && this.getTaskData().currentState != data.taskData.currentState); + const controlledChanged = (data.baseData != undefined && data.baseData.controlled != undefined && this.getBaseData().controlled != data.baseData.controlled); + var updateMarker = (positionChanged || headingChanged || aliveChanged || stateChanged || controlledChanged || !getMap().hasLayer(this)); /* Load the data from the received json */ Object.keys(this.#data).forEach((key1: string) => { @@ -391,7 +393,7 @@ export class Unit extends CustomMarker { const hiddenUnits = getUnitsManager().getHiddenTypes(); if (this.getMissionData().flags.Human && hiddenUnits.includes("human")) hidden = true; - else if (this.getBaseData().AI == false && hiddenUnits.includes("dcs")) + else if (this.getBaseData().controlled == false && hiddenUnits.includes("dcs")) hidden = true; else if (hiddenUnits.includes(this.getMarkerCategory())) hidden = true; @@ -724,7 +726,7 @@ export class Unit extends CustomMarker { /* Set current unit state */ if (this.getMissionData().flags.Human) // Unit is human element.querySelector(".unit")?.setAttribute("data-state", "human"); - else if (!this.getBaseData().AI) // Unit is under DCS control (not Olympus) + else if (!this.getBaseData().controlled) // Unit is under DCS control (not Olympus) element.querySelector(".unit")?.setAttribute("data-state", "dcs"); else if ((this.getBaseData().category == "Aircraft" || this.getBaseData().category == "Helicopter") && !this.getMissionData().hasTask) element.querySelector(".unit")?.setAttribute("data-state", "no-task"); @@ -827,8 +829,8 @@ export class Unit extends CustomMarker { } #drawDetectedUnits() { - for (let index in this.getMissionData().targets) { - var targetData = this.getMissionData().targets[index]; + for (let index in this.getMissionData().contacts) { + var targetData = this.getMissionData().contacts[index]; if (targetData.object != undefined){ var target = getUnitsManager().getUnitByID(targetData.object["id_"]) if (target != null) { @@ -846,15 +848,15 @@ export class Unit extends CustomMarker { color = "#FFFFFF"; var targetPolyline = new Polyline([startLatLng, endLatLng], { color: color, weight: 3, opacity: 0.4, smoothFactor: 1, dashArray: "4, 8" }); targetPolyline.addTo(getMap()); - this.#targetsPolylines.push(targetPolyline) + this.#contactsPolylines.push(targetPolyline) } } } } #clearDetectedUnits() { - for (let index in this.#targetsPolylines) { - getMap().removeLayer(this.#targetsPolylines[index]) + for (let index in this.#contactsPolylines) { + getMap().removeLayer(this.#contactsPolylines[index]) } } diff --git a/scripts/OlympusCommand.lua b/scripts/OlympusCommand.lua index 71007d8d..34d74cb5 100644 --- a/scripts/OlympusCommand.lua +++ b/scripts/OlympusCommand.lua @@ -98,13 +98,14 @@ function Olympus.buildEnrouteTask(options) end -- Builds a valid task depending on the provided options -function Olympus.buildTask(options) +function Olympus.buildTask(groupName, options) local task = nil + local group = Group.getByName(groupName) if (Olympus.isArray(options)) then local tasks = {} for idx, subOptions in pairs(options) do - tasks[idx] = Olympus.buildTask(subOptions) or Olympus.buildEnrouteTask(subOptions) + tasks[idx] = Olympus.buildTask(groupName, subOptions) or Olympus.buildEnrouteTask(subOptions) end task = { id = 'ComboTask', @@ -139,6 +140,25 @@ function Olympus.buildTask(options) pattern = options['pattern'] or "Circle" } } + if options['altitude'] then + if options ['altitudeType'] then + if options ['altitudeType'] == "AGL" then + local groundHeight = 0 + if group then + local groupPos = mist.getLeadPos(group) + groundHeight = land.getHeight({x = groupPos.x, y = groupPos.z}) + end + task['params']['altitude'] = groundHeight + options['altitude'] + else + task['params']['altitude'] = options['altitude'] + end + else + task['params']['altitude'] = options['altitude'] + end + end + if options['speed'] then + task['params']['speed'] = options['speed'] + end elseif options['id'] == 'Bombing' and options['lat'] and options['lng'] then local point = coord.LLtoLO(options['lat'], options['lng'], 0) task = { @@ -524,7 +544,7 @@ 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); + local task = Olympus.buildTask(groupName, taskOptions); Olympus.debug("Olympus.setTask " .. Olympus.serializeTable(task), 20) if task then group:getController():setTask(task) @@ -664,7 +684,7 @@ function Olympus.setMissionData(arg, time) for index, unit in pairs(group:getUnits()) do local unitController = unit:getController() local table = {} - table["targets"] = {} + table["contacts"] = {} for i, target in ipairs(controllerTargets) do for det, enum in pairs(Controller.Detection) do @@ -673,7 +693,7 @@ function Olympus.setMissionData(arg, time) if detected then target["detectionMethod"] = det - table["targets"][#table["targets"] + 1] = target + table["contacts"][#table["contacts"] + 1] = target end end end diff --git a/src/core/include/unit.h b/src/core/include/unit.h index 5d6dafb3..817beb29 100644 --- a/src/core/include/unit.h +++ b/src/core/include/unit.h @@ -62,14 +62,16 @@ public: /********** Public methods **********/ void initialize(json::value json); + void setDefaults(bool force = false); int getID() { return ID; } + void runAILoop(); void updateExportData(json::value json); void updateMissionData(json::value json); json::value getData(long long time, bool getAll = false); virtual wstring getCategory() { return L"No category"; }; /********** Base data **********/ - void setAI(bool newAI) { AI = newAI; addMeasure(L"AI", json::value(newAI)); } + void setControlled(bool newControlled) { controlled = newControlled; addMeasure(L"controlled", json::value(newControlled)); } void setName(wstring newName) { name = newName; addMeasure(L"name", json::value(newName));} void setUnitName(wstring newUnitName) { unitName = newUnitName; addMeasure(L"unitName", json::value(newUnitName));} void setGroupName(wstring newGroupName) { groupName = newGroupName; addMeasure(L"groupName", json::value(newGroupName));} @@ -77,7 +79,7 @@ public: void setType(json::value newType) { type = newType; addMeasure(L"type", newType);} void setCountry(int newCountry) { country = newCountry; addMeasure(L"country", json::value(newCountry));} - bool getAI() { return AI; } + bool getControlled() { return controlled; } wstring getName() { return name; } wstring getUnitName() { return unitName; } wstring getGroupName() { return groupName; } @@ -101,14 +103,14 @@ public: /********** Mission data **********/ void setFuel(double newFuel) { fuel = newFuel; addMeasure(L"fuel", json::value(newFuel));} void setAmmo(json::value newAmmo) { ammo = newAmmo; addMeasure(L"ammo", json::value(newAmmo));} - void setTargets(json::value newTargets) {targets = newTargets; addMeasure(L"targets", json::value(newTargets));} + void setContacts(json::value newContacts) {contacts = newContacts; addMeasure(L"contacts", json::value(newContacts));} void setHasTask(bool newHasTask); void setCoalitionID(int newCoalitionID); void setFlags(json::value newFlags) { flags = newFlags; addMeasure(L"flags", json::value(newFlags));} double getFuel() { return fuel; } json::value getAmmo() { return ammo; } - json::value getTargets() { return targets; } + json::value getTargets() { return contacts; } bool getHasTask() { return hasTask; } wstring getCoalition() { return coalition; } int getCoalitionID(); @@ -123,10 +125,10 @@ public: /********** Task data **********/ 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 setDesiredSpeed(double newDesiredSpeed); + void setDesiredAltitude(double newDesiredAltitude); + void setDesiredSpeedType(wstring newDesiredSpeedType); + void setDesiredAltitudeType(wstring newDesiredAltitudeType); void setActiveDestination(Coords newActiveDestination) { activeDestination = newActiveDestination; addMeasure(L"activeDestination", json::value("")); } // TODO fix void setActivePath(list newActivePath); void setTargetID(int newTargetID) { targetID = newTargetID; addMeasure(L"targetID", json::value(newTargetID));} @@ -137,10 +139,10 @@ public: 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; }; + virtual double getDesiredSpeed() { return desiredSpeed; }; + virtual double getDesiredAltitude() { return desiredAltitude; }; + virtual wstring getDesiredSpeedType() { return desiredSpeedType; }; + virtual wstring getDesiredAltitudeType() { return desiredAltitudeType; }; Coords getActiveDestination() { return activeDestination; } list getActivePath() { return activePath; } int getTargetID() { return targetID; } @@ -151,13 +153,13 @@ public: bool getFollowRoads() { return followRoads; }; /********** Options data **********/ - void setROE(wstring newROE); - void setReactionToThreat(wstring newReactionToThreat); - void setEmissionsCountermeasures(wstring newEmissionsCountermeasures); - void setTACAN(Options::TACAN newTACAN); - void setRadio(Options::Radio newradio); - void setGeneralSettings(Options::GeneralSettings newGeneralSettings); - void setEPLRS(bool newEPLRS); + void setROE(wstring newROE, bool force = false); + void setReactionToThreat(wstring newReactionToThreat, bool force = false); + void setEmissionsCountermeasures(wstring newEmissionsCountermeasures, bool force = false); + void setTACAN(Options::TACAN newTACAN, bool force = false); + void setRadio(Options::Radio newradio, bool force = false); + void setGeneralSettings(Options::GeneralSettings newGeneralSettings, bool force = false); + void setEPLRS(bool newEPLRS, bool force = false); wstring getROE() { return ROE; } wstring getReactionToThreat() { return reactionToThreat; } @@ -186,7 +188,7 @@ protected: int taskCheckCounter = 0; /********** Base data **********/ - bool AI = false; + bool controlled = false; wstring name = L"undefined"; wstring unitName = L"undefined"; wstring groupName = L"undefined"; @@ -205,7 +207,7 @@ protected: double fuel = 0; double initialFuel = 0; // Used internally to detect refueling completed json::value ammo = json::value::null(); - json::value targets = json::value::null(); + json::value contacts = json::value::null(); bool hasTask = false; wstring coalition = L""; json::value flags = json::value::null(); @@ -216,10 +218,10 @@ protected: /********** Task data **********/ wstring currentTask = L""; - double targetSpeed = 0; - double targetAltitude = 0; - wstring targetSpeedType = L"GS"; - wstring targetAltitudeType = L"AGL"; + double desiredSpeed = 0; + double desiredAltitude = 0; + wstring desiredSpeedType = L"GS"; + wstring desiredAltitudeType = L"AGL"; list activePath; Coords activeDestination = Coords(NULL); int targetID = NULL; diff --git a/src/core/include/unitsmanager.h b/src/core/include/unitsmanager.h index d3d5d65b..871c9e74 100644 --- a/src/core/include/unitsmanager.h +++ b/src/core/include/unitsmanager.h @@ -18,8 +18,10 @@ public: vector getGroupMembers(wstring groupName); void updateExportData(lua_State* L); void updateMissionData(json::value missionData); + void runAILoop(); void getData(json::value& answer, long long time); void deleteUnit(int ID, bool explosion); + void acquireControl(int ID); private: map units; diff --git a/src/core/src/aircraft.cpp b/src/core/src/aircraft.cpp index f03c616b..14c8c005 100644 --- a/src/core/src/aircraft.cpp +++ b/src/core/src/aircraft.cpp @@ -18,10 +18,10 @@ 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); + double desiredSpeed = knotsToMs(300); + double desiredAltitude = ftToM(20000); + setDesiredSpeed(desiredSpeed); + setDesiredAltitude(desiredAltitude); }; void Aircraft::changeSpeed(wstring change) @@ -29,34 +29,40 @@ void Aircraft::changeSpeed(wstring change) if (change.compare(L"stop") == 0) setState(State::IDLE); else if (change.compare(L"slow") == 0) - setTargetSpeed(getTargetSpeed() - knotsToMs(25)); + setDesiredSpeed(getDesiredSpeed() - knotsToMs(25)); else if (change.compare(L"fast") == 0) - setTargetSpeed(getTargetSpeed() + knotsToMs(25)); + setDesiredSpeed(getDesiredSpeed() + knotsToMs(25)); - if (getTargetSpeed() < knotsToMs(50)) - setTargetSpeed(knotsToMs(50)); + if (getDesiredSpeed() < knotsToMs(50)) + setDesiredSpeed(knotsToMs(50)); - goToDestination(); /* Send the command to reach the destination */ + if (state == State::IDLE) + resetTask(); + else + goToDestination(); /* Send the command to reach the destination */ } void Aircraft::changeAltitude(wstring change) { if (change.compare(L"descend") == 0) { - if (getTargetAltitude() > 5000) - setTargetAltitude(getTargetAltitude() - ftToM(2500)); - else if (getTargetAltitude() > 0) - setTargetAltitude(getTargetAltitude() - ftToM(500)); + if (getDesiredAltitude() > 5000) + setDesiredAltitude(getDesiredAltitude() - ftToM(2500)); + else if (getDesiredAltitude() > 0) + setDesiredAltitude(getDesiredAltitude() - ftToM(500)); } else if (change.compare(L"climb") == 0) { - if (getTargetAltitude() > 5000) - setTargetAltitude(getTargetAltitude() + ftToM(2500)); - else if (getTargetAltitude() >= 0) - setTargetAltitude(getTargetAltitude() + ftToM(500)); + if (getDesiredAltitude() > 5000) + setDesiredAltitude(getDesiredAltitude() + ftToM(2500)); + else if (getDesiredAltitude() >= 0) + setDesiredAltitude(getDesiredAltitude() + ftToM(500)); } - if (getTargetAltitude() < 0) - setTargetAltitude(0); + if (getDesiredAltitude() < 0) + setDesiredAltitude(0); - goToDestination(); /* Send the command to reach the destination */ + if (state == State::IDLE) + resetTask(); + else + goToDestination(); /* Send the command to reach the destination */ } \ No newline at end of file diff --git a/src/core/src/airunit.cpp b/src/core/src/airunit.cpp index 331e3ff8..06c0808a 100644 --- a/src/core/src/airunit.cpp +++ b/src/core/src/airunit.cpp @@ -135,13 +135,13 @@ void AirUnit::AIloop() { std::wostringstream taskSS; if (isTanker) { - taskSS << "{ [1] = { id = 'Tanker' }, [2] = { id = 'Orbit', pattern = 'Race-Track' } }"; + taskSS << "{ [1] = { id = 'Tanker' }, [2] = { id = 'Orbit', pattern = 'Race-Track', altitude = " << desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" << desiredAltitudeType << "' } }"; } else if (isAWACS) { - taskSS << "{ [1] = { id = 'AWACS' }, [2] = { id = 'Orbit', pattern = 'Circle' } }"; + taskSS << "{ [1] = { id = 'AWACS' }, [2] = { id = 'Orbit', pattern = 'Circle', altitude = " << desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" << desiredAltitudeType << "' } }"; } else { - taskSS << "{ id = 'Orbit', pattern = 'Circle' }"; + taskSS << "{ id = 'Orbit', pattern = 'Circle', altitude = " << desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" << desiredAltitudeType << "' }"; } Command* command = dynamic_cast(new SetTask(groupName, taskSS.str())); scheduler->appendCommand(command); @@ -313,5 +313,4 @@ void AirUnit::AIloop() } addMeasure(L"currentTask", json::value(currentTask)); - } \ No newline at end of file diff --git a/src/core/src/core.cpp b/src/core/src/core.cpp index 5eef82e2..38e490f2 100644 --- a/src/core/src/core.cpp +++ b/src/core/src/core.cpp @@ -69,6 +69,7 @@ extern "C" DllExport int coreFrame(lua_State* L) if (unitsManager != nullptr) { unitsManager->updateExportData(L); + unitsManager->runAILoop(); } before = std::chrono::system_clock::now(); } diff --git a/src/core/src/groundunit.cpp b/src/core/src/groundunit.cpp index c75ea2c0..58b8fd50 100644 --- a/src/core/src/groundunit.cpp +++ b/src/core/src/groundunit.cpp @@ -18,8 +18,8 @@ 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); + double desiredSpeed = 10; + setDesiredSpeed(desiredSpeed); }; void GroundUnit::setState(int newState) @@ -128,12 +128,12 @@ 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)); + setDesiredSpeed(getDesiredSpeed() - knotsToMs(5)); else if (change.compare(L"fast") == 0) - setTargetSpeed(getTargetSpeed() + knotsToMs(5)); + setDesiredSpeed(getDesiredSpeed() + knotsToMs(5)); - if (getTargetSpeed() < 0) - setTargetSpeed(0); + if (getDesiredSpeed() < 0) + setDesiredSpeed(0); } void GroundUnit::setOnOff(bool newOnOff) diff --git a/src/core/src/helicopter.cpp b/src/core/src/helicopter.cpp index f952dc4f..d728f4c5 100644 --- a/src/core/src/helicopter.cpp +++ b/src/core/src/helicopter.cpp @@ -18,10 +18,10 @@ 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); + double desiredSpeed = knotsToMs(100); + double desiredAltitude = ftToM(5000); + setDesiredSpeed(desiredSpeed); + setDesiredAltitude(desiredAltitude); }; void Helicopter::changeSpeed(wstring change) @@ -32,11 +32,11 @@ void Helicopter::changeSpeed(wstring change) clearActivePath(); } else if (change.compare(L"slow") == 0) - targetSpeed -= knotsToMs(10); + desiredSpeed -= knotsToMs(10); else if (change.compare(L"fast") == 0) - targetSpeed += knotsToMs(10); - if (targetSpeed < 0) - targetSpeed = 0; + desiredSpeed += knotsToMs(10); + if (desiredSpeed < 0) + desiredSpeed = 0; goToDestination(); /* Send the command to reach the destination */ } @@ -45,20 +45,20 @@ void Helicopter::changeAltitude(wstring change) { if (change.compare(L"descend") == 0) { - if (targetAltitude > 100) - targetAltitude -= ftToM(100); - else if (targetAltitude > 0) - targetAltitude -= ftToM(10); + if (desiredAltitude > 100) + desiredAltitude -= ftToM(100); + else if (desiredAltitude > 0) + desiredAltitude -= ftToM(10); } else if (change.compare(L"climb") == 0) { - if (targetAltitude > 100) - targetAltitude += ftToM(100); - else if (targetAltitude >= 0) - targetAltitude += ftToM(10); + if (desiredAltitude > 100) + desiredAltitude += ftToM(100); + else if (desiredAltitude >= 0) + desiredAltitude += ftToM(10); } - if (targetAltitude < 0) - targetAltitude = 0; + if (desiredAltitude < 0) + desiredAltitude = 0; goToDestination(); /* Send the command to reach the destination */ } diff --git a/src/core/src/navyunit.cpp b/src/core/src/navyunit.cpp index 9898b24d..dc96f7a1 100644 --- a/src/core/src/navyunit.cpp +++ b/src/core/src/navyunit.cpp @@ -18,8 +18,8 @@ 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); + double desiredSpeed = 10; + setDesiredSpeed(desiredSpeed); }; void NavyUnit::AIloop() diff --git a/src/core/src/scheduler.cpp b/src/core/src/scheduler.cpp index d6fc9f51..e7a7de4e 100644 --- a/src/core/src/scheduler.cpp +++ b/src/core/src/scheduler.cpp @@ -59,8 +59,8 @@ void Scheduler::handleRequest(wstring key, json::value value) if (key.compare(L"setPath") == 0) { int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); Unit* unit = unitsManager->getGroupLeader(ID); - if (unit != nullptr) { wstring unitName = unit->getUnitName(); @@ -116,6 +116,7 @@ void Scheduler::handleRequest(wstring key, json::value value) else if (key.compare(L"attackUnit") == 0) { int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); int targetID = value[L"targetID"].as_integer(); Unit* unit = unitsManager->getGroupLeader(ID); @@ -141,6 +142,7 @@ void Scheduler::handleRequest(wstring key, json::value value) else if (key.compare(L"followUnit") == 0) { int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); int leaderID = value[L"targetID"].as_integer(); int offsetX = value[L"offsetX"].as_integer(); int offsetY = value[L"offsetY"].as_integer(); @@ -170,6 +172,7 @@ void Scheduler::handleRequest(wstring key, json::value value) else if (key.compare(L"changeSpeed") == 0) { int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); Unit* unit = unitsManager->getGroupLeader(ID); if (unit != nullptr) unit->changeSpeed(value[L"change"].as_string()); @@ -177,6 +180,7 @@ void Scheduler::handleRequest(wstring key, json::value value) else if (key.compare(L"changeAltitude") == 0) { int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); Unit* unit = unitsManager->getGroupLeader(ID); if (unit != nullptr) unit->changeAltitude(value[L"change"].as_string()); @@ -184,30 +188,34 @@ void Scheduler::handleRequest(wstring key, json::value value) else if (key.compare(L"setSpeed") == 0) { int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); Unit* unit = unitsManager->getGroupLeader(ID); if (unit != nullptr) - unit->setTargetSpeed(value[L"speed"].as_double()); + unit->setDesiredSpeed(value[L"speed"].as_double()); } else if (key.compare(L"setSpeedType") == 0) { int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); Unit* unit = unitsManager->getGroupLeader(ID); if (unit != nullptr) - unit->setTargetSpeedType(value[L"speedType"].as_string()); + unit->setDesiredSpeedType(value[L"speedType"].as_string()); } else if (key.compare(L"setAltitude") == 0) { int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); Unit* unit = unitsManager->getGroupLeader(ID); if (unit != nullptr) - unit->setTargetAltitude(value[L"altitude"].as_double()); + unit->setDesiredAltitude(value[L"altitude"].as_double()); } else if (key.compare(L"setAltitudeType") == 0) { int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); Unit* unit = unitsManager->getGroupLeader(ID); if (unit != nullptr) - unit->setTargetAltitudeType(value[L"altitudeType"].as_string()); + unit->setDesiredAltitudeType(value[L"altitudeType"].as_string()); } else if (key.compare(L"cloneUnit") == 0) { @@ -221,6 +229,7 @@ void Scheduler::handleRequest(wstring key, json::value value) else if (key.compare(L"setROE") == 0) { int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); Unit* unit = unitsManager->getGroupLeader(ID); wstring ROE = value[L"ROE"].as_string(); unit->setROE(ROE); @@ -228,6 +237,7 @@ void Scheduler::handleRequest(wstring key, json::value value) else if (key.compare(L"setReactionToThreat") == 0) { int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); Unit* unit = unitsManager->getGroupLeader(ID); wstring reactionToThreat = value[L"reactionToThreat"].as_string(); unit->setReactionToThreat(reactionToThreat); @@ -235,6 +245,7 @@ void Scheduler::handleRequest(wstring key, json::value value) else if (key.compare(L"setEmissionsCountermeasures") == 0) { int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); Unit* unit = unitsManager->getGroupLeader(ID); wstring emissionsCountermeasures = value[L"emissionsCountermeasures"].as_string(); unit->setEmissionsCountermeasures(emissionsCountermeasures); @@ -242,6 +253,7 @@ void Scheduler::handleRequest(wstring key, json::value value) else if (key.compare(L"landAt") == 0) { int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); Unit* unit = unitsManager->getGroupLeader(ID); double lat = value[L"location"][L"lat"].as_double(); double lng = value[L"location"][L"lng"].as_double(); @@ -257,12 +269,14 @@ void Scheduler::handleRequest(wstring key, json::value value) else if (key.compare(L"refuel") == 0) { int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); Unit* unit = unitsManager->getGroupLeader(ID); unit->setState(State::REFUEL); } else if (key.compare(L"setAdvancedOptions") == 0) { int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); Unit* unit = unitsManager->getGroupLeader(ID); if (unit != nullptr) { @@ -300,6 +314,7 @@ void Scheduler::handleRequest(wstring key, json::value value) else if (key.compare(L"setFollowRoads") == 0) { int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); bool followRoads = value[L"followRoads"].as_bool(); Unit* unit = unitsManager->getGroupLeader(ID); unit->setFollowRoads(followRoads); @@ -307,6 +322,7 @@ void Scheduler::handleRequest(wstring key, json::value value) else if (key.compare(L"setOnOff") == 0) { int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); bool onOff = value[L"onOff"].as_bool(); Unit* unit = unitsManager->getGroupLeader(ID); unit->setOnOff(onOff); @@ -323,6 +339,7 @@ void Scheduler::handleRequest(wstring key, json::value value) else if (key.compare(L"bombPoint") == 0) { int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); double lat = value[L"location"][L"lat"].as_double(); double lng = value[L"location"][L"lng"].as_double(); Coords loc; loc.lat = lat; loc.lng = lng; @@ -333,6 +350,7 @@ void Scheduler::handleRequest(wstring key, json::value value) else if (key.compare(L"carpetBomb") == 0) { int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); double lat = value[L"location"][L"lat"].as_double(); double lng = value[L"location"][L"lng"].as_double(); Coords loc; loc.lat = lat; loc.lng = lng; @@ -343,6 +361,7 @@ void Scheduler::handleRequest(wstring key, json::value value) else if (key.compare(L"bombBuilding") == 0) { int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); double lat = value[L"location"][L"lat"].as_double(); double lng = value[L"location"][L"lng"].as_double(); Coords loc; loc.lat = lat; loc.lng = lng; @@ -353,6 +372,7 @@ void Scheduler::handleRequest(wstring key, json::value value) else if (key.compare(L"fireAtArea") == 0) { int ID = value[L"ID"].as_integer(); + unitsManager->acquireControl(ID); double lat = value[L"location"][L"lat"].as_double(); double lng = value[L"location"][L"lng"].as_double(); Coords loc; loc.lat = lat; loc.lng = lng; diff --git a/src/core/src/unit.cpp b/src/core/src/unit.cpp index b0a86a73..0e402933 100644 --- a/src/core/src/unit.cpp +++ b/src/core/src/unit.cpp @@ -46,19 +46,30 @@ Unit::~Unit() void Unit::initialize(json::value json) { updateExportData(json); + setDefaults(); +} - if (getAI()) { +void Unit::setDefaults(bool force) +{ + const bool isUnitControlledByOlympus = getControlled(); + const bool isUnitAlive = getAlive(); + const bool isUnitLeader = unitsManager->isUnitGroupLeader(this); + const bool isUnitLeaderOfAGroupWithOtherUnits = unitsManager->isUnitInGroup(this) && unitsManager->isUnitGroupLeader(this); + const bool isUnitHuman = getFlags()[L"Human"].as_bool(); + if (isUnitControlledByOlympus && (isUnitAlive || isUnitLeaderOfAGroupWithOtherUnits) && isUnitLeader && !isUnitHuman) { /* Set the default IDLE state */ setState(State::IDLE); /* Set the default options (these are all defaults so will only affect the export data, no DCS command will be sent) */ - setROE(L"Designated"); - setReactionToThreat(L"Evade"); - setEmissionsCountermeasures(L"Defend"); - setTACAN(TACAN); - setRadio(radio); - setEPLRS(EPLRS); - setGeneralSettings(generalSettings); + setROE(L"Designated", force); + setReactionToThreat(L"Evade", force); + setEmissionsCountermeasures(L"Defend", force); + setTACAN(TACAN, force); + setRadio(radio, force); + setEPLRS(EPLRS, force); + setGeneralSettings(generalSettings, force); + setOnOff(onOff); + setFollowRoads(followRoads); } } @@ -77,6 +88,24 @@ void Unit::addMeasure(wstring key, json::value value) } } +void Unit::runAILoop() { + /* If the unit is alive and it is not a human, run the AI Loop that performs the requested commands and instructions (moving, attacking, etc) */ + const bool isUnitControlledByOlympus = getControlled(); + const bool isUnitAlive = getAlive(); + const bool isUnitLeader = unitsManager->isUnitGroupLeader(this); + const bool isUnitLeaderOfAGroupWithOtherUnits = unitsManager->isUnitInGroup(this) && unitsManager->isUnitGroupLeader(this); + const bool isUnitHuman = getFlags()[L"Human"].as_bool(); + + // Keep running the AI loop even if the unit is dead if it is the leader of a group which has other members in it + if (isUnitControlledByOlympus && (isUnitAlive || isUnitLeaderOfAGroupWithOtherUnits) && isUnitLeader && !isUnitHuman) + { + if (checkTaskFailed() && state != State::IDLE && State::LAND) + setState(State::IDLE); + + AIloop(); + } +} + void Unit::updateExportData(json::value json) { /* Compute speed (loGetWorldObjects does not provide speed, we compute it for better performance instead of relying on many lua calls) */ @@ -112,25 +141,8 @@ void Unit::updateExportData(json::value json) setFlags(json[L"Flags"]); /* All units which contain the name "Olympus" are automatically under AI control */ - /* TODO: I don't really like using this method */ - setAI(getUnitName().find(L"Olympus") != wstring::npos); - - /* If the unit is alive and it is not a human, run the AI Loop that performs the requested commands and instructions (moving, attacking, etc) */ - // 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(); - } + if (getUnitName().find(L"Olympus") != wstring::npos) + setControlled(true); } void Unit::updateMissionData(json::value json) @@ -139,8 +151,8 @@ void Unit::updateMissionData(json::value json) setFuel(int(json[L"fuel"].as_number().to_double() * 100)); if (json.has_object_field(L"ammo")) setAmmo(json[L"ammo"]); - if (json.has_object_field(L"targets")) - setTargets(json[L"targets"]); + if (json.has_object_field(L"contacts")) + setContacts(json[L"contacts"]); if (json.has_boolean_field(L"hasTask")) setHasTask(json[L"hasTask"].as_bool()); } @@ -155,7 +167,7 @@ json::value Unit::getData(long long time, bool sendAll) /********** Base data **********/ json[L"baseData"] = json::value::object(); - for (auto key : { L"AI", L"name", L"unitName", L"groupName", L"alive", L"category"}) + for (auto key : { L"controlled", L"name", L"unitName", L"groupName", L"alive", L"category"}) { if (measures.find(key) != measures.end() && measures[key]->getTime() > time) json[L"baseData"][key] = measures[key]->getValue(); @@ -176,7 +188,7 @@ json::value Unit::getData(long long time, bool sendAll) /********** Mission data **********/ json[L"missionData"] = json::value::object(); - for (auto key : { L"fuel", L"ammo", L"targets", L"hasTask", L"coalition", L"flags" }) + for (auto key : { L"fuel", L"ammo", L"contacts", L"hasTask", L"coalition", L"flags" }) { if (measures.find(key) != measures.end() && measures[key]->getTime() > time) json[L"missionData"][key] = measures[key]->getValue(); @@ -198,7 +210,7 @@ json::value Unit::getData(long long time, bool sendAll) 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" }) + for (auto key : { L"currentState", L"currentTask", L"desiredSpeed", L"desiredAltitude", L"desiredSpeedType", L"desiredAltitudeType", L"activePath", L"isTanker", L"isAWACS", L"onOff", L"followRoads", L"targetID", L"targetLocation" }) { if (measures.find(key) != measures.end() && measures[key]->getTime() > time) json[L"taskData"][key] = measures[key]->getValue(); @@ -354,10 +366,10 @@ void Unit::setFormationOffset(Offset newFormationOffset) resetTask(); } -void Unit::setROE(wstring newROE) { +void Unit::setROE(wstring newROE, bool force) { addMeasure(L"ROE", json::value(newROE)); - if (ROE != newROE) { + if (ROE != newROE || force) { ROE = newROE; int ROEEnum; @@ -379,10 +391,10 @@ void Unit::setROE(wstring newROE) { } } -void Unit::setReactionToThreat(wstring newReactionToThreat) { +void Unit::setReactionToThreat(wstring newReactionToThreat, bool force) { addMeasure(L"reactionToThreat", json::value(newReactionToThreat)); - if (reactionToThreat != newReactionToThreat) { + if (reactionToThreat != newReactionToThreat || force) { reactionToThreat = newReactionToThreat; int reactionToThreatEnum; @@ -404,10 +416,10 @@ void Unit::setReactionToThreat(wstring newReactionToThreat) { } } -void Unit::setEmissionsCountermeasures(wstring newEmissionsCountermeasures) { +void Unit::setEmissionsCountermeasures(wstring newEmissionsCountermeasures, bool force) { addMeasure(L"emissionsCountermeasures", json::value(newEmissionsCountermeasures)); - if (emissionsCountermeasures != newEmissionsCountermeasures) { + if (emissionsCountermeasures != newEmissionsCountermeasures || force) { emissionsCountermeasures = newEmissionsCountermeasures; int radarEnum; @@ -472,7 +484,7 @@ void Unit::setIsAWACS(bool newIsAWACS) { setEPLRS(isAWACS); } -void Unit::setTACAN(Options::TACAN newTACAN) { +void Unit::setTACAN(Options::TACAN newTACAN, bool force) { auto json = json::value(); json[L"isOn"] = json::value(newTACAN.isOn); json[L"channel"] = json::value(newTACAN.channel); @@ -480,7 +492,7 @@ void Unit::setTACAN(Options::TACAN newTACAN) { json[L"callsign"] = json::value(newTACAN.callsign); addMeasure(L"TACAN", json); - if (TACAN != newTACAN) + if (TACAN != newTACAN || force) { TACAN = newTACAN; if (TACAN.isOn) { @@ -511,7 +523,7 @@ void Unit::setTACAN(Options::TACAN newTACAN) { } } -void Unit::setRadio(Options::Radio newRadio) { +void Unit::setRadio(Options::Radio newRadio, bool force) { auto json = json::value(); json[L"frequency"] = json::value(newRadio.frequency); @@ -519,7 +531,7 @@ void Unit::setRadio(Options::Radio newRadio) { json[L"callsignNumber"] = json::value(newRadio.callsignNumber); addMeasure(L"radio", json); - if (radio != newRadio) + if (radio != newRadio || force) { radio = newRadio; @@ -551,11 +563,11 @@ void Unit::setRadio(Options::Radio newRadio) { } } -void Unit::setEPLRS(bool newEPLRS) +void Unit::setEPLRS(bool newEPLRS, bool force) { //addMeasure(L"EPLRS", json::value(newEPLRS)); // - //if (EPLRS != newEPLRS) { + //if (EPLRS != newEPLRS || force) { // EPLRS = newEPLRS; // // std::wostringstream commandSS; @@ -570,7 +582,7 @@ void Unit::setEPLRS(bool newEPLRS) //} } -void Unit::setGeneralSettings(Options::GeneralSettings newGeneralSettings) { +void Unit::setGeneralSettings(Options::GeneralSettings newGeneralSettings, bool force) { auto json = json::value(); json[L"prohibitJettison"] = json::value(newGeneralSettings.prohibitJettison); @@ -598,35 +610,47 @@ void Unit::setGeneralSettings(Options::GeneralSettings newGeneralSettings) { } } -void Unit::setTargetSpeed(double newTargetSpeed) { - targetSpeed = newTargetSpeed; - addMeasure(L"targetSpeed", json::value(newTargetSpeed)); - goToDestination(); +void Unit::setDesiredSpeed(double newDesiredSpeed) { + desiredSpeed = newDesiredSpeed; + addMeasure(L"desiredSpeed", json::value(newDesiredSpeed)); + if (state == State::IDLE) + resetTask(); + else + goToDestination(); /* Send the command to reach the destination */ } -void Unit::setTargetAltitude(double newTargetAltitude) { - targetAltitude = newTargetAltitude; - addMeasure(L"targetAltitude", json::value(newTargetAltitude)); - goToDestination(); +void Unit::setDesiredAltitude(double newDesiredAltitude) { + desiredAltitude = newDesiredAltitude; + addMeasure(L"desiredAltitude", json::value(newDesiredAltitude)); + if (state == State::IDLE) + resetTask(); + else + goToDestination(); /* Send the command to reach the destination */ } -void Unit::setTargetSpeedType(wstring newTargetSpeedType) { - targetSpeedType = newTargetSpeedType; - addMeasure(L"targetSpeedType", json::value(newTargetSpeedType)); - goToDestination(); +void Unit::setDesiredSpeedType(wstring newDesiredSpeedType) { + desiredSpeedType = newDesiredSpeedType; + addMeasure(L"desiredSpeedType", json::value(newDesiredSpeedType)); + if (state == State::IDLE) + resetTask(); + else + goToDestination(); /* Send the command to reach the destination */ } -void Unit::setTargetAltitudeType(wstring newTargetAltitudeType) { - targetAltitudeType = newTargetAltitudeType; - addMeasure(L"targetAltitudeType", json::value(newTargetAltitudeType)); - goToDestination(); +void Unit::setDesiredAltitudeType(wstring newDesiredAltitudeType) { + desiredAltitudeType = newDesiredAltitudeType; + addMeasure(L"desiredAltitudeType", json::value(newDesiredAltitudeType)); + if (state == State::IDLE) + resetTask(); + else + goToDestination(); /* Send the command to reach the destination */ } void Unit::goToDestination(wstring enrouteTask) { if (activeDestination != NULL) { - Command* command = dynamic_cast(new Move(groupName, activeDestination, getTargetSpeed(), getTargetSpeedType(), getTargetAltitude(), getTargetAltitudeType(), enrouteTask, getCategory())); + Command* command = dynamic_cast(new Move(groupName, activeDestination, getDesiredSpeed(), getDesiredSpeedType(), getDesiredAltitude(), getDesiredAltitudeType(), enrouteTask, getCategory())); scheduler->appendCommand(command); setHasTask(true); } diff --git a/src/core/src/unitsmanager.cpp b/src/core/src/unitsmanager.cpp index b5ec63be..2c683858 100644 --- a/src/core/src/unitsmanager.cpp +++ b/src/core/src/unitsmanager.cpp @@ -156,6 +156,14 @@ void UnitsManager::updateMissionData(json::value missionData) } } +void UnitsManager::runAILoop() { + /* Run the AI Loop on all units */ + for (auto const& unit : units) + { + unit.second->runAILoop(); + } +} + void UnitsManager::getData(json::value& answer, long long time) { auto unitsJson = json::value::object(); @@ -177,3 +185,17 @@ void UnitsManager::deleteUnit(int ID, bool explosion) } } +void UnitsManager::acquireControl(int ID) { + Unit* unit = getUnit(ID); + if (unit != nullptr) { + for (auto const& groupMember : getGroupMembers(unit->getGroupName())) { + if (!groupMember->getControlled()) { + groupMember->setControlled(true); + groupMember->setState(State::IDLE); + groupMember->setDefaults(true); + } + } + } + +} +