More work on follow and tanking

This commit is contained in:
Pax1601 2023-04-14 17:30:10 +02:00
parent b56f1ca547
commit 39698c66a3
15 changed files with 308 additions and 104 deletions

View File

@ -50,7 +50,15 @@ const DEMO_UNIT_DATA = {
activePath: undefined,
targetSpeed: 400,
targetAltitude: 3000,
isTanker: true
isTanker: false,
TACANOn: false,
TACANChannel: 32,
TACANXY: "Y",
TACANCallsign: "ASD",
radioFrequency: 123.750,
radioCallsign: 2,
radioCallsignNumber: 3,
radioAMFM: "FM"
},
optionsData: {
ROE: "Designated",

View File

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="follow.svg"
id="svg14"
version="1.1"
fill="none"
viewBox="0 0 16 16"
height="16"
width="16">
<metadata
id="metadata20">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs18" />
<sodipodi:namedview
inkscape:current-layer="svg14"
inkscape:window-maximized="1"
inkscape:window-y="-8"
inkscape:window-x="1912"
inkscape:cy="14.663012"
inkscape:cx="22.433158"
inkscape:zoom="12.142857"
showgrid="false"
id="namedview16"
inkscape:window-height="1017"
inkscape:window-width="1920"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
guidetolerance="10"
gridtolerance="10"
objecttolerance="10"
borderopacity="1"
bordercolor="#666666"
pagecolor="#ffffff" />
<path
style="fill:#000000;fill-opacity:1;stroke-width:1.38669"
id="path2"
fill="#202831"
d="m 1.2760685,7.4643156 c -0.1658027,0.070984 -0.272592,0.2358263 -0.272592,0.4178212 0,0.1818565 0.106789,0.346698 0.272592,0.4178225 l 2.8916403,1.2533251 c 0.224802,0.096784 0.4636823,0.147827 0.7081738,0.147827 H 7.0396595 L 9.4001929,13.794119 H 8.8719691 c -0.3737975,0 -0.6745171,0.304161 -0.6745171,0.682098 0,0.378076 0.3007196,0.682237 0.6745171,0.682237 h 1.5736429 0.899265 0.674379 c 0.373797,0 0.674518,-0.304161 0.674518,-0.682237 0,-0.377937 -0.300721,-0.682098 -0.674518,-0.682098 H 11.794509 V 9.7011114 h 0.918844 l 1.441691,1.6627796 c 0.08425,0.09944 0.207925,0.156335 0.337121,0.156335 h 0.449631 c 0.24736,0 0.449631,-0.204588 0.449631,-0.454779 V 8.3367762 H 13.5929 c -0.247222,0 -0.449495,-0.2045879 -0.449495,-0.4546394 0,-0.2501899 0.202273,-0.4547778 0.449495,-0.4547778 h 1.798527 V 4.6986885 c 0,-0.250191 -0.202271,-0.4547784 -0.449631,-0.4547784 h -0.449631 c -0.129196,0 -0.252876,0.056762 -0.337121,0.1561949 L 12.713353,6.0630238 H 11.794509 V 1.9700179 h 0.224747 c 0.373797,0 0.674518,-0.3041619 0.674518,-0.6820981 0,-0.37807561 -0.300721,-0.68223748 -0.674518,-0.68223748 H 11.344877 10.445612 8.8719691 c -0.3737975,0 -0.6745171,0.30416187 -0.6745171,0.68223748 0,0.3779362 0.3007196,0.6820981 0.6745171,0.6820981 H 9.4001929 L 7.0396595,6.0630238 H 4.8758826 c -0.2444915,0 -0.4833718,0.051184 -0.7081738,0.1478276 z" />
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
class="svg-icon"
style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;"
viewBox="0 0 1024 1024"
version="1.1"
id="svg6"
sodipodi:docname="sword.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
inkscape:document-rotation="0"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview8"
showgrid="false"
inkscape:zoom="0.83007812"
inkscape:cx="512"
inkscape:cy="512"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg6" />
<path
d="M34.133333 870.4c-17.066667-17.066667-17.066667-42.666667 0-59.733333l194.133334-194.133334-134.4-134.4c-17.066667-17.066667-17.066667-42.666667 0-59.733333 17.066667-17.066667 42.666667-17.066667 59.733333 0l59.733333 59.733333 448-448c10.666667-10.666667 25.6-14.933333 38.4-10.666666l224 44.8c17.066667 4.266667 29.866667 17.066667 34.133334 34.133333L1002.666667 324.266667c2.133333 14.933333-2.133333 27.733333-10.666667 38.4l-448 448 59.733333 59.733333c17.066667 17.066667 17.066667 42.666667 0 59.733333-8.533333 8.533333-19.2 12.8-29.866666 12.8-10.666667 0-21.333333-4.266667-29.866667-12.8l-134.4-134.4-196.266667 194.133334c-8.533333 8.533333-19.2 12.8-29.866666 12.8s-21.333333-4.266667-29.866667-12.8l-119.466667-119.466667z m253.866667-194.133333l-164.266667 164.266666 59.733334 59.733334 164.266666-164.266667-59.733333-59.733333zM706.133333 110.933333L273.066667 541.866667l209.066666 209.066666L913.066667 320l-34.133334-172.8-172.8-36.266667z"
fill="#2F3CF4"
id="path2"
style="fill:#000000;fill-opacity:1" />
<path
style="fill:#000000;fill-opacity:1"
d="M795.733333 288c17.066667-17.066667 17.066667-42.666667 0-59.733333s-42.666667-17.066667-59.733333 0L422.4 541.866667c-17.066667 17.066667-17.066667 42.666667 0 59.733333 8.533333 8.533333 19.2 12.8 29.866667 12.8 10.666667 0 21.333333-4.266667 29.866666-12.8l313.6-313.6z"
fill="#FFFFFF"
id="path4" />
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -207,10 +207,44 @@
display: flex;
flex-direction: column;
height: fit-content;
width: fit-content;
position: absolute;
row-gap: 5px;
width: 150px;
z-index: 1000;
padding: 15px;
}
#unit-contextmenu button {
border: 1px solid var(--background-offwhite);
border-radius: var(--border-radius-sm);
padding: 12px;
font-weight: normal;
}
#unit-contextmenu div {
display: flex;
flex-direction: row;
align-content: center;
}
#unit-contextmenu div:before {
display: inline-block;
filter: invert(100%);
height: 16px;
margin-right: 15px;
width: 16px;
}
#refuel::before {
content: url( /images/icons/fuel.svg );
}
#attack::before {
content: url( /images/icons/sword.svg );
}
#follow::before {
content: url( /images/icons/follow.svg );
}
/* Airbase context menu */

