mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Follow feature completed
This commit is contained in:
parent
cfd98e74ea
commit
f24c57cc18
@ -7,7 +7,7 @@
|
||||
@import url("unitdatatable.css");
|
||||
@import url("unitcontrolpanel.css");
|
||||
@import url("unitinfopanel.css");
|
||||
|
||||
@import url("popup.css");
|
||||
|
||||
|
||||
* {
|
||||
@ -441,8 +441,6 @@ nav.ol-panel> :last-child {
|
||||
font-weight: var(--font-weight-bolder);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.hide {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
23
client/public/stylesheets/popup.css
Normal file
23
client/public/stylesheets/popup.css
Normal file
@ -0,0 +1,23 @@
|
||||
#info-popup {
|
||||
position: absolute;
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
top: 100px;
|
||||
left: 50%;
|
||||
translate: -50% 0%;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.ol-popup > div {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.visible {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.invisible {
|
||||
opacity: 0;
|
||||
transition: opacity 2s linear;
|
||||
}
|
||||
@ -1,7 +1,9 @@
|
||||
import { getUnitsManager } from "..";
|
||||
import { deg2rad } from "../other/utils";
|
||||
import { ContextMenu } from "./contextmenu";
|
||||
|
||||
export class UnitContextMenu extends ContextMenu {
|
||||
#callback: CallableFunction | null = null;
|
||||
#customFormationCallback: CallableFunction | null = null;
|
||||
|
||||
constructor(id: string) {
|
||||
super(id);
|
||||
@ -19,17 +21,28 @@ export class UnitContextMenu extends ContextMenu {
|
||||
clock++;
|
||||
}
|
||||
var angleDeg = 360 - (clock - 1) * 45;
|
||||
var distance = parseInt((<HTMLInputElement> dialog.querySelector(`#distance`)?.querySelector("input")).value);
|
||||
var upDown = parseInt((<HTMLInputElement> dialog.querySelector(`#up-down`)?.querySelector("input")).value);
|
||||
var asd= 1;
|
||||
var angleRad = deg2rad(angleDeg);
|
||||
var distance = parseInt((<HTMLInputElement> dialog.querySelector(`#distance`)?.querySelector("input")).value) * 0.3048;
|
||||
var upDown = parseInt((<HTMLInputElement> dialog.querySelector(`#up-down`)?.querySelector("input")).value) * 0.3048;
|
||||
|
||||
}
|
||||
// X: front-rear, positive front
|
||||
// Y: top-bottom, positive top
|
||||
// Z: left-right, positive right
|
||||
|
||||
if (this.#callback)
|
||||
this.#callback()
|
||||
var x = distance * Math.cos(angleRad);
|
||||
var y = upDown;
|
||||
var z = distance * Math.sin(angleRad);
|
||||
|
||||
if (this.#customFormationCallback)
|
||||
this.#customFormationCallback({"x": x, "y": y, "z": z})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
setCustomFormationCallback(callback: CallableFunction) {
|
||||
this.#customFormationCallback = callback;
|
||||
}
|
||||
|
||||
setOptions(options: {[key: string]: string}, callback: CallableFunction)
|
||||
{
|
||||
this.getContainer()?.replaceChildren(...Object.keys(options).map((option: string, idx: number) =>
|
||||
|
||||
@ -12,6 +12,7 @@ import { LogPanel } from "./panels/logpanel";
|
||||
import { getAirbases, getBullseye as getBullseyes, getConfig, getMission, getUnits, setAddress, toggleDemoEnabled } from "./server/server";
|
||||
import { UnitDataTable } from "./units/unitdatatable";
|
||||
import { keyEventWasInInput } from "./other/utils";
|
||||
import { Popup } from "./popups/popup";
|
||||
|
||||
var map: Map;
|
||||
|
||||
@ -27,6 +28,8 @@ var unitControlPanel: UnitControlPanel;
|
||||
var mouseInfoPanel: MouseInfoPanel;
|
||||
var logPanel: LogPanel;
|
||||
|
||||
var infoPopup: Popup;
|
||||
|
||||
var connected: boolean = false;
|
||||
var paused: boolean = false;
|
||||
var activeCoalition: string = "blue";
|
||||
@ -52,6 +55,9 @@ function setup() {
|
||||
mouseInfoPanel = new MouseInfoPanel("mouse-info-panel");
|
||||
//logPanel = new LogPanel("log-panel");
|
||||
|
||||
/* Popups */
|
||||
infoPopup = new Popup("info-popup");
|
||||
|
||||
unitDataTable = new UnitDataTable("unit-data-table");
|
||||
|
||||
/* AIC */
|
||||
@ -269,7 +275,9 @@ export function getActiveCoalition() {
|
||||
}
|
||||
|
||||
export function setConnected(newConnected: boolean) {
|
||||
connected = newConnected
|
||||
if (connected != newConnected)
|
||||
newConnected? getInfoPopup().setText("Connected to DCS Olympus server"): getInfoPopup().setText("Disconnected from DCS Olympus server");
|
||||
connected = newConnected;
|
||||
}
|
||||
|
||||
export function getConnected() {
|
||||
@ -278,10 +286,15 @@ export function getConnected() {
|
||||
|
||||
export function setPaused(newPaused: boolean) {
|
||||
paused = newPaused;
|
||||
paused? getInfoPopup().setText("Paused"): getInfoPopup().setText("Unpaused");
|
||||
}
|
||||
|
||||
export function getPaused() {
|
||||
return paused;
|
||||
}
|
||||
|
||||
export function getInfoPopup() {
|
||||
return infoPopup;
|
||||
}
|
||||
|
||||
window.onload = setup;
|
||||
26
client/src/popups/popup.ts
Normal file
26
client/src/popups/popup.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { Panel } from "../panels/panel";
|
||||
|
||||
export class Popup extends Panel {
|
||||
#fadeTime: number = 2000; // Milliseconds
|
||||
#hideTimer: number | undefined = undefined;
|
||||
#visibilityTimer: number | undefined = undefined;
|
||||
|
||||
setFadeTime(fadeTime: number) {
|
||||
this.#fadeTime = fadeTime;
|
||||
}
|
||||
|
||||
setText(text: string) {
|
||||
(<HTMLElement> this.getElement().querySelector("div")).innerText = text;
|
||||
this.show();
|
||||
this.getElement().classList.remove("invisible");
|
||||
this.getElement().classList.add("visible");
|
||||
|
||||
clearTimeout(this.#visibilityTimer);
|
||||
clearTimeout(this.#hideTimer);
|
||||
this.#visibilityTimer = setTimeout(() => {
|
||||
this.getElement().classList.remove("visible");
|
||||
this.getElement().classList.add("invisible");
|
||||
this.#hideTimer = setTimeout(() => this.hide(), 2000);
|
||||
}, this.#fadeTime);
|
||||
}
|
||||
}
|
||||
@ -476,6 +476,9 @@ export class Unit extends Marker {
|
||||
if (action === "Custom")
|
||||
{
|
||||
document.getElementById("custom-formation-dialog")?.classList.remove("hide");
|
||||
getMap().getUnitContextMenu().setCustomFormationCallback((offset: {x: number, y: number, z: number}) => {
|
||||
getUnitsManager().selectedUnitsFollowUnit(this.ID, offset);
|
||||
})
|
||||
}
|
||||
else {
|
||||
// X: front-rear, positive front
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { LatLng, LatLngBounds } from "leaflet";
|
||||
import { getMap, getUnitDataTable } from "..";
|
||||
import { getInfoPopup, getMap, getUnitDataTable } from "..";
|
||||
import { Unit } from "./unit";
|
||||
import { cloneUnit } from "../server/server";
|
||||
import { IDLE, MOVE_UNIT } from "../map/map";
|
||||
@ -176,6 +176,7 @@ export class UnitsManager {
|
||||
var commandedUnit = selectedUnits[idx];
|
||||
commandedUnit.addDestination(latlng);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, " new destination added");
|
||||
}
|
||||
|
||||
selectedUnitsClearDestinations() {
|
||||
@ -193,6 +194,7 @@ export class UnitsManager {
|
||||
{
|
||||
selectedUnits[idx].landAt(latlng);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, " landing");
|
||||
}
|
||||
|
||||
selectedUnitsChangeSpeed(speedChange: string)
|
||||
@ -220,6 +222,8 @@ export class UnitsManager {
|
||||
{
|
||||
selectedUnits[idx].setSpeed(speed);
|
||||
}
|
||||
|
||||
this.#showActionMessage(selectedUnits, `setting speed to ${speed * 1.94384} kts`);
|
||||
}
|
||||
|
||||
selectedUnitsSetAltitude(altitude: number)
|
||||
@ -229,6 +233,7 @@ export class UnitsManager {
|
||||
{
|
||||
selectedUnits[idx].setAltitude(altitude);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `setting altitude to ${altitude / 0.3048} ft`);
|
||||
}
|
||||
|
||||
selectedUnitsSetROE(ROE: string)
|
||||
@ -238,6 +243,7 @@ export class UnitsManager {
|
||||
{
|
||||
selectedUnits[idx].setROE(ROE);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `ROE set to ${ROE}`);
|
||||
}
|
||||
|
||||
selectedUnitsSetReactionToThreat(reactionToThreat: string)
|
||||
@ -247,73 +253,15 @@ export class UnitsManager {
|
||||
{
|
||||
selectedUnits[idx].setReactionToThreat(reactionToThreat);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `reaction to threat set to ${reactionToThreat}`);
|
||||
}
|
||||
|
||||
selectedUnitsAttackUnit(ID: number) {
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
for (let idx in selectedUnits) {
|
||||
/* If a unit is a wingman, send the command to its leader */
|
||||
var commandedUnit = selectedUnits[idx];
|
||||
//if (selectedUnits[idx].wingman)
|
||||
//{
|
||||
// commandedUnit = this.getLeader(selectedUnits[idx].ID);
|
||||
//}
|
||||
commandedUnit.attackUnit(ID);
|
||||
}
|
||||
}
|
||||
|
||||
selectedUnitsCreateFormation(ID: number | null = null)
|
||||
{
|
||||
var selectedUnits = this.getSelectedUnits();
|
||||
if (selectedUnits.length >= 2)
|
||||
{
|
||||
if (ID == null)
|
||||
ID = selectedUnits[0].ID
|
||||
|
||||
var wingmenIDs = [];
|
||||
for (let idx in selectedUnits)
|
||||
{
|
||||
if (selectedUnits[idx].getFormationData().isWingman)
|
||||
{
|
||||
//console.log(selectedUnits[idx].unitName + " is already in a formation.");
|
||||
return;
|
||||
}
|
||||
else if (selectedUnits[idx].getFormationData().isLeader)
|
||||
{
|
||||
//console.log(selectedUnits[idx].unitName + " is already in a formation.");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO
|
||||
if (selectedUnits[idx].category !== this.getUnitByID(ID).category)
|
||||
{
|
||||
showMessage("All units must be of the same category to create a formation.");
|
||||
}
|
||||
*/
|
||||
if (selectedUnits[idx].ID != ID)
|
||||
{
|
||||
wingmenIDs.push(selectedUnits[idx].ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (wingmenIDs.length > 0)
|
||||
{
|
||||
this.getUnitByID(ID)?.setLeader(true, wingmenIDs);
|
||||
}
|
||||
else
|
||||
{
|
||||
//console.log("At least 2 units must be selected to create a formation.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
selectedUnitsUndoFormation()
|
||||
{
|
||||
for (let leader of this.getSelectedLeaders())
|
||||
{
|
||||
leader.setLeader(false);
|
||||
selectedUnits[idx].attackUnit(ID);
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `attacking unit ${this.getUnitByID(ID)?.getBaseData().unitName}`);
|
||||
}
|
||||
|
||||
selectedUnitsDelete()
|
||||
@ -323,6 +271,7 @@ export class UnitsManager {
|
||||
{
|
||||
selectedUnits[idx].delete();
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `deleted`);
|
||||
}
|
||||
|
||||
selectedUnitsRefuel()
|
||||
@ -332,6 +281,7 @@ export class UnitsManager {
|
||||
{
|
||||
selectedUnits[idx].refuel();
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `sent to nearest tanker`);
|
||||
}
|
||||
|
||||
selectedUnitsFollowUnit(ID: number, offset: {"x": number, "y": number, "z": number}) {
|
||||
@ -342,11 +292,13 @@ export class UnitsManager {
|
||||
commandedUnit.followUnit(ID, {"x": offset.x * count, "y": offset.y * count, "z": offset.z * count} );
|
||||
count++;
|
||||
}
|
||||
this.#showActionMessage(selectedUnits, `following unit ${this.getUnitByID(ID)?.getBaseData().unitName}`);
|
||||
}
|
||||
|
||||
copyUnits()
|
||||
{
|
||||
this.#copiedUnits = this.getSelectedUnits();
|
||||
this.#showActionMessage(this.#copiedUnits, `copied`);
|
||||
}
|
||||
|
||||
pasteUnits()
|
||||
@ -357,6 +309,7 @@ export class UnitsManager {
|
||||
{
|
||||
var unit = this.#copiedUnits[idx];
|
||||
cloneUnit(unit.ID, getMap().getMouseCoordinates());
|
||||
this.#showActionMessage(this.#copiedUnits, `pasted`);
|
||||
}
|
||||
this.#pasteDisabled = true;
|
||||
setTimeout(() => this.#pasteDisabled = false, 250);
|
||||
@ -398,4 +351,11 @@ export class UnitsManager {
|
||||
else
|
||||
document.dispatchEvent(new CustomEvent("unitsDeselection", {detail: this.getSelectedUnits()}));
|
||||
}
|
||||
|
||||
#showActionMessage(units: Unit[], message: string) {
|
||||
if (units.length == 1)
|
||||
getInfoPopup().setText(`${units[0].getBaseData().unitName} ${message}`);
|
||||
else
|
||||
getInfoPopup().setText(`${units[0].getBaseData().unitName} and ${units.length - 1} other units ${message}`);
|
||||
}
|
||||
}
|
||||
@ -17,8 +17,6 @@
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div id="advanced-settings-dialog" class="ol-panel ol-dialog hide">
|
||||
<div class="ol-dialog-close" data-on-click="closeDialog"></div>
|
||||
|
||||
@ -143,7 +141,7 @@
|
||||
</div>
|
||||
|
||||
|
||||
<div id="custom-formation-dialog" class="ol-panel ol-dialog">
|
||||
<div id="custom-formation-dialog" class="ol-panel ol-dialog hide">
|
||||
<div class="ol-dialog-close" data-on-click="closeDialog"></div>
|
||||
|
||||
<div class="ol-dialog-header">
|
||||
@ -168,7 +166,7 @@
|
||||
|
||||
<div class="ol-group">
|
||||
<div id="distance" class="ol-text-input">
|
||||
<input type="number" min="0" max="99999" step="1" value="150">
|
||||
<input type="number" min="0" max="999999" step="1" value="150">
|
||||
</div>
|
||||
<label>ft</label>
|
||||
</div>
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
<%- include('connectionstatuspanel.ejs') %>
|
||||
<%- include('dialogs.ejs') %>
|
||||
<%- include('unitdatatable.ejs') %>
|
||||
<%- include('popups.ejs') %>
|
||||
|
||||
<% /* %>
|
||||
<%- include('log.ejs') %>
|
||||
|
||||
5
client/views/popups.ejs
Normal file
5
client/views/popups.ejs
Normal file
@ -0,0 +1,5 @@
|
||||
<div id="info-popup" class="ol-panel ol-popup hide">
|
||||
<div>
|
||||
<!-- Here the content of the popup will be shown -->
|
||||
</div>
|
||||
</div>
|
||||
Loading…
x
Reference in New Issue
Block a user