fix: Complete implementation of alarm state

This commit is contained in:
Pax1601 2025-03-24 22:59:41 +01:00
parent 7573720398
commit 8cce77c4d3
13 changed files with 776 additions and 3939 deletions

View File

@ -48,9 +48,9 @@ namespace ROE {
namespace AlarmState {
enum AlarmStates {
AUTO = 2,
AUTO = 0,
GREEN = 1,
RED = 0,
RED = 2,
};
}

View File

@ -412,7 +412,7 @@ void Scheduler::handleRequest(string key, json::value value, string username, js
unitsManager->acquireControl(ID);
Unit* unit = unitsManager->getGroupLeader(ID);
if (unit != nullptr) {
unsigned char alarmState = value[L"alarmState"].as_integer();
unsigned char alarmState = value[L"alarmState"].as_number().to_uint32();
unit->setAlarmState(alarmState);
log(username + " set unit " + unit->getUnitName() + "(" + unit->getName() + ") alarm state to " + to_string(alarmState), true);
} else {

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
version="1.1"
id="svg4"
sodipodi:docname="designated.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs8" />
<sodipodi:namedview
id="namedview6"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
width="30px"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="5.9428571"
inkscape:cx="-29.026442"
inkscape:cy="16.237981"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg4" />
<path
d="m 7.5000002,0 c 0.498,0 0.9375,0.4395 0.9375,0.9375 V 1.2598 C 11.1621,1.6699 13.3301,3.8379002 13.7402,6.5625002 h 0.3223 c 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 H 13.7402 C 13.3301,11.1914 11.1621,13.3594 8.4375002,13.7695 v 0.293 c 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 v -0.293 C 3.8086002,13.3594 1.6406,11.1914 1.2305,8.4375002 h -0.293 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 h 0.293 C 1.6406,3.8379002 3.8086002,1.6699 6.5625002,1.2598 V 0.9375 c 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 z m -4.3652,8.4375002 c 0.3515,1.7284998 1.6992,3.0761998 3.4277,3.4276998 V 11.25 c 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 0.498,0 0.9375,0.4395 0.9375,0.9375 v 0.6152 C 10.1367,11.5137 11.4844,10.166 11.8359,8.4375002 H 11.25 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 h 0.5859 c -0.3515,-1.6992 -1.6992,-3.0469 -3.3983998,-3.3984 v 0.5859 c 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 v -0.5859 c -1.7285,0.3515 -3.0762,1.6992 -3.4277,3.3984 h 0.6152 c 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 z m 4.3652,0 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 z"
fill="#5ca7ff"
id="path2"
style="stroke: none" />
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="9.3896503"
height="9.3896503"
viewBox="0 0 9.3896503 9.3896503"
fill="none"
version="1.1"
id="svg4"
sodipodi:docname="hold.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs8" />
<sodipodi:namedview
id="namedview6"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="23.771429"
inkscape:cx="1.1989183"
inkscape:cy="4.311899"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg4" />
<path
d="m 9.103975,1.603975 c 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 l -3.0762,3.0761 -3.1055,-3.0761 c -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 -0.3809,0.3515 -0.3809,0.9668 0,1.3183 l 3.0761,3.0762 -3.0761,3.1055 c -0.3809,0.3515 -0.3809,0.9668 0,1.3183 0.3515,0.3809 0.9668,0.3809 1.3183,0 l 3.1055,-3.0761 3.0762,3.0761 c 0.3515,0.3809 0.9668,0.3809 1.3183,0 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 l -3.0761,-3.1055 z"
fill="#5ca7ff"
id="path2"
style="stroke: none" />
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="13.126647"
height="15.015483"
viewBox="0 0 13.126647 15.015483"
fill="none"
version="1.1"
id="svg4"
sodipodi:docname="free.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs8" />
<sodipodi:namedview
id="namedview6"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="43.789474"
inkscape:cx="4.5330529"
inkscape:cy="6.7710337"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg4" />
<path
d="m 10.796771,3.75 c 0,1.31836 -0.7618,2.46094 -1.8750496,3.13476 v 0.61525 c 0,0.5273 -0.43945,0.9375 -0.9375,0.9375 h -2.8125 c -0.52734,0 -0.9375,-0.4102 -0.9375,-0.9375 V 6.88476 c -1.14258,-0.67382 -1.875,-1.8164 -1.875,-3.13476 0,-2.05078 1.875,-3.75 4.21875,-3.75 2.31445,0 4.2187996,1.69922 4.2187996,3.75 z M 4.9373514,5.15625 c 0.49804,0 0.9375,-0.41016 0.9375,-0.9375 0,-0.49805 -0.43946,-0.9375 -0.9375,-0.9375 -0.52735,0 -0.9375,0.43945 -0.9375,0.9375 0,0.52734 0.41015,0.9375 0.9375,0.9375 z m 4.21872,-0.9375 c 0,-0.49805 -0.43943,-0.9375 -0.93748,-0.9375 -0.52734,0 -0.9375,0.43945 -0.9375,0.9375 0,0.52734 0.41016,0.9375 0.9375,0.9375 0.49805,0 0.93748,-0.41016 0.93748,-0.9375 z M 0.10336144,8.02731 c 0.23438,-0.4687 0.79102,-0.6445 1.25976996,-0.4101 l 5.21484,2.6074 5.1854996,-2.6074 c 0.4688,-0.2344 1.0254,-0.0586 1.2598,0.4101 0.2344,0.4688 0.0586,1.0254 -0.4101,1.2598 l -3.9551196,1.9629 3.9551196,1.9922 c 0.4687,0.2344 0.6445,0.791 0.4101,1.2597 -0.2344,0.4688 -0.791,0.6446 -1.2598,0.4102 l -5.1854996,-2.6074 -5.21484,2.6074 c -0.46874996,0.2344 -1.02538996,0.0586 -1.25976996,-0.4102 -0.234374,-0.4687 -0.058593,-1.0253 0.41016,-1.2597 L 4.4685914,11.25001 0.51352144,9.28711 c -0.468753,-0.2344 -0.644534,-0.791 -0.41016,-1.2598 z"
fill="#5ca7ff"
id="path2"
style="stroke: none" />
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 16 16"
version="1.1"
id="svg1"
sodipodi:docname="alarmStateGreen.svg"
width="16"
height="16"
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
xml:space="preserve"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs1" /><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="25.919883"
inkscape:cx="13.831081"
inkscape:cy="11.400514"
inkscape:window-width="2560"
inkscape:window-height="1369"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" /><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path
d="M 3.7422746,4.0810782 C 3.5794387,3.952686 3.3430088,3.9824344 3.2146172,4.1452726 3.0862247,4.3081112 3.1159759,4.5445408 3.2788135,4.6729303 l 9.2692385,7.2650807 c 0.162838,0.128392 0.399268,0.09864 0.527657,-0.0642 0.128392,-0.162837 0.09864,-0.399267 -0.0642,-0.527658 l -1.412307,-1.106987 c 0.0031,-0.0062 0.0062,-0.01409 0.0094,-0.02036 0.08142,-0.180061 0.04853,-0.3914375 -0.08298,-0.5386172 L 11.409754,9.5502434 C 10.921242,8.999099 10.650365,8.2898138 10.650365,7.552346 V 7.257985 c 0,-1.2118908 -0.8611614,-2.2233655 -2.0041593,-2.4550974 v -0.300624 c 0,-0.2771365 -0.2239031,-0.5010395 -0.5010397,-0.5010395 -0.2771384,0 -0.5010389,0.223903 -0.5010389,0.5010395 V 4.8028878 C 6.9771163,4.9375431 6.4071837,5.3383753 6.0470597,5.8879535 Z M 9.4948418,10.514745 5.6399655,7.4787555 v 0.075159 c 0,0.7359021 -0.2708759,1.4467532 -0.7593887,1.9978975 L 4.764711,9.6817695 c -0.1315225,0.1471797 -0.1628385,0.3585555 -0.082989,0.5386165 0.079855,0.180061 0.259915,0.294361 0.4571968,0.294361 z m -0.6403933,1.210324 c 0.1878922,-0.187889 0.292796,-0.443107 0.292796,-0.709284 H 8.145166 7.1430839 c 0,0.266177 0.1049072,0.521395 0.2927959,0.709284 0.1878913,0.18789 0.4431078,0.292796 0.7092862,0.292796 0.2661774,0 0.5213939,-0.104907 0.7092825,-0.292796 z"
id="path1-6"
style="fill:#8bff63;fill-opacity:1;stroke:#272727;stroke-width:3.50002;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers" /></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 16 16"
version="1.1"
id="svg1"
sodipodi:docname="alarmStateRed.svg"
width="16"
height="16"
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1" />
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="36.65625"
inkscape:cx="17.009378"
inkscape:cy="10.980392"
inkscape:window-width="2560"
inkscape:window-height="1369"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" />
<!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
<path
d="m 8.3545299,3.3811696 c -0.300221,0 -0.542773,0.247612 -0.542773,0.554097 v 0.332456 c -1.238204,0.25627 -2.171098,1.374849 -2.171098,2.715068 v 0.32553 c 0,0.813829 -0.293438,1.599952 -0.822642,2.209456 l -0.125517,0.143718 c -0.142479,0.162766 -0.176403,0.3965254 -0.0899,0.5956544 0.0865,0.199127 0.281565,0.327261 0.495283,0.327261 h 6.5132921 c 0.213718,0 0.407082,-0.128134 0.495281,-0.327261 0.0882,-0.199129 0.05258,-0.4328884 -0.0899,-0.5956544 L 11.89104,9.5177766 c -0.529204,-0.609504 -0.822641,-1.393896 -0.822641,-2.209456 v -0.32553 c 0,-1.340219 -0.932895,-2.458798 -2.1710981,-2.715068 v -0.332456 c 0,-0.306485 -0.242553,-0.554097 -0.542776,-0.554097 z m 0.768367,8.5417264 c 0.203539,-0.207784 0.317182,-0.490027 0.317182,-0.78439 h -1.085549 -1.085547 c 0,0.294363 0.113643,0.576606 0.317183,0.78439 0.203541,0.207786 0.480016,0.323801 0.768364,0.323801 0.288349,0 0.564825,-0.116015 0.768367,-0.323801 z"
id="path1"
style="fill:#ff5858;fill-opacity:1;stroke:#272727;stroke-width:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers" />
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -173,6 +173,7 @@ export interface ObjectIconOptions {
showCallsign: boolean;
rotateToHeading: boolean;
showCluster: boolean;
showAlarmState: boolean;
}
export interface GeneralSettings {

View File

@ -661,25 +661,31 @@
/* Unit Radar State */
.unit-alarm-state {
height: 10px;
width: 10px;
background-repeat: no-repeat;
height: 16px;
width: 16px;
position: absolute;
border-radius: 50%;
border: none;
background: transparent;
left: 35px;
bottom: 8px;
bottom: 0px;
}
.unit[data-alarm-state="green"] .unit-alarm-state {
border: 1px solid white;
background: rgb(0, 226, 0);
background-image: url("/images/states/alarm-state-green.svg");
}
.unit[data-alarm-state="red"] .unit-alarm-state {
border: 1px solid white;
background: red;
background-image: url("/images/states/alarm-state-red.svg");
}
.unit[data-alarm-state="auto"] .unit-alarm-state {
border: 0px solid transpare;
background: transparent;
}
[todo-data-awacs-mode] [data-object|="unit"] .unit-selected-spotlight,
[todo-data-awacs-mode] [data-object|="unit"] .unit-short-label,
[todo-data-awacs-mode] [data-object|="unit"] .unit-state,

View File

@ -6,7 +6,7 @@ import { Converter } from "usng";
import { MGRS } from "../types/types";
import { featureCollection } from "turf";
import MagVar from "magvar";
import axios from 'axios';
import axios from "axios";
export function bearing(lat1: number, lon1: number, lat2: number, lon2: number, magnetic = true) {
const φ1 = deg2rad(lat1); // φ, λ in radians
@ -54,19 +54,19 @@ export function midpoint(lat1: number, lon1: number, lat2: number, lon2: number,
const λ2 = deg2rad(lon2); // Convert longitude of point 2 from degrees to radians
// Convert point 1 to Mercator projection coordinates
const x1 = 1 / (2 * Math.PI) * Math.pow(2, zoom) * (Math.PI + λ1);
const y1 = 1 / (2 * Math.PI) * Math.pow(2, zoom) * (Math.PI - Math.log(Math.tan(Math.PI / 4 + φ1 / 2)));
const x1 = (1 / (2 * Math.PI)) * Math.pow(2, zoom) * (Math.PI + λ1);
const y1 = (1 / (2 * Math.PI)) * Math.pow(2, zoom) * (Math.PI - Math.log(Math.tan(Math.PI / 4 + φ1 / 2)));
// Convert point 2 to Mercator projection coordinates
const x2 = 1 / (2 * Math.PI) * Math.pow(2, zoom) * (Math.PI + λ2);
const y2 = 1 / (2 * Math.PI) * Math.pow(2, zoom) * (Math.PI - Math.log(Math.tan(Math.PI / 4 + φ2 / 2)));
const x2 = (1 / (2 * Math.PI)) * Math.pow(2, zoom) * (Math.PI + λ2);
const y2 = (1 / (2 * Math.PI)) * Math.pow(2, zoom) * (Math.PI - Math.log(Math.tan(Math.PI / 4 + φ2 / 2)));
// Calculate the midpoint in Mercator projection coordinates
const mx = (x1 + x2) / 2;
const my = (y1 + y2) / 2;
// Convert the midpoint back to latitude and longitude
const λ = (2 * Math.PI * mx / Math.pow(2, zoom)) - Math.PI;
const λ = (2 * Math.PI * mx) / Math.pow(2, zoom) - Math.PI;
const φ = 2 * Math.atan(Math.exp(Math.PI - (2 * Math.PI * my) / Math.pow(2, zoom))) - Math.PI / 2;
// Return the midpoint as a LatLng object
@ -277,11 +277,11 @@ export function enumToROE(ROE: number) {
export function enumToAlarmState(alarmState: number) {
switch (alarmState) {
case 0:
case 2:
return AlarmState.RED;
case 1:
return AlarmState.GREEN;
case 2:
case 0:
return AlarmState.AUTO;
default:
return AlarmState.AUTO;
@ -524,7 +524,7 @@ export function computeStandardFormationOffset(formation, idx) {
var xl = xr * Math.cos(Math.PI / 4) - yr * Math.sin(Math.PI / 4);
var yl = xr * Math.sin(Math.PI / 4) + yr * Math.cos(Math.PI / 4);
offset = { x: xl * 50, y: yl * 50, z: 0 };
offset.z = -Math.sqrt(offset.x * offset.x + offset.y * offset.y) * 0.1
offset.z = -Math.sqrt(offset.x * offset.x + offset.y * offset.y) * 0.1;
if (yr == 0) {
layer++;
xr = 0;
@ -560,7 +560,7 @@ export function roundToNearestFive(number) {
return Math.round(number / 5) * 5;
}
export function toDCSFormationOffset(offset: { x: number, y: number, z: number }) {
export function toDCSFormationOffset(offset: { x: number; y: number; z: number }) {
// X: front-rear, positive front
// Y: top-bottom, positive top
// Z: left-right, positive right
@ -568,7 +568,7 @@ export function toDCSFormationOffset(offset: { x: number, y: number, z: number }
return { x: -offset.y, y: offset.z, z: offset.x };
}
export function fromDCSFormationOffset(offset: { x: number, y: number, z: number }) {
export function fromDCSFormationOffset(offset: { x: number; y: number; z: number }) {
return { x: offset.z, y: -offset.x, z: offset.y };
}
@ -581,7 +581,7 @@ export function fromDCSFormationOffset(offset: { x: number, y: number, z: number
export function adjustBrightness(color, percent) {
// Ensure the color is in the correct format
if (!/^#[0-9A-F]{6}$/i.test(color)) {
throw new Error('Invalid color format. Use #RRGGBB.');
throw new Error("Invalid color format. Use #RRGGBB.");
}
// Parse the color components
@ -607,12 +607,12 @@ export function adjustBrightness(color, percent) {
export function setOpacity(color, opacity) {
// Ensure the color is in the correct format
if (!/^#[0-9A-F]{6}$/i.test(color)) {
throw new Error('Invalid color format. Use #RRGGBB.');
throw new Error("Invalid color format. Use #RRGGBB.");
}
// Ensure the opacity is within the valid range
if (opacity < 0 || opacity > 1) {
throw new Error('Opacity must be between 0 and 1.');
throw new Error("Opacity must be between 0 and 1.");
}
// Parse the color components
@ -632,7 +632,7 @@ export function setOpacity(color, opacity) {
export function computeBrightness(color) {
// Ensure the color is in the correct format
if (!/^#[0-9A-F]{6}$/i.test(color)) {
throw new Error('Invalid color format. Use #RRGGBB.');
throw new Error("Invalid color format. Use #RRGGBB.");
}
// Parse the color components
@ -673,18 +673,18 @@ export function decimalToRGBA(decimal: number): string {
export async function getWikipediaImage(unitName: string): Promise<string | null> {
try {
// Search for the unit name on Wikipedia
const searchResponse = await axios.get('https://en.wikipedia.org/w/api.php', {
const searchResponse = await axios.get("https://en.wikipedia.org/w/api.php", {
params: {
action: 'query',
list: 'search',
action: "query",
list: "search",
srsearch: unitName,
format: 'json',
origin: '*'
}
format: "json",
origin: "*",
},
});
if (searchResponse.data.query.search.length === 0) {
console.error('No search results found for the unit name.');
console.error("No search results found for the unit name.");
return null;
}
@ -692,15 +692,15 @@ export async function getWikipediaImage(unitName: string): Promise<string | null
const pageTitle = searchResponse.data.query.search[0].title;
// Get the page content to find the image
const pageResponse = await axios.get('https://en.wikipedia.org/w/api.php', {
const pageResponse = await axios.get("https://en.wikipedia.org/w/api.php", {
params: {
action: 'query',
action: "query",
titles: pageTitle,
prop: 'pageimages',
prop: "pageimages",
pithumbsize: 500,
format: 'json',
origin: '*'
}
format: "json",
origin: "*",
},
});
const pages = pageResponse.data.query.pages;
@ -710,11 +710,11 @@ export async function getWikipediaImage(unitName: string): Promise<string | null
if (page.thumbnail && page.thumbnail.source) {
return page.thumbnail.source;
} else {
console.error('No image found for the unit name.');
console.error("No image found for the unit name.");
return null;
}
} catch (error) {
console.error('Error fetching data from Wikipedia:', error);
console.error("Error fetching data from Wikipedia:", error);
return null;
}
}
@ -722,18 +722,18 @@ export async function getWikipediaImage(unitName: string): Promise<string | null
export async function getWikipediaSummary(unitName: string): Promise<string | null> {
try {
// Search for the unit name on Wikipedia
const searchResponse = await axios.get('https://en.wikipedia.org/w/api.php', {
const searchResponse = await axios.get("https://en.wikipedia.org/w/api.php", {
params: {
action: 'query',
list: 'search',
action: "query",
list: "search",
srsearch: unitName,
format: 'json',
origin: '*'
}
format: "json",
origin: "*",
},
});
if (searchResponse.data.query.search.length === 0) {
console.error('No search results found for the unit name.');
console.error("No search results found for the unit name.");
return null;
}
@ -741,16 +741,16 @@ export async function getWikipediaSummary(unitName: string): Promise<string | nu
const pageTitle = searchResponse.data.query.search[0].title;
// Get the page content to find the summary
const pageResponse = await axios.get('https://en.wikipedia.org/w/api.php', {
const pageResponse = await axios.get("https://en.wikipedia.org/w/api.php", {
params: {
action: 'query',
prop: 'extracts',
action: "query",
prop: "extracts",
exintro: true,
explaintext: true,
titles: pageTitle,
format: 'json',
origin: '*'
}
format: "json",
origin: "*",
},
});
const pages = pageResponse.data.query.pages;
@ -760,11 +760,11 @@ export async function getWikipediaSummary(unitName: string): Promise<string | nu
if (page.extract) {
return page.extract;
} else {
console.error('No summary found for the unit name.');
console.error("No summary found for the unit name.");
return null;
}
} catch (error) {
console.error('Error fetching data from Wikipedia:', error);
console.error("Error fetching data from Wikipedia:", error);
return null;
}
}
@ -775,4 +775,4 @@ export function secondsToTimeString(seconds: number) {
const secs = Math.floor(seconds % 60);
return `${zeroPad(hours, 2)}:${zeroPad(minutes, 2)}:${zeroPad(secs, 2)}`;
}
}

File diff suppressed because one or more lines are too long

View File

@ -8,7 +8,6 @@ import { OlButtonGroup, OlButtonGroupItem } from "../components/olbuttongroup";
import { OlCheckbox } from "../components/olcheckbox";
import {
ROEs,
alarmStates,
UnitState,
altitudeIncrements,
emissionsCountermeasures,
@ -20,6 +19,9 @@ import {
import { OlToggle } from "../components/oltoggle";
import { OlCoalitionToggle } from "../components/olcoalitiontoggle";
import {
olButtonsAlarmstateAuto,
olButtonsAlarmstateGreen,
olButtonsAlarmstateRed,
olButtonsEmissionsAttack,
olButtonsEmissionsDefend,
olButtonsEmissionsFree,
@ -890,7 +892,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
{/* ============== Rules of Engagement END ============== */}
{/* ============== Alarm state selector START ============== */}
{selectedUnitsData.alarmState &&
{
<div className="flex flex-col gap-2">
<span
className={`
@ -908,9 +910,15 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
<div className="flex flex-col gap-2">
<div>Sets the alarm state of the unit, in order:</div>
<div className="flex flex-col gap-2 px-2">
<div className="flex content-center gap-2">
{" "}
<FontAwesomeIcon icon={olButtonsAlarmstateGreen} className={`
my-auto min-w-8 text-white
`} /> Green: The unit will not engage with its sensors in any circumstances. The unit will be able to move.
</div>
<div className="flex content-center gap-2">
{" "}
<FontAwesomeIcon icon={olButtonsRoeDesignated} className={`
<FontAwesomeIcon icon={olButtonsAlarmstateAuto} className={`
my-auto min-w-8 text-white
`} />{" "}
<div>
@ -918,15 +926,10 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
Auto: The unit will use its sensors to engage based on its ROE.
</div>
</div>
<div className="flex content-center gap-2">
{" "}
<FontAwesomeIcon icon={olButtonsRoeReturn} className={`
my-auto min-w-8 text-white
`} /> Green: The unit will not engage with its sensors in any circumstances. The unit will be able to move.
</div>
<div className="flex content-center gap-2">
{" "}
<FontAwesomeIcon icon={olButtonsRoeHold} className={`
<FontAwesomeIcon icon={olButtonsAlarmstateRed} className={`
my-auto min-w-8 text-white
`} /> Red: The unit will be actively searching for target with its sensors. For some units, this will deploy
the radar and make the unit not able to move.
@ -938,33 +941,21 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
)}
tooltipRelativeToParent={true}
>
{[olButtonsRoeHold, olButtonsRoeReturn, olButtonsRoeDesignated].map((icon, idx) => {
const getAlarmStateByIdx = (idx) => {
switch (idx) {
case 0:
return AlarmState.AUTO;
case 1:
return AlarmState.GREEN;
case 2:
return AlarmState.RED;
}
}
{[olButtonsAlarmstateGreen, olButtonsAlarmstateAuto, olButtonsAlarmstateRed].map((icon, idx) => {
return (
<OlButtonGroupItem
key={idx}
onClick={() => {
getApp()
.getUnitsManager()
.setAlarmState(idx, null, () =>
.setAlarmState([1, 0, 2][idx], null, () =>
setForcedUnitsData({
...forcedUnitsData,
alarmState: getAlarmStateByIdx(idx),
alarmState: [AlarmState.GREEN, AlarmState.AUTO, AlarmState.RED][idx],
})
);
}}
active={selectedUnitsData.alarmState === getAlarmStateByIdx(idx)}
active={selectedUnitsData.alarmState === [AlarmState.GREEN, AlarmState.AUTO, AlarmState.RED][idx]}
icon={icon}
/>
);
@ -1430,7 +1421,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
{/* ============== Miss on purpose toggle END ============== */}
<div className="flex gap-4">
{/* ============== Shots scatter START ============== */}
<div className={`flex flex-col gap-2`}>
<div className={`flex w-full justify-between gap-2`}>
<span
className={`
my-auto font-normal
@ -1463,7 +1454,7 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
</div>
{/* ============== Shots scatter END ============== */}
{/* ============== Shots intensity START ============== */}
<div className="flex flex-col gap-2">
{/*<div className="flex flex-col gap-2">
<span
className={`
my-auto font-normal
@ -1495,12 +1486,13 @@ export function UnitControlMenu(props: { open: boolean; onClose: () => void }) {
</OlButtonGroup>
</div>
{/* ============== Shots intensity END ============== */}
<OlStateButton
{/*<OlStateButton
className="mt-auto"
checked={showEngagementSettings}
onClick={() => setShowEngagementSettings(!showEngagementSettings)}
icon={faCog}
></OlStateButton>
*/}
</div>
{/* ============== Operate as toggle START ============== */}
{selectedUnits.every((unit) => unit.getCoalition() === "neutral") && (

View File

@ -1190,10 +1190,10 @@ export abstract class Unit extends CustomMarker {
el.append(healthIndicator);
}
/* Radar state indicator */
if (this.#alarmState) {
/* Alarm state indicator */
if (iconOptions.showAlarmState) {
var alarmStateIcon = document.createElement("div");
alarmStateIcon.classList.add("unit-radar-state");
alarmStateIcon.classList.add("unit-alarm-state");
el.append(alarmStateIcon);
}
@ -1774,8 +1774,7 @@ export abstract class Unit extends CustomMarker {
element.querySelector(".unit")?.toggleAttribute("data-is-dead", !this.#alive);
/* Set radar state*/
// if (this.#radarState !== undefined) element.querySelector(".unit")?.setAttribute("data-radar-state", (this.#radarState === true ? 'on' : 'off'));
if (this.#alarmState !== AlarmState.AUTO) element.querySelector(".unit")?.setAttribute("data-alarm-state", (this.#alarmState === AlarmState.RED ? 'red' : 'green'));
element.querySelector(".unit")?.setAttribute("data-alarm-state", this.#alarmState);
/* Set current unit state */
if (this.#human) {
@ -2423,6 +2422,7 @@ export abstract class AirUnit extends Unit {
showCallsign: belongsToCommandedCoalition && /*TODO !getApp().getMap().getOptions().AWACSMode || */ this.getHuman(),
rotateToHeading: false,
showCluster: false,
showAlarmState: false
} as ObjectIconOptions;
}
@ -2511,6 +2511,7 @@ export class GroundUnit extends Unit {
showCallsign: belongsToCommandedCoalition && /*TODO !getApp().getMap().getOptions().AWACSMode || */ this.getHuman(),
rotateToHeading: false,
showCluster: true,
showAlarmState: true,
} as ObjectIconOptions;
}
@ -2578,6 +2579,7 @@ export class NavyUnit extends Unit {
showCallsign: belongsToCommandedCoalition && /*TODO !getApp().getMap().getOptions().AWACSMode || */ this.getHuman(),
rotateToHeading: false,
showCluster: false,
showAlarmState: true
} as ObjectIconOptions;
}