Merge pull request #243 from Pax1601/209-update-follow-functionality-for-ordering-units
209 update follow functionality for ordering units
@@ -2,7 +2,7 @@
|
|||||||
const DEMO_UNIT_DATA = {
|
const DEMO_UNIT_DATA = {
|
||||||
["1"]:{
|
["1"]:{
|
||||||
baseData: {
|
baseData: {
|
||||||
AI: true,
|
AI: false,
|
||||||
name: "KC-135",
|
name: "KC-135",
|
||||||
unitName: "Olympus 1-1",
|
unitName: "Olympus 1-1",
|
||||||
groupName: "Group 1",
|
groupName: "Group 1",
|
||||||
@@ -18,7 +18,7 @@ const DEMO_UNIT_DATA = {
|
|||||||
},
|
},
|
||||||
missionData: {
|
missionData: {
|
||||||
fuel: 50,
|
fuel: 50,
|
||||||
flags: {human: true},
|
flags: {Human: false},
|
||||||
ammo: [
|
ammo: [
|
||||||
{
|
{
|
||||||
count: 4,
|
count: 4,
|
||||||
@@ -47,6 +47,7 @@ const DEMO_UNIT_DATA = {
|
|||||||
},
|
},
|
||||||
taskData: {
|
taskData: {
|
||||||
currentTask: "Holding",
|
currentTask: "Holding",
|
||||||
|
currentState: "Idle",
|
||||||
activePath: undefined,
|
activePath: undefined,
|
||||||
targetSpeed: 400,
|
targetSpeed: 400,
|
||||||
targetAltitude: 3000,
|
targetAltitude: 3000,
|
||||||
@@ -67,7 +68,7 @@ const DEMO_UNIT_DATA = {
|
|||||||
},
|
},
|
||||||
["2"]:{
|
["2"]:{
|
||||||
baseData: {
|
baseData: {
|
||||||
AI: false,
|
AI: true,
|
||||||
name: "KC-135",
|
name: "KC-135",
|
||||||
unitName: "Olympus 1-2",
|
unitName: "Olympus 1-2",
|
||||||
groupName: "Group 1",
|
groupName: "Group 1",
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 8.5 KiB |
@@ -392,8 +392,8 @@
|
|||||||
padding: var( --unit-aircraft-ammo-radius );
|
padding: var( --unit-aircraft-ammo-radius );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[data-object|="unit"] .unit-summary {
|
[data-object|="unit"] .unit-summary {
|
||||||
|
pointer-events: none;
|
||||||
column-gap: 6px;
|
column-gap: 6px;
|
||||||
color:white;
|
color:white;
|
||||||
display:flex;
|
display:flex;
|
||||||
@@ -438,14 +438,14 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
[data-object|="unit"][data-pilot|="ai"]:hover .unit-ammo,
|
[data-object|="unit"]:hover .unit-ammo,
|
||||||
[data-object|="unit"][data-pilot|="ai"]:hover .unit-fuel {
|
[data-object|="unit"]:hover .unit-fuel {
|
||||||
display:flex;
|
display:flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-object|="unit"][data-is-in-hotgroup] .unit-hotgroup,
|
[data-object|="unit"][data-is-in-hotgroup] .unit-hotgroup,
|
||||||
[data-object|="unit"][data-pilot|="ai"][data-is-selected] .unit-ammo,
|
[data-object|="unit"][data-is-selected] .unit-ammo,
|
||||||
[data-object|="unit"][data-pilot|="ai"][data-is-selected] .unit-fuel,
|
[data-object|="unit"][data-is-selected] .unit-fuel,
|
||||||
[data-object|="unit"][data-is-selected] .unit-selected-spotlight {
|
[data-object|="unit"][data-is-selected] .unit-selected-spotlight {
|
||||||
display:flex;
|
display:flex;
|
||||||
}
|
}
|
||||||
@@ -501,7 +501,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-object|="unit"][data-pilot|="ai"][data-has-low-fuel] .unit-fuel {
|
[data-object|="unit"][data-has-low-fuel] .unit-fuel {
|
||||||
animation: pulse 1.5s linear infinite;
|
animation: pulse 1.5s linear infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,83 @@
|
|||||||
<svg width="63" height="63" viewBox="0 0 63 63" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M31.4998 46.9756C40.0468 46.9756 46.9756 40.0468 46.9756 31.4998C46.9756 22.9528 40.0468 16.024 31.4998 16.024C22.9528 16.024 16.024 22.9528 16.024 31.4998C16.024 40.0468 22.9528 46.9756 31.4998 46.9756ZM31.4998 52.734C43.2271 52.734 52.734 43.2271 52.734 31.4998C52.734 19.7725 43.2271 10.2656 31.4998 10.2656C19.7725 10.2656 10.2656 19.7725 10.2656 31.4998C10.2656 43.2271 19.7725 52.734 31.4998 52.734Z" fill="white"/>
|
<svg
|
||||||
<path d="M35.3291 61L37.3291 61L37.3291 59L37.3291 49.2532L37.3291 47.2532L35.3291 47.2532L27.6709 47.2532L25.6709 47.2532L25.6709 49.2532L25.6709 59L25.6709 61L27.6709 61L35.3291 61Z" fill="#247BE2" stroke="white" stroke-width="4"/>
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
<path d="M47.2529 35.3291V37.3291H49.2529H58.9998H60.9998V35.3291V27.6709V25.6709L58.9998 25.6709H49.2529H47.2529V27.6709V35.3291Z" fill="#247BE2" stroke="white" stroke-width="4"/>
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
<path d="M35.3291 15.7471L37.3291 15.7471L37.3291 13.7471L37.3291 4.00023L37.3291 2.00023L35.3291 2.00023L27.6709 2.00023L25.6709 2.00023L25.6709 4.00023L25.6709 13.7471L25.6709 15.7471L27.6709 15.7471L35.3291 15.7471Z" fill="#247BE2" stroke="white" stroke-width="4"/>
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
<path d="M2 35.3291V37.3291H4H13.7468H15.7468V35.3291L15.7468 27.6709V25.6709L13.7468 25.6709H4H2V27.6709L2 35.3291Z" fill="#247BE2" stroke="white" stroke-width="4"/>
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
<circle cx="31.5001" cy="31.5001" r="15.4494" fill="white" stroke="#247BE2" stroke-width="6"/>
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
<line x1="25.7895" y1="23.9132" x2="36.5242" y2="38.6028" stroke="#247BE2" stroke-width="2" stroke-linecap="square"/>
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
<line x1="38.9357" y1="33.9313" x2="25.9313" y2="33.0643" stroke="#247BE2" stroke-width="2" stroke-linecap="square"/>
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||||
|
sodipodi:docname="icon_airbase_blue.svg"
|
||||||
|
id="svg18"
|
||||||
|
version="1.1"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 63 63"
|
||||||
|
height="63"
|
||||||
|
width="63">
|
||||||
|
<metadata
|
||||||
|
id="metadata24">
|
||||||
|
<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="defs22" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
inkscape:current-layer="svg18"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-x="1912"
|
||||||
|
inkscape:cy="31.5"
|
||||||
|
inkscape:cx="31.5"
|
||||||
|
inkscape:zoom="13.492063"
|
||||||
|
showgrid="false"
|
||||||
|
id="namedview20"
|
||||||
|
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
|
||||||
|
id="path2"
|
||||||
|
fill="white"
|
||||||
|
d="M31.4998 46.9756C40.0468 46.9756 46.9756 40.0468 46.9756 31.4998C46.9756 22.9528 40.0468 16.024 31.4998 16.024C22.9528 16.024 16.024 22.9528 16.024 31.4998C16.024 40.0468 22.9528 46.9756 31.4998 46.9756ZM31.4998 52.734C43.2271 52.734 52.734 43.2271 52.734 31.4998C52.734 19.7725 43.2271 10.2656 31.4998 10.2656C19.7725 10.2656 10.2656 19.7725 10.2656 31.4998C10.2656 43.2271 19.7725 52.734 31.4998 52.734Z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
fill-rule="evenodd" />
|
||||||
|
<circle
|
||||||
|
id="circle12"
|
||||||
|
stroke-width="6"
|
||||||
|
stroke="#247BE2"
|
||||||
|
fill="white"
|
||||||
|
r="15.4494"
|
||||||
|
cy="31.5001"
|
||||||
|
cx="31.5001" />
|
||||||
|
<line
|
||||||
|
id="line14"
|
||||||
|
stroke-linecap="square"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke="#247BE2"
|
||||||
|
y2="38.6028"
|
||||||
|
x2="36.5242"
|
||||||
|
y1="23.9132"
|
||||||
|
x1="25.7895" />
|
||||||
|
<line
|
||||||
|
id="line16"
|
||||||
|
stroke-linecap="square"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke="#247BE2"
|
||||||
|
y2="33.0643"
|
||||||
|
x2="25.9313"
|
||||||
|
y1="33.9313"
|
||||||
|
x1="38.9357" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.4 KiB |
@@ -1,10 +1,83 @@
|
|||||||
<svg width="63" height="63" viewBox="0 0 63 63" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M31.4998 46.9756C40.0468 46.9756 46.9756 40.0468 46.9756 31.4998C46.9756 22.9528 40.0468 16.024 31.4998 16.024C22.9528 16.024 16.024 22.9528 16.024 31.4998C16.024 40.0468 22.9528 46.9756 31.4998 46.9756ZM31.4998 52.734C43.2271 52.734 52.734 43.2271 52.734 31.4998C52.734 19.7725 43.2271 10.2656 31.4998 10.2656C19.7725 10.2656 10.2656 19.7725 10.2656 31.4998C10.2656 43.2271 19.7725 52.734 31.4998 52.734Z" fill="white"/>
|
<svg
|
||||||
<path d="M35.3291 61L37.3291 61L37.3291 59L37.3291 49.2532L37.3291 47.2532L35.3291 47.2532L27.6709 47.2532L25.6709 47.2532L25.6709 49.2532L25.6709 59L25.6709 61L27.6709 61L35.3291 61Z" fill="#CFD9E8" stroke="white" stroke-width="4"/>
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
<path d="M47.2529 35.3291V37.3291H49.2529H58.9998H60.9998V35.3291V27.6709V25.6709L58.9998 25.6709H49.2529H47.2529V27.6709V35.3291Z" fill="#CFD9E8" stroke="white" stroke-width="4"/>
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
<path d="M35.3291 15.7471L37.3291 15.7471L37.3291 13.7471L37.3291 4.00023L37.3291 2.00023L35.3291 2.00023L27.6709 2.00023L25.6709 2.00023L25.6709 4.00023L25.6709 13.7471L25.6709 15.7471L27.6709 15.7471L35.3291 15.7471Z" fill="#CFD9E8" stroke="white" stroke-width="4"/>
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
<path d="M2 35.3291V37.3291H4H13.7468H15.7468V35.3291L15.7468 27.6709V25.6709L13.7468 25.6709H4H2V27.6709L2 35.3291Z" fill="#CFD9E8" stroke="white" stroke-width="4"/>
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
<circle cx="31.5001" cy="31.5001" r="15.4494" fill="white" stroke="#CFD9E8" stroke-width="6"/>
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
<line x1="25.7895" y1="23.9132" x2="36.5242" y2="38.6028" stroke="#CFD9E8" stroke-width="2" stroke-linecap="square"/>
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
<line x1="38.9357" y1="33.9313" x2="25.9313" y2="33.0643" stroke="#CFD9E8" stroke-width="2" stroke-linecap="square"/>
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||||
|
sodipodi:docname="icon_airbase_neutral.svg"
|
||||||
|
id="svg18"
|
||||||
|
version="1.1"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 63 63"
|
||||||
|
height="63"
|
||||||
|
width="63">
|
||||||
|
<metadata
|
||||||
|
id="metadata24">
|
||||||
|
<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="defs22" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
inkscape:current-layer="svg18"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-x="1912"
|
||||||
|
inkscape:cy="31.5"
|
||||||
|
inkscape:cx="31.5"
|
||||||
|
inkscape:zoom="13.492063"
|
||||||
|
showgrid="false"
|
||||||
|
id="namedview20"
|
||||||
|
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
|
||||||
|
id="path2"
|
||||||
|
fill="white"
|
||||||
|
d="M31.4998 46.9756C40.0468 46.9756 46.9756 40.0468 46.9756 31.4998C46.9756 22.9528 40.0468 16.024 31.4998 16.024C22.9528 16.024 16.024 22.9528 16.024 31.4998C16.024 40.0468 22.9528 46.9756 31.4998 46.9756ZM31.4998 52.734C43.2271 52.734 52.734 43.2271 52.734 31.4998C52.734 19.7725 43.2271 10.2656 31.4998 10.2656C19.7725 10.2656 10.2656 19.7725 10.2656 31.4998C10.2656 43.2271 19.7725 52.734 31.4998 52.734Z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
fill-rule="evenodd" />
|
||||||
|
<circle
|
||||||
|
id="circle12"
|
||||||
|
stroke-width="6"
|
||||||
|
stroke="#CFD9E8"
|
||||||
|
fill="white"
|
||||||
|
r="15.4494"
|
||||||
|
cy="31.5001"
|
||||||
|
cx="31.5001" />
|
||||||
|
<line
|
||||||
|
id="line14"
|
||||||
|
stroke-linecap="square"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke="#CFD9E8"
|
||||||
|
y2="38.6028"
|
||||||
|
x2="36.5242"
|
||||||
|
y1="23.9132"
|
||||||
|
x1="25.7895" />
|
||||||
|
<line
|
||||||
|
id="line16"
|
||||||
|
stroke-linecap="square"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke="#CFD9E8"
|
||||||
|
y2="33.0643"
|
||||||
|
x2="25.9313"
|
||||||
|
y1="33.9313"
|
||||||
|
x1="38.9357" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.4 KiB |
@@ -1,10 +1,83 @@
|
|||||||
<svg width="63" height="63" viewBox="0 0 63 63" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M31.4998 46.9756C40.0468 46.9756 46.9756 40.0468 46.9756 31.4998C46.9756 22.9528 40.0468 16.024 31.4998 16.024C22.9528 16.024 16.024 22.9528 16.024 31.4998C16.024 40.0468 22.9528 46.9756 31.4998 46.9756ZM31.4998 52.734C43.2271 52.734 52.734 43.2271 52.734 31.4998C52.734 19.7725 43.2271 10.2656 31.4998 10.2656C19.7725 10.2656 10.2656 19.7725 10.2656 31.4998C10.2656 43.2271 19.7725 52.734 31.4998 52.734Z" fill="white"/>
|
<svg
|
||||||
<path d="M35.3291 61L37.3291 61L37.3291 59L37.3291 49.2532L37.3291 47.2532L35.3291 47.2532L27.6709 47.2532L25.6709 47.2532L25.6709 49.2532L25.6709 59L25.6709 61L27.6709 61L35.3291 61Z" fill="#ff5858" stroke="white" stroke-width="4"/>
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
<path d="M47.2529 35.3291V37.3291H49.2529H58.9998H60.9998V35.3291V27.6709V25.6709L58.9998 25.6709H49.2529H47.2529V27.6709V35.3291Z" fill="#ff5858" stroke="white" stroke-width="4"/>
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
<path d="M35.3291 15.7471L37.3291 15.7471L37.3291 13.7471L37.3291 4.00023L37.3291 2.00023L35.3291 2.00023L27.6709 2.00023L25.6709 2.00023L25.6709 4.00023L25.6709 13.7471L25.6709 15.7471L27.6709 15.7471L35.3291 15.7471Z" fill="#ff5858" stroke="white" stroke-width="4"/>
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
<path d="M2 35.3291V37.3291H4H13.7468H15.7468V35.3291L15.7468 27.6709V25.6709L13.7468 25.6709H4H2V27.6709L2 35.3291Z" fill="#ff5858" stroke="white" stroke-width="4"/>
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
<circle cx="31.5001" cy="31.5001" r="15.4494" fill="white" stroke="#ff5858" stroke-width="6"/>
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
<line x1="25.7895" y1="23.9132" x2="36.5242" y2="38.6028" stroke="#ff5858" stroke-width="2" stroke-linecap="square"/>
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
<line x1="38.9357" y1="33.9313" x2="25.9313" y2="33.0643" stroke="#ff5858" stroke-width="2" stroke-linecap="square"/>
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||||
|
sodipodi:docname="icon_airbase_red.svg"
|
||||||
|
id="svg18"
|
||||||
|
version="1.1"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 63 63"
|
||||||
|
height="63"
|
||||||
|
width="63">
|
||||||
|
<metadata
|
||||||
|
id="metadata24">
|
||||||
|
<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="defs22" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
inkscape:current-layer="svg18"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-x="1912"
|
||||||
|
inkscape:cy="31.5"
|
||||||
|
inkscape:cx="31.5"
|
||||||
|
inkscape:zoom="13.492063"
|
||||||
|
showgrid="false"
|
||||||
|
id="namedview20"
|
||||||
|
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
|
||||||
|
id="path2"
|
||||||
|
fill="white"
|
||||||
|
d="M31.4998 46.9756C40.0468 46.9756 46.9756 40.0468 46.9756 31.4998C46.9756 22.9528 40.0468 16.024 31.4998 16.024C22.9528 16.024 16.024 22.9528 16.024 31.4998C16.024 40.0468 22.9528 46.9756 31.4998 46.9756ZM31.4998 52.734C43.2271 52.734 52.734 43.2271 52.734 31.4998C52.734 19.7725 43.2271 10.2656 31.4998 10.2656C19.7725 10.2656 10.2656 19.7725 10.2656 31.4998C10.2656 43.2271 19.7725 52.734 31.4998 52.734Z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
fill-rule="evenodd" />
|
||||||
|
<circle
|
||||||
|
id="circle12"
|
||||||
|
stroke-width="6"
|
||||||
|
stroke="#ff5858"
|
||||||
|
fill="white"
|
||||||
|
r="15.4494"
|
||||||
|
cy="31.5001"
|
||||||
|
cx="31.5001" />
|
||||||
|
<line
|
||||||
|
id="line14"
|
||||||
|
stroke-linecap="square"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke="#ff5858"
|
||||||
|
y2="38.6028"
|
||||||
|
x2="36.5242"
|
||||||
|
y1="23.9132"
|
||||||
|
x1="25.7895" />
|
||||||
|
<line
|
||||||
|
id="line16"
|
||||||
|
stroke-linecap="square"
|
||||||
|
stroke-width="2"
|
||||||
|
stroke="#ff5858"
|
||||||
|
y2="33.0643"
|
||||||
|
x2="25.9313"
|
||||||
|
y1="33.9313"
|
||||||
|
x1="38.9357" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.4 KiB |
1256
client/public/themes/olympus/images/task_tanker.svg
Normal file
|
After Width: | Height: | Size: 91 KiB |
4
client/src/@types/unit.d.ts
vendored
@@ -29,11 +29,7 @@ interface MissionData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface FormationData {
|
interface FormationData {
|
||||||
formation: string;
|
|
||||||
isLeader: boolean;
|
|
||||||
isWingman: boolean;
|
|
||||||
leaderID: number;
|
leaderID: number;
|
||||||
wingmenIDs: number[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TaskData {
|
interface TaskData {
|
||||||
|
|||||||
@@ -381,57 +381,6 @@ export class HelicopterDatabase extends UnitDatabase {
|
|||||||
],
|
],
|
||||||
"filename": "ah-1.png"
|
"filename": "ah-1.png"
|
||||||
},
|
},
|
||||||
"AH-1W": {
|
|
||||||
"name": "AH-1W",
|
|
||||||
"label": "AH-1W Cobra",
|
|
||||||
"shortLabel": "AH1",
|
|
||||||
"loadouts": [
|
|
||||||
{
|
|
||||||
"fuel": 1,
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "BGM-71 TOW",
|
|
||||||
"quantity": 8
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Hydra-70 WP",
|
|
||||||
"quantity": 38
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"roles": [
|
|
||||||
"CAS"
|
|
||||||
],
|
|
||||||
"code": "8xBGM-71, 38xHYDRA-70 WP",
|
|
||||||
"name": "TOW / Hydra"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fuel": 1,
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "Hydra-70",
|
|
||||||
"quantity": 76
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"roles": [
|
|
||||||
"CAS"
|
|
||||||
],
|
|
||||||
"code": "76xHYDRA-70",
|
|
||||||
"name": "Hydra"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"fuel": 1,
|
|
||||||
"items": [
|
|
||||||
|
|
||||||
],
|
|
||||||
"roles": [
|
|
||||||
""
|
|
||||||
],
|
|
||||||
"code": "",
|
|
||||||
"name": "Empty Loadout"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"filename": "ah-1.png"
|
|
||||||
},
|
|
||||||
"Mi-26": {
|
"Mi-26": {
|
||||||
"name": "Mi-26",
|
"name": "Mi-26",
|
||||||
"label": "Mi-26 Halo",
|
"label": "Mi-26 Halo",
|
||||||
|
|||||||
@@ -40,11 +40,7 @@ export class Unit extends Marker {
|
|||||||
coalition: "",
|
coalition: "",
|
||||||
},
|
},
|
||||||
formationData: {
|
formationData: {
|
||||||
formation: "",
|
leaderID: 0
|
||||||
isLeader: false,
|
|
||||||
isWingman: false,
|
|
||||||
leaderID: 0,
|
|
||||||
wingmenIDs: [],
|
|
||||||
},
|
},
|
||||||
taskData: {
|
taskData: {
|
||||||
currentState: "IDLE",
|
currentState: "IDLE",
|
||||||
@@ -71,6 +67,7 @@ export class Unit extends Marker {
|
|||||||
|
|
||||||
#selectable: boolean;
|
#selectable: boolean;
|
||||||
#selected: boolean = false;
|
#selected: boolean = false;
|
||||||
|
#hovered: boolean = false;
|
||||||
#hidden: boolean = false;
|
#hidden: boolean = false;
|
||||||
|
|
||||||
#preventClick: boolean = false;
|
#preventClick: boolean = false;
|
||||||
@@ -81,7 +78,6 @@ export class Unit extends Marker {
|
|||||||
#miniMapMarker: CircleMarker | null = null;
|
#miniMapMarker: CircleMarker | null = null;
|
||||||
|
|
||||||
#timer: number = 0;
|
#timer: number = 0;
|
||||||
#forceUpdate: boolean = false;
|
|
||||||
|
|
||||||
static getConstructor(type: string) {
|
static getConstructor(type: string) {
|
||||||
if (type === "GroundUnit") return GroundUnit;
|
if (type === "GroundUnit") return GroundUnit;
|
||||||
@@ -102,6 +98,8 @@ export class Unit extends Marker {
|
|||||||
this.on('click', (e) => this.#onClick(e));
|
this.on('click', (e) => this.#onClick(e));
|
||||||
this.on('dblclick', (e) => this.#onDoubleClick(e));
|
this.on('dblclick', (e) => this.#onDoubleClick(e));
|
||||||
this.on('contextmenu', (e) => this.#onContextMenu(e));
|
this.on('contextmenu', (e) => this.#onContextMenu(e));
|
||||||
|
this.on('mouseover', () => { this.#hovered = true;})
|
||||||
|
this.on('mouseout', () => { this.#hovered = false;})
|
||||||
|
|
||||||
this.#pathPolyline = new Polyline([], { color: '#2d3e50', weight: 3, opacity: 0.5, smoothFactor: 1 });
|
this.#pathPolyline = new Polyline([], { color: '#2d3e50', weight: 3, opacity: 0.5, smoothFactor: 1 });
|
||||||
this.#pathPolyline.addTo(getMap());
|
this.#pathPolyline.addTo(getMap());
|
||||||
@@ -123,7 +121,8 @@ export class Unit extends Marker {
|
|||||||
var icon = new DivIcon({
|
var icon = new DivIcon({
|
||||||
html: this.getMarkerHTML(),
|
html: this.getMarkerHTML(),
|
||||||
className: 'leaflet-unit-marker',
|
className: 'leaflet-unit-marker',
|
||||||
iconAnchor: [0, 0]
|
iconAnchor: [25, 0],
|
||||||
|
iconSize: [50, 50],
|
||||||
});
|
});
|
||||||
this.setIcon(icon);
|
this.setIcon(icon);
|
||||||
}
|
}
|
||||||
@@ -143,13 +142,11 @@ export class Unit extends Marker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setData(data: UpdateData) {
|
setData(data: UpdateData) {
|
||||||
var updateMarker = false;
|
/* Check if data has changed comparing new values to old values */
|
||||||
|
const positionChanged = (data.flightData.latitude != undefined && data.flightData.longitude != undefined && (this.getFlightData().latitude != data.flightData.latitude || this.getFlightData().longitude != data.flightData.longitude));
|
||||||
if ((data.flightData.latitude != undefined && data.flightData.longitude != undefined && (this.getFlightData().latitude != data.flightData.latitude || this.getFlightData().longitude != data.flightData.longitude))
|
const headingChanged = (data.flightData.heading != undefined && this.getFlightData().heading != data.flightData.heading);
|
||||||
|| (data.flightData.heading != undefined && this.getFlightData().heading != data.flightData.heading)
|
const aliveChanged = (data.baseData.alive != undefined && this.getBaseData().alive != data.baseData.alive);
|
||||||
|| (data.baseData.alive != undefined && this.getBaseData().alive != data.baseData.alive)
|
var updateMarker = (positionChanged || headingChanged || aliveChanged || !getMap().hasLayer(this))
|
||||||
|| this.#forceUpdate || !getMap().hasLayer(this))
|
|
||||||
updateMarker = true;
|
|
||||||
|
|
||||||
if (data.baseData != undefined)
|
if (data.baseData != undefined)
|
||||||
{
|
{
|
||||||
@@ -314,38 +311,18 @@ export class Unit extends Marker {
|
|||||||
return getUnitsManager().getUnitByID(this.getFormationData().leaderID);
|
return getUnitsManager().getUnitByID(this.getFormationData().leaderID);
|
||||||
}
|
}
|
||||||
|
|
||||||
getFormation() {
|
|
||||||
return [<Unit>this].concat(this.getWingmen())
|
|
||||||
}
|
|
||||||
|
|
||||||
getWingmen() {
|
|
||||||
var wingmen: Unit[] = [];
|
|
||||||
if (this.getFormationData().wingmenIDs != undefined) {
|
|
||||||
for (let ID of this.getFormationData().wingmenIDs) {
|
|
||||||
var unit = getUnitsManager().getUnitByID(ID)
|
|
||||||
if (unit)
|
|
||||||
wingmen.push(unit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return wingmen;
|
|
||||||
}
|
|
||||||
|
|
||||||
attackUnit(targetID: number) {
|
attackUnit(targetID: number) {
|
||||||
|
/* Units can't attack themselves */
|
||||||
if (this.ID != targetID) {
|
if (this.ID != targetID) {
|
||||||
attackUnit(this.ID, targetID);
|
attackUnit(this.ID, targetID);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// TODO: show a message
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
followUnit(targetID: number, offset: {"x": number, "y": number, "z": number}) {
|
followUnit(targetID: number, offset: {"x": number, "y": number, "z": number}) {
|
||||||
|
/* Units can't follow themselves */
|
||||||
if (this.ID != targetID) {
|
if (this.ID != targetID) {
|
||||||
followUnit(this.ID, targetID, offset);
|
followUnit(this.ID, targetID, offset);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// TODO: show a message
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
landAt(latlng: LatLng) {
|
landAt(latlng: LatLng) {
|
||||||
@@ -399,7 +376,7 @@ export class Unit extends Marker {
|
|||||||
if (!e.originalEvent.ctrlKey) {
|
if (!e.originalEvent.ctrlKey) {
|
||||||
getUnitsManager().deselectAllUnits();
|
getUnitsManager().deselectAllUnits();
|
||||||
}
|
}
|
||||||
this.setSelected(true);
|
this.setSelected(!this.getSelected());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.#preventClick = false;
|
this.#preventClick = false;
|
||||||
@@ -416,12 +393,11 @@ export class Unit extends Marker {
|
|||||||
|
|
||||||
options["Center"] = `<div id="center-map">Center map</div>`;
|
options["Center"] = `<div id="center-map">Center map</div>`;
|
||||||
|
|
||||||
if (getUnitsManager().getSelectedUnits().length > 0 && !(getUnitsManager().getSelectedUnits().includes(this)))
|
if (getUnitsManager().getSelectedUnits().length > 0 && !(getUnitsManager().getSelectedUnits().length == 1 && (getUnitsManager().getSelectedUnits().includes(this))))
|
||||||
{
|
{
|
||||||
options = {
|
options['Attack'] = `<div id="attack">Attack</div>`;
|
||||||
'Attack': `<div id="attack">Attack</div>`,
|
if (getUnitsManager().getSelectedUnitsType() === "Aircraft")
|
||||||
'Follow': `<div id="follow">Follow</div>`,
|
options['Follow'] = `<div id="follow">Follow</div>`;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if ((getUnitsManager().getSelectedUnits().length > 0 && (getUnitsManager().getSelectedUnits().includes(this))) || getUnitsManager().getSelectedUnits().length == 0)
|
else if ((getUnitsManager().getSelectedUnits().length > 0 && (getUnitsManager().getSelectedUnits().includes(this))) || getUnitsManager().getSelectedUnits().length == 0)
|
||||||
{
|
{
|
||||||
@@ -487,30 +463,12 @@ export class Unit extends Marker {
|
|||||||
// Z: left-right, positive right
|
// Z: left-right, positive right
|
||||||
|
|
||||||
var offset = {"x": 0, "y": 0, "z": 0};
|
var offset = {"x": 0, "y": 0, "z": 0};
|
||||||
if (action == "Trail")
|
if (action == "Trail") { offset.x = -50; offset.y = -30; offset.z = 0; }
|
||||||
{
|
else if (action == "Echelon (LH)") { offset.x = -50; offset.y = -10; offset.z = -50; }
|
||||||
offset.x = -50; offset.y = -30; offset.z = 0;
|
else if (action == "Echelon (RH)") { offset.x = -50; offset.y = -10; offset.z = 50; }
|
||||||
}
|
else if (action == "Line abreast (RH)") { offset.x = 0; offset.y = 0; offset.z = 50; }
|
||||||
else if (action == "Echelon (LH)")
|
else if (action == "Line abreast (LH)") { offset.x = 0; offset.y = 0; offset.z = -50; }
|
||||||
{
|
else if (action == "Front") { offset.x = 100; offset.y = 0; offset.z = 0; }
|
||||||
offset.x = -50; offset.y = -10; offset.z = -50;
|
|
||||||
}
|
|
||||||
else if (action == "Echelon (RH)")
|
|
||||||
{
|
|
||||||
offset.x = -50; offset.y = -10; offset.z = 50;
|
|
||||||
}
|
|
||||||
else if (action == "Line abreast (RH)")
|
|
||||||
{
|
|
||||||
offset.x = 0; offset.y = 0; offset.z = 50;
|
|
||||||
}
|
|
||||||
else if (action == "Line abreast (LH)")
|
|
||||||
{
|
|
||||||
offset.x = 0; offset.y = 0; offset.z = -50;
|
|
||||||
}
|
|
||||||
else if (action == "Front")
|
|
||||||
{
|
|
||||||
offset.x = 100; offset.y = 0; offset.z = 0;
|
|
||||||
}
|
|
||||||
getUnitsManager().selectedUnitsFollowUnit(this.ID, offset);
|
getUnitsManager().selectedUnitsFollowUnit(this.ID, offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -518,6 +476,7 @@ export class Unit extends Marker {
|
|||||||
#updateMarker() {
|
#updateMarker() {
|
||||||
this.updateVisibility();
|
this.updateVisibility();
|
||||||
|
|
||||||
|
/* Draw the minimap marker */
|
||||||
if (this.getBaseData().alive )
|
if (this.getBaseData().alive )
|
||||||
{
|
{
|
||||||
if (this.#miniMapMarker == null)
|
if (this.#miniMapMarker == null)
|
||||||
@@ -544,47 +503,47 @@ export class Unit extends Marker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Draw the marker */
|
||||||
if (!this.getHidden()) {
|
if (!this.getHidden()) {
|
||||||
this.setLatLng(new LatLng(this.getFlightData().latitude, this.getFlightData().longitude));
|
this.setLatLng(new LatLng(this.getFlightData().latitude, this.getFlightData().longitude));
|
||||||
|
|
||||||
var element = this.getElement();
|
var element = this.getElement();
|
||||||
if (element != null) {
|
if (element != null) {
|
||||||
|
/* Draw the velocity vector */
|
||||||
element.querySelector(".unit-vvi")?.setAttribute("style", `height: ${15 + this.getFlightData().speed / 5}px;`);
|
element.querySelector(".unit-vvi")?.setAttribute("style", `height: ${15 + this.getFlightData().speed / 5}px;`);
|
||||||
element.querySelector(".unit")?.setAttribute("data-pilot", this.getMissionData().flags.human? "human": "ai");
|
|
||||||
|
|
||||||
|
/* Set fuel data */
|
||||||
element.querySelector(".unit-fuel-level")?.setAttribute("style", `width: ${this.getMissionData().fuel}%`);
|
element.querySelector(".unit-fuel-level")?.setAttribute("style", `width: ${this.getMissionData().fuel}%`);
|
||||||
element.querySelector(".unit")?.toggleAttribute("data-has-low-fuel", this.getMissionData().fuel < 20);
|
element.querySelector(".unit")?.toggleAttribute("data-has-low-fuel", this.getMissionData().fuel < 20);
|
||||||
|
|
||||||
|
/* Set dead/alive flag */
|
||||||
element.querySelector(".unit")?.toggleAttribute("data-is-dead", !this.getBaseData().alive);
|
element.querySelector(".unit")?.toggleAttribute("data-is-dead", !this.getBaseData().alive);
|
||||||
|
|
||||||
if (this.getMissionData().flags.Human) // Unit is human
|
/* Set current unit state */
|
||||||
|
if (this.getMissionData().flags.Human) // Unit is human
|
||||||
element.querySelector(".unit")?.setAttribute("data-state", "human");
|
element.querySelector(".unit")?.setAttribute("data-state", "human");
|
||||||
else if (!this.getBaseData().AI) // Unit is under DCS control (no Olympus)
|
else if (!this.getBaseData().AI) // Unit is under DCS control (not Olympus)
|
||||||
element.querySelector(".unit")?.setAttribute("data-state", "dcs");
|
element.querySelector(".unit")?.setAttribute("data-state", "dcs");
|
||||||
else // Unit is under Olympus control
|
else // Unit is under Olympus control
|
||||||
element.querySelector(".unit")?.setAttribute("data-state", this.getTaskData().currentState.toLowerCase());
|
element.querySelector(".unit")?.setAttribute("data-state", this.getTaskData().currentState.toLowerCase());
|
||||||
|
|
||||||
var unitAltitudeDiv = element.querySelector(".unit-altitude");
|
/* Set altitude and speed */
|
||||||
if (unitAltitudeDiv != null)
|
if (element.querySelector(".unit-altitude"))
|
||||||
unitAltitudeDiv.innerHTML = "FL" + String(Math.floor(this.getFlightData().altitude / 0.3048 / 1000));
|
(<HTMLElement> element.querySelector(".unit-altitude")).innerText = "FL" + String(Math.floor(this.getFlightData().altitude / 0.3048 / 1000));
|
||||||
|
if (element.querySelector(".unit-speed"))
|
||||||
var unitSpeedDiv = element.querySelector(".unit-speed");
|
(<HTMLElement> element.querySelector(".unit-speed")).innerHTML = String(Math.floor(this.getFlightData().speed * 1.94384 ) );
|
||||||
if (unitSpeedDiv != null)
|
|
||||||
unitSpeedDiv.innerHTML = String(Math.floor(this.getFlightData().speed * 1.94384 ) );
|
|
||||||
|
|
||||||
|
/* Rotate elements according to heading */
|
||||||
element.querySelectorAll( "[data-rotate-to-heading]" ).forEach( el => {
|
element.querySelectorAll( "[data-rotate-to-heading]" ).forEach( el => {
|
||||||
const headingDeg = rad2deg( this.getFlightData().heading );
|
const headingDeg = rad2deg( this.getFlightData().heading );
|
||||||
let currentStyle = el.getAttribute( "style" ) || "";
|
let currentStyle = el.getAttribute( "style" ) || "";
|
||||||
el.setAttribute( "style", currentStyle + `transform:rotate(${headingDeg}deg);` );
|
el.setAttribute( "style", currentStyle + `transform:rotate(${headingDeg}deg);` );
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
/* Set vertical offset for altitude stacking */
|
||||||
var pos = getMap().latLngToLayerPoint(this.getLatLng()).round();
|
var pos = getMap().latLngToLayerPoint(this.getLatLng()).round();
|
||||||
this.setZIndexOffset(1000 + Math.floor(this.getFlightData().altitude) - pos.y);
|
this.setZIndexOffset(1000 + Math.floor(this.getFlightData().altitude) - pos.y + (this.#hovered || this.#selected? 5000: 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#forceUpdate = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#drawPath() {
|
#drawPath() {
|
||||||
@@ -643,7 +602,7 @@ export class Unit extends Marker {
|
|||||||
color = "#00FF00";
|
color = "#00FF00";
|
||||||
else
|
else
|
||||||
color = "#FFFFFF";
|
color = "#FFFFFF";
|
||||||
var targetPolyline = new Polyline([startLatLng, endLatLng], { color: color, weight: 3, opacity: 1, smoothFactor: 1 });
|
var targetPolyline = new Polyline([startLatLng, endLatLng], { color: color, weight: 3, opacity: 0.4, smoothFactor: 1 });
|
||||||
targetPolyline.addTo(getMap());
|
targetPolyline.addTo(getMap());
|
||||||
this.#targetsPolylines.push(targetPolyline)
|
this.#targetsPolylines.push(targetPolyline)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,35 +119,7 @@ export class UnitsManager {
|
|||||||
this.#units[ID].setSelected(false);
|
this.#units[ID].setSelected(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getSelectedLeaders() {
|
|
||||||
var leaders: Unit[] = [];
|
|
||||||
for (let idx in this.getSelectedUnits())
|
|
||||||
{
|
|
||||||
var unit = this.getSelectedUnits()[idx];
|
|
||||||
if (unit.getFormationData().isLeader)
|
|
||||||
leaders.push(unit);
|
|
||||||
else if (unit.getFormationData().isWingman)
|
|
||||||
{
|
|
||||||
var leader = unit.getLeader();
|
|
||||||
if (leader && !leaders.includes(leader))
|
|
||||||
leaders.push(leader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return leaders;
|
|
||||||
}
|
|
||||||
|
|
||||||
getSelectedSingletons() {
|
|
||||||
var singletons: Unit[] = [];
|
|
||||||
for (let idx in this.getSelectedUnits())
|
|
||||||
{
|
|
||||||
var unit = this.getSelectedUnits()[idx];
|
|
||||||
if (!unit.getFormationData().isLeader && !unit.getFormationData().isWingman)
|
|
||||||
singletons.push(unit);
|
|
||||||
}
|
|
||||||
return singletons;
|
|
||||||
}
|
|
||||||
|
|
||||||
getSelectedUnitsType () {
|
getSelectedUnitsType () {
|
||||||
if (this.getSelectedUnits().length == 0)
|
if (this.getSelectedUnits().length == 0)
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -191,8 +163,17 @@ export class UnitsManager {
|
|||||||
selectedUnitsAddDestination(latlng: L.LatLng) {
|
selectedUnitsAddDestination(latlng: L.LatLng) {
|
||||||
var selectedUnits = this.getSelectedUnits();
|
var selectedUnits = this.getSelectedUnits();
|
||||||
for (let idx in selectedUnits) {
|
for (let idx in selectedUnits) {
|
||||||
var commandedUnit = selectedUnits[idx];
|
const unit = selectedUnits[idx];
|
||||||
commandedUnit.addDestination(latlng);
|
if (unit.getTaskData().currentState === "Follow")
|
||||||
|
{
|
||||||
|
const leader = this.getUnitByID(unit.getFormationData().leaderID)
|
||||||
|
if (leader && leader.getSelected())
|
||||||
|
leader.addDestination(latlng);
|
||||||
|
else
|
||||||
|
unit.addDestination(latlng);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
unit.addDestination(latlng);
|
||||||
}
|
}
|
||||||
this.#showActionMessage(selectedUnits, " new destination added");
|
this.#showActionMessage(selectedUnits, " new destination added");
|
||||||
}
|
}
|
||||||
@@ -200,8 +181,17 @@ export class UnitsManager {
|
|||||||
selectedUnitsClearDestinations() {
|
selectedUnitsClearDestinations() {
|
||||||
var selectedUnits = this.getSelectedUnits();
|
var selectedUnits = this.getSelectedUnits();
|
||||||
for (let idx in selectedUnits) {
|
for (let idx in selectedUnits) {
|
||||||
var commandedUnit = selectedUnits[idx];
|
const unit = selectedUnits[idx];
|
||||||
commandedUnit.clearDestinations();
|
if (unit.getTaskData().currentState === "Follow")
|
||||||
|
{
|
||||||
|
const leader = this.getUnitByID(unit.getFormationData().leaderID)
|
||||||
|
if (leader && leader.getSelected())
|
||||||
|
leader.clearDestinations();
|
||||||
|
else
|
||||||
|
unit.clearDestinations();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
unit.clearDestinations();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ protected:
|
|||||||
virtual void setState(int newState);
|
virtual void setState(int newState);
|
||||||
bool isDestinationReached();
|
bool isDestinationReached();
|
||||||
bool setActiveDestination();
|
bool setActiveDestination();
|
||||||
void createHoldingPattern();
|
|
||||||
bool updateActivePath(bool looping);
|
bool updateActivePath(bool looping);
|
||||||
void goToDestination(wstring enrouteTask = L"nil");
|
void goToDestination(wstring enrouteTask = L"nil");
|
||||||
};
|
};
|
||||||
@@ -79,17 +79,9 @@ public:
|
|||||||
json::value getFlags() { return flags; }
|
json::value getFlags() { return flags; }
|
||||||
|
|
||||||
/********** Formation data **********/
|
/********** Formation data **********/
|
||||||
void setIsLeader(bool newIsLeader);
|
void setLeaderID(int newLeaderID) { leaderID = newLeaderID; addMeasure(L"leaderID", json::value(newLeaderID)); }
|
||||||
void setIsWingman(bool newIsWingman);
|
|
||||||
void setLeader(Unit* newLeader);
|
|
||||||
void setWingmen(vector<Unit*> newWingmen);
|
|
||||||
void setFormation(wstring newFormation) { formation = newFormation; addMeasure(L"formation", json::value(formation));}
|
|
||||||
void setFormationOffset(Offset formationOffset);
|
void setFormationOffset(Offset formationOffset);
|
||||||
bool getIsLeader() { return isLeader; }
|
int getLeaderID() { return leaderID; }
|
||||||
bool getIsWingman() { return isWingman; }
|
|
||||||
Unit* getLeader() { return leader; }
|
|
||||||
vector<Unit*> getWingmen() { return wingmen; }
|
|
||||||
wstring getFormation() { return formation; }
|
|
||||||
Offset getFormationoffset() { return formationOffset; }
|
Offset getFormationoffset() { return formationOffset; }
|
||||||
|
|
||||||
/********** Task data **********/
|
/********** Task data **********/
|
||||||
@@ -177,11 +169,7 @@ protected:
|
|||||||
json::value flags = json::value::null();
|
json::value flags = json::value::null();
|
||||||
|
|
||||||
/********** Formation data **********/
|
/********** Formation data **********/
|
||||||
bool isLeader = false;
|
int leaderID = NULL;
|
||||||
bool isWingman = false;
|
|
||||||
wstring formation = L"";
|
|
||||||
Unit *leader = nullptr;
|
|
||||||
vector<Unit *> wingmen;
|
|
||||||
Offset formationOffset = Offset(NULL);
|
Offset formationOffset = Offset(NULL);
|
||||||
|
|
||||||
/********** Task data **********/
|
/********** Task data **********/
|
||||||
@@ -215,7 +203,9 @@ protected:
|
|||||||
/********** Functions **********/
|
/********** Functions **********/
|
||||||
virtual wstring getCategory() { return L"No category"; };
|
virtual wstring getCategory() { return L"No category"; };
|
||||||
wstring getTargetName();
|
wstring getTargetName();
|
||||||
|
wstring getLeaderName();
|
||||||
bool isTargetAlive();
|
bool isTargetAlive();
|
||||||
|
bool isLeaderAlive();
|
||||||
virtual void AIloop() = 0;
|
virtual void AIloop() = 0;
|
||||||
void addMeasure(wstring key, json::value value);
|
void addMeasure(wstring key, json::value value);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ void AirUnit::setState(int newState)
|
|||||||
{
|
{
|
||||||
if (state != newState)
|
if (state != newState)
|
||||||
{
|
{
|
||||||
/* Perform any action required when LEAVING a certain state */
|
/************ Perform any action required when LEAVING a certain state ************/
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case State::IDLE: {
|
case State::IDLE: {
|
||||||
break;
|
break;
|
||||||
@@ -35,6 +35,7 @@ void AirUnit::setState(int newState)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case State::FOLLOW: {
|
case State::FOLLOW: {
|
||||||
|
setLeaderID(NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case State::LAND: {
|
case State::LAND: {
|
||||||
@@ -47,7 +48,7 @@ void AirUnit::setState(int newState)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform any action required when ENTERING a certain state */
|
/************ Perform any action required when ENTERING a certain state ************/
|
||||||
switch (newState) {
|
switch (newState) {
|
||||||
case State::IDLE: {
|
case State::IDLE: {
|
||||||
clearActivePath();
|
clearActivePath();
|
||||||
@@ -135,23 +136,6 @@ bool AirUnit::setActiveDestination()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AirUnit::createHoldingPattern()
|
|
||||||
{
|
|
||||||
/* Air units must ALWAYS have a destination or they will RTB and become uncontrollable */
|
|
||||||
clearActivePath();
|
|
||||||
Coords point1;
|
|
||||||
Coords point2;
|
|
||||||
Coords point3;
|
|
||||||
Geodesic::WGS84().Direct(latitude, longitude, 45, 10000, point1.lat, point1.lng);
|
|
||||||
Geodesic::WGS84().Direct(point1.lat, point1.lng, 135, 10000, point2.lat, point2.lng);
|
|
||||||
Geodesic::WGS84().Direct(point2.lat, point2.lng, 225, 10000, point3.lat, point3.lng);
|
|
||||||
pushActivePathBack(point1);
|
|
||||||
pushActivePathBack(point2);
|
|
||||||
pushActivePathBack(point3);
|
|
||||||
pushActivePathBack(Coords(latitude, longitude));
|
|
||||||
log(unitName + L" holding pattern created");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AirUnit::updateActivePath(bool looping)
|
bool AirUnit::updateActivePath(bool looping)
|
||||||
{
|
{
|
||||||
if (activePath.size() > 0)
|
if (activePath.size() > 0)
|
||||||
@@ -282,22 +266,22 @@ void AirUnit::AIloop()
|
|||||||
clearActivePath();
|
clearActivePath();
|
||||||
activeDestination = Coords(NULL);
|
activeDestination = Coords(NULL);
|
||||||
|
|
||||||
/* If the target is not alive (either not set or was destroyed) go back to IDLE */
|
/* If the leader is not alive (either not set or was destroyed) go back to IDLE */
|
||||||
if (!isTargetAlive()) {
|
if (!isLeaderAlive()) {
|
||||||
setState(State::IDLE);
|
setState(State::IDLE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentTask = L"Following " + getTargetName();
|
currentTask = L"Following " + getTargetName();
|
||||||
|
|
||||||
Unit* target = unitsManager->getUnit(targetID);
|
Unit* leader = unitsManager->getUnit(leaderID);
|
||||||
if (!hasTask) {
|
if (!hasTask) {
|
||||||
if (target != nullptr && target->getAlive() && formationOffset != NULL)
|
if (leader != nullptr && leader->getAlive() && formationOffset != NULL)
|
||||||
{
|
{
|
||||||
std::wostringstream taskSS;
|
std::wostringstream taskSS;
|
||||||
taskSS << "{"
|
taskSS << "{"
|
||||||
<< "id = 'FollowUnit'" << ", "
|
<< "id = 'FollowUnit'" << ", "
|
||||||
<< "leaderID = " << target->getID() << ","
|
<< "leaderID = " << leader->getID() << ","
|
||||||
<< "offset = {"
|
<< "offset = {"
|
||||||
<< "x = " << formationOffset.x << ","
|
<< "x = " << formationOffset.x << ","
|
||||||
<< "y = " << formationOffset.y << ","
|
<< "y = " << formationOffset.y << ","
|
||||||
@@ -332,5 +316,6 @@ void AirUnit::AIloop()
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
addMeasure(L"currentTask", json::value(currentTask));
|
addMeasure(L"currentTask", json::value(currentTask));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,30 +145,30 @@ void Scheduler::handleRequest(wstring key, json::value value)
|
|||||||
else if (key.compare(L"followUnit") == 0)
|
else if (key.compare(L"followUnit") == 0)
|
||||||
{
|
{
|
||||||
int ID = value[L"ID"].as_integer();
|
int ID = value[L"ID"].as_integer();
|
||||||
int targetID = value[L"targetID"].as_integer();
|
int leaderID = value[L"targetID"].as_integer();
|
||||||
int offsetX = value[L"offsetX"].as_integer();
|
int offsetX = value[L"offsetX"].as_integer();
|
||||||
int offsetY = value[L"offsetY"].as_integer();
|
int offsetY = value[L"offsetY"].as_integer();
|
||||||
int offsetZ = value[L"offsetZ"].as_integer();
|
int offsetZ = value[L"offsetZ"].as_integer();
|
||||||
|
|
||||||
Unit* unit = unitsManager->getUnit(ID);
|
Unit* unit = unitsManager->getUnit(ID);
|
||||||
Unit* target = unitsManager->getUnit(targetID);
|
Unit* leader = unitsManager->getUnit(leaderID);
|
||||||
|
|
||||||
wstring unitName;
|
wstring unitName;
|
||||||
wstring targetName;
|
wstring leaderName;
|
||||||
|
|
||||||
if (unit != nullptr)
|
if (unit != nullptr)
|
||||||
unitName = unit->getUnitName();
|
unitName = unit->getUnitName();
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (target != nullptr)
|
if (leader != nullptr)
|
||||||
targetName = target->getUnitName();
|
leaderName = leader->getUnitName();
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
log(L"Unit " + unitName + L" following unit " + targetName);
|
log(L"Unit " + unitName + L" following unit " + leaderName);
|
||||||
unit->setFormationOffset(Offset(offsetX, offsetY, offsetZ));
|
unit->setFormationOffset(Offset(offsetX, offsetY, offsetZ));
|
||||||
unit->setTargetID(targetID);
|
unit->setLeaderID(leaderID);
|
||||||
unit->setState(State::FOLLOW);
|
unit->setState(State::FOLLOW);
|
||||||
}
|
}
|
||||||
else if (key.compare(L"changeSpeed") == 0)
|
else if (key.compare(L"changeSpeed") == 0)
|
||||||
@@ -208,40 +208,6 @@ void Scheduler::handleRequest(wstring key, json::value value)
|
|||||||
command = dynamic_cast<Command*>(new Clone(ID, loc));
|
command = dynamic_cast<Command*>(new Clone(ID, loc));
|
||||||
log(L"Cloning unit " + to_wstring(ID));
|
log(L"Cloning unit " + to_wstring(ID));
|
||||||
}
|
}
|
||||||
else if (key.compare(L"setLeader") == 0)
|
|
||||||
{
|
|
||||||
int ID = value[L"ID"].as_integer();
|
|
||||||
Unit* unit = unitsManager->getUnit(ID);
|
|
||||||
bool isLeader = value[L"isLeader"].as_bool();
|
|
||||||
if (isLeader)
|
|
||||||
{
|
|
||||||
json::value wingmenIDs = value[L"wingmenIDs"];
|
|
||||||
vector<Unit*> wingmen;
|
|
||||||
if (unit != nullptr)
|
|
||||||
{
|
|
||||||
for (auto itr = wingmenIDs.as_array().begin(); itr != wingmenIDs.as_array().end(); itr++)
|
|
||||||
{
|
|
||||||
Unit* wingman = unitsManager->getUnit(itr->as_integer());
|
|
||||||
if (wingman != nullptr)
|
|
||||||
wingmen.push_back(wingman);
|
|
||||||
}
|
|
||||||
unit->setFormation(L"Line abreast");
|
|
||||||
unit->setIsLeader(true);
|
|
||||||
unit->setWingmen(wingmen);
|
|
||||||
log(L"Setting " + unit->getName() + L" as formation leader");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
unit->setIsLeader(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (key.compare(L"setFormation") == 0)
|
|
||||||
{
|
|
||||||
int ID = value[L"ID"].as_integer();
|
|
||||||
Unit* unit = unitsManager->getUnit(ID);
|
|
||||||
wstring formation = value[L"formation"].as_string();
|
|
||||||
unit->setFormation(formation);
|
|
||||||
}
|
|
||||||
else if (key.compare(L"setROE") == 0)
|
else if (key.compare(L"setROE") == 0)
|
||||||
{
|
{
|
||||||
int ID = value[L"ID"].as_integer();
|
int ID = value[L"ID"].as_integer();
|
||||||
|
|||||||
@@ -20,6 +20,14 @@ Unit::Unit(json::value json, int ID) :
|
|||||||
{
|
{
|
||||||
log("Creating unit with ID: " + to_string(ID));
|
log("Creating unit with ID: " + to_string(ID));
|
||||||
addMeasure(L"currentState", json::value(L"Idle"));
|
addMeasure(L"currentState", json::value(L"Idle"));
|
||||||
|
|
||||||
|
addMeasure(L"TACANChannel", json::value(TACANChannel));
|
||||||
|
addMeasure(L"TACANXY", json::value(TACANXY));
|
||||||
|
addMeasure(L"TACANCallsign", json::value(TACANCallsign));
|
||||||
|
|
||||||
|
addMeasure(L"radioFrequency", json::value(radioFrequency));
|
||||||
|
addMeasure(L"radioCallsign", json::value(radioCallsign));
|
||||||
|
addMeasure(L"radioCallsignNumber", json::value(radioCallsignNumber));
|
||||||
}
|
}
|
||||||
|
|
||||||
Unit::~Unit()
|
Unit::~Unit()
|
||||||
@@ -127,10 +135,10 @@ json::value Unit::getData(long long time)
|
|||||||
|
|
||||||
/********** Formation data **********/
|
/********** Formation data **********/
|
||||||
json[L"formationData"] = json::value::object();
|
json[L"formationData"] = json::value::object();
|
||||||
for (auto key : { L"isLeader", L"isWingman", L"formation", L"wingmenIDs", L"leaderID" })
|
for (auto key : { L"leaderID" })
|
||||||
{
|
{
|
||||||
if (measures.find(key) != measures.end() && measures[key]->getTime() > time)
|
if (measures.find(key) != measures.end() && measures[key]->getTime() > time)
|
||||||
json[L"missionData"][key] = measures[key]->getValue();
|
json[L"formationData"][key] = measures[key]->getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/********** Task data **********/
|
/********** Task data **********/
|
||||||
@@ -154,12 +162,9 @@ json::value Unit::getData(long long time)
|
|||||||
|
|
||||||
void Unit::setActivePath(list<Coords> newPath)
|
void Unit::setActivePath(list<Coords> newPath)
|
||||||
{
|
{
|
||||||
if (state != State::WINGMAN && state != State::FOLLOW)
|
activePath = newPath;
|
||||||
{
|
resetActiveDestination();
|
||||||
activePath = newPath;
|
|
||||||
resetActiveDestination();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto path = json::value::object();
|
auto path = json::value::object();
|
||||||
if (activePath.size() > 0) {
|
if (activePath.size() > 0) {
|
||||||
int count = 1;
|
int count = 1;
|
||||||
@@ -223,22 +228,6 @@ int Unit::getCoalitionID()
|
|||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Unit::setLeader(Unit* newLeader)
|
|
||||||
{
|
|
||||||
leader = newLeader;
|
|
||||||
if (leader != nullptr)
|
|
||||||
addMeasure(L"leaderID", json::value(leader->getID()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Unit::setWingmen(vector<Unit*> newWingmen) {
|
|
||||||
wingmen = newWingmen;
|
|
||||||
auto wingmenIDs = json::value::object();
|
|
||||||
int i = 0;
|
|
||||||
for (auto itr = wingmen.begin(); itr != wingmen.end(); itr++)
|
|
||||||
wingmenIDs[i++] = (*itr)->getID();
|
|
||||||
addMeasure(L"wingmen", wingmenIDs);
|
|
||||||
}
|
|
||||||
|
|
||||||
wstring Unit::getTargetName()
|
wstring Unit::getTargetName()
|
||||||
{
|
{
|
||||||
if (isTargetAlive())
|
if (isTargetAlive())
|
||||||
@@ -262,6 +251,29 @@ bool Unit::isTargetAlive()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wstring Unit::getLeaderName()
|
||||||
|
{
|
||||||
|
if (isLeaderAlive())
|
||||||
|
{
|
||||||
|
Unit* leader = unitsManager->getUnit(leaderID);
|
||||||
|
if (leader != nullptr)
|
||||||
|
return leader->getUnitName();
|
||||||
|
}
|
||||||
|
return L"";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Unit::isLeaderAlive()
|
||||||
|
{
|
||||||
|
if (leaderID == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unit* leader = unitsManager->getUnit(leaderID);
|
||||||
|
if (leader != nullptr)
|
||||||
|
return leader->alive;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Unit::resetActiveDestination()
|
void Unit::resetActiveDestination()
|
||||||
{
|
{
|
||||||
activeDestination = Coords(NULL);
|
activeDestination = Coords(NULL);
|
||||||
@@ -273,30 +285,6 @@ void Unit::resetTask()
|
|||||||
scheduler->appendCommand(command);
|
scheduler->appendCommand(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Unit::setIsLeader(bool newIsLeader) {
|
|
||||||
isLeader = newIsLeader;
|
|
||||||
if (!isLeader) {
|
|
||||||
for (auto wingman : wingmen)
|
|
||||||
{
|
|
||||||
wingman->setFormation(L"");
|
|
||||||
wingman->setIsWingman(false);
|
|
||||||
wingman->setLeader(nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addMeasure(L"isLeader", json::value(newIsLeader));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Unit::setIsWingman(bool newIsWingman)
|
|
||||||
{
|
|
||||||
isWingman = newIsWingman;
|
|
||||||
if (isWingman)
|
|
||||||
setState(State::WINGMAN);
|
|
||||||
else
|
|
||||||
setState(State::IDLE);
|
|
||||||
|
|
||||||
addMeasure(L"isWingman", json::value(isWingman));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Unit::setFormationOffset(Offset newFormationOffset)
|
void Unit::setFormationOffset(Offset newFormationOffset)
|
||||||
{
|
{
|
||||||
formationOffset = newFormationOffset;
|
formationOffset = newFormationOffset;
|
||||||
|
|||||||