More AIC work so I don't lose it. (Best commit message ever.)

This commit is contained in:
PeekabooSteam
2023-02-15 11:28:14 +00:00
parent a3f90d3b46
commit 5b7bf63909
8 changed files with 411 additions and 132 deletions

View File

@@ -1,37 +1,79 @@
interface AICFormation {
"descriptor" : string,
"icon" : string,
"label" : string,
"name" : string
}
import { AICFormation } from "./AICFormation";
import { AICFormation_Azimuth } from "./AICFormation/Azimuth";
import { AICFormation_Range } from "./AICFormation/Range";
import { AICFormation_Single } from "./AICFormation/Single";
import { AICFormationDescriptorSection } from "./AICFormationDescriptorSection";
// import { AICFormationDescriptor } from "./aicformationdescriptor"
export class AIC {
#status:boolean = true;
#formations:AICFormation[] = [{
"descriptor" : "group, single, Bullseye, <bearing>, <range>, <altitude>, tracks <N|NE|E|SE|S|SW|W|NW>, <bogey|hostile>",
"icon" : "single.png",
"label" : "Single",
"name" : "single"
}, {
"descriptor" : "",
"icon" : "azimuth.png",
"label" : "Azimuth",
"name" : "azimuth"
}, {
"descriptor" : "",
"icon" : "range.png",
"label" : "Range",
"name" : "range"
}];
#formations = [
new AICFormation_Single(),
new AICFormation_Range(),
new AICFormation_Azimuth()
];
constructor() {
this.#onStatusUpdate();
// This feels kind of dirty
let $aicFormationList = document.getElementById( "aic-formation-list" );
if ( $aicFormationList ) {
this.getFormations().forEach( formation => {
// Image
let $imageDiv = document.createElement( "div" );
$imageDiv.classList.add( "aic-formation-image" );
let $img = document.createElement( "img" );
$img.src = "images/formations/" + formation.icon;
$imageDiv.appendChild( $img );
// Name
let $nameDiv = document.createElement( "div" );
$nameDiv.classList.add( "aic-formation-name" );
$nameDiv.innerText = formation.label;
// Wrapper
let $wrapperDiv = document.createElement( "div" );
$wrapperDiv.dataset.formationName = formation.name;
$wrapperDiv.appendChild( $imageDiv )
$wrapperDiv.appendChild( $nameDiv );
$wrapperDiv.addEventListener( "click", ( ev ) => {
const controlTypeInput = document.querySelector( "input[type='radio'][name='control-type']:checked" );
let controlTypeValue:any = ( controlTypeInput instanceof HTMLInputElement && [ "broadcast", "tactical" ].indexOf( controlTypeInput.value ) > -1 ) ? controlTypeInput.value : "broadcast";
// TODO: make this not an "any"
const output:any = formation.getDescriptor({
"aicCallsign" : "Magic",
"bullseyeName" : "Bullseye",
"control" : controlTypeValue,
"numGroups" : formation.numGroups
});
this.updateTeleprompt( output );
});
// Add to DOM
$aicFormationList?.appendChild( $wrapperDiv );
});
}
}
@@ -67,4 +109,80 @@ export class AIC {
}
toggleHelp() {
document.getElementById( "aic-help" )?.classList.toggle( "hide" );
}
//*
updateTeleprompt<T extends AICFormationDescriptorSection>( descriptor:T[] ) {
let $teleprompt = document.getElementById( "aic-teleprompt" );
if ( $teleprompt instanceof HTMLElement ) {
// Clean slate
while ( $teleprompt.childNodes.length > 0 ) {
$teleprompt.childNodes[0].remove();
}
function newDiv() {
return document.createElement( "div" );
}
// Wrapper
let $descriptor = newDiv();
$descriptor.id = "aic-descriptor";
for ( const section of descriptor ) {
if ( section.omitSection ) {
continue;
}
let $section = newDiv();
$section.classList.add( "aic-descriptor-section" );
let $sectionLabel = newDiv();
$sectionLabel.classList.add( "aic-descriptor-section-label" );
$sectionLabel.innerText = section.label;
$section.appendChild( $sectionLabel );
let $components = newDiv();
$components.classList.add( "aic-descriptor-components" );
for ( const component of section.getComponents() ) {
let $component = newDiv();
$component.classList.add( "aic-descriptor-component" );
let $componentLabel = newDiv();
$componentLabel.classList.add( "aic-descriptor-component-label" );
$componentLabel.innerText = component.label;
let $componentValue = newDiv();
$componentValue.classList.add( "aic-descriptor-component-value" );
$componentValue.innerText = component.value;
$component.appendChild( $componentLabel );
$component.appendChild( $componentValue );
$components.appendChild( $component );
}
$section.appendChild( $components );
$descriptor.appendChild( $section );
}
$teleprompt.appendChild( $descriptor );
}
}
//*/
}

