mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
Compare commits
9 Commits
v0.4.0
...
v0.4.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3b4c4ae36 | ||
|
|
fd7f4b9772 | ||
|
|
bac2c430ef | ||
|
|
3f1c9942c3 | ||
|
|
80ed675cbc | ||
|
|
6d434e48a1 | ||
|
|
7961870ac4 | ||
|
|
0150ae9df1 | ||
|
|
875f3ebe68 |
@@ -33,22 +33,7 @@ const DEMO_UNIT_DATA = {
|
|||||||
ammo: [{ quantity: 2, name: "A cool missile", guidance: 0, category: 0, missileCategory: 0 } ],
|
ammo: [{ quantity: 2, name: "A cool missile", guidance: 0, category: 0, missileCategory: 0 } ],
|
||||||
contacts: [{ID: 1, detectionMethod: 16}],
|
contacts: [{ID: 1, detectionMethod: 16}],
|
||||||
activePath: [ ]
|
activePath: [ ]
|
||||||
}, ["3"]:{ category: "Missile", alive: true, human: false, controlled: false, coalition: 1, country: 0, name: "", unitName: "Cool guy 1-3", groupName: "Cool group 3", state: 1, task: "Being cool",
|
}, ["3"]:{ category: "Helicopter", alive: true, human: false, controlled: false, coalition: 1, country: 0, name: "AH-64D_BLK_II", unitName: "Cool guy 1-4", groupName: "Cool group 3", state: 1, task: "Being cool",
|
||||||
hasTask: false, position: { lat: 37.1, lng: -116, alt: 1000 }, speed: 200, heading: 315 * Math.PI / 180, isTanker: false, isAWACS: false, onOff: true, followRoads: false, fuel: 50,
|
|
||||||
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
|
|
||||||
formationOffset: { x: 0, y: 0, z: 0 },
|
|
||||||
targetID: 0,
|
|
||||||
targetPosition: { lat: 0, lng: 0, alt: 0 },
|
|
||||||
ROE: 2,
|
|
||||||
reactionToThreat: 1,
|
|
||||||
emissionsCountermeasures: 1,
|
|
||||||
TACAN: { isOn: false, XY: 'Y', callsign: 'TKR', channel: 40 },
|
|
||||||
radio: { frequency: 124000000, callsign: 1, callsignNumber: 1 },
|
|
||||||
generalSettings: { prohibitAA: false, prohibitAfterburner: false, prohibitAG: false, prohibitAirWpn: false, prohibitJettison: false },
|
|
||||||
ammo: [{ quantity: 2, name: "A cool missile", guidance: 0, category: 0, missileCategory: 0 } ],
|
|
||||||
contacts: [{ID: 1, detectionMethod: 16}],
|
|
||||||
activePath: [ ]
|
|
||||||
}, ["4"]:{ category: "Helicopter", alive: true, human: false, controlled: false, coalition: 1, country: 0, name: "AH-64D_BLK_II", unitName: "Cool guy 1-4", groupName: "Cool group 3", state: 1, task: "Being cool",
|
|
||||||
hasTask: false, position: { lat: 37.1, lng: -116.1, alt: 1000 }, speed: 200, heading: 315 * Math.PI / 180, isTanker: false, isAWACS: false, onOff: true, followRoads: false, fuel: 50,
|
hasTask: false, position: { lat: 37.1, lng: -116.1, alt: 1000 }, speed: 200, heading: 315 * Math.PI / 180, isTanker: false, isAWACS: false, onOff: true, followRoads: false, fuel: 50,
|
||||||
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
|
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
|
||||||
formationOffset: { x: 0, y: 0, z: 0 },
|
formationOffset: { x: 0, y: 0, z: 0 },
|
||||||
@@ -63,7 +48,7 @@ const DEMO_UNIT_DATA = {
|
|||||||
ammo: [{ quantity: 2, name: "A cool missile", guidance: 0, category: 0, missileCategory: 0 } ],
|
ammo: [{ quantity: 2, name: "A cool missile", guidance: 0, category: 0, missileCategory: 0 } ],
|
||||||
contacts: [{ID: 1, detectionMethod: 16}],
|
contacts: [{ID: 1, detectionMethod: 16}],
|
||||||
activePath: [ ]
|
activePath: [ ]
|
||||||
}, ["5"]:{ category: "GroundUnit", alive: true, human: false, controlled: true, coalition: 1, country: 0, name: "Gepard", unitName: "Cool guy 2-1", groupName: "Cool group 4", state: 1, task: "Being cool",
|
}, ["4"]:{ category: "GroundUnit", alive: true, human: false, controlled: true, coalition: 1, country: 0, name: "Gepard", unitName: "Cool guy 2-1", groupName: "Cool group 4", state: 1, task: "Being cool",
|
||||||
hasTask: false, position: { lat: 37.2, lng: -116.1, alt: 1000 }, speed: 200, heading: 315 * Math.PI / 180, isTanker: false, isAWACS: false, onOff: true, followRoads: false, fuel: 50,
|
hasTask: false, position: { lat: 37.2, lng: -116.1, alt: 1000 }, speed: 200, heading: 315 * Math.PI / 180, isTanker: false, isAWACS: false, onOff: true, followRoads: false, fuel: 50,
|
||||||
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
|
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
|
||||||
formationOffset: { x: 0, y: 0, z: 0 },
|
formationOffset: { x: 0, y: 0, z: 0 },
|
||||||
@@ -76,10 +61,10 @@ const DEMO_UNIT_DATA = {
|
|||||||
radio: { frequency: 124000000, callsign: 1, callsignNumber: 1 },
|
radio: { frequency: 124000000, callsign: 1, callsignNumber: 1 },
|
||||||
generalSettings: { prohibitAA: false, prohibitAfterburner: false, prohibitAG: false, prohibitAirWpn: false, prohibitJettison: false },
|
generalSettings: { prohibitAA: false, prohibitAfterburner: false, prohibitAG: false, prohibitAirWpn: false, prohibitJettison: false },
|
||||||
ammo: [{ quantity: 2, name: "A cool missile\0Ciao", guidance: 0, category: 0, missileCategory: 0 } ],
|
ammo: [{ quantity: 2, name: "A cool missile\0Ciao", guidance: 0, category: 0, missileCategory: 0 } ],
|
||||||
contacts: [{ID: 1, detectionMethod: 16}],
|
contacts: [{ID: 1001, detectionMethod: 16}],
|
||||||
activePath: [ ],
|
activePath: [ ],
|
||||||
isLeader: true
|
isLeader: true
|
||||||
}, ["6"]:{ category: "GroundUnit", alive: true, human: false, controlled: true, coalition: 1, country: 0, name: "Gepard", unitName: "Cool guy 2-2", groupName: "Cool group 4", state: 1, task: "Being cool",
|
}, ["5"]:{ category: "GroundUnit", alive: true, human: false, controlled: true, coalition: 1, country: 0, name: "Gepard", unitName: "Cool guy 2-2", groupName: "Cool group 4", state: 1, task: "Being cool",
|
||||||
hasTask: false, position: { lat: 37.21, lng: -116.1, alt: 1000 }, speed: 200, heading: 315 * Math.PI / 180, isTanker: false, isAWACS: false, onOff: true, followRoads: false, fuel: 50,
|
hasTask: false, position: { lat: 37.21, lng: -116.1, alt: 1000 }, speed: 200, heading: 315 * Math.PI / 180, isTanker: false, isAWACS: false, onOff: true, followRoads: false, fuel: 50,
|
||||||
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
|
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
|
||||||
formationOffset: { x: 0, y: 0, z: 0 },
|
formationOffset: { x: 0, y: 0, z: 0 },
|
||||||
@@ -92,16 +77,21 @@ const DEMO_UNIT_DATA = {
|
|||||||
radio: { frequency: 124000000, callsign: 1, callsignNumber: 1 },
|
radio: { frequency: 124000000, callsign: 1, callsignNumber: 1 },
|
||||||
generalSettings: { prohibitAA: false, prohibitAfterburner: false, prohibitAG: false, prohibitAirWpn: false, prohibitJettison: false },
|
generalSettings: { prohibitAA: false, prohibitAfterburner: false, prohibitAG: false, prohibitAirWpn: false, prohibitJettison: false },
|
||||||
ammo: [{ quantity: 2, name: "A cool missile", guidance: 0, category: 0, missileCategory: 0 } ],
|
ammo: [{ quantity: 2, name: "A cool missile", guidance: 0, category: 0, missileCategory: 0 } ],
|
||||||
contacts: [{ID: 1, detectionMethod: 16}],
|
contacts: [],
|
||||||
activePath: [ ],
|
activePath: [ ],
|
||||||
isLeader: false
|
isLeader: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DEMO_WEAPONS_DATA = {
|
||||||
|
["1001"]:{ category: "Missile", alive: true, coalition: 2, name: "", position: { lat: 37.1, lng: -116, alt: 1000 }, speed: 200, heading: 45 * Math.PI / 180 },
|
||||||
|
}
|
||||||
|
|
||||||
class DemoDataGenerator {
|
class DemoDataGenerator {
|
||||||
constructor(app)
|
constructor(app)
|
||||||
{
|
{
|
||||||
app.get('/demo/units', (req, res) => this.units(req, res));
|
app.get('/demo/units', (req, res) => this.units(req, res));
|
||||||
|
app.get('/demo/weapons', (req, res) => this.weapons(req, res));
|
||||||
app.get('/demo/logs', (req, res) => this.logs(req, res));
|
app.get('/demo/logs', (req, res) => this.logs(req, res));
|
||||||
app.get('/demo/bullseyes', (req, res) => this.bullseyes(req, res));
|
app.get('/demo/bullseyes', (req, res) => this.bullseyes(req, res));
|
||||||
app.get('/demo/airbases', (req, res) => this.airbases(req, res));
|
app.get('/demo/airbases', (req, res) => this.airbases(req, res));
|
||||||
@@ -168,6 +158,25 @@ class DemoDataGenerator {
|
|||||||
res.end(Buffer.from(array, 'binary'));
|
res.end(Buffer.from(array, 'binary'));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
weapons(req, res){
|
||||||
|
var array = new Uint8Array();
|
||||||
|
var time = Date.now();
|
||||||
|
array = this.concat(array, this.uint64ToByteArray(BigInt(time)));
|
||||||
|
for (let idx in DEMO_WEAPONS_DATA) {
|
||||||
|
const weapon = DEMO_WEAPONS_DATA[idx];
|
||||||
|
array = this.concat(array, this.uint32ToByteArray(idx));
|
||||||
|
array = this.appendString(array, weapon.category, 1);
|
||||||
|
array = this.appendUint8(array, weapon.alive, 2);
|
||||||
|
array = this.appendUint16(array, weapon.coalition, 5);
|
||||||
|
array = this.appendString(array, weapon.name, 7);
|
||||||
|
array = this.appendCoordinates(array, weapon.position, 13);
|
||||||
|
array = this.appendDouble(array, weapon.speed, 14);
|
||||||
|
array = this.appendDouble(array, weapon.heading, 15);
|
||||||
|
array = this.concat(array, this.uint8ToByteArray(255));
|
||||||
|
}
|
||||||
|
res.end(Buffer.from(array, 'binary'));
|
||||||
|
};
|
||||||
|
|
||||||
concat(array1, array2) {
|
concat(array1, array2) {
|
||||||
var mergedArray = new Uint8Array(array1.length + array2.length);
|
var mergedArray = new Uint8Array(array1.length + array2.length);
|
||||||
mergedArray.set(array1);
|
mergedArray.set(array1);
|
||||||
|
|||||||
446
client/package-lock.json
generated
446
client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
|||||||
"name": "DCSOlympus",
|
"name": "DCSOlympus",
|
||||||
"node-main": "./bin/www",
|
"node-main": "./bin/www",
|
||||||
"main": "http://localhost:3000",
|
"main": "http://localhost:3000",
|
||||||
"version": "v0.4.0-alpha",
|
"version": "v0.4.1-alpha",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"copy": "copy.bat",
|
"copy": "copy.bat",
|
||||||
@@ -10,35 +10,35 @@
|
|||||||
"watch": "watchify .\\src\\index.ts --debug -o .\\public\\javascripts\\bundle.js -t [ babelify --global true --presets [ @babel/preset-env ] --extensions '.js'] -p [ tsify --noImplicitAny ]"
|
"watch": "watchify .\\src\\index.ts --debug -o .\\public\\javascripts\\bundle.js -t [ babelify --global true --presets [ @babel/preset-env ] --extensions '.js'] -p [ tsify --noImplicitAny ]"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@turf/turf": "^6.5.0",
|
|
||||||
"@types/formatcoords": "^1.1.0",
|
|
||||||
"@types/geojson": "^7946.0.10",
|
|
||||||
"@types/leaflet": "^1.9.0",
|
|
||||||
"@types/svg-injector": "^0.0.29",
|
|
||||||
"cookie-parser": "~1.4.4",
|
"cookie-parser": "~1.4.4",
|
||||||
"debug": "~2.6.9",
|
"debug": "~2.6.9",
|
||||||
"ejs": "^3.1.8",
|
"ejs": "^3.1.8",
|
||||||
"express": "~4.16.1",
|
"express": "~4.16.1",
|
||||||
"formatcoords": "^1.1.3",
|
|
||||||
"leaflet": "^1.9.3",
|
|
||||||
"leaflet-control-mini-map": "^0.4.0",
|
|
||||||
"leaflet-path-drag": "*",
|
|
||||||
"leaflet.nauticscale": "^1.1.0",
|
|
||||||
"morgan": "~1.9.1",
|
"morgan": "~1.9.1",
|
||||||
"save": "^2.9.0"
|
"save": "^2.9.0",
|
||||||
|
"express-basic-auth": "^1.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/preset-env": "^7.21.4",
|
"@babel/preset-env": "^7.21.4",
|
||||||
"@tanem/svg-injector": "^10.1.55",
|
"@tanem/svg-injector": "^10.1.55",
|
||||||
|
"@turf/turf": "^6.5.0",
|
||||||
|
"@types/formatcoords": "^1.1.0",
|
||||||
|
"@types/geojson": "^7946.0.10",
|
||||||
"@types/gtag.js": "^0.0.12",
|
"@types/gtag.js": "^0.0.12",
|
||||||
|
"@types/leaflet": "^1.9.0",
|
||||||
"@types/node": "^18.16.1",
|
"@types/node": "^18.16.1",
|
||||||
"@types/sortablejs": "^1.15.0",
|
"@types/sortablejs": "^1.15.0",
|
||||||
|
"@types/svg-injector": "^0.0.29",
|
||||||
"babelify": "^10.0.0",
|
"babelify": "^10.0.0",
|
||||||
"browserify": "^17.0.0",
|
"browserify": "^17.0.0",
|
||||||
"concurrently": "^7.6.0",
|
"concurrently": "^7.6.0",
|
||||||
"cp": "^0.2.0",
|
"cp": "^0.2.0",
|
||||||
"esmify": "^2.1.1",
|
"esmify": "^2.1.1",
|
||||||
"express-basic-auth": "^1.2.1",
|
"formatcoords": "^1.1.3",
|
||||||
|
"leaflet": "^1.9.3",
|
||||||
|
"leaflet-control-mini-map": "^0.4.0",
|
||||||
|
"leaflet-path-drag": "*",
|
||||||
|
"leaflet.nauticscale": "^1.1.0",
|
||||||
"nodemon": "^2.0.20",
|
"nodemon": "^2.0.20",
|
||||||
"sortablejs": "^1.15.0",
|
"sortablejs": "^1.15.0",
|
||||||
"tsify": "^5.0.4",
|
"tsify": "^5.0.4",
|
||||||
|
|||||||
2
client/src/@types/unit.d.ts
vendored
2
client/src/@types/unit.d.ts
vendored
@@ -1,6 +1,6 @@
|
|||||||
import { LatLng } from "leaflet"
|
import { LatLng } from "leaflet"
|
||||||
|
|
||||||
interface UnitIconOptions {
|
interface ObjectIconOptions {
|
||||||
showState: boolean,
|
showState: boolean,
|
||||||
showVvi: boolean,
|
showVvi: boolean,
|
||||||
showHotgroup: boolean,
|
showHotgroup: boolean,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Dropdown } from "../controls/dropdown";
|
import { Dropdown } from "../controls/dropdown";
|
||||||
import { zeroAppend } from "../other/utils";
|
import { zeroAppend } from "../other/utils";
|
||||||
import { ATC } from "./atc";
|
import { ATC } from "./atc";
|
||||||
import { Unit } from "../units/unit";
|
import { Unit } from "../unit/unit";
|
||||||
import { getMissionHandler, getUnitsManager } from "..";
|
import { getMissionHandler, getUnitsManager } from "..";
|
||||||
import Sortable from "sortablejs";
|
import Sortable from "sortablejs";
|
||||||
import { FlightInterface } from "./atc";
|
import { FlightInterface } from "./atc";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { getUnitsManager } from "..";
|
import { getUnitsManager } from "..";
|
||||||
import { Panel } from "../panels/panel";
|
import { Panel } from "../panels/panel";
|
||||||
import { Unit } from "../units/unit";
|
import { Unit } from "../unit/unit";
|
||||||
|
|
||||||
export class UnitDataTable extends Panel {
|
export class UnitDataTable extends Panel {
|
||||||
constructor(id: string) {
|
constructor(id: string) {
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ export const CARPET_BOMBING = "Carpet bombing";
|
|||||||
export const FIRE_AT_AREA = "Fire at area";
|
export const FIRE_AT_AREA = "Fire at area";
|
||||||
export const COALITIONAREA_DRAW_POLYGON = "Draw Coalition Area";
|
export const COALITIONAREA_DRAW_POLYGON = "Draw Coalition Area";
|
||||||
export const visibilityControls: string[] = ["human", "dcs", "aircraft", "groundunit-sam", "groundunit-other", "navyunit", "airbase"];
|
export const visibilityControls: string[] = ["human", "dcs", "aircraft", "groundunit-sam", "groundunit-other", "navyunit", "airbase"];
|
||||||
|
export const visibilityControlsTypes: string[][] = [["human"], ["dcs"], ["aircraft"], ["groundunit-sam", "groundunit-sam-radar", "groundunit-sam-launcher"], ["groundunit-other", "groundunit-ewr"], ["navyunit"], ["airbase"]];
|
||||||
export const visibilityControlsTootlips: string[] = ["Toggle human players visibility", "Toggle DCS controlled units visibility", "Toggle aircrafts visibility", "Toggle SAM units visibility", "Toggle ground units (not SAM) visibility", "Toggle navy units visibility", "Toggle airbases visibility"];
|
export const visibilityControlsTootlips: string[] = ["Toggle human players visibility", "Toggle DCS controlled units visibility", "Toggle aircrafts visibility", "Toggle SAM units visibility", "Toggle ground units (not SAM) visibility", "Toggle navy units visibility", "Toggle airbases visibility"];
|
||||||
|
|
||||||
export const IADSTypes = ["AAA", "MANPADS", "SAM Site", "Radar"];
|
export const IADSTypes = ["AAA", "MANPADS", "SAM Site", "Radar"];
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { ContextMenu } from "./contextmenu";
|
|||||||
import { Dropdown } from "./dropdown";
|
import { Dropdown } from "./dropdown";
|
||||||
import { Slider } from "./slider";
|
import { Slider } from "./slider";
|
||||||
import { Switch } from "./switch";
|
import { Switch } from "./switch";
|
||||||
import { groundUnitDatabase } from "../units/groundunitdatabase";
|
import { groundUnitDatabase } from "../unit/groundunitdatabase";
|
||||||
import { createCheckboxOption, getCheckboxOptions } from "../other/utils";
|
import { createCheckboxOption, getCheckboxOptions } from "../other/utils";
|
||||||
|
|
||||||
export class CoalitionAreaContextMenu extends ContextMenu {
|
export class CoalitionAreaContextMenu extends ContextMenu {
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import { LatLng } from "leaflet";
|
import { LatLng } from "leaflet";
|
||||||
import { getActiveCoalition, getMap, getMissionHandler, getUnitsManager, setActiveCoalition } from "..";
|
import { getActiveCoalition, getMap, getMissionHandler, getUnitsManager, setActiveCoalition } from "..";
|
||||||
import { spawnExplosion, spawnSmoke } from "../server/server";
|
import { spawnExplosion, spawnSmoke } from "../server/server";
|
||||||
import { aircraftDatabase } from "../units/aircraftdatabase";
|
import { aircraftDatabase } from "../unit/aircraftdatabase";
|
||||||
import { groundUnitDatabase } from "../units/groundunitdatabase";
|
import { groundUnitDatabase } from "../unit/groundunitdatabase";
|
||||||
import { helicopterDatabase } from "../units/helicopterdatabase";
|
import { helicopterDatabase } from "../unit/helicopterdatabase";
|
||||||
import { ContextMenu } from "./contextmenu";
|
import { ContextMenu } from "./contextmenu";
|
||||||
import { Dropdown } from "./dropdown";
|
import { Dropdown } from "./dropdown";
|
||||||
import { Switch } from "./switch";
|
import { Switch } from "./switch";
|
||||||
import { Slider } from "./slider";
|
import { Slider } from "./slider";
|
||||||
import { ftToM } from "../other/utils";
|
import { ftToM } from "../other/utils";
|
||||||
import { GAME_MASTER } from "../constants/constants";
|
import { GAME_MASTER } from "../constants/constants";
|
||||||
import { navyUnitDatabase } from "../units/navyunitdatabase";
|
import { navyUnitDatabase } from "../unit/navyunitdatabase";
|
||||||
import { CoalitionArea } from "../map/coalitionarea";
|
import { CoalitionArea } from "../map/coalitionarea";
|
||||||
|
|
||||||
export class MapContextMenu extends ContextMenu {
|
export class MapContextMenu extends ContextMenu {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Map } from "./map/map"
|
import { Map } from "./map/map"
|
||||||
import { UnitsManager } from "./units/unitsmanager";
|
import { UnitsManager } from "./unit/unitsmanager";
|
||||||
import { UnitInfoPanel } from "./panels/unitinfopanel";
|
import { UnitInfoPanel } from "./panels/unitinfopanel";
|
||||||
import { ConnectionStatusPanel } from "./panels/connectionstatuspanel";
|
import { ConnectionStatusPanel } from "./panels/connectionstatuspanel";
|
||||||
import { MissionHandler } from "./mission/missionhandler";
|
import { MissionHandler } from "./mission/missionhandler";
|
||||||
@@ -18,10 +18,12 @@ import { HotgroupPanel } from "./panels/hotgrouppanel";
|
|||||||
import { SVGInjector } from "@tanem/svg-injector";
|
import { SVGInjector } from "@tanem/svg-injector";
|
||||||
import { BLUE_COMMANDER, GAME_MASTER, RED_COMMANDER } from "./constants/constants";
|
import { BLUE_COMMANDER, GAME_MASTER, RED_COMMANDER } from "./constants/constants";
|
||||||
import { ServerStatusPanel } from "./panels/serverstatuspanel";
|
import { ServerStatusPanel } from "./panels/serverstatuspanel";
|
||||||
|
import { WeaponsManager } from "./weapon/weaponsmanager";
|
||||||
|
|
||||||
var map: Map;
|
var map: Map;
|
||||||
|
|
||||||
var unitsManager: UnitsManager;
|
var unitsManager: UnitsManager;
|
||||||
|
var weaponsManager: WeaponsManager;
|
||||||
var missionHandler: MissionHandler;
|
var missionHandler: MissionHandler;
|
||||||
|
|
||||||
var aic: AIC;
|
var aic: AIC;
|
||||||
@@ -48,6 +50,7 @@ function setup() {
|
|||||||
|
|
||||||
/* Initialize base functionalitites */
|
/* Initialize base functionalitites */
|
||||||
unitsManager = new UnitsManager();
|
unitsManager = new UnitsManager();
|
||||||
|
weaponsManager = new WeaponsManager();
|
||||||
map = new Map('map-container');
|
map = new Map('map-container');
|
||||||
missionHandler = new MissionHandler();
|
missionHandler = new MissionHandler();
|
||||||
|
|
||||||
@@ -222,6 +225,11 @@ export function getUnitsManager() {
|
|||||||
return unitsManager;
|
return unitsManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getWeaponsManager() {
|
||||||
|
return weaponsManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export function getMissionHandler() {
|
export function getMissionHandler() {
|
||||||
return missionHandler;
|
return missionHandler;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ import { UnitContextMenu } from "../controls/unitcontextmenu";
|
|||||||
import { AirbaseContextMenu } from "../controls/airbasecontextmenu";
|
import { AirbaseContextMenu } from "../controls/airbasecontextmenu";
|
||||||
import { Dropdown } from "../controls/dropdown";
|
import { Dropdown } from "../controls/dropdown";
|
||||||
import { Airbase } from "../mission/airbase";
|
import { Airbase } from "../mission/airbase";
|
||||||
import { Unit } from "../units/unit";
|
import { Unit } from "../unit/unit";
|
||||||
import { bearing, createCheckboxOption } from "../other/utils";
|
import { bearing, createCheckboxOption } from "../other/utils";
|
||||||
import { DestinationPreviewMarker } from "./destinationpreviewmarker";
|
import { DestinationPreviewMarker } from "./destinationpreviewmarker";
|
||||||
import { TemporaryUnitMarker } from "./temporaryunitmarker";
|
import { TemporaryUnitMarker } from "./temporaryunitmarker";
|
||||||
import { ClickableMiniMap } from "./clickableminimap";
|
import { ClickableMiniMap } from "./clickableminimap";
|
||||||
import { SVGInjector } from '@tanem/svg-injector'
|
import { SVGInjector } from '@tanem/svg-injector'
|
||||||
import { layers as mapLayers, mapBounds, minimapBoundaries, IDLE, COALITIONAREA_DRAW_POLYGON, visibilityControls, visibilityControlsTootlips, FIRE_AT_AREA, MOVE_UNIT, CARPET_BOMBING, BOMBING, SHOW_CONTACT_LINES, HIDE_GROUP_MEMBERS, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS } from "../constants/constants";
|
import { layers as mapLayers, mapBounds, minimapBoundaries, IDLE, COALITIONAREA_DRAW_POLYGON, visibilityControls, visibilityControlsTootlips, FIRE_AT_AREA, MOVE_UNIT, CARPET_BOMBING, BOMBING, SHOW_CONTACT_LINES, HIDE_GROUP_MEMBERS, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, visibilityControlsTypes } from "../constants/constants";
|
||||||
import { TargetMarker } from "./targetmarker";
|
import { TargetMarker } from "./targetmarker";
|
||||||
import { CoalitionArea } from "./coalitionarea";
|
import { CoalitionArea } from "./coalitionarea";
|
||||||
import { CoalitionAreaContextMenu } from "../controls/coalitionareacontextmenu";
|
import { CoalitionAreaContextMenu } from "../controls/coalitionareacontextmenu";
|
||||||
@@ -120,7 +120,7 @@ export class Map extends L.Map {
|
|||||||
document.addEventListener("toggleUnitVisibility", (ev: CustomEventInit) => {
|
document.addEventListener("toggleUnitVisibility", (ev: CustomEventInit) => {
|
||||||
const el = ev.detail._element;
|
const el = ev.detail._element;
|
||||||
el?.classList.toggle("off");
|
el?.classList.toggle("off");
|
||||||
getUnitsManager().setHiddenType(ev.detail.type, !el?.classList.contains("off"));
|
ev.detail.types.forEach((type: string) => getUnitsManager().setHiddenType(type, !el?.classList.contains("off")));
|
||||||
Object.values(getUnitsManager().getUnits()).forEach((unit: Unit) => unit.updateVisibility());
|
Object.values(getUnitsManager().getUnits()).forEach((unit: Unit) => unit.updateVisibility());
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ export class Map extends L.Map {
|
|||||||
|
|
||||||
/* Option buttons */
|
/* Option buttons */
|
||||||
this.#optionButtons["visibility"] = visibilityControls.map((option: string, index: number) => {
|
this.#optionButtons["visibility"] = visibilityControls.map((option: string, index: number) => {
|
||||||
return this.#createOptionButton(option, `visibility/${option.toLowerCase()}.svg`, visibilityControlsTootlips[index], "toggleUnitVisibility", `{"type": "${option}"}`);
|
return this.#createOptionButton(option, `visibility/${option.toLowerCase()}.svg`, visibilityControlsTootlips[index], "toggleUnitVisibility", `{"types": "${visibilityControlsTypes[index]}"}`);
|
||||||
});
|
});
|
||||||
document.querySelector("#unit-visibility-control")?.append(...this.#optionButtons["visibility"]);
|
document.querySelector("#unit-visibility-control")?.append(...this.#optionButtons["visibility"]);
|
||||||
|
|
||||||
@@ -616,7 +616,7 @@ export class Map extends L.Map {
|
|||||||
|
|
||||||
#showDestinationCursors() {
|
#showDestinationCursors() {
|
||||||
const singleCursor = !this.#shiftKey;
|
const singleCursor = !this.#shiftKey;
|
||||||
const selectedUnitsCount = getUnitsManager().getSelectedUnits({ excludeHumans: true, onlyOnePerGroup: true }).length;
|
const selectedUnitsCount = getUnitsManager().getSelectedUnits({ excludeHumans: false, onlyOnePerGroup: true }).length;
|
||||||
if (selectedUnitsCount > 0) {
|
if (selectedUnitsCount > 0) {
|
||||||
if (singleCursor && this.#destinationPreviewCursors.length != 1) {
|
if (singleCursor && this.#destinationPreviewCursors.length != 1) {
|
||||||
this.#hideDestinationCursors();
|
this.#hideDestinationCursors();
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
import { LatLng } from "leaflet";
|
import { LatLng } from "leaflet";
|
||||||
import { getInfoPopup, getMap, getUnitsManager } from "..";
|
import { getInfoPopup, getMap } from "..";
|
||||||
import { Airbase } from "./airbase";
|
import { Airbase } from "./airbase";
|
||||||
import { Bullseye } from "./bullseye";
|
import { Bullseye } from "./bullseye";
|
||||||
import { BLUE_COMMANDER, GAME_MASTER, RED_COMMANDER } from "../constants/constants";
|
import { BLUE_COMMANDER, GAME_MASTER, NONE, RED_COMMANDER } from "../constants/constants";
|
||||||
import { setCommandModeOptions } from "../server/server";
|
import { refreshAll, setCommandModeOptions } from "../server/server";
|
||||||
import { Dropdown } from "../controls/dropdown";
|
import { Dropdown } from "../controls/dropdown";
|
||||||
import { groundUnitDatabase } from "../units/groundunitdatabase";
|
import { groundUnitDatabase } from "../unit/groundunitdatabase";
|
||||||
import { createCheckboxOption, getCheckboxOptions } from "../other/utils";
|
import { createCheckboxOption, getCheckboxOptions } from "../other/utils";
|
||||||
import { aircraftDatabase } from "../units/aircraftdatabase";
|
import { aircraftDatabase } from "../unit/aircraftdatabase";
|
||||||
import { helicopterDatabase } from "../units/helicopterdatabase";
|
import { helicopterDatabase } from "../unit/helicopterdatabase";
|
||||||
import { navyUnitDatabase } from "../units/navyunitdatabase";
|
import { navyUnitDatabase } from "../unit/navyunitdatabase";
|
||||||
|
|
||||||
export class MissionHandler {
|
export class MissionHandler {
|
||||||
#bullseyes: { [name: string]: Bullseye } = {};
|
#bullseyes: { [name: string]: Bullseye } = {};
|
||||||
#airbases: { [name: string]: Airbase } = {};
|
#airbases: { [name: string]: Airbase } = {};
|
||||||
#theatre: string = "";
|
#theatre: string = "";
|
||||||
#dateAndTime: DateAndTime = {date: {Year: 0, Month: 0, Day: 0}, time: {h: 0, m: 0, s: 0}, startTime: 0, elapsedTime: 0};
|
#dateAndTime: DateAndTime = {date: {Year: 0, Month: 0, Day: 0}, time: {h: 0, m: 0, s: 0}, startTime: 0, elapsedTime: 0};
|
||||||
#commandModeOptions: CommandModeOptions = {commandMode: "Hide all", restrictSpawns: false, restrictToCoalition: false, setupTime: Infinity, spawnPoints: {red: Infinity, blue: Infinity}, eras: []};
|
#commandModeOptions: CommandModeOptions = {commandMode: NONE, restrictSpawns: false, restrictToCoalition: false, setupTime: Infinity, spawnPoints: {red: Infinity, blue: Infinity}, eras: []};
|
||||||
#remainingSetupTime: number = 0;
|
#remainingSetupTime: number = 0;
|
||||||
#spentSpawnPoint: number = 0;
|
#spentSpawnPoint: number = 0;
|
||||||
#commandModeDialog: HTMLElement;
|
#commandModeDialog: HTMLElement;
|
||||||
@@ -183,6 +183,16 @@ export class MissionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#setcommandModeOptions(commandModeOptions: CommandModeOptions) {
|
#setcommandModeOptions(commandModeOptions: CommandModeOptions) {
|
||||||
|
/* Refresh all the data if we have exited the NONE state */
|
||||||
|
var requestRefresh = false;
|
||||||
|
if (this.#commandModeOptions.commandMode === NONE && commandModeOptions.commandMode !== NONE)
|
||||||
|
requestRefresh = true;
|
||||||
|
|
||||||
|
/* Refresh the page if we have lost Game Master priviledges */
|
||||||
|
if (this.#commandModeOptions.commandMode === GAME_MASTER && commandModeOptions.commandMode !== GAME_MASTER)
|
||||||
|
location.reload();
|
||||||
|
|
||||||
|
/* Check if any option has changed */
|
||||||
var commandModeOptionsChanged = (!commandModeOptions.eras.every((value: string, idx: number) => {return value === this.getCommandModeOptions().eras[idx]}) ||
|
var commandModeOptionsChanged = (!commandModeOptions.eras.every((value: string, idx: number) => {return value === this.getCommandModeOptions().eras[idx]}) ||
|
||||||
commandModeOptions.spawnPoints.red !== this.getCommandModeOptions().spawnPoints.red ||
|
commandModeOptions.spawnPoints.red !== this.getCommandModeOptions().spawnPoints.red ||
|
||||||
commandModeOptions.spawnPoints.blue !== this.getCommandModeOptions().spawnPoints.blue ||
|
commandModeOptions.spawnPoints.blue !== this.getCommandModeOptions().spawnPoints.blue ||
|
||||||
@@ -195,7 +205,6 @@ export class MissionHandler {
|
|||||||
|
|
||||||
if (commandModeOptionsChanged) {
|
if (commandModeOptionsChanged) {
|
||||||
document.dispatchEvent(new CustomEvent("commandModeOptionsChanged", { detail: this }));
|
document.dispatchEvent(new CustomEvent("commandModeOptionsChanged", { detail: this }));
|
||||||
|
|
||||||
document.getElementById("command-mode-toolbar")?.classList.remove("hide");
|
document.getElementById("command-mode-toolbar")?.classList.remove("hide");
|
||||||
const el = document.getElementById("command-mode");
|
const el = document.getElementById("command-mode");
|
||||||
if (el) {
|
if (el) {
|
||||||
@@ -206,6 +215,9 @@ export class MissionHandler {
|
|||||||
|
|
||||||
document.querySelector("#spawn-points-container")?.classList.toggle("hide", this.getCommandModeOptions().commandMode === GAME_MASTER || !this.getCommandModeOptions().restrictSpawns);
|
document.querySelector("#spawn-points-container")?.classList.toggle("hide", this.getCommandModeOptions().commandMode === GAME_MASTER || !this.getCommandModeOptions().restrictSpawns);
|
||||||
document.querySelector("#command-mode-settings-button")?.classList.toggle("hide", this.getCommandModeOptions().commandMode !== GAME_MASTER);
|
document.querySelector("#command-mode-settings-button")?.classList.toggle("hide", this.getCommandModeOptions().commandMode !== GAME_MASTER);
|
||||||
|
|
||||||
|
if (requestRefresh)
|
||||||
|
refreshAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
#onAirbaseClick(e: any) {
|
#onAirbaseClick(e: any) {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { LatLng, Point, Polygon } from "leaflet";
|
import { LatLng, Point, Polygon } from "leaflet";
|
||||||
import * as turf from "@turf/turf";
|
import * as turf from "@turf/turf";
|
||||||
import { UnitDatabase } from "../units/unitdatabase";
|
import { UnitDatabase } from "../unit/unitdatabase";
|
||||||
import { aircraftDatabase } from "../units/aircraftdatabase";
|
import { aircraftDatabase } from "../unit/aircraftdatabase";
|
||||||
import { helicopterDatabase } from "../units/helicopterdatabase";
|
import { helicopterDatabase } from "../unit/helicopterdatabase";
|
||||||
import { groundUnitDatabase } from "../units/groundunitdatabase";
|
import { groundUnitDatabase } from "../unit/groundunitdatabase";
|
||||||
import { Buffer } from "buffer";
|
import { Buffer } from "buffer";
|
||||||
import { ROEs, emissionsCountermeasures, reactionsToThreat, states } from "../constants/constants";
|
import { ROEs, emissionsCountermeasures, reactionsToThreat, states } from "../constants/constants";
|
||||||
import { Dropdown } from "../controls/dropdown";
|
import { Dropdown } from "../controls/dropdown";
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { getUnitsManager } from "..";
|
import { getUnitsManager } from "..";
|
||||||
import { Unit } from "../units/unit";
|
import { Unit } from "../unit/unit";
|
||||||
import { Panel } from "./panel";
|
import { Panel } from "./panel";
|
||||||
|
|
||||||
export class HotgroupPanel extends Panel {
|
export class HotgroupPanel extends Panel {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Icon, LatLng, Marker, Polyline } from "leaflet";
|
import { Icon, LatLng, Marker, Polyline } from "leaflet";
|
||||||
import { getMap, getMissionHandler, getUnitsManager } from "..";
|
import { getMap, getMissionHandler, getUnitsManager } from "..";
|
||||||
import { distance, bearing, zeroAppend, mToNm, nmToFt } from "../other/utils";
|
import { distance, bearing, zeroAppend, mToNm, nmToFt } from "../other/utils";
|
||||||
import { Unit } from "../units/unit";
|
import { Unit } from "../unit/unit";
|
||||||
import { Panel } from "./panel";
|
import { Panel } from "./panel";
|
||||||
import formatcoords from "formatcoords";
|
import formatcoords from "formatcoords";
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import { SVGInjector } from "@tanem/svg-injector";
|
|||||||
import { getUnitsManager } from "..";
|
import { getUnitsManager } from "..";
|
||||||
import { Dropdown } from "../controls/dropdown";
|
import { Dropdown } from "../controls/dropdown";
|
||||||
import { Slider } from "../controls/slider";
|
import { Slider } from "../controls/slider";
|
||||||
import { aircraftDatabase } from "../units/aircraftdatabase";
|
import { aircraftDatabase } from "../unit/aircraftdatabase";
|
||||||
import { Unit } from "../units/unit";
|
import { Unit } from "../unit/unit";
|
||||||
import { Panel } from "./panel";
|
import { Panel } from "./panel";
|
||||||
import { Switch } from "../controls/switch";
|
import { Switch } from "../controls/switch";
|
||||||
import { ROEDescriptions, ROEs, altitudeIncrements, emissionsCountermeasures, emissionsCountermeasuresDescriptions, maxAltitudeValues, maxSpeedValues, minAltitudeValues, minSpeedValues, reactionsToThreat, reactionsToThreatDescriptions, speedIncrements } from "../constants/constants";
|
import { ROEDescriptions, ROEs, altitudeIncrements, emissionsCountermeasures, emissionsCountermeasuresDescriptions, maxAltitudeValues, maxSpeedValues, minAltitudeValues, minSpeedValues, reactionsToThreat, reactionsToThreatDescriptions, speedIncrements } from "../constants/constants";
|
||||||
@@ -22,6 +22,8 @@ export class UnitControlPanel extends Panel {
|
|||||||
#radioCallsignDropdown: Dropdown;
|
#radioCallsignDropdown: Dropdown;
|
||||||
#optionButtons: { [key: string]: HTMLButtonElement[] } = {}
|
#optionButtons: { [key: string]: HTMLButtonElement[] } = {}
|
||||||
#advancedSettingsDialog: HTMLElement;
|
#advancedSettingsDialog: HTMLElement;
|
||||||
|
#units: Unit[] = [];
|
||||||
|
#selectedUnitsTypes: string[] = [];
|
||||||
|
|
||||||
constructor(ID: string) {
|
constructor(ID: string) {
|
||||||
super(ID);
|
super(ID);
|
||||||
@@ -96,9 +98,11 @@ export class UnitControlPanel extends Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addButtons() {
|
addButtons() {
|
||||||
var units = getUnitsManager().getSelectedUnits();
|
this.#units = getUnitsManager().getSelectedUnits();
|
||||||
if (units.length < 20) {
|
this.#selectedUnitsTypes = getUnitsManager().getSelectedUnitsTypes();
|
||||||
this.getElement().querySelector("#selected-units-container")?.replaceChildren(...units.map((unit: Unit, index: number) => {
|
|
||||||
|
if (this.#units.length < 20) {
|
||||||
|
this.getElement().querySelector("#selected-units-container")?.replaceChildren(...this.#units.map((unit: Unit, index: number) => {
|
||||||
var button = document.createElement("button");
|
var button = document.createElement("button");
|
||||||
var callsign = unit.getUnitName() || "";
|
var callsign = unit.getUnitName() || "";
|
||||||
var label = unit.getDatabase()?.getByName(unit.getName())?.label || unit.getName();
|
var label = unit.getDatabase()?.getByName(unit.getName())?.label || unit.getName();
|
||||||
@@ -125,37 +129,34 @@ export class UnitControlPanel extends Panel {
|
|||||||
update() {
|
update() {
|
||||||
if (this.getVisible()){
|
if (this.getVisible()){
|
||||||
const element = this.getElement();
|
const element = this.getElement();
|
||||||
const units = getUnitsManager().getSelectedUnits();
|
if (element != null && this.#units.length > 0) {
|
||||||
const selectedUnitsTypes = getUnitsManager().getSelectedUnitsTypes();
|
|
||||||
|
|
||||||
if (element != null && units.length > 0) {
|
|
||||||
/* Toggle visibility of control elements */
|
/* Toggle visibility of control elements */
|
||||||
element.toggleAttribute("data-show-categories-tooltip", selectedUnitsTypes.length > 1);
|
element.toggleAttribute("data-show-categories-tooltip", this.#selectedUnitsTypes.length > 1);
|
||||||
element.toggleAttribute("data-show-speed-slider", selectedUnitsTypes.length == 1);
|
element.toggleAttribute("data-show-speed-slider", this.#selectedUnitsTypes.length == 1);
|
||||||
element.toggleAttribute("data-show-altitude-slider", selectedUnitsTypes.length == 1 && (selectedUnitsTypes.includes("Aircraft") || selectedUnitsTypes.includes("Helicopter")));
|
element.toggleAttribute("data-show-altitude-slider", this.#selectedUnitsTypes.length == 1 && (this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter")));
|
||||||
element.toggleAttribute("data-show-roe", true);
|
element.toggleAttribute("data-show-roe", true);
|
||||||
element.toggleAttribute("data-show-threat", (selectedUnitsTypes.includes("Aircraft") || selectedUnitsTypes.includes("Helicopter")) && !(selectedUnitsTypes.includes("GroundUnit") || selectedUnitsTypes.includes("NavyUnit")));
|
element.toggleAttribute("data-show-threat", (this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter")) && !(this.#selectedUnitsTypes.includes("GroundUnit") || this.#selectedUnitsTypes.includes("NavyUnit")));
|
||||||
element.toggleAttribute("data-show-emissions-countermeasures", (selectedUnitsTypes.includes("Aircraft") || selectedUnitsTypes.includes("Helicopter")) && !(selectedUnitsTypes.includes("GroundUnit") || selectedUnitsTypes.includes("NavyUnit")));
|
element.toggleAttribute("data-show-emissions-countermeasures", (this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter")) && !(this.#selectedUnitsTypes.includes("GroundUnit") || this.#selectedUnitsTypes.includes("NavyUnit")));
|
||||||
element.toggleAttribute("data-show-on-off", (selectedUnitsTypes.includes("GroundUnit") || selectedUnitsTypes.includes("NavyUnit")) && !(selectedUnitsTypes.includes("Aircraft") || selectedUnitsTypes.includes("Helicopter")));
|
element.toggleAttribute("data-show-on-off", (this.#selectedUnitsTypes.includes("GroundUnit") || this.#selectedUnitsTypes.includes("NavyUnit")) && !(this.#selectedUnitsTypes.includes("Aircraft") || this.#selectedUnitsTypes.includes("Helicopter")));
|
||||||
element.toggleAttribute("data-show-follow-roads", (selectedUnitsTypes.length == 1 && selectedUnitsTypes.includes("GroundUnit")));
|
element.toggleAttribute("data-show-follow-roads", (this.#selectedUnitsTypes.length == 1 && this.#selectedUnitsTypes.includes("GroundUnit")));
|
||||||
element.toggleAttribute("data-show-advanced-settings-button", units.length == 1);
|
element.toggleAttribute("data-show-advanced-settings-button", this.#units.length == 1);
|
||||||
|
|
||||||
/* Flight controls */
|
if (this.#selectedUnitsTypes.length == 1) {
|
||||||
var desiredAltitude = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredAltitude()});
|
/* Flight controls */
|
||||||
var desiredAltitudeType = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredAltitudeType()});
|
var desiredAltitude = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredAltitude()});
|
||||||
var desiredSpeed = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredSpeed()});
|
var desiredAltitudeType = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredAltitudeType()});
|
||||||
var desiredSpeedType = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredSpeedType()});
|
var desiredSpeed = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredSpeed()});
|
||||||
var onOff = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getOnOff()});
|
var desiredSpeedType = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getDesiredSpeedType()});
|
||||||
var followRoads = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getFollowRoads()});
|
var onOff = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getOnOff()});
|
||||||
|
var followRoads = getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getFollowRoads()});
|
||||||
if (selectedUnitsTypes.length == 1) {
|
|
||||||
this.#altitudeTypeSwitch.setValue(desiredAltitudeType != undefined? desiredAltitudeType == "AGL": undefined, false);
|
this.#altitudeTypeSwitch.setValue(desiredAltitudeType != undefined? desiredAltitudeType == "AGL": undefined, false);
|
||||||
this.#speedTypeSwitch.setValue(desiredSpeedType != undefined? desiredSpeedType == "GS": undefined, false);
|
this.#speedTypeSwitch.setValue(desiredSpeedType != undefined? desiredSpeedType == "GS": undefined, false);
|
||||||
|
|
||||||
this.#speedSlider.setMinMax(minSpeedValues[selectedUnitsTypes[0]], maxSpeedValues[selectedUnitsTypes[0]]);
|
this.#speedSlider.setMinMax(minSpeedValues[this.#selectedUnitsTypes[0]], maxSpeedValues[this.#selectedUnitsTypes[0]]);
|
||||||
this.#altitudeSlider.setMinMax(minAltitudeValues[selectedUnitsTypes[0]], maxAltitudeValues[selectedUnitsTypes[0]]);
|
this.#altitudeSlider.setMinMax(minAltitudeValues[this.#selectedUnitsTypes[0]], maxAltitudeValues[this.#selectedUnitsTypes[0]]);
|
||||||
this.#speedSlider.setIncrement(speedIncrements[selectedUnitsTypes[0]]);
|
this.#speedSlider.setIncrement(speedIncrements[this.#selectedUnitsTypes[0]]);
|
||||||
this.#altitudeSlider.setIncrement(altitudeIncrements[selectedUnitsTypes[0]]);
|
this.#altitudeSlider.setIncrement(altitudeIncrements[this.#selectedUnitsTypes[0]]);
|
||||||
|
|
||||||
this.#speedSlider.setActive(desiredSpeed != undefined);
|
this.#speedSlider.setActive(desiredSpeed != undefined);
|
||||||
if (desiredSpeed != undefined)
|
if (desiredSpeed != undefined)
|
||||||
@@ -172,15 +173,15 @@ export class UnitControlPanel extends Panel {
|
|||||||
|
|
||||||
/* Option buttons */
|
/* Option buttons */
|
||||||
this.#optionButtons["ROE"].forEach((button: HTMLButtonElement) => {
|
this.#optionButtons["ROE"].forEach((button: HTMLButtonElement) => {
|
||||||
button.classList.toggle("selected", units.every((unit: Unit) => unit.getROE() === button.value))
|
button.classList.toggle("selected", this.#units.every((unit: Unit) => unit.getROE() === button.value))
|
||||||
});
|
});
|
||||||
|
|
||||||
this.#optionButtons["reactionToThreat"].forEach((button: HTMLButtonElement) => {
|
this.#optionButtons["reactionToThreat"].forEach((button: HTMLButtonElement) => {
|
||||||
button.classList.toggle("selected", units.every((unit: Unit) => unit.getReactionToThreat() === button.value))
|
button.classList.toggle("selected", this.#units.every((unit: Unit) => unit.getReactionToThreat() === button.value))
|
||||||
});
|
});
|
||||||
|
|
||||||
this.#optionButtons["emissionsCountermeasures"].forEach((button: HTMLButtonElement) => {
|
this.#optionButtons["emissionsCountermeasures"].forEach((button: HTMLButtonElement) => {
|
||||||
button.classList.toggle("selected", units.every((unit: Unit) => unit.getEmissionsCountermeasures() === button.value))
|
button.classList.toggle("selected", this.#units.every((unit: Unit) => unit.getEmissionsCountermeasures() === button.value))
|
||||||
});
|
});
|
||||||
|
|
||||||
this.#onOffSwitch.setValue(onOff, false);
|
this.#onOffSwitch.setValue(onOff, false);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { getUnitsManager } from "..";
|
import { getUnitsManager } from "..";
|
||||||
import { Ammo } from "../@types/unit";
|
import { Ammo } from "../@types/unit";
|
||||||
import { ConvertDDToDMS, rad2deg } from "../other/utils";
|
import { ConvertDDToDMS, rad2deg } from "../other/utils";
|
||||||
import { aircraftDatabase } from "../units/aircraftdatabase";
|
import { aircraftDatabase } from "../unit/aircraftdatabase";
|
||||||
import { Unit } from "../units/unit";
|
import { Unit } from "../unit/unit";
|
||||||
import { Panel } from "./panel";
|
import { Panel } from "./panel";
|
||||||
|
|
||||||
export class UnitInfoPanel extends Panel {
|
export class UnitInfoPanel extends Panel {
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ export class DataExtractor {
|
|||||||
this.#decoder = new TextDecoder("utf-8");
|
this.#decoder = new TextDecoder("utf-8");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setSeekPosition(seekPosition: number) {
|
||||||
|
this.#seekPosition = seekPosition;
|
||||||
|
}
|
||||||
|
|
||||||
getSeekPosition() {
|
getSeekPosition() {
|
||||||
return this.#seekPosition;
|
return this.#seekPosition;
|
||||||
}
|
}
|
||||||
@@ -67,7 +71,13 @@ export class DataExtractor {
|
|||||||
var stringBuffer = this.#buffer.slice(this.#seekPosition, this.#seekPosition + length);
|
var stringBuffer = this.#buffer.slice(this.#seekPosition, this.#seekPosition + length);
|
||||||
var view = new Int8Array(stringBuffer);
|
var view = new Int8Array(stringBuffer);
|
||||||
var stringLength = length;
|
var stringLength = length;
|
||||||
view.forEach((value: number, idx: number) => { if (value === 0) stringLength = idx; });
|
view.every((value: number, idx: number) => {
|
||||||
|
if (value === 0) {
|
||||||
|
stringLength = idx;
|
||||||
|
return false;
|
||||||
|
} else
|
||||||
|
return true;
|
||||||
|
});
|
||||||
const value = this.#decoder.decode(stringBuffer);
|
const value = this.#decoder.decode(stringBuffer);
|
||||||
this.#seekPosition += length;
|
this.#seekPosition += length;
|
||||||
return value.substring(0, stringLength).trim();
|
return value.substring(0, stringLength).trim();
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { LatLng } from 'leaflet';
|
import { LatLng } from 'leaflet';
|
||||||
import { getConnectionStatusPanel, getInfoPopup, getLogPanel, getMissionHandler, getServerStatusPanel, getUnitDataTable, getUnitsManager, setLoginStatus } from '..';
|
import { getConnectionStatusPanel, getInfoPopup, getLogPanel, getMissionHandler, getServerStatusPanel, getUnitsManager, getWeaponsManager, setLoginStatus } from '..';
|
||||||
import { GeneralSettings, Radio, TACAN } from '../@types/unit';
|
import { GeneralSettings, Radio, TACAN } from '../@types/unit';
|
||||||
import { ROEs, emissionsCountermeasures, reactionsToThreat } from '../constants/constants';
|
import { NONE, ROEs, emissionsCountermeasures, reactionsToThreat } from '../constants/constants';
|
||||||
|
|
||||||
var connected: boolean = false;
|
var connected: boolean = false;
|
||||||
var paused: boolean = false;
|
var paused: boolean = false;
|
||||||
@@ -9,6 +9,7 @@ var paused: boolean = false;
|
|||||||
var REST_ADDRESS = "http://localhost:30000/olympus";
|
var REST_ADDRESS = "http://localhost:30000/olympus";
|
||||||
var DEMO_ADDRESS = window.location.href + "demo";
|
var DEMO_ADDRESS = window.location.href + "demo";
|
||||||
const UNITS_URI = "units";
|
const UNITS_URI = "units";
|
||||||
|
const WEAPONS_URI = "weapons";
|
||||||
const LOGS_URI = "logs";
|
const LOGS_URI = "logs";
|
||||||
const AIRBASES_URI = "airbases";
|
const AIRBASES_URI = "airbases";
|
||||||
const BULLSEYE_URI = "bullseyes";
|
const BULLSEYE_URI = "bullseyes";
|
||||||
@@ -19,6 +20,13 @@ var password = "";
|
|||||||
|
|
||||||
var sessionHash: string | null = null;
|
var sessionHash: string | null = null;
|
||||||
var lastUpdateTimes: {[key: string]: number} = {}
|
var lastUpdateTimes: {[key: string]: number} = {}
|
||||||
|
lastUpdateTimes[UNITS_URI] = Date.now();
|
||||||
|
lastUpdateTimes[WEAPONS_URI] = Date.now();
|
||||||
|
lastUpdateTimes[LOGS_URI] = Date.now();
|
||||||
|
lastUpdateTimes[AIRBASES_URI] = Date.now();
|
||||||
|
lastUpdateTimes[BULLSEYE_URI] = Date.now();
|
||||||
|
lastUpdateTimes[MISSION_URI] = Date.now();
|
||||||
|
|
||||||
var demoEnabled = false;
|
var demoEnabled = false;
|
||||||
|
|
||||||
export function toggleDemoEnabled() {
|
export function toggleDemoEnabled() {
|
||||||
@@ -128,6 +136,10 @@ export function getUnits(callback: CallableFunction, refresh: boolean = false) {
|
|||||||
GET(callback, UNITS_URI, { time: refresh ? 0 : lastUpdateTimes[UNITS_URI] }, 'arraybuffer');
|
GET(callback, UNITS_URI, { time: refresh ? 0 : lastUpdateTimes[UNITS_URI] }, 'arraybuffer');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getWeapons(callback: CallableFunction, refresh: boolean = false) {
|
||||||
|
GET(callback, WEAPONS_URI, { time: refresh ? 0 : lastUpdateTimes[WEAPONS_URI] }, 'arraybuffer');
|
||||||
|
}
|
||||||
|
|
||||||
export function addDestination(ID: number, path: any) {
|
export function addDestination(ID: number, path: any) {
|
||||||
var command = { "ID": ID, "path": path }
|
var command = { "ID": ID, "path": path }
|
||||||
var data = { "setPath": command }
|
var data = { "setPath": command }
|
||||||
@@ -334,26 +346,6 @@ export function setCommandModeOptions(restrictSpawns: boolean, restrictToCoaliti
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function startUpdate() {
|
export function startUpdate() {
|
||||||
window.setInterval(() => {
|
|
||||||
if (!getPaused()) {
|
|
||||||
getAirbases((data: AirbasesData) => {
|
|
||||||
checkSessionHash(data.sessionHash);
|
|
||||||
getMissionHandler()?.updateAirbases(data);
|
|
||||||
return data.time;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, 10000);
|
|
||||||
|
|
||||||
window.setInterval(() => {
|
|
||||||
if (!getPaused()){
|
|
||||||
getBullseye((data: BullseyesData) => {
|
|
||||||
checkSessionHash(data.sessionHash);
|
|
||||||
getMissionHandler()?.updateBullseyes(data);
|
|
||||||
return data.time;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, 10000);
|
|
||||||
|
|
||||||
window.setInterval(() => {
|
window.setInterval(() => {
|
||||||
if (!getPaused()) {
|
if (!getPaused()) {
|
||||||
getMission((data: MissionData) => {
|
getMission((data: MissionData) => {
|
||||||
@@ -365,7 +357,27 @@ export function startUpdate() {
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
window.setInterval(() => {
|
window.setInterval(() => {
|
||||||
if (!getPaused()) {
|
if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) {
|
||||||
|
getAirbases((data: AirbasesData) => {
|
||||||
|
checkSessionHash(data.sessionHash);
|
||||||
|
getMissionHandler()?.updateAirbases(data);
|
||||||
|
return data.time;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
window.setInterval(() => {
|
||||||
|
if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE){
|
||||||
|
getBullseye((data: BullseyesData) => {
|
||||||
|
checkSessionHash(data.sessionHash);
|
||||||
|
getMissionHandler()?.updateBullseyes(data);
|
||||||
|
return data.time;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
window.setInterval(() => {
|
||||||
|
if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) {
|
||||||
getLogs((data: any) => {
|
getLogs((data: any) => {
|
||||||
checkSessionHash(data.sessionHash);
|
checkSessionHash(data.sessionHash);
|
||||||
getLogPanel().appendLogs(data.logs)
|
getLogPanel().appendLogs(data.logs)
|
||||||
@@ -375,7 +387,7 @@ export function startUpdate() {
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
window.setInterval(() => {
|
window.setInterval(() => {
|
||||||
if (!getPaused()) {
|
if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) {
|
||||||
getUnits((buffer: ArrayBuffer) => {
|
getUnits((buffer: ArrayBuffer) => {
|
||||||
var time = getUnitsManager()?.update(buffer);
|
var time = getUnitsManager()?.update(buffer);
|
||||||
return time;
|
return time;
|
||||||
@@ -384,7 +396,16 @@ export function startUpdate() {
|
|||||||
}, 250);
|
}, 250);
|
||||||
|
|
||||||
window.setInterval(() => {
|
window.setInterval(() => {
|
||||||
if (!getPaused()) {
|
if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) {
|
||||||
|
getWeapons((buffer: ArrayBuffer) => {
|
||||||
|
var time = getWeaponsManager()?.update(buffer);
|
||||||
|
return time;
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
}, 250);
|
||||||
|
|
||||||
|
window.setInterval(() => {
|
||||||
|
if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) {
|
||||||
getUnits((buffer: ArrayBuffer) => {
|
getUnits((buffer: ArrayBuffer) => {
|
||||||
var time = getUnitsManager()?.update(buffer);
|
var time = getUnitsManager()?.update(buffer);
|
||||||
return time;
|
return time;
|
||||||
@@ -392,19 +413,50 @@ export function startUpdate() {
|
|||||||
getConnectionStatusPanel()?.update(getConnected());
|
getConnectionStatusPanel()?.update(getConnected());
|
||||||
}
|
}
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
|
window.setInterval(() => {
|
||||||
|
if (!getPaused() && getMissionHandler().getCommandModeOptions().commandMode != NONE) {
|
||||||
|
getWeapons((buffer: ArrayBuffer) => {
|
||||||
|
var time = getWeaponsManager()?.update(buffer);
|
||||||
|
return time;
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
}, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function requestUpdate() {
|
export function refreshAll() {
|
||||||
/* Main update rate = 250ms is minimum time, equal to server update time. */
|
getAirbases((data: AirbasesData) => {
|
||||||
if (!getPaused()) {
|
checkSessionHash(data.sessionHash);
|
||||||
getUnits((buffer: ArrayBuffer) => { return getUnitsManager()?.update(buffer); }, false);
|
getMissionHandler()?.updateAirbases(data);
|
||||||
}
|
return data.time;
|
||||||
window.setTimeout(() => requestUpdate(), getConnected() ? 250 : 1000);
|
});
|
||||||
|
|
||||||
|
getBullseye((data: BullseyesData) => {
|
||||||
|
checkSessionHash(data.sessionHash);
|
||||||
|
getMissionHandler()?.updateBullseyes(data);
|
||||||
|
return data.time;
|
||||||
|
});
|
||||||
|
|
||||||
|
getLogs((data: any) => {
|
||||||
|
checkSessionHash(data.sessionHash);
|
||||||
|
getLogPanel().appendLogs(data.logs)
|
||||||
|
return data.time;
|
||||||
|
});
|
||||||
|
|
||||||
|
getWeapons((buffer: ArrayBuffer) => {
|
||||||
|
var time = getWeaponsManager()?.update(buffer);
|
||||||
|
return time;
|
||||||
|
}, true);
|
||||||
|
|
||||||
|
getUnits((buffer: ArrayBuffer) => {
|
||||||
|
var time = getUnitsManager()?.update(buffer);
|
||||||
|
return time;
|
||||||
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkSessionHash(newSessionHash: string) {
|
export function checkSessionHash(newSessionHash: string) {
|
||||||
if (sessionHash != null) {
|
if (sessionHash != null) {
|
||||||
if (newSessionHash != sessionHash)
|
if (newSessionHash !== sessionHash)
|
||||||
location.reload();
|
location.reload();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -7,8 +7,8 @@ import { SVGInjector } from '@tanem/svg-injector';
|
|||||||
import { UnitDatabase } from './unitdatabase';
|
import { UnitDatabase } from './unitdatabase';
|
||||||
import { TargetMarker } from '../map/targetmarker';
|
import { TargetMarker } from '../map/targetmarker';
|
||||||
import { BOMBING, CARPET_BOMBING, DLINK, DataIndexes, FIRE_AT_AREA, GAME_MASTER, HIDE_GROUP_MEMBERS, IDLE, IRST, MOVE_UNIT, OPTIC, RADAR, ROEs, RWR, SHOW_CONTACT_LINES, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, VISUAL, emissionsCountermeasures, reactionsToThreat, states } from '../constants/constants';
|
import { BOMBING, CARPET_BOMBING, DLINK, DataIndexes, FIRE_AT_AREA, GAME_MASTER, HIDE_GROUP_MEMBERS, IDLE, IRST, MOVE_UNIT, OPTIC, RADAR, ROEs, RWR, SHOW_CONTACT_LINES, SHOW_UNIT_PATHS, SHOW_UNIT_TARGETS, VISUAL, emissionsCountermeasures, reactionsToThreat, states } from '../constants/constants';
|
||||||
import { Ammo, Contact, GeneralSettings, Offset, Radio, TACAN, UnitIconOptions } from '../@types/unit';
|
import { Ammo, Contact, GeneralSettings, Offset, Radio, TACAN, ObjectIconOptions } from '../@types/unit';
|
||||||
import { DataExtractor } from './dataextractor';
|
import { DataExtractor } from '../server/dataextractor';
|
||||||
import { groundUnitDatabase } from './groundunitdatabase';
|
import { groundUnitDatabase } from './groundunitdatabase';
|
||||||
import { navyUnitDatabase } from './navyunitdatabase';
|
import { navyUnitDatabase } from './navyunitdatabase';
|
||||||
|
|
||||||
@@ -135,8 +135,6 @@ export class Unit extends CustomMarker {
|
|||||||
if (type === "GroundUnit") return GroundUnit;
|
if (type === "GroundUnit") return GroundUnit;
|
||||||
if (type === "Aircraft") return Aircraft;
|
if (type === "Aircraft") return Aircraft;
|
||||||
if (type === "Helicopter") return Helicopter;
|
if (type === "Helicopter") return Helicopter;
|
||||||
if (type === "Missile") return Missile;
|
|
||||||
if (type === "Bomb") return Bomb;
|
|
||||||
if (type === "NavyUnit") return NavyUnit;
|
if (type === "NavyUnit") return NavyUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +190,7 @@ export class Unit extends CustomMarker {
|
|||||||
case DataIndexes.alive: this.setAlive(dataExtractor.extractBool()); updateMarker = true; break;
|
case DataIndexes.alive: this.setAlive(dataExtractor.extractBool()); updateMarker = true; break;
|
||||||
case DataIndexes.human: this.#human = dataExtractor.extractBool(); break;
|
case DataIndexes.human: this.#human = dataExtractor.extractBool(); break;
|
||||||
case DataIndexes.controlled: this.#controlled = dataExtractor.extractBool(); updateMarker = true; break;
|
case DataIndexes.controlled: this.#controlled = dataExtractor.extractBool(); updateMarker = true; break;
|
||||||
case DataIndexes.coalition: this.#coalition = enumToCoalition(dataExtractor.extractUInt8()); break;
|
case DataIndexes.coalition: this.#coalition = enumToCoalition(dataExtractor.extractUInt8()); updateMarker = true; break;
|
||||||
case DataIndexes.country: this.#country = dataExtractor.extractUInt8(); break;
|
case DataIndexes.country: this.#country = dataExtractor.extractUInt8(); break;
|
||||||
case DataIndexes.name: this.#name = dataExtractor.extractString(); break;
|
case DataIndexes.name: this.#name = dataExtractor.extractString(); break;
|
||||||
case DataIndexes.unitName: this.#unitName = dataExtractor.extractString(); break;
|
case DataIndexes.unitName: this.#unitName = dataExtractor.extractString(); break;
|
||||||
@@ -297,7 +295,7 @@ export class Unit extends CustomMarker {
|
|||||||
return getUnitDatabaseByCategory(this.getMarkerCategory());
|
return getUnitDatabaseByCategory(this.getMarkerCategory());
|
||||||
}
|
}
|
||||||
|
|
||||||
getIconOptions(): UnitIconOptions {
|
getIconOptions(): ObjectIconOptions {
|
||||||
// Default values, overloaded by child classes if needed
|
// Default values, overloaded by child classes if needed
|
||||||
return {
|
return {
|
||||||
showState: false,
|
showState: false,
|
||||||
@@ -408,9 +406,11 @@ export class Unit extends CustomMarker {
|
|||||||
el.setAttribute("data-object", `unit-${this.getMarkerCategory()}`);
|
el.setAttribute("data-object", `unit-${this.getMarkerCategory()}`);
|
||||||
el.setAttribute("data-coalition", this.#coalition);
|
el.setAttribute("data-coalition", this.#coalition);
|
||||||
|
|
||||||
|
var iconOptions = this.getIconOptions();
|
||||||
|
|
||||||
// Generate and append elements depending on active options
|
// Generate and append elements depending on active options
|
||||||
// Velocity vector
|
// Velocity vector
|
||||||
if (this.getIconOptions().showVvi) {
|
if (iconOptions.showVvi) {
|
||||||
var vvi = document.createElement("div");
|
var vvi = document.createElement("div");
|
||||||
vvi.classList.add("unit-vvi");
|
vvi.classList.add("unit-vvi");
|
||||||
vvi.toggleAttribute("data-rotate-to-heading");
|
vvi.toggleAttribute("data-rotate-to-heading");
|
||||||
@@ -418,7 +418,7 @@ export class Unit extends CustomMarker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Hotgroup indicator
|
// Hotgroup indicator
|
||||||
if (this.getIconOptions().showHotgroup) {
|
if (iconOptions.showHotgroup) {
|
||||||
var hotgroup = document.createElement("div");
|
var hotgroup = document.createElement("div");
|
||||||
hotgroup.classList.add("unit-hotgroup");
|
hotgroup.classList.add("unit-hotgroup");
|
||||||
var hotgroupId = document.createElement("div");
|
var hotgroupId = document.createElement("div");
|
||||||
@@ -428,26 +428,26 @@ export class Unit extends CustomMarker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Main icon
|
// Main icon
|
||||||
if (this.getIconOptions().showUnitIcon) {
|
if (iconOptions.showUnitIcon) {
|
||||||
var unitIcon = document.createElement("div");
|
var unitIcon = document.createElement("div");
|
||||||
unitIcon.classList.add("unit-icon");
|
unitIcon.classList.add("unit-icon");
|
||||||
var img = document.createElement("img");
|
var img = document.createElement("img");
|
||||||
img.src = `/resources/theme/images/units/${this.getMarkerCategory()}.svg`;
|
img.src = `/resources/theme/images/units/${this.getMarkerCategory()}.svg`;
|
||||||
img.onload = () => SVGInjector(img);
|
img.onload = () => SVGInjector(img);
|
||||||
unitIcon.appendChild(img);
|
unitIcon.appendChild(img);
|
||||||
unitIcon.toggleAttribute("data-rotate-to-heading", this.getIconOptions().rotateToHeading);
|
unitIcon.toggleAttribute("data-rotate-to-heading", iconOptions.rotateToHeading);
|
||||||
el.append(unitIcon);
|
el.append(unitIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
// State icon
|
// State icon
|
||||||
if (this.getIconOptions().showState) {
|
if (iconOptions.showState) {
|
||||||
var state = document.createElement("div");
|
var state = document.createElement("div");
|
||||||
state.classList.add("unit-state");
|
state.classList.add("unit-state");
|
||||||
el.appendChild(state);
|
el.appendChild(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Short label
|
// Short label
|
||||||
if (this.getIconOptions().showShortLabel) {
|
if (iconOptions.showShortLabel) {
|
||||||
var shortLabel = document.createElement("div");
|
var shortLabel = document.createElement("div");
|
||||||
shortLabel.classList.add("unit-short-label");
|
shortLabel.classList.add("unit-short-label");
|
||||||
shortLabel.innerText = getUnitDatabaseByCategory(this.getMarkerCategory())?.getByName(this.#name)?.shortLabel || "";
|
shortLabel.innerText = getUnitDatabaseByCategory(this.getMarkerCategory())?.getByName(this.#name)?.shortLabel || "";
|
||||||
@@ -455,7 +455,7 @@ export class Unit extends CustomMarker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fuel indicator
|
// Fuel indicator
|
||||||
if (this.getIconOptions().showFuel) {
|
if (iconOptions.showFuel) {
|
||||||
var fuelIndicator = document.createElement("div");
|
var fuelIndicator = document.createElement("div");
|
||||||
fuelIndicator.classList.add("unit-fuel");
|
fuelIndicator.classList.add("unit-fuel");
|
||||||
var fuelLevel = document.createElement("div");
|
var fuelLevel = document.createElement("div");
|
||||||
@@ -465,7 +465,7 @@ export class Unit extends CustomMarker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ammo indicator
|
// Ammo indicator
|
||||||
if (this.getIconOptions().showAmmo) {
|
if (iconOptions.showAmmo) {
|
||||||
var ammoIndicator = document.createElement("div");
|
var ammoIndicator = document.createElement("div");
|
||||||
ammoIndicator.classList.add("unit-ammo");
|
ammoIndicator.classList.add("unit-ammo");
|
||||||
for (let i = 0; i <= 3; i++)
|
for (let i = 0; i <= 3; i++)
|
||||||
@@ -474,7 +474,7 @@ export class Unit extends CustomMarker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Unit summary
|
// Unit summary
|
||||||
if (this.getIconOptions().showSummary) {
|
if (iconOptions.showSummary) {
|
||||||
var summary = document.createElement("div");
|
var summary = document.createElement("div");
|
||||||
summary.classList.add("unit-summary");
|
summary.classList.add("unit-summary");
|
||||||
var callsign = document.createElement("div");
|
var callsign = document.createElement("div");
|
||||||
@@ -484,7 +484,7 @@ export class Unit extends CustomMarker {
|
|||||||
altitude.classList.add("unit-altitude");
|
altitude.classList.add("unit-altitude");
|
||||||
var speed = document.createElement("div");
|
var speed = document.createElement("div");
|
||||||
speed.classList.add("unit-speed");
|
speed.classList.add("unit-speed");
|
||||||
if (this.getIconOptions().showCallsign) summary.appendChild(callsign);
|
if (iconOptions.showCallsign) summary.appendChild(callsign);
|
||||||
summary.appendChild(altitude);
|
summary.appendChild(altitude);
|
||||||
summary.appendChild(speed);
|
summary.appendChild(speed);
|
||||||
el.appendChild(summary);
|
el.appendChild(summary);
|
||||||
@@ -500,8 +500,8 @@ export class Unit extends CustomMarker {
|
|||||||
(this.#controlled == false && hiddenUnits.includes("dcs")) ||
|
(this.#controlled == false && hiddenUnits.includes("dcs")) ||
|
||||||
(hiddenUnits.includes(this.getMarkerCategory())) ||
|
(hiddenUnits.includes(this.getMarkerCategory())) ||
|
||||||
(hiddenUnits.includes(this.#coalition)) ||
|
(hiddenUnits.includes(this.#coalition)) ||
|
||||||
(!this.belongsToCommandedCoalition() && this.#detectionMethods.length == 0) ||
|
(!this.belongsToCommandedCoalition() && (this.#detectionMethods.length == 0 || (this.#detectionMethods.length == 1 && this.#detectionMethods[0] === RWR))) ||
|
||||||
(getMap().getVisibilityOptions()[HIDE_GROUP_MEMBERS] && !this.#isLeader && this.getCategory() == "GroundUnit" && getMap().getZoom() < 13)) &&
|
(getMap().getVisibilityOptions()[HIDE_GROUP_MEMBERS] && !this.#isLeader && this.getCategory() == "GroundUnit" && getMap().getZoom() < 13 && (this.belongsToCommandedCoalition() || (!this.belongsToCommandedCoalition() && this.#detectionMethods.length == 0)))) &&
|
||||||
!(this.getSelected());
|
!(this.getSelected());
|
||||||
|
|
||||||
this.setHidden(hidden || !this.#alive);
|
this.setHidden(hidden || !this.#alive);
|
||||||
@@ -748,6 +748,11 @@ export class Unit extends CustomMarker {
|
|||||||
options["fire-at-area"] = { text: "Fire at area", tooltip: "Fire at a large area" };
|
options["fire-at-area"] = { text: "Fire at area", tooltip: "Fire at a large area" };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((selectedUnits.length === 0 && this.getCategory() == "NavyUnit") || selectedUnitTypes.length === 1 && ["NavyUnit"].includes(selectedUnitTypes[0])) {
|
||||||
|
if (selectedUnits.concat([this]).every((unit: Unit) => { return ["Cruiser", "Destroyer", "Frigate"].includes(this.getType()) }))
|
||||||
|
options["fire-at-area"] = { text: "Fire at area", tooltip: "Fire at a large area" };
|
||||||
|
}
|
||||||
|
|
||||||
if (selectedUnitTypes.length === 1 && ["NavyUnit", "GroundUnit"].includes(selectedUnitTypes[0]) && getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getCoalition()}) !== undefined)
|
if (selectedUnitTypes.length === 1 && ["NavyUnit", "GroundUnit"].includes(selectedUnitTypes[0]) && getUnitsManager().getSelectedUnitsVariable((unit: Unit) => {return unit.getCoalition()}) !== undefined)
|
||||||
options["group"] = { text: "Create group", tooltip: "Create a group from the selected units." };
|
options["group"] = { text: "Create group", tooltip: "Create a group from the selected units." };
|
||||||
|
|
||||||
@@ -976,7 +981,7 @@ export class Unit extends CustomMarker {
|
|||||||
if (getMap().getVisibilityOptions()[SHOW_CONTACT_LINES]) {
|
if (getMap().getVisibilityOptions()[SHOW_CONTACT_LINES]) {
|
||||||
for (let index in this.#contacts) {
|
for (let index in this.#contacts) {
|
||||||
var contactData = this.#contacts[index];
|
var contactData = this.#contacts[index];
|
||||||
var contact = getUnitsManager().getUnitByID(contactData.ID)
|
var contact = getUnitsManager().getUnitByID(contactData.ID);
|
||||||
if (contact != null && contact.getAlive()) {
|
if (contact != null && contact.getAlive()) {
|
||||||
var startLatLng = new LatLng(this.#position.lat, this.#position.lng);
|
var startLatLng = new LatLng(this.#position.lat, this.#position.lng);
|
||||||
var endLatLng: LatLng;
|
var endLatLng: LatLng;
|
||||||
@@ -1149,74 +1154,3 @@ export class NavyUnit extends Unit {
|
|||||||
return blueprint?.type? blueprint.type: "";
|
return blueprint?.type? blueprint.type: "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Weapon extends Unit {
|
|
||||||
constructor(ID: number) {
|
|
||||||
super(ID);
|
|
||||||
this.setSelectable(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Missile extends Weapon {
|
|
||||||
constructor(ID: number) {
|
|
||||||
super(ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
getCategory() {
|
|
||||||
return "Missile";
|
|
||||||
}
|
|
||||||
|
|
||||||
getMarkerCategory() {
|
|
||||||
if (this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC))
|
|
||||||
return "missile";
|
|
||||||
else
|
|
||||||
return "aircraft";
|
|
||||||
}
|
|
||||||
|
|
||||||
getIconOptions() {
|
|
||||||
return {
|
|
||||||
showState: false,
|
|
||||||
showVvi: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
|
|
||||||
showHotgroup: false,
|
|
||||||
showUnitIcon: (this.belongsToCommandedCoalition() || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))),
|
|
||||||
showShortLabel: false,
|
|
||||||
showFuel: false,
|
|
||||||
showAmmo: false,
|
|
||||||
showSummary: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
|
|
||||||
showCallsign: false,
|
|
||||||
rotateToHeading: this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Bomb extends Weapon {
|
|
||||||
constructor(ID: number) {
|
|
||||||
super(ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
getCategory() {
|
|
||||||
return "Bomb";
|
|
||||||
}
|
|
||||||
|
|
||||||
getMarkerCategory() {
|
|
||||||
if (this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC))
|
|
||||||
return "bomb";
|
|
||||||
else
|
|
||||||
return "aircraft";
|
|
||||||
}
|
|
||||||
|
|
||||||
getIconOptions() {
|
|
||||||
return {
|
|
||||||
showState: false,
|
|
||||||
showVvi: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
|
|
||||||
showHotgroup: false,
|
|
||||||
showUnitIcon: (this.belongsToCommandedCoalition() || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))),
|
|
||||||
showShortLabel: false,
|
|
||||||
showFuel: false,
|
|
||||||
showAmmo: false,
|
|
||||||
showSummary: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
|
|
||||||
showCallsign: false,
|
|
||||||
rotateToHeading: this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
import { LatLng, LatLngBounds } from "leaflet";
|
import { LatLng, LatLngBounds } from "leaflet";
|
||||||
import { getHotgroupPanel, getInfoPopup, getMap, getMissionHandler, getUnitsManager } from "..";
|
import { getHotgroupPanel, getInfoPopup, getMap, getMissionHandler, getUnitsManager } from "..";
|
||||||
import { Unit } from "./unit";
|
import { Unit } from "./unit";
|
||||||
import { cloneUnit, deleteUnit, spawnAircrafts, spawnGroundUnits, spawnHelicopters, spawnNavyUnits } from "../server/server";
|
import { cloneUnit, deleteUnit, refreshAll, spawnAircrafts, spawnGroundUnits, spawnHelicopters, spawnNavyUnits } from "../server/server";
|
||||||
import { bearingAndDistanceToLatLng, deg2rad, keyEventWasInInput, latLngToMercator, mToFt, mercatorToLatLng, msToKnots, polyContains, polygonArea, randomPointInPoly, randomUnitBlueprint } from "../other/utils";
|
import { bearingAndDistanceToLatLng, deg2rad, keyEventWasInInput, latLngToMercator, mToFt, mercatorToLatLng, msToKnots, polyContains, polygonArea, randomPointInPoly, randomUnitBlueprint } from "../other/utils";
|
||||||
import { CoalitionArea } from "../map/coalitionarea";
|
import { CoalitionArea } from "../map/coalitionarea";
|
||||||
import { groundUnitDatabase } from "./groundunitdatabase";
|
import { groundUnitDatabase } from "./groundunitdatabase";
|
||||||
import { DataIndexes, GAME_MASTER, IADSDensities, IDLE, MOVE_UNIT, NONE } from "../constants/constants";
|
import { DataIndexes, GAME_MASTER, IADSDensities, IDLE, MOVE_UNIT, NONE } from "../constants/constants";
|
||||||
import { DataExtractor } from "./dataextractor";
|
import { DataExtractor } from "../server/dataextractor";
|
||||||
import { Contact } from "../@types/unit";
|
import { Contact } from "../@types/unit";
|
||||||
import { citiesDatabase } from "./citiesdatabase";
|
import { citiesDatabase } from "./citiesDatabase";
|
||||||
import { aircraftDatabase } from "./aircraftdatabase";
|
import { aircraftDatabase } from "./aircraftdatabase";
|
||||||
import { helicopterDatabase } from "./helicopterdatabase";
|
import { helicopterDatabase } from "./helicopterdatabase";
|
||||||
import { navyUnitDatabase } from "./navyunitdatabase";
|
import { navyUnitDatabase } from "./navyunitdatabase";
|
||||||
@@ -35,7 +35,7 @@ export class UnitsManager {
|
|||||||
document.addEventListener('exportToFile', () => this.exportToFile());
|
document.addEventListener('exportToFile', () => this.exportToFile());
|
||||||
document.addEventListener('importFromFile', () => this.importFromFile());
|
document.addEventListener('importFromFile', () => this.importFromFile());
|
||||||
document.addEventListener('contactsUpdated', (e: CustomEvent) => {this.#requestDetectionUpdate = true});
|
document.addEventListener('contactsUpdated', (e: CustomEvent) => {this.#requestDetectionUpdate = true});
|
||||||
document.addEventListener("commandModeOptionsChanged", () => {Object.values(this.#units).forEach((unit: Unit) => unit.updateVisibility())});
|
document.addEventListener('commandModeOptionsChanged', () => {Object.values(this.#units).forEach((unit: Unit) => unit.updateVisibility())});
|
||||||
}
|
}
|
||||||
|
|
||||||
getSelectableAircraft() {
|
getSelectableAircraft() {
|
||||||
@@ -73,14 +73,9 @@ export class UnitsManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeUnit(ID: number) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
update(buffer: ArrayBuffer) {
|
update(buffer: ArrayBuffer) {
|
||||||
var dataExtractor = new DataExtractor(buffer);
|
var dataExtractor = new DataExtractor(buffer);
|
||||||
var updateTime = Number(dataExtractor.extractUInt64());
|
var updateTime = Number(dataExtractor.extractUInt64());
|
||||||
var requestRefresh = false;
|
|
||||||
while (dataExtractor.getSeekPosition() < buffer.byteLength) {
|
while (dataExtractor.getSeekPosition() < buffer.byteLength) {
|
||||||
const ID = dataExtractor.extractUInt32();
|
const ID = dataExtractor.extractUInt32();
|
||||||
if (!(ID in this.#units)) {
|
if (!(ID in this.#units)) {
|
||||||
@@ -90,18 +85,40 @@ export class UnitsManager {
|
|||||||
this.addUnit(ID, category);
|
this.addUnit(ID, category);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
requestRefresh = true;
|
/* Inconsistent data, we need to wait for a refresh */
|
||||||
|
return updateTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.#units[ID]?.setData(dataExtractor);
|
this.#units[ID]?.setData(dataExtractor);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.#requestDetectionUpdate && getMissionHandler().getCommandModeOptions().commandMode != GAME_MASTER) {
|
if (this.#requestDetectionUpdate && getMissionHandler().getCommandModeOptions().commandMode != GAME_MASTER) {
|
||||||
|
/* Create a dictionary of empty detection methods arrays */
|
||||||
|
var detectionMethods: {[key: string]: number[]} = {};
|
||||||
for (let ID in this.#units) {
|
for (let ID in this.#units) {
|
||||||
var unit = this.#units[ID];
|
const unit = this.#units[ID];
|
||||||
if (!unit.belongsToCommandedCoalition())
|
detectionMethods[ID] = [];
|
||||||
unit.setDetectionMethods(this.getUnitDetectedMethods(unit));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fill the array with the detection methods */
|
||||||
|
for (let ID in this.#units) {
|
||||||
|
const unit = this.#units[ID];
|
||||||
|
if (unit.getAlive() && unit.belongsToCommandedCoalition()){
|
||||||
|
const contacts = unit.getContacts();
|
||||||
|
contacts.forEach((contact: Contact) => {
|
||||||
|
const contactID = contact.ID;
|
||||||
|
if (!(detectionMethods[contactID].includes(contact.detectionMethod)))
|
||||||
|
detectionMethods[contactID]?.push(contact.detectionMethod);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the detection methods for every unit */
|
||||||
|
for (let ID in this.#units) {
|
||||||
|
const unit = this.#units[ID];
|
||||||
|
unit.setDetectionMethods(detectionMethods[ID]);
|
||||||
|
}
|
||||||
|
|
||||||
this.#requestDetectionUpdate = false;
|
this.#requestDetectionUpdate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -654,9 +671,10 @@ export class UnitsManager {
|
|||||||
var contents = e.target.result;
|
var contents = e.target.result;
|
||||||
var groups = JSON.parse(contents);
|
var groups = JSON.parse(contents);
|
||||||
for (let groupName in groups) {
|
for (let groupName in groups) {
|
||||||
if (groupName !== "" && groups[groupName].length > 0 && groups[groupName].every((unit: any) => {return unit.category == "GroundUnit";})) {
|
if (groupName !== "" && groups[groupName].length > 0 && (groups[groupName].every((unit: any) => {return unit.category == "GroundUnit";}) || groups[groupName].every((unit: any) => {return unit.category == "NavyUnit";}))) {
|
||||||
var units = groups[groupName].map((unit: any) => {return {unitType: unit.name, location: unit.position}});
|
var aliveUnits = groups[groupName].filter((unit: any) => {return unit.alive});
|
||||||
getUnitsManager().spawnUnits("GroundUnit", units, groups[groupName][0].coalition, true);
|
var units = aliveUnits.map((unit: any) => {return {unitType: unit.name, location: unit.position}});
|
||||||
|
getUnitsManager().spawnUnits(groups[groupName][0].category, units, groups[groupName][0].coalition, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -668,28 +686,28 @@ export class UnitsManager {
|
|||||||
spawnUnits(category: string, units: any, coalition: string = "blue", immediate: boolean = true, airbase: string = "") {
|
spawnUnits(category: string, units: any, coalition: string = "blue", immediate: boolean = true, airbase: string = "") {
|
||||||
var spawnPoints = 0;
|
var spawnPoints = 0;
|
||||||
if (category === "Aircraft") {
|
if (category === "Aircraft") {
|
||||||
if (airbase == "" && getMissionHandler().getRemainingSetupTime() < 0 && getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER) {
|
if (airbase == "" && getMissionHandler().getCommandModeOptions().restrictSpawns && getMissionHandler().getRemainingSetupTime() < 0 && getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER) {
|
||||||
getInfoPopup().setText("Aircrafts can be air spawned during the SETUP phase only");
|
getInfoPopup().setText("Aircrafts can be air spawned during the SETUP phase only");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
spawnPoints = units.reduce((points: number, unit: any) => {return points + aircraftDatabase.getSpawnPointsByName(unit.unitType)}, 0);
|
spawnPoints = units.reduce((points: number, unit: any) => {return points + aircraftDatabase.getSpawnPointsByName(unit.unitType)}, 0);
|
||||||
spawnAircrafts(units, coalition, airbase, immediate, spawnPoints);
|
spawnAircrafts(units, coalition, airbase, immediate, spawnPoints);
|
||||||
} else if (category === "Helicopter") {
|
} else if (category === "Helicopter") {
|
||||||
if (airbase == "" && getMissionHandler().getRemainingSetupTime() < 0 && getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER) {
|
if (airbase == "" && getMissionHandler().getCommandModeOptions().restrictSpawns && getMissionHandler().getRemainingSetupTime() < 0 && getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER) {
|
||||||
getInfoPopup().setText("Helicopters can be air spawned during the SETUP phase only");
|
getInfoPopup().setText("Helicopters can be air spawned during the SETUP phase only");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
spawnPoints = units.reduce((points: number, unit: any) => {return points + helicopterDatabase.getSpawnPointsByName(unit.unitType)}, 0);
|
spawnPoints = units.reduce((points: number, unit: any) => {return points + helicopterDatabase.getSpawnPointsByName(unit.unitType)}, 0);
|
||||||
spawnHelicopters(units, coalition, airbase, immediate, spawnPoints);
|
spawnHelicopters(units, coalition, airbase, immediate, spawnPoints);
|
||||||
} else if (category === "GroundUnit") {
|
} else if (category === "GroundUnit") {
|
||||||
if (getMissionHandler().getRemainingSetupTime() < 0 && getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER) {
|
if (getMissionHandler().getCommandModeOptions().restrictSpawns && getMissionHandler().getRemainingSetupTime() < 0 && getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER) {
|
||||||
getInfoPopup().setText("Ground units can be spawned during the SETUP phase only");
|
getInfoPopup().setText("Ground units can be spawned during the SETUP phase only");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
spawnPoints = units.reduce((points: number, unit: any) => {return points + groundUnitDatabase.getSpawnPointsByName(unit.unitType)}, 0);
|
spawnPoints = units.reduce((points: number, unit: any) => {return points + groundUnitDatabase.getSpawnPointsByName(unit.unitType)}, 0);
|
||||||
spawnGroundUnits(units, coalition, immediate, spawnPoints);
|
spawnGroundUnits(units, coalition, immediate, spawnPoints);
|
||||||
} else if (category === "NavyUnit") {
|
} else if (category === "NavyUnit") {
|
||||||
if (getMissionHandler().getRemainingSetupTime() < 0 && getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER) {
|
if (getMissionHandler().getCommandModeOptions().restrictSpawns && getMissionHandler().getRemainingSetupTime() < 0 && getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER) {
|
||||||
getInfoPopup().setText("Navy units can be spawned during the SETUP phase only");
|
getInfoPopup().setText("Navy units can be spawned during the SETUP phase only");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -718,9 +736,9 @@ export class UnitsManager {
|
|||||||
|
|
||||||
#onUnitSelection(unit: Unit) {
|
#onUnitSelection(unit: Unit) {
|
||||||
if (this.getSelectedUnits().length > 0) {
|
if (this.getSelectedUnits().length > 0) {
|
||||||
getMap().setState(MOVE_UNIT);
|
|
||||||
/* Disable the firing of the selection event for a certain amount of time. This avoids firing many events if many units are selected */
|
/* Disable the firing of the selection event for a certain amount of time. This avoids firing many events if many units are selected */
|
||||||
if (!this.#selectionEventDisabled) {
|
if (!this.#selectionEventDisabled) {
|
||||||
|
getMap().setState(MOVE_UNIT);
|
||||||
window.setTimeout(() => {
|
window.setTimeout(() => {
|
||||||
document.dispatchEvent(new CustomEvent("unitsSelection", { detail: this.getSelectedUnits() }));
|
document.dispatchEvent(new CustomEvent("unitsSelection", { detail: this.getSelectedUnits() }));
|
||||||
this.#selectionEventDisabled = false;
|
this.#selectionEventDisabled = false;
|
||||||
323
client/src/weapon/weapon.ts
Normal file
323
client/src/weapon/weapon.ts
Normal file
@@ -0,0 +1,323 @@
|
|||||||
|
import { LatLng, DivIcon, Map } from 'leaflet';
|
||||||
|
import { getMap, getMissionHandler, getUnitsManager } from '..';
|
||||||
|
import { enumToCoalition, mToFt, msToKnots, rad2deg } from '../other/utils';
|
||||||
|
import { CustomMarker } from '../map/custommarker';
|
||||||
|
import { SVGInjector } from '@tanem/svg-injector';
|
||||||
|
import { DLINK, DataIndexes, GAME_MASTER, IRST, OPTIC, RADAR, VISUAL } from '../constants/constants';
|
||||||
|
import { ObjectIconOptions } from '../@types/unit';
|
||||||
|
import { DataExtractor } from '../server/dataextractor';
|
||||||
|
|
||||||
|
export class Weapon extends CustomMarker {
|
||||||
|
ID: number;
|
||||||
|
|
||||||
|
#alive: boolean = false;
|
||||||
|
#coalition: string = "neutral";
|
||||||
|
#name: string = "";
|
||||||
|
#position: LatLng = new LatLng(0, 0, 0);
|
||||||
|
#speed: number = 0;
|
||||||
|
#heading: number = 0;
|
||||||
|
|
||||||
|
#hidden: boolean = false;
|
||||||
|
#detectionMethods: number[] = [];
|
||||||
|
|
||||||
|
getAlive() {return this.#alive};
|
||||||
|
getCoalition() {return this.#coalition};
|
||||||
|
getName() {return this.#name};
|
||||||
|
getPosition() {return this.#position};
|
||||||
|
getSpeed() {return this.#speed};
|
||||||
|
getHeading() {return this.#heading};
|
||||||
|
|
||||||
|
static getConstructor(type: string) {
|
||||||
|
if (type === "Missile") return Missile;
|
||||||
|
if (type === "Bomb") return Bomb;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(ID: number) {
|
||||||
|
super(new LatLng(0, 0), { riseOnHover: true, keyboard: false });
|
||||||
|
|
||||||
|
this.ID = ID;
|
||||||
|
|
||||||
|
/* Deselect units if they are hidden */
|
||||||
|
document.addEventListener("toggleCoalitionVisibility", (ev: CustomEventInit) => {
|
||||||
|
window.setTimeout(() => { !this.getHidden() }, 300);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("toggleUnitVisibility", (ev: CustomEventInit) => {
|
||||||
|
window.setTimeout(() => { !this.getHidden() }, 300);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("mapVisibilityOptionsChanged", (ev: CustomEventInit) => {
|
||||||
|
this.#updateMarker();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getCategory() {
|
||||||
|
// Overloaded by child classes
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************** Unit data *************************/
|
||||||
|
setData(dataExtractor: DataExtractor) {
|
||||||
|
var updateMarker = !getMap().hasLayer(this);
|
||||||
|
|
||||||
|
var datumIndex = 0;
|
||||||
|
while (datumIndex != DataIndexes.endOfData) {
|
||||||
|
datumIndex = dataExtractor.extractUInt8();
|
||||||
|
switch (datumIndex) {
|
||||||
|
case DataIndexes.category: dataExtractor.extractString(); break;
|
||||||
|
case DataIndexes.alive: this.setAlive(dataExtractor.extractBool()); updateMarker = true; break;
|
||||||
|
case DataIndexes.coalition: this.#coalition = enumToCoalition(dataExtractor.extractUInt8()); break;
|
||||||
|
case DataIndexes.name: this.#name = dataExtractor.extractString(); break;
|
||||||
|
case DataIndexes.position: this.#position = dataExtractor.extractLatLng(); updateMarker = true; break;
|
||||||
|
case DataIndexes.speed: this.#speed = dataExtractor.extractFloat64(); updateMarker = true; break;
|
||||||
|
case DataIndexes.heading: this.#heading = dataExtractor.extractFloat64(); updateMarker = true; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateMarker)
|
||||||
|
this.#updateMarker();
|
||||||
|
}
|
||||||
|
|
||||||
|
getData() {
|
||||||
|
return {
|
||||||
|
category: this.getCategory(),
|
||||||
|
ID: this.ID,
|
||||||
|
alive: this.#alive,
|
||||||
|
coalition: this.#coalition,
|
||||||
|
name: this.#name,
|
||||||
|
position: this.#position,
|
||||||
|
speed: this.#speed,
|
||||||
|
heading: this.#heading
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getMarkerCategory(): string {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
getIconOptions(): ObjectIconOptions {
|
||||||
|
// Default values, overloaded by child classes if needed
|
||||||
|
return {
|
||||||
|
showState: false,
|
||||||
|
showVvi: false,
|
||||||
|
showHotgroup: false,
|
||||||
|
showUnitIcon: true,
|
||||||
|
showShortLabel: false,
|
||||||
|
showFuel: false,
|
||||||
|
showAmmo: false,
|
||||||
|
showSummary: true,
|
||||||
|
showCallsign: true,
|
||||||
|
rotateToHeading: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setAlive(newAlive: boolean) {
|
||||||
|
this.#alive = newAlive;
|
||||||
|
}
|
||||||
|
|
||||||
|
belongsToCommandedCoalition() {
|
||||||
|
if (getMissionHandler().getCommandModeOptions().commandMode !== GAME_MASTER && getMissionHandler().getCommandedCoalition() !== this.#coalition)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getType() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************** Icon *************************/
|
||||||
|
createIcon(): void {
|
||||||
|
/* Set the icon */
|
||||||
|
var icon = new DivIcon({
|
||||||
|
className: 'leaflet-unit-icon',
|
||||||
|
iconAnchor: [25, 25],
|
||||||
|
iconSize: [50, 50],
|
||||||
|
});
|
||||||
|
this.setIcon(icon);
|
||||||
|
|
||||||
|
var el = document.createElement("div");
|
||||||
|
el.classList.add("unit");
|
||||||
|
el.setAttribute("data-object", `unit-${this.getMarkerCategory()}`);
|
||||||
|
el.setAttribute("data-coalition", this.#coalition);
|
||||||
|
|
||||||
|
// Generate and append elements depending on active options
|
||||||
|
// Velocity vector
|
||||||
|
if (this.getIconOptions().showVvi) {
|
||||||
|
var vvi = document.createElement("div");
|
||||||
|
vvi.classList.add("unit-vvi");
|
||||||
|
vvi.toggleAttribute("data-rotate-to-heading");
|
||||||
|
el.append(vvi);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main icon
|
||||||
|
if (this.getIconOptions().showUnitIcon) {
|
||||||
|
var unitIcon = document.createElement("div");
|
||||||
|
unitIcon.classList.add("unit-icon");
|
||||||
|
var img = document.createElement("img");
|
||||||
|
img.src = `/resources/theme/images/units/${this.getMarkerCategory()}.svg`;
|
||||||
|
img.onload = () => SVGInjector(img);
|
||||||
|
unitIcon.appendChild(img);
|
||||||
|
unitIcon.toggleAttribute("data-rotate-to-heading", this.getIconOptions().rotateToHeading);
|
||||||
|
el.append(unitIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getElement()?.appendChild(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************** Visibility *************************/
|
||||||
|
updateVisibility() {
|
||||||
|
const hiddenUnits = getUnitsManager().getHiddenTypes();
|
||||||
|
var hidden = (hiddenUnits.includes(this.getMarkerCategory())) ||
|
||||||
|
(hiddenUnits.includes(this.#coalition)) ||
|
||||||
|
(!this.belongsToCommandedCoalition() && this.#detectionMethods.length == 0);
|
||||||
|
|
||||||
|
this.setHidden(hidden || !this.#alive);
|
||||||
|
}
|
||||||
|
|
||||||
|
setHidden(hidden: boolean) {
|
||||||
|
this.#hidden = hidden;
|
||||||
|
|
||||||
|
/* Add the marker if not present */
|
||||||
|
if (!getMap().hasLayer(this) && !this.getHidden()) {
|
||||||
|
if (getMap().isZooming())
|
||||||
|
this.once("zoomend", () => {this.addTo(getMap())})
|
||||||
|
else
|
||||||
|
this.addTo(getMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide the marker if necessary*/
|
||||||
|
if (getMap().hasLayer(this) && this.getHidden()) {
|
||||||
|
getMap().removeLayer(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getHidden() {
|
||||||
|
return this.#hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
setDetectionMethods(newDetectionMethods: number[]) {
|
||||||
|
if (!this.belongsToCommandedCoalition()) {
|
||||||
|
/* Check if the detection methods of this unit have changed */
|
||||||
|
if (this.#detectionMethods.length !== newDetectionMethods.length || this.getDetectionMethods().some(value => !newDetectionMethods.includes(value))) {
|
||||||
|
/* Force a redraw of the unit to reflect the new status of the detection methods */
|
||||||
|
this.setHidden(true);
|
||||||
|
this.#detectionMethods = newDetectionMethods;
|
||||||
|
this.updateVisibility();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDetectionMethods() {
|
||||||
|
return this.#detectionMethods;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************/
|
||||||
|
onAdd(map: Map): this {
|
||||||
|
super.onAdd(map);
|
||||||
|
/* If this is the first time adding this unit to the map, remove the temporary marker */
|
||||||
|
getMap().removeTemporaryMarker(new LatLng(this.#position.lat, this.#position.lng));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#updateMarker() {
|
||||||
|
this.updateVisibility();
|
||||||
|
|
||||||
|
/* Draw the marker */
|
||||||
|
if (!this.getHidden()) {
|
||||||
|
if (this.getLatLng().lat !== this.#position.lat || this.getLatLng().lng !== this.#position.lng) {
|
||||||
|
this.setLatLng(new LatLng(this.#position.lat, this.#position.lng));
|
||||||
|
}
|
||||||
|
|
||||||
|
var element = this.getElement();
|
||||||
|
if (element != null) {
|
||||||
|
/* Draw the velocity vector */
|
||||||
|
element.querySelector(".unit-vvi")?.setAttribute("style", `height: ${15 + this.#speed / 5}px;`);
|
||||||
|
|
||||||
|
/* Set dead/alive flag */
|
||||||
|
element.querySelector(".unit")?.toggleAttribute("data-is-dead", !this.#alive);
|
||||||
|
|
||||||
|
|
||||||
|
/* Set altitude and speed */
|
||||||
|
if (element.querySelector(".unit-altitude"))
|
||||||
|
(<HTMLElement>element.querySelector(".unit-altitude")).innerText = "FL" + String(Math.floor(mToFt(this.#position.alt as number) / 100));
|
||||||
|
if (element.querySelector(".unit-speed"))
|
||||||
|
(<HTMLElement>element.querySelector(".unit-speed")).innerText = String(Math.floor(msToKnots(this.#speed))) + "GS";
|
||||||
|
|
||||||
|
/* Rotate elements according to heading */
|
||||||
|
element.querySelectorAll("[data-rotate-to-heading]").forEach(el => {
|
||||||
|
const headingDeg = rad2deg(this.#heading);
|
||||||
|
let currentStyle = el.getAttribute("style") || "";
|
||||||
|
el.setAttribute("style", currentStyle + `transform:rotate(${headingDeg}deg);`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set vertical offset for altitude stacking */
|
||||||
|
var pos = getMap().latLngToLayerPoint(this.getLatLng()).round();
|
||||||
|
this.setZIndexOffset(1000 + Math.floor(this.#position.alt as number) - pos.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Missile extends Weapon {
|
||||||
|
constructor(ID: number) {
|
||||||
|
super(ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
getCategory() {
|
||||||
|
return "Missile";
|
||||||
|
}
|
||||||
|
|
||||||
|
getMarkerCategory() {
|
||||||
|
if (this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC))
|
||||||
|
return "missile";
|
||||||
|
else
|
||||||
|
return "aircraft";
|
||||||
|
}
|
||||||
|
|
||||||
|
getIconOptions() {
|
||||||
|
return {
|
||||||
|
showState: false,
|
||||||
|
showVvi: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
|
||||||
|
showHotgroup: false,
|
||||||
|
showUnitIcon: (this.belongsToCommandedCoalition() || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))),
|
||||||
|
showShortLabel: false,
|
||||||
|
showFuel: false,
|
||||||
|
showAmmo: false,
|
||||||
|
showSummary: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
|
||||||
|
showCallsign: false,
|
||||||
|
rotateToHeading: this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Bomb extends Weapon {
|
||||||
|
constructor(ID: number) {
|
||||||
|
super(ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
getCategory() {
|
||||||
|
return "Bomb";
|
||||||
|
}
|
||||||
|
|
||||||
|
getMarkerCategory() {
|
||||||
|
if (this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC))
|
||||||
|
return "bomb";
|
||||||
|
else
|
||||||
|
return "aircraft";
|
||||||
|
}
|
||||||
|
|
||||||
|
getIconOptions() {
|
||||||
|
return {
|
||||||
|
showState: false,
|
||||||
|
showVvi: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
|
||||||
|
showHotgroup: false,
|
||||||
|
showUnitIcon: (this.belongsToCommandedCoalition() || this.getDetectionMethods().some(value => [VISUAL, OPTIC, RADAR, IRST, DLINK].includes(value))),
|
||||||
|
showShortLabel: false,
|
||||||
|
showFuel: false,
|
||||||
|
showAmmo: false,
|
||||||
|
showSummary: (!this.belongsToCommandedCoalition() && !this.getDetectionMethods().some(value => [VISUAL, OPTIC].includes(value)) && this.getDetectionMethods().some(value => [RADAR, IRST, DLINK].includes(value))),
|
||||||
|
showCallsign: false,
|
||||||
|
rotateToHeading: this.belongsToCommandedCoalition() || this.getDetectionMethods().includes(VISUAL) || this.getDetectionMethods().includes(OPTIC)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
84
client/src/weapon/weaponsmanager.ts
Normal file
84
client/src/weapon/weaponsmanager.ts
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
import { getMissionHandler, getUnitsManager } from "..";
|
||||||
|
import { Weapon } from "./weapon";
|
||||||
|
import { DataIndexes, GAME_MASTER } from "../constants/constants";
|
||||||
|
import { DataExtractor } from "../server/dataextractor";
|
||||||
|
import { Contact } from "../@types/unit";
|
||||||
|
|
||||||
|
export class WeaponsManager {
|
||||||
|
#weapons: { [ID: number]: Weapon };
|
||||||
|
#requestDetectionUpdate: boolean = false;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.#weapons = {};
|
||||||
|
|
||||||
|
document.addEventListener("commandModeOptionsChanged", () => {Object.values(this.#weapons).forEach((weapon: Weapon) => weapon.updateVisibility())});
|
||||||
|
document.addEventListener('contactsUpdated', (e: CustomEvent) => {this.#requestDetectionUpdate = true});
|
||||||
|
}
|
||||||
|
|
||||||
|
getWeapons() {
|
||||||
|
return this.#weapons;
|
||||||
|
}
|
||||||
|
|
||||||
|
getWeaponByID(ID: number) {
|
||||||
|
if (ID in this.#weapons)
|
||||||
|
return this.#weapons[ID];
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
addWeapon(ID: number, category: string) {
|
||||||
|
if (category){
|
||||||
|
/* The name of the weapon category is exactly the same as the constructor name */
|
||||||
|
var constructor = Weapon.getConstructor(category);
|
||||||
|
if (constructor != undefined) {
|
||||||
|
this.#weapons[ID] = new constructor(ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(buffer: ArrayBuffer) {
|
||||||
|
var dataExtractor = new DataExtractor(buffer);
|
||||||
|
var updateTime = Number(dataExtractor.extractUInt64());
|
||||||
|
while (dataExtractor.getSeekPosition() < buffer.byteLength) {
|
||||||
|
const ID = dataExtractor.extractUInt32();
|
||||||
|
if (!(ID in this.#weapons)) {
|
||||||
|
const datumIndex = dataExtractor.extractUInt8();
|
||||||
|
if (datumIndex == DataIndexes.category) {
|
||||||
|
const category = dataExtractor.extractString();
|
||||||
|
this.addWeapon(ID, category);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Inconsistent data, we need to wait for a refresh */
|
||||||
|
return updateTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.#weapons[ID]?.setData(dataExtractor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.#requestDetectionUpdate && getMissionHandler().getCommandModeOptions().commandMode != GAME_MASTER) {
|
||||||
|
for (let ID in this.#weapons) {
|
||||||
|
var weapon = this.#weapons[ID];
|
||||||
|
if (!weapon.belongsToCommandedCoalition())
|
||||||
|
weapon.setDetectionMethods(this.getWeaponDetectedMethods(weapon));
|
||||||
|
}
|
||||||
|
this.#requestDetectionUpdate = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return updateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
getWeaponDetectedMethods(weapon: Weapon) {
|
||||||
|
var detectionMethods: number[] = [];
|
||||||
|
var units = getUnitsManager().getUnits();
|
||||||
|
for (let idx in units) {
|
||||||
|
if (units[idx].getAlive() && units[idx].getIsLeader() && units[idx].getCoalition() !== "neutral" && units[idx].getCoalition() != weapon.getCoalition())
|
||||||
|
{
|
||||||
|
units[idx].getContacts().forEach((contact: Contact) => {
|
||||||
|
if (contact.ID == weapon.ID && !detectionMethods.includes(contact.detectionMethod))
|
||||||
|
detectionMethods.push(contact.detectionMethod);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return detectionMethods;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
<div id="app-summary">
|
<div id="app-summary">
|
||||||
<h2>DCS Olympus</h2>
|
<h2>DCS Olympus</h2>
|
||||||
<h4>Dynamic Unit Command</h4>
|
<h4>Dynamic Unit Command</h4>
|
||||||
<div class="app-version">Version <span class="app-version-number">v0.4.0-alpha</span></div>
|
<div class="app-version">Version <span class="app-version-number">v0.4.1-alpha</span></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="authentication-form">
|
<div id="authentication-form">
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<div class="ol-select-options">
|
<div class="ol-select-options">
|
||||||
<div id="toolbar-summary">
|
<div id="toolbar-summary">
|
||||||
<h3>DCS Olympus</h3>
|
<h3>DCS Olympus</h3>
|
||||||
<div class="accent-green app-version-number">version v0.4.0-alpha</div>
|
<div class="accent-green app-version-number">version v0.4.1-alpha</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="https://www.discord.com" target="_blank">Discord</a>
|
<a href="https://www.discord.com" target="_blank">Discord</a>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#define nwjsFolder "C:\Users\dpass\Documents\nwjs\"
|
#define nwjsFolder "C:\Users\dpass\Documents\nwjs\"
|
||||||
#define version "v0.4.0-alpha"
|
#define version "v0.4.1-alpha"
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
AppName=DCS Olympus
|
AppName=DCS Olympus
|
||||||
@@ -8,7 +8,7 @@ DefaultDirName={usersavedgames}\DCS.openbeta
|
|||||||
DefaultGroupName=DCSOlympus
|
DefaultGroupName=DCSOlympus
|
||||||
OutputBaseFilename=DCSOlympus_{#version}
|
OutputBaseFilename=DCSOlympus_{#version}
|
||||||
UninstallFilesDir={app}\Mods\Services\Olympus
|
UninstallFilesDir={app}\Mods\Services\Olympus
|
||||||
;SetupIconFile="..\img\olympus.ico"
|
SetupIconFile="..\img\olympus.ico"
|
||||||
|
|
||||||
[Tasks]
|
[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.
|
; 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.
|
||||||
@@ -16,8 +16,6 @@ Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{
|
|||||||
|
|
||||||
[Files]
|
[Files]
|
||||||
; NOTE: Don't use "Flags: ignoreversion" on any shared system 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\OlympusHook.lua"; DestDir: "{app}\Scripts\Hooks"; Flags: ignoreversion
|
||||||
Source: "..\olympus.json"; DestDir: "{app}\Mods\Services\Olympus"; Flags: onlyifdoesntexist
|
Source: "..\olympus.json"; DestDir: "{app}\Mods\Services\Olympus"; Flags: onlyifdoesntexist
|
||||||
Source: "..\scripts\OlympusCommand.lua"; DestDir: "{app}\Mods\Services\Olympus\Scripts"; Flags: ignoreversion
|
Source: "..\scripts\OlympusCommand.lua"; DestDir: "{app}\Mods\Services\Olympus\Scripts"; Flags: ignoreversion
|
||||||
@@ -62,9 +60,3 @@ ChangesEnvironment=yes
|
|||||||
|
|
||||||
[Icons]
|
[Icons]
|
||||||
Name: "{userdesktop}\DCS Olympus Client"; Filename: "{app}\Mods\Services\Olympus\client\nw.exe"; Tasks: desktopicon; IconFilename: "{app}\Mods\Services\Olympus\img\olympus.ico"
|
Name: "{userdesktop}\DCS Olympus Client"; Filename: "{app}\Mods\Services\Olympus\client\nw.exe"; Tasks: desktopicon; IconFilename: "{app}\Mods\Services\Olympus\img\olympus.ico"
|
||||||
|
|
||||||
;[Run]
|
|
||||||
;Filename: "{app}\Scripts\OlympusPatcher.exe"; Parameters: "-i"
|
|
||||||
|
|
||||||
;[UninstallRun]
|
|
||||||
;Filename: "{app}\Scripts\OlympusPatcher.exe"; Parameters: "-u"
|
|
||||||
@@ -15,7 +15,7 @@ declare_plugin(self_ID,
|
|||||||
shortName = "Olympus",
|
shortName = "Olympus",
|
||||||
fileMenuName = "Olympus",
|
fileMenuName = "Olympus",
|
||||||
|
|
||||||
version = "v0.4.0-alpha",
|
version = "v0.4.1-alpha",
|
||||||
state = "installed",
|
state = "installed",
|
||||||
developerName= "DCS Refugees 767 squadron",
|
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."),
|
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."),
|
||||||
|
|||||||
4
package.bat
Normal file
4
package.bat
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
cd client
|
||||||
|
call npm prune --production
|
||||||
|
cd ..
|
||||||
|
call "C:\Program Files (x86)\Inno Setup 6\iscc.exe" "installer\olympus.iss"
|
||||||
@@ -1,20 +1,26 @@
|
|||||||
local version = "v0.4.0-alpha"
|
local version = "v0.4.1-alpha"
|
||||||
|
|
||||||
local debug = false
|
local debug = false
|
||||||
|
|
||||||
Olympus.unitCounter = 1
|
|
||||||
Olympus.payloadRegistry = {}
|
|
||||||
Olympus.groupIndex = 0
|
|
||||||
Olympus.groupStep = 5
|
|
||||||
|
|
||||||
Olympus.OlympusDLL = nil
|
Olympus.OlympusDLL = nil
|
||||||
Olympus.DLLsloaded = false
|
Olympus.DLLsloaded = false
|
||||||
Olympus.OlympusModPath = os.getenv('DCSOLYMPUS_PATH')..'\\bin\\'
|
Olympus.OlympusModPath = os.getenv('DCSOLYMPUS_PATH')..'\\bin\\'
|
||||||
Olympus.log = mist.Logger:new("Olympus", 'info')
|
Olympus.log = mist.Logger:new("Olympus", 'info')
|
||||||
|
|
||||||
|
Olympus.unitCounter = 1
|
||||||
|
Olympus.payloadRegistry = {}
|
||||||
|
|
||||||
Olympus.missionData = {}
|
Olympus.missionData = {}
|
||||||
Olympus.unitsData = {}
|
Olympus.unitsData = {}
|
||||||
Olympus.unitNames = {}
|
Olympus.weaponsData = {}
|
||||||
|
|
||||||
|
Olympus.unitIndex = 0
|
||||||
|
Olympus.unitStep = 50
|
||||||
|
Olympus.units = {}
|
||||||
|
|
||||||
|
Olympus.weaponIndex = 0
|
||||||
|
Olympus.weaponStep = 50
|
||||||
|
Olympus.weapons = {}
|
||||||
|
|
||||||
Olympus.missionStartTime = DCS.getRealTime()
|
Olympus.missionStartTime = DCS.getRealTime()
|
||||||
|
|
||||||
@@ -43,35 +49,36 @@ end
|
|||||||
|
|
||||||
-- Gets a unit class reference from a given ObjectID (the ID used by Olympus for unit referencing)
|
-- Gets a unit class reference from a given ObjectID (the ID used by Olympus for unit referencing)
|
||||||
function Olympus.getUnitByID(ID)
|
function Olympus.getUnitByID(ID)
|
||||||
for name, table in pairs(mist.DBs.unitsByName) do
|
return Olympus.units[ID];
|
||||||
local unit = Unit.getByName(name)
|
|
||||||
if unit and unit["getObjectID"] and unit:getObjectID() == ID then
|
|
||||||
return unit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Olympus.getCountryIDByCoalition(coalition)
|
function Olympus.getCountryIDByCoalition(coalitionString)
|
||||||
local countryID = 0
|
for countryName, countryId in pairs(country.id) do
|
||||||
if coalition == 'red' then
|
if coalition.getCountryCoalition(countryId) == Olympus.getCoalitionIDByCoalition(coalitionString) then
|
||||||
countryID = country.id.CJTF_RED
|
return countryId
|
||||||
elseif coalition == 'blue' then
|
end
|
||||||
countryID = country.id.CJTF_BLUE
|
|
||||||
else
|
|
||||||
countryID = country.id.UN_PEACEKEEPERS
|
|
||||||
end
|
end
|
||||||
return countryID
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function Olympus.getCoalitionIDByCoalition(coalitionString)
|
||||||
|
local coalitionID = 0
|
||||||
|
if coalitionString == "red" then
|
||||||
|
coalitionID = 1
|
||||||
|
elseif coalitionString == "blue" then
|
||||||
|
coalitionID = 2
|
||||||
|
end
|
||||||
|
return coalitionID
|
||||||
end
|
end
|
||||||
|
|
||||||
function Olympus.getCoalitionByCoalitionID(coalitionID)
|
function Olympus.getCoalitionByCoalitionID(coalitionID)
|
||||||
local coalition = "neutral"
|
local coalitionString = "neutral"
|
||||||
if coalitionID == 1 then
|
if coalitionID == 1 then
|
||||||
coalition = "red"
|
coalitionString = "red"
|
||||||
elseif coalitionID == 2 then
|
elseif coalitionID == 2 then
|
||||||
coalition = "blue"
|
coalitionString = "blue"
|
||||||
end
|
end
|
||||||
return coalition
|
return coalitionString
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Builds a valid task depending on the provided options
|
-- Builds a valid task depending on the provided options
|
||||||
@@ -219,7 +226,6 @@ function Olympus.move(groupName, lat, lng, altitude, altitudeType, speed, speedT
|
|||||||
if category == "Aircraft" then
|
if category == "Aircraft" then
|
||||||
local startPoint = mist.getLeadPos(group)
|
local startPoint = mist.getLeadPos(group)
|
||||||
local endPoint = coord.LLtoLO(lat, lng, 0)
|
local endPoint = coord.LLtoLO(lat, lng, 0)
|
||||||
|
|
||||||
if altitudeType == "AGL" then
|
if altitudeType == "AGL" then
|
||||||
altitude = land.getHeight({x = endPoint.x, y = endPoint.z}) + altitude
|
altitude = land.getHeight({x = endPoint.x, y = endPoint.z}) + altitude
|
||||||
end
|
end
|
||||||
@@ -305,11 +311,15 @@ function Olympus.move(groupName, lat, lng, altitude, altitudeType, speed, speedT
|
|||||||
end
|
end
|
||||||
Olympus.debug("Olympus.move executed successfully on Helicopter", 2)
|
Olympus.debug("Olympus.move executed successfully on Helicopter", 2)
|
||||||
elseif category == "GroundUnit" then
|
elseif category == "GroundUnit" then
|
||||||
|
local startPoint = mist.getLeadPos(group)
|
||||||
|
local endPoint = coord.LLtoLO(lat, lng, 0)
|
||||||
|
local bearing = math.atan2(endPoint.z - startPoint.z, endPoint.x - startPoint.x)
|
||||||
|
|
||||||
vars =
|
vars =
|
||||||
{
|
{
|
||||||
group = group,
|
group = group,
|
||||||
point = coord.LLtoLO(lat, lng, 0),
|
point = endPoint,
|
||||||
heading = 0,
|
heading = bearing,
|
||||||
speed = speed
|
speed = speed
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,11 +333,15 @@ function Olympus.move(groupName, lat, lng, altitude, altitudeType, speed, speedT
|
|||||||
mist.groupToRandomPoint(vars)
|
mist.groupToRandomPoint(vars)
|
||||||
Olympus.debug("Olympus.move executed succesfully on GroundUnit", 2)
|
Olympus.debug("Olympus.move executed succesfully on GroundUnit", 2)
|
||||||
elseif category == "NavyUnit" then
|
elseif category == "NavyUnit" then
|
||||||
|
local startPoint = mist.getLeadPos(group)
|
||||||
|
local endPoint = coord.LLtoLO(lat, lng, 0)
|
||||||
|
local bearing = math.atan2(endPoint.z - startPoint.z, endPoint.x - startPoint.x)
|
||||||
|
|
||||||
vars =
|
vars =
|
||||||
{
|
{
|
||||||
group = group,
|
group = group,
|
||||||
point = coord.LLtoLO(lat, lng, 0),
|
point = endPoint,
|
||||||
heading = 0,
|
heading = bearing,
|
||||||
speed = speed
|
speed = speed
|
||||||
}
|
}
|
||||||
mist.groupToRandomPoint(vars)
|
mist.groupToRandomPoint(vars)
|
||||||
@@ -542,7 +556,7 @@ function Olympus.generateNavyUnitsTable(units)
|
|||||||
["y"] = spawnLocation.z + value.dy,
|
["y"] = spawnLocation.z + value.dy,
|
||||||
["heading"] = 0,
|
["heading"] = 0,
|
||||||
["skill"] = "High",
|
["skill"] = "High",
|
||||||
["name"] = "NavyUnit-" .. Olympus.unitCounter .. "-" .. #unitTable + 1,
|
["name"] = "Olympus-" .. Olympus.unitCounter .. "-" .. #unitTable + 1,
|
||||||
["transportable"] = { ["randomTransportable"] = false }
|
["transportable"] = { ["randomTransportable"] = false }
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@@ -554,7 +568,7 @@ function Olympus.generateNavyUnitsTable(units)
|
|||||||
["y"] = spawnLocation.z,
|
["y"] = spawnLocation.z,
|
||||||
["heading"] = 0,
|
["heading"] = 0,
|
||||||
["skill"] = "High",
|
["skill"] = "High",
|
||||||
["name"] = "NavyUnit-" .. Olympus.unitCounter .. "-" .. #unitTable + 1,
|
["name"] = "Olympus-" .. Olympus.unitCounter .. "-" .. #unitTable + 1,
|
||||||
["transportable"] = { ["randomTransportable"] = false }
|
["transportable"] = { ["randomTransportable"] = false }
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@@ -568,10 +582,9 @@ function Olympus.clone(ID, lat, lng, category)
|
|||||||
Olympus.debug("Olympus.clone " .. ID .. ", " .. category, 2)
|
Olympus.debug("Olympus.clone " .. ID .. ", " .. category, 2)
|
||||||
local unit = Olympus.getUnitByID(ID)
|
local unit = Olympus.getUnitByID(ID)
|
||||||
if unit then
|
if unit then
|
||||||
local coalition = Olympus.getCoalitionByCoalitionID(unit:getCoalition())
|
|
||||||
-- TODO: understand category in this script
|
-- TODO: understand category in this script
|
||||||
local spawnTable = {
|
local spawnTable = {
|
||||||
coalition = coalition,
|
coalition = Olympus.getCoalitionByCoalitionID(unit:getCoalition()),
|
||||||
category = category,
|
category = category,
|
||||||
units = {
|
units = {
|
||||||
[1] = {
|
[1] = {
|
||||||
@@ -651,6 +664,240 @@ function Olympus.setOnOff(groupName, onOff)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Olympus.setUnitsData(arg, time)
|
||||||
|
-- Units data
|
||||||
|
local units = {}
|
||||||
|
|
||||||
|
local startIndex = Olympus.unitIndex
|
||||||
|
local endIndex = startIndex + Olympus.unitStep
|
||||||
|
local index = 0
|
||||||
|
for ID, unit in pairs(Olympus.units) do
|
||||||
|
index = index + 1
|
||||||
|
if index > startIndex then
|
||||||
|
if unit ~= nil then
|
||||||
|
local table = {}
|
||||||
|
-- Get the object category in Olympus name
|
||||||
|
local objectCategory = unit:getCategory()
|
||||||
|
if objectCategory == Object.Category.UNIT then
|
||||||
|
if unit:getDesc().category == Unit.Category.AIRPLANE then
|
||||||
|
table["category"] = "Aircraft"
|
||||||
|
elseif unit:getDesc().category == Unit.Category.HELICOPTER then
|
||||||
|
table["category"] = "Helicopter"
|
||||||
|
elseif unit:getDesc().category == Unit.Category.GROUND_UNIT then
|
||||||
|
table["category"] = "GroundUnit"
|
||||||
|
elseif unit:getDesc().category == Unit.Category.SHIP then
|
||||||
|
table["category"] = "NavyUnit"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
units[ID] = {isAlive = false}
|
||||||
|
Olympus.units[ID] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If the category is handled by Olympus, get the data
|
||||||
|
if table["category"] ~= nil then
|
||||||
|
-- Compute unit position and heading
|
||||||
|
local lat, lng, alt = coord.LOtoLL(unit:getPoint())
|
||||||
|
local position = unit:getPosition()
|
||||||
|
local heading = math.atan2( position.x.z, position.x.x )
|
||||||
|
|
||||||
|
-- Fill the data table
|
||||||
|
table["name"] = unit:getTypeName()
|
||||||
|
table["coalitionID"] = unit:getCoalition()
|
||||||
|
table["position"] = {}
|
||||||
|
table["position"]["lat"] = lat
|
||||||
|
table["position"]["lng"] = lng
|
||||||
|
table["position"]["alt"] = alt
|
||||||
|
table["speed"] = mist.vec.mag(unit:getVelocity())
|
||||||
|
table["heading"] = heading
|
||||||
|
table["isAlive"] = unit:isExist() and unit:isActive() and unit:getLife() >= 1
|
||||||
|
|
||||||
|
local group = unit:getGroup()
|
||||||
|
if group ~= nil then
|
||||||
|
local controller = group:getController()
|
||||||
|
if controller ~= nil then
|
||||||
|
-- Get the targets detected by the unit controller
|
||||||
|
local contacts = {}
|
||||||
|
local unitController = unit:getController()
|
||||||
|
if unitController ~= nil then
|
||||||
|
for det, enum in pairs(Controller.Detection) do
|
||||||
|
local controllerTargets = unitController:getDetectedTargets(enum)
|
||||||
|
for i, target in ipairs(controllerTargets) do
|
||||||
|
if target ~= nil and target.object ~= nil and target.visible then
|
||||||
|
target["detectionMethod"] = det
|
||||||
|
contacts[#contacts + 1] = target
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
table["country"] = unit:getCountry()
|
||||||
|
table["unitName"] = unit:getName()
|
||||||
|
table["groupName"] = group:getName()
|
||||||
|
table["isHuman"] = (unit:getPlayerName() ~= nil)
|
||||||
|
table["hasTask"] = controller:hasTask()
|
||||||
|
table["ammo"] = unit:getAmmo() --TODO remove a lot of stuff we don't really need
|
||||||
|
table["fuel"] = unit:getFuel()
|
||||||
|
table["life"] = unit:getLife() / unit:getLife0()
|
||||||
|
table["contacts"] = contacts
|
||||||
|
|
||||||
|
units[ID] = table
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
units[ID] = {isAlive = false}
|
||||||
|
Olympus.units[ID] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if index >= endIndex then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if index ~= endIndex then
|
||||||
|
Olympus.unitIndex = 0
|
||||||
|
else
|
||||||
|
Olympus.unitIndex = endIndex
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Assemble unitsData table
|
||||||
|
Olympus.unitsData["units"] = units
|
||||||
|
|
||||||
|
Olympus.OlympusDLL.setUnitsData()
|
||||||
|
return time + 0.05
|
||||||
|
end
|
||||||
|
|
||||||
|
function Olympus.setWeaponsData(arg, time)
|
||||||
|
-- Weapons data
|
||||||
|
local weapons = {}
|
||||||
|
|
||||||
|
local startIndex = Olympus.weaponIndex
|
||||||
|
local endIndex = startIndex + Olympus.weaponStep
|
||||||
|
local index = 0
|
||||||
|
for ID, weapon in pairs(Olympus.weapons) do
|
||||||
|
index = index + 1
|
||||||
|
if index > startIndex then
|
||||||
|
if weapon ~= nil then
|
||||||
|
local table = {}
|
||||||
|
|
||||||
|
-- Get the object category in Olympus name
|
||||||
|
local objectCategory = weapon:getCategory()
|
||||||
|
if objectCategory == Object.Category.WEAPON then
|
||||||
|
if weapon:getDesc().category == Weapon.Category.MISSILE then
|
||||||
|
table["category"] = "Missile"
|
||||||
|
elseif weapon:getDesc().category == Weapon.Category.ROCKET then
|
||||||
|
table["category"] = "Missile"
|
||||||
|
elseif weapon:getDesc().category == Weapon.Category.BOMB then
|
||||||
|
table["category"] = "Bomb"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
weapons[ID] = {isAlive = false}
|
||||||
|
Olympus.weapons[ID] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
-- If the category is handled by Olympus, get the data
|
||||||
|
if table["category"] ~= nil then
|
||||||
|
-- Compute weapon position and heading
|
||||||
|
local lat, lng, alt = coord.LOtoLL(weapon:getPoint())
|
||||||
|
local position = weapon:getPosition()
|
||||||
|
local heading = math.atan2( position.x.z, position.x.x )
|
||||||
|
|
||||||
|
-- Fill the data table
|
||||||
|
table["name"] = weapon:getTypeName()
|
||||||
|
table["coalitionID"] = weapon:getCoalition()
|
||||||
|
table["position"] = {}
|
||||||
|
table["position"]["lat"] = lat
|
||||||
|
table["position"]["lng"] = lng
|
||||||
|
table["position"]["alt"] = alt
|
||||||
|
table["speed"] = mist.vec.mag(weapon:getVelocity())
|
||||||
|
table["heading"] = heading
|
||||||
|
table["isAlive"] = weapon:isExist()
|
||||||
|
|
||||||
|
weapons[ID] = table
|
||||||
|
end
|
||||||
|
else
|
||||||
|
weapons[ID] = {isAlive = false}
|
||||||
|
Olympus.weapons[ID] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if index >= endIndex then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if index ~= endIndex then
|
||||||
|
Olympus.weaponIndex = 0
|
||||||
|
else
|
||||||
|
Olympus.weaponIndex = endIndex
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Assemble weaponsData table
|
||||||
|
Olympus.weaponsData["weapons"] = weapons
|
||||||
|
|
||||||
|
Olympus.OlympusDLL.setWeaponsData()
|
||||||
|
return time + 0.25
|
||||||
|
end
|
||||||
|
|
||||||
|
function Olympus.setMissionData(arg, time)
|
||||||
|
-- Bullseye data
|
||||||
|
local bullseyes = {}
|
||||||
|
for i = 0, 2 do
|
||||||
|
local bullseyeVec3 = coalition.getMainRefPoint(i)
|
||||||
|
local bullseyeLatitude, bullseyeLongitude, bullseyeAltitude = coord.LOtoLL(bullseyeVec3)
|
||||||
|
bullseyes[i] = {}
|
||||||
|
bullseyes[i]["latitude"] = bullseyeLatitude
|
||||||
|
bullseyes[i]["longitude"] = bullseyeLongitude
|
||||||
|
bullseyes[i]["coalition"] = Olympus.getCoalitionByCoalitionID(i)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Airbases data
|
||||||
|
local base = world.getAirbases()
|
||||||
|
local airbases = {}
|
||||||
|
for i = 1, #base do
|
||||||
|
local info = {}
|
||||||
|
local latitude, longitude, altitude = coord.LOtoLL(Airbase.getPoint(base[i]))
|
||||||
|
info["callsign"] = Airbase.getCallsign(base[i])
|
||||||
|
info["coalition"] = Olympus.getCoalitionByCoalitionID(Airbase.getCoalition(base[i]))
|
||||||
|
info["latitude"] = latitude
|
||||||
|
info["longitude"] = longitude
|
||||||
|
if Airbase.getUnit(base[i]) then
|
||||||
|
info["unitId"] = Airbase.getUnit(base[i]):getID()
|
||||||
|
end
|
||||||
|
airbases[i] = info
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Mission
|
||||||
|
local mission = {}
|
||||||
|
mission.theatre = env.mission.theatre
|
||||||
|
mission.dateAndTime = {
|
||||||
|
["elapsedTime"] = DCS.getRealTime() - Olympus.missionStartTime,
|
||||||
|
["time"] = mist.time.getDHMS(timer.getAbsTime()),
|
||||||
|
["startTime"] = env.mission.start_time,
|
||||||
|
["date"] = env.mission.date
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Assemble table
|
||||||
|
Olympus.missionData["bullseyes"] = bullseyes
|
||||||
|
Olympus.missionData["airbases"] = airbases
|
||||||
|
Olympus.missionData["mission"] = mission
|
||||||
|
|
||||||
|
Olympus.OlympusDLL.setMissionData()
|
||||||
|
return time + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function Olympus.initializeUnits()
|
||||||
|
if mist and mist.DBs and mist.DBs.MEunitsById then
|
||||||
|
for id, unitTable in pairs(mist.DBs.MEunitsById) do
|
||||||
|
local unit = Unit.getByName(unitTable["unitName"])
|
||||||
|
if unit then
|
||||||
|
Olympus.units[unit["id_"]] = unit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Olympus.notify("Olympus units table initialized", 2)
|
||||||
|
else
|
||||||
|
Olympus.debug("MIST DBs not ready", 2)
|
||||||
|
timer.scheduleFunction(Olympus.initializeUnits, {}, timer.getTime() + 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function Olympus.serializeTable(val, name, skipnewlines, depth)
|
function Olympus.serializeTable(val, name, skipnewlines, depth)
|
||||||
skipnewlines = skipnewlines or false
|
skipnewlines = skipnewlines or false
|
||||||
depth = depth or 0
|
depth = depth or 0
|
||||||
@@ -712,171 +959,10 @@ function Olympus.hasKey(tab, key)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
function Olympus.setUnitsData(arg, time)
|
------------------------------------------------------------------------------------------------------
|
||||||
-- Units data
|
-- Olympus startup script
|
||||||
local units = {}
|
------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
local startIndex = Olympus.groupIndex
|
|
||||||
local endIndex = startIndex + Olympus.groupStep
|
|
||||||
local index = 0
|
|
||||||
if mist ~= nil and mist.DBs ~= nil and mist.DBs.groupsByName ~= nil then
|
|
||||||
for groupName, gp in pairs(mist.DBs.groupsByName) do
|
|
||||||
index = index + 1
|
|
||||||
if index > startIndex then
|
|
||||||
if groupName ~= nil then
|
|
||||||
local group = Group.getByName(groupName)
|
|
||||||
if group ~= nil then
|
|
||||||
-- Get the targets detected by the group controller
|
|
||||||
local controller = group:getController()
|
|
||||||
local controllerTargets = controller:getDetectedTargets()
|
|
||||||
local contacts = {}
|
|
||||||
for i, target in ipairs(controllerTargets) do
|
|
||||||
for det, enum in pairs(Controller.Detection) do
|
|
||||||
if target.object ~= nil then
|
|
||||||
target["detectionMethod"] = det
|
|
||||||
contacts[#contacts + 1] = target
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Update the units position
|
|
||||||
for index, unit in pairs(group:getUnits()) do
|
|
||||||
local unitController = unit:getController()
|
|
||||||
local table = {}
|
|
||||||
table["category"] = "None"
|
|
||||||
|
|
||||||
-- Get the object category in Olympus name
|
|
||||||
local objectCategory = unit:getCategory()
|
|
||||||
if objectCategory == Object.Category.UNIT then
|
|
||||||
if unit:getDesc().category == Unit.Category.AIRPLANE then
|
|
||||||
table["category"] = "Aircraft"
|
|
||||||
elseif unit:getDesc().category == Unit.Category.HELICOPTER then
|
|
||||||
table["category"] = "Helicopter"
|
|
||||||
elseif unit:getDesc().category == Unit.Category.GROUND_UNIT then
|
|
||||||
table["category"] = "GroundUnit"
|
|
||||||
elseif unit:getDesc().category == Unit.Category.SHIP then
|
|
||||||
table["category"] = "NavyUnit"
|
|
||||||
end
|
|
||||||
elseif objectCategory == Object.Category.WEAPON then
|
|
||||||
if unit:getDesc().category == Weapon.Category.MISSILE then
|
|
||||||
table["category"] = "Missile"
|
|
||||||
elseif unit:getDesc().category == Weapon.Category.ROCKET then
|
|
||||||
table["category"] = "Missile"
|
|
||||||
elseif unit:getDesc().category == Unit.Category.BOMB then
|
|
||||||
table["category"] = "Bomb"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- If the category is handled by Olympus, get the data
|
|
||||||
if table["category"] ~= "None" then
|
|
||||||
-- Compute unit position and heading
|
|
||||||
local lat, lng, alt = coord.LOtoLL(unit:getPoint())
|
|
||||||
local position = unit:getPosition()
|
|
||||||
local heading = math.atan2( position.x.z, position.x.x )
|
|
||||||
|
|
||||||
-- Fill the data table
|
|
||||||
table["name"] = unit:getTypeName()
|
|
||||||
table["unitName"] = unit:getName()
|
|
||||||
table["groupName"] = group:getName()
|
|
||||||
table["isHuman"] = (unit:getPlayerName() ~= nil)
|
|
||||||
table["coalitionID"] = unit:getCoalition()
|
|
||||||
table["hasTask"] = controller:hasTask()
|
|
||||||
table["ammo"] = unit:getAmmo() --TODO remove a lot of stuff we don't really need
|
|
||||||
table["fuel"] = unit:getFuel()
|
|
||||||
table["life"] = unit:getLife() / unit:getLife0()
|
|
||||||
table["contacts"] = contacts
|
|
||||||
table["position"] = {}
|
|
||||||
table["position"]["lat"] = lat
|
|
||||||
table["position"]["lng"] = lng
|
|
||||||
table["position"]["alt"] = alt
|
|
||||||
table["speed"] = mist.vec.mag(unit:getVelocity())
|
|
||||||
table["heading"] = heading
|
|
||||||
table["country"] = unit:getCountry()
|
|
||||||
table["isAlive"] = (unit:getLife() > 1) and unit:isExist()
|
|
||||||
|
|
||||||
units[unit:getObjectID()] = table
|
|
||||||
Olympus.unitNames[unit:getObjectID()] = unit:getName() -- Used to find what units are dead, since they will not be in mist.DBs.groupsByName
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if index >= endIndex then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if index ~= endIndex then
|
|
||||||
Olympus.groupIndex = 0
|
|
||||||
else
|
|
||||||
Olympus.groupIndex = endIndex
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- All the units that can't be retrieved by getByName are dead
|
|
||||||
for ID, name in pairs(Olympus.unitNames) do
|
|
||||||
local unit = Unit.getByName(name)
|
|
||||||
if unit == nil then
|
|
||||||
units[ID] = {isAlive = false}
|
|
||||||
Olympus.unitNames[ID] = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Assemble unitsData table
|
|
||||||
Olympus.unitsData["units"] = units
|
|
||||||
|
|
||||||
Olympus.OlympusDLL.setUnitsData()
|
|
||||||
return time + 0.05
|
|
||||||
end
|
|
||||||
|
|
||||||
function Olympus.setMissionData(arg, time)
|
|
||||||
-- Bullseye data
|
|
||||||
local bullseyes = {}
|
|
||||||
for i = 0, 2 do
|
|
||||||
local bullseyeVec3 = coalition.getMainRefPoint(i)
|
|
||||||
local bullseyeLatitude, bullseyeLongitude, bullseyeAltitude = coord.LOtoLL(bullseyeVec3)
|
|
||||||
bullseyes[i] = {}
|
|
||||||
bullseyes[i]["latitude"] = bullseyeLatitude
|
|
||||||
bullseyes[i]["longitude"] = bullseyeLongitude
|
|
||||||
bullseyes[i]["coalition"] = Olympus.getCoalitionByCoalitionID(i)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Airbases data
|
|
||||||
local base = world.getAirbases()
|
|
||||||
local airbases = {}
|
|
||||||
for i = 1, #base do
|
|
||||||
local info = {}
|
|
||||||
local latitude, longitude, altitude = coord.LOtoLL(Airbase.getPoint(base[i]))
|
|
||||||
info["callsign"] = Airbase.getCallsign(base[i])
|
|
||||||
info["coalition"] = Olympus.getCoalitionByCoalitionID(Airbase.getCoalition(base[i]))
|
|
||||||
info["latitude"] = latitude
|
|
||||||
info["longitude"] = longitude
|
|
||||||
if Airbase.getUnit(base[i]) then
|
|
||||||
info["unitId"] = Airbase.getUnit(base[i]):getID()
|
|
||||||
end
|
|
||||||
airbases[i] = info
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Mission
|
|
||||||
local mission = {}
|
|
||||||
mission.theatre = env.mission.theatre
|
|
||||||
mission.dateAndTime = {
|
|
||||||
["elapsedTime"] = DCS.getRealTime() - Olympus.missionStartTime,
|
|
||||||
["time"] = mist.time.getDHMS(timer.getAbsTime()),
|
|
||||||
["startTime"] = env.mission.start_time,
|
|
||||||
["date"] = env.mission.date
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Assemble table
|
|
||||||
Olympus.missionData["bullseyes"] = bullseyes
|
|
||||||
Olympus.missionData["airbases"] = airbases
|
|
||||||
Olympus.missionData["mission"] = mission
|
|
||||||
|
|
||||||
Olympus.OlympusDLL.setMissionData()
|
|
||||||
return time + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
local OlympusName = 'Olympus ' .. version .. ' C++ module';
|
local OlympusName = 'Olympus ' .. version .. ' C++ module';
|
||||||
isOlympusModuleInitialized=true;
|
|
||||||
Olympus.DLLsloaded = Olympus.loadDLLs()
|
Olympus.DLLsloaded = Olympus.loadDLLs()
|
||||||
if Olympus.DLLsloaded then
|
if Olympus.DLLsloaded then
|
||||||
Olympus.notify(OlympusName..' successfully loaded.', 20)
|
Olympus.notify(OlympusName..' successfully loaded.', 20)
|
||||||
@@ -884,7 +970,36 @@ else
|
|||||||
Olympus.notify('Failed to load '..OlympusName, 20)
|
Olympus.notify('Failed to load '..OlympusName, 20)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Create the handler to detect new units
|
||||||
|
if handler ~= nil then
|
||||||
|
world.removeEventHandler(handler)
|
||||||
|
Olympus.debug("Olympus handler removed" , 2)
|
||||||
|
end
|
||||||
|
handler = {}
|
||||||
|
function handler:onEvent(event)
|
||||||
|
if event.id == 1 then
|
||||||
|
local weapon = event.weapon
|
||||||
|
if Olympus ~= nil and Olympus.weapons ~= nil then
|
||||||
|
Olympus.weapons[weapon["id_"]] = weapon
|
||||||
|
Olympus.debug("New weapon created " .. weapon["id_"], 2)
|
||||||
|
end
|
||||||
|
elseif event.id == 15 then
|
||||||
|
local unit = event.initiator
|
||||||
|
if Olympus ~= nil and Olympus.units ~= nil then
|
||||||
|
Olympus.units[unit["id_"]] = unit
|
||||||
|
Olympus.debug("New unit created " .. unit["id_"], 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
world.addEventHandler(handler)
|
||||||
|
|
||||||
|
-- Start the periodic functions
|
||||||
timer.scheduleFunction(Olympus.setUnitsData, {}, timer.getTime() + 0.05)
|
timer.scheduleFunction(Olympus.setUnitsData, {}, timer.getTime() + 0.05)
|
||||||
|
timer.scheduleFunction(Olympus.setWeaponsData, {}, timer.getTime() + 0.25)
|
||||||
timer.scheduleFunction(Olympus.setMissionData, {}, timer.getTime() + 1)
|
timer.scheduleFunction(Olympus.setMissionData, {}, timer.getTime() + 1)
|
||||||
|
|
||||||
|
-- Initialize the ME units
|
||||||
|
Olympus.initializeUnits()
|
||||||
|
|
||||||
Olympus.notify("OlympusCommand script " .. version .. " loaded successfully", 2, true)
|
Olympus.notify("OlympusCommand script " .. version .. " loaded successfully", 2, true)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
local version = 'v0.4.0-alpha'
|
local version = 'v0.4.1-alpha'
|
||||||
|
|
||||||
Olympus = {}
|
Olympus = {}
|
||||||
Olympus.OlympusDLL = nil
|
Olympus.OlympusDLL = nil
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
<ClInclude Include="include\unit.h" />
|
<ClInclude Include="include\unit.h" />
|
||||||
<ClInclude Include="include\unitsmanager.h" />
|
<ClInclude Include="include\unitsmanager.h" />
|
||||||
<ClInclude Include="include\weapon.h" />
|
<ClInclude Include="include\weapon.h" />
|
||||||
|
<ClInclude Include="include\weaponsmanager.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="src\aircraft.cpp" />
|
<ClCompile Include="src\aircraft.cpp" />
|
||||||
@@ -64,6 +65,7 @@
|
|||||||
<ClCompile Include="src\unit.cpp" />
|
<ClCompile Include="src\unit.cpp" />
|
||||||
<ClCompile Include="src\unitsmanager.cpp" />
|
<ClCompile Include="src\unitsmanager.cpp" />
|
||||||
<ClCompile Include="src\weapon.cpp" />
|
<ClCompile Include="src\weapon.cpp" />
|
||||||
|
<ClCompile Include="src\weaponsmanager.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<VCProjectVersion>16.0</VCProjectVersion>
|
<VCProjectVersion>16.0</VCProjectVersion>
|
||||||
|
|||||||
@@ -51,6 +51,9 @@
|
|||||||
<ClInclude Include="include\datatypes.h">
|
<ClInclude Include="include\datatypes.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\weaponsmanager.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="src\aircraft.cpp">
|
<ClCompile Include="src\aircraft.cpp">
|
||||||
@@ -98,5 +101,8 @@
|
|||||||
<ClCompile Include="src\datatypes.cpp">
|
<ClCompile Include="src\datatypes.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\weaponsmanager.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,6 +1,73 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "framework.h"
|
#include "framework.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace DataIndex {
|
||||||
|
enum DataIndexes {
|
||||||
|
startOfData = 0,
|
||||||
|
category,
|
||||||
|
alive,
|
||||||
|
human,
|
||||||
|
controlled,
|
||||||
|
coalition,
|
||||||
|
country,
|
||||||
|
name,
|
||||||
|
unitName,
|
||||||
|
groupName,
|
||||||
|
state,
|
||||||
|
task,
|
||||||
|
hasTask,
|
||||||
|
position,
|
||||||
|
speed,
|
||||||
|
heading,
|
||||||
|
isTanker,
|
||||||
|
isAWACS,
|
||||||
|
onOff,
|
||||||
|
followRoads,
|
||||||
|
fuel,
|
||||||
|
desiredSpeed,
|
||||||
|
desiredSpeedType,
|
||||||
|
desiredAltitude,
|
||||||
|
desiredAltitudeType,
|
||||||
|
leaderID,
|
||||||
|
formationOffset,
|
||||||
|
targetID,
|
||||||
|
targetPosition,
|
||||||
|
ROE,
|
||||||
|
reactionToThreat,
|
||||||
|
emissionsCountermeasures,
|
||||||
|
TACAN,
|
||||||
|
radio,
|
||||||
|
generalSettings,
|
||||||
|
ammo,
|
||||||
|
contacts,
|
||||||
|
activePath,
|
||||||
|
isLeader,
|
||||||
|
lastIndex,
|
||||||
|
endOfData = 255
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace State
|
||||||
|
{
|
||||||
|
enum States
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
IDLE,
|
||||||
|
REACH_DESTINATION,
|
||||||
|
ATTACK,
|
||||||
|
FOLLOW,
|
||||||
|
LAND,
|
||||||
|
REFUEL,
|
||||||
|
AWACS,
|
||||||
|
TANKER,
|
||||||
|
BOMB_POINT,
|
||||||
|
CARPET_BOMB,
|
||||||
|
BOMB_BUILDING,
|
||||||
|
FIRE_AT_AREA
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
namespace DataTypes {
|
namespace DataTypes {
|
||||||
struct TACAN
|
struct TACAN
|
||||||
|
|||||||
@@ -1,12 +1,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "unit.h"
|
#include "unit.h"
|
||||||
|
|
||||||
|
#define NAVY_DEST_DIST_THR 100
|
||||||
|
|
||||||
class NavyUnit : public Unit
|
class NavyUnit : public Unit
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NavyUnit(json::value json, unsigned int ID);
|
NavyUnit(json::value json, unsigned int ID);
|
||||||
virtual void AIloop();
|
|
||||||
|
virtual void setState(unsigned char newState);
|
||||||
|
virtual void setDefaults(bool force = false);
|
||||||
|
|
||||||
virtual void changeSpeed(string change);
|
virtual void changeSpeed(string change);
|
||||||
|
virtual void setOnOff(bool newOnOff, bool force = false);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void AIloop();
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -13,72 +13,6 @@ using namespace std::chrono;
|
|||||||
|
|
||||||
#define TASK_CHECK_INIT_VALUE 10
|
#define TASK_CHECK_INIT_VALUE 10
|
||||||
|
|
||||||
namespace DataIndex {
|
|
||||||
enum DataIndexes {
|
|
||||||
startOfData = 0,
|
|
||||||
category,
|
|
||||||
alive,
|
|
||||||
human,
|
|
||||||
controlled,
|
|
||||||
coalition,
|
|
||||||
country,
|
|
||||||
name,
|
|
||||||
unitName,
|
|
||||||
groupName,
|
|
||||||
state,
|
|
||||||
task,
|
|
||||||
hasTask,
|
|
||||||
position,
|
|
||||||
speed,
|
|
||||||
heading,
|
|
||||||
isTanker,
|
|
||||||
isAWACS,
|
|
||||||
onOff,
|
|
||||||
followRoads,
|
|
||||||
fuel,
|
|
||||||
desiredSpeed,
|
|
||||||
desiredSpeedType,
|
|
||||||
desiredAltitude,
|
|
||||||
desiredAltitudeType,
|
|
||||||
leaderID,
|
|
||||||
formationOffset,
|
|
||||||
targetID,
|
|
||||||
targetPosition,
|
|
||||||
ROE,
|
|
||||||
reactionToThreat,
|
|
||||||
emissionsCountermeasures,
|
|
||||||
TACAN,
|
|
||||||
radio,
|
|
||||||
generalSettings,
|
|
||||||
ammo,
|
|
||||||
contacts,
|
|
||||||
activePath,
|
|
||||||
isLeader,
|
|
||||||
lastIndex,
|
|
||||||
endOfData = 255
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace State
|
|
||||||
{
|
|
||||||
enum States
|
|
||||||
{
|
|
||||||
NONE = 0,
|
|
||||||
IDLE,
|
|
||||||
REACH_DESTINATION,
|
|
||||||
ATTACK,
|
|
||||||
FOLLOW,
|
|
||||||
LAND,
|
|
||||||
REFUEL,
|
|
||||||
AWACS,
|
|
||||||
TANKER,
|
|
||||||
BOMB_POINT,
|
|
||||||
CARPET_BOMB,
|
|
||||||
BOMB_BUILDING,
|
|
||||||
FIRE_AT_AREA
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
class Unit
|
class Unit
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -1,13 +1,107 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "unit.h"
|
#include "framework.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "dcstools.h"
|
||||||
|
#include "luatools.h"
|
||||||
|
#include "measure.h"
|
||||||
|
#include "logger.h"
|
||||||
|
#include "commands.h"
|
||||||
|
#include "datatypes.h"
|
||||||
|
|
||||||
class Weapon : public Unit
|
#include <chrono>
|
||||||
|
using namespace std::chrono;
|
||||||
|
|
||||||
|
class Weapon
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Weapon(json::value json, unsigned int ID);
|
Weapon(json::value json, unsigned int ID);
|
||||||
|
~Weapon();
|
||||||
|
|
||||||
|
/********** Methods **********/
|
||||||
|
void initialize(json::value json);
|
||||||
|
void update(json::value json, double dt);
|
||||||
|
unsigned int getID() { return ID; }
|
||||||
|
void getData(stringstream& ss, unsigned long long time);
|
||||||
|
void triggerUpdate(unsigned char datumIndex);
|
||||||
|
bool hasFreshData(unsigned long long time);
|
||||||
|
bool checkFreshness(unsigned char datumIndex, unsigned long long time);
|
||||||
|
|
||||||
|
/********** Setters **********/
|
||||||
|
virtual void setCategory(string newValue) { updateValue(category, newValue, DataIndex::category); }
|
||||||
|
virtual void setAlive(bool newValue) { updateValue(alive, newValue, DataIndex::alive); }
|
||||||
|
virtual void setCoalition(unsigned char newValue) { updateValue(coalition, newValue, DataIndex::coalition); }
|
||||||
|
virtual void setName(string newValue) { updateValue(name, newValue, DataIndex::name); }
|
||||||
|
virtual void setPosition(Coords newValue) { updateValue(position, newValue, DataIndex::position); }
|
||||||
|
virtual void setSpeed(double newValue) { updateValue(speed, newValue, DataIndex::speed); }
|
||||||
|
virtual void setHeading(double newValue) { updateValue(heading, newValue, DataIndex::heading); }
|
||||||
|
|
||||||
|
/********** Getters **********/
|
||||||
|
virtual string getCategory() { return category; };
|
||||||
|
virtual bool getAlive() { return alive; }
|
||||||
|
virtual unsigned char getCoalition() { return coalition; }
|
||||||
|
virtual string getName() { return name; }
|
||||||
|
virtual Coords getPosition() { return position; }
|
||||||
|
virtual double getSpeed() { return speed; }
|
||||||
|
virtual double getHeading() { return heading; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* Weapons are not controllable and have no AIloop */
|
unsigned int ID;
|
||||||
virtual void AIloop() {};
|
|
||||||
|
string category;
|
||||||
|
bool alive = false;
|
||||||
|
unsigned char coalition = NULL;
|
||||||
|
string name = "";
|
||||||
|
Coords position = Coords(NULL);
|
||||||
|
double speed = NULL;
|
||||||
|
double heading = NULL;
|
||||||
|
|
||||||
|
/********** Other **********/
|
||||||
|
map<unsigned char, unsigned long long> updateTimeMap;
|
||||||
|
|
||||||
|
/********** Private methods **********/
|
||||||
|
void appendString(stringstream& ss, const unsigned char& datumIndex, const string& datumValue) {
|
||||||
|
const unsigned short size = datumValue.size();
|
||||||
|
ss.write((const char*)&datumIndex, sizeof(unsigned char));
|
||||||
|
ss.write((const char*)&size, sizeof(unsigned short));
|
||||||
|
ss << datumValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********** Template methods **********/
|
||||||
|
template <typename T>
|
||||||
|
void updateValue(T& value, T& newValue, unsigned char datumIndex)
|
||||||
|
{
|
||||||
|
if (newValue != value)
|
||||||
|
{
|
||||||
|
triggerUpdate(datumIndex);
|
||||||
|
value = newValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void appendNumeric(stringstream& ss, const unsigned char& datumIndex, T& datumValue) {
|
||||||
|
ss.write((const char*)&datumIndex, sizeof(unsigned char));
|
||||||
|
ss.write((const char*)&datumValue, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void appendVector(stringstream& ss, const unsigned char& datumIndex, vector<T>& datumValue) {
|
||||||
|
const unsigned short size = datumValue.size();
|
||||||
|
ss.write((const char*)&datumIndex, sizeof(unsigned char));
|
||||||
|
ss.write((const char*)&size, sizeof(unsigned short));
|
||||||
|
|
||||||
|
for (auto& el : datumValue)
|
||||||
|
ss.write((const char*)&el, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void appendList(stringstream& ss, const unsigned char& datumIndex, list<T>& datumValue) {
|
||||||
|
const unsigned short size = datumValue.size();
|
||||||
|
ss.write((const char*)&datumIndex, sizeof(unsigned char));
|
||||||
|
ss.write((const char*)&size, sizeof(unsigned short));
|
||||||
|
|
||||||
|
for (auto& el : datumValue)
|
||||||
|
ss.write((const char*)&el, sizeof(T));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Missile : public Weapon
|
class Missile : public Weapon
|
||||||
|
|||||||
21
src/core/include/weaponsmanager.h
Normal file
21
src/core/include/weaponsmanager.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "framework.h"
|
||||||
|
#include "dcstools.h"
|
||||||
|
|
||||||
|
class Weapon;
|
||||||
|
|
||||||
|
class WeaponsManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WeaponsManager(lua_State* L);
|
||||||
|
~WeaponsManager();
|
||||||
|
|
||||||
|
map<unsigned int, Weapon*>& getWeapons() { return weapons; };
|
||||||
|
Weapon* getWeapon(unsigned int ID);
|
||||||
|
void update(json::value& missionData, double dt);
|
||||||
|
void getWeaponData(stringstream& ss, unsigned long long time);
|
||||||
|
|
||||||
|
private:
|
||||||
|
map<unsigned int, Weapon*> weapons;
|
||||||
|
};
|
||||||
|
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include "unitsManager.h"
|
#include "unitsManager.h"
|
||||||
|
#include "weaponsManager.h"
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "scriptLoader.h"
|
#include "scriptLoader.h"
|
||||||
@@ -9,11 +10,13 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
|
||||||
auto lastUpdate = std::chrono::system_clock::now();
|
auto lastUnitsUpdate = std::chrono::system_clock::now();
|
||||||
|
auto lastWeaponsUpdate = std::chrono::system_clock::now();
|
||||||
auto lastExecution = std::chrono::system_clock::now();
|
auto lastExecution = std::chrono::system_clock::now();
|
||||||
|
|
||||||
/* Singleton objects */
|
/* Singleton objects */
|
||||||
UnitsManager* unitsManager = nullptr;
|
UnitsManager* unitsManager = nullptr;
|
||||||
|
WeaponsManager* weaponsManager = nullptr;
|
||||||
Server* server = nullptr;
|
Server* server = nullptr;
|
||||||
Scheduler* scheduler = nullptr;
|
Scheduler* scheduler = nullptr;
|
||||||
|
|
||||||
@@ -38,6 +41,7 @@ extern "C" DllExport int coreDeinit(lua_State* L)
|
|||||||
server->stop(L);
|
server->stop(L);
|
||||||
|
|
||||||
delete unitsManager;
|
delete unitsManager;
|
||||||
|
delete weaponsManager;
|
||||||
delete server;
|
delete server;
|
||||||
delete scheduler;
|
delete scheduler;
|
||||||
|
|
||||||
@@ -51,6 +55,7 @@ extern "C" DllExport int coreInit(lua_State* L)
|
|||||||
{
|
{
|
||||||
sessionHash = random_string(16);
|
sessionHash = random_string(16);
|
||||||
unitsManager = new UnitsManager(L);
|
unitsManager = new UnitsManager(L);
|
||||||
|
weaponsManager = new WeaponsManager(L);
|
||||||
server = new Server(L);
|
server = new Server(L);
|
||||||
scheduler = new Scheduler(L);
|
scheduler = new Scheduler(L);
|
||||||
|
|
||||||
@@ -101,15 +106,36 @@ extern "C" DllExport int coreUnitsData(lua_State * L)
|
|||||||
lua_getfield(L, -1, "unitsData");
|
lua_getfield(L, -1, "unitsData");
|
||||||
luaTableToJSON(L, -1, unitsData);
|
luaTableToJSON(L, -1, unitsData);
|
||||||
|
|
||||||
const std::chrono::duration<double> updateDuration = std::chrono::system_clock::now() - lastUpdate;
|
const std::chrono::duration<double> updateDuration = std::chrono::system_clock::now() - lastUnitsUpdate;
|
||||||
if (unitsData.has_object_field(L"units")) {
|
if (unitsData.has_object_field(L"units")) {
|
||||||
unitsManager->update(unitsData[L"units"], updateDuration.count());
|
unitsManager->update(unitsData[L"units"], updateDuration.count());
|
||||||
}
|
}
|
||||||
lastUpdate = std::chrono::system_clock::now();
|
lastUnitsUpdate = std::chrono::system_clock::now();
|
||||||
|
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C" DllExport int coreWeaponsData(lua_State * L)
|
||||||
|
{
|
||||||
|
if (!initialized)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
/* Lock for thread safety */
|
||||||
|
lock_guard<mutex> guard(mutexLock);
|
||||||
|
|
||||||
|
json::value weaponsData = json::value::object();
|
||||||
|
lua_getglobal(L, "Olympus");
|
||||||
|
lua_getfield(L, -1, "weaponsData");
|
||||||
|
luaTableToJSON(L, -1, weaponsData);
|
||||||
|
|
||||||
|
const std::chrono::duration<double> updateDuration = std::chrono::system_clock::now() - lastWeaponsUpdate;
|
||||||
|
if (weaponsData.has_object_field(L"weapons")) {
|
||||||
|
weaponsManager->update(weaponsData[L"weapons"], updateDuration.count());
|
||||||
|
}
|
||||||
|
lastWeaponsUpdate = std::chrono::system_clock::now();
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" DllExport int coreMissionData(lua_State * L)
|
extern "C" DllExport int coreMissionData(lua_State * L)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -21,23 +21,132 @@ NavyUnit::NavyUnit(json::value json, unsigned int ID) : Unit(json, ID)
|
|||||||
setDesiredSpeed(10);
|
setDesiredSpeed(10);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void NavyUnit::setDefaults(bool force)
|
||||||
|
{
|
||||||
|
if (!getAlive() || !getControlled() || getHuman() || !getIsLeader()) return;
|
||||||
|
|
||||||
|
/* Set the default IDLE state */
|
||||||
|
setState(State::IDLE);
|
||||||
|
|
||||||
|
/* Set the default options */
|
||||||
|
setROE(ROE::OPEN_FIRE_WEAPON_FREE, force);
|
||||||
|
setOnOff(onOff, force);
|
||||||
|
setFollowRoads(followRoads, force);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavyUnit::setState(unsigned char newState)
|
||||||
|
{
|
||||||
|
/************ Perform any action required when LEAVING a state ************/
|
||||||
|
if (newState != state) {
|
||||||
|
switch (state) {
|
||||||
|
case State::IDLE: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case State::REACH_DESTINATION: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case State::FIRE_AT_AREA: {
|
||||||
|
setTargetPosition(Coords(NULL));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/************ Perform any action required when ENTERING a state ************/
|
||||||
|
switch (newState) {
|
||||||
|
case State::IDLE: {
|
||||||
|
clearActivePath();
|
||||||
|
resetActiveDestination();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case State::REACH_DESTINATION: {
|
||||||
|
resetActiveDestination();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case State::FIRE_AT_AREA: {
|
||||||
|
clearActivePath();
|
||||||
|
resetActiveDestination();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newState != state)
|
||||||
|
resetTask();
|
||||||
|
|
||||||
|
log(unitName + " setting state from " + to_string(state) + " to " + to_string(newState));
|
||||||
|
state = newState;
|
||||||
|
|
||||||
|
triggerUpdate(DataIndex::state);
|
||||||
|
}
|
||||||
|
|
||||||
void NavyUnit::AIloop()
|
void NavyUnit::AIloop()
|
||||||
{
|
{
|
||||||
/* TODO */
|
switch (state) {
|
||||||
|
case State::IDLE: {
|
||||||
|
setTask("Idle");
|
||||||
|
if (getHasTask())
|
||||||
|
resetTask();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case State::REACH_DESTINATION: {
|
||||||
|
string enrouteTask = "{}";
|
||||||
|
bool looping = false;
|
||||||
|
|
||||||
|
if (activeDestination == NULL || !getHasTask())
|
||||||
|
{
|
||||||
|
if (!setActiveDestination())
|
||||||
|
setState(State::IDLE);
|
||||||
|
else
|
||||||
|
goToDestination(enrouteTask);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (isDestinationReached(NAVY_DEST_DIST_THR)) {
|
||||||
|
if (updateActivePath(looping) && setActiveDestination())
|
||||||
|
goToDestination(enrouteTask);
|
||||||
|
else
|
||||||
|
setState(State::IDLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case State::FIRE_AT_AREA: {
|
||||||
|
setTask("Firing at area");
|
||||||
|
|
||||||
|
if (!getHasTask()) {
|
||||||
|
std::ostringstream taskSS;
|
||||||
|
taskSS << "{id = 'FireAtPoint', lat = " << targetPosition.lat << ", lng = " << targetPosition.lng << ", radius = 1000}";
|
||||||
|
Command* command = dynamic_cast<Command*>(new SetTask(groupName, taskSS.str()));
|
||||||
|
scheduler->appendCommand(command);
|
||||||
|
setHasTask(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavyUnit::changeSpeed(string change)
|
void NavyUnit::changeSpeed(string change)
|
||||||
{
|
{
|
||||||
if (change.compare("stop") == 0)
|
if (change.compare("stop") == 0)
|
||||||
{
|
setState(State::IDLE);
|
||||||
|
|
||||||
}
|
|
||||||
else if (change.compare("slow") == 0)
|
else if (change.compare("slow") == 0)
|
||||||
{
|
setDesiredSpeed(getDesiredSpeed() - knotsToMs(5));
|
||||||
|
|
||||||
}
|
|
||||||
else if (change.compare("fast") == 0)
|
else if (change.compare("fast") == 0)
|
||||||
{
|
setDesiredSpeed(getDesiredSpeed() + knotsToMs(5));
|
||||||
|
|
||||||
|
if (getDesiredSpeed() < 0)
|
||||||
|
setDesiredSpeed(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavyUnit::setOnOff(bool newOnOff, bool force)
|
||||||
|
{
|
||||||
|
if (newOnOff != onOff || force) {
|
||||||
|
Unit::setOnOff(newOnOff, force);
|
||||||
|
Command* command = dynamic_cast<Command*>(new SetOnOff(groupName, onOff));
|
||||||
|
scheduler->appendCommand(command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include "unitsManager.h"
|
#include "unitsManager.h"
|
||||||
|
#include "weaponsManager.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "luatools.h"
|
#include "luatools.h"
|
||||||
#include <exception>
|
#include <exception>
|
||||||
@@ -13,6 +14,7 @@ using namespace std::chrono;
|
|||||||
using namespace base64;
|
using namespace base64;
|
||||||
|
|
||||||
extern UnitsManager* unitsManager;
|
extern UnitsManager* unitsManager;
|
||||||
|
extern WeaponsManager* weaponsManager;
|
||||||
extern Scheduler* scheduler;
|
extern Scheduler* scheduler;
|
||||||
extern json::value missionData;
|
extern json::value missionData;
|
||||||
extern mutex mutexLock;
|
extern mutex mutexLock;
|
||||||
@@ -94,7 +96,7 @@ void Server::handle_get(http_request request)
|
|||||||
if (path.size() > 0)
|
if (path.size() > 0)
|
||||||
{
|
{
|
||||||
string URI = to_string(path[0]);
|
string URI = to_string(path[0]);
|
||||||
/* Units data. This is the only binary format data transmitted, all others are transmitted as text json for simplicity */
|
/* Units data */
|
||||||
if (URI.compare(UNITS_URI) == 0)
|
if (URI.compare(UNITS_URI) == 0)
|
||||||
{
|
{
|
||||||
unsigned long long updateTime = ms.count();
|
unsigned long long updateTime = ms.count();
|
||||||
@@ -103,8 +105,16 @@ void Server::handle_get(http_request request)
|
|||||||
unitsManager->getUnitData(ss, time);
|
unitsManager->getUnitData(ss, time);
|
||||||
response.set_body(concurrency::streams::bytestream::open_istream(ss.str()));
|
response.set_body(concurrency::streams::bytestream::open_istream(ss.str()));
|
||||||
}
|
}
|
||||||
|
else if (URI.compare(WEAPONS_URI) == 0)
|
||||||
|
{
|
||||||
|
unsigned long long updateTime = ms.count();
|
||||||
|
stringstream ss;
|
||||||
|
ss.write((char*)&updateTime, sizeof(updateTime));
|
||||||
|
weaponsManager->getWeaponData(ss, time);
|
||||||
|
response.set_body(concurrency::streams::bytestream::open_istream(ss.str()));
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
/* Logs data*/
|
/* Logs data */
|
||||||
if (URI.compare(LOGS_URI) == 0)
|
if (URI.compare(LOGS_URI) == 0)
|
||||||
{
|
{
|
||||||
auto logs = json::value::object();
|
auto logs = json::value::object();
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ void Unit::update(json::value json, double dt)
|
|||||||
if (json.has_boolean_field(L"isAlive"))
|
if (json.has_boolean_field(L"isAlive"))
|
||||||
setAlive(json[L"isAlive"].as_bool());
|
setAlive(json[L"isAlive"].as_bool());
|
||||||
|
|
||||||
if (json.has_object_field(L"isHuman"))
|
if (json.has_boolean_field(L"isHuman"))
|
||||||
setHuman(json[L"isHuman"].as_bool());
|
setHuman(json[L"isHuman"].as_bool());
|
||||||
|
|
||||||
if (json.has_number_field(L"fuel")) {
|
if (json.has_number_field(L"fuel")) {
|
||||||
@@ -84,18 +84,26 @@ void Unit::update(json::value json, double dt)
|
|||||||
for (auto const& el : json[L"ammo"].as_object()) {
|
for (auto const& el : json[L"ammo"].as_object()) {
|
||||||
DataTypes::Ammo ammoItem;
|
DataTypes::Ammo ammoItem;
|
||||||
auto ammoJson = el.second;
|
auto ammoJson = el.second;
|
||||||
ammoItem.quantity = ammoJson[L"count"].as_number().to_uint32();
|
|
||||||
string name = to_string(ammoJson[L"desc"][L"displayName"].as_string()).substr(0, sizeof(ammoItem.name) - 1);
|
|
||||||
strcpy_s(ammoItem.name, sizeof(ammoItem.name), name.c_str());
|
|
||||||
|
|
||||||
if (ammoJson[L"desc"].has_number_field(L"guidance"))
|
if (ammoJson.has_number_field(L"count"))
|
||||||
ammoItem.guidance = ammoJson[L"desc"][L"guidance"].as_number().to_uint32();
|
ammoItem.quantity = ammoJson[L"count"].as_number().to_uint32();
|
||||||
|
|
||||||
if (ammoJson[L"desc"].has_number_field(L"category"))
|
if (ammoJson.has_object_field(L"desc")) {
|
||||||
ammoItem.category = ammoJson[L"desc"][L"category"].as_number().to_uint32();
|
if (ammoJson[L"desc"].has_string_field(L"displayName")) {
|
||||||
|
string name = to_string(ammoJson[L"desc"][L"displayName"].as_string());
|
||||||
|
name = name.substr(0, min(name.size(), sizeof(ammoItem.name) - 1));
|
||||||
|
strcpy_s(ammoItem.name, sizeof(ammoItem.name), name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
if (ammoJson[L"desc"].has_number_field(L"missileCategory"))
|
if (ammoJson[L"desc"].has_number_field(L"guidance"))
|
||||||
ammoItem.missileCategory = ammoJson[L"desc"][L"missileCategory"].as_number().to_uint32();
|
ammoItem.guidance = ammoJson[L"desc"][L"guidance"].as_number().to_uint32();
|
||||||
|
|
||||||
|
if (ammoJson[L"desc"].has_number_field(L"category"))
|
||||||
|
ammoItem.category = ammoJson[L"desc"][L"category"].as_number().to_uint32();
|
||||||
|
|
||||||
|
if (ammoJson[L"desc"].has_number_field(L"missileCategory"))
|
||||||
|
ammoItem.missileCategory = ammoJson[L"desc"][L"missileCategory"].as_number().to_uint32();
|
||||||
|
}
|
||||||
ammo.push_back(ammoItem);
|
ammo.push_back(ammoItem);
|
||||||
}
|
}
|
||||||
setAmmo(ammo);
|
setAmmo(ammo);
|
||||||
@@ -109,7 +117,7 @@ void Unit::update(json::value json, double dt)
|
|||||||
contactItem.ID = contactJson[L"object"][L"id_"].as_number().to_uint32();
|
contactItem.ID = contactJson[L"object"][L"id_"].as_number().to_uint32();
|
||||||
|
|
||||||
string detectionMethod = to_string(contactJson[L"detectionMethod"]);
|
string detectionMethod = to_string(contactJson[L"detectionMethod"]);
|
||||||
if (detectionMethod.compare("VISUAL") == 0) contactItem.detectionMethod = 1;
|
if (detectionMethod.compare("VISUAL") == 0) contactItem.detectionMethod = 1;
|
||||||
else if (detectionMethod.compare("OPTIC") == 0) contactItem.detectionMethod = 2;
|
else if (detectionMethod.compare("OPTIC") == 0) contactItem.detectionMethod = 2;
|
||||||
else if (detectionMethod.compare("RADAR") == 0) contactItem.detectionMethod = 4;
|
else if (detectionMethod.compare("RADAR") == 0) contactItem.detectionMethod = 4;
|
||||||
else if (detectionMethod.compare("IRST") == 0) contactItem.detectionMethod = 8;
|
else if (detectionMethod.compare("IRST") == 0) contactItem.detectionMethod = 8;
|
||||||
@@ -211,48 +219,56 @@ void Unit::getData(stringstream& ss, unsigned long long time)
|
|||||||
|
|
||||||
const unsigned char endOfData = DataIndex::endOfData;
|
const unsigned char endOfData = DataIndex::endOfData;
|
||||||
ss.write((const char*)&ID, sizeof(ID));
|
ss.write((const char*)&ID, sizeof(ID));
|
||||||
for (unsigned char datumIndex = DataIndex::startOfData + 1; datumIndex < DataIndex::lastIndex; datumIndex++)
|
if (!alive && time == 0) {
|
||||||
{
|
unsigned char datumIndex = DataIndex::category;
|
||||||
if (checkFreshness(datumIndex, time)) {
|
appendString(ss, datumIndex, category);
|
||||||
switch (datumIndex) {
|
datumIndex = DataIndex::alive;
|
||||||
case DataIndex::category: appendString(ss, datumIndex, category); break;
|
appendNumeric(ss, datumIndex, alive);
|
||||||
case DataIndex::alive: appendNumeric(ss, datumIndex, alive); break;
|
}
|
||||||
case DataIndex::human: appendNumeric(ss, datumIndex, human); break;
|
else {
|
||||||
case DataIndex::controlled: appendNumeric(ss, datumIndex, controlled); break;
|
for (unsigned char datumIndex = DataIndex::startOfData + 1; datumIndex < DataIndex::lastIndex; datumIndex++)
|
||||||
case DataIndex::coalition: appendNumeric(ss, datumIndex, coalition); break;
|
{
|
||||||
case DataIndex::country: appendNumeric(ss, datumIndex, country); break;
|
if (checkFreshness(datumIndex, time)) {
|
||||||
case DataIndex::name: appendString(ss, datumIndex, name); break;
|
switch (datumIndex) {
|
||||||
case DataIndex::unitName: appendString(ss, datumIndex, unitName); break;
|
case DataIndex::category: appendString(ss, datumIndex, category); break;
|
||||||
case DataIndex::groupName: appendString(ss, datumIndex, groupName); break;
|
case DataIndex::alive: appendNumeric(ss, datumIndex, alive); break;
|
||||||
case DataIndex::state: appendNumeric(ss, datumIndex, state); break;
|
case DataIndex::human: appendNumeric(ss, datumIndex, human); break;
|
||||||
case DataIndex::task: appendString(ss, datumIndex, task); break;
|
case DataIndex::controlled: appendNumeric(ss, datumIndex, controlled); break;
|
||||||
case DataIndex::hasTask: appendNumeric(ss, datumIndex, hasTask); break;
|
case DataIndex::coalition: appendNumeric(ss, datumIndex, coalition); break;
|
||||||
case DataIndex::position: appendNumeric(ss, datumIndex, position); break;
|
case DataIndex::country: appendNumeric(ss, datumIndex, country); break;
|
||||||
case DataIndex::speed: appendNumeric(ss, datumIndex, speed); break;
|
case DataIndex::name: appendString(ss, datumIndex, name); break;
|
||||||
case DataIndex::heading: appendNumeric(ss, datumIndex, heading); break;
|
case DataIndex::unitName: appendString(ss, datumIndex, unitName); break;
|
||||||
case DataIndex::isTanker: appendNumeric(ss, datumIndex, isTanker); break;
|
case DataIndex::groupName: appendString(ss, datumIndex, groupName); break;
|
||||||
case DataIndex::isAWACS: appendNumeric(ss, datumIndex, isAWACS); break;
|
case DataIndex::state: appendNumeric(ss, datumIndex, state); break;
|
||||||
case DataIndex::onOff: appendNumeric(ss, datumIndex, onOff); break;
|
case DataIndex::task: appendString(ss, datumIndex, task); break;
|
||||||
case DataIndex::followRoads: appendNumeric(ss, datumIndex, followRoads); break;
|
case DataIndex::hasTask: appendNumeric(ss, datumIndex, hasTask); break;
|
||||||
case DataIndex::fuel: appendNumeric(ss, datumIndex, fuel); break;
|
case DataIndex::position: appendNumeric(ss, datumIndex, position); break;
|
||||||
case DataIndex::desiredSpeed: appendNumeric(ss, datumIndex, desiredSpeed); break;
|
case DataIndex::speed: appendNumeric(ss, datumIndex, speed); break;
|
||||||
case DataIndex::desiredSpeedType: appendNumeric(ss, datumIndex, desiredSpeedType); break;
|
case DataIndex::heading: appendNumeric(ss, datumIndex, heading); break;
|
||||||
case DataIndex::desiredAltitude: appendNumeric(ss, datumIndex, desiredAltitude); break;
|
case DataIndex::isTanker: appendNumeric(ss, datumIndex, isTanker); break;
|
||||||
case DataIndex::desiredAltitudeType: appendNumeric(ss, datumIndex, desiredAltitudeType); break;
|
case DataIndex::isAWACS: appendNumeric(ss, datumIndex, isAWACS); break;
|
||||||
case DataIndex::leaderID: appendNumeric(ss, datumIndex, leaderID); break;
|
case DataIndex::onOff: appendNumeric(ss, datumIndex, onOff); break;
|
||||||
case DataIndex::formationOffset: appendNumeric(ss, datumIndex, formationOffset); break;
|
case DataIndex::followRoads: appendNumeric(ss, datumIndex, followRoads); break;
|
||||||
case DataIndex::targetID: appendNumeric(ss, datumIndex, targetID); break;
|
case DataIndex::fuel: appendNumeric(ss, datumIndex, fuel); break;
|
||||||
case DataIndex::targetPosition: appendNumeric(ss, datumIndex, targetPosition); break;
|
case DataIndex::desiredSpeed: appendNumeric(ss, datumIndex, desiredSpeed); break;
|
||||||
case DataIndex::ROE: appendNumeric(ss, datumIndex, ROE); break;
|
case DataIndex::desiredSpeedType: appendNumeric(ss, datumIndex, desiredSpeedType); break;
|
||||||
case DataIndex::reactionToThreat: appendNumeric(ss, datumIndex, reactionToThreat); break;
|
case DataIndex::desiredAltitude: appendNumeric(ss, datumIndex, desiredAltitude); break;
|
||||||
case DataIndex::emissionsCountermeasures: appendNumeric(ss, datumIndex, emissionsCountermeasures); break;
|
case DataIndex::desiredAltitudeType: appendNumeric(ss, datumIndex, desiredAltitudeType); break;
|
||||||
case DataIndex::TACAN: appendNumeric(ss, datumIndex, TACAN); break;
|
case DataIndex::leaderID: appendNumeric(ss, datumIndex, leaderID); break;
|
||||||
case DataIndex::radio: appendNumeric(ss, datumIndex, radio); break;
|
case DataIndex::formationOffset: appendNumeric(ss, datumIndex, formationOffset); break;
|
||||||
case DataIndex::generalSettings: appendNumeric(ss, datumIndex, generalSettings); break;
|
case DataIndex::targetID: appendNumeric(ss, datumIndex, targetID); break;
|
||||||
case DataIndex::ammo: appendVector(ss, datumIndex, ammo); break;
|
case DataIndex::targetPosition: appendNumeric(ss, datumIndex, targetPosition); break;
|
||||||
case DataIndex::contacts: appendVector(ss, datumIndex, contacts); break;
|
case DataIndex::ROE: appendNumeric(ss, datumIndex, ROE); break;
|
||||||
case DataIndex::activePath: appendList(ss, datumIndex, activePath); break;
|
case DataIndex::reactionToThreat: appendNumeric(ss, datumIndex, reactionToThreat); break;
|
||||||
case DataIndex::isLeader: appendNumeric(ss, datumIndex, isLeader); break;
|
case DataIndex::emissionsCountermeasures: appendNumeric(ss, datumIndex, emissionsCountermeasures); break;
|
||||||
|
case DataIndex::TACAN: appendNumeric(ss, datumIndex, TACAN); break;
|
||||||
|
case DataIndex::radio: appendNumeric(ss, datumIndex, radio); break;
|
||||||
|
case DataIndex::generalSettings: appendNumeric(ss, datumIndex, generalSettings); break;
|
||||||
|
case DataIndex::ammo: appendVector(ss, datumIndex, ammo); break;
|
||||||
|
case DataIndex::contacts: appendVector(ss, datumIndex, contacts); break;
|
||||||
|
case DataIndex::activePath: appendList(ss, datumIndex, activePath); break;
|
||||||
|
case DataIndex::isLeader: appendNumeric(ss, datumIndex, isLeader); break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ extern Scheduler* scheduler;
|
|||||||
|
|
||||||
UnitsManager::UnitsManager(lua_State* L)
|
UnitsManager::UnitsManager(lua_State* L)
|
||||||
{
|
{
|
||||||
LogInfo(L, "Units Factory constructor called successfully");
|
LogInfo(L, "Units Manager constructor called successfully");
|
||||||
}
|
}
|
||||||
|
|
||||||
UnitsManager::~UnitsManager()
|
UnitsManager::~UnitsManager()
|
||||||
@@ -110,10 +110,6 @@ void UnitsManager::update(json::value& json, double dt)
|
|||||||
units[ID] = dynamic_cast<Unit*>(new GroundUnit(p.second, ID));
|
units[ID] = dynamic_cast<Unit*>(new GroundUnit(p.second, ID));
|
||||||
else if (category.compare("NavyUnit") == 0)
|
else if (category.compare("NavyUnit") == 0)
|
||||||
units[ID] = dynamic_cast<Unit*>(new NavyUnit(p.second, ID));
|
units[ID] = dynamic_cast<Unit*>(new NavyUnit(p.second, ID));
|
||||||
else if (category.compare("Missile") == 0)
|
|
||||||
units[ID] = dynamic_cast<Unit*>(new Missile(p.second, ID));
|
|
||||||
else if (category.compare("Bomb") == 0)
|
|
||||||
units[ID] = dynamic_cast<Unit*>(new Bomb(p.second, ID));
|
|
||||||
|
|
||||||
/* Initialize the unit if creation was successfull */
|
/* Initialize the unit if creation was successfull */
|
||||||
if (units.count(ID) != 0) {
|
if (units.count(ID) != 0) {
|
||||||
|
|||||||
@@ -4,19 +4,102 @@
|
|||||||
#include "commands.h"
|
#include "commands.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include "unitsmanager.h"
|
|
||||||
|
|
||||||
#include <GeographicLib/Geodesic.hpp>
|
#include <chrono>
|
||||||
using namespace GeographicLib;
|
using namespace std::chrono;
|
||||||
|
|
||||||
extern Scheduler* scheduler;
|
Weapon::Weapon(json::value json, unsigned int ID) :
|
||||||
extern UnitsManager* unitsManager;
|
ID(ID)
|
||||||
|
{
|
||||||
|
log("Creating weapon with ID: " + to_string(ID));
|
||||||
|
}
|
||||||
|
|
||||||
/* Weapon */
|
Weapon::~Weapon()
|
||||||
Weapon::Weapon(json::value json, unsigned int ID) : Unit(json, ID)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
};
|
}
|
||||||
|
|
||||||
|
void Weapon::initialize(json::value json)
|
||||||
|
{
|
||||||
|
if (json.has_string_field(L"name"))
|
||||||
|
setName(to_string(json[L"name"]));
|
||||||
|
|
||||||
|
|
||||||
|
if (json.has_number_field(L"coalitionID"))
|
||||||
|
setCoalition(json[L"coalitionID"].as_number().to_int32());
|
||||||
|
|
||||||
|
update(json, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Weapon::update(json::value json, double dt)
|
||||||
|
{
|
||||||
|
if (json.has_object_field(L"position"))
|
||||||
|
{
|
||||||
|
setPosition({
|
||||||
|
json[L"position"][L"lat"].as_number().to_double(),
|
||||||
|
json[L"position"][L"lng"].as_number().to_double(),
|
||||||
|
json[L"position"][L"alt"].as_number().to_double()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has_number_field(L"heading"))
|
||||||
|
setHeading(json[L"heading"].as_number().to_double());
|
||||||
|
|
||||||
|
if (json.has_number_field(L"speed"))
|
||||||
|
setSpeed(json[L"speed"].as_number().to_double());
|
||||||
|
|
||||||
|
if (json.has_boolean_field(L"isAlive"))
|
||||||
|
setAlive(json[L"isAlive"].as_bool());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Weapon::checkFreshness(unsigned char datumIndex, unsigned long long time) {
|
||||||
|
auto it = updateTimeMap.find(datumIndex);
|
||||||
|
if (it == updateTimeMap.end())
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return it->second > time;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Weapon::hasFreshData(unsigned long long time) {
|
||||||
|
for (auto it : updateTimeMap)
|
||||||
|
if (it.second > time)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Weapon::getData(stringstream& ss, unsigned long long time)
|
||||||
|
{
|
||||||
|
const unsigned char endOfData = DataIndex::endOfData;
|
||||||
|
ss.write((const char*)&ID, sizeof(ID));
|
||||||
|
if (!alive && time == 0) {
|
||||||
|
unsigned char datumIndex = DataIndex::category;
|
||||||
|
appendString(ss, datumIndex, category);
|
||||||
|
datumIndex = DataIndex::alive;
|
||||||
|
appendNumeric(ss, datumIndex, alive);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (unsigned char datumIndex = DataIndex::startOfData + 1; datumIndex < DataIndex::lastIndex; datumIndex++)
|
||||||
|
{
|
||||||
|
if (checkFreshness(datumIndex, time)) {
|
||||||
|
switch (datumIndex) {
|
||||||
|
case DataIndex::category: appendString(ss, datumIndex, category); break;
|
||||||
|
case DataIndex::alive: appendNumeric(ss, datumIndex, alive); break;
|
||||||
|
case DataIndex::coalition: appendNumeric(ss, datumIndex, coalition); break;
|
||||||
|
case DataIndex::name: appendString(ss, datumIndex, name); break;
|
||||||
|
case DataIndex::position: appendNumeric(ss, datumIndex, position); break;
|
||||||
|
case DataIndex::speed: appendNumeric(ss, datumIndex, speed); break;
|
||||||
|
case DataIndex::heading: appendNumeric(ss, datumIndex, heading); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ss.write((const char*)&endOfData, sizeof(endOfData));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Weapon::triggerUpdate(unsigned char datumIndex) {
|
||||||
|
updateTimeMap[datumIndex] = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
|
||||||
|
}
|
||||||
|
|
||||||
/* Missile */
|
/* Missile */
|
||||||
Missile::Missile(json::value json, unsigned int ID) : Weapon(json, ID)
|
Missile::Missile(json::value json, unsigned int ID) : Weapon(json, ID)
|
||||||
|
|||||||
65
src/core/src/weaponsmanager.cpp
Normal file
65
src/core/src/weaponsmanager.cpp
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#include "framework.h"
|
||||||
|
#include "weaponsManager.h"
|
||||||
|
#include "logger.h"
|
||||||
|
#include "weapon.h"
|
||||||
|
#include "scheduler.h"
|
||||||
|
|
||||||
|
#include "base64.hpp"
|
||||||
|
using namespace base64;
|
||||||
|
|
||||||
|
WeaponsManager::WeaponsManager(lua_State* L)
|
||||||
|
{
|
||||||
|
LogInfo(L, "Weapons Manager constructor called successfully");
|
||||||
|
}
|
||||||
|
|
||||||
|
WeaponsManager::~WeaponsManager()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Weapon* WeaponsManager::getWeapon(unsigned int ID)
|
||||||
|
{
|
||||||
|
if (weapons.find(ID) == weapons.end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return weapons[ID];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WeaponsManager::update(json::value& json, double dt)
|
||||||
|
{
|
||||||
|
for (auto const& p : json.as_object())
|
||||||
|
{
|
||||||
|
unsigned int ID = std::stoi(p.first);
|
||||||
|
if (weapons.count(ID) == 0)
|
||||||
|
{
|
||||||
|
json::value value = p.second;
|
||||||
|
if (value.has_string_field(L"category")) {
|
||||||
|
string category = to_string(value[L"category"].as_string());
|
||||||
|
if (category.compare("Missile") == 0)
|
||||||
|
weapons[ID] = dynamic_cast<Weapon*>(new Missile(p.second, ID));
|
||||||
|
else if (category.compare("Bomb") == 0)
|
||||||
|
weapons[ID] = dynamic_cast<Weapon*>(new Bomb(p.second, ID));
|
||||||
|
|
||||||
|
/* Initialize the weapon if creation was successfull */
|
||||||
|
if (weapons.count(ID) != 0) {
|
||||||
|
weapons[ID]->update(p.second, dt);
|
||||||
|
weapons[ID]->initialize(p.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Update the weapon if present*/
|
||||||
|
if (weapons.count(ID) != 0)
|
||||||
|
weapons[ID]->update(p.second, dt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WeaponsManager::getWeaponData(stringstream& ss, unsigned long long time)
|
||||||
|
{
|
||||||
|
for (auto const& p : weapons)
|
||||||
|
p.second->getData(ss, time);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -9,11 +9,13 @@ typedef int(__stdcall* f_coreInit)(lua_State* L);
|
|||||||
typedef int(__stdcall* f_coreDeinit)(lua_State* L);
|
typedef int(__stdcall* f_coreDeinit)(lua_State* L);
|
||||||
typedef int(__stdcall* f_coreFrame)(lua_State* L);
|
typedef int(__stdcall* f_coreFrame)(lua_State* L);
|
||||||
typedef int(__stdcall* f_coreUnitsData)(lua_State* L);
|
typedef int(__stdcall* f_coreUnitsData)(lua_State* L);
|
||||||
|
typedef int(__stdcall* f_coreWeaponsData)(lua_State* L);
|
||||||
typedef int(__stdcall* f_coreMissionData)(lua_State* L);
|
typedef int(__stdcall* f_coreMissionData)(lua_State* L);
|
||||||
f_coreInit coreInit = nullptr;
|
f_coreInit coreInit = nullptr;
|
||||||
f_coreDeinit coreDeinit = nullptr;
|
f_coreDeinit coreDeinit = nullptr;
|
||||||
f_coreFrame coreFrame = nullptr;
|
f_coreFrame coreFrame = nullptr;
|
||||||
f_coreUnitsData coreUnitsData = nullptr;
|
f_coreUnitsData coreUnitsData = nullptr;
|
||||||
|
f_coreWeaponsData coreWeaponsData = nullptr;
|
||||||
f_coreMissionData coreMissionData = nullptr;
|
f_coreMissionData coreMissionData = nullptr;
|
||||||
|
|
||||||
static int onSimulationStart(lua_State* L)
|
static int onSimulationStart(lua_State* L)
|
||||||
@@ -67,14 +69,21 @@ static int onSimulationStart(lua_State* L)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
coreUnitsData = (f_coreFrame)GetProcAddress(hGetProcIDDLL, "coreUnitsData");
|
coreUnitsData = (f_coreUnitsData)GetProcAddress(hGetProcIDDLL, "coreUnitsData");
|
||||||
if (!coreUnitsData)
|
if (!coreUnitsData)
|
||||||
{
|
{
|
||||||
LogError(L, "Error getting coreUnitsData ProcAddress from DLL");
|
LogError(L, "Error getting coreUnitsData ProcAddress from DLL");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
coreMissionData = (f_coreFrame)GetProcAddress(hGetProcIDDLL, "coreMissionData");
|
coreWeaponsData = (f_coreWeaponsData)GetProcAddress(hGetProcIDDLL, "coreWeaponsData");
|
||||||
|
if (!coreWeaponsData)
|
||||||
|
{
|
||||||
|
LogError(L, "Error getting coreWeaponsData ProcAddress from DLL");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
coreMissionData = (f_coreMissionData)GetProcAddress(hGetProcIDDLL, "coreMissionData");
|
||||||
if (!coreMissionData)
|
if (!coreMissionData)
|
||||||
{
|
{
|
||||||
LogError(L, "Error getting coreMissionData ProcAddress from DLL");
|
LogError(L, "Error getting coreMissionData ProcAddress from DLL");
|
||||||
@@ -126,6 +135,7 @@ static int onSimulationStop(lua_State* L)
|
|||||||
coreDeinit = nullptr;
|
coreDeinit = nullptr;
|
||||||
coreFrame = nullptr;
|
coreFrame = nullptr;
|
||||||
coreUnitsData = nullptr;
|
coreUnitsData = nullptr;
|
||||||
|
coreWeaponsData = nullptr;
|
||||||
coreMissionData = nullptr;
|
coreMissionData = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,6 +157,15 @@ static int setUnitsData(lua_State* L)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int setWeaponsData(lua_State* L)
|
||||||
|
{
|
||||||
|
if (coreWeaponsData)
|
||||||
|
{
|
||||||
|
coreWeaponsData(L);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int setMissionData(lua_State* L)
|
static int setMissionData(lua_State* L)
|
||||||
{
|
{
|
||||||
if (coreMissionData)
|
if (coreMissionData)
|
||||||
@@ -161,6 +180,7 @@ static const luaL_Reg Map[] = {
|
|||||||
{"onSimulationFrame", onSimulationFrame},
|
{"onSimulationFrame", onSimulationFrame},
|
||||||
{"onSimulationStop", onSimulationStop},
|
{"onSimulationStop", onSimulationStop},
|
||||||
{"setUnitsData", setUnitsData },
|
{"setUnitsData", setUnitsData },
|
||||||
|
{"setWeaponsData", setWeaponsData },
|
||||||
{"setMissionData", setMissionData },
|
{"setMissionData", setMissionData },
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define VERSION "v0.4.0-alpha"
|
#define VERSION "v0.4.1-alpha"
|
||||||
#define LOG_NAME "Olympus_log.txt"
|
#define LOG_NAME "Olympus_log.txt"
|
||||||
#define REST_ADDRESS "http://localhost:30000"
|
#define REST_ADDRESS "http://localhost:30000"
|
||||||
#define REST_URI "olympus"
|
#define REST_URI "olympus"
|
||||||
#define UNITS_URI "units"
|
#define UNITS_URI "units"
|
||||||
|
#define WEAPONS_URI "weapons"
|
||||||
#define LOGS_URI "logs"
|
#define LOGS_URI "logs"
|
||||||
#define AIRBASES_URI "airbases"
|
#define AIRBASES_URI "airbases"
|
||||||
#define BULLSEYE_URI "bullseyes"
|
#define BULLSEYE_URI "bullseyes"
|
||||||
|
|||||||
Reference in New Issue
Block a user