diff --git a/client/TODO.txt b/client/TODO.txt index 43ba41c2..5b8b49aa 100644 --- a/client/TODO.txt +++ b/client/TODO.txt @@ -4,6 +4,4 @@ scenario dropdown explosion wrong name for ground units improve map zIndex -fuel is wrong (either 0 or 1, its is casting it to int somewhere) -weapons should not be selectable human symbol if user \ No newline at end of file diff --git a/client/public/stylesheets/button.css b/client/public/stylesheets/button.css index 5540c792..d5910387 100644 --- a/client/public/stylesheets/button.css +++ b/client/public/stylesheets/button.css @@ -1,4 +1,4 @@ -.olympus-button { +.ol-button { width: 24px; height: 24px; background-color: transparent; @@ -7,11 +7,11 @@ align-items: center; } -.olympus-button img { +.ol-button img { width: 24px; height: 24px; } -.olympus-button:hover {} +.ol-button:hover {} -.olympus-button:active {} \ No newline at end of file +.ol-button:active {} \ No newline at end of file diff --git a/client/public/stylesheets/connectionstatuspanel.css b/client/public/stylesheets/connectionstatuspanel.css index fce5a084..6acc1021 100644 --- a/client/public/stylesheets/connectionstatuspanel.css +++ b/client/public/stylesheets/connectionstatuspanel.css @@ -10,7 +10,7 @@ color: white; } -.olympus-status-disconnected::after { +.ol-status-disconnected::after { content: ""; position: absolute; right: 5px; @@ -21,7 +21,7 @@ background-color: red; } -.olympus-status-connected::after { +.ol-status-connected::after { content: ""; position: absolute; right: 5px; diff --git a/client/public/stylesheets/dropdown.css b/client/public/stylesheets/dropdown.css index a9faaa44..ca735077 100644 --- a/client/public/stylesheets/dropdown.css +++ b/client/public/stylesheets/dropdown.css @@ -1,4 +1,4 @@ -.olympus-dropdown { +.ol-dropdown { width: 100%; min-width: 100px; height: 30px; @@ -18,7 +18,7 @@ padding-left: 15px; } -.olympus-dropdown::before { +.ol-dropdown::before { content: ""; position: absolute; height: 30px; @@ -31,11 +31,11 @@ border-bottom-right-radius: 15px; } -.olympus-dropdown-open { +.ol-dropdown-open { border-bottom-left-radius: 0px; } -.olympus-dropdown-open::after { +.ol-dropdown-open::after { content: ""; position: absolute; top: 13px; @@ -50,7 +50,7 @@ -webkit-transform: rotate(-135deg); } -.olympus-dropdown-closed::after { +.ol-dropdown-closed::after { content: ""; position: absolute; top: 9px; @@ -65,7 +65,7 @@ -webkit-transform: rotate(45deg); } -.olympus-dropdown-content { +.ol-dropdown-content { position: fixed; /*overflow: visible; overflow-y: scroll;*/ @@ -75,7 +75,7 @@ border-bottom-right-radius: 4px; } -.olympus-dropdown-element { +.ol-dropdown-element { margin: 2px; font-family: Verdana, Geneva, Tahoma, sans-serif; color: var(--background-color-dark); @@ -85,6 +85,6 @@ padding-left: 5px; } -.olympus-dropdown-element:hover { +.ol-dropdown-element:hover { background-color: var(--highlight-color); } \ No newline at end of file diff --git a/client/public/stylesheets/elements.css b/client/public/stylesheets/elements.css index 1ac11c9f..570c8c95 100644 --- a/client/public/stylesheets/elements.css +++ b/client/public/stylesheets/elements.css @@ -1,4 +1,4 @@ -.olympus-element-1 { +.ol-element-1 { background-color: #247be2; height: 28; border-radius: 14px; diff --git a/client/public/stylesheets/layout.css b/client/public/stylesheets/layout.css index a3d5a182..4a53250b 100644 --- a/client/public/stylesheets/layout.css +++ b/client/public/stylesheets/layout.css @@ -45,7 +45,7 @@ body { position: absolute; left: 230px; height: 30px; - width: 150; + width: fit-content; top: 10px; z-index: 1000; display: flex; diff --git a/client/public/stylesheets/panels.css b/client/public/stylesheets/panels.css index 0b00f8a6..74153621 100644 --- a/client/public/stylesheets/panels.css +++ b/client/public/stylesheets/panels.css @@ -1,5 +1,5 @@ /* Panels style */ -.olympus-panel { +.ol-panel { background-color: var(--background-color-dark); font-size: 12px; transition: bottom 0.2s; diff --git a/client/public/stylesheets/selectionscroll.css b/client/public/stylesheets/selectionscroll.css index 70cd38d3..b2913d86 100644 --- a/client/public/stylesheets/selectionscroll.css +++ b/client/public/stylesheets/selectionscroll.css @@ -1,4 +1,4 @@ -.olympus-selection-scroll-container { +.ol-selection-scroll-container { position: absolute; font-size: 12px; border-radius: 5px; @@ -13,7 +13,7 @@ align-items: center; } -#olympus-selection-scroll-top-bar { +#ol-selection-scroll-top-bar { color: white; font-size: 14px; opacity: 1; @@ -30,30 +30,30 @@ padding-right: 15px; } -.olympus-selection-scroll { +.ol-selection-scroll { overflow-x: hidden; overflow-y: auto; height: 100%; width: 100%; } -.olympus-selection-scroll::-webkit-scrollbar { +.ol-selection-scroll::-webkit-scrollbar { width: 10px; } -.olympus-selection-scroll::-webkit-scrollbar-track { +.ol-selection-scroll::-webkit-scrollbar-track { background-color: transparent; border-radius: 100px; } -.olympus-selection-scroll::-webkit-scrollbar-thumb { +.ol-selection-scroll::-webkit-scrollbar-thumb { background-color: white; border-radius: 100px; opacity: 0.8; margin-top: 10px; } -.olympus-selection-scroll-element { +.ol-selection-scroll-element { border-bottom: 1px solid #FFF5; color: white; cursor: pointer; @@ -66,25 +66,25 @@ font-weight: 600; } -.olympus-selection-scroll:last-child { +.ol-selection-scroll:last-child { border-radius: 5px; border-bottom: 0px transparent !important; } -.olympus-selection-scroll-container label { +.ol-selection-scroll-container label { display: inline-block; width: 40px; height: 24px; } -.olympus-selection-scroll-container input { +.ol-selection-scroll-container input { display: inline-block; width: 0; height: 0; margin: 0px; } -.olympus-selection-scroll-switch { +.ol-selection-scroll-switch { position: relative; display: inline-block; width: 40px; @@ -94,7 +94,7 @@ cursor: pointer; } -.olympus-selection-scroll-switch:before { +.ol-selection-scroll-switch:before { position: absolute; content: ""; height: 16px; @@ -107,13 +107,13 @@ border-radius: 999px; } -input:checked+.olympus-selection-scroll-switch:before { +input:checked+.ol-selection-scroll-switch:before { -webkit-transform: translateX(16px); -ms-transform: translateX(16px); transform: translateX(16px); } -.olympus-selection-scroll-title { +.ol-selection-scroll-title { font-size: 11px; font-weight: 600; } \ No newline at end of file diff --git a/client/public/stylesheets/selectionwheel.css b/client/public/stylesheets/selectionwheel.css index d0d56f50..a3ff61f7 100644 --- a/client/public/stylesheets/selectionwheel.css +++ b/client/public/stylesheets/selectionwheel.css @@ -1,4 +1,4 @@ -.olympus-selection-wheel { +.ol-selection-wheel { margin: 0; position: fixed; z-index: 1000; @@ -10,7 +10,7 @@ justify-content: center; } -.olympus-wheel { +.ol-wheel { width: 100%; border-radius: 50%; background-color: var(--background-color-dark); @@ -19,7 +19,7 @@ transition: background-color 0.2s; } -.olympus-wheel:before { +.ol-wheel:before { content: ""; display: block; padding-top: 100%; @@ -57,17 +57,17 @@ /*filter: invert(21%) sepia(23%) saturate(775%) hue-rotate(170deg) brightness(92%) contrast(90%);*/ } -.olympus-selection-wheel label { +.ol-selection-wheel label { width: 0; height: 0; } -.olympus-selection-wheel input { +.ol-selection-wheel input { width: 0; height: 0; } -.olympus-selection-wheel-switch { +.ol-selection-wheel-switch { position: absolute; top: 50%; left: 50%; @@ -81,7 +81,7 @@ cursor: pointer; } -.olympus-selection-wheel-switch:before { +.ol-selection-wheel-switch:before { position: absolute; content: ""; height: 26px; @@ -95,7 +95,7 @@ } -input:checked+.olympus-selection-wheel-switch:before { +input:checked+.ol-selection-wheel-switch:before { -webkit-transform: translateX(26px); -ms-transform: translateX(26px); transform: translateX(26px); diff --git a/client/public/stylesheets/style.css b/client/public/stylesheets/style.css index b68fd52a..d4c01fcc 100644 --- a/client/public/stylesheets/style.css +++ b/client/public/stylesheets/style.css @@ -184,4 +184,23 @@ html { font-size: 12px; z-index: 2000; font-weight: 600; +} + +.ol-scrollable { + overflow-y: auto; +} + +.ol-scrollable::-webkit-scrollbar { + width: 10px; +} + +.ol-scrollable::-webkit-scrollbar-track { + background-color: transparent; + border-radius: 100px; +} + +.ol-scrollable::-webkit-scrollbar-thumb { + background-color: white; + border-radius: 100px; + opacity: 0.8; } \ No newline at end of file diff --git a/client/public/stylesheets/unitcontrolpanel.css b/client/public/stylesheets/unitcontrolpanel.css index f01d791a..fc7c0eac 100644 --- a/client/public/stylesheets/unitcontrolpanel.css +++ b/client/public/stylesheets/unitcontrolpanel.css @@ -29,7 +29,10 @@ flex-direction: column; row-gap: 5px; width: 100%; - height: 100%; + height: fit-content; + max-height: 200px; + padding-top: 10px; + padding-bottom: 10px; } #formation-buttons-container { diff --git a/client/public/stylesheets/unitinfopanel.css b/client/public/stylesheets/unitinfopanel.css index ec6f24d8..ca311143 100644 --- a/client/public/stylesheets/unitinfopanel.css +++ b/client/public/stylesheets/unitinfopanel.css @@ -119,3 +119,12 @@ font-weight: 600; } +#loadout-container { + display: flex; + flex-direction: row; + flex-wrap: wrap; + column-gap: 2px; + row-gap: 2px; + min-height: 0px; + max-height: 70px; /* TODO: fix me, magic number */ +} diff --git a/client/public/stylesheets/visibilitycontrolpanel.css b/client/public/stylesheets/visibilitycontrolpanel.css index 92ad6bef..5e637c0a 100644 --- a/client/public/stylesheets/visibilitycontrolpanel.css +++ b/client/public/stylesheets/visibilitycontrolpanel.css @@ -1,4 +1,16 @@ -#visibility-control-panel .olympus-button { - filter: invert(100%); - opacity: 0.8; -} \ No newline at end of file +#visibility-control-panel +{ + display: flex; + column-gap: 10px; +} + +#visibility-control-panel .label { + color: white; + font-size: 12px; + font-weight: 600; +} + +#visibility-control-panel .vl { + height: 60%; +} + diff --git a/client/src/controls/dropdown.ts b/client/src/controls/dropdown.ts index 68b73a2a..aded3cd6 100644 --- a/client/src/controls/dropdown.ts +++ b/client/src/controls/dropdown.ts @@ -20,10 +20,10 @@ export class Dropdown { open() { if (this.#container != null) { this.#open = true; - this.#container.classList.add("olympus-dropdown-open"); - this.#container.classList.remove("olympus-dropdown-closed"); + this.#container.classList.add("ol-dropdown-open"); + this.#container.classList.remove("ol-dropdown-closed"); this.#content = document.createElement("div"); - this.#content.classList.add("olympus-dropdown-content"); + this.#content.classList.add("ol-dropdown-content"); this.#content.style.width = (this.#container.offsetWidth - this.#container.offsetHeight) + "px"; this.#content.style.left = this.#container.offsetLeft + "px"; @@ -34,7 +34,7 @@ export class Dropdown { var height = 2; for (let optionID in this.#options) { var node = document.createElement("div"); - node.classList.add("olympus-dropdown-element"); + node.classList.add("ol-dropdown-element"); node.appendChild(document.createTextNode(this.#options[optionID])); this.#content.appendChild(node); height += node.offsetHeight + 2; @@ -53,8 +53,8 @@ export class Dropdown { close() { if (this.#container != null) { this.#open = false; - this.#container?.classList.remove("olympus-dropdown-open"); - this.#container?.classList.add("olympus-dropdown-closed"); + this.#container?.classList.remove("ol-dropdown-open"); + this.#container?.classList.add("ol-dropdown-closed"); if (this.#content != null) document.body.removeChild(this.#content); } diff --git a/client/src/controls/selectionscroll.ts b/client/src/controls/selectionscroll.ts index 7a518371..e4322e73 100644 --- a/client/src/controls/selectionscroll.ts +++ b/client/src/controls/selectionscroll.ts @@ -20,18 +20,17 @@ export class SelectionScroll { this.hide(); if (this.#container != null && options.length >= 1) { - var titleDiv = this.#container.querySelector("#olympus-selection-scroll-top-bar")?.querySelector(".olympus-selection-scroll-title"); + var titleDiv = this.#container.querySelector("#ol-selection-scroll-top-bar")?.querySelector(".ol-selection-scroll-title"); if (titleDiv) titleDiv.innerHTML = title; this.#container.style.display = this.#display; - this.#container.style.left = x - this.#container.offsetWidth / 2 + "px"; - this.#container.style.top = y - 20 + "px"; - var scroll = this.#container.querySelector(".olympus-selection-scroll"); + + var scroll = this.#container.querySelector(".ol-selection-scroll"); if (scroll != null) { for (let optionID in options) { var node = document.createElement("div"); - node.classList.add("olympus-selection-scroll-element"); + node.classList.add("ol-selection-scroll-element"); if (typeof options[optionID] === 'string' || options[optionID] instanceof String){ node.appendChild(document.createTextNode(options[optionID])); node.addEventListener('click', () => callback(options[optionID])); @@ -45,7 +44,7 @@ export class SelectionScroll { } /* Hide the coalition switch if required */ - var switchContainer = this.#container.querySelector("#olympus-selection-scroll-top-bar")?.querySelector("#coalition-switch-container"); + var switchContainer = this.#container.querySelector("#ol-selection-scroll-top-bar")?.querySelector("#coalition-switch-container"); if (showCoalition == false) { switchContainer.style.display = "none"; document.documentElement.style.setProperty('--active-coalition-color', getComputedStyle(this.#container).getPropertyValue("--neutral-coalition-color")); @@ -57,14 +56,26 @@ export class SelectionScroll { else document.documentElement.style.setProperty('--active-coalition-color', getComputedStyle(this.#container).getPropertyValue("--red-coalition-color")); } + + if (x - this.#container.offsetWidth / 2 + this.#container.offsetWidth < window.innerWidth) + this.#container.style.left = x - this.#container.offsetWidth / 2 + "px"; + else + this.#container.style.left = window.innerWidth - this.#container.offsetWidth + "px"; + + console.log(y - 20 + this.#container.offsetHeight) + if (y - 20 + this.#container.offsetHeight < window.innerHeight) + this.#container.style.top = y - 20 + "px"; + else + this.#container.style.top = window.innerHeight - this.#container.offsetHeight + "px"; + } } hide() { if (this.#container != null) { this.#container.style.display = "none"; - var buttons = this.#container.querySelectorAll(".olympus-selection-scroll-element"); - var scroll = this.#container.querySelector(".olympus-selection-scroll"); + var buttons = this.#container.querySelectorAll(".ol-selection-scroll-element"); + var scroll = this.#container.querySelector(".ol-selection-scroll"); if (scroll != null) { for (let child of buttons) { diff --git a/client/src/index.ts b/client/src/index.ts index 3a4925d6..24b56f2c 100644 --- a/client/src/index.ts +++ b/client/src/index.ts @@ -11,6 +11,7 @@ import { MissionData } from "./missiondata/missiondata"; import { UnitControlPanel } from "./panels/unitcontrolpanel"; import { MouseInfoPanel } from "./panels/mouseInfoPanel"; import { Slider } from "./controls/slider"; +import { VisibilityControlPanel } from "./panels/visibilitycontrolpanel"; /* TODO: should this be a class? */ var map: Map; @@ -24,6 +25,7 @@ var unitInfoPanel: UnitInfoPanel; var connectionStatusPanel: ConnectionStatusPanel; var unitControlPanel: UnitControlPanel; var mouseInfoPanel: MouseInfoPanel; +var visibilityControlPanel: VisibilityControlPanel; var scenarioDropdown: Dropdown; var mapSourceDropdown: Dropdown; @@ -32,11 +34,6 @@ var slowButton: Button; var fastButton: Button; var climbButton: Button; var descendButton: Button; -var userVisibilityButton: Button; -var aiVisibilityButton: Button; -var uncontrolledVisibilityButton: Button; -var weaponVisibilityButton: Button; -var deadVisibilityButton: Button; var altitudeSlider: Slider; var airspeedSlider: Slider; @@ -47,15 +44,20 @@ var activeCoalition: string; function setup() { /* Initialize */ map = new Map('map-container'); + unitsManager = new UnitsManager(); + selectionWheel = new SelectionWheel("selection-wheel"); selectionScroll = new SelectionScroll("selection-scroll"); - unitsManager = new UnitsManager(); + unitInfoPanel = new UnitInfoPanel("unit-info-panel"); unitControlPanel = new UnitControlPanel("unit-control-panel"); - scenarioDropdown = new Dropdown("scenario-dropdown", ["Caucasus", "Syria", "Marianas", "Nevada", "South Atlantic", "The channel"], () => { }); - mapSourceDropdown = new Dropdown("map-source-dropdown", map.getLayers(), (option: string) => map.setLayer(option)); connectionStatusPanel = new ConnectionStatusPanel("connection-status-panel"); mouseInfoPanel = new MouseInfoPanel("mouse-info-panel"); + visibilityControlPanel = new VisibilityControlPanel("visibility-control-panel"); + + scenarioDropdown = new Dropdown("scenario-dropdown", ["Caucasus", "Syria", "Marianas", "Nevada", "South Atlantic", "The channel"], () => { }); + mapSourceDropdown = new Dropdown("map-source-dropdown", map.getLayers(), (option: string) => map.setLayer(option)); + missionData = new MissionData(); /* Unit control buttons */ @@ -68,18 +70,6 @@ function setup() { altitudeSlider = new Slider("altitude-slider", 0, 100, "ft", (value: number) => getUnitsManager().selectedUnitsSetAltitude(value * 0.3048)); airspeedSlider = new Slider("airspeed-slider", 0, 100, "kts", (value: number) => getUnitsManager().selectedUnitsSetSpeed(value / 1.94384)); - /* Visibility buttons */ - userVisibilityButton = new Button("user-visibility-button", ["images/buttons/user-full.svg", "images/buttons/user-partial.svg", "images/buttons/user-none.svg", "images/buttons/user-hidden.svg"], () => { getUnitsManager().forceUpdate() }); - aiVisibilityButton = new Button("ai-visibility-button", ["images/buttons/ai-full.svg", "images/buttons/ai-partial.svg", "images/buttons/ai-none.svg", "images/buttons/ai-hidden.svg"], () => { getUnitsManager().forceUpdate() }); - uncontrolledVisibilityButton = new Button("uncontrolled-visibility-button", ["images/buttons/ai-full.svg", "images/buttons/ai-partial.svg", "images/buttons/ai-none.svg", "images/buttons/ai-hidden.svg"], () => { getUnitsManager().forceUpdate() }); - weaponVisibilityButton = new Button("weapon-visibility-button", ["images/buttons/weapon-partial.svg", "images/buttons/weapon-none.svg", "images/buttons/weapon-hidden.svg"], () => { getUnitsManager().forceUpdate() }); - deadVisibilityButton = new Button("dead-visibility-button", ["images/buttons/dead.svg", "images/buttons/dead-hidden.svg"], () => { getUnitsManager().forceUpdate() }); - - aiVisibilityButton.setState(1); - uncontrolledVisibilityButton.setState(3); - weaponVisibilityButton.setState(1); - deadVisibilityButton.setState(1); - /* Default values */ activeCoalition = "blue"; connected = false; @@ -147,70 +137,6 @@ export function getConnected() { return connected; } -export function getVisibilitySettings() { - var visibility = { - user: "", - ai: "", - uncontrolled: "", - weapon: "", - dead: "" - }; - - switch (userVisibilityButton.getState()) { - case 0: - visibility.user = "full"; break; - case 1: - visibility.user = "partial"; break; - case 2: - visibility.user = "none"; break; - case 3: - visibility.user = "hidden"; break; - } - - switch (aiVisibilityButton.getState()) { - case 0: - visibility.ai = "full"; break; - case 1: - visibility.ai = "partial"; break; - case 2: - visibility.ai = "none"; break; - case 3: - visibility.ai = "hidden"; break; - } - - switch (uncontrolledVisibilityButton.getState()) { - case 0: - visibility.uncontrolled = "full"; break; - case 1: - visibility.uncontrolled = "partial"; break; - case 2: - visibility.uncontrolled = "none"; break; - case 3: - visibility.uncontrolled = "hidden"; break; - } - - switch (weaponVisibilityButton.getState()) { - case 0: - visibility.weapon = "partial"; break; - case 1: - visibility.weapon = "none"; break; - case 2: - visibility.weapon = "hidden"; break; - } - - switch (deadVisibilityButton.getState()) { - case 0: - visibility.dead = "none"; break; - case 1: - visibility.dead = "hidden"; break; - } - return visibility; -} - -export function getVisibilityButtons() { - return {user: userVisibilityButton, ai: aiVisibilityButton, weapon: weaponVisibilityButton, dead: deadVisibilityButton} -} - export function getUnitControlSliders() { return {altitude: altitudeSlider, airspeed: airspeedSlider} } diff --git a/client/src/panels/connectionstatuspanel.ts b/client/src/panels/connectionstatuspanel.ts index f1ece049..87525048 100644 --- a/client/src/panels/connectionstatuspanel.ts +++ b/client/src/panels/connectionstatuspanel.ts @@ -11,13 +11,13 @@ export class ConnectionStatusPanel { if (div != null) { if (connected) { div.innerHTML = "Connected"; - div.classList.add("olympus-status-connected"); - div.classList.remove("olympus-status-disconnected"); + div.classList.add("ol-status-connected"); + div.classList.remove("ol-status-disconnected"); } else { div.innerHTML = "Disconnected"; - div.classList.add("olympus-status-disconnected"); - div.classList.remove("olympus-status-connected"); + div.classList.add("ol-status-disconnected"); + div.classList.remove("ol-status-connected"); } } } diff --git a/client/src/panels/unitinfopanel.ts b/client/src/panels/unitinfopanel.ts index 070d1dda..2887c0ed 100644 --- a/client/src/panels/unitinfopanel.ts +++ b/client/src/panels/unitinfopanel.ts @@ -26,7 +26,7 @@ export class UnitInfoPanel { if (this.#element != null) { var els = this.#element.getElementsByClassName("js-loadout-element"); while (els.length > 0) - this.#element.querySelector("#loadout-data")?.removeChild(els[0]); + this.#element.querySelector("#loadout-container")?.removeChild(els[0]); for (let index in unit.ammo) { var ammo = unit.ammo[index]; @@ -35,7 +35,7 @@ export class UnitInfoPanel { var el = document.createElement("div") el.classList.add("js-loadout-element", "rectangular-container-dark") el.innerHTML = amount + "x" + displayName; - this.#element.querySelector("#loadout-data")?.appendChild(el); + this.#element.querySelector("#loadout-container")?.appendChild(el); } this.#element.querySelector("#unit-name")!.innerHTML = unit.unitName; diff --git a/client/src/panels/visibilitycontrolpanel.ts b/client/src/panels/visibilitycontrolpanel.ts new file mode 100644 index 00000000..e4c6b402 --- /dev/null +++ b/client/src/panels/visibilitycontrolpanel.ts @@ -0,0 +1,80 @@ +import { AirUnit, GroundUnit, NavyUnit, Weapon } from "../units/unit"; + +export class VisibilityControlPanel { + #element: HTMLElement + + constructor(ID: string) { + this.#element = document.getElementById(ID); + + if (this.#element != null) + { + var airVisibilityCheckbox = this.#element.querySelector("#air-visibility"); + var groundVisibilityCheckbox = this.#element.querySelector("#ground-visibility"); + var navyVisibilityCheckbox = this.#element.querySelector("#navy-visibility"); + var weaponVisibilityCheckbox = this.#element.querySelector("#weapon-visibility"); + + airVisibilityCheckbox?.addEventListener("change", () => this.#onChange()); + groundVisibilityCheckbox?.addEventListener("change", () => this.#onChange()); + navyVisibilityCheckbox?.addEventListener("change", () => this.#onChange()); + weaponVisibilityCheckbox?.addEventListener("change", () => this.#onChange()); + + var fullVisibilitySelection = this.#element.querySelector("#full-visibility"); + var partialVisibilitySelection = this.#element.querySelector("#partial-visibility"); + var minimalVisibilitySelection = this.#element.querySelector("#minimal-visibility"); + + fullVisibilitySelection?.addEventListener("change", () => this.#onChange()); + partialVisibilitySelection?.addEventListener("change", () => this.#onChange()); + minimalVisibilitySelection?.addEventListener("change", () => this.#onChange()); + + var uncontrolledVisibilityCheckbox = this.#element.querySelector("#uncontrolled-visibility"); + uncontrolledVisibilityCheckbox?.addEventListener("change", () => this.#onChange()); + } + } + + #onChange(){ + if (this.#element != null) + { + var fullVisibilitySelection = this.#element.querySelector("#full-visibility"); + var partialVisibilitySelection = this.#element.querySelector("#partial-visibility"); + var minimalVisibilitySelection = this.#element.querySelector("#minimal-visibility"); + + var activeVisibility = ""; + if (fullVisibilitySelection.checked) + activeVisibility = "full"; + else if (partialVisibilitySelection.checked) + activeVisibility = "partial"; + else if (minimalVisibilitySelection.checked) + activeVisibility = "minimal"; + + var uncontrolledVisibilityCheckbox = this.#element.querySelector("#uncontrolled-visibility"); + var uncontrolledVisibility = !uncontrolledVisibilityCheckbox.checked; + + var airVisibilityCheckbox = this.#element.querySelector("#air-visibility"); + if (airVisibilityCheckbox.checked) + AirUnit.setVisibility({human: activeVisibility, ai: activeVisibility, uncontrolled: uncontrolledVisibility? activeVisibility: "hidden", dead: "hidden"}); + else + AirUnit.setVisibility({human: "hidden", ai: "hidden", uncontrolled: "hidden", dead: "hidden"}); + + var groundVisibilityCheckbox = this.#element.querySelector("#ground-visibility"); + if (groundVisibilityCheckbox.checked) + GroundUnit.setVisibility({human: activeVisibility, ai: activeVisibility, uncontrolled: uncontrolledVisibility? activeVisibility: "hidden", dead: "hidden"}); + else + GroundUnit.setVisibility({human: "hidden", ai: "hidden", uncontrolled: "hidden", dead: "hidden"}); + + var navyVisibilityCheckbox = this.#element.querySelector("#navy-visibility"); + if (navyVisibilityCheckbox.checked) + NavyUnit.setVisibility({human: activeVisibility, ai: activeVisibility, uncontrolled: uncontrolledVisibility? activeVisibility: "hidden", dead: "hidden"}); + else + NavyUnit.setVisibility({human: "hidden", ai: "hidden", uncontrolled: "hidden", dead: "hidden"}); + + var weaponVisibilityCheckbox = this.#element.querySelector("#weapon-visibility"); + if (weaponVisibilityCheckbox.checked) + Weapon.setVisibility({human: activeVisibility, ai: activeVisibility, uncontrolled: uncontrolledVisibility? activeVisibility: "hidden", dead: "hidden"}); + else + Weapon.setVisibility({human: "hidden", ai: "hidden", uncontrolled: "hidden", dead: "hidden"}); + } + + } + + +} \ No newline at end of file diff --git a/client/src/units/unit.ts b/client/src/units/unit.ts index 9e9c1b3a..918967b6 100644 --- a/client/src/units/unit.ts +++ b/client/src/units/unit.ts @@ -1,9 +1,15 @@ import { Marker, LatLng, Polyline, Icon } from 'leaflet'; -import { ConvertDDToDMS } from '../other/utils'; -import { getMap, getUnitsManager, getVisibilitySettings } from '..'; +import { getMap, getUnitsManager} from '..'; import { UnitMarker, MarkerOptions, AircraftMarker, HelicopterMarker, GroundUnitMarker, NavyUnitMarker, WeaponMarker } from './unitmarker'; import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, landAt, setAltitude, setReactionToThreat, setROE, setSpeed } from '../dcs/dcs'; +interface visibilityOptions { + dead: string; + ai: string; + uncontrolled: string; + human: string; +} + var pathIcon = new Icon({ iconUrl: 'images/marker-icon.png', shadowUrl: 'images/marker-shadow.png', @@ -387,20 +393,33 @@ export class Unit { } export class AirUnit extends Unit { - getHidden() { - if (this.AI == false && getVisibilitySettings().uncontrolled === "hidden") - return true + static visibility: visibilityOptions = {dead: "hidden", ai: "partial", uncontrolled: "partial", human: "partial"} + static setVisibility(visibility: visibilityOptions) + { + getUnitsManager().forceUpdate(); + AirUnit.visibility = visibility; + } + static getVisibility() + { + return AirUnit.visibility; + } + + getHidden() { if (this.alive) { - if (this.flags.user && getVisibilitySettings().user === "hidden") - return true - else if (!this.flags.user && getVisibilitySettings().ai === "hidden") - return true + if (this.flags.user) + return AirUnit.getVisibility().human === "hidden" + + if (this.AI) + return AirUnit.getVisibility().ai === "hidden" + else + return AirUnit.getVisibility().uncontrolled === "hidden" } else - return getVisibilitySettings().dead === "hidden" - return false; + { + return AirUnit.getVisibility().dead === "hidden" + } } } @@ -419,52 +438,87 @@ export class Helicopter extends AirUnit { } export class GroundUnit extends Unit { + static visibility: visibilityOptions = {dead: "hidden", ai: "partial", uncontrolled: "partial", human: "partial"} + static setVisibility(visibility: visibilityOptions) + { + getUnitsManager().forceUpdate(); + GroundUnit.visibility = visibility; + } + + static getVisibility() + { + return GroundUnit.visibility; + } + constructor(ID: number, options: MarkerOptions) { var marker = new GroundUnitMarker(options); super(ID, marker); } getHidden() { - if (this.AI == false && getVisibilitySettings().uncontrolled === "hidden") - return true - if (this.alive) { - if (this.flags.user && getVisibilitySettings().user === "hidden") - return true - else if (!this.flags.user && getVisibilitySettings().ai === "hidden") - return true + if (this.flags.user) + return GroundUnit.getVisibility().human === "hidden" + + if (this.AI) + return GroundUnit.getVisibility().ai === "hidden" + else + return GroundUnit.getVisibility().uncontrolled === "hidden" } else - return getVisibilitySettings().dead === "hidden" - return false; + { + return GroundUnit.getVisibility().dead === "hidden" + } } } export class NavyUnit extends Unit { + static visibility: visibilityOptions = {dead: "hidden", ai: "partial", uncontrolled: "partial", human: "partial"} + static setVisibility(visibility: visibilityOptions) + { + getUnitsManager().forceUpdate(); + NavyUnit.visibility = visibility; + } + + static getVisibility() + { + return NavyUnit.visibility; + } + constructor(ID: number, options: MarkerOptions) { var marker = new NavyUnitMarker(options); super(ID, marker); } getHidden() { - if (this.AI == false && getVisibilitySettings().uncontrolled === "hidden") - return true - if (this.alive) { - if (this.flags.user && getVisibilitySettings().user === "hidden") - return true - else if (!this.flags.user && getVisibilitySettings().ai === "hidden") - return true + if (this.AI) + return NavyUnit.getVisibility().ai === "hidden" + else + return NavyUnit.getVisibility().uncontrolled === "hidden" } else - return getVisibilitySettings().dead === "hidden" - return false; + { + return NavyUnit.getVisibility().dead === "hidden" + } } } export class Weapon extends Unit { + static visibility: visibilityOptions = {dead: "hidden", ai: "partial", uncontrolled: "partial", human: "partial"} + static setVisibility(visibility: visibilityOptions) + { + getUnitsManager().forceUpdate(); + Weapon.visibility = visibility; + } + + static getVisibility() + { + return Weapon.visibility; + } + constructor(ID: number, marker: UnitMarker) { super(ID, marker); @@ -473,13 +527,9 @@ export class Weapon extends Unit { getHidden() { if (this.alive) - { - if (!this.flags.user && getVisibilitySettings().weapon === "hidden") - return true - } + return Weapon.getVisibility().uncontrolled === "hidden" else - return getVisibilitySettings().dead === "hidden" - return false; + return true; } } diff --git a/client/src/units/unitmarker.ts b/client/src/units/unitmarker.ts index c981a6f6..55c2297a 100644 --- a/client/src/units/unitmarker.ts +++ b/client/src/units/unitmarker.ts @@ -1,6 +1,6 @@ import * as L from 'leaflet' import { Symbol } from 'milsymbol' -import { getVisibilitySettings } from '..' +import { AirUnit, GroundUnit, NavyUnit, Weapon } from './unit' export interface MarkerOptions { unitName: string @@ -88,13 +88,13 @@ export class UnitMarker extends L.Marker { speedDiv.style.display = ''; /* If visibility is partial shown only icon and unit name. If none, shown only icon. */ - if (this.getVisibility() === "partial" || this.getVisibility() === "none") + if (this.getVisibility() === "partial" || this.getVisibility() === "minimal") { unitNameDiv.style.display = 'none'; altitudeDiv.style.display = 'none'; speedDiv.style.display = 'none'; } - if (this.getVisibility() === "none" && nameDiv.style.display != 'none') + if (this.getVisibility() === "minimal" && nameDiv.style.display != 'none') nameDiv.style.display = 'none'; nameDiv.style.left = (-(nameDiv.offsetWidth - container.offsetWidth) / 2) + "px"; @@ -225,15 +225,19 @@ export class UnitMarker extends L.Marker { export class AirUnitMarker extends UnitMarker { getVisibility() { - if (this.getSelected()) - return "full"; - - if (this.getHuman()) - return getVisibilitySettings().user; - else if (!this.getAlive()) - return "none"; - else - return this.getAI()? getVisibilitySettings().ai: getVisibilitySettings().uncontrolled; + if (this.getAlive()) + { + if (this.getSelected()) + return "full"; + else if (this.getHuman()) + return AirUnit.getVisibility().human; + else if (this.getAI()) + return AirUnit.getVisibility().ai; + else + return AirUnit.getVisibility().uncontrolled; + } + else + return "minimal"; } } @@ -246,38 +250,54 @@ export class HelicopterMarker extends AirUnitMarker { export class GroundUnitMarker extends UnitMarker { /* Are user driven units recognized as human? */ getVisibility() { - if (this.getSelected()) - return "full"; - - if (this.getHuman()) - return getVisibilitySettings().user; - else if (!this.getAlive()) - return "none"; - else - return this.getAI()? getVisibilitySettings().ai: getVisibilitySettings().uncontrolled; + if (this.getAlive()) + { + if (this.getSelected()) + return "full"; + else if (this.getHuman()) + return GroundUnit.getVisibility().human; + else if (this.getAI()) + return GroundUnit.getVisibility().ai; + else + return GroundUnit.getVisibility().uncontrolled; + } + else + return "minimal"; } } export class NavyUnitMarker extends UnitMarker { getVisibility() { - if (this.getSelected()) - return "full"; - - if (!this.getAlive()) - return "none"; - else - return this.getAI()? getVisibilitySettings().ai: getVisibilitySettings().uncontrolled; + if (this.getAlive()) + { + if (this.getSelected()) + return "full"; + else if (this.getHuman()) + return NavyUnit.getVisibility().human; + else if (this.getAI()) + return NavyUnit.getVisibility().ai; + else + return NavyUnit.getVisibility().uncontrolled; + } + else + return "minimal"; } } export class WeaponMarker extends UnitMarker { getVisibility() { - if (this.getSelected()) - return "full"; - - if (!this.getAlive()) - return "none"; - else - return getVisibilitySettings().weapon; + if (this.getAlive()) + { + if (this.getSelected()) + return "full"; + else if (this.getHuman()) + return Weapon.getVisibility().human; + else if (this.getAI()) + return Weapon.getVisibility().ai; + else + return Weapon.getVisibility().uncontrolled; + } + else + return "minimal"; } } \ No newline at end of file diff --git a/client/views/connectionstatuspanel.ejs b/client/views/connectionstatuspanel.ejs index 47f4636f..ad74ea88 100644 --- a/client/views/connectionstatuspanel.ejs +++ b/client/views/connectionstatuspanel.ejs @@ -1,3 +1,3 @@ -
-
Connected
+
+
Connected
\ No newline at end of file diff --git a/client/views/index.ejs b/client/views/index.ejs index 885d97c5..ecfaa7be 100644 --- a/client/views/index.ejs +++ b/client/views/index.ejs @@ -13,8 +13,8 @@
<%- include('selectionwheel.ejs') %> <%- include('selectionscroll.ejs') %> -
- +
+ <%- include('unitinfopanel.ejs') %> <%- include('unitcontrolpanel.ejs') %> <%- include('visibilitycontrolpanel.ejs') %> diff --git a/client/views/mouseinfopanel.ejs b/client/views/mouseinfopanel.ejs index 4e6bac2c..bfa98c02 100644 --- a/client/views/mouseinfopanel.ejs +++ b/client/views/mouseinfopanel.ejs @@ -1,4 +1,4 @@ -
+
---° / --- NM
---° / --- NM
---° / --- NM
diff --git a/client/views/selectionscroll.ejs b/client/views/selectionscroll.ejs index 3a78b420..581a4f97 100644 --- a/client/views/selectionscroll.ejs +++ b/client/views/selectionscroll.ejs @@ -1,11 +1,11 @@ -
-
-
+
+
+
-
+
\ No newline at end of file diff --git a/client/views/selectionwheel.ejs b/client/views/selectionwheel.ejs index f8a149c6..bf714b7c 100644 --- a/client/views/selectionwheel.ejs +++ b/client/views/selectionwheel.ejs @@ -1,8 +1,8 @@ -
-
+
+
\ No newline at end of file diff --git a/client/views/unitcontrolpanel.ejs b/client/views/unitcontrolpanel.ejs index fba42229..b589f4ec 100644 --- a/client/views/unitcontrolpanel.ejs +++ b/client/views/unitcontrolpanel.ejs @@ -1,14 +1,14 @@ -
-
-
-
-
-
+
+
+
+
+
+
Selected units
-
+
diff --git a/client/views/unitinfopanel.ejs b/client/views/unitinfopanel.ejs index 03ffd10f..345bbd77 100644 --- a/client/views/unitinfopanel.ejs +++ b/client/views/unitinfopanel.ejs @@ -1,4 +1,4 @@ -
+
@@ -26,5 +26,8 @@
Fuel
+
+ +
\ No newline at end of file diff --git a/client/views/visibilitycontrolpanel.ejs b/client/views/visibilitycontrolpanel.ejs index 7103e935..861028b9 100644 --- a/client/views/visibilitycontrolpanel.ejs +++ b/client/views/visibilitycontrolpanel.ejs @@ -1,7 +1,44 @@ -
-
-
-
-
-
+
+
Air:
+
+ +
+ +
Ground:
+
+ +
+ +
Navy:
+
+ +
+ +
Weapons:
+
+ +
+ +
+ +
Full:
+
+ +
+ +
Partial:
+
+ +
+ +
Minimal:
+
+ +
+ +
+
Olympus only:
+
+ +
\ No newline at end of file diff --git a/img/icon-38x38.png b/img/icon-38x38.png new file mode 100644 index 00000000..9ddcb4b9 Binary files /dev/null and b/img/icon-38x38.png differ diff --git a/img/icon.xcf b/img/icon.xcf new file mode 100644 index 00000000..c33dd3ed Binary files /dev/null and b/img/icon.xcf differ diff --git a/img/incon_active.png b/img/incon_active.png new file mode 100644 index 00000000..3b69985d Binary files /dev/null and b/img/incon_active.png differ diff --git a/installer/DCSOlympus.iss b/installer/DCSOlympus.iss index 61c67383..479b72a5 100644 --- a/installer/DCSOlympus.iss +++ b/installer/DCSOlympus.iss @@ -2,10 +2,11 @@ [Setup] AppName=DCS Olympus -AppVerName=DCS Olympus Alpha v0.0.5 +AppVerName=DCS Olympus Alpha v0.0.7 DefaultDirName={usersavedgames}\DCS.openbeta DefaultGroupName=DCSOlympus OutputBaseFilename=DCSOlympus +UninstallFilesDir={app}\Mods\Services\Olympus [Tasks] ; NOTE: The following entry contains English phrases ("Create a desktop icon" and "Additional icons"). You are free to translate them into another language if required. @@ -15,11 +16,13 @@ Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{ [Files] ; NOTE: Don't use "Flags: ignoreversion" on any shared system files Source: "..\scripts\OlympusExport.lua"; DestDir: "{app}\Scripts"; Flags: ignoreversion +Source: "..\scripts\OlympusPatcher.exe"; DestDir: "{app}\Scripts"; Flags: ignoreversion Source: "..\scripts\OlympusHook.lua"; DestDir: "{app}\Scripts\Hooks"; Flags: ignoreversion Source: "..\scripts\OlympusCommand.lua"; DestDir: "{app}\Mods\Services\Olympus\Scripts"; Flags: ignoreversion Source: "..\scripts\unitPayloads.lua"; DestDir: "{app}\Mods\Services\Olympus\Scripts"; Flags: ignoreversion Source: "..\scripts\OlympusMission.lua"; DestDir: "{app}\Mods\Services\Olympus\Scripts"; Flags: ignoreversion Source: "..\scripts\mist_4_4_90.lua"; DestDir: "{app}\Mods\Services\Olympus\Scripts"; Flags: ignoreversion +Source: "..\mod\*.*"; DestDir: "{app}\Mods\Services\Olympus"; Flags: ignoreversion; Source: "..\bin\*.dll"; DestDir: "{app}\Mods\Services\Olympus\bin"; Flags: ignoreversion; Source: "..\client\bin\*"; DestDir: "{app}\Mods\Services\Olympus\client\bin"; Flags: ignoreversion; Source: "..\client\node_modules\*"; DestDir: "{app}\Mods\Services\Olympus\client\node_modules"; Flags: ignoreversion recursesubdirs; @@ -55,4 +58,10 @@ Root: HKCU; Subkey: "Environment"; ValueType: expandsz; ValueName: "Path"; Value ChangesEnvironment=yes [Icons] -Name: "{userdesktop}\DCS Olympus Client"; Filename: "{app}\Mods\Services\Olympus\client\nw.exe"; Tasks: desktopicon \ No newline at end of file +Name: "{userdesktop}\DCS Olympus Client"; Filename: "{app}\Mods\Services\Olympus\client\nw.exe"; Tasks: desktopicon + +[Run] +Filename: "{app}\Scripts\OlympusPatcher.exe"; Parameters: "-i" + +[UninstallRun] +Filename: "{app}\Scripts\OlympusPatcher.exe"; Parameters: "-u" \ No newline at end of file diff --git a/mod/Options/options.dlg b/mod/Options/options.dlg new file mode 100644 index 00000000..db77ba48 --- /dev/null +++ b/mod/Options/options.dlg @@ -0,0 +1,163 @@ + +-- Olympus + +-- Layout + +local TopMargin = 48 +local LeftMargin = 32 +local CenterMargin = 80 + +local LeftColumnX = LeftMargin +local LeftColumnLabelWidth = 232 +local LeftColumnOptionWidth = 272 +local LeftColumnWidth = LeftColumnLabelWidth + LeftColumnOptionWidth + +local RightColumnX = LeftColumnX + LeftColumnWidth + CenterMargin +local RightColumnLabelWidth = 192 +local RightColumnOptionWidth = 128 +local RightColumnWidth = RightColumnLabelWidth + RightColumnOptionWidth + +local LineHeight = 24 +local TotalLineHeight = LineHeight + 8 + +local HelpLineHeight = 16 + +-- Styles + +local TitleSkin = { + ["params"] = { + ["name"] = "staticOptionsTitleSkin", + }, + ["states"] = { + ["released"] = { + [1] = { + ["text"] = { + ["horzAlign"] = { + ["type"] = "min" + } + } + } + } + } + } + +local OptionLabelSkin = { + ["params"] = { + ["name"] = "staticOptionsCaptionSkin", + } + } + +local WarningSkin = { + ["params"] = { + ["name"] = "staticOptionsCaptionSkin", + }, + ["states"] = { + ["released"] = { + [1] = { + ["text"] = { + ["horzAlign"] = { + ["type"] = "min" + }, + ["color"] = "0xEFB441ff", + } + } + } + } + } + +local CheckBoxSkin = { + ["params"] = { + ["name"] = "checkBoxSkin_options", + } + } + +local ComboListSkin = { + ["params"] = { + ["name"] = "comboListSkin_options", + } + } + +local EditBoxSkin = { + ["params"] = { + ["name"] = "editBoxSkin_login", + } + } + +-- Content + +dialog = { + ["children"] = { + ["containerPlugin"] = { + ["children"] = { + + ----------------------------------------------- + -- [X] Enable Olympus Module + ----------------------------------------------- + + -- Olympus Module Enabled + + ["olympusModuleEnabledCheckbox"] = { + ["params"] = { + ["bounds"] = { + ["x"] = LeftColumnX, + ["y"] = TopMargin, + ["w"] = 256, + ["h"] = LineHeight, + }, + ["enabled"] = true, + ["state"] = false, + ["text"] = "$Olympus_MODULE_ENABLED_LABEL", + ["tooltip"] = "", + ["visible"] = true, + ["zindex"] = 0, + ["tabOrder"] = 1, + }, + ["skin"] = CheckBoxSkin, + ["type"] = "CheckBox", + }, + }, + ["params"] = { + ["bounds"] = { + ["h"] = 600, + ["w"] = 974, + ["x"] = 0, + ["y"] = 0, + }, + ["enabled"] = true, + ["text"] = "", + ["tooltip"] = "", + ["visible"] = true, + ["zindex"] = 0, + }, + ["skin"] = { + ["params"] = { + ["name"] = "panelSkin", + }, + }, + ["type"] = "Panel", + }, + }, + ["params"] = { + ["bounds"] = { + ["h"] = 851, + ["w"] = 1135, + ["x"] = 0, + ["y"] = 0, + }, + ["draggable"] = true, + ["enabled"] = true, + ["hasCursor"] = true, + ["lockFlow"] = false, + ["modal"] = false, + ["offscreen"] = false, + ["resizable"] = false, + ["text"] = "New dialog", + ["zOrder"] = 0, + }, + ["skin"] = { + ["params"] = { + ["name"] = "windowSkin", + }, + }, + ["type"] = "Window", +} \ No newline at end of file diff --git a/mod/Options/optionsData.lua b/mod/Options/optionsData.lua new file mode 100644 index 00000000..68c333d3 --- /dev/null +++ b/mod/Options/optionsData.lua @@ -0,0 +1,7 @@ +cdata = +{ + -- Module on/off + + Olympus_MODULE_ENABLED_LABEL = _("Olympus Module Enabled"), + +} diff --git a/mod/Options/optionsDb.lua b/mod/Options/optionsDb.lua new file mode 100644 index 00000000..6379b762 --- /dev/null +++ b/mod/Options/optionsDb.lua @@ -0,0 +1,60 @@ +local DbOption = require("Options.DbOption") +local i18n = require('i18n') + +-- Constants + + +-- Local variables + +local olympusConfigDialog = nil + +-- Update UI + +local function UpdateOptions() + + -- Check parameters + + if olympusConfigDialog == nil then + return + end + + local moduleEnabled = olympusConfigDialog.olympusModuleEnabledCheckbox:getState() + +end + +-- Callbacks + +local function OnShowDialog(dialogBox) + + -- Setup local variables + + if olympusConfigDialog ~= dialogBox then + olympusConfigDialog = dialogBox + end + + -- Update dialog box state + + UpdateOptions() + +end + +-- Module on/off + +local olympusModuleEnabled = DbOption.new():setValue(true):checkbox() +:callback(function(value) + UpdateOptions() +end) + +-- Returns dialog box controls and callbacks + +return +{ + -- Events + + callbackOnShowDialog = OnShowDialog, + + -- Module on/off + + olympusModuleEnabled = olympusModuleEnabled, + +} diff --git a/mod/Theme/icon-38x38.png b/mod/Theme/icon-38x38.png new file mode 100644 index 00000000..9ddcb4b9 Binary files /dev/null and b/mod/Theme/icon-38x38.png differ diff --git a/mod/Theme/icon.png b/mod/Theme/icon.png new file mode 100644 index 00000000..d4b60c09 Binary files /dev/null and b/mod/Theme/icon.png differ diff --git a/mod/Theme/icon_active.png b/mod/Theme/icon_active.png new file mode 100644 index 00000000..3b69985d Binary files /dev/null and b/mod/Theme/icon_active.png differ diff --git a/mod/Theme/icon_select.png b/mod/Theme/icon_select.png new file mode 100644 index 00000000..3b69985d Binary files /dev/null and b/mod/Theme/icon_select.png differ diff --git a/mod/entry.lua b/mod/entry.lua new file mode 100644 index 00000000..4cd8d578 --- /dev/null +++ b/mod/entry.lua @@ -0,0 +1,42 @@ +local self_ID = "DCS-Olympus" + +declare_plugin(self_ID, +{ + image = "Olympus.png", + installed = true, -- if false that will be place holder , or advertising + dirName = current_mod_path, + binaries = + { +-- 'Olympus', + }, + load_immediately = true, + + displayName = "Olympus", + shortName = "Olympus", + fileMenuName = "Olympus", + + version = "0.0.7", + state = "installed", + developerName= "DCS Refugees 767 squadron", + info = _("DCS Olympus is a mod for DCS World. It allows users to spawn, control, task, group, and remove units from a DCS World server using a real-time map interface, similarly to Real Time Strategy games. The user interface also provides useful informations units, like loadouts, fuel, tasking, and so on. In the future, more features for DCS World GCI and JTAC will be available."), + + Skins = + { + { + name = "Olympus", + dir = "Theme" + }, + }, + + Options = + { + { + name = "Olympus", + nameId = "Olympus", + dir = "Options", + CLSID = "{Olympus-options}" + }, + }, +}) + +plugin_done() \ No newline at end of file diff --git a/scripts/Export.lua b/scripts/Export.lua deleted file mode 100644 index f60c236d..00000000 --- a/scripts/Export.lua +++ /dev/null @@ -1 +0,0 @@ -local Olympuslfs=require('lfs');dofile(Olympuslfs.writedir()..'Scripts/OlympusExport.lua') diff --git a/scripts/OlympusCommand.lua b/scripts/OlympusCommand.lua index 6f45160f..65a58eed 100644 --- a/scripts/OlympusCommand.lua +++ b/scripts/OlympusCommand.lua @@ -137,7 +137,7 @@ function Olympus.move(ID, lat, lng, altitude, speed, category, taskOptions) Olympus.notify("Olympus.move not implemented yet for " .. category, 2) end else - Olympus.notify("Error in Olympus.move " .. unitName, 2) + Olympus.notify("Error in Olympus.move " .. ID, 2) end end diff --git a/scripts/OlympusPatcher.exe b/scripts/OlympusPatcher.exe new file mode 100644 index 00000000..ee35a74d Binary files /dev/null and b/scripts/OlympusPatcher.exe differ diff --git a/scripts/OlympusPatcher.py b/scripts/OlympusPatcher.py new file mode 100644 index 00000000..bcfc1ce1 --- /dev/null +++ b/scripts/OlympusPatcher.py @@ -0,0 +1,42 @@ +import shutil +import sys + +START_STRING = "/* Olympus START */\n" +END_STRING = "/* Olympus END */\n" +EXPORT_STRING = "local Olympuslfs=require('lfs');dofile(Olympuslfs.writedir()..'Scripts/OlympusExport.lua')\n" + +def main(flag): + if flag == "-i": + try: + with open("Export.lua", "r") as f: + shutil.copyfile("Export.lua", "Export.lua.bak") + lines = f.readlines() + if START_STRING in lines: + return + except FileNotFoundError: + print('File does not exist') + + with open("Export.lua", "a") as f: + f.writelines(["\n", START_STRING, EXPORT_STRING, END_STRING, "\n"]) + elif flag == "-u": + try: + with open("Export.lua", "r") as f: + shutil.copyfile("Export.lua", "Export.lua.bak") + lines = f.readlines() + except FileNotFoundError: + print('File does not exist') + + with open("Export.lua", "w") as f: + block = False + for line in lines: + if line == START_STRING: + block = True + + if not block: + f.write(line) + + if line == END_STRING: + block = False + +if __name__ == "__main__": + main(sys.argv[1]) diff --git a/src/core/include/Scheduler.h b/src/core/include/Scheduler.h index a7f1210f..68792841 100644 --- a/src/core/include/Scheduler.h +++ b/src/core/include/Scheduler.h @@ -13,9 +13,7 @@ public: void execute(lua_State* L); void handleRequest(wstring key, json::value value); - private: list commands; - mutex mutexLock; }; diff --git a/src/core/include/Unit.h b/src/core/include/Unit.h index 3b99897b..4b0a30b2 100644 --- a/src/core/include/Unit.h +++ b/src/core/include/Unit.h @@ -105,9 +105,6 @@ protected: Coords oldPosition = Coords(0); // Used to approximate speed virtual void AIloop() = 0; - -private: - mutex mutexLock; }; diff --git a/src/core/src/Scheduler.cpp b/src/core/src/Scheduler.cpp index 119c9f87..d855dbfa 100644 --- a/src/core/src/Scheduler.cpp +++ b/src/core/src/Scheduler.cpp @@ -24,8 +24,6 @@ void Scheduler::appendCommand(Command* command) void Scheduler::execute(lua_State* L) { - /* Lock for thread safety */ - lock_guard guard(mutexLock); int priority = CommandPriority::HIGH; while (priority >= CommandPriority::LOW) { @@ -51,8 +49,6 @@ void Scheduler::execute(lua_State* L) void Scheduler::handleRequest(wstring key, json::value value) { - /* Lock for thread safety */ - lock_guard guard(mutexLock); Command* command = nullptr; log(L"Received request with ID: " + key); diff --git a/src/core/src/Unit.cpp b/src/core/src/Unit.cpp index 86f4c36d..5b814869 100644 --- a/src/core/src/Unit.cpp +++ b/src/core/src/Unit.cpp @@ -25,9 +25,6 @@ Unit::~Unit() void Unit::updateExportData(json::value json) { - /* Lock for thread safety */ - lock_guard guard(mutexLock); - /* Compute speed (loGetWorldObjects does not provide speed, we compute it for better performance instead of relying on many lua calls) */ if (oldPosition != NULL) { @@ -77,11 +74,8 @@ void Unit::updateExportData(json::value json) void Unit::updateMissionData(json::value json) { - /* Lock for thread safety */ - lock_guard guard(mutexLock); - if (json.has_number_field(L"fuel")) - fuel = json[L"fuel"].as_number().to_int32(); + fuel = int(json[L"fuel"].as_number().to_double() * 100); if (json.has_object_field(L"ammo")) ammo = json[L"ammo"]; if (json.has_object_field(L"targets")) @@ -92,9 +86,6 @@ void Unit::updateMissionData(json::value json) json::value Unit::json() { - /* Lock for thread safety */ - lock_guard guard(mutexLock); - auto json = json::value::object(); json[L"alive"] = alive; diff --git a/src/core/src/core.cpp b/src/core/src/core.cpp index 24849509..cd2740e1 100644 --- a/src/core/src/core.cpp +++ b/src/core/src/core.cpp @@ -13,11 +13,15 @@ Server* server = nullptr; Scheduler* scheduler = nullptr; json::value airbasesData; json::value bullseyeData; - +mutex mutexLock; +bool initialized = false; /* Called when DCS simulation stops. All singleton instances are deleted. */ extern "C" DllExport int coreDeinit(lua_State* L) { + if (!initialized) + return (0); + log("Olympus coreDeinit called successfully"); delete unitsFactory; @@ -38,11 +42,18 @@ extern "C" DllExport int coreInit(lua_State* L) registerLuaFunctions(L); + initialized = true; return(0); } extern "C" DllExport int coreFrame(lua_State* L) { + if (!initialized) + return (0); + + /* Lock for thread safety */ + lock_guard guard(mutexLock); + const std::chrono::duration duration = std::chrono::system_clock::now() - before; // TODO make intervals editable @@ -65,6 +76,12 @@ extern "C" DllExport int coreFrame(lua_State* L) extern "C" DllExport int coreMissionData(lua_State * L) { + if (!initialized) + return (0); + + /* Lock for thread safety */ + lock_guard guard(mutexLock); + lua_getglobal(L, "Olympus"); lua_getfield(L, -1, "missionData"); json::value missionData = luaTableToJSON(L, -1); diff --git a/src/core/src/server.cpp b/src/core/src/server.cpp index f70ff8c5..a33e4eab 100644 --- a/src/core/src/server.cpp +++ b/src/core/src/server.cpp @@ -11,6 +11,7 @@ extern UnitsFactory* unitsFactory; extern Scheduler* scheduler; extern json::value airbasesData; extern json::value bullseyeData; +extern mutex mutexLock; void handle_eptr(std::exception_ptr eptr) { @@ -49,6 +50,9 @@ void Server::handle_options(http_request request) void Server::handle_get(http_request request) { + /* Lock for thread safety */ + lock_guard guard(mutexLock); + http_response response(status_codes::OK); response.headers().add(U("Allow"), U("GET, POST, PUT, OPTIONS")); response.headers().add(U("Access-Control-Allow-Origin"), U("*")); @@ -107,6 +111,9 @@ void Server::handle_put(http_request request) request, [](json::value const& jvalue, json::value& answer) { + /* Lock for thread safety */ + lock_guard guard(mutexLock); + for (auto const& e : jvalue.as_object()) { auto key = e.first;