diff --git a/client/public/stylesheets/panels/unitcontrol.css b/client/public/stylesheets/panels/unitcontrol.css index ee3e4145..7cf344a9 100644 --- a/client/public/stylesheets/panels/unitcontrol.css +++ b/client/public/stylesheets/panels/unitcontrol.css @@ -136,19 +136,19 @@ body.feature-forceShowUnitControlPanel #unit-control-panel { } #altitude-type-switch[data-value="true"]>.ol-switch-fill::before { - content: "AGL"; -} - -#altitude-type-switch[data-value="false"]>.ol-switch-fill::before { content: "ASL"; } +#altitude-type-switch[data-value="false"]>.ol-switch-fill::before { + content: "AGL"; +} + #speed-type-switch[data-value="true"]>.ol-switch-fill::before { - content: "GS"; + content: "CAS"; } #speed-type-switch[data-value="false"]>.ol-switch-fill::before { - content: "CAS"; + content: "GS"; } #unit-control-panel .ol-slider-value { diff --git a/client/public/stylesheets/style/style.css b/client/public/stylesheets/style/style.css index f013aa57..08b8350d 100644 --- a/client/public/stylesheets/style/style.css +++ b/client/public/stylesheets/style/style.css @@ -1016,6 +1016,7 @@ nav.ol-panel> :last-child { } .ol-target-icon { + background-image: url("/resources/theme/images/markers/target.svg"); height: 52px; pointer-events: none; width: 52px; diff --git a/client/src/controls/unitspawnmenu.ts b/client/src/controls/unitspawnmenu.ts index 250169a6..1e353ca5 100644 --- a/client/src/controls/unitspawnmenu.ts +++ b/client/src/controls/unitspawnmenu.ts @@ -482,10 +482,11 @@ export class GroundUnitSpawnMenu extends UnitSpawnMenu { location: spawnOptions.latlng, liveryID: spawnOptions.liveryID? spawnOptions.liveryID: "" }; + var units = []; - for (let i = 1; i < unitsCount + 1; i++) { + for (let i = 0; i < unitsCount; i++) { units.push(JSON.parse(JSON.stringify(unitTable))); - unitTable.location.lat += 0.0001; + unitTable.location.lat += i > 0? 0.0001: 0; } getUnitsManager().spawnUnits("GroundUnit", units, getActiveCoalition(), false, spawnOptions.airbase ? spawnOptions.airbase.getName() : "", spawnOptions.country, (res: any) => { @@ -519,10 +520,11 @@ export class NavyUnitSpawnMenu extends UnitSpawnMenu { location: spawnOptions.latlng, liveryID: spawnOptions.liveryID? spawnOptions.liveryID: "" }; + var units = []; - for (let i = 1; i < unitsCount + 1; i++) { + for (let i = 0; i < unitsCount; i++) { units.push(JSON.parse(JSON.stringify(unitTable))); - unitTable.location.lat += 0.0001; + unitTable.location.lat += i > 0? 0.0001: 0; } getUnitsManager().spawnUnits("NavyUnit", units, getActiveCoalition(), false, spawnOptions.airbase ? spawnOptions.airbase.getName() : "", spawnOptions.country, (res: any) => { diff --git a/client/src/index.ts b/client/src/index.ts index a3b33b38..e9bfacb4 100644 --- a/client/src/index.ts +++ b/client/src/index.ts @@ -16,7 +16,7 @@ import { ServerStatusPanel } from "./panels/serverstatuspanel"; import { WeaponsManager } from "./weapon/weaponsmanager"; import { ConfigParameters } from "./@types/dom"; import { CommandModeToolbar } from "./toolbars/commandmodetoolbar"; -import { PrimaryToolbar } from "./toolbars/primaryToolbar"; +import { PrimaryToolbar } from "./toolbars/primarytoolbar"; /* Global data */ var activeCoalition: string = "blue"; diff --git a/client/src/panels/unitcontrolpanel.ts b/client/src/panels/unitcontrolpanel.ts index 19694e7b..8cfd1fd6 100644 --- a/client/src/panels/unitcontrolpanel.ts +++ b/client/src/panels/unitcontrolpanel.ts @@ -34,10 +34,10 @@ export class UnitControlPanel extends Panel { /* Unit control sliders */ this.#altitudeSlider = new Slider("altitude-slider", 0, 100, "ft", (value: number) => { getUnitsManager().selectedUnitsSetAltitude(ftToM(value)); }); - this.#altitudeTypeSwitch = new Switch("altitude-type-switch", (value: boolean) => { getUnitsManager().selectedUnitsSetAltitudeType(value? "AGL": "ASL"); }); + this.#altitudeTypeSwitch = new Switch("altitude-type-switch", (value: boolean) => { getUnitsManager().selectedUnitsSetAltitudeType(value? "ASL": "AGL"); }); this.#speedSlider = new Slider("speed-slider", 0, 100, "kts", (value: number) => { getUnitsManager().selectedUnitsSetSpeed(knotsToMs(value)); }); - this.#speedTypeSwitch = new Switch("speed-type-switch", (value: boolean) => { getUnitsManager().selectedUnitsSetSpeedType(value? "GS": "CAS"); }); + this.#speedTypeSwitch = new Switch("speed-type-switch", (value: boolean) => { getUnitsManager().selectedUnitsSetSpeedType(value? "CAS": "GS"); }); /* Option buttons */ // Reversing the ROEs so that the least "aggressive" option is always on the left @@ -168,8 +168,8 @@ export class UnitControlPanel extends Panel { var onOff = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getOnOff()}); var followRoads = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getFollowRoads()}); - this.#altitudeTypeSwitch.setValue(desiredAltitudeType != undefined? desiredAltitudeType == "AGL": undefined, false); - this.#speedTypeSwitch.setValue(desiredSpeedType != undefined? desiredSpeedType == "GS": undefined, false); + this.#altitudeTypeSwitch.setValue(desiredAltitudeType != undefined? desiredAltitudeType == "ASL": undefined, false); + this.#speedTypeSwitch.setValue(desiredSpeedType != undefined? desiredSpeedType == "CAS": undefined, false); this.#speedSlider.setMinMax(minSpeedValues[this.#selectedUnitsTypes[0]], maxSpeedValues[this.#selectedUnitsTypes[0]]); this.#altitudeSlider.setMinMax(minAltitudeValues[this.#selectedUnitsTypes[0]], maxAltitudeValues[this.#selectedUnitsTypes[0]]); diff --git a/client/src/unit/unit.ts b/client/src/unit/unit.ts index 88a1f4e0..fad3752e 100644 --- a/client/src/unit/unit.ts +++ b/client/src/unit/unit.ts @@ -43,9 +43,9 @@ export class Unit extends CustomMarker { #followRoads: boolean = false; #fuel: number = 0; #desiredSpeed: number = 0; - #desiredSpeedType: string = "GS"; + #desiredSpeedType: string = "CAS"; #desiredAltitude: number = 0; - #desiredAltitudeType: string = "AGL"; + #desiredAltitudeType: string = "ASL"; #leaderID: number = 0; #formationOffset: Offset = { x: 0, diff --git a/scripts/OlympusCommand.lua b/scripts/OlympusCommand.lua index 32f3fa70..bbe0129e 100644 --- a/scripts/OlympusCommand.lua +++ b/scripts/OlympusCommand.lua @@ -173,6 +173,8 @@ function Olympus.buildTask(groupName, options) pattern = options['pattern'] or "Circle" } } + + -- Compute the altitude depending on the altitude type if options['altitude'] then if options ['altitudeType'] then if options ['altitudeType'] == "AGL" then @@ -189,8 +191,15 @@ function Olympus.buildTask(groupName, options) task['params']['altitude'] = options['altitude'] end end + + -- Compute the speed depending on the speed type. CAS calculation is only available if the altitude is also available if options['speed'] then - task['params']['speed'] = options['speed'] + -- Simplified formula to compute CAS from GS + local speed = options['speed'] + if options['speedType'] and options['speedType'] == "CAS" and task['params']['altitude'] then + speed = speed * (1 + 0.02 * task['params']['altitude'] / 0.3048 / 1000) + end + task['params']['speed'] = speed end -- Bomb a specific location elseif options['id'] == 'Bombing' and options['lat'] and options['lng'] then @@ -246,6 +255,11 @@ function Olympus.move(groupName, lat, lng, altitude, altitudeType, speed, speedT altitude = land.getHeight({x = endPoint.x, y = endPoint.z}) + altitude end + -- Simplified formula to compute CAS from GS + if speedType == "CAS" then + speed = speed * (1 + 0.02 * altitude / 0.3048 / 1000) + end + -- Create the path local path = { [1] = mist.fixedWing.buildWP(startPoint, turningPoint, speed, altitude, 'BARO'), @@ -284,6 +298,11 @@ function Olympus.move(groupName, lat, lng, altitude, altitudeType, speed, speedT altitude = land.getHeight({x = endPoint.x, y = endPoint.z}) + altitude end + -- Simplified formula to compute CAS from GS + if speedType == "CAS" then + speed = speed * (1 + 0.02 * altitude / 0.3048 / 1000) + end + -- Create the path local path = { [1] = mist.heli.buildWP(startPoint, turningPoint, speed, altitude, 'BARO'), diff --git a/src/core/include/unit.h b/src/core/include/unit.h index 4f287ed8..b0fdc56e 100644 --- a/src/core/include/unit.h +++ b/src/core/include/unit.h @@ -164,9 +164,9 @@ protected: bool followRoads = false; unsigned short fuel = 0; double desiredSpeed = 0; - bool desiredSpeedType = 1; - double desiredAltitude = 0; - bool desiredAltitudeType = 1; + bool desiredSpeedType = 0; /* CAS */ + double desiredAltitude = 1; + bool desiredAltitudeType = 0; /* ASL */ unsigned int leaderID = NULL; Offset formationOffset = Offset(NULL); unsigned int targetID = NULL; diff --git a/src/core/src/airunit.cpp b/src/core/src/airunit.cpp index 75b79d53..2ea3e1c9 100644 --- a/src/core/src/airunit.cpp +++ b/src/core/src/airunit.cpp @@ -148,13 +148,19 @@ void AirUnit::AIloop() { std::ostringstream taskSS; if (isTanker) { - taskSS << "{ [1] = { id = 'Tanker' }, [2] = { id = 'Orbit', pattern = 'Race-Track', altitude = " << desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" << desiredAltitudeType << "' } }"; + taskSS << "{ [1] = { id = 'Tanker' }, [2] = { id = 'Orbit', pattern = 'Race-Track', altitude = " << + desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" << + (desiredAltitudeType ? "AGL" : "ASL") << "', speedType = '" << (desiredSpeedType ? "GS" : "CAS") << "' }}"; } else if (isAWACS) { - taskSS << "{ [1] = { id = 'AWACS' }, [2] = { id = 'Orbit', pattern = 'Circle', altitude = " << desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" << desiredAltitudeType << "' } }"; + taskSS << "{ [1] = { id = 'AWACS' }, [2] = { id = 'Orbit', pattern = 'Circle', altitude = " << + desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" << + (desiredAltitudeType ? "AGL" : "ASL") << "', speedType = '" << (desiredSpeedType ? "GS" : "CAS") << "' }}"; } else { - taskSS << "{ id = 'Orbit', pattern = 'Circle', altitude = " << desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" << desiredAltitudeType << "' }"; + taskSS << "{ id = 'Orbit', pattern = 'Circle', altitude = " << + desiredAltitude << ", speed = " << desiredSpeed << ", altitudeType = '" << + (desiredAltitudeType ? "AGL" : "ASL") << "', speedType = '" << (desiredSpeedType ? "GS" : "CAS") << "'}"; } Command* command = dynamic_cast(new SetTask(groupName, taskSS.str())); scheduler->appendCommand(command);