View File

@@ -11,8 +11,8 @@ import { MissionData } from "./missiondata/missiondata";
import { UnitControlPanel } from "./panels/unitcontrolpanel";
import { MouseInfoPanel } from "./panels/mouseInfoPanel";
import { Slider } from "./controls/slider";
import { AIC } from "./aic/AIC";
import { AIC } from "./aic/aic";
/* TODO: should this be a class? */
var map: Map;
@@ -41,6 +41,7 @@ var deadVisibilityButton: Button;
var aic: AIC;
var aicToggleButton: Button;
var aicHelpButton: Button;
var altitudeSlider: Slider;
var airspeedSlider: Slider;
@@ -84,11 +85,31 @@ function setup() {
/* AIC */
aic = new AIC();
setupAICFormations( aic );
aicToggleButton = new Button( "toggle-aic-button", ["images/buttons/ai-full.svg"], () => {
aicToggleButton = new Button( "toggle-aic-button", ["images/buttons/radar.svg"], () => {
aic.toggleStatus();
});
aicHelpButton = new Button( "aic-help-button", [ "images/buttons/question-mark.svg" ], () => {
aic.toggleHelp();
});
/* Generic clicks */
document.addEventListener( "click", ( ev ) => {
if ( ev instanceof PointerEvent && ev.target instanceof HTMLElement ) {
if ( ev.target.classList.contains( "olympus-dialog-close" ) ) {
ev.target.closest( "div.olympus-dialog" )?.classList.add( "hide" );
}
}
});
/* Default values */
@@ -226,55 +247,4 @@ export function getUnitControlSliders() {
}
function setupAICFormations( aic:AIC ) {
let $aicFormationList = document.getElementById( "aic-formation-list" );
if ( $aicFormationList ) {
/* // Example display
<div>
<div class="aic-formation-image">
<img src="images/formations/azimuth.png" />
</div>
<div class="aic-formation-name">Azimuth</div>
<div class="aic-formation-descriptor">(instructions)</div>
</div>
//*/
aic.getFormations().forEach( formation => {
// Image
let imageDiv = document.createElement( "div" );
imageDiv.classList.add( "aic-formation-image" );
let img = document.createElement( "img" );
img.src = "images/formations/" + formation.icon;
imageDiv.appendChild( img );
// Name
let nameDiv = document.createElement( "div" );
nameDiv.classList.add( "aic-formation-name" );
nameDiv.innerText = formation.label;
// Descriptor
let descriptorDiv = document.createElement( "div" );
descriptorDiv.classList.add( "aic-formation-descriptor" );
descriptorDiv.innerText = formation.descriptor;
// Wrapper
let wrapperDiv = document.createElement( "div" );
wrapperDiv.dataset.formationName = formation.name;
wrapperDiv.appendChild( imageDiv )
wrapperDiv.appendChild( nameDiv );
wrapperDiv.appendChild( descriptorDiv );
// Add to DOM
$aicFormationList?.appendChild( wrapperDiv );
});
}
}
window.onload = setup;

View File

@@ -1,3 +1,37 @@
export function bearing(lat1: number, lon1: number, lat2: number, lon2: number) {
const φ1 = deg2rad(lat1); // φ, λ in radians
const φ2 = deg2rad(lat2);
const λ1 = deg2rad(lon1); // φ, λ in radians
const λ2 = deg2rad(lon2);
const y = Math.sin(λ2 - λ1) * Math.cos(φ2);
const x = Math.cos(φ1) * Math.sin(φ2) - Math.sin(φ1) * Math.cos(φ2) * Math.cos(λ2 - λ1);
const θ = Math.atan2(y, x);
const brng = (rad2deg(θ) + 360) % 360; // in degrees
return brng;
}
export function ConvertDDToDMS(D: number, lng: boolean) {
var dir = D < 0 ? (lng ? "W" : "S") : lng ? "E" : "N";
var deg = 0 | (D < 0 ? (D = -D) : D);
var min = 0 | (((D += 1e-9) % 1) * 60);
var sec = (0 | (((D * 60) % 1) * 6000)) / 100;
var dec = Math.round((sec - Math.floor(sec)) * 100);
var sec = Math.floor(sec);
if (lng)
return dir + zeroPad(deg, 3) + "°" + zeroPad(min, 2) + "'" + zeroPad(sec, 2) + "." + zeroPad(dec, 2) + "\"";
else
return dir + zeroPad(deg, 2) + "°" + zeroPad(min, 2) + "'" + zeroPad(sec, 2) + "." + zeroPad(dec, 2) + "\"";
}
export function deg2rad(deg: number) {
var pi = Math.PI;
return deg * (pi / 180);
}
export function distance(lat1: number, lon1: number, lat2: number, lon2: number) {
const R = 6371e3; // metres
const φ1 = deg2rad(lat1); // φ, λ in radians
@@ -13,27 +47,24 @@ export function distance(lat1: number, lon1: number, lat2: number, lon2: number)
return d;
}
export function bearing(lat1: number, lon1: number, lat2: number, lon2: number) {
const φ1 = deg2rad(lat1); // φ, λ in radians
const φ2 = deg2rad(lat2);
const λ1 = deg2rad(lon1); // φ, λ in radians
const λ2 = deg2rad(lon2);
const y = Math.sin(λ2 - λ1) * Math.cos(φ2);
const x = Math.cos(φ1) * Math.sin(φ2) - Math.sin(φ1) * Math.cos(φ2) * Math.cos(λ2 - λ1);
const θ = Math.atan2(y, x);
const brng = (rad2deg(θ) + 360) % 360; // in degrees
return brng;
export function rad2deg(rad: number) {
var pi = Math.PI;
return rad / (pi / 180);
}
export const zeroPad = function (num: number, places: number) {
var string = String(num);
while (string.length < places) {
string += "0";
export function reciprocalHeading( heading:number ): number {
if ( heading > 180 ) {
return heading - 180;
}
return string;
return heading + 180;
}
export const zeroAppend = function (num: number, places: number) {
var string = String(num);
while (string.length < places) {
@@ -42,25 +73,11 @@ export const zeroAppend = function (num: number, places: number) {
return string;
}
export function ConvertDDToDMS(D: number, lng: boolean) {
var dir = D < 0 ? (lng ? "W" : "S") : lng ? "E" : "N";
var deg = 0 | (D < 0 ? (D = -D) : D);
var min = 0 | (((D += 1e-9) % 1) * 60);
var sec = (0 | (((D * 60) % 1) * 6000)) / 100;
var dec = Math.round((sec - Math.floor(sec)) * 100);
var sec = Math.floor(sec);
if (lng)
return dir + zeroPad(deg, 3) + "°" + zeroPad(min, 2) + "'" + zeroPad(sec, 2) + "." + zeroPad(dec, 2) + "\"";
else
return dir + zeroPad(deg, 2) + "°" + zeroPad(min, 2) + "'" + zeroPad(sec, 2) + "." + zeroPad(dec, 2) + "\"";
}
export function deg2rad(deg: number) {
var pi = Math.PI;
return deg * (pi / 180);
}
export function rad2deg(rad: number) {
var pi = Math.PI;
return rad / (pi / 180);
export const zeroPad = function (num: number, places: number) {
var string = String(num);
while (string.length < places) {
string += "0";
}
return string;
}