View File

@ -53,6 +53,10 @@ button {
padding: 6px;
}
button:hover {
background-color: var(--background-hover);
}
button[disabled="disabled"] {
color: var(--highlight-color);
cursor: not-allowed;

View File

@ -93,8 +93,24 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
margin-bottom:8px;
}
#unit-control-panel #threat,
#unit-control-panel #roe {
margin-top:12px;
}
#advanced-settings-dialog {
width: 400px;
}
#advanced-settings-dialog > .ol-dialog-content {
margin-top: 10px;
margin-bottom: 10px;
display: flex;
flex-direction: column;
flex-wrap: nowrap;
row-gap: 10px;
}
#advanced-settings-dialog > .ol-dialog-content > .ol-group {
justify-content: space-between;
}

View File

@ -31,6 +31,8 @@
--secondary-light-grey : #797e83;
--secondary-yellow : #ffd46893;
--background-hover : #f2f2f333;
--nav-text : #ECECEC;

View File

@ -37,19 +37,21 @@ interface FormationData {
}
interface TaskData {
currentState: string;
currentTask: string;
activePath: any;
targetSpeed: number;
targetAltitude: number;
isTanker: boolean;
isAWACS: boolean;
radioOn: boolean;
TACANOn: boolean;
radioFrequency: number;
radioCallsign: number;
TACANChannel: number;
TACANXY: string;
TACANCallsign: string;
radioFrequency: number;
radioCallsign: number;
radioCallsignNumber: number;
radioAMFM: string;
}
interface OptionsData {

View File

@ -5,12 +5,12 @@ export class UnitContextMenu extends ContextMenu {
super(id);
}
setOptions(options: string[], callback: CallableFunction)
setOptions(options: {[key: string]: string}, callback: CallableFunction)
{
this.getContainer()?.replaceChildren(...options.map((option: string) =>
this.getContainer()?.replaceChildren(...Object.keys(options).map((option: string, idx: number) =>
{
var button = document.createElement("button");
button.innerText = option;
button.innerHTML = options[option];
button.addEventListener("click", () => callback(option));
return (button);
}));

View File

@ -18,7 +18,7 @@ export class MouseInfoPanel extends Panel {
this.#measureMarker = new Marker([0, 0], {icon: this.#measureIcon, interactive: false});
this.#measureBox = document.createElement("div");
this.#measureBox.classList.add("ol-measure-box");
this.#measureBox.classList.add("ol-measure-box", "hide");
document.body.appendChild(this.#measureBox);
getMap()?.on("click", (e: any) => this.#onMapClick(e));

View File

@ -111,6 +111,9 @@ export class UnitControlPanel extends Panel {
update() {
var units = getUnitsManager().getSelectedUnits();
this.getElement().querySelector("#advanced-settings-div")?.classList.toggle("hide", units.length != 1);
if (this.getElement() != null && units.length > 0) {
this.#showFlightControlSliders(units);
@ -123,8 +126,6 @@ export class UnitControlPanel extends Panel {
else
database = null; // TODO add databases for other unit types
console.log(unit.getBaseData());
var button = document.createElement("button");
var callsign = unit.getBaseData().unitName || "";
@ -202,19 +203,20 @@ export class UnitControlPanel extends Panel {
#updateAdvancedSettingsDialog(units: Unit[])
{
this.getElement().querySelector("#advanced-settings-div")?.classList.toggle("hide", units.length != 1);
if (units.length == 1)
{
const unit = units[0];
(<HTMLElement>this.#advancedSettingsDialog.querySelector("#unit-name")).innerText = unit.getBaseData().unitName;
if (getUnitsManager().getSelectedUnits().length == 1){
if (getUnitsManager().getSelectedUnits().length == 1)
{
var asd = this.#advancedSettingsDialog;
this.#radioCallsignDropdown.setOptions(["Enfield", "Springfield", "Uzi", "Colt", "Dodge", "Ford", "Chevy", "Pontiac"]);
this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign);
this.#advancedSettingsDialog.querySelector("#tanker-checkbox")?.querySelector("input")?.setAttribute('checked', String(unit.getTaskData().isTanker));
this.#advancedSettingsDialog.querySelector("#AWACS-checkbox")?.querySelector("input")?.setAttribute('checked', String(unit.getTaskData().isAWACS));
var tankerCheckbox = this.#advancedSettingsDialog.querySelector("#tanker-checkbox")?.querySelector("input")
if (tankerCheckbox) tankerCheckbox.checked = unit.getTaskData().isTanker;
var AWACSCheckbox = this.#advancedSettingsDialog.querySelector("#AWACS-checkbox")?.querySelector("input")
if (AWACSCheckbox) AWACSCheckbox.checked = unit.getTaskData().isAWACS;
var roles = aircraftDatabase.getByName(unit.getBaseData().name)?.loadouts.map((loadout) => {return loadout.roles})
if (roles != undefined && Array.prototype.concat.apply([], roles)?.includes("Tanker")){
@ -240,7 +242,7 @@ export class UnitControlPanel extends Panel {
#applyAdvancedSettings()
{
const isTanker = this.#advancedSettingsDialog.querySelector("#tanker-checkbox")?.querySelector("input")?.checked? true: false;
const isAWACS = false; //this.#advancedSettingsDialog.querySelector("#AWACS-checkbox")?.querySelector("input")?.checked? true: false;
const isAWACS = this.#advancedSettingsDialog.querySelector("#AWACS-checkbox")?.querySelector("input")?.checked? true: false;
const TACANChannel = Number(this.#advancedSettingsDialog.querySelector("#TACAN-channel")?.querySelector("input")?.value);
const TACANXY = this.#TACANXYDropdown.getValue();
const TACANCallsign = <string> this.#advancedSettingsDialog.querySelector("#tacan-callsign")?.querySelector("input")?.value

View File

@ -117,6 +117,12 @@ export function attackUnit(ID: number, targetID: number) {
POST(data, () => { });
}
export function followUnit(ID: number, targetID: number) {
var command = { "ID": ID, "targetID": targetID };
var data = { "followUnit": command }
POST(data, () => { });
}
export function cloneUnit(ID: number, latlng: L.LatLng) {
var command = { "ID": ID, "location": latlng };
var data = { "cloneUnit": command }

View File

@ -1,7 +1,7 @@
import { Marker, LatLng, Polyline, Icon, DivIcon } from 'leaflet';
import { getMap, getUnitsManager } from '..';
import { rad2deg } from '../other/utils';
import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, getUnits, landAt, setAltitude, setReactionToThreat, setROE, setSpeed, refuel, setAdvacedOptions } from '../server/server';
import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, getUnits, landAt, setAltitude, setReactionToThreat, setROE, setSpeed, refuel, setAdvacedOptions, followUnit } from '../server/server';
import { aircraftDatabase } from './aircraftdatabase';
import { groundUnitsDatabase } from './groundunitsdatabase';
@ -46,19 +46,21 @@ export class Unit extends Marker {
wingmenIDs: [],
},
taskData: {
currentState: "IDLE",
currentTask: "",
activePath: {},
targetSpeed: 0,
targetAltitude: 0,
isTanker: false,
isAWACS: false,
radioOn: false,
TACANOn: false,
radioFrequency: 0,
radioCallsign: 0,
TACANChannel: 0,
TACANXY: "X",
TACANCallsign: "",
radioFrequency: 0,
radioCallsign: 0,
radioCallsignNumber: 0,
radioAMFM: "AM"
},
optionsData: {
ROE: "",
@ -336,6 +338,16 @@ export class Unit extends Marker {
}
}
followUnit(targetID: number) {
/* Call DCS attackUnit function */
if (this.ID != targetID) {
followUnit(this.ID, targetID);
}
else {
// TODO: show a message
}
}
landAt(latlng: LatLng) {
landAt(this.ID, latlng);
}
@ -400,22 +412,23 @@ export class Unit extends Marker {
}
#onContextMenu(e: any) {
var options: string[] = [];
var options: {[key: string]: string} = {};
if (getUnitsManager().getSelectedUnits().length > 0 && !(getUnitsManager().getSelectedUnits().includes(this)))
{
options = [
'Attack'
]
options = {
'Attack': `<div id="attack">Attack</div>`,
'Follow': `<div id="follow">Follow</div>`
}
}
else if (getUnitsManager().getSelectedUnits().length > 0 && (getUnitsManager().getSelectedUnits().includes(this)))
else if ((getUnitsManager().getSelectedUnits().length > 0 && (getUnitsManager().getSelectedUnits().includes(this))) || getUnitsManager().getSelectedUnits().length == 0)
{
if (this.getBaseData().category == "Aircraft")
{
options.push("Refuel"); // TODO Add some way of knowing which aircraft can AAR
options["Refuel"] = `<div id="refuel">Refuel</div>`; // TODO Add some way of knowing which aircraft can AAR
}
}
if (options.length > 0)
if (Object.keys(options).length > 0)
{
getMap().showUnitContextMenu(e);
getMap().getUnitContextMenu().setOptions(options, (option: string) => {
@ -430,6 +443,8 @@ export class Unit extends Marker {
getUnitsManager().selectedUnitsAttackUnit(this.ID);
if (action === "Refuel")
getUnitsManager().selectedUnitsRefuel();
if (action === "Follow")
getUnitsManager().selectedUnitsFollowUnit(this.ID);
}
#updateMarker() {

View File

@ -334,6 +334,14 @@ export class UnitsManager {
}
}
selectedUnitsFollowUnit(ID: number) {
var selectedUnits = this.getSelectedUnits();
for (let idx in selectedUnits) {
var commandedUnit = selectedUnits[idx];
commandedUnit.followUnit(ID);
}
}
copyUnits()
{
this.#copiedUnits = this.getSelectedUnits();
@ -370,7 +378,7 @@ export class UnitsManager {
setTimeout(() => {
document.dispatchEvent(new CustomEvent("unitsSelection", {detail: this.getSelectedUnits()}));
this.#selectionEventDisabled = false;
}, 300);
}, 100);
this.#selectionEventDisabled = true;
}
}

View File

@ -72,91 +72,81 @@
</div>
<div class="ol-dialog-content">
<form onsubmit="return false">
<!--
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Use ECM when available
</label>
</div>
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Prohibit jettison
</label>
</div>
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Prohibit afterburner
</label>
</div>
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Prohibit A/A
</label>
</div>
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Prohibit A/G
</label>
</div>
-->
<!--
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Use ECM when available
</label>
</div>
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Prohibit jettison
</label>
</div>
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Prohibit afterburner
</label>
</div>
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Prohibit A/A
</label>
</div>
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Prohibit A/G
</label>
</div>
-->
<div id="tanker-checkbox" class="ol-checkbox">
<label>
<input type="checkbox" />
Operate as tanker
</label>
</div>
<div id="tanker-checkbox" class="ol-checkbox">
<label>
<input type="checkbox" />
Operate as AAR tanker
</label>
</div>
<div id="AWACS-checkbox" class="ol-checkbox">
<label>
<input type="checkbox" />
Operate as AWACS
</label>
</div>
<div id="AWACS-checkbox" class="ol-checkbox">
<label>
<input type="checkbox" />
Operate as AWACS
</label>
</div>
<div class="ol-group">
<label>A/A TACAN: </label>
<div class="ol-group">
<div id="TACAN-checkbox" class="ol-checkbox">
<label>
A/A TACAN:
</label>
</div>
<div id="TACAN-channel" class="ol-text-input">
<input type="number" min="1" max="126" step="1" value="40">
</div>
<div id="TACAN-XY" class="ol-select">
<div class="ol-select-value">X</div>
<div class="ol-select-options">
</div>
</div>
<label>
Morse:
</label>
<div id="TACAN-callsign" class="ol-text-input">
<input type="text" maxlength="3" value="TKR" style="width: 50px">
</div>
</div>
</div>
<div class="ol-group">
<label> Radio frequency: </label>
<div class="ol-group">
<div id="radio-checkbox" class="ol-checkbox">
<label>
Radio frequency:
</label>
</div>
<div id="radio-mhz" class="ol-text-input">
<input type="number" min="1" max="999" step="1" value="260">
</div>
@ -167,12 +157,12 @@
</div>
</div>
</div>
</div>
<div class="ol-group">
<label> Radio callsign: </label>
<div class="ol-group">
<label>
Radio callsign:
</label>
<div id="radio-callsign" class="ol-select">
<div class="ol-select-value"></div>
<div class="ol-select-options">
@ -186,9 +176,8 @@
<div id="radio-callsign-number" class="ol-text-input">
<input type="number" min="1" max="999" step="1" value="1">
</div>
</div>
</form>
</div>
</div>
<div class="ol-dialog-footer ol-group">