diff --git a/client/src/components/airdefenserangelayer/AirDefenseRangeLayer.tsx b/client/src/components/airdefenserangelayer/AirDefenseRangeLayer.tsx
new file mode 100644
index 00000000..a92cdc82
--- /dev/null
+++ b/client/src/components/airdefenserangelayer/AirDefenseRangeLayer.tsx
@@ -0,0 +1,70 @@
+import { Circle, LayerGroup } from "react-leaflet";
+
+import Tgo from "../../api/tgo";
+import { selectTgos } from "../../api/tgosSlice";
+import { useAppSelector } from "../../app/hooks";
+
+interface TgoRangeCirclesProps {
+ tgo: Tgo;
+ blue: boolean;
+ detection?: boolean;
+}
+
+function colorFor(blue: boolean, detection: boolean) {
+ if (blue) {
+ return detection ? "#bb89ff" : "#0084ff";
+ }
+ return detection ? "#eee17b" : "#c85050";
+}
+
+const TgoRangeCircles = (props: TgoRangeCirclesProps) => {
+ const radii = props.detection
+ ? props.tgo.detection_ranges
+ : props.tgo.threat_ranges;
+ const color = colorFor(props.blue, props.detection === true);
+ const weight = props.detection ? 1 : 2;
+
+ return (
+ <>
+ {radii.map((radius) => {
+ return (
+
+ );
+ })}
+ >
+ );
+};
+
+interface AirDefenseRangeLayerProps {
+ blue: boolean;
+ detection?: boolean;
+}
+
+export const AirDefenseRangeLayer = (props: AirDefenseRangeLayerProps) => {
+ const tgos = useAppSelector(selectTgos);
+ var allTgos: Tgo[] = [];
+ for (const tgoType of Object.values(tgos.tgosByType)) {
+ for (const tgo of tgoType) {
+ if (tgo.blue === props.blue) {
+ allTgos.push(tgo);
+ }
+ }
+ }
+
+ return (
+
+ {allTgos.map((tgo) => {
+ return ;
+ })}
+
+ );
+};
+
+export default AirDefenseRangeLayer;
diff --git a/client/src/components/airdefenserangelayer/index.ts b/client/src/components/airdefenserangelayer/index.ts
new file mode 100644
index 00000000..906609aa
--- /dev/null
+++ b/client/src/components/airdefenserangelayer/index.ts
@@ -0,0 +1 @@
+export { default } from "./AirDefenseRangeLayer";
diff --git a/client/src/components/liberationmap/LiberationMap.tsx b/client/src/components/liberationmap/LiberationMap.tsx
index 829e42a8..b95ceb20 100644
--- a/client/src/components/liberationmap/LiberationMap.tsx
+++ b/client/src/components/liberationmap/LiberationMap.tsx
@@ -2,6 +2,7 @@ import "./LiberationMap.css";
import { LayersControl, MapContainer, ScaleControl } from "react-leaflet";
+import AirDefenseRangeLayer from "../airdefenserangelayer";
import { BasemapLayer } from "react-esri-leaflet";
import ControlPointsLayer from "../controlpointslayer";
import FlightPlansLayer from "../flightplanslayer";
@@ -37,6 +38,18 @@ export default function LiberationMap(props: GameProps) {
);
})}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/game/server/tgos/models.py b/game/server/tgos/models.py
index a7b44e8b..2ae03098 100644
--- a/game/server/tgos/models.py
+++ b/game/server/tgos/models.py
@@ -25,7 +25,9 @@ class TgoJs(BaseModel):
detection_ranges = []
else:
threat_ranges = [tgo.threat_range(group).meters for group in tgo.groups]
- detection_ranges = [tgo.threat_range(group).meters for group in tgo.groups]
+ detection_ranges = [
+ tgo.detection_range(group).meters for group in tgo.groups
+ ]
return TgoJs(
name=tgo.name,
control_point_name=tgo.control_point.name,