121 Commits

Author SHA1 Message Date
Pax1601
98a6053a85 v0.2.1 release 2023-05-10 17:07:26 +02:00
Pax1601
7d3debfa7a Merge pull request #259 from Pax1601/221-dont-allow-to-give-tasks-to-human-players
Removed options to command human units
2023-05-10 16:54:52 +02:00
Pax1601
847234633a Removed options to command human units 2023-05-10 16:54:36 +02:00
Pax1601
47d9ff2e10 Merge pull request #258 from Pax1601/236-clean-up-server-from-dead-units
Optimized transmission of data of dead units
2023-05-10 16:14:15 +02:00
Pax1601
e69294b98c Optimized transmission of data of dead units
Dead units only transmit basedata. Empty fields and empty units are removed from update packages.
2023-05-10 16:13:55 +02:00
Pax1601
cf3cdcbd44 Merge pull request #257 from Pax1601/210-fix-ordinance-indicators-below-unit-markers
Ordnance markers are now painted correctly
2023-05-10 11:50:44 +02:00
Pax1601
7545e848d6 Ordnance markers are now painted correctly 2023-05-10 11:50:26 +02:00
Pax1601
d146a47e71 Merge pull request #255 from Pax1601/38-user-authentication-missing
38 user authentication missing
2023-05-10 08:59:21 +02:00
Pax1601
91f8996fba Implemented basic authentication
Also fixed Tankers and AWACS which now operate as expected
2023-05-10 08:59:02 +02:00
Pax1601
57b74bd1b1 Added frontend code for authentication 2023-05-09 15:41:04 +02:00
Pax1601
865be6283c Merge branch 'main' of https://github.com/Pax1601/DCSOlympus 2023-05-05 17:12:16 +02:00
Pax1601
e0636b53f0 Added tristate coalition switch 2023-05-05 17:11:28 +02:00
Pax1601
987c8ee41c Merge pull request #254 from Pax1601/216-increase-ui-reactivity
Removed 200ms delay and small UI fixes
2023-05-04 17:34:08 +02:00
Pax1601
e54a70ffa8 Removed 200ms delay and small UI fixes 2023-05-04 17:32:55 +02:00
Pax1601
fcf1e2d94a Merge pull request #253 from Pax1601/186-style-dropdown-scrollbars
Partially styled, fixed custom fonts
2023-05-04 16:03:47 +02:00
Pax1601
35648b67f5 Partially styled, fixed custom fonts 2023-05-04 16:03:28 +02:00
Pax1601
f0dc581261 Merge pull request #252 from Pax1601/217-dropdowns-dont-close-when-clicking-outside-of-them
Dropdowns now close when clicking outside of them
2023-05-04 09:54:43 +02:00
Pax1601
7ecfc5afef Dropdowns now close when clicking outside of them 2023-05-04 09:54:26 +02:00
Pax1601
e3b88d4e35 Merge pull request #251 from Pax1601/220-add-temporary-marker-for-units-spawning
Added temporary spawn marker
2023-05-03 19:15:21 +02:00
Pax1601
669ee510d3 Added temporary spawn marker 2023-05-03 19:15:00 +02:00
Pax1601
b8edc500c4 Merge pull request #250 from Pax1601/241-ground-units-can-not-be-copy-pasted
Ground units can now be copy-pasted
2023-05-03 10:08:37 +02:00
Pax1601
dc57028a3c Ground units can now be copy-pasted 2023-05-03 10:07:38 +02:00
Pax1601
9eb01654c6 Merge pull request #249 from Pax1601/213-request-spawn-on-airfield
Takeoff task changed to TakeoffParkingHot
2023-05-03 09:22:21 +02:00
Pax1601
8539314984 Takeoff task changed to TakeoffParkingHot 2023-05-03 09:22:00 +02:00
Pax1601
cb24a19d17 Small fixes to map panning 2023-05-02 15:50:55 +02:00
Pax1601
bd7700efce Merge pull request #248 from Pax1601/245-map-cant-be-panned-with-arrows-if-unit-is-selected
Multiple map panning fixes and improvements
2023-05-02 14:30:59 +02:00
Pax1601
a23bdd4b33 Multiple map panning fixes and improvements 2023-05-01 21:51:46 +02:00
Pax1601
89a71ef04e Merge pull request #243 from Pax1601/209-update-follow-functionality-for-ordering-units
209 update follow functionality for ordering units
2023-05-01 10:37:59 +02:00
Pax1601
640f764354 Implemented as described in issue 2023-05-01 10:37:40 +02:00
Pax1601
ee08d9d48e Started work on better follow functionality
And other minor fixes
2023-04-28 17:32:28 +02:00
Pax1601
bf365270ae Merge pull request #230 from Pax1601/218-add-humandcs-controlledolympus-controller-icon
218 add humandcs controlledolympus controller icon
2023-04-28 15:43:22 +02:00
Pax1601
6ec2235114 Fixed units jumping back 2023-04-27 16:06:08 +02:00
Pax1601
8f7071510b Merge pull request #225 from Shredmetal/Add-loadouts-to-aircraftdatabase-and-unipayloads-22/4
Add files via upload
2023-04-27 12:27:48 +02:00
Shredmetal
1f72612255 Add files via upload
fixed issues with the tomcat loadouts in use - ISSUE WILL RESURFACE IF NEW LOADOUTS ADDED. Remember to change the unitPayloads lua together with the AircraftDatabase
2023-04-27 02:45:04 +08:00
Shredmetal
94c5765bc6 Add files via upload
fixed references to aircraftdatabase
2023-04-27 02:43:08 +08:00
Pax1601
04c7fc3741 Added human and DCS controlled icons 2023-04-26 17:42:17 +02:00
Pax1601
40bcd46677 Added minimap and scale 2023-04-26 16:49:01 +02:00
Shredmetal
ab736adabe Add files via upload
Helicopterdatabase
2023-04-26 05:19:55 +08:00
Pax1601
f4fd516d92 Merge pull request #214 from Shredmetal/Add-loadouts-to-aircraftdatabase-and-unipayloads-22/4
Changed aircraftdatabase.ts and unitpayloads.lua
2023-04-24 19:23:03 +02:00
Shredmetal
4c3cfc608b Add files via upload
Added MiG-21Bis Fox-1 only loadout
2023-04-24 18:54:47 +08:00
Shredmetal
6ae23509a6 Add files via upload
added MiG-21Bis loadout, fox 1 only
2023-04-24 18:53:49 +08:00
Shredmetal
20077417af Add files via upload
replacing deleted unitpaylods
2023-04-22 23:47:41 +08:00
Shredmetal
673e00c0e8 Delete unitPayloads.lua
Delete to reuploaded amended unitpayloads
2023-04-22 23:36:36 +08:00
Shredmetal
197159fc2a Add files via upload
Updated aircraftdatabase.ts
2023-04-22 23:33:06 +08:00
Shredmetal
1ca0029407 Delete aircraftdatabase.ts
Delete to reupload amended file
2023-04-22 23:31:07 +08:00
Pax1601
b72d92ffd7 Fixed installer 2023-04-22 10:07:21 +02:00
Pax1601
e04e4b2dec Merge pull request #203 from Pax1601/146-add-in-game-clock-time-to-data-stream
Implemented
2023-04-21 19:10:31 +02:00
Pax1601
35709987e7 Implemented
Added date, start time, elapsed time, current time
2023-04-21 19:10:03 +02:00
Pax1601
bcc6b5b5c3 Merge pull request #202 from Pax1601/200-multiple-errors-referring-to-script
Issue fixed by updating MIST and checking method existance
2023-04-21 19:00:51 +02:00
Pax1601
a047a04d09 Issue fixed by updating MIST and checking method existance 2023-04-21 19:00:29 +02:00
Pax1601
f6d16944c2 Added loadouts 2023-04-21 18:10:09 +02:00
Pax1601
ee361f12f2 Merge pull request #201 from Pax1601/194-atc-tower-assign-altitude
Adding missing files.
2023-04-20 20:20:59 +02:00
PeekabooSteam
14cdec9615 Adding missing files. 2023-04-20 19:14:19 +01:00
Pax1601
5cff54bfde Merge branch 'main' of https://github.com/Pax1601/DCSOlympus 2023-04-20 17:28:49 +02:00
Pax1601
a9e18e42d3 Added missing planes 2023-04-20 17:28:46 +02:00
Pax1601
6ce9b2ddea Merge pull request #199 from Pax1601/feature-atc-tower
Feature atc tower
2023-04-20 15:50:50 +02:00
PeekabooSteam
06f10cd399 Merge pull request #198 from Pax1601/194-atc-tower-assign-altitude
Added assigned speeds, alts, select unit.
2023-04-20 14:23:57 +01:00
PeekabooSteam
3124a0f6b5 Added assigned speeds, alts, select unit. 2023-04-20 14:22:16 +01:00
dpassoni
090973a3d1 Updated version 2023-04-20 12:36:43 +02:00
Pax1601
992b1d40c9 Merge pull request #196 from Pax1601/73-add-tankers-and-awacs-spawning
73 add tankers and awacs spawning
2023-04-20 12:18:57 +02:00
Pax1601
41be6402cd Merge branch 'main' into 73-add-tankers-and-awacs-spawning 2023-04-19 16:35:37 +02:00
Pax1601
c3c84b2115 Follow, tankers and AWACS completed 2023-04-19 16:30:14 +02:00
Pax1601
f24c57cc18 Follow feature completed 2023-04-19 10:19:56 +02:00
Pax1601
cfd98e74ea Added states and more work on custom formations 2023-04-18 11:01:31 +02:00
Pax1601
be69aeb69e Custom formations 2023-04-17 18:01:23 +02:00
PeekabooSteam
79f616cf8d Merge pull request #195 from Pax1601/193-atc-tower-manually-sort-strips
Flights now sortable.
2023-04-16 23:42:04 +01:00
PeekabooSteam
d77735581a Flights now sortable. 2023-04-16 23:34:00 +01:00
Pax1601
77d39c17b8 More work on follow and tanking (added combo tasks) 2023-04-16 20:24:33 +02:00
PeekabooSteam
3eefe441b4 Merge pull request #192 from Pax1601/188-atc-tower-add-plane-to-strip-board-via-click
Can add flights by click.
2023-04-16 13:15:56 +01:00
PeekabooSteam
e84fa7caaa Can add flights by click. 2023-04-16 12:58:14 +01:00
PeekabooSteam
a3d919bad9 Merge pull request #190 from Pax1601/187-atc-tower-list-planes-being-monitored
Flights now listed by board.
2023-04-14 23:13:46 +01:00
PeekabooSteam
8707982769 Flights now listed by board. 2023-04-14 23:11:55 +01:00
Pax1601
39698c66a3 More work on follow and tanking 2023-04-14 17:30:10 +02:00
Pax1601
b56f1ca547 Fixed checkbox and frequency 2023-04-14 07:59:24 +02:00
Pax1601
4a90193426 Added functions to set TACAN and radio frequencies 2023-04-13 08:09:15 +02:00
Pax1601
7eee469bed More work on advanced settings dialog 2023-04-12 17:21:36 +02:00
Pax1601
316261e01e Started to implement advanced settings 2023-04-11 20:30:59 +02:00
Pax1601
df2aef498f Updated version numbers 2023-04-11 20:30:19 +02:00
Pax1601
f4bb484c7d Merge pull request #179 from Pax1601/atc-mission-board
Atc mission board
2023-04-11 15:23:09 +02:00
Pax1601
f4ddbbd1af Merge pull request #184 from Pax1601/180-unit-loadout-overflows-unitinfopanel
String management for loadout items.
2023-04-11 15:22:04 +02:00
Pax1601
c3233ad999 Merge pull request #185 from Pax1601/181-dropdowns-can-overflow-to-window-page
Dropdowns limited to 382px.  Ground unit types are automatically sorted
2023-04-11 15:21:22 +02:00
Pax1601
1f51d69126 Added basic tanker and AWACS enroute tasks
Tanker not working propertly yet, frequency setting still needed
2023-04-11 15:20:17 +02:00
PeekabooSteam
14ae0d083f Dropdowns limited to 382px. Ground unit types are automatically sorted 2023-04-09 15:22:27 +01:00
PeekabooSteam
8d951410e5 String management for loadout items. 2023-04-09 10:49:40 +01:00
PeekabooSteam
7605dd26ff Resolved conflicts 2023-04-09 09:54:21 +01:00
Pax1601
1b093782c3 Merge pull request #182 from Pax1601/176-minus-keystroke-zooms-out-and-brings-up-unit-list
Removed callback at "minus" keypress
2023-04-09 10:12:41 +02:00
Pax1601
2947d55bc5 Merge pull request #183 from Pax1601/163-f-15c-instant-action-cc-bomber-intercept-crashes-olympus
Added check on existance of mist structures
2023-04-09 10:12:29 +02:00
Pax1601
103fcde426 Removed callback at "minus" keypress 2023-04-09 10:11:51 +02:00
Pax1601
3193eb0021 Added check on existance of mist structures 2023-04-09 10:08:49 +02:00
Pax1601
0456bbef52 Minor bugfix on demo data 2023-04-09 09:48:49 +02:00
Pax1601
c54c7d2d78 Merge pull request #174 from Pax1601/147-speed-and-altitude-controls-jumping-back
Sliders no longer jump after update.
2023-04-08 15:16:07 +02:00
Pax1601
9c834e4072 Merge pull request #170 from Pax1601/149-loadout-numbers-overflowing
Aligned numbers within pills.
2023-04-08 15:04:51 +02:00
Pax1601
b10522498b Merge pull request #171 from Pax1601/111-measurebox-shows-000-when-measuring-north-should-read-360
111 measurebox shows 000 when measuring north should read 360
2023-04-08 15:01:44 +02:00
Pax1601
fd23fd3034 Merge pull request #172 from Pax1601/148-missing-scrollbar-for-units-buttons
Added scrollable to selected units' list; bit of tidying up.
2023-04-08 15:00:06 +02:00
Pax1601
3aa6d27ed3 Merge pull request #177 from Pax1601/175-keystrokes-in-input-fields-are-triggering-shortcuts
keyEventWasInInput() function added.
2023-04-08 14:55:36 +02:00
Pax1601
b98c392f79 Merge pull request #178 from Pax1601/121-spawn-context-menu-and-airbase-menu-overflow-window
Clipping is now less bad.
2023-04-08 14:54:15 +02:00
PeekabooSteam
071942b632 Slightly nicer PoC. 2023-04-04 23:38:08 +01:00
PeekabooSteam
5dda45ad22 Clipping is now less bad. 2023-04-04 19:16:00 +01:00
PeekabooSteam
6ffcb76f03 keyEventWasInInput() function added. 2023-04-04 15:51:11 +01:00
PeekabooSteam
6993650ff8 Sliders no longer jump after update. 2023-04-04 15:04:45 +01:00
PeekabooSteam
6b22c1ef63 Added scrollable to selected units' list; bit of tidying up. 2023-03-31 21:06:46 +01:00
PeekabooSteam
ee6fadfb36 Merge branch '111-measurebox-shows-000-when-measuring-north-should-read-360' of https://github.com/Pax1601/DCSOlympus into 111-measurebox-shows-000-when-measuring-north-should-read-360 2023-03-31 20:31:45 +01:00
PeekabooSteam
2f5b9d1f94 360 now shows for bullseyes. 2023-03-31 20:31:36 +01:00
PeekabooSteam
b9f32a5b82 Aligned numbers within pills. 2023-03-31 20:27:04 +01:00
PeekabooSteam
6f64bd1622 ATC Ground board PoC. 2023-03-29 21:15:33 +01:00
Pax1601
ff20eec472 Merge pull request #169 from Pax1601/71-add-counters-to-data-to-avoid-units-jumping-back
Added check on message time
2023-03-29 09:19:53 +02:00
Pax1601
9c9d53f3fb Added check on message time 2023-03-29 09:19:35 +02:00
Pax1601
b4e34bf9e4 Merge pull request #168 from Pax1601/155-pasting-units-generates-many-units-if-ctrl+v-is-held-down
Maximum paste rate set to once every 250ms
2023-03-29 09:00:16 +02:00
Pax1601
73a539bf94 Removed log 2023-03-29 09:00:04 +02:00
Pax1601
ac44c208a8 Maximum paste rate set to once every 250ms 2023-03-29 08:59:32 +02:00
Pax1601
04618cb247 Merge pull request #167 from Pax1601/166-ground-unit-type-not-selected
Fixed
2023-03-29 08:54:20 +02:00
Pax1601
3bdba116e8 Fixed 2023-03-29 08:54:03 +02:00
Pax1601
ea94d8ac24 Merge branch 'main' of https://github.com/Pax1601/DCSOlympus 2023-03-29 08:51:08 +02:00
Pax1601
ab51a76075 Client modified to work on any address 2023-03-29 08:51:05 +02:00
Pax1601
cae9b16d97 Merge pull request #157 from Pax1601/156-delete-lua-function-can-cause-player-desync-in-multiplayer
updated Olympus.delete to avoid player desync
2023-03-28 14:27:28 +02:00
Wirts Legs
ee6537de7c updated Olympus.delete to avoid player desync 2023-03-27 19:16:50 -04:00
Pax1601
efae7c23ff Merge pull request #152 from Pax1601/151-spawn-menu-not-working-in-firefox
PointerEvent changed to MouseEvent.
2023-03-27 09:19:50 +02:00
PeekabooSteam
df79f6577b PointerEvent changed to MouseEvent. 2023-03-26 20:10:25 +01:00
PeekabooSteam
14147168f9 ATC stuff. 2023-03-26 20:00:23 +01:00
PeekabooSteam
da008c220d Added beginnings of new ATC framework. 2023-03-26 15:39:21 +01:00
PeekabooSteam
d86a250575 Remove old ATC code. 2023-03-26 11:00:20 +01:00
110 changed files with 30880 additions and 16573 deletions

View File

@@ -1,7 +0,0 @@
RTB
tanker
scenario dropdown
explosion
wrong name for ground units
improve map zIndex
human symbol if user

View File

@@ -3,7 +3,9 @@ var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var fs = require('fs');
var basicAuth = require('express-basic-auth')
var atcRouter = require('./routes/api/atc');
var indexRouter = require('./routes/index');
var uikitRouter = require('./routes/uikit');
var usersRouter = require('./routes/users');
@@ -17,6 +19,7 @@ app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/api/atc', atcRouter);
app.use('/users', usersRouter);
app.use('/uikit', uikitRouter);
@@ -24,7 +27,8 @@ app.set('view engine', 'ejs');
let rawdata = fs.readFileSync('../olympus.json');
let config = JSON.parse(rawdata);
app.get('/config', (req, res) => res.send(config));
if (config["server"] != undefined)
app.get('/config', (req, res) => res.send(config["server"]));
module.exports = app;
@@ -36,3 +40,8 @@ app.get('/demo/bullseyes', (req, res) => demoDataGenerator.bullseyes(req, res));
app.get('/demo/airbases', (req, res) => demoDataGenerator.airbases(req, res));
app.get('/demo/mission', (req, res) => demoDataGenerator.mission(req, res));
app.use('/demo', basicAuth({
users: { 'admin': 'socks' }
}))

View File

@@ -1,2 +1,2 @@
start cmd /k "npm run start"
start cmd /k "watchify .\src\index.ts --debug -p [ tsify --noImplicitAny ] -o .\public\javascripts\bundle.js"
start cmd /k "watchify .\src\index.ts --debug -o .\public\javascripts\bundle.js -t [ babelify --global true --presets [ @babel/preset-env ] --extensions '.js'] -p [ tsify --noImplicitAny ]

View File

@@ -2,8 +2,8 @@
const DEMO_UNIT_DATA = {
["1"]:{
baseData: {
AI: true,
name: "F-5E",
AI: false,
name: "KC-135",
unitName: "Olympus 1-1",
groupName: "Group 1",
alive: true,
@@ -18,7 +18,7 @@ const DEMO_UNIT_DATA = {
},
missionData: {
fuel: 50,
flags: {human: false},
flags: {Human: false},
ammo: [
{
count: 4,
@@ -47,9 +47,19 @@ const DEMO_UNIT_DATA = {
},
taskData: {
currentTask: "Holding",
currentState: "Idle",
activePath: undefined,
targetSpeed: 400,
targetAltitude: 3000
targetAltitude: 3000,
isTanker: false,
TACANOn: false,
TACANChannel: 32,
TACANXY: "Y",
TACANCallsign: "ASD",
radioFrequency: 123.750,
radioCallsign: 2,
radioCallsignNumber: 3,
radioAMFM: "FM"
},
optionsData: {
ROE: "Designated",
@@ -59,7 +69,7 @@ const DEMO_UNIT_DATA = {
["2"]:{
baseData: {
AI: true,
name: "F-5E",
name: "KC-135",
unitName: "Olympus 1-2",
groupName: "Group 1",
alive: true,
@@ -625,11 +635,16 @@ class DemoDataGenerator {
units(req, res){
var ret = this.demoUnits;
for (let ID in this.demoUnits["units"]){
this.demoUnits["units"][ID].flightData.latitude += 0.00001;
}
ret.time = Date.now();
res.send(JSON.stringify(ret));
};
logs(req, res){
var ret = {logs: {}};
ret.time = Date.now();
res.send(JSON.stringify(ret));
};
@@ -654,6 +669,7 @@ class DemoDataGenerator {
coalition: "blue"
}
}};
ret.time = Date.now();
res.send(JSON.stringify(ret));
};
@@ -672,11 +688,13 @@ class DemoDataGenerator {
longitude: -115.7
}
}};
ret.time = Date.now();
res.send(JSON.stringify(ret));
};
mission(req, res){
var ret = {mission: {theatre: "Nevada"}};
ret.time = Date.now();
res.send(JSON.stringify(ret));
}

4200
client/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,12 +2,12 @@
"name": "DCSOlympus",
"node-main": "./bin/www",
"main": "http://localhost:3000",
"version": "0.1.1-alpha",
"version": "v0.2.1-alpha",
"private": true,
"scripts": {
"copy": "copy .\\node_modules\\leaflet\\dist\\leaflet.css .\\public\\stylesheets\\leaflet.css",
"start": "npm run copy & concurrently --kill-others \"npm run watch\" \"nodemon ./bin/www\"",
"watch": "watchify .\\src\\index.ts --debug -p [ tsify --noImplicitAny ] -o .\\public\\javascripts\\bundle.js"
"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": {
"@types/geojson": "^7946.0.10",
@@ -16,16 +16,24 @@
"debug": "~2.6.9",
"ejs": "^3.1.8",
"express": "~4.16.1",
"geomag": "^1.0.0",
"leaflet": "^1.9.3",
"leaflet-control-mini-map": "^0.4.0",
"leaflet.nauticscale": "^1.1.0",
"milsymbol": "^2.0.0",
"morgan": "~1.9.1",
"save": "^2.9.0"
},
"devDependencies": {
"@babel/preset-env": "^7.21.4",
"@types/gtag.js": "^0.0.12",
"@types/node": "^18.16.1",
"@types/sortablejs": "^1.15.0",
"babelify": "^10.0.0",
"browserify": "^17.0.0",
"concurrently": "^7.6.0",
"esmify": "^2.1.1",
"express-basic-auth": "^1.2.1",
"nodemon": "^2.0.20",
"sortablejs": "^1.15.0",
"tsify": "^5.0.4",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M0 55.2V426c0 12.2 9.9 22 22 22c6.3 0 12.4-2.7 16.6-7.5L121.2 346l58.1 116.3c7.9 15.8 27.1 22.2 42.9 14.3s22.2-27.1 14.3-42.9L179.8 320H297.9c12.2 0 22.1-9.9 22.1-22.1c0-6.3-2.7-12.3-7.4-16.5L38.6 37.9C34.3 34.1 28.9 32 23.2 32C10.4 32 0 42.4 0 55.2z"/></svg>

After

Width:  |  Height:  |  Size: 498 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M15 15C24.4 5.7 39.6 5.7 49 15l63 63V40c0-13.3 10.7-24 24-24s24 10.7 24 24v96c0 13.3-10.7 24-24 24H40c-13.3 0-24-10.7-24-24s10.7-24 24-24H78.1L15 49C5.7 39.6 5.7 24.4 15 15zM133.5 243.9C158.6 193.6 222.7 112 320 112s161.4 81.6 186.5 131.9c3.8 7.6 3.8 16.5 0 24.2C481.4 318.4 417.3 400 320 400s-161.4-81.6-186.5-131.9c-3.8-7.6-3.8-16.5 0-24.2zM320 320a64 64 0 1 0 0-128 64 64 0 1 0 0 128zM591 15c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-63 63H600c13.3 0 24 10.7 24 24s-10.7 24-24 24H504c-13.3 0-24-10.7-24-24V40c0-13.3 10.7-24 24-24s24 10.7 24 24V78.1l63-63zM15 497c-9.4-9.4-9.4-24.6 0-33.9l63-63H40c-13.3 0-24-10.7-24-24s10.7-24 24-24h96c13.3 0 24 10.7 24 24v96c0 13.3-10.7 24-24 24s-24-10.7-24-24V433.9L49 497c-9.4 9.4-24.6 9.4-33.9 0zm576 0l-63-63V472c0 13.3-10.7 24-24 24s-24-10.7-24-24V376c0-13.3 10.7-24 24-24h96c13.3 0 24 10.7 24 24s-10.7 24-24 24H561.9l63 63c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M448 256A192 192 0 1 0 64 256a192 192 0 1 0 384 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm256 80a80 80 0 1 0 0-160 80 80 0 1 0 0 160zm0-224a144 144 0 1 1 0 288 144 144 0 1 1 0-288zM224 256a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"/></svg>

After

Width:  |  Height:  |  Size: 480 B

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
version="1.1"
id="svg14"
sodipodi:docname="echelon-lh.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)">
<metadata
id="metadata20">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs18" />
<sodipodi:namedview
inkscape:document-rotation="0"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview16"
showgrid="false"
inkscape:zoom="34.345186"
inkscape:cx="9.7964424"
inkscape:cy="8.7196642"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg14" />
<path
d="m 11.760336,0.82277727 c 0.03507,-0.0819211 0.116519,-0.13468436 0.20644,-0.13468436 0.08985,0 0.171299,0.0527631 0.206441,0.13468436 L 12.79247,2.2515013 c 0.04782,0.1110719 0.07304,0.2290997 0.07304,0.3498999 v 1.0690957 l 2.022304,1.1663106 V 4.5758186 c 0,-0.1846888 0.150282,-0.3332707 0.337016,-0.3332707 0.186803,0 0.337085,0.1485819 0.337085,0.3332707 V 5.353336 5.7976518 6.1308542 c 0,0.1846885 -0.150282,0.3332711 -0.337085,0.3332711 -0.186734,0 -0.337016,-0.1485826 -0.337016,-0.3332711 V 6.0198095 H 12.865509 V 6.473799 l 0.821559,0.7123218 c 0.04913,0.041627 0.07724,0.1027332 0.07724,0.1665674 v 0.2221572 c 0,0.1222175 -0.101084,0.2221571 -0.224701,0.2221571 H 12.191408 V 6.9083724 c 0,-0.1221494 -0.101085,-0.22209 -0.224632,-0.22209 -0.123616,0 -0.2247,0.099941 -0.2247,0.22209 v 0.8886301 h -1.348203 c -0.123616,0 -0.2247,-0.09994 -0.2247,-0.2221571 V 7.3526882 c 0,-0.063834 0.02804,-0.1249429 0.07717,-0.1665674 L 11.067975,6.473799 V 6.0198095 H 9.0456705 v 0.1110447 c 0,0.1846885 -0.1502827,0.3332711 -0.3370162,0.3332711 -0.1868027,0 -0.3370854,-0.1485826 -0.3370854,-0.3332711 V 5.7976518 5.353336 4.5758186 c 0,-0.1846888 0.1502827,-0.3332707 0.3370854,-0.3332707 0.1867335,0 0.3370162,0.1485819 0.3370162,0.3332707 V 4.8368075 L 11.067975,3.6704969 V 2.6014012 c 0,-0.1208002 0.02529,-0.238828 0.07304,-0.3498999 z"
fill="#202831"
id="path2"
style="fill:#000000;fill-opacity:1;stroke-width:0.685147" />
<path
style="fill:#000000;fill-opacity:1;stroke-width:0.685147"
id="path2-4"
fill="#202831"
d="m 4.3098319,8.5178559 c 0.03507,-0.081921 0.116519,-0.1346843 0.206441,-0.1346843 0.08985,0 0.171299,0.052763 0.206441,0.1346843 L 5.3419659,9.94658 c 0.04782,0.111072 0.07304,0.2291 0.07304,0.3499 v 1.069096 l 2.0223043,1.166311 v -0.26099 c 0,-0.184688 0.1502822,-0.33327 0.3370163,-0.33327 0.1868027,0 0.3370848,0.148582 0.3370848,0.33327 v 0.777518 0.444316 0.333202 c 0,0.184689 -0.1502821,0.333271 -0.3370848,0.333271 -0.1867341,0 -0.3370163,-0.148582 -0.3370163,-0.333271 V 13.714889 H 5.4150049 v 0.453989 l 0.821559,0.712322 c 0.04913,0.04163 0.07724,0.102733 0.07724,0.166567 v 0.222157 c 0,0.122218 -0.101084,0.222158 -0.2247,0.222158 h -1.348203 v -0.888631 c 0,-0.122149 -0.101084,-0.22209 -0.224631,-0.22209 -0.123616,0 -0.224701,0.09994 -0.224701,0.22209 v 0.888631 h -1.348202 c -0.123616,0 -0.224701,-0.09994 -0.224701,-0.222158 v -0.222157 c 0,-0.06383 0.02804,-0.124943 0.07717,-0.166567 l 0.821635,-0.712322 v -0.453989 h -2.022304 v 0.111044 c 0,0.184689 -0.150283,0.333271 -0.337016,0.333271 -0.186803,0 -0.33708499,-0.148582 -0.33708499,-0.333271 v -0.333202 -0.444316 -0.777518 c 0,-0.184688 0.15028199,-0.33327 0.33708499,-0.33327 0.186733,0 0.337016,0.148582 0.337016,0.33327 v 0.26099 l 2.022304,-1.166311 V 10.29648 c 0,-0.1208 0.02529,-0.238828 0.07304,-0.3499 z" />
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
version="1.1"
id="svg14"
sodipodi:docname="echelon-rh.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)">
<metadata
id="metadata20">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs18" />
<sodipodi:namedview
inkscape:document-rotation="0"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview16"
showgrid="false"
inkscape:zoom="34.345186"
inkscape:cx="9.7964424"
inkscape:cy="8.7196642"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg14" />
<path
d="M 4.7226453,0.82277727 C 4.687573,0.74085619 4.6061264,0.68809291 4.516205,0.68809291 c -0.089853,0 -0.1712993,0.0527631 -0.206441,0.13468436 L 3.6905114,2.2515013 c -0.04782,0.1110719 -0.07304,0.2290997 -0.07304,0.3498999 V 3.6704969 L 1.5951671,4.8368075 V 4.5758186 c 0,-0.1846888 -0.1502822,-0.3332707 -0.3370163,-0.3332707 -0.1868027,0 -0.33708489,0.1485819 -0.33708489,0.3332707 V 5.353336 5.7976518 6.1308542 c 0,0.1846885 0.15028219,0.3332711 0.33708489,0.3332711 0.1867341,0 0.3370163,-0.1485826 0.3370163,-0.3332711 V 6.0198095 H 3.6174719 V 6.473799 l -0.821559,0.7123218 c -0.049132,0.041627 -0.077243,0.1027332 -0.077243,0.1665674 v 0.2221572 c 0,0.1222175 0.1010844,0.2221571 0.2247007,0.2221571 H 4.2915732 V 6.9083724 c 0,-0.1221494 0.1010844,-0.22209 0.2246318,-0.22209 0.1236157,0 0.2247001,0.099941 0.2247001,0.22209 v 0.8886301 h 1.3482024 c 0.1236163,0 0.2247007,-0.09994 0.2247007,-0.2221571 V 7.3526882 c 0,-0.063834 -0.028044,-0.1249429 -0.077174,-0.1665674 L 5.4150063,6.473799 V 6.0198095 h 2.0223041 v 0.1110447 c 0,0.1846885 0.1502827,0.3332711 0.3370162,0.3332711 0.1868027,0 0.3370854,-0.1485826 0.3370854,-0.3332711 V 5.7976518 5.353336 4.5758186 c 0,-0.1846888 -0.1502827,-0.3332707 -0.3370854,-0.3332707 -0.1867335,0 -0.3370162,0.1485819 -0.3370162,0.3332707 V 4.8368075 L 5.4150063,3.6704969 V 2.6014012 c 0,-0.1208002 -0.025289,-0.238828 -0.07304,-0.3498999 z"
fill="#202831"
id="path2"
style="fill:#000000;fill-opacity:1;stroke-width:0.685147" />
<path
style="fill:#000000;fill-opacity:1;stroke-width:0.685147"
id="path2-4"
fill="#202831"
d="m 12.173149,8.5178559 c -0.03507,-0.081921 -0.116519,-0.1346843 -0.206441,-0.1346843 -0.08985,0 -0.171299,0.052763 -0.206441,0.1346843 L 11.141015,9.94658 c -0.04782,0.111072 -0.07304,0.2291 -0.07304,0.3499 v 1.069096 l -2.0223043,1.166311 v -0.26099 c 0,-0.184688 -0.1502822,-0.33327 -0.3370163,-0.33327 -0.1868027,0 -0.3370848,0.148582 -0.3370848,0.33327 v 0.777518 0.444316 0.333202 c 0,0.184689 0.1502821,0.333271 0.3370848,0.333271 0.1867341,0 0.3370163,-0.148582 0.3370163,-0.333271 v -0.111044 h 2.0223053 v 0.453989 L 10.246417,14.8812 c -0.04913,0.04163 -0.07724,0.102733 -0.07724,0.166567 v 0.222157 c 0,0.122218 0.101084,0.222158 0.2247,0.222158 h 1.348203 v -0.888631 c 0,-0.122149 0.101084,-0.22209 0.224631,-0.22209 0.123616,0 0.224701,0.09994 0.224701,0.22209 v 0.888631 h 1.348202 c 0.123616,0 0.224701,-0.09994 0.224701,-0.222158 v -0.222157 c 0,-0.06383 -0.02804,-0.124943 -0.07717,-0.166567 L 12.86551,14.168878 v -0.453989 h 2.022304 v 0.111044 c 0,0.184689 0.150283,0.333271 0.337016,0.333271 0.186803,0 0.337085,-0.148582 0.337085,-0.333271 v -0.333202 -0.444316 -0.777518 c 0,-0.184688 -0.150282,-0.33327 -0.337085,-0.33327 -0.186733,0 -0.337016,0.148582 -0.337016,0.33327 v 0.26099 L 12.86551,11.365576 V 10.29648 c 0,-0.1208 -0.02529,-0.238828 -0.07304,-0.3499 z" />
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
version="1.1"
id="svg14"
sodipodi:docname="echelon.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)">
<metadata
id="metadata20">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs18" />
<sodipodi:namedview
inkscape:document-rotation="0"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview16"
showgrid="false"
inkscape:zoom="34.345186"
inkscape:cx="9.7964424"
inkscape:cy="8.7196642"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg14" />
<path
d="M 4.7226453,0.82277727 C 4.687573,0.74085619 4.6061264,0.68809291 4.516205,0.68809291 c -0.089853,0 -0.1712993,0.0527631 -0.206441,0.13468436 L 3.6905114,2.2515013 c -0.04782,0.1110719 -0.07304,0.2290997 -0.07304,0.3498999 V 3.6704969 L 1.5951671,4.8368075 V 4.5758186 c 0,-0.1846888 -0.1502822,-0.3332707 -0.3370163,-0.3332707 -0.1868027,0 -0.33708489,0.1485819 -0.33708489,0.3332707 V 5.353336 5.7976518 6.1308542 c 0,0.1846885 0.15028219,0.3332711 0.33708489,0.3332711 0.1867341,0 0.3370163,-0.1485826 0.3370163,-0.3332711 V 6.0198095 H 3.6174719 V 6.473799 l -0.821559,0.7123218 c -0.049132,0.041627 -0.077243,0.1027332 -0.077243,0.1665674 v 0.2221572 c 0,0.1222175 0.1010844,0.2221571 0.2247007,0.2221571 H 4.2915732 V 6.9083724 c 0,-0.1221494 0.1010844,-0.22209 0.2246318,-0.22209 0.1236157,0 0.2247001,0.099941 0.2247001,0.22209 v 0.8886301 h 1.3482024 c 0.1236163,0 0.2247007,-0.09994 0.2247007,-0.2221571 V 7.3526882 c 0,-0.063834 -0.028044,-0.1249429 -0.077174,-0.1665674 L 5.4150063,6.473799 V 6.0198095 h 2.0223041 v 0.1110447 c 0,0.1846885 0.1502827,0.3332711 0.3370162,0.3332711 0.1868027,0 0.3370854,-0.1485826 0.3370854,-0.3332711 V 5.7976518 5.353336 4.5758186 c 0,-0.1846888 -0.1502827,-0.3332707 -0.3370854,-0.3332707 -0.1867335,0 -0.3370162,0.1485819 -0.3370162,0.3332707 V 4.8368075 L 5.4150063,3.6704969 V 2.6014012 c 0,-0.1208002 -0.025289,-0.238828 -0.07304,-0.3498999 z"
fill="#202831"
id="path2"
style="fill:#000000;fill-opacity:1;stroke-width:0.685147" />
<path
style="fill:#000000;fill-opacity:1;stroke-width:0.685147"
id="path2-4"
fill="#202831"
d="m 12.173149,8.5178559 c -0.03507,-0.081921 -0.116519,-0.1346843 -0.206441,-0.1346843 -0.08985,0 -0.171299,0.052763 -0.206441,0.1346843 L 11.141015,9.94658 c -0.04782,0.111072 -0.07304,0.2291 -0.07304,0.3499 v 1.069096 l -2.0223043,1.166311 v -0.26099 c 0,-0.184688 -0.1502822,-0.33327 -0.3370163,-0.33327 -0.1868027,0 -0.3370848,0.148582 -0.3370848,0.33327 v 0.777518 0.444316 0.333202 c 0,0.184689 0.1502821,0.333271 0.3370848,0.333271 0.1867341,0 0.3370163,-0.148582 0.3370163,-0.333271 v -0.111044 h 2.0223053 v 0.453989 L 10.246417,14.8812 c -0.04913,0.04163 -0.07724,0.102733 -0.07724,0.166567 v 0.222157 c 0,0.122218 0.101084,0.222158 0.2247,0.222158 h 1.348203 v -0.888631 c 0,-0.122149 0.101084,-0.22209 0.224631,-0.22209 0.123616,0 0.224701,0.09994 0.224701,0.22209 v 0.888631 h 1.348202 c 0.123616,0 0.224701,-0.09994 0.224701,-0.222158 v -0.222157 c 0,-0.06383 -0.02804,-0.124943 -0.07717,-0.166567 L 12.86551,14.168878 v -0.453989 h 2.022304 v 0.111044 c 0,0.184689 0.150283,0.333271 0.337016,0.333271 0.186803,0 0.337085,-0.148582 0.337085,-0.333271 v -0.333202 -0.444316 -0.777518 c 0,-0.184688 -0.150282,-0.33327 -0.337085,-0.33327 -0.186733,0 -0.337016,0.148582 -0.337016,0.33327 v 0.26099 L 12.86551,11.365576 V 10.29648 c 0,-0.1208 -0.02529,-0.238828 -0.07304,-0.3499 z" />
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
version="1.1"
id="svg14"
sodipodi:docname="follow.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)">
<metadata
id="metadata20">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs18" />
<sodipodi:namedview
inkscape:document-rotation="0"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview16"
showgrid="false"
inkscape:zoom="12.142857"
inkscape:cx="22.433158"
inkscape:cy="14.663012"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg14" />
<path
d="m 8.6152043,0.96068491 c -0.070984,-0.1658027 -0.2358263,-0.272592 -0.4178212,-0.272592 -0.1818565,0 -0.346698,0.106789 -0.4178225,0.272592 L 6.5262355,3.8523252 C 6.4294515,4.0771272 6.3784085,4.3160075 6.3784085,4.560499 V 6.7242759 L 2.2854009,9.0848093 V 8.5565855 c 0,-0.3737975 -0.304161,-0.6745171 -0.682098,-0.6745171 -0.378076,0 -0.68223699,0.3007196 -0.68223699,0.6745171 v 1.5736425 0.899265 0.674379 c 0,0.373797 0.30416099,0.674518 0.68223699,0.674518 0.377937,0 0.682098,-0.300721 0.682098,-0.674518 v -0.224747 h 4.0930076 v 0.918844 L 4.7156289,13.83966 c -0.09944,0.08425 -0.156335,0.207925 -0.156335,0.337121 v 0.449631 c 0,0.24736 0.204588,0.449631 0.454779,0.449631 h 2.7286708 v -1.798527 c 0,-0.247222 0.2045879,-0.449495 0.4546394,-0.449495 0.2501899,0 0.4547778,0.202273 0.4547778,0.449495 v 1.798527 h 2.7286701 c 0.250191,0 0.454779,-0.202271 0.454779,-0.449631 v -0.449631 c 0,-0.129196 -0.05676,-0.252876 -0.156195,-0.337121 l -1.662919,-1.441691 v -0.918844 h 4.093006 v 0.224747 c 0,0.373797 0.304162,0.674518 0.682098,0.674518 0.378076,0 0.682238,-0.300721 0.682238,-0.674518 V 11.029493 10.130228 8.5565855 c 0,-0.3737975 -0.304162,-0.6745171 -0.682238,-0.6745171 -0.377936,0 -0.682098,0.3007196 -0.682098,0.6745171 V 9.0848093 L 10.016496,6.7242759 V 4.560499 c 0,-0.2444915 -0.051184,-0.4833718 -0.1478275,-0.7081738 z"
fill="#202831"
id="path2"
style="fill:#000000;fill-opacity:1;stroke-width:1.38669" />
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
version="1.1"
id="svg14"
sodipodi:docname="front.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)">
<metadata
id="metadata20">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs18" />
<sodipodi:namedview
inkscape:document-rotation="0"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview16"
showgrid="false"
inkscape:zoom="34.345186"
inkscape:cx="9.7964424"
inkscape:cy="8.7196642"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg14" />
<path
d="m 7.5384925,0.85189343 c 0.03507,-0.0819211 0.116519,-0.13468436 0.20644,-0.13468436 0.08985,0 0.171299,0.0527631 0.206441,0.13468436 l 0.619253,1.42872407 c 0.04782,0.1110719 0.07304,0.2290997 0.07304,0.3498999 V 3.6996131 L 10.665971,4.8659237 V 4.6049348 c 0,-0.1846888 0.150282,-0.3332707 0.337016,-0.3332707 0.186803,0 0.337085,0.1485819 0.337085,0.3332707 V 5.3824522 5.826768 6.1599704 c 0,0.1846885 -0.150282,0.3332711 -0.337085,0.3332711 -0.186734,0 -0.337016,-0.1485826 -0.337016,-0.3332711 V 6.0489257 H 8.6436655 v 0.4539895 l 0.821559,0.7123218 c 0.04913,0.041627 0.07724,0.1027332 0.07724,0.1665674 v 0.2221572 c 0,0.1222175 -0.101084,0.2221571 -0.224701,0.2221571 H 7.9695645 V 6.9374886 c 0,-0.1221494 -0.101085,-0.22209 -0.224632,-0.22209 -0.123616,0 -0.2247,0.099941 -0.2247,0.22209 v 0.8886301 h -1.348203 c -0.123616,0 -0.2247,-0.09994 -0.2247,-0.2221571 V 7.3818044 c 0,-0.063834 0.02804,-0.1249429 0.07717,-0.1665674 L 6.8461315,6.5029152 V 6.0489257 H 4.823827 v 0.1110447 c 0,0.1846885 -0.1502827,0.3332711 -0.3370162,0.3332711 -0.1868027,0 -0.3370854,-0.1485826 -0.3370854,-0.3332711 V 5.826768 5.3824522 4.6049348 c 0,-0.1846888 0.1502827,-0.3332707 0.3370854,-0.3332707 0.1867335,0 0.3370162,0.1485819 0.3370162,0.3332707 V 4.8659237 L 6.8461315,3.6996131 V 2.6305174 c 0,-0.1208002 0.02529,-0.238828 0.07304,-0.3498999 z"
fill="#202831"
id="path2"
style="fill:#000000;fill-opacity:1;stroke-width:0.685147" />
<path
style="fill:#000000;fill-opacity:1;stroke-width:0.685147"
id="path2-4"
fill="#202831"
d="m 7.5417259,8.4887398 c 0.03507,-0.081921 0.116519,-0.1346843 0.206441,-0.1346843 0.08985,0 0.171299,0.052763 0.206441,0.1346843 l 0.619252,1.4287241 c 0.04782,0.1110721 0.07304,0.2291001 0.07304,0.3499001 v 1.069096 l 2.0223041,1.166311 v -0.26099 c 0,-0.184688 0.150282,-0.33327 0.337016,-0.33327 0.186803,0 0.337085,0.148582 0.337085,0.33327 v 0.777518 0.444316 0.333202 c 0,0.184689 -0.150282,0.333271 -0.337085,0.333271 -0.186734,0 -0.337016,-0.148582 -0.337016,-0.333271 V 13.685773 H 8.6468989 v 0.453989 l 0.821559,0.712322 c 0.04913,0.04163 0.07724,0.102733 0.07724,0.166567 v 0.222157 c 0,0.122218 -0.101084,0.222158 -0.2247,0.222158 h -1.348203 v -0.888631 c 0,-0.122149 -0.101084,-0.22209 -0.224631,-0.22209 -0.123616,0 -0.224701,0.09994 -0.224701,0.22209 v 0.888631 h -1.348202 c -0.123616,0 -0.224701,-0.09994 -0.224701,-0.222158 v -0.222157 c 0,-0.06383 0.02804,-0.124943 0.07717,-0.166567 l 0.821635,-0.712322 v -0.453989 h -2.022304 v 0.111044 c 0,0.184689 -0.150283,0.333271 -0.337016,0.333271 -0.186803,0 -0.337085,-0.148582 -0.337085,-0.333271 v -0.333202 -0.444316 -0.777518 c 0,-0.184688 0.150282,-0.33327 0.337085,-0.33327 0.186733,0 0.337016,0.148582 0.337016,0.33327 v 0.26099 l 2.022304,-1.166311 v -1.069096 c 0,-0.1208 0.02529,-0.238828 0.07304,-0.3499001 z" />
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M32 288c-17.7 0-32 14.3-32 32s14.3 32 32 32l384 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L32 288zm0-128c-17.7 0-32 14.3-32 32s14.3 32 32 32l384 0c17.7 0 32-14.3 32-32s-14.3-32-32-32L32 160z"/></svg>

After

Width:  |  Height:  |  Size: 433 B

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
version="1.1"
id="svg14"
sodipodi:docname="line-abreast.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)">
<metadata
id="metadata20">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs18" />
<sodipodi:namedview
inkscape:document-rotation="0"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview16"
showgrid="false"
inkscape:zoom="34.345186"
inkscape:cx="9.7964424"
inkscape:cy="8.7196642"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg14" />
<path
inkscape:transform-center-y="-0.37851011"
inkscape:transform-center-x="-0.37851011"
d="m 3.8116238,3.5888127 c 0.03507,-0.081921 0.116519,-0.1346844 0.20644,-0.1346844 0.08985,0 0.171299,0.052763 0.206441,0.1346844 l 0.619253,1.428724 c 0.04782,0.1110719 0.07304,0.2290997 0.07304,0.3498999 V 6.4365323 L 6.9391023,7.6028429 V 7.341854 c 0,-0.1846888 0.150282,-0.3332707 0.337016,-0.3332707 0.186803,0 0.337085,0.1485819 0.337085,0.3332707 v 0.7775174 0.4443158 0.3332024 c 0,0.1846885 -0.150282,0.3332711 -0.337085,0.3332711 -0.186734,0 -0.337016,-0.1485826 -0.337016,-0.3332711 V 8.7858449 H 4.9167968 v 0.4539895 l 0.821559,0.7123218 c 0.04913,0.041627 0.07724,0.1027328 0.07724,0.1665678 v 0.222157 c 0,0.122217 -0.101084,0.222157 -0.224701,0.222157 H 4.2426958 V 9.6744078 c 0,-0.1221494 -0.101085,-0.22209 -0.224632,-0.22209 -0.123616,0 -0.2247,0.099941 -0.2247,0.22209 v 0.8886302 h -1.348203 c -0.123616,0 -0.2247,-0.09994 -0.2247,-0.222157 v -0.222157 c 0,-0.06383 0.02804,-0.1249433 0.07717,-0.1665678 L 3.1192628,9.2398344 V 8.7858449 H 1.0969583 v 0.1110447 c 0,0.1846885 -0.15028273,0.3332711 -0.33701623,0.3332711 -0.1868027,0 -0.3370854,-0.1485826 -0.3370854,-0.3332711 V 8.5636872 8.1193714 7.341854 c 0,-0.1846888 0.1502827,-0.3332707 0.3370854,-0.3332707 0.1867335,0 0.33701623,0.1485819 0.33701623,0.3332707 V 7.6028429 L 3.1192628,6.4365323 V 5.3674366 c 0,-0.1208002 0.02529,-0.238828 0.07304,-0.3498999 z"
fill="#202831"
id="path2"
style="fill:#000000;fill-opacity:1;stroke-width:0.685147" />
<path
style="fill:#000000;fill-opacity:1;stroke-width:0.685147"
id="path2-4"
fill="#202831"
d="m 11.763569,3.5972246 c 0.03507,-0.081921 0.116519,-0.1346843 0.206441,-0.1346843 0.08985,0 0.171299,0.052763 0.206441,0.1346843 l 0.619252,1.4287241 c 0.04782,0.1110721 0.07304,0.2291001 0.07304,0.3499001 v 1.069096 l 2.022304,1.166311 v -0.26099 c 0,-0.184688 0.150282,-0.33327 0.337016,-0.33327 0.186803,0 0.337085,0.148582 0.337085,0.33327 v 0.777518 0.444316 0.333202 c 0,0.184689 -0.150282,0.333271 -0.337085,0.333271 -0.186734,0 -0.337016,-0.148582 -0.337016,-0.333271 v -0.111044 h -2.022305 v 0.453989 l 0.821559,0.712322 c 0.04913,0.04163 0.07724,0.1027332 0.07724,0.1665672 v 0.222157 c 0,0.122218 -0.101084,0.222158 -0.2247,0.222158 H 12.194638 V 9.6828198 c 0,-0.122149 -0.101084,-0.22209 -0.224631,-0.22209 -0.123616,0 -0.224701,0.09994 -0.224701,0.22209 v 0.8886312 h -1.348202 c -0.123616,0 -0.224701,-0.09994 -0.224701,-0.222158 v -0.222157 c 0,-0.06383 0.02804,-0.124943 0.07717,-0.1665672 l 0.821635,-0.712322 V 8.7942578 H 9.0489044 v 0.111044 c 0,0.184689 -0.150283,0.333271 -0.337016,0.333271 -0.186803,0 -0.337085,-0.148582 -0.337085,-0.333271 v -0.333202 -0.444316 -0.777518 c 0,-0.184688 0.150282,-0.33327 0.337085,-0.33327 0.186733,0 0.337016,0.148582 0.337016,0.33327 v 0.26099 l 2.0223036,-1.166311 v -1.069096 c 0,-0.1208 0.02529,-0.238828 0.07304,-0.3499001 z" />
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
class="svg-icon"
style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;"
viewBox="0 0 1024 1024"
version="1.1"
id="svg6"
sodipodi:docname="sword.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
inkscape:document-rotation="0"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview8"
showgrid="false"
inkscape:zoom="0.83007812"
inkscape:cx="512"
inkscape:cy="512"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg6" />
<path
d="M34.133333 870.4c-17.066667-17.066667-17.066667-42.666667 0-59.733333l194.133334-194.133334-134.4-134.4c-17.066667-17.066667-17.066667-42.666667 0-59.733333 17.066667-17.066667 42.666667-17.066667 59.733333 0l59.733333 59.733333 448-448c10.666667-10.666667 25.6-14.933333 38.4-10.666666l224 44.8c17.066667 4.266667 29.866667 17.066667 34.133334 34.133333L1002.666667 324.266667c2.133333 14.933333-2.133333 27.733333-10.666667 38.4l-448 448 59.733333 59.733333c17.066667 17.066667 17.066667 42.666667 0 59.733333-8.533333 8.533333-19.2 12.8-29.866666 12.8-10.666667 0-21.333333-4.266667-29.866667-12.8l-134.4-134.4-196.266667 194.133334c-8.533333 8.533333-19.2 12.8-29.866666 12.8s-21.333333-4.266667-29.866667-12.8l-119.466667-119.466667z m253.866667-194.133333l-164.266667 164.266666 59.733334 59.733334 164.266666-164.266667-59.733333-59.733333zM706.133333 110.933333L273.066667 541.866667l209.066666 209.066666L913.066667 320l-34.133334-172.8-172.8-36.266667z"
fill="#2F3CF4"
id="path2"
style="fill:#000000;fill-opacity:1" />
<path
style="fill:#000000;fill-opacity:1"
d="M795.733333 288c17.066667-17.066667 17.066667-42.666667 0-59.733333s-42.666667-17.066667-59.733333 0L422.4 541.866667c-17.066667 17.066667-17.066667 42.666667 0 59.733333 8.533333 8.533333 19.2 12.8 29.866667 12.8 10.666667 0 21.333333-4.266667 29.866666-12.8l313.6-313.6z"
fill="#FFFFFF"
id="path4" />
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
version="1.1"
id="svg14"
sodipodi:docname="trail.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)">
<metadata
id="metadata20">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs18" />
<sodipodi:namedview
inkscape:document-rotation="0"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview16"
showgrid="false"
inkscape:zoom="34.345186"
inkscape:cx="9.7964424"
inkscape:cy="8.7196642"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg14" />
<path
d="m 7.5384925,0.85189343 c 0.03507,-0.0819211 0.116519,-0.13468436 0.20644,-0.13468436 0.08985,0 0.171299,0.0527631 0.206441,0.13468436 l 0.619253,1.42872407 c 0.04782,0.1110719 0.07304,0.2290997 0.07304,0.3498999 V 3.6996131 L 10.665971,4.8659237 V 4.6049348 c 0,-0.1846888 0.150282,-0.3332707 0.337016,-0.3332707 0.186803,0 0.337085,0.1485819 0.337085,0.3332707 V 5.3824522 5.826768 6.1599704 c 0,0.1846885 -0.150282,0.3332711 -0.337085,0.3332711 -0.186734,0 -0.337016,-0.1485826 -0.337016,-0.3332711 V 6.0489257 H 8.6436655 v 0.4539895 l 0.821559,0.7123218 c 0.04913,0.041627 0.07724,0.1027332 0.07724,0.1665674 v 0.2221572 c 0,0.1222175 -0.101084,0.2221571 -0.224701,0.2221571 H 7.9695645 V 6.9374886 c 0,-0.1221494 -0.101085,-0.22209 -0.224632,-0.22209 -0.123616,0 -0.2247,0.099941 -0.2247,0.22209 v 0.8886301 h -1.348203 c -0.123616,0 -0.2247,-0.09994 -0.2247,-0.2221571 V 7.3818044 c 0,-0.063834 0.02804,-0.1249429 0.07717,-0.1665674 L 6.8461315,6.5029152 V 6.0489257 H 4.823827 v 0.1110447 c 0,0.1846885 -0.1502827,0.3332711 -0.3370162,0.3332711 -0.1868027,0 -0.3370854,-0.1485826 -0.3370854,-0.3332711 V 5.826768 5.3824522 4.6049348 c 0,-0.1846888 0.1502827,-0.3332707 0.3370854,-0.3332707 0.1867335,0 0.3370162,0.1485819 0.3370162,0.3332707 V 4.8659237 L 6.8461315,3.6996131 V 2.6305174 c 0,-0.1208002 0.02529,-0.238828 0.07304,-0.3498999 z"
fill="#202831"
id="path2"
style="fill:#000000;fill-opacity:1;stroke-width:0.685147" />
<path
style="fill:#000000;fill-opacity:1;stroke-width:0.685147"
id="path2-4"
fill="#202831"
d="m 7.5417259,8.4887398 c 0.03507,-0.081921 0.116519,-0.1346843 0.206441,-0.1346843 0.08985,0 0.171299,0.052763 0.206441,0.1346843 l 0.619252,1.4287241 c 0.04782,0.1110721 0.07304,0.2291001 0.07304,0.3499001 v 1.069096 l 2.0223041,1.166311 v -0.26099 c 0,-0.184688 0.150282,-0.33327 0.337016,-0.33327 0.186803,0 0.337085,0.148582 0.337085,0.33327 v 0.777518 0.444316 0.333202 c 0,0.184689 -0.150282,0.333271 -0.337085,0.333271 -0.186734,0 -0.337016,-0.148582 -0.337016,-0.333271 V 13.685773 H 8.6468989 v 0.453989 l 0.821559,0.712322 c 0.04913,0.04163 0.07724,0.102733 0.07724,0.166567 v 0.222157 c 0,0.122218 -0.101084,0.222158 -0.2247,0.222158 h -1.348203 v -0.888631 c 0,-0.122149 -0.101084,-0.22209 -0.224631,-0.22209 -0.123616,0 -0.224701,0.09994 -0.224701,0.22209 v 0.888631 h -1.348202 c -0.123616,0 -0.224701,-0.09994 -0.224701,-0.222158 v -0.222157 c 0,-0.06383 0.02804,-0.124943 0.07717,-0.166567 l 0.821635,-0.712322 v -0.453989 h -2.022304 v 0.111044 c 0,0.184689 -0.150283,0.333271 -0.337016,0.333271 -0.186803,0 -0.337085,-0.148582 -0.337085,-0.333271 v -0.333202 -0.444316 -0.777518 c 0,-0.184688 0.150282,-0.33327 0.337085,-0.33327 0.186733,0 0.337016,0.148582 0.337016,0.33327 v 0.26099 l 2.022304,-1.166311 v -1.069096 c 0,-0.1208 0.02529,-0.238828 0.07304,-0.3499001 z" />
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M170.5 51.6L151.5 80h145l-19-28.4c-1.5-2.2-4-3.6-6.7-3.6H177.1c-2.7 0-5.2 1.3-6.7 3.6zm147-26.6L354.2 80H368h48 8c13.3 0 24 10.7 24 24s-10.7 24-24 24h-8V432c0 44.2-35.8 80-80 80H112c-44.2 0-80-35.8-80-80V128H24c-13.3 0-24-10.7-24-24S10.7 80 24 80h8H80 93.8l36.7-55.1C140.9 9.4 158.4 0 177.1 0h93.7c18.7 0 36.2 9.4 46.6 24.9zM80 128V432c0 17.7 14.3 32 32 32H336c17.7 0 32-14.3 32-32V128H80zm80 64V400c0 8.8-7.2 16-16 16s-16-7.2-16-16V192c0-8.8 7.2-16 16-16s16 7.2 16 16zm80 0V400c0 8.8-7.2 16-16 16s-16-7.2-16-16V192c0-8.8 7.2-16 16-16s16 7.2 16 16zm80 0V400c0 8.8-7.2 16-16 16s-16-7.2-16-16V192c0-8.8 7.2-16 16-16s16 7.2 16 16z"/></svg>

After

Width:  |  Height:  |  Size: 875 B

View File

@@ -0,0 +1,370 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="reference-system-test.svg"
id="svg8"
version="1.1"
viewBox="0 0 232.62689 109.65005"
height="109.65005mm"
width="232.62689mm">
<defs
id="defs2">
<marker
inkscape:stockid="TriangleOutM"
orient="auto"
refY="0.0"
refX="0.0"
id="marker3764"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path3762"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
style="fill-rule:evenodd;stroke:#00fff1;stroke-width:1pt;stroke-opacity:1;fill:#00fffb;fill-opacity:1"
transform="scale(0.4)" />
</marker>
<marker
inkscape:stockid="TriangleOutM"
orient="auto"
refY="0.0"
refX="0.0"
id="marker3754"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path3752"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
style="fill-rule:evenodd;stroke:#00fff1;stroke-width:1pt;stroke-opacity:1;fill:#00fffb;fill-opacity:1"
transform="scale(0.4)" />
</marker>
<marker
inkscape:stockid="Arrow2Send"
orient="auto"
refY="0.0"
refX="0.0"
id="marker3658"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path3656"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#00fff1;stroke-opacity:1;fill:#00fffb;fill-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(0.3) rotate(180) translate(-2.3,0)" />
</marker>
<marker
inkscape:stockid="Arrow2Send"
orient="auto"
refY="0.0"
refX="0.0"
id="marker3648"
style="overflow:visible;"
inkscape:isstock="true">
<path
id="path3646"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#00fff1;stroke-opacity:1;fill:#00fffb;fill-opacity:1"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(0.3) rotate(180) translate(-2.3,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="Arrow2Mend"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mend">
<path
transform="scale(-0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path1088" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="Arrow2Lend"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lend">
<path
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path1082" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="Arrow1Lend"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1064" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend-7"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path1088-1"
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="Arrow2Mend-7-8"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mend">
<path
transform="scale(-0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path1088-1-6" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend-7-8-0"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path1088-1-6-8"
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)" />
</marker>
</defs>
<sodipodi:namedview
inkscape:window-maximized="1"
inkscape:window-y="-8"
inkscape:window-x="1912"
inkscape:window-height="1017"
inkscape:window-width="1920"
fit-margin-bottom="0"
fit-margin-right="0"
fit-margin-left="0"
fit-margin-top="0"
showgrid="false"
inkscape:document-rotation="0"
inkscape:current-layer="layer1"
inkscape:document-units="mm"
inkscape:cy="180.46845"
inkscape:cx="179.92513"
inkscape:zoom="0.70710678"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(-9.0472264,-0.3638854)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<g
transform="matrix(2.7166059,0,0,2.7166059,6.5450533,19.640703)"
id="g839"
style="fill:none">
<path
d="m 8.6152043,0.96068491 c -0.070984,-0.1658027 -0.2358263,-0.272592 -0.4178212,-0.272592 -0.1818565,0 -0.346698,0.106789 -0.4178225,0.272592 L 6.5262355,3.8523252 C 6.4294515,4.0771272 6.3784085,4.3160075 6.3784085,4.560499 V 6.7242759 L 2.2854009,9.0848093 V 8.5565855 c 0,-0.3737975 -0.304161,-0.6745171 -0.682098,-0.6745171 -0.378076,0 -0.68223699,0.3007196 -0.68223699,0.6745171 v 1.5736425 0.899265 0.674379 c 0,0.373797 0.30416099,0.674518 0.68223699,0.674518 0.377937,0 0.682098,-0.300721 0.682098,-0.674518 v -0.224747 h 4.0930076 v 0.918844 L 4.7156289,13.83966 c -0.09944,0.08425 -0.156335,0.207925 -0.156335,0.337121 v 0.449631 c 0,0.24736 0.204588,0.449631 0.454779,0.449631 h 2.7286708 v -1.798527 c 0,-0.247222 0.2045879,-0.449495 0.4546394,-0.449495 0.2501899,0 0.4547778,0.202273 0.4547778,0.449495 v 1.798527 h 2.7286701 c 0.250191,0 0.454779,-0.202271 0.454779,-0.449631 v -0.449631 c 0,-0.129196 -0.05676,-0.252876 -0.156195,-0.337121 l -1.662919,-1.441691 v -0.918844 h 4.093006 v 0.224747 c 0,0.373797 0.304162,0.674518 0.682098,0.674518 0.378076,0 0.682238,-0.300721 0.682238,-0.674518 V 11.029493 10.130228 8.5565855 c 0,-0.3737975 -0.304162,-0.6745171 -0.682238,-0.6745171 -0.377936,0 -0.682098,0.3007196 -0.682098,0.6745171 V 9.0848093 L 10.016496,6.7242759 V 4.560499 c 0,-0.2444915 -0.051184,-0.4833718 -0.1478275,-0.7081738 z"
fill="#202831"
id="path2"
style="fill:#000000;fill-opacity:1;stroke-width:1.38669" />
</g>
<g
style="fill:none"
id="g839-2"
transform="matrix(2.7166059,0,0,2.7166059,59.782498,69.058264)">
<path
style="fill:#000000;fill-opacity:1;stroke-width:1.38669"
id="path2-3"
fill="#202831"
d="m 8.6152043,0.96068491 c -0.070984,-0.1658027 -0.2358263,-0.272592 -0.4178212,-0.272592 -0.1818565,0 -0.346698,0.106789 -0.4178225,0.272592 L 6.5262355,3.8523252 C 6.4294515,4.0771272 6.3784085,4.3160075 6.3784085,4.560499 V 6.7242759 L 2.2854009,9.0848093 V 8.5565855 c 0,-0.3737975 -0.304161,-0.6745171 -0.682098,-0.6745171 -0.378076,0 -0.68223699,0.3007196 -0.68223699,0.6745171 v 1.5736425 0.899265 0.674379 c 0,0.373797 0.30416099,0.674518 0.68223699,0.674518 0.377937,0 0.682098,-0.300721 0.682098,-0.674518 v -0.224747 h 4.0930076 v 0.918844 L 4.7156289,13.83966 c -0.09944,0.08425 -0.156335,0.207925 -0.156335,0.337121 v 0.449631 c 0,0.24736 0.204588,0.449631 0.454779,0.449631 h 2.7286708 v -1.798527 c 0,-0.247222 0.2045879,-0.449495 0.4546394,-0.449495 0.2501899,0 0.4547778,0.202273 0.4547778,0.449495 v 1.798527 h 2.7286701 c 0.250191,0 0.454779,-0.202271 0.454779,-0.449631 v -0.449631 c 0,-0.129196 -0.05676,-0.252876 -0.156195,-0.337121 l -1.662919,-1.441691 v -0.918844 h 4.093006 v 0.224747 c 0,0.373797 0.304162,0.674518 0.682098,0.674518 0.378076,0 0.682238,-0.300721 0.682238,-0.674518 V 11.029493 10.130228 8.5565855 c 0,-0.3737975 -0.304162,-0.6745171 -0.682238,-0.6745171 -0.377936,0 -0.682098,0.3007196 -0.682098,0.6745171 V 9.0848093 L 10.016496,6.7242759 V 4.560499 c 0,-0.2444915 -0.051184,-0.4833718 -0.1478275,-0.7081738 z" />
</g>
<circle
r="0"
style="fill:#000000;fill-opacity:1;stroke-width:0.225344;stroke-linecap:round"
id="path865-3"
cx="29.19866"
cy="80.130951" />
<g
transform="translate(140.21868,-45.703089)"
id="g1019">
<circle
style="fill:#000000;fill-opacity:1;stroke-width:0.0680267;stroke-linecap:round"
id="path859"
cx="29.259609"
cy="85.105995"
r="4.9218788" />
<rect
style="fill:#000000;fill-opacity:1;stroke-width:0.122238;stroke-linecap:round"
id="rect861"
width="39.215027"
height="1.5119048"
x="9.5438986"
y="84.477676"
ry="0.42838952" />
<circle
style="fill:#000000;fill-opacity:1;stroke-width:0.122238;stroke-linecap:round"
id="path865"
cx="10.866816"
cy="85.139137"
r="1.5119048" />
<circle
r="1.5119048"
cy="85.139137"
cx="48.097469"
id="path865-5"
style="fill:#000000;fill-opacity:1;stroke-width:0.122238;stroke-linecap:round" />
<rect
style="fill:#000000;fill-opacity:1;stroke-width:0.122238;stroke-linecap:round"
id="rect888"
width="1.0394346"
height="5.1971726"
x="28.726191"
y="73.232887"
ry="0.42838952" />
<rect
ry="0.35266024"
y="82.231239"
x="19.213385"
height="1.2446353"
width="19.704351"
id="rect861-3"
style="fill:#000000;fill-opacity:1;stroke-width:0.0786176;stroke-linecap:round" />
<circle
style="fill:#000000;fill-opacity:1;stroke-width:0.212007;stroke-linecap:round"
id="path865-5-8"
cx="29.175037"
cy="80.674294"
r="2.6222098" />
</g>
<g
id="g1019-5"
transform="translate(192.06475,5.3360099)">
<circle
r="4.9218788"
cy="85.105995"
cx="29.259609"
id="path859-5"
style="fill:#000000;fill-opacity:1;stroke-width:0.0680267;stroke-linecap:round" />
<rect
ry="0.42838952"
y="84.477676"
x="9.5438986"
height="1.5119048"
width="39.215027"
id="rect861-1"
style="fill:#000000;fill-opacity:1;stroke-width:0.122238;stroke-linecap:round" />
<circle
r="1.5119048"
cy="85.139137"
cx="10.866816"
id="path865-6"
style="fill:#000000;fill-opacity:1;stroke-width:0.122238;stroke-linecap:round" />
<circle
style="fill:#000000;fill-opacity:1;stroke-width:0.122238;stroke-linecap:round"
id="path865-5-6"
cx="48.097469"
cy="85.139137"
r="1.5119048" />
<rect
ry="0.42838952"
y="73.232887"
x="28.726191"
height="5.1971726"
width="1.0394346"
id="rect888-2"
style="fill:#000000;fill-opacity:1;stroke-width:0.122238;stroke-linecap:round" />
<rect
style="fill:#000000;fill-opacity:1;stroke-width:0.0786176;stroke-linecap:round"
id="rect861-3-0"
width="19.704351"
height="1.2446353"
x="19.213385"
y="82.231239"
ry="0.35266024" />
<circle
r="2.6222098"
cy="80.674294"
cx="29.175037"
id="path865-5-8-9"
style="fill:#000000;fill-opacity:1;stroke-width:0.212007;stroke-linecap:round" />
</g>
<path
style="fill:none;fill-opacity:1;stroke:#00fff1;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3754)"
d="m 28.820683,45.262649 46.641256,42.10261"
id="path1059-0"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
id="path1059-0-0"
d="M 169.40181,40.337642 V 90.041518"
style="fill:#00fffb;fill-opacity:1;stroke:#00fff1;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3764)" />
<text
xml:space="preserve"
style="font-size:16.5205px;line-height:1.25;font-family:sans-serif;fill:#00fffb;fill-opacity:1;stroke:#00fff1;stroke-width:0.619518;stroke-opacity:1"
x="148.62083"
y="97.970039"
id="text2102-4"><tspan
sodipodi:role="line"
id="tspan2100-0"
x="148.62083"
y="97.970039"
style="font-size:16.5205px;fill:#00fffb;fill-opacity:1;stroke:#00fff1;stroke-width:0.619518;stroke-opacity:1">+</tspan></text>
<path
sodipodi:open="true"
d="m 30.431293,14.137878 a 29.450657,29.450657 0 0 1 27.20886,18.180379 29.450657,29.450657 0 0 1 -6.3841,32.095037"
sodipodi:arc-type="arc"
sodipodi:end="0.78539816"
sodipodi:start="4.712389"
sodipodi:ry="29.450657"
sodipodi:rx="29.450657"
sodipodi:cy="43.588535"
sodipodi:cx="30.431293"
sodipodi:type="arc"
id="path3121"
style="fill:none;fill-opacity:1;stroke:#00fff1;stroke-width:3;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:none;fill-opacity:1;stroke:#00fff1;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 28.820683,1.8638854 V 45.262649"
id="path1059-0-0-2"
sodipodi:nodetypes="cc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -0,0 +1,218 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="reference-system.svg"
id="svg8"
version="1.1"
viewBox="0 0 13.229166 13.229167"
height="50"
width="50">
<defs
id="defs2">
<marker
inkscape:stockid="TriangleOutM"
orient="auto"
refY="0"
refX="0"
id="marker3764"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path3762"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:1pt;stroke-opacity:1"
transform="scale(0.4)" />
</marker>
<marker
inkscape:stockid="TriangleOutM"
orient="auto"
refY="0"
refX="0"
id="marker3754"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path3752"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#00fff1;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:1pt;stroke-opacity:1"
transform="scale(0.4)" />
</marker>
<marker
inkscape:stockid="Arrow2Send"
orient="auto"
refY="0"
refX="0"
id="marker3658"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path3656"
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-0.3,0,0,-0.3,0.69,0)" />
</marker>
<marker
inkscape:stockid="Arrow2Send"
orient="auto"
refY="0"
refX="0"
id="marker3648"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path3646"
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-0.3,0,0,-0.3,0.69,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="Arrow2Mend"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mend">
<path
transform="scale(-0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path1088" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="Arrow2Lend"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lend">
<path
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path1082" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="Arrow1Lend"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1064" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend-7"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path1088-1"
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="Arrow2Mend-7-8"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mend">
<path
transform="scale(-0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path1088-1-6" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend-7-8-0"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path1088-1-6-8"
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)" />
</marker>
</defs>
<sodipodi:namedview
units="px"
inkscape:window-maximized="1"
inkscape:window-y="-8"
inkscape:window-x="1912"
inkscape:window-height="1017"
inkscape:window-width="1920"
fit-margin-bottom="0"
fit-margin-right="0"
fit-margin-left="0"
fit-margin-top="0"
showgrid="false"
inkscape:document-rotation="0"
inkscape:current-layer="layer1"
inkscape:document-units="mm"
inkscape:cy="24.946043"
inkscape:cx="23.906148"
inkscape:zoom="11.313708"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(-9.0472264,-21.50998)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<g
transform="matrix(0.90904788,0,0,0.91946153,8.2333194,20.900691)"
id="g839"
style="fill:none">
<path
d="m 8.6152043,0.96068491 c -0.070984,-0.1658027 -0.2358263,-0.272592 -0.4178212,-0.272592 -0.1818565,0 -0.346698,0.106789 -0.4178225,0.272592 L 6.5262355,3.8523252 C 6.4294515,4.0771272 6.3784085,4.3160075 6.3784085,4.560499 V 6.7242759 L 2.2854009,9.0848093 V 8.5565855 c 0,-0.3737975 -0.304161,-0.6745171 -0.682098,-0.6745171 -0.378076,0 -0.68223699,0.3007196 -0.68223699,0.6745171 v 1.5736425 0.899265 0.674379 c 0,0.373797 0.30416099,0.674518 0.68223699,0.674518 0.377937,0 0.682098,-0.300721 0.682098,-0.674518 v -0.224747 h 4.0930076 v 0.918844 L 4.7156289,13.83966 c -0.09944,0.08425 -0.156335,0.207925 -0.156335,0.337121 v 0.449631 c 0,0.24736 0.204588,0.449631 0.454779,0.449631 h 2.7286708 v -1.798527 c 0,-0.247222 0.2045879,-0.449495 0.4546394,-0.449495 0.2501899,0 0.4547778,0.202273 0.4547778,0.449495 v 1.798527 h 2.7286701 c 0.250191,0 0.454779,-0.202271 0.454779,-0.449631 v -0.449631 c 0,-0.129196 -0.05676,-0.252876 -0.156195,-0.337121 l -1.662919,-1.441691 v -0.918844 h 4.093006 v 0.224747 c 0,0.373797 0.304162,0.674518 0.682098,0.674518 0.378076,0 0.682238,-0.300721 0.682238,-0.674518 V 11.029493 10.130228 8.5565855 c 0,-0.3737975 -0.304162,-0.6745171 -0.682238,-0.6745171 -0.377936,0 -0.682098,0.3007196 -0.682098,0.6745171 V 9.0848093 L 10.016496,6.7242759 V 4.560499 c 0,-0.2444915 -0.051184,-0.4833718 -0.1478275,-0.7081738 z"
fill="#202831"
id="path2"
style="fill:#000000;fill-opacity:1;stroke-width:1.38669" />
</g>
<circle
r="0"
style="fill:#000000;fill-opacity:1;stroke-width:0.225344;stroke-linecap:round"
id="path865-3"
cx="29.19866"
cy="80.130951" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@@ -1,211 +1,195 @@
/*** Control panel ***/
#atc-control-panel {
align-self: flex-end;
background: white;
border-radius: 10px;
display:flex;
margin: 0 0 50px 100px;
padding:5px;
position: absolute;
z-index: 9999;
}
.atc-tool {
align-self: center;
border-radius: 10px;
display:none;
justify-self: center;
padding: 10px;
position: absolute;
z-index: 9999;
}
.atc-enabled .atc-tool {
display:flex;
}
#atc-flight-list {
flex-direction: column;
}
#atc-flight-list table {
color:white;
}
#atc-flight-list table td {
padding:0 10px;
text-align: center;
}
#atc-flight-list table td:first-of-type {
text-align: left;
}
#atc-flight-list table tr[data-status='checkedIn'] td {
background-color:goldenrod;
}
#atc-flight-list table tr[data-status='readyToTaxi'] td {
background-color:darkgreen;
}
#atc-flight-list table button {
background-color: #666;
border:1px solid white;
color:white;
font-weight: bold;
margin:2px 0;
}
.atc-strip-board {
align-self: center;
display:flex;
justify-self: center;
position: absolute;
z-index: 9999 ;
}
.atc-strip-board-header {
display:none;
}
.atc-strip-board-strips {
.ol-strip-board-strips {
display:flex;
flex-direction: column;
row-gap: 4px;
}
.atc-strip-board-strip {
display:flex;
flex-direction: row;
}
/*
.atc-strip-board-header {
background:black;
color:white;
display:none;
justify-content: right;
}
.atc-strip-board {
display:flex;
flex-direction: column;
row-gap: 5px;
}
.atc-strip-board-strips {
display:flex;
flex-direction: column;
padding:10px;
row-gap: 5px;
}
.atc-strip-board-strips > div {
.ol-strip-board-strip {
align-items: center;
border-radius: var( --border-radius-sm );
column-gap: 4px;
display:flex;
flex-flow: row nowrap;
row-gap:4px;
}
.ol-strip-board-strip[data-flight-status="checkedin"] {
background-color: #ffffff2A;
}
.ol-strip-board-strip[data-flight-status="readytotaxi"] {
background-color: #ffff0063;
}
.ol-strip-board-strip[data-flight-status="clearedtotaxi"] {
background-color: #00ff0030;
}
.ol-strip-board-strip[data-flight-status="halted"] {
background-color: #FF000040;
}
.ol-strip-board-strip[data-flight-status="terminated"] {
background-color: black;
}
.ol-strip-board-headers {
column-gap: 4px;
display:flex;
flex-flow:row nowrap;
text-align: center;
}
.ol-strip-board-headers > *, .ol-strip-board-strip > [data-point] {
padding: 4px;
text-overflow: ellipsis;
white-space: nowrap;
width:80px;
}
.ol-strip-board-strip input[type="text"] {
appearance: none;
background-color: transparent;
border:1px solid #ffffff30;
border-radius: var( --border-radius-sm );
color:white;
column-gap: 2px;
display: flex;
flex-direction: row;
padding: 5px;
}
.atc-strip-board-header > div, .atc-strip-board-strips > div > div {
text-align: center;
width: 75px;
}
.atc-strip-board-header > .name {
width:150px;
}
.atc-strip-board-header > div, .atc-strip-board-strips > div > div {
text-align: center;
width: 75px;
}
.atc-strip-board-strips > div > .name {
text-align: left;
width:150px;
}
.atc-strip-board-strips > div {
align-items: center;
column-gap: 5px;
display: flex;
flex-direction: row;
font-size:12px;
font-weight: 600;
padding: 5px;
row-gap: 5px;
}
/*
.atc-strip-board-header, .atc-strip-board-strips > div {
align-items: center;
background:#FFF3;
color:white;
column-gap: 5px;
display: flex;
flex-direction: row;
font-size:12px;
font-weight: 600;
padding: 5px;
row-gap: 5px;
}
.atc-strip-board-header {
background:black;
color:white;
display:none;
justify-content: right;
}
.atc-strip-board-strips > div {
border-bottom:1px solid black;
}
.atc-strip-board-header > div, .atc-strip-board-strips > div > div {
font-weight:normal;
outline:none;
padding: 4px 0;
text-align: center;
width: 75px;
width:100%;
}
.atc-strip-board-header > .name {
width:150px;
.ol-strip-board-strip[data-time-warning="level-1"] [data-point="timeToGo"] {
border:1px solid #cc0000;
}
.atc-strip-board-strips > div > .handle {
background: black;
border-radius: 50%;
cursor:grab;
height:10px;
width:10px;
.ol-strip-board-headers :nth-child(1) {
width:12px;
}
.atc-strip-board-strips > div > .name {
.ol-strip-board-headers :nth-child(2),
.ol-strip-board-strip :nth-child(2),
[data-board-type="ground"] .ol-strip-board-headers :nth-child(3),
[data-board-type="ground"] .ol-strip-board-strip :nth-child(3) {
width:130px;
}
[data-board-type="ground"] .ol-strip-board-strip :nth-child(5) {
text-align: center;
}
.ol-strip-board-headers :last-child,
.ol-strip-board-strip :last-child {
width:20px;
}
[data-board-type="tower"] .ol-strip-board-strip > * {
text-align: center;
}
[data-board-type="tower"] .ol-strip-board-strip a {
color:white;
}
[data-board-type="tower"] .ol-strip-board-strip > :nth-child(2) {
text-align: left;
width:150px;
}
.atc-strip-board-strips > div > .warning {
background:red;
color: white;
font-weight: bold;
[data-board-type="tower"] .ol-strip-board-strip :nth-child(3) input,
[data-board-type="tower"] .ol-strip-board-strip :nth-child(5) input {
width:30px;
}
.atc-strip-board-strips > div > .link-warning {
border: 1px solid red;
color: red;
font-weight: bold;
[data-board-type="tower"] .ol-strip-board-strip :nth-child(3) {
font-size:10px;
}
*/
[data-altitude-assigned] [data-point="assignedAltitude"] input,
[data-speed-assigned] [data-point="assignedSpeed"] input {
background-color:#ffffffbb;
color: black;
font-weight: var( --font-weight-bolder );
}
[data-warning-altitude] [data-point="altitude"],
[data-warning-speed] [data-point="speed"] {
background:#cc0000;
border-radius: var( --border-radius-sm );
}
.ol-strip-board-strip > [data-point="name"] {
text-overflow: ellipsis;
overflow:hidden;
}
.ol-strip-board-strip .ol-select-value {
opacity: .85;
}
.ol-strip-board-add-flight {
display:flex;
flex-flow: row nowrap;
position:relative;
}
.ol-strip-board-add-flight > * {
border:none;
outline: none;
padding:4px 8px;
}
.add-flight-by-click img {
filter:invert();
height: 12px;
}
.ol-strip-board-add-flight input {
border-radius: var( --border-radius-sm );
}
.ol-strip-board-add-flight .ol-auto-suggest {
background:white;
border-radius: var(--border-radius-sm );
color:black;
display:none;
flex-direction: column;
left:0;
margin:0;
position:absolute;
translate:0 -100%;
top:0;
}
.ol-strip-board-add-flight .ol-auto-suggest[data-has-suggestions] {
display:flex;
}
.ol-strip-board-add-flight .ol-auto-suggest[data-has-suggestions] a {
cursor: pointer;
}
[data-board-type="ground"] {
bottom:20px;
}
[data-board-type="tower"] {
right:10px;
top:10px;
}

View File

@@ -5,7 +5,7 @@
position: absolute;
row-gap: 5px;
width: 230px;
z-index: 1000;
z-index: 9999;
}
#aircraft-spawn-menu {
@@ -70,8 +70,6 @@
align-self: stretch;
}
#aircraft-spawn-menu .ol-select.is-open .ol-select-options {
max-height: 300px;
}
@@ -131,6 +129,16 @@
background-color: var(--primary-red)
}
[data-active-coalition="neutral"].toggle-fill,
[data-active-coalition="neutral"].unit-spawn-button:hover,
[data-active-coalition="neutral"].unit-spawn-button.is-open,
[data-active-coalition="neutral"]#active-coalition-label,
[data-active-coalition="neutral"].deploy-unit-button,
[data-active-coalition="neutral"]#spawn-airbase-aircraft-button
{
background-color: var(--primary-neutral)
}
[data-active-coalition="blue"].deploy-unit-button:disabled {
background-color: transparent;
border: 1px solid var(--primary-blue);
@@ -141,6 +149,21 @@
border: 1px solid var(--primary-red);
cursor: default;
}
[data-active-coalition="neutral"].deploy-unit-button:disabled {
background-color: transparent;
border: 1px solid var(--primary-neutral);
cursor: default;
}
[data-active-coalition="blue"].toggle-fill::after {
transform: translateX(0);
}
[data-active-coalition="red"].toggle-fill::after {
transform: translateX(var(--height));
}
[data-active-coalition="neutral"].toggle-fill::after {
transform: translateX(calc(var(--height) / 2));
}
[data-active-coalition="blue"]#active-coalition-label::after {
content: "Create blue unit";
@@ -148,6 +171,9 @@
[data-active-coalition="red"]#active-coalition-label::after {
content: "Create red unit";
}
[data-active-coalition="neutral"]#active-coalition-label::after {
content: "Create neutral unit";
}
#loadout-preview {
display: flex;
@@ -167,6 +193,7 @@
#unit-image {
width: 100px;
height: 100px;
filter: invert(100%);
margin-top: 10px;
margin-bottom: 10px;
@@ -207,10 +234,117 @@
display: flex;
flex-direction: column;
height: fit-content;
width: fit-content;
position: absolute;
row-gap: 5px;
width: 150px;
z-index: 1000;
padding: 15px;
}
#unit-contextmenu button {
border: 1px solid var(--background-offwhite);
border-radius: var(--border-radius-sm);
padding: 12px;
font-weight: normal;
}
#unit-contextmenu div {
display: flex;
flex-direction: row;
align-content: center;
}
#unit-contextmenu div:before {
display: inline-block;
filter: invert(100%);
height: 16px;
margin-right: 15px;
width: 16px;
}
#center-map::before {
content: url( /images/icons/arrows-to-eye-solid.svg );
}
#refuel::before {
content: url( /images/icons/fuel.svg );
}
#attack::before {
content: url( /images/icons/sword.svg );
}
#follow::before {
content: url( /images/icons/follow.svg );
}
#trail::before {
content: url( /images/icons/trail.svg );
}
#echelon-lh::before {
content: url( /images/icons/echelon-lh.svg );
}
#echelon-rh::before {
content: url( /images/icons/echelon-rh.svg );
}
#line-abreast::before {
content: url( /images/icons/line-abreast.svg );
}
#front::before {
content: url( /images/icons/front.svg );
}
#custom::before {
content: url( /images/icons/custom.svg );
}
#custom-formation-dialog {
width: 250px;
}
#custom-formation-dialog > .ol-dialog-content {
margin-top: 10px;
margin-bottom: 10px;
display: flex;
flex-direction: column;
flex-wrap: nowrap;
row-gap: 10px;
align-items: center;
}
#custom-formation-dialog > .ol-dialog-content > .ol-group {
width: 100%;
justify-content: space-between;
}
#reference-system {
content: url( /images/reference-system.svg );
display: inline-block;
filter: invert(100%);
width: 50px;
transform: translate(-50%, -50%);
position: absolute;
}
.formation-position-clock {
position: relative;
height: 100px;
width: 100px;
margin: 15px;
}
.formation-position-clock > .clock-hand {
transform: translate(-50%, -50%);
display: flex;
position: absolute;
align-items: center;
justify-content: center;
height: 20px;
width: 20px;
}
/* Airbase context menu */
@@ -222,4 +356,39 @@
row-gap: 5px;
width: 180px;
z-index: 1000;
}
}
.toggle {
--width: 40px;
--height: calc(var(--width) / 2);
--border-radius: calc(var(--height) / 2);
display: inline-block;
cursor: pointer;
}
.toggle-input {
display: none;
}
.toggle-fill {
position: relative;
width: var(--width);
height: var(--height);
border-radius: var(--border-radius);
transition: background-color 0.2s;
}
.toggle-fill::after {
content: "";
position: absolute;
top: 2;
left: 2;
height: calc(var(--height) - 4px);
width: calc(var(--height) - 4px);
background-color: #ffffff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.25);
border-radius: var(--border-radius);
transition: transform 0.2s;
}

View File

@@ -1,4 +1,3 @@
/* Page style */
#map-container {
height: 100%;
@@ -7,6 +6,8 @@
}
#primary-toolbar {
align-items: center;
display:flex;
position: absolute;
left: 10px;
top: 10px;
@@ -14,32 +15,31 @@
}
#olympus-toolbar-summary {
background-image: url( "/images/icon-round.png" );
background-position: 25px 20px;
background-image: url("/images/icon-round.png");
background-position: 20px 22px;
background-repeat: no-repeat;
background-size:36px 36px;
background-size: 45px 45px;
display: flex;
flex-direction: column;
text-indent: 44px;
text-indent: 60px;
padding: 20px;
}
dl.ol-data-grid {
align-items: center;
display:flex;
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin:0;
margin: 0;
row-gap: 4px;
}
dl.ol-data-grid dt {
width:60%;
width: 60%;
}
dl.ol-data-grid dd {
width:40%;
width: 40%;
}
@@ -48,24 +48,23 @@ dl.ol-data-grid dt.icon {
}
dl.ol-data-grid dt.icon::before {
content: url( /images/icons/speed.svg );
display:inline-block;
filter:invert(100%);
content: url(/images/icons/speed.svg );
display: inline-block;
filter: invert(100%);
width: 20px;
translate:-20px 2px;
translate: -20px 2px;
}
dl.ol-data-grid dt.icon-speed::before {
content: url( /images/icons/speed.svg );
content: url(/images/icons/speed.svg );
}
dl.ol-data-grid dt.icon-altitude::before {
content: url( /images/icons/altitude.svg );
content: url(/images/icons/altitude.svg );
}
dl.ol-data-grid dd {
display: flex;
justify-content: flex-end;
@@ -73,59 +72,53 @@ dl.ol-data-grid dd {
}
.br-info::after {
content: attr( data-bearing ) '\00B0 / ' attr( data-distance ) attr( data-distance-units );
content: attr(data-bearing) '\00B0 / ' attr(data-distance) attr(data-distance-units);
}
.br-info[data-message]::after {
content: attr( data-message );
content: attr(data-message);
}
.coordinates::after {
content: attr( data-dd ) "\00b0 " attr( data-mm ) "'" attr( data-ss ) "." attr( data-sss ) '"' attr( data-label );
content: attr(data-dd) "\00b0 " attr(data-mm) "'" attr(data-ss) "." attr(data-sss) '"' attr(data-label);
}
.ol-button-box {
column-gap: 6px;
display:flex;
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin:5px 0;
margin: 5px 0;
row-gap: 5px;
}
.ol-button-box button {
background-repeat: no-repeat;;
border:1px solid var( --accent-light-blue );
color: var( --accent-light-blue );
background-repeat: no-repeat;
;
border: 1px solid var(--accent-light-blue);
color: var(--accent-light-blue);
}
.ol-dialog {
align-self: center;
background-color: var( --background-slate-blue );
color:white;
background-color: var(--background-slate-blue);
color: white;
justify-self: center;
position: absolute;
z-index:1000;
z-index: 1000;
}
.ol-panel.ol-dialog {
padding:20px;
padding: 20px;
}
.ol-dialog-close {
cursor: pointer;
font-size:16px;
font-weight: var( --font-weight-bolder );
font-size: 16px;
font-weight: var(--font-weight-bolder);
position: absolute;
right: 25px;
top: 25px;
right: 20px;
top: 10px;
}
.ol-dialog-close::before {
@@ -133,21 +126,25 @@ dl.ol-data-grid dd {
}
.ol-dialog-header {
border-bottom:1px solid var( --background-grey );
padding-bottom:10px;
border-bottom: 1px solid var(--background-grey);
padding-bottom: 10px;
}
.ol-dialog-content {
margin:4px 0;
}
.ol-dialog-footer {
border-top:1px solid var( --background-grey );
padding-top:15px;
border-top: 1px solid var(--background-grey);
padding-top: 15px;
display: flex;
row-gap: 10px;
}
.ol-dialog.scrollable .ol-dialog-content {
overflow-y: auto;
}
.ol-checkbox label {
align-items: center;
cursor: pointer;
@@ -157,63 +154,93 @@ dl.ol-data-grid dd {
}
.ol-checkbox input[type="checkbox"] {
appearance:none;
appearance: none;
background-color: transparent;
border:none;
margin:0;
border: none;
margin: 0;
}
.ol-checkbox input[type="checkbox"]::before {
align-self:center;
background-image: url( "/images/icons/square-check-solid.svg" );
align-self: center;
background-image: url("/images/icons/square-regular.svg");
background-repeat: no-repeat;
content: "";
filter: invert( 100% );
display:flex;
height:16px;
margin-right:10px;
width:16px;
filter: invert(100%);
display: flex;
height: 16px;
margin-right: 10px;
width: 16px;
}
.ol-checkbox input[type="checkbox"]:checked::before {
background-image: url( "/images/icons/square-regular.svg" );
background-image: url("/images/icons/square-check-solid.svg");
}
.ol-text-input input {
height: 40px;
border-radius: 5px;
color: var(--background-offwhite);
background-color: var(--background-grey);
border: 1px solid var(--background-grey);
border-radius: var(--border-radius-sm);
text-align: center;
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
}
input[type=number] {
-moz-appearance: textfield;
appearance: textfield;
margin: 0;
}
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
[class|="ol-button"] {
align-items: center;
background-repeat: no-repeat;
display:flex;
display: flex;
font-weight: normal;
padding:8px 10px;
padding: 8px 10px;
white-space: nowrap;
}
[class|="ol-button"]::before {
margin-right:8px;
margin-right: 8px;
}
.ol-button-close {
background: transparent;
border:1px solid white;
border: 1px solid white;
}
.ol-button-close::before {
content: "\d7";
}
.ol-button-apply {
background: transparent;
border: 1px solid white;
}
.ol-button-apply::before {
content: "\2713";
}
.ol-button-settings {
background-color: var( --background-slate-blue );
background-color: var(--background-slate-blue);
}
.ol-button-settings::before {
background-image: url( "/images/icons/gears-solid.svg" );
background-position:0 50%;
background-size:24px 24px;
background-image: url("/images/icons/gears-solid.svg");
background-position: 0 50%;
background-size: 24px 24px;
content: "";
display:flex;
filter: invert( 100% );
display: flex;
filter: invert(100%);
height: 24px;
width: 24px;
}

View File

@@ -1,5 +1,6 @@
@import url("layout.css");
@import url("airbase.css");
@import url("atc.css");
@import url("connectionstatuspanel.css");
@import url("contextmenus.css");
@import url("mouseinfopanel.css");
@@ -7,8 +8,7 @@
@import url("unitdatatable.css");
@import url("unitcontrolpanel.css");
@import url("unitinfopanel.css");
@import url("popup.css");
* {
-moz-box-sizing: border-box;
@@ -16,24 +16,22 @@
box-sizing: border-box;
}
html {
font-family: 'Open Sans', sans-serif;
html * {
font-family: 'Open Sans', sans-serif !important;
}
body {
display:grid;
margin: 0;
padding: 0;
display: grid;
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
width: 100%;
height: 100%;
width: 100%;
}
a {
text-decoration: none;
}
@@ -42,7 +40,6 @@ a:hover {
text-decoration: underline;
}
button {
background-color: var(--background-steel);
border: 1px solid var(--background-steel);
@@ -53,6 +50,10 @@ button {
padding: 6px;
}
button:hover {
background-color: var(--background-hover);
}
button[disabled="disabled"] {
color: var(--highlight-color);
cursor: not-allowed;
@@ -63,18 +64,48 @@ form {
padding: 0;
}
form > div {
form>div {
margin: 20px 0;
}
.pill {
background-color: var( --background-dark-steel );
background-color: var(--background-dark-steel);
border-radius: var(--border-radius-sm);
padding: 4px 8px;
width: fit-content;
}
.ol-scrollable {
overflow-y: scroll;
scrollbar-color: white transparent;
scrollbar-width: thin;
}
.ol-scrollable::-webkit-scrollbar {
width: var(--border-radius-md);
}
.ol-scrollable::-webkit-scrollbar-track {
background-color: transparent;
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
margin-top: 0px;
}
.ol-select .ol-scrollable {
scrollbar-color: white var(--background-grey);
}
.ol-select .ol-scrollable::-webkit-scrollbar-track {
background-color: var(--background-grey);
}
.ol-scrollable::-webkit-scrollbar-thumb {
background-color: white;
border-radius: 100px;
opacity: 0.8;
margin-top: 10px;
}
.ol-panel {
background-color: var(--background-steel);
@@ -103,6 +134,14 @@ form > div {
width: 100%;
}
.ol-ellipsed {
display: inline-block;
width: calc(100%);
overflow: hidden;
text-overflow: ellipsis;
text-align: left;
}
.ol-select {
position: relative;
color: var(--nav-text);
@@ -117,20 +156,24 @@ form > div {
text-align: center;
white-space: nowrap;
width: 100%;
min-width: 0;
}
.ol-select:not(.ol-select-image)>.ol-select-value {
align-items: center;
background-color: var(--background-grey);
border-radius: var(--border-radius-sm);
padding: 1em;
width: 100%;
padding-left: 20px;
padding-right: 30px;
padding: 1em 30px 1em 20px;
width: calc(100%);
overflow: hidden;
text-overflow: ellipsis;
}
.ol-select.narrow:not(.ol-select-image)>.ol-select-value {
opacity: .9;
padding: 4px 30px 4px 15px;
}
.ol-select:not(.ol-select-image)>.ol-select-value svg {
margin-right: 10px;
}
@@ -142,48 +185,51 @@ form > div {
}
.ol-select>.ol-select-options {
position: absolute;
border-radius: var(--border-radius-md);
overflow: hidden;
position: absolute;
max-height: 0;
translate: 0 -2px;
z-index: 1000;
}
.ol-select-options.scrollbar-visible {
border-top-right-radius: 0px !important;
border-bottom-right-radius: 0px !important;
}
.ol-select.ol-select-image>.ol-select-options {
position: absolute;
}
.ol-select.is-open > .ol-select-options {
max-height: fit-content;
.ol-select.is-open>.ol-select-options {
max-height: 382px;
overflow: visible;
overflow-y: auto;
padding: 8px 0;
min-width: 100%;
z-index: 9999;
translate: 0px 5px;
}
.ol-select.is-open[data-position="top"]>.ol-select-options {
top: 0;
translate: 0 -100%;
}
.ol-select>.ol-select-options > div {
.ol-select>.ol-select-options>div {
background-color: var(--background-grey);
box-shadow: 0 4px 4px rgba(0, 0, 0, 0.25);
display: flex;
justify-content: left;
padding: 6px 25px;
padding: 2px 10px;
width: 100%;
}
.ol-select>.ol-select-options>div:first-of-type {
border-top-left-radius: var(--border-radius-md);
border-top-right-radius: var(--border-radius-md);
padding-top: 16px;
padding-top: 12px;
}
.ol-select>.ol-select-options>div:last-of-type {
border-bottom-left-radius: var(--border-radius-md);
border-bottom-right-radius: var(--border-radius-md);
padding-bottom: 16px;
padding-bottom: 12px;
}
.ol-select>.ol-select-options div hr {
@@ -192,41 +238,29 @@ form > div {
width: 100%;
}
.ol-select>.ol-select-options > div a, .ol-select>.ol-select-options > div button {
.ol-select>.ol-select-options>div a,
.ol-select>.ol-select-options>div button {
background-color: transparent;
border: none;
border-radius: 0;
color: white;
display:block;
font-size: 14px;
display: block;
font-size: 12px;
font-weight: normal;
padding: 6px 2px;
text-align: left;
white-space: nowrap;
width: 100%;
padding: 5px;
border-radius: var(--border-radius-sm);
}
.ol-select>.ol-select-options > div a:hover, .ol-select>.ol-select-options > div button:hover {
text-decoration: underline;
.ol-select>.ol-select-options>div a:hover,
.ol-select>.ol-select-options>div button:hover {
background-color: #FFF3;
text-decoration: none;
}
.ol-select>.ol-select-options::-webkit-scrollbar {
width: 10px;
}
.ol-select>.ol-select-options::-webkit-scrollbar-track {
background-color: transparent;
border-radius: 100px;
}
.ol-select>.ol-select-options::-webkit-scrollbar-thumb {
background-color: white;
border-radius: 100px;
opacity: 0.8;
margin-top: 10px;
}
.ol-panel-list {
border-radius: var(--border-radius-sm);
display: flex;
@@ -260,32 +294,30 @@ form > div {
max-width: 16px;
}
.ol-panel-board {
display: flex;
flex-direction: row;
justify-content: space-evenly;
}
.ol-panel-board > .panel-section {
.ol-panel-board>.panel-section {
border-right: 1px solid #555;
margin:10px 0;
padding:0 30px;
margin: 10px 0;
padding: 0 30px;
}
.ol-panel-board > .panel-section:first-child {
padding-left:20px;
.ol-panel-board>.panel-section:first-child {
padding-left: 20px;
}
.ol-panel-board > .panel-section:last-child {
padding-right:20px;
.ol-panel-board>.panel-section:last-child {
padding-right: 20px;
}
.ol-panel-board > .panel-section:last-of-type {
.ol-panel-board>.panel-section:last-of-type {
border-right-width: 0;
}
h1,
h2,
h3,
@@ -320,7 +352,6 @@ button.ol-button-warning {
color: var(--primary-red);
}
nav.ol-panel {
column-gap: 20px;
display: flex;
@@ -332,7 +363,6 @@ nav.ol-panel> :last-child {
margin-right: 5px;
}
.ol-panel .ol-group {
border-radius: var(--border-radius-sm);
column-gap: 10px;
@@ -340,13 +370,18 @@ nav.ol-panel> :last-child {
flex-direction: row;
flex-wrap: nowrap;
row-gap: 4px;
align-items: center;
}
.ol-group-header {
text-align: center;
width: 100%;
}
.ol-panel .ol-group.wrap {
flex-wrap: wrap;
}
.ol-panel .ol-group-button-toggle {
align-items: center;
column-gap: 15px;
@@ -360,7 +395,7 @@ nav.ol-panel> :last-child {
background-position: 5px 50%;
background-repeat: no-repeat;
border: 0;
display:flex;
display: flex;
justify-items: left;
text-indent: 5px;
}
@@ -371,38 +406,36 @@ nav.ol-panel> :last-child {
content: "";
filter: invert(100%);
-webkit-filter: invert(100%);
height:16px;
width:16px;
height: 16px;
width: 16px;
}
.ol-panel .ol-group-button-toggle button.off::before {
background-image: url("/images/icons/square-regular.svg");
}
.highlight-primary {
background-color: var(--secondary-light-grey);
}
.highlight-coalition, .highlight-neutral {
background-color: var(--primary-grey);
.highlight-coalition,
.highlight-neutral {
background-color: var(--primary-neutral);
color: var(--secondary-gunmetal-grey)
}
.highlight-coalition[data-coalition="blue"], .highlight-bluefor {
.highlight-coalition[data-coalition="blue"],
.highlight-bluefor {
background-color: var(--primary-blue);
color: white;
}
.highlight-coalition[data-coalition="red"], .highlight-redfor {
.highlight-coalition[data-coalition="red"],
.highlight-redfor {
background-color: var(--primary-red);
color: white;
}
.accent-green {
color: var(--accent-green);
font-weight: var(--font-weight-bolder);
@@ -424,12 +457,10 @@ nav.ol-panel> :last-child {
}
.accent-neutral {
color: var(--primary-grey);
color: var(--primary-neutral);
font-weight: var(--font-weight-bolder);
}
.hide {
display: none !important;
}
@@ -445,7 +476,6 @@ nav.ol-panel> :last-child {
flex-direction: column;
}
.slider-container {
width: 100%;
}
@@ -510,13 +540,19 @@ nav.ol-panel> :last-child {
width: fit-content;
height: fit-content;
text-align: center;
color: var(--primary-grey);
color: var(--primary-neutral);
font-size: 12px;
z-index: 2000;
font-weight: var(--font-weight-bolder);
}
.ol-sortable .handle {
background-image: url("/images/icons/grip-lines-solid.svg");
cursor: ns-resize;
filter: invert();
height: 12px;
width: 12px;
}
#unit-selection {
display: flex;
@@ -541,30 +577,6 @@ nav.ol-panel> :last-child {
width: 28px;
}
#unit-selection #unit-identification [data-object|="unit"] .unit-short-label {
font-size: 12px;
}
#unit-selection #unit-identification #unit-name {
background-color: transparent;
border: none;
color: white;
font-size: 16px;
font-weight: var(--font-weight-bolder);
outline: none;
overflow: hidden;
white-space: nowrap;
width: 150px;
}
#edit-unit-name {
background-image: url("/images/buttons/edit.svg");
background-repeat: no-repeat;
height: 14px;
margin-left: 10px;
width: 15px;
}
#unit-visibility-control {
align-items: center;
}
@@ -615,213 +627,233 @@ body[data-hide-navyunit] #unit-visibility-control-navyunit {
background-image: var(--visibility-control-navyunit-hidden-url);
}
.toggle {
--width: 40px;
--height: calc(var(--width) / 2);
--border-radius: calc(var(--height) / 2);
display: inline-block;
cursor: pointer;
#atc-navbar-control {
align-items: center;
display: flex;
flex-direction: column;
}
.toggle-input {
display: none;
#atc-navbar-control button {
background: #ffffff20;
border-radius: var(--border-radius-sm);
padding: 4px;
}
.toggle-fill {
position: relative;
width: var(--width);
height: var(--height);
border-radius: var(--border-radius);
transition: background-color 0.2s;
}
.toggle-fill::after {
content: "";
position: absolute;
top: 2;
left: 2;
height: calc(var(--height) - 4px);
width: calc(var(--height) - 4px);
background-color: #ffffff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.25);
border-radius: var(--border-radius);
transition: transform 0.2s;
}
.toggle-input:checked ~ .toggle-fill::after {
transform: translateX(var(--height));
}
#roe-buttons-container button {
background-color:transparent;
border:1px solid var( --accent-light-blue );
background-color: transparent;
border: 1px solid var(--accent-light-blue);
}
#roe-buttons-container button.selected, #reaction-to-threat-buttons-container button.selected {
#roe-buttons-container button.selected,
#reaction-to-threat-buttons-container button.selected {
background-color: white;
border-color: white;
}
#roe-buttons-container button::before, #reaction-to-threat-buttons-container button::before {
background-position:center;
#roe-buttons-container button::before,
#reaction-to-threat-buttons-container button::before {
background-position: center;
background-repeat: no-repeat;
content: "";
display:block;
height:24px;
width:24px;
display: block;
height: 24px;
width: 24px;
}
#roe-buttons-container button[title="Hold"]::before {
background-image: url( "/themes/olympus/images/icons_roe_stop_light.svg");
background-image: url("/themes/olympus/images/icons_roe_stop_light.svg");
}
#roe-buttons-container button[title="Hold"].selected::before {
background-image: url( "/themes/olympus/images/icons_roe_stop_dark.svg");
background-image: url("/themes/olympus/images/icons_roe_stop_dark.svg");
}
/**/
#roe-buttons-container button[title="Return"]::before {
background-image: url( "/themes/olympus/images/icons_roe_defend_light.svg");
background-image: url("/themes/olympus/images/icons_roe_defend_light.svg");
}
#roe-buttons-container button[title="Return"].selected::before {
background-image: url( "/themes/olympus/images/icons_roe_defend_dark.svg");
background-image: url("/themes/olympus/images/icons_roe_defend_dark.svg");
}
/**/
#roe-buttons-container button[title="Designated"]::before {
background-image: url( "/themes/olympus/images/icons_roe_target_light.svg");
background-image: url("/themes/olympus/images/icons_roe_target_light.svg");
}
#roe-buttons-container button[title="Designated"].selected::before {
background-image: url( "/themes/olympus/images/icons_roe_target_dark.svg");
background-image: url("/themes/olympus/images/icons_roe_target_dark.svg");
}
/**/
#roe-buttons-container button[title="Free"]::before {
background-image: url( "/themes/olympus/images/icons_roe_free_light.svg");
background-image: url("/themes/olympus/images/icons_roe_free_light.svg");
}
#roe-buttons-container button[title="Free"].selected::before {
background-image: url( "/themes/olympus/images/icons_roe_free_dark.svg");
background-image: url("/themes/olympus/images/icons_roe_free_dark.svg");
}
/****************************************************************************************/
#reaction-to-threat-buttons-container button[title="None"]::before {
background-image: url( "/themes/olympus/images/icons_threat_nothing_light.svg");
background-image: url("/themes/olympus/images/icons_threat_nothing_light.svg");
}
#reaction-to-threat-buttons-container button[title="None"].selected::before {
background-image: url( "/themes/olympus/images/icons_threat_nothing_dark.svg");
background-image: url("/themes/olympus/images/icons_threat_nothing_dark.svg");
}
/**/
#reaction-to-threat-buttons-container button[title="Passive"]::before {
background-image: url( "/themes/olympus/images/icons_threat_cms_light.svg");
background-image: url("/themes/olympus/images/icons_threat_cms_light.svg");
}
#reaction-to-threat-buttons-container button[title="Passive"].selected::before {
background-image: url( "/themes/olympus/images/icons_threat_cms_dark.svg");
background-image: url("/themes/olympus/images/icons_threat_cms_dark.svg");
}
/**/
#reaction-to-threat-buttons-container button[title="Evade"]::before {
background-image: url( "/themes/olympus/images/icons_threat_defend_light.svg");
background-image: url("/themes/olympus/images/icons_threat_defend_light.svg");
}
#reaction-to-threat-buttons-container button[title="Evade"].selected::before {
background-image: url( "/themes/olympus/images/icons_threat_defend_dark.svg");
background-image: url("/themes/olympus/images/icons_threat_defend_dark.svg");
}
/****************************************************************************************/
#splash-screen {
background-image: url( "/images/splash/splash_pic_ship.png" );
background-position:100% 50%;
background-size:320px;
border-radius: var( --border-radius-lg );
display:none;
background-image: url("/images/splash/splash_pic_ship.png");
background-position: 100% 50%;
background-size: 60%;
border-radius: var(--border-radius-lg);
overflow: hidden;
width:700px;
width: 1200px;
z-index: 99999;
}
#splash-content {
background-color: var( --background-steel );
background-color: var(--background-steel);
display: flex;
flex-direction: column;
padding:20px;
position:relative;
row-gap:10px;
width:55%;
z-index:10;
padding: 30px;
position: relative;
row-gap: 10px;
width: 50%;
z-index: 10;
}
#splash-content::after {
background-color: var( --background-steel );
background-color: var(--background-steel);
content: "";
display: block;
height:250px;
height: 800px;
position: absolute;
right:0;
top:0;
right: 0;
top: 0;
transform: rotate(-23deg);
transform-origin: top right;
width:200px;
width: 200px;
z-index: -1;
}
#splash-content #app-summary {
background-image: url( "/images/olympus-500x500.png" );
background-image: url("/images/olympus-500x500.png");
background-position: 0 50%;
background-repeat: no-repeat;
background-size:75px 75px;
background-size: 75px 75px;
content: "";
display:flex;
display: flex;
flex-direction: column;
justify-content: space-between;
min-height: 75px;
text-indent: 85px;
}
#splash-content #app-summary > * {
height:fit-content;
#splash-content #app-summary>* {
height: fit-content;
line-height: 25px;
white-space: nowrap;
width:fit-content;
width: fit-content;
padding: 2px;
}
#splash-content .app-version {
font-size:11px;
font-size: 11px;
}
#splash-content #legal-stuff h4 {
text-transform:uppercase;
#splash-content #legal-stuff h5 {
text-transform: uppercase;
}
#splash-content #legal-stuff p {
font-size:10px;
font-size: 10px;
color:#FFF7;
width: 120%;
}
#splash-content.ol-dialog-content {
margin: 0px;
}
.feature-splashScreen #splash-screen {
display:flex;
display: flex;
}
#gray-out {
position: fixed;
height: 100%;
width: 100%;
left: 0px;
top: 0px;
z-index: 9999;
background-color: #000A;
}
#authentication-form {
display: flex;
align-items: end;
column-gap: 10px;
margin: 10px 0px;
flex-direction: row;
}
#authentication-form>div {
display: flex;
align-items: start;
row-gap: 4px;
flex-direction: column;
}
#authentication-form>div>input {
height: 35px;
border-radius: var(--border-radius-sm);
border: 0px solid transparent;
width: 200px;
}
#splash-content a {
color: #FFFB;
font-weight: bold;
}
#connection-status {
margin-bottom: 5px;
}
#connection-status[data-status="connecting"]::before {
content: "Connecting...";
animation: blinker 1s linear infinite;
}
#connection-status[data-status="failed"]::before {
content: "Incorrect username/password!";
color: var(--primary-red);
}
@keyframes blinker {
50% {
opacity: 0;
}
}

View File

@@ -0,0 +1,23 @@
#info-popup {
position: absolute;
width: fit-content;
height: fit-content;
top: 100px;
left: 50%;
translate: -50% 0%;
z-index: 9999;
}
.ol-popup > div {
padding-left: 15px;
padding-right: 15px;
}
.visible {
opacity: 1;
}
.invisible {
opacity: 0;
transition: opacity 2s linear;
}

View File

@@ -1,5 +1,5 @@
body.feature-forceShowUnitControlPanel #unit-control-panel {
display:block !important;
display: block !important;
}
@@ -12,78 +12,105 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
z-index: 1000;
}
#unit-control-panel h3 {
margin-bottom: 8px;
}
#unit-control-panel #selected-units-container {
align-items: left;
border-radius: var( --border-radius-md );
display:flex;
border-radius: var(--border-radius-md);
display: flex;
flex-direction: column;
max-height: 136px;
overflow-y: auto;
row-gap: 4px;
}
#unit-control-panel #selected-units-container button {
align-items: center;
border-radius: var( --border-radius-lg );
display:flex;
border-radius: var(--border-radius-lg);
display: flex;
font-size: 11px;
height:30px;
padding:8px 0;
height: 30px;
padding: 8px 0;
position: relative;
width:90%;
width: 100%;
}
#unit-control-panel #selected-units-container button::before {
background-color: var( --primary-grey );
border-radius: var( --border-radius-md );
content: attr( data-short-label );
margin:0 5px;
padding:4px 6px;
background-color: var( --primary-neutral );
border-radius: 999px;
content: attr(data-short-label);
margin: 0 5px;
padding: 4px 6px;
white-space: nowrap;
width:fit-content;
width: 30px;
text-overflow: ellipsis;
overflow: hidden;
}
#unit-control-panel #selected-units-container button[data-coalition="blue"]::before {
background-color: var( --accent-light-blue );
background-color: var(--accent-light-blue);
}
#unit-control-panel #selected-units-container button[data-coalition="red"]::before {
background-color: var( --accent-light-red );
color:var(--secondary-red-outline)
background-color: var(--accent-light-red);
color: var(--secondary-red-outline)
}
#unit-control-panel #selected-units-container button::after {
border-radius: var( --border-radius-sm );
content: attr( data-callsign );
border-radius: var(--border-radius-sm);
content: attr(data-callsign);
display: block;
overflow: hidden;
padding:4px;
padding-left:0;
padding: 4px;
padding-left: 0;
text-align: left;
text-overflow: ellipsis;
white-space: nowrap;
width:fit-content;
width: fit-content;
}
#unit-control-panel #selected-units-container button:hover::after {
overflow: visible;
text-overflow:initial;
text-overflow: initial;
}
#unit-control-panel #selected-units-container button:hover::after {
background-color: var( --background-grey );
background-color: var(--background-grey);
}
#unit-control-panel #selected-units-container button[data-coalition="blue"]:hover::after {
background-color: var( --primary-blue );
background-color: var(--primary-blue);
}
#unit-control-panel #selected-units-container button[data-coalition="red"]:hover::after {
background-color: var( --primary-red );
background-color: var(--primary-red);
}
#unit-control-panel h4 {
margin-bottom:8px;
margin-top:20px;
margin-bottom: 8px;
}
#unit-control-panel #threat,
#unit-control-panel #roe {
margin-top: 12px;
}
#advanced-settings-dialog {
width: 400px;
}
#advanced-settings-dialog>.ol-dialog-content {
margin-top: 10px;
margin-bottom: 10px;
display: flex;
flex-direction: column;
flex-wrap: nowrap;
row-gap: 10px;
}
#advanced-settings-dialog>.ol-dialog-content>.ol-group {
justify-content: space-between;
}

View File

@@ -26,19 +26,16 @@
}
#loadout-container {
width:250px;
}
#loadout {
display:flex;
overflow: visible;
}
#loadout-silhouette {
align-items: center;
display:flex;
justify-content: center;
width:55%;
width:100px;
}
#loadout-silhouette::before {
@@ -58,8 +55,6 @@
display:flex;
flex-flow: column nowrap;
row-gap: 8px;
text-align: center;
width:45%;
}
@@ -67,27 +62,29 @@
align-items: center;
column-gap: 8px;
display:flex;
justify-content: flex-end;
white-space: nowrap;
}
#loadout-items > *::before {
align-items: center;
background-color: var( --secondary-light-grey );
border-radius: 50%;
border-radius: var( --border-radius-sm );
content: attr( data-qty );
display:flex;
font-weight: var( --font-weight-bolder );
justify-content: center;
height:20px;
width:20px;
padding:1px 4px;
}
#loadout-items > *::after {
content: attr( data-item );
overflow: hidden;
position:relative;
text-overflow: ellipsis;
width:80px;
}
#fuel-percentage {
align-items: center;
display:flex;
@@ -113,7 +110,6 @@
height:6px;
margin-top:4px;
overflow: hidden;
width:90%;
}
#fuel-display #fuel-bar {

View File

@@ -1,46 +1,48 @@
:root {
/* Generic marker settings */
--unit-centre-x: calc( var( --unit-width ) / 2 );
--unit-centre-y: calc( var( --unit-height ) / 2 );
--unit-hotgroup-height: 10px;
--unit-hotgroup-width: var( --unit-hotgroup-height );
/* Air units' marker settings */
--unit-aircraft-label-x: calc( var( --unit-centre-x ) - ( var( --unit-aircraft-width ) / 2 ) + ( var( --unit-stroke-width ) / 2 ) );
--unit-aircraft-label-y: calc( var( --unit-centre-y ) - ( var( --unit-aircraft-height ) / 2 ) + ( var( --unit-stroke-width ) / 2 ) );
/* Generic marker settings */
--unit-centre-x: calc(var(--unit-width) / 2);
--unit-centre-y: calc(var(--unit-height) / 2);
--unit-hotgroup-height: 10px;
--unit-hotgroup-width: var(--unit-hotgroup-height);
/* Air units' marker settings */
--unit-aircraft-label-x: calc(var(--unit-centre-x) - (var(--unit-aircraft-width) / 2) + (var(--unit-stroke-width) / 2));
--unit-aircraft-label-y: calc(var(--unit-centre-y) - (var(--unit-aircraft-height) / 2) + (var(--unit-stroke-width) / 2));
}
[data-object|="unit"] {
align-items: center;
cursor:pointer;
display:flex;
cursor: pointer;
display: flex;
justify-content: center;
position:relative;
position: relative;
height: 100%;
width: 100%;
}
[data-object|="unit"] .unit-selected-spotlight {
background-color: var( --unit-spotlight-fill );
background-color: var(--unit-spotlight-fill);
border-radius: 50%;
display:none;
padding: var( --unit-spotlight-radius );
display: none;
padding: var(--unit-spotlight-radius);
position: absolute;
z-index:1;
z-index: 1;
}
[data-object|="unit"] .unit-vvi {
align-self: center;
background:var( --secondary-gunmetal-grey );
display:flex;
background: var(--secondary-gunmetal-grey);
display: flex;
justify-self: center;
transform-origin: bottom;
translate:0 -50%;
padding-bottom: calc( ( var( --unit-aircraft-width ) / 2 ) + var( --unit-stroke-width ) );
position:absolute;
width: var( --unit-aircraft-vvi-width );
translate: 0 -50%;
padding-bottom: calc((var(--unit-aircraft-width) / 2) + var(--unit-stroke-width));
position: absolute;
width: var(--unit-aircraft-vvi-width);
z-index: 3;
}
@@ -48,32 +50,32 @@
[data-object|="unit"] .unit-hotgroup {
align-content: center;
background-color: black;
border-radius: var( --border-radius-xs );
display:none;
height: var( --unit-hotgroup-height );
border-radius: var(--border-radius-xs);
display: none;
height: var(--unit-hotgroup-height);
justify-content: center;
position:absolute;
transform: rotate( -45deg );
translate:0 -275%;
width: var( --unit-hotgroup-width );
position: absolute;
transform: rotate(-45deg);
translate: 0 -275%;
width: var(--unit-hotgroup-width);
z-index: 5;
}
[data-object|="unit"] .unit-hotgroup-id {
background-color: transparent;
color:white;
color: white;
font-size: 9px;
font-weight: bolder;
transform:rotate( 45deg );
transform: rotate(45deg);
}
[data-object|="unit"] .unit-marker-border {
border-radius: var( --border-radius-sm );
display:none;
height: calc( var( --unit-aircraft-height ) + ( var( --unit-label-border-width ) * 2 ) );
position:absolute;
width: calc( var( --unit-aircraft-width ) + ( var( --unit-label-border-width ) * 2 ) );
z-index:2;
border-radius: var(--border-radius-sm);
display: none;
height: calc(var(--unit-aircraft-height) + (var(--unit-label-border-width) * 2));
position: absolute;
width: calc(var(--unit-aircraft-width) + (var(--unit-label-border-width) * 2));
z-index: 2;
}
@@ -85,9 +87,9 @@
background-color: transparent;
background-repeat: no-repeat;
background-size: cover;
position:absolute;
position: absolute;
transform-origin: center;
z-index:3;
z-index: 3;
}
@@ -95,43 +97,43 @@
/* Air */
[data-object|="unit-aircraft"] .unit-marker {
background-image: var( --unit-aircraft-marker-neutral-url );
height: var( --unit-aircraft-marker-height );
width: var( --unit-aircraft-marker-width );
background-image: var(--unit-aircraft-marker-neutral-url);
height: var(--unit-aircraft-marker-height);
width: var(--unit-aircraft-marker-width);
}
[data-object|="unit-aircraft"]:hover .unit-marker {
background-image: var( --unit-aircraft-marker-neutral-hover-url );
background-image: var(--unit-aircraft-marker-neutral-hover-url);
}
[data-object|="unit-aircraft"][data-is-selected] .unit-marker {
background-image: var( --unit-aircraft-marker-neutral-selected-url );
background-image: var(--unit-aircraft-marker-neutral-selected-url);
}
[data-object|="unit-aircraft"][data-coalition="blue"] .unit-marker {
background-image: var( --unit-aircraft-marker-blue-url );
background-image: var(--unit-aircraft-marker-blue-url);
}
[data-object|="unit-aircraft"][data-coalition="blue"]:hover .unit-marker {
background-image: var( --unit-aircraft-marker-blue-hover-url );
background-image: var(--unit-aircraft-marker-blue-hover-url);
}
[data-object|="unit-aircraft"][data-coalition="blue"][data-is-selected] .unit-marker {
background-image: var( --unit-aircraft-marker-blue-selected-url );
background-image: var(--unit-aircraft-marker-blue-selected-url);
}
[data-object|="unit-aircraft"][data-coalition="red"] .unit-marker {
background-image: var( --unit-aircraft-marker-red-url );
background-image: var(--unit-aircraft-marker-red-url);
}
[data-object|="unit-aircraft"][data-coalition="red"]:hover .unit-marker {
background-image: var( --unit-aircraft-marker-red-hover-url );
background-image: var(--unit-aircraft-marker-red-hover-url);
}
[data-object|="unit-aircraft"][data-coalition="red"][data-is-selected] .unit-marker {
background-image: var( --unit-aircraft-marker-red-selected-url );
background-image: var(--unit-aircraft-marker-red-selected-url);
}
@@ -140,194 +142,195 @@
/* Ground vehicles (not SAMs) */
[data-object|="unit-groundunit"] .unit-marker {
background-image: var( --unit-groundunit-marker-neutral-url );
height: var( --unit-groundunit-marker-height );
width: var( --unit-groundunit-marker-width );
background-image: var(--unit-groundunit-marker-neutral-url);
height: var(--unit-groundunit-marker-height);
width: var(--unit-groundunit-marker-width);
}
[data-object|="unit-groundunit"]:hover .unit-marker {
background-image: var( --unit-groundunit-marker-neutral-hover-url );
background-image: var(--unit-groundunit-marker-neutral-hover-url);
}
[data-object|="unit-groundunit"][data-is-selected] .unit-marker {
background-image: var( --unit-groundunit-marker-neutral-selected-url );
background-image: var(--unit-groundunit-marker-neutral-selected-url);
}
[data-object|="unit-groundunit"][data-coalition="blue"] .unit-marker {
background-image: var( --unit-groundunit-marker-blue-url );
background-image: var(--unit-groundunit-marker-blue-url);
}
[data-object|="unit-groundunit"][data-coalition="blue"]:hover .unit-marker {
background-image: var( --unit-groundunit-marker-blue-hover-url );
background-image: var(--unit-groundunit-marker-blue-hover-url);
}
[data-object|="unit-groundunit"][data-coalition="blue"][data-is-selected] .unit-marker {
background-image: var( --unit-groundunit-marker-blue-selected-url );
background-image: var(--unit-groundunit-marker-blue-selected-url);
}
[data-object|="unit-groundunit"][data-coalition="red"] .unit-marker {
background-image: var( --unit-groundunit-marker-red-url );
background-image: var(--unit-groundunit-marker-red-url);
}
[data-object|="unit-groundunit"][data-coalition="red"]:hover .unit-marker {
background-image: var( --unit-groundunit-marker-red-hover-url );
background-image: var(--unit-groundunit-marker-red-hover-url);
}
[data-object|="unit-groundunit"][data-coalition="red"][data-is-selected] .unit-marker {
background-image: var( --unit-groundunit-marker-red-selected-url );
background-image: var(--unit-groundunit-marker-red-selected-url);
}
/* SAMs */
[data-object|="unit-sam"] .unit-selected-spotlight {
translate:0 2px;
translate: 0 2px;
}
[data-object|="unit-sam"] .unit-marker {
background-image: var( --unit-sam-marker-neutral-url );
height: var( --unit-sam-marker-height );
width: var( --unit-sam-marker-width );
background-image: var(--unit-sam-marker-neutral-url);
height: var(--unit-sam-marker-height);
width: var(--unit-sam-marker-width);
}
[data-object|="unit-sam"]:hover .unit-marker {
background-image: var( --unit-sam-marker-neutral-hover-url );
background-image: var(--unit-sam-marker-neutral-hover-url);
}
[data-object|="unit-sam"][data-is-selected] .unit-marker {
background-image: var( --unit-sam-marker-neutral-selected-url );
background-image: var(--unit-sam-marker-neutral-selected-url);
}
[data-object|="unit-sam"][data-coalition="blue"] .unit-marker {
background-image: var( --unit-sam-marker-blue-url );
background-image: var(--unit-sam-marker-blue-url);
}
[data-object|="unit-sam"][data-coalition="blue"]:hover .unit-marker {
background-image: var( --unit-sam-marker-blue-hover-url );
background-image: var(--unit-sam-marker-blue-hover-url);
}
[data-object|="unit-sam"][data-coalition="blue"][data-is-selected] .unit-marker {
background-image: var( --unit-sam-marker-blue-selected-url );
background-image: var(--unit-sam-marker-blue-selected-url);
}
[data-object|="unit-sam"][data-coalition="red"] .unit-marker {
background-image: var( --unit-sam-marker-red-url );
background-image: var(--unit-sam-marker-red-url);
}
[data-object|="unit-sam"][data-coalition="red"]:hover .unit-marker {
background-image: var( --unit-sam-marker-red-hover-url );
background-image: var(--unit-sam-marker-red-hover-url);
}
[data-object|="unit-sam"][data-coalition="red"][data-is-selected] .unit-marker {
background-image: var( --unit-sam-marker-red-selected-url );
background-image: var(--unit-sam-marker-red-selected-url);
}
/* navyunit */
[data-object|="unit-navyunit"] .unit-selected-spotlight {
translate:0 -2px;
translate: 0 -2px;
}
[data-object|="unit-navyunit"] .unit-marker {
background-image: var( --unit-navyunit-marker-neutral-url );
height: var( --unit-navyunit-marker-height );
width: var( --unit-navyunit-marker-width );
background-image: var(--unit-navyunit-marker-neutral-url);
height: var(--unit-navyunit-marker-height);
width: var(--unit-navyunit-marker-width);
}
[data-object|="unit-navyunit"]:hover .unit-marker {
background-image: var( --unit-navyunit-marker-neutral-hover-url );
background-image: var(--unit-navyunit-marker-neutral-hover-url);
}
[data-object|="unit-navyunit"][data-is-selected] .unit-marker {
background-image: var( --unit-navyunit-marker-neutral-selected-url );
background-image: var(--unit-navyunit-marker-neutral-selected-url);
}
[data-object|="unit-navyunit"][data-coalition="blue"] .unit-marker {
background-image: var( --unit-navyunit-marker-blue-url );
background-image: var(--unit-navyunit-marker-blue-url);
}
[data-object|="unit-navyunit"][data-coalition="blue"]:hover .unit-marker {
background-image: var( --unit-navyunit-marker-blue-hover-url );
background-image: var(--unit-navyunit-marker-blue-hover-url);
}
[data-object|="unit-navyunit"][data-coalition="blue"][data-is-selected] .unit-marker {
background-image: var( --unit-navyunit-marker-blue-selected-url );
background-image: var(--unit-navyunit-marker-blue-selected-url);
}
[data-object|="unit-navyunit"][data-coalition="red"] .unit-marker {
background-image: var( --unit-navyunit-marker-red-url );
background-image: var(--unit-navyunit-marker-red-url);
}
[data-object|="unit-navyunit"][data-coalition="red"]:hover .unit-marker {
background-image: var( --unit-navyunit-marker-red-hover-url );
background-image: var(--unit-navyunit-marker-red-hover-url);
}
[data-object|="unit-navyunit"][data-coalition="red"][data-is-selected] .unit-marker {
background-image: var( --unit-navyunit-marker-red-selected-url );
background-image: var(--unit-navyunit-marker-red-selected-url);
}
/* Building */
[data-object|="unit-building"] .unit-marker {
background-image: var( --unit-building-marker-neutral-url );
height: var( --unit-building-marker-height );
width: var( --unit-building-marker-width );
background-image: var(--unit-building-marker-neutral-url);
height: var(--unit-building-marker-height);
width: var(--unit-building-marker-width);
}
[data-object|="unit-building"][data-coalition="blue"] .unit-marker {
background-image: var( --unit-building-marker-blue-url );
background-image: var(--unit-building-marker-blue-url);
}
[data-object|="unit-building"][data-coalition="red"] .unit-marker {
background-image: var( --unit-building-marker-red-url );
background-image: var(--unit-building-marker-red-url);
}
/* Weapons */
[data-object|="unit-missile"], [data-object|="unit-bomb"] {
[data-object|="unit-missile"],
[data-object|="unit-bomb"] {
cursor: default;
}
[data-object|="unit-missile"] .unit-marker {
background-image: var( --unit-missile-marker-neutral-url );
height: var( --unit-missile-marker-height );
width: var( --unit-missile-marker-width );
background-image: var(--unit-missile-marker-neutral-url);
height: var(--unit-missile-marker-height);
width: var(--unit-missile-marker-width);
}
[data-object|="unit-missile"][data-coalition="blue"] .unit-marker {
background-image: var( --unit-missile-marker-blue-url );
background-image: var(--unit-missile-marker-blue-url);
}
[data-object|="unit-missile"][data-coalition="red"] .unit-marker {
background-image: var( --unit-missile-marker-red-url );
background-image: var(--unit-missile-marker-red-url);
}
[data-object|="unit-bomb"] .unit-marker {
background-image: var( --unit-bomb-marker-neutral-url );
height: var( --unit-bomb-marker-height );
width: var( --unit-bomb-marker-width );
background-image: var(--unit-bomb-marker-neutral-url);
height: var(--unit-bomb-marker-height);
width: var(--unit-bomb-marker-width);
}
[data-object|="unit-bomb"][data-coalition="blue"] .unit-marker {
background-image: var( --unit-bomb-marker-blue-url );
background-image: var(--unit-bomb-marker-blue-url);
}
[data-object|="unit-bomb"][data-coalition="red"] .unit-marker {
background-image: var( --unit-bomb-marker-red-url );
background-image: var(--unit-bomb-marker-red-url);
}
@@ -336,12 +339,12 @@
********************************************/
[data-object|="unit"] .unit-short-label {
color: var( --secondary-gunmetal-grey );
color: var(--secondary-gunmetal-grey);
font-size: var(--unit-font-size);
font-weight: var(--unit-font-weight);
line-height: normal;
position: absolute;
z-index:10;
z-index: 10;
}
[data-object|="unit-groundunit"] .unit-short-label {
@@ -349,81 +352,81 @@
}
[data-object|="unit-sam"] .unit-short-label {
translate:0 50%;
translate: 0 25%;
}
[data-object|="unit-navyunit"] .unit-short-label {
translate:0 -50%;
translate: 0 -50%;
}
[data-object|="unit"] .unit-fuel {
background:white;
border: var( --unit-aircraft-fuel-border-width ) solid var( --secondary-dark-steel );
border-radius: var( --border-radius-sm );
display:none;
height: var( --unit-aircraft-fuel-height );
background: white;
border: var(--unit-aircraft-fuel-border-width) solid var(--secondary-dark-steel);
border-radius: var(--border-radius-sm);
display: none;
height: var(--unit-aircraft-fuel-height);
position: absolute;
translate:var( --unit-aircraft-fuel-x ) var( --unit-aircraft-fuel-y );
width: var( --unit-aircraft-fuel-width );
translate: var(--unit-aircraft-fuel-x) var(--unit-aircraft-fuel-y);
width: var(--unit-aircraft-fuel-width);
z-index: 5;
}
[data-object|="unit"] .unit-fuel-level {
background-color: var( --secondary-light-grey );
height:100%;
width:100%;
background-color: var(--secondary-light-grey);
height: 100%;
width: 100%;
}
[data-object|="unit"] .unit-ammo {
column-gap: var( --unit-aircraft-ammo-spacing );
display:none;
height:fit-content;
position:absolute;
translate:var( --unit-aircraft-ammo-x ) var( --unit-aircraft-ammo-y );
width:fit-content;
column-gap: var(--unit-aircraft-ammo-spacing);
display: none;
height: fit-content;
position: absolute;
translate: var(--unit-aircraft-ammo-x) var(--unit-aircraft-ammo-y);
width: fit-content;
}
[data-object|="unit"] .unit-ammo > * {
[data-object|="unit"] .unit-ammo>* {
background-color: white;
border: var( --unit-aircraft-ammo-border-width ) solid var( --secondary-dark-steel );
border: var(--unit-aircraft-ammo-border-width) solid var(--secondary-dark-steel);
border-radius: 50%;
padding: var( --unit-aircraft-ammo-radius );
padding: var(--unit-aircraft-ammo-radius);
}
[data-object|="unit"] .unit-summary {
pointer-events: none;
column-gap: 6px;
color:white;
display:flex;
color: white;
display: flex;
flex-wrap: wrap;
font-size:11px;
font-size: 11px;
font-weight: bold;
justify-content: right;
line-height: 12px;
position:absolute;
position: absolute;
row-gap: 1px;
text-shadow:
-1px -1px 0 #000,
-1px -1px 0 #000,
1px -1px 0 #000,
-1px 1px 0 #000,
1px 1px 0 #000;
-1px 1px 0 #000,
1px 1px 0 #000;
translate: -60px 0;
width:fit-content;
z-index:20;
width: fit-content;
z-index: 20;
}
[data-hide-labels] [data-object|="unit"] .unit-summary {
display:none;
display: none;
}
[data-object|="unit"] .unit-summary > * {
padding:1px;
[data-object|="unit"] .unit-summary>* {
padding: 1px;
}
[data-object|="unit"] .unit-summary .unit-callsign {
color:white;
color: white;
overflow: hidden;
text-align: right;
transform-origin: right;
@@ -433,35 +436,35 @@
[data-object|="unit"] .unit-summary .unit-callsign:hover {
direction: rtl;
overflow:visible;
overflow: visible;
}
[data-object|="unit"][data-pilot|="ai"]:hover .unit-ammo,
[data-object|="unit"][data-pilot|="ai"]:hover .unit-fuel {
display:flex;
[data-object|="unit"]:hover .unit-ammo,
[data-object|="unit"]:hover .unit-fuel {
display: flex;
}
[data-object|="unit"][data-is-in-hotgroup] .unit-hotgroup,
[data-object|="unit"][data-pilot|="ai"][data-is-selected] .unit-ammo,
[data-object|="unit"][data-pilot|="ai"][data-is-selected] .unit-fuel,
[data-object|="unit"][data-is-selected] .unit-ammo,
[data-object|="unit"][data-is-selected] .unit-fuel,
[data-object|="unit"][data-is-selected] .unit-selected-spotlight {
display:flex;
display: flex;
}
[data-object|="unit"][data-has-fox-1] .unit-ammo-fox-1,
[data-object|="unit"][data-has-fox-2] .unit-ammo-fox-2,
[data-object|="unit"][data-has-fox-3] .unit-ammo-fox-3,
[data-object|="unit"][data-has-other-ammo] .unit-ammo-other {
background-color: var( --secondary-gunmetal-grey );
background-color: var(--secondary-gunmetal-grey);
}
[data-object|="unit"][data-coalition="blue"][data-is-selected] .unit-short-label {
color: var( --secondary-blue-text );
color: var(--secondary-blue-text);
}
[data-object|="unit"][data-coalition="blue"] .unit-fuel-level,
@@ -469,16 +472,16 @@
[data-object|="unit"][data-coalition="blue"][data-has-fox-2] .unit-ammo-fox-2,
[data-object|="unit"][data-coalition="blue"][data-has-fox-3] .unit-ammo-fox-3,
[data-object|="unit"][data-coalition="blue"][data-has-other-ammo] .unit-ammo-other {
background-color: var( --primary-blue );
background-color: var(--primary-blue);
}
[data-object|="unit"][data-coalition="blue"] .unit-vvi {
background-color: var( --secondary-blue-outline );
background-color: var(--secondary-blue-outline);
}
[data-object|="unit"][data-coalition="red"][data-is-selected] .unit-short-label {
color: var( --secondary-red-text );
color: var(--secondary-red-text);
}
[data-object|="unit"][data-coalition="red"] .unit-fuel-level,
@@ -486,105 +489,104 @@
[data-object|="unit"][data-coalition="red"][data-has-fox-2] .unit-ammo-fox-2,
[data-object|="unit"][data-coalition="red"][data-has-fox-3] .unit-ammo-fox-3,
[data-object|="unit"][data-coalition="red"][data-has-other-ammo] .unit-ammo-other {
background-color: var( --primary-red );
background-color: var(--primary-red);
}
[data-object|="unit"][data-coalition="blue"] .unit-vvi {
background-color: var( --secondary-red-outline );
background-color: var(--secondary-red-outline);
}
@keyframes pulse {
50% {
opacity: 0;
opacity: 0;
}
}
[data-object|="unit"][data-pilot|="ai"][data-has-low-fuel] .unit-fuel {
[data-object|="unit"][data-has-low-fuel] .unit-fuel {
animation: pulse 1.5s linear infinite;
}
[data-object|="unit"] .unit-status {
[data-object|="unit"] .unit-state {
background-repeat: no-repeat;
position:absolute;
height:var( --unit-aircraft-status-rtb-height );
width:var( --unit-aircraft-status-rtb-width );
position: absolute;
height: var(--unit-aircraft-state-height);
width: var(--unit-aircraft-state-width);
z-index: 10;
}
[data-object|="unit"][data-status="rtb"] .unit-status {
background-image: var( --unit-aircraft-status-rtb-neutral-url );
height:var( --unit-aircraft-status-rtb-height );
width:var( --unit-aircraft-status-rtb-width );
[data-object|="unit"][data-state="rtb"] .unit-state {
background-image: var(--unit-aircraft-state-rtb);
}
[data-object|="unit"][data-status="rtb"][data-coalition="blue"] .unit-status {
background-image: var( --unit-aircraft-status-rtb-blue-url );
[data-object|="unit"][data-state="land"] .unit-state {
background-image: var(--unit-aircraft-state-rtb);
}
[data-object|="unit"][data-status="rtb"][data-coalition="red"] .unit-status {
background-image: var( --unit-aircraft-status-rtb-red-url );
[data-object|="unit"][data-state="idle"] .unit-state {
background-image: var(--unit-aircraft-state-idle);
}
[data-object|="unit"][data-status="hold"] .unit-status {
background-image: var( --unit-aircraft-status-hold-neutral-url );
height:var( --unit-aircraft-status-hold-height );
width:var( --unit-aircraft-status-hold-width );
[data-object|="unit"][data-state="attack"] .unit-state {
background-image: var(--unit-aircraft-state-attack);
}
[data-object|="unit"][data-status="hold"][data-coalition="blue"] .unit-status {
background-image: var( --unit-aircraft-status-hold-blue-url );
[data-object|="unit"][data-state="follow"] .unit-state {
background-image: var(--unit-aircraft-state-follow);
}
[data-object|="unit"][data-status="hold"][data-coalition="red"] .unit-status {
background-image: var( --unit-aircraft-status-hold-red-url );
[data-object|="unit"][data-state="refuel"] .unit-state {
background-image: var(--unit-aircraft-state-refuel);
}
[data-object|="unit"][data-state="human"] .unit-state {
background-image: var(--unit-aircraft-state-human);
}
[data-object|="unit"][data-state="dcs"] .unit-state {
background-image: var(--unit-aircraft-state-dcs);
}
/*** DEAD ***/
[data-object|="unit-aircraft"][ data-is-dead ] {
[data-object|="unit-aircraft"][ data-is-dead] {
cursor: default;
}
[data-object|="unit-aircraft"][ data-is-dead ] .unit-marker {
background-image: var( --unit-aircraft-marker-neutral-dead-url );
[data-object|="unit-aircraft"][ data-is-dead] .unit-marker {
background-image: var(--unit-aircraft-marker-neutral-dead-url);
background-position: 50% 50%;
background-size: auto 32px;
}
[data-object|="unit-aircraft"][ data-is-dead ][data-coalition="blue"] .unit-marker {
background-image: var( --unit-aircraft-marker-blue-dead-url );
[data-object|="unit-aircraft"][ data-is-dead][data-coalition="blue"] .unit-marker {
background-image: var(--unit-aircraft-marker-blue-dead-url);
}
[data-object|="unit-aircraft"][ data-is-dead ][data-coalition="red"] .unit-marker {
background-image: var( --unit-aircraft-marker-red-dead-url );
[data-object|="unit-aircraft"][ data-is-dead][data-coalition="red"] .unit-marker {
background-image: var(--unit-aircraft-marker-red-dead-url);
}
[data-object|="unit-aircraft"][ data-is-dead ] .unit-selected-spotlight,
[data-object|="unit-aircraft"][ data-is-dead ] .unit-short-label,
[data-object|="unit-aircraft"][ data-is-dead ] .unit-vvi,
[data-object|="unit-aircraft"][ data-is-dead ] .unit-hotgroup,
[data-object|="unit-aircraft"][ data-is-dead ] .unit-hotgroup-id,
[data-object|="unit-aircraft"][ data-is-dead ] .unit-status,
[data-object|="unit-aircraft"][ data-is-dead ] .unit-fuel,
[data-object|="unit-aircraft"][ data-is-dead ] .unit-ammo,
[data-object|="unit-aircraft"][ data-is-dead ]:hover .unit-fuel,
[data-object|="unit-aircraft"][ data-is-dead ]:hover .unit-ammo {
display:none !important;
[data-object|="unit-aircraft"][ data-is-dead] .unit-selected-spotlight,
[data-object|="unit-aircraft"][ data-is-dead] .unit-short-label,
[data-object|="unit-aircraft"][ data-is-dead] .unit-vvi,
[data-object|="unit-aircraft"][ data-is-dead] .unit-hotgroup,
[data-object|="unit-aircraft"][ data-is-dead] .unit-hotgroup-id,
[data-object|="unit-aircraft"][ data-is-dead] .unit-state,
[data-object|="unit-aircraft"][ data-is-dead] .unit-fuel,
[data-object|="unit-aircraft"][ data-is-dead] .unit-ammo,
[data-object|="unit-aircraft"][ data-is-dead]:hover .unit-fuel,
[data-object|="unit-aircraft"][ data-is-dead]:hover .unit-ammo {
display: none !important;
}
[data-object|="unit-aircraft"][ data-is-dead ] .unit-summary > * {
display:none;
}
[data-object|="unit-aircraft"][ data-is-dead ] .unit-summary .unit-callsign {
display:block;
[data-object|="unit-aircraft"][ data-is-dead] .unit-summary>* {
display: none;
}
[data-object|="unit-aircraft"][ data-is-dead] .unit-summary .unit-callsign {
display: block;
}

View File

@@ -1,10 +1,83 @@
<svg width="63" height="63" viewBox="0 0 63 63" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M31.4998 46.9756C40.0468 46.9756 46.9756 40.0468 46.9756 31.4998C46.9756 22.9528 40.0468 16.024 31.4998 16.024C22.9528 16.024 16.024 22.9528 16.024 31.4998C16.024 40.0468 22.9528 46.9756 31.4998 46.9756ZM31.4998 52.734C43.2271 52.734 52.734 43.2271 52.734 31.4998C52.734 19.7725 43.2271 10.2656 31.4998 10.2656C19.7725 10.2656 10.2656 19.7725 10.2656 31.4998C10.2656 43.2271 19.7725 52.734 31.4998 52.734Z" fill="white"/>
<path d="M35.3291 61L37.3291 61L37.3291 59L37.3291 49.2532L37.3291 47.2532L35.3291 47.2532L27.6709 47.2532L25.6709 47.2532L25.6709 49.2532L25.6709 59L25.6709 61L27.6709 61L35.3291 61Z" fill="#247BE2" stroke="white" stroke-width="4"/>
<path d="M47.2529 35.3291V37.3291H49.2529H58.9998H60.9998V35.3291V27.6709V25.6709L58.9998 25.6709H49.2529H47.2529V27.6709V35.3291Z" fill="#247BE2" stroke="white" stroke-width="4"/>
<path d="M35.3291 15.7471L37.3291 15.7471L37.3291 13.7471L37.3291 4.00023L37.3291 2.00023L35.3291 2.00023L27.6709 2.00023L25.6709 2.00023L25.6709 4.00023L25.6709 13.7471L25.6709 15.7471L27.6709 15.7471L35.3291 15.7471Z" fill="#247BE2" stroke="white" stroke-width="4"/>
<path d="M2 35.3291V37.3291H4H13.7468H15.7468V35.3291L15.7468 27.6709V25.6709L13.7468 25.6709H4H2V27.6709L2 35.3291Z" fill="#247BE2" stroke="white" stroke-width="4"/>
<circle cx="31.5001" cy="31.5001" r="15.4494" fill="white" stroke="#247BE2" stroke-width="6"/>
<line x1="25.7895" y1="23.9132" x2="36.5242" y2="38.6028" stroke="#247BE2" stroke-width="2" stroke-linecap="square"/>
<line x1="38.9357" y1="33.9313" x2="25.9313" y2="33.0643" stroke="#247BE2" stroke-width="2" stroke-linecap="square"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="icon_airbase_blue.svg"
id="svg18"
version="1.1"
fill="none"
viewBox="0 0 63 63"
height="63"
width="63">
<metadata
id="metadata24">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs22" />
<sodipodi:namedview
inkscape:current-layer="svg18"
inkscape:window-maximized="1"
inkscape:window-y="-8"
inkscape:window-x="1912"
inkscape:cy="31.5"
inkscape:cx="31.5"
inkscape:zoom="13.492063"
showgrid="false"
id="namedview20"
inkscape:window-height="1017"
inkscape:window-width="1920"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
guidetolerance="10"
gridtolerance="10"
objecttolerance="10"
borderopacity="1"
bordercolor="#666666"
pagecolor="#ffffff" />
<path
id="path2"
fill="white"
d="M31.4998 46.9756C40.0468 46.9756 46.9756 40.0468 46.9756 31.4998C46.9756 22.9528 40.0468 16.024 31.4998 16.024C22.9528 16.024 16.024 22.9528 16.024 31.4998C16.024 40.0468 22.9528 46.9756 31.4998 46.9756ZM31.4998 52.734C43.2271 52.734 52.734 43.2271 52.734 31.4998C52.734 19.7725 43.2271 10.2656 31.4998 10.2656C19.7725 10.2656 10.2656 19.7725 10.2656 31.4998C10.2656 43.2271 19.7725 52.734 31.4998 52.734Z"
clip-rule="evenodd"
fill-rule="evenodd" />
<circle
id="circle12"
stroke-width="6"
stroke="#247BE2"
fill="white"
r="15.4494"
cy="31.5001"
cx="31.5001" />
<line
id="line14"
stroke-linecap="square"
stroke-width="2"
stroke="#247BE2"
y2="38.6028"
x2="36.5242"
y1="23.9132"
x1="25.7895" />
<line
id="line16"
stroke-linecap="square"
stroke-width="2"
stroke="#247BE2"
y2="33.0643"
x2="25.9313"
y1="33.9313"
x1="38.9357" />
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -1,10 +1,83 @@
<svg width="63" height="63" viewBox="0 0 63 63" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M31.4998 46.9756C40.0468 46.9756 46.9756 40.0468 46.9756 31.4998C46.9756 22.9528 40.0468 16.024 31.4998 16.024C22.9528 16.024 16.024 22.9528 16.024 31.4998C16.024 40.0468 22.9528 46.9756 31.4998 46.9756ZM31.4998 52.734C43.2271 52.734 52.734 43.2271 52.734 31.4998C52.734 19.7725 43.2271 10.2656 31.4998 10.2656C19.7725 10.2656 10.2656 19.7725 10.2656 31.4998C10.2656 43.2271 19.7725 52.734 31.4998 52.734Z" fill="white"/>
<path d="M35.3291 61L37.3291 61L37.3291 59L37.3291 49.2532L37.3291 47.2532L35.3291 47.2532L27.6709 47.2532L25.6709 47.2532L25.6709 49.2532L25.6709 59L25.6709 61L27.6709 61L35.3291 61Z" fill="#CFD9E8" stroke="white" stroke-width="4"/>
<path d="M47.2529 35.3291V37.3291H49.2529H58.9998H60.9998V35.3291V27.6709V25.6709L58.9998 25.6709H49.2529H47.2529V27.6709V35.3291Z" fill="#CFD9E8" stroke="white" stroke-width="4"/>
<path d="M35.3291 15.7471L37.3291 15.7471L37.3291 13.7471L37.3291 4.00023L37.3291 2.00023L35.3291 2.00023L27.6709 2.00023L25.6709 2.00023L25.6709 4.00023L25.6709 13.7471L25.6709 15.7471L27.6709 15.7471L35.3291 15.7471Z" fill="#CFD9E8" stroke="white" stroke-width="4"/>
<path d="M2 35.3291V37.3291H4H13.7468H15.7468V35.3291L15.7468 27.6709V25.6709L13.7468 25.6709H4H2V27.6709L2 35.3291Z" fill="#CFD9E8" stroke="white" stroke-width="4"/>
<circle cx="31.5001" cy="31.5001" r="15.4494" fill="white" stroke="#CFD9E8" stroke-width="6"/>
<line x1="25.7895" y1="23.9132" x2="36.5242" y2="38.6028" stroke="#CFD9E8" stroke-width="2" stroke-linecap="square"/>
<line x1="38.9357" y1="33.9313" x2="25.9313" y2="33.0643" stroke="#CFD9E8" stroke-width="2" stroke-linecap="square"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="icon_airbase_neutral.svg"
id="svg18"
version="1.1"
fill="none"
viewBox="0 0 63 63"
height="63"
width="63">
<metadata
id="metadata24">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs22" />
<sodipodi:namedview
inkscape:current-layer="svg18"
inkscape:window-maximized="1"
inkscape:window-y="-8"
inkscape:window-x="1912"
inkscape:cy="31.5"
inkscape:cx="31.5"
inkscape:zoom="13.492063"
showgrid="false"
id="namedview20"
inkscape:window-height="1017"
inkscape:window-width="1920"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
guidetolerance="10"
gridtolerance="10"
objecttolerance="10"
borderopacity="1"
bordercolor="#666666"
pagecolor="#ffffff" />
<path
id="path2"
fill="white"
d="M31.4998 46.9756C40.0468 46.9756 46.9756 40.0468 46.9756 31.4998C46.9756 22.9528 40.0468 16.024 31.4998 16.024C22.9528 16.024 16.024 22.9528 16.024 31.4998C16.024 40.0468 22.9528 46.9756 31.4998 46.9756ZM31.4998 52.734C43.2271 52.734 52.734 43.2271 52.734 31.4998C52.734 19.7725 43.2271 10.2656 31.4998 10.2656C19.7725 10.2656 10.2656 19.7725 10.2656 31.4998C10.2656 43.2271 19.7725 52.734 31.4998 52.734Z"
clip-rule="evenodd"
fill-rule="evenodd" />
<circle
id="circle12"
stroke-width="6"
stroke="#CFD9E8"
fill="white"
r="15.4494"
cy="31.5001"
cx="31.5001" />
<line
id="line14"
stroke-linecap="square"
stroke-width="2"
stroke="#CFD9E8"
y2="38.6028"
x2="36.5242"
y1="23.9132"
x1="25.7895" />
<line
id="line16"
stroke-linecap="square"
stroke-width="2"
stroke="#CFD9E8"
y2="33.0643"
x2="25.9313"
y1="33.9313"
x1="38.9357" />
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -1,10 +1,83 @@
<svg width="63" height="63" viewBox="0 0 63 63" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M31.4998 46.9756C40.0468 46.9756 46.9756 40.0468 46.9756 31.4998C46.9756 22.9528 40.0468 16.024 31.4998 16.024C22.9528 16.024 16.024 22.9528 16.024 31.4998C16.024 40.0468 22.9528 46.9756 31.4998 46.9756ZM31.4998 52.734C43.2271 52.734 52.734 43.2271 52.734 31.4998C52.734 19.7725 43.2271 10.2656 31.4998 10.2656C19.7725 10.2656 10.2656 19.7725 10.2656 31.4998C10.2656 43.2271 19.7725 52.734 31.4998 52.734Z" fill="white"/>
<path d="M35.3291 61L37.3291 61L37.3291 59L37.3291 49.2532L37.3291 47.2532L35.3291 47.2532L27.6709 47.2532L25.6709 47.2532L25.6709 49.2532L25.6709 59L25.6709 61L27.6709 61L35.3291 61Z" fill="#ff5858" stroke="white" stroke-width="4"/>
<path d="M47.2529 35.3291V37.3291H49.2529H58.9998H60.9998V35.3291V27.6709V25.6709L58.9998 25.6709H49.2529H47.2529V27.6709V35.3291Z" fill="#ff5858" stroke="white" stroke-width="4"/>
<path d="M35.3291 15.7471L37.3291 15.7471L37.3291 13.7471L37.3291 4.00023L37.3291 2.00023L35.3291 2.00023L27.6709 2.00023L25.6709 2.00023L25.6709 4.00023L25.6709 13.7471L25.6709 15.7471L27.6709 15.7471L35.3291 15.7471Z" fill="#ff5858" stroke="white" stroke-width="4"/>
<path d="M2 35.3291V37.3291H4H13.7468H15.7468V35.3291L15.7468 27.6709V25.6709L13.7468 25.6709H4H2V27.6709L2 35.3291Z" fill="#ff5858" stroke="white" stroke-width="4"/>
<circle cx="31.5001" cy="31.5001" r="15.4494" fill="white" stroke="#ff5858" stroke-width="6"/>
<line x1="25.7895" y1="23.9132" x2="36.5242" y2="38.6028" stroke="#ff5858" stroke-width="2" stroke-linecap="square"/>
<line x1="38.9357" y1="33.9313" x2="25.9313" y2="33.0643" stroke="#ff5858" stroke-width="2" stroke-linecap="square"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="icon_airbase_red.svg"
id="svg18"
version="1.1"
fill="none"
viewBox="0 0 63 63"
height="63"
width="63">
<metadata
id="metadata24">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs22" />
<sodipodi:namedview
inkscape:current-layer="svg18"
inkscape:window-maximized="1"
inkscape:window-y="-8"
inkscape:window-x="1912"
inkscape:cy="31.5"
inkscape:cx="31.5"
inkscape:zoom="13.492063"
showgrid="false"
id="namedview20"
inkscape:window-height="1017"
inkscape:window-width="1920"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
guidetolerance="10"
gridtolerance="10"
objecttolerance="10"
borderopacity="1"
bordercolor="#666666"
pagecolor="#ffffff" />
<path
id="path2"
fill="white"
d="M31.4998 46.9756C40.0468 46.9756 46.9756 40.0468 46.9756 31.4998C46.9756 22.9528 40.0468 16.024 31.4998 16.024C22.9528 16.024 16.024 22.9528 16.024 31.4998C16.024 40.0468 22.9528 46.9756 31.4998 46.9756ZM31.4998 52.734C43.2271 52.734 52.734 43.2271 52.734 31.4998C52.734 19.7725 43.2271 10.2656 31.4998 10.2656C19.7725 10.2656 10.2656 19.7725 10.2656 31.4998C10.2656 43.2271 19.7725 52.734 31.4998 52.734Z"
clip-rule="evenodd"
fill-rule="evenodd" />
<circle
id="circle12"
stroke-width="6"
stroke="#ff5858"
fill="white"
r="15.4494"
cy="31.5001"
cx="31.5001" />
<line
id="line14"
stroke-linecap="square"
stroke-width="2"
stroke="#ff5858"
y2="38.6028"
x2="36.5242"
y1="23.9132"
x1="25.7895" />
<line
id="line16"
stroke-linecap="square"
stroke-width="2"
stroke="#ff5858"
y2="33.0643"
x2="25.9313"
y1="33.9313"
x1="38.9357" />
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="19"
height="15"
viewBox="0 0 19 15"
fill="none"
version="1.1"
id="svg6"
sodipodi:docname="state_attack.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs10" />
<sodipodi:namedview
id="namedview8"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="27.733333"
inkscape:cx="3.6959135"
inkscape:cy="10.258414"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg6" />
<path
style="fill:none;stroke:#262626;stroke-width:3.6454;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 3.9375571,11.604826 5.4120513,13.142064 8.1100626,10.334251 10.243372,12.373445 9.1610315,11.30679 15.074691,5.314696 14.525677,2.506882 11.81198,1.8794375 5.8198901,7.8087875 4.6748047,6.7891902 6.6826265,8.7499543 Z"
id="path2232" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.74012;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 3.7087499,11.821755 1.4744947,1.537239 2.926818,-3.024743 c 0.958603,0.899307 1.0509689,0.972539 1.0509689,0.972539 L 14.845884,5.5316249 14.29687,2.7238111 11.583172,2.0963666 5.8198909,7.8087874 c 0,0 -0.1141197,-0.012794 0.8627356,0.9411669 z"
id="path2232-9"
sodipodi:nodetypes="cccccccccc" />
<path
style="fill:#262222;fill-opacity:1;stroke-width:0.0124914"
d="m 12.8516,4.8268957 c 0.213183,-0.2131845 0.213183,-0.5329611 0,-0.7461455 -0.213185,-0.2131845 -0.532961,-0.2131845 -0.746145,0 L 8.1881937,7.9980144 c -0.2131847,0.2131845 -0.2131847,0.5329612 0,0.7461458 0.1065924,0.106592 0.2398327,0.1598881 0.3730732,0.1598881 0.1332405,0 0.26648,-0.053296 0.3730723,-0.1598881 z"
fill="#FFFFFF"
id="path4-5" />
<path
style="fill:none;stroke:#262626;stroke-width:1.19854;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 4.6748047,6.7891902 10.243372,12.373445"
id="path2082" />
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="19"
height="15"
viewBox="0 0 19 15"
fill="none"
version="1.1"
id="svg6"
sodipodi:docname="state_dcs.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs10" />
<sodipodi:namedview
id="namedview8"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="19.610428"
inkscape:cx="1.0453622"
inkscape:cy="12.21289"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg6" />
<rect
style="fill:#262626;fill-opacity:1;stroke:none;stroke-width:5.63192;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers"
id="rect4324"
width="5.226213"
height="7.0879617"
x="1.5176032"
y="4.8923955"
rx="1.6057953" />
<rect
style="fill:#262626;fill-opacity:1;stroke:none;stroke-width:5.74938;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers"
id="rect4324-6"
width="5.5898962"
height="6.9061198"
x="11.848835"
y="4.9978404"
rx="1.7175397" />
<rect
style="fill:#262626;fill-opacity:1;stroke:none;stroke-width:4.02396;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers"
id="rect4324-7"
width="3.214294"
height="5.8832622"
x="7.7873521"
y="0.59372008"
rx="1.5281793" />
<rect
style="fill:#262626;fill-opacity:1;stroke:none;stroke-width:3.84388;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers"
id="rect4100"
width="12.76161"
height="12.015139"
x="3.0333979"
y="1.9770601"
rx="2.5930805" />
<path
d="m 9.3852027,1.9350755 c 0.358221,0 0.6476303,0.2894099 0.6476303,0.6476303 v 1.2952618 h 2.428616 c 0.805492,0 1.457171,0.6516785 1.457171,1.4571695 v 5.5048619 c 0,0.805491 -0.651679,1.457169 -1.457171,1.457169 H 6.3089565 c -0.8054909,0 -1.4571694,-0.651678 -1.4571694,-1.457169 V 5.3351371 c 0,-0.805491 0.6516785,-1.4571695 1.4571694,-1.4571695 H 8.7375714 V 2.5827058 c 0,-0.3582204 0.2894111,-0.6476303 0.6476313,-0.6476303 z M 7.1184944,9.7066454 c -0.1780979,0 -0.3238152,0.145716 -0.3238152,0.3238146 0,0.178099 0.1457173,0.323817 0.3238152,0.323817 h 0.6476303 c 0.1780991,0 0.3238164,-0.145718 0.3238164,-0.323817 0,-0.1780986 -0.1457173,-0.3238146 -0.3238164,-0.3238146 z m 1.9428933,0 c -0.178099,0 -0.3238163,0.145716 -0.3238163,0.3238146 0,0.178099 0.1457173,0.323817 0.3238163,0.323817 h 0.64763 c 0.178099,0 0.3238153,-0.145718 0.3238153,-0.323817 0,-0.1780986 -0.1457163,-0.3238146 -0.3238153,-0.3238146 z m 1.9428923,0 c -0.178098,0 -0.323815,0.145716 -0.323815,0.3238146 0,0.178099 0.145717,0.323817 0.323815,0.323817 h 0.647631 c 0.178098,0 0.323816,-0.145718 0.323816,-0.323817 0,-0.1780986 -0.145718,-0.3238146 -0.323816,-0.3238146 z M 8.2518487,7.1161213 a 0.8095391,0.8095391 0 1 0 -1.6190782,0 0.8095391,0.8095391 0 1 0 1.6190782,0 z m 3.0762473,0.809538 a 0.80953865,0.80953865 0 1 0 0,-1.6190771 0.80953865,0.80953865 0 1 0 0,1.6190771 z M 3.8803405,6.4684911 h 0.323815 v 3.8857859 h -0.323815 c -0.5363195,0 -0.9714467,-0.4351276 -0.9714467,-0.9714486 V 7.4399365 c 0,-0.5363182 0.4351272,-0.9714454 0.9714467,-0.9714454 z m 11.0097255,0 c 0.536319,0 0.971446,0.4351272 0.971446,0.9714454 v 1.9428919 c 0,0.536321 -0.435127,0.9714486 -0.971446,0.9714486 H 14.566249 V 6.4684911 Z"
id="path3711"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.0202384" />
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -0,0 +1,222 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="19"
height="15"
viewBox="0 0 19 15"
fill="none"
version="1.1"
id="svg6"
sodipodi:docname="state_follow.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs10">
<marker
inkscape:stockid="TriangleOutM"
orient="auto"
refY="0"
refX="0"
id="marker3764"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path3762"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:1pt;stroke-opacity:1"
transform="scale(0.4)" />
</marker>
<marker
inkscape:stockid="TriangleOutM"
orient="auto"
refY="0"
refX="0"
id="marker3754"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path3752"
d="M 5.77,0 -2.88,5 V -5 Z"
style="fill:#00fff1;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:1pt;stroke-opacity:1"
transform="scale(0.4)" />
</marker>
<marker
inkscape:stockid="Arrow2Send"
orient="auto"
refY="0"
refX="0"
id="marker3658"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path3656"
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-0.3,0,0,-0.3,0.69,0)" />
</marker>
<marker
inkscape:stockid="Arrow2Send"
orient="auto"
refY="0"
refX="0"
id="marker3648"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path3646"
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="matrix(-0.3,0,0,-0.3,0.69,0)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="Arrow2Mend"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mend">
<path
transform="scale(-0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path1088" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="Arrow2Lend"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Lend">
<path
transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path1082" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="Arrow1Lend"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path1064" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend-7"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path1088-1"
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible"
id="Arrow2Mend-7-8"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow2Mend">
<path
transform="scale(-0.6)"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
id="path1088-1-6" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend-7-8-0"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path1088-1-6-8"
style="fill:#00fffb;fill-opacity:1;fill-rule:evenodd;stroke:#00fff1;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)" />
</marker>
</defs>
<sodipodi:namedview
id="namedview8"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="27.733333"
inkscape:cx="4.7776442"
inkscape:cy="6.5084135"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg6" />
<path
style="fill:none;stroke:#000000;stroke-width:0.83575px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 9.7400387,13.368089 0.010654,-1.821905"
id="path6803" />
<path
style="fill:none;stroke:#000000;stroke-width:2.92331;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 4.4447961,10.874958 V 7.976957"
id="path5404"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:2.92331;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 15.077899,10.949537 15.056587,7.9023759"
id="path5404-6"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:2.33883;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 5.0092879,8.5461224 3.2885491,-1.9183098 0.025165,-2.0602673 1.4363865,-3.081709 1.3976871,2.9751649 0.0638,2.1668114 3.288548,1.9183098"
id="path5844"
sodipodi:nodetypes="ccccccc" />
<path
style="fill:none;stroke:#000000;stroke-width:2.33883;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 5.0092879,10.491885 H 8.297837 v 0.746707 l -1.4877615,1.34107 -0.010655,0.767118 5.8918905,0.03195 -0.02131,-0.905625 -1.449125,-1.234526 v -0.746698 h 3.288549"
id="path5912"
sodipodi:nodetypes="cccccccccc" />
<g
transform="matrix(0.88384279,0,0,0.88384279,-4.1038899,-17.309659)"
id="layer1-7"
inkscape:label="Layer 1"
style="fill:#ffffff;fill-opacity:1">
<g
transform="matrix(0.90904788,0,0,0.91946153,8.2333194,20.900691)"
id="g839-1"
style="fill:#ffffff;fill-opacity:1">
<path
d="m 8.6152043,0.96068491 c -0.070984,-0.1658027 -0.2358263,-0.272592 -0.4178212,-0.272592 -0.1818565,0 -0.346698,0.106789 -0.4178225,0.272592 L 6.5262355,3.8523252 C 6.4294515,4.0771272 6.3784085,4.3160075 6.3784085,4.560499 V 6.7242759 L 2.2854009,9.0848093 V 8.5565855 c 0,-0.3737975 -0.304161,-0.6745171 -0.682098,-0.6745171 -0.378076,0 -0.68223699,0.3007196 -0.68223699,0.6745171 v 1.5736425 0.899265 0.674379 c 0,0.373797 0.30416099,0.674518 0.68223699,0.674518 0.377937,0 0.682098,-0.300721 0.682098,-0.674518 v -0.224747 h 4.0930076 v 0.918844 L 4.7156289,13.83966 c -0.09944,0.08425 -0.156335,0.207925 -0.156335,0.337121 v 0.449631 c 0,0.24736 0.204588,0.449631 0.454779,0.449631 h 2.7286708 v -1.798527 c 0,-0.247222 0.2045879,-0.449495 0.4546394,-0.449495 0.2501899,0 0.4547778,0.202273 0.4547778,0.449495 v 1.798527 h 2.7286701 c 0.250191,0 0.454779,-0.202271 0.454779,-0.449631 v -0.449631 c 0,-0.129196 -0.05676,-0.252876 -0.156195,-0.337121 l -1.662919,-1.441691 v -0.918844 h 4.093006 v 0.224747 c 0,0.373797 0.304162,0.674518 0.682098,0.674518 0.378076,0 0.682238,-0.300721 0.682238,-0.674518 V 11.029493 10.130228 8.5565855 c 0,-0.3737975 -0.304162,-0.6745171 -0.682238,-0.6745171 -0.377936,0 -0.682098,0.3007196 -0.682098,0.6745171 V 9.0848093 L 10.016496,6.7242759 V 4.560499 c 0,-0.2444915 -0.051184,-0.4833718 -0.1478275,-0.7081738 z"
fill="#202831"
id="path2-5"
style="fill:#ffffff;fill-opacity:1;stroke-width:1.38669" />
</g>
<circle
r="0"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.225344;stroke-linecap:round"
id="path865-3-0"
cx="29.19866"
cy="80.130951" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="19"
height="15"
viewBox="0 0 19 15"
fill="none"
version="1.1"
id="svg6"
sodipodi:docname="state_human.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs10" />
<sodipodi:namedview
id="namedview8"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="27.733334"
inkscape:cx="1.8930288"
inkscape:cy="5.3185095"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg6" />
<ellipse
style="fill:#262626;fill-opacity:1;stroke:none;stroke-width:12.2489;stroke-dashoffset:5.6;paint-order:stroke fill markers"
id="path1149"
cx="9.2425327"
cy="4.9208517"
rx="5.0100894"
ry="4.9463482" />
<path
style="fill:none;stroke:#262626;stroke-width:3.3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 4.5129051,12.490473 C 3.7913718,12.480652 3.327463,12.244253 3.2890664,11.649084 3.2075443,9.1160904 4.4151773,8.6100056 5.7622404,8.0795609 l 6.6154506,-0.012246 c 2.45028,0.2890709 3.047775,1.846629 3.047775,3.4797821 0.0127,0.360443 -0.331282,0.901957 -1.478805,0.943376 z"
id="path1359"
sodipodi:nodetypes="ccccccc" />
<path
d="m 9.2659737,7.6041687 c 1.6415273,0 2.9733343,-1.2969197 2.9733343,-2.8954494 0,-1.5985298 -1.331807,-2.8954501 -2.9733343,-2.8954501 -1.6415283,0 -2.973335,1.2969203 -2.973335,2.8954501 0,1.5985297 1.3318067,2.8954494 2.973335,2.8954494 z m 2.6429633,0.6434347 h -1.137714 c -0.458391,0.2050939 -0.9683982,0.3217163 -1.5052493,0.3217163 -0.5368511,0 -1.0447965,-0.1166224 -1.5052498,-0.3217163 H 6.6230093 c -1.4598251,0 -2.6429652,1.152148 -2.6429652,2.5737386 v 0.321716 c 0,0.532843 0.4439358,0.965149 0.991112,0.965149 H 13.56079 c 0.547177,0 0.991112,-0.432306 0.991112,-0.965149 v -0.321716 c 0,-1.4215906 -1.18314,-2.5737386 -2.642965,-2.5737386 z"
id="path916"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.0203759" />
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,4 @@
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.5356 0.900581C9.69508 -0.282964 11.5945 -0.302474 12.778 0.857004L14.5643 2.607C15.1403 3.17128 15.4649 3.94367 15.4649 4.75C15.4649 4.98835 15.4366 5.22373 15.3817 5.45165C15.8245 5.85549 16.151 6.39558 16.2888 7.02558L16.4103 7.58115L16.4103 7.58116C17.2333 11.3434 14.3009 14.75 10.5685 14.75H8.64315C8.50267 15.0566 8.30769 15.3446 8.05807 15.5994C6.89859 16.783 4.99919 16.8025 3.81565 15.643L2.02933 13.893C1.45334 13.3287 1.12875 12.5563 1.12875 11.75C1.12875 11.5117 1.15711 11.2763 1.21194 11.0484C0.769126 10.6445 0.442675 10.1044 0.30487 9.47436L0.183357 8.91882C0.183355 8.91881 0.183354 8.9188 0.183352 8.9188C-0.639549 5.15664 2.29279 1.75 6.02519 1.75H7.95052C8.09101 1.44337 8.28598 1.15538 8.5356 0.900581ZM7.95052 7.75H7.89958C7.93031 7.77715 7.9606 7.80505 7.99045 7.83367C7.97668 7.80595 7.96338 7.77805 7.95052 7.75ZM8.60322 8.66633C8.61699 8.69406 8.6303 8.72195 8.64315 8.75H8.69409C8.66337 8.72285 8.63307 8.69496 8.60322 8.66633Z" fill="#2F2F2F"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.1426 2.47515C10.4325 2.17926 10.9074 2.17438 11.2032 2.46425L12.9896 4.21425C13.1336 4.35532 13.2147 4.54842 13.2147 4.75C13.2147 4.95158 13.1336 5.14468 12.9896 5.28575L11.2032 7.03575C10.9074 7.32562 10.4325 7.32074 10.1426 7.02486C9.85276 6.72897 9.85764 6.25412 10.1535 5.96425L10.6274 5.5H6.02497C4.5888 5.5 3.55582 6.78851 3.84652 8.11751L3.84652 8.11751L3.96804 8.67308C4.05655 9.07772 3.80027 9.4775 3.39562 9.56601C2.99097 9.65452 2.59119 9.39824 2.50268 8.99359L2.38117 8.43803C2.38117 8.43803 2.38117 8.43803 2.38117 8.43802C1.87759 6.13576 3.6703 4 6.02497 4H10.6274L10.1535 3.53575C9.85764 3.24588 9.85276 2.77103 10.1426 2.47515ZM13.1976 6.93399C13.6022 6.84548 14.002 7.10175 14.0905 7.5064L14.2121 8.06196L13.5077 8.21604L14.2121 8.06196C14.7157 10.3642 12.9229 12.5 10.5683 12.5H5.96582L6.4397 12.9643C6.73559 13.2541 6.74047 13.729 6.4506 14.0249C6.16073 14.3207 5.68588 14.3256 5.38999 14.0357L3.60367 12.2857C3.45967 12.1447 3.37853 11.9516 3.37853 11.75C3.37853 11.5484 3.45967 11.3553 3.60367 11.2143L5.38999 9.46425C5.68588 9.17438 6.16073 9.17926 6.4506 9.47515C6.74047 9.77103 6.73559 10.2459 6.4397 10.5357L5.96582 11H10.5683C12.0044 11 13.0374 9.71149 12.7467 8.38251L12.6252 7.82694C12.5367 7.42229 12.7929 7.02251 13.1976 6.93399Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="19"
height="15"
viewBox="0 0 19 15"
fill="none"
version="1.1"
id="svg6"
sodipodi:docname="state_refuel.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs10" />
<sodipodi:namedview
id="namedview8"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="19.610428"
inkscape:cx="9.1532933"
inkscape:cy="9.2042866"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg6" />
<path
style="fill:none;stroke:#262626;stroke-width:2.80114;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 14.109032,5.6203217 14.096876,4.2589893"
id="path3134"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#262626;stroke-width:4.752;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 11.2162,7.8446415 c 0.611292,0.23067 1.379382,0.1813438 1.567963,1.1668564 l 0.01216,0.9116069 0.948071,1.1060822 c 0.556356,0.0066 1.240492,0.262304 1.17901,-0.935916 L 15.032793,5.7783334 C 15.029293,5.1839171 14.968765,4.6085103 14.485828,4.173906 L 13.075877,2.7761093"
id="path2668"
sodipodi:nodetypes="cccccccc" />
<path
style="fill:none;stroke:#262626;stroke-width:5.05323;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 5.5156203,2.6788713 v 9.4807077 l -0.9723803,0.02431 7.122686,0.01216 -1.069619,-0.03646 V 2.6302523 Z"
id="path2480"
sodipodi:nodetypes="ccccccc" />
<path
d="M 11.606497,11.523453 H 4.6132695 c -0.1923136,0 -0.3496607,0.157348 -0.3496607,0.349662 v 0.699322 c 0,0.192314 0.1573471,0.349662 0.3496607,0.349662 h 6.9932275 c 0.192314,0 0.349661,-0.157348 0.349661,-0.349662 v -0.699322 c 0,-0.192314 -0.157347,-0.349662 -0.349661,-0.349662 z M 15.04192,4.0778511 13.27176,2.3076902 c -0.135494,-0.1354933 -0.358404,-0.1354933 -0.493897,0 l -0.246948,0.2469485 c -0.135494,0.1354943 -0.135494,0.3584027 0,0.493897 l 0.823889,0.8238892 V 5.229548 c 0,0.6140934 0.456745,1.1211021 1.048985,1.206332 v 3.5140965 c 0,0.2884715 -0.236022,0.5244925 -0.524492,0.5244925 -0.288471,0 -0.524493,-0.236021 -0.524493,-0.5244925 V 9.2506542 c 0,-1.0620966 -0.861041,-1.9231375 -1.923138,-1.9231375 h -0.17483 V 3.1315803 c 0,-0.7714404 -0.627205,-1.3986455 -1.3986454,-1.3986455 h -3.496614 c -0.7714405,0 -1.3986455,0.6272051 -1.3986455,1.3986455 V 10.82413 H 11.256836 V 8.3765006 h 0.17483 c 0.482971,0 0.874154,0.3911839 0.874154,0.8741536 v 0.6075366 c 0,0.8238902 0.590054,1.5734762 1.409573,1.6587062 0.939715,0.09397 1.73738,-0.644688 1.73738,-1.5669205 V 5.0678294 c 0,-0.3715144 -0.148606,-0.7277319 -0.410853,-0.9899783 z M 9.8581906,5.9288713 h -3.496614 v -2.797291 h 3.496614 z"
id="path2270"
style="fill:#fffffd;fill-opacity:1;stroke-width:0.0218539" />
<rect
style="fill:#262626;fill-opacity:1;stroke:none;stroke-width:0.100774;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers"
id="rect3805"
width="3.496614"
height="2.7972908"
x="6.3615766"
y="3.1315804" />
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@@ -0,0 +1,4 @@
<svg width="19" height="15" viewBox="0 0 19 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.83594 4.99219L4.52344 8.55469V12.375C4.52344 12.5859 4.6875 12.75 4.89844 12.75H7.52344C7.71094 12.75 7.875 12.5859 7.875 12.375V10.125C7.875 9.9375 8.0625 9.75 8.25 9.75H9.75C9.96094 9.75 10.125 9.9375 10.125 10.125V12.375C10.125 12.5859 10.3125 12.75 10.5 12.75H13.1484C13.3359 12.75 13.5234 12.5859 13.5234 12.375V8.53125L9.1875 4.99219C9.14062 4.94531 9.07031 4.92188 9.02344 4.92188C8.95312 4.92188 8.88281 4.94531 8.83594 4.99219ZM15.6562 7.40625L13.7109 5.78906V2.55469C13.7109 2.39062 13.5703 2.27344 13.4297 2.27344H12.1172C11.9531 2.27344 11.8359 2.39062 11.8359 2.55469V4.24219L9.72656 2.50781C9.53906 2.36719 9.28125 2.27344 9.02344 2.27344C8.74219 2.27344 8.48438 2.36719 8.29688 2.50781L2.36719 7.40625C2.29688 7.45312 2.25 7.54688 2.25 7.61719C2.25 7.6875 2.29688 7.75781 2.32031 7.80469L2.92969 8.53125C2.97656 8.60156 3.04688 8.625 3.14062 8.625C3.21094 8.625 3.28125 8.60156 3.32812 8.55469L8.83594 4.03125C8.88281 3.98438 8.95312 3.96094 9.02344 3.96094C9.07031 3.96094 9.14062 3.98438 9.1875 4.03125L14.6953 8.55469C14.7422 8.60156 14.8125 8.625 14.8828 8.625C14.9766 8.625 15.0469 8.60156 15.0938 8.53125L15.7031 7.80469C15.75 7.75781 15.7734 7.6875 15.7734 7.61719C15.7734 7.54688 15.7266 7.45312 15.6562 7.40625Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.5234 8.53125V12.375C13.5234 12.5859 13.3359 12.75 13.1484 12.75H10.5C10.3125 12.75 10.125 12.5859 10.125 12.375V10.125C10.125 9.9375 9.96094 9.75 9.75 9.75H8.25C8.0625 9.75 7.875 9.9375 7.875 10.125V12.375C7.875 12.5859 7.71094 12.75 7.52344 12.75H4.89844C4.6875 12.75 4.52344 12.5859 4.52344 12.375V8.55469L8.83594 4.99219C8.88281 4.94531 8.95312 4.92188 9.02344 4.92188C9.07031 4.92188 9.14062 4.94531 9.1875 4.99219L13.5234 8.53125ZM14.6953 8.55469C14.6964 8.55582 14.6976 8.55693 14.6987 8.55803C14.737 8.5945 14.7898 8.61608 14.8452 8.62275C14.8577 8.62425 14.8702 8.625 14.8828 8.625C14.9766 8.625 15.0469 8.60156 15.0938 8.53125L15.7031 7.80469C15.75 7.75781 15.7734 7.6875 15.7734 7.61719C15.7734 7.58321 15.7625 7.54375 15.7432 7.50676C15.7227 7.46721 15.6926 7.43047 15.6562 7.40625L13.7109 5.78906V2.55469C13.7109 2.39062 13.5703 2.27344 13.4297 2.27344H12.1172C11.9531 2.27344 11.8359 2.39062 11.8359 2.55469V4.24219L9.72656 2.50781C9.68416 2.47601 9.63816 2.44661 9.58938 2.42014C9.42246 2.32958 9.22295 2.27344 9.02344 2.27344C8.74219 2.27344 8.48438 2.36719 8.29688 2.50781L2.36719 7.40625C2.34189 7.42312 2.31962 7.44605 2.30148 7.47178C2.29357 7.483 2.28645 7.49475 2.2802 7.50676C2.27782 7.51134 2.27556 7.51595 2.27344 7.52059C2.25841 7.55343 2.25 7.58741 2.25 7.61719C2.25 7.64997 2.26019 7.68274 2.27344 7.71315C2.28332 7.73582 2.29491 7.75718 2.30524 7.77623C2.31078 7.78642 2.31595 7.79596 2.32031 7.80469L2.92969 8.53125C2.93534 8.53973 2.94134 8.54753 2.94767 8.55469C2.99386 8.60688 3.05818 8.625 3.14062 8.625C3.15319 8.625 3.16576 8.62425 3.17819 8.62275C3.23202 8.61627 3.28333 8.59576 3.32129 8.56121C3.32362 8.55909 3.3259 8.55692 3.32812 8.55469L8.83594 4.03125C8.88281 3.98438 8.95312 3.96094 9.02344 3.96094C9.07031 3.96094 9.14062 3.98438 9.1875 4.03125L14.6953 8.55469ZM2.27344 10.7274C1.89755 10.5959 1.49315 10.355 1.16162 9.92451L0.426251 9.04772L0.32017 8.83555C0.319597 8.83449 0.319 8.83338 0.318378 8.83223C0.304066 8.80565 0.267288 8.73712 0.228043 8.65078C0.161627 8.50467 0 8.12434 0 7.61719C0 7.12558 0.148836 6.71911 0.301167 6.4362C0.439348 6.17958 0.654902 5.88605 0.975475 5.63749L6.90462 0.739506L6.94688 0.707813C7.52384 0.275088 8.25535 0.0234375 9.02344 0.0234375C9.62455 0.0234375 10.201 0.186404 10.691 0.458244C11.0961 0.183444 11.5866 0.0234375 12.1172 0.0234375H13.4297C14.6901 0.0234375 15.9609 1.02855 15.9609 2.55469V4.73359L17.0522 5.64079C17.3704 5.88864 17.5847 6.18072 17.7223 6.4362C17.8746 6.71911 18.0234 7.12558 18.0234 7.61719C18.0234 8.10158 17.8785 8.74439 17.3959 9.28773L16.8618 9.92451C16.5372 10.3461 16.1426 10.5858 15.7734 10.719V12.375C15.7734 13.9179 14.4874 15 13.1484 15H10.5C9.9703 15 9.44888 14.8306 9.01208 14.5304C8.60011 14.823 8.09287 15 7.52344 15H4.89844C3.44486 15 2.27344 13.8286 2.27344 12.375V10.7274Z" fill="#262222"/>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 91 KiB

View File

@@ -3,33 +3,35 @@
/** Colours **/
/*** Coalition: neutral **/
--primary-grey : #CFD9E8;
--secondary-neutral : #111111;
--primary-neutral : #949ba7;
--secondary-neutral-outline : #111111;
--secondary-neutral-text : #111111;
/*** Coalition: blue **/
--primary-blue : #247be2;
--secondary-blue-outline : #082e44;
--secondary-blue-text : #017DC1;
--primary-blue : #247be2;
--secondary-blue-outline : #082e44;
--secondary-blue-text : #017DC1;
/*** Coalition: red **/
--primary-red : #ff5858;
--secondary-red-outline : #262222;
--secondary-red-text : #D42121;
--primary-red : #ff5858;
--secondary-red-outline : #262222;
--secondary-red-text : #D42121;
--accent-green : #8bff63;
--accent-light-blue : #5ca7ff;
--accent-light-red : #F5B6B6;
--accent-green : #8bff63;
--accent-light-blue : #5ca7ff;
--accent-light-red : #F5B6B6;
--background-grey : #3d4651;
--background-slate-blue : #363c43;
--background-offwhite : #f2f2f3;
--background-steel : #202831;
--background-grey : #3d4651;
--background-slate-blue : #363c43;
--background-offwhite : #f2f2f3;
--background-steel : #202831;
--secondary-dark-steel : #181e25;
--secondary-gunmetal-grey : #2f2f2f;
--secondary-light-grey : #797e83;
--secondary-yellow : #ffd46893;
--secondary-dark-steel : #181e25;
--secondary-gunmetal-grey : #2f2f2f;
--secondary-light-grey : #797e83;
--secondary-yellow : #ffd46893;
--background-hover : #f2f2f333;
--nav-text : #ECECEC;
@@ -120,24 +122,19 @@
--unit-aircraft-marker-red-dead-url: url( "/themes/olympus/images/icon_death_red.svg" );
/*** Air units' statuses ***/
/*** Air units' states ***/
--unit-aircraft-status-rtb-height: 50px;
--unit-aircraft-status-rtb-width: 50px;
--unit-aircraft-state-height: 50px;
--unit-aircraft-state-width: 50px;
--unit-aircraft-status-rtb-blue-url: url( "data:image/svg+xml,%3Csvg width='19' height='15' viewBox='0 0 19 15' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M9.8125 4.99219L5.5 8.55469V12.375C5.5 12.5859 5.66406 12.75 5.875 12.75H8.5C8.6875 12.75 8.85156 12.5859 8.85156 12.375V10.125C8.85156 9.9375 9.03906 9.75 9.22656 9.75H10.7266C10.9375 9.75 11.1016 9.9375 11.1016 10.125V12.375C11.1016 12.5859 11.2891 12.75 11.4766 12.75H14.125C14.3125 12.75 14.5 12.5859 14.5 12.375V8.53125L10.1641 4.99219C10.1172 4.94531 10.0469 4.92188 10 4.92188C9.92969 4.92188 9.85938 4.94531 9.8125 4.99219ZM16.6328 7.40625L14.6875 5.78906V2.55469C14.6875 2.39062 14.5469 2.27344 14.4062 2.27344H13.0938C12.9297 2.27344 12.8125 2.39062 12.8125 2.55469V4.24219L10.7031 2.50781C10.5156 2.36719 10.2578 2.27344 10 2.27344C9.71875 2.27344 9.46094 2.36719 9.27344 2.50781L3.34375 7.40625C3.27344 7.45312 3.22656 7.54688 3.22656 7.61719C3.22656 7.6875 3.27344 7.75781 3.29688 7.80469L3.90625 8.53125C3.95312 8.60156 4.02344 8.625 4.11719 8.625C4.1875 8.625 4.25781 8.60156 4.30469 8.55469L9.8125 4.03125C9.85938 3.98438 9.92969 3.96094 10 3.96094C10.0469 3.96094 10.1172 3.98438 10.1641 4.03125L15.6719 8.55469C15.7188 8.60156 15.7891 8.625 15.8594 8.625C15.9531 8.625 16.0234 8.60156 16.0703 8.53125L16.6797 7.80469C16.7266 7.75781 16.75 7.6875 16.75 7.61719C16.75 7.54688 16.7031 7.45312 16.6328 7.40625Z' fill='white'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M14.5 8.53125V12.375C14.5 12.5859 14.3125 12.75 14.125 12.75H11.4766C11.2891 12.75 11.1016 12.5859 11.1016 12.375V10.125C11.1016 9.9375 10.9375 9.75 10.7266 9.75H9.22656C9.03906 9.75 8.85156 9.9375 8.85156 10.125V12.375C8.85156 12.5859 8.6875 12.75 8.5 12.75H5.875C5.66406 12.75 5.5 12.5859 5.5 12.375V8.55469L9.8125 4.99219C9.85938 4.94531 9.92969 4.92188 10 4.92188C10.0469 4.92188 10.1172 4.94531 10.1641 4.99219L14.5 8.53125ZM15.6719 8.55469C15.673 8.55582 15.6741 8.55693 15.6753 8.55803C15.7136 8.5945 15.7664 8.61608 15.8218 8.62275C15.8342 8.62425 15.8468 8.625 15.8594 8.625C15.9531 8.625 16.0234 8.60156 16.0703 8.53125L16.6797 7.80469C16.7266 7.75781 16.75 7.6875 16.75 7.61719C16.75 7.58321 16.7391 7.54375 16.7198 7.50676C16.6992 7.46721 16.6691 7.43047 16.6328 7.40625L14.6875 5.78906V2.55469C14.6875 2.39062 14.5469 2.27344 14.4062 2.27344H13.0938C12.9297 2.27344 12.8125 2.39062 12.8125 2.55469V4.24219L10.7031 2.50781C10.6607 2.47601 10.6147 2.44661 10.5659 2.42014C10.399 2.32958 10.1995 2.27344 10 2.27344C9.71875 2.27344 9.46094 2.36719 9.27344 2.50781L3.34375 7.40625C3.31845 7.42312 3.29618 7.44605 3.27804 7.47178C3.27013 7.483 3.26301 7.49475 3.25676 7.50676C3.25438 7.51134 3.25212 7.51595 3.25 7.52059C3.23497 7.55343 3.22656 7.58741 3.22656 7.61719C3.22656 7.64997 3.23675 7.68274 3.25 7.71315C3.25988 7.73582 3.27147 7.75718 3.2818 7.77623C3.28734 7.78642 3.29251 7.79596 3.29688 7.80469L3.90625 8.53125C3.9119 8.53973 3.9179 8.54753 3.92423 8.55469C3.97043 8.60688 4.03475 8.625 4.11719 8.625C4.12975 8.625 4.14232 8.62425 4.15475 8.62275C4.20858 8.61627 4.2599 8.59576 4.29785 8.56121C4.30018 8.55909 4.30246 8.55692 4.30469 8.55469L9.8125 4.03125C9.85938 3.98438 9.92969 3.96094 10 3.96094C10.0469 3.96094 10.1172 3.98438 10.1641 4.03125L15.6719 8.55469ZM3.25 10.7274C2.87411 10.5959 2.46972 10.355 2.13819 9.92451L1.40281 9.04772L1.29673 8.83555C1.29616 8.83449 1.29556 8.83338 1.29494 8.83223C1.28063 8.80565 1.24385 8.73712 1.20461 8.65078C1.13819 8.50467 0.976562 8.12434 0.976562 7.61719C0.976562 7.12558 1.1254 6.71911 1.27773 6.4362C1.41591 6.17958 1.63146 5.88605 1.95204 5.63749L7.88118 0.739506L7.92344 0.707813C8.5004 0.275088 9.23192 0.0234375 10 0.0234375C10.6011 0.0234375 11.1776 0.186404 11.6675 0.458244C12.0727 0.183444 12.5631 0.0234375 13.0938 0.0234375H14.4062C15.6666 0.0234375 16.9375 1.02855 16.9375 2.55469V4.73359L18.0288 5.64079C18.347 5.88864 18.5613 6.18072 18.6988 6.4362C18.8512 6.71911 19 7.12558 19 7.61719C19 8.10158 18.8551 8.74439 18.3724 9.28773L17.8384 9.92451C17.5137 10.3461 17.1192 10.5858 16.75 10.719V12.375C16.75 13.9179 15.4639 15 14.125 15H11.4766C10.9469 15 10.4254 14.8306 9.98865 14.5304C9.57667 14.823 9.06944 15 8.5 15H5.875C4.42142 15 3.25 13.8286 3.25 12.375V10.7274Z' fill='%23082E44'/%3E%3C/svg%3E" );
--unit-aircraft-status-rtb-neutral-url: url( "data:image/svg+xml,%3Csvg width='19' height='15' viewBox='0 0 19 15' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8.85938 4.99219L4.54688 8.55469V12.375C4.54688 12.5859 4.71094 12.75 4.92188 12.75H7.54688C7.73438 12.75 7.89844 12.5859 7.89844 12.375V10.125C7.89844 9.9375 8.08594 9.75 8.27344 9.75H9.77344C9.98438 9.75 10.1484 9.9375 10.1484 10.125V12.375C10.1484 12.5859 10.3359 12.75 10.5234 12.75H13.1719C13.3594 12.75 13.5469 12.5859 13.5469 12.375V8.53125L9.21094 4.99219C9.16406 4.94531 9.09375 4.92188 9.04688 4.92188C8.97656 4.92188 8.90625 4.94531 8.85938 4.99219ZM15.6797 7.40625L13.7344 5.78906V2.55469C13.7344 2.39062 13.5938 2.27344 13.4531 2.27344H12.1406C11.9766 2.27344 11.8594 2.39062 11.8594 2.55469V4.24219L9.75 2.50781C9.5625 2.36719 9.30469 2.27344 9.04688 2.27344C8.76562 2.27344 8.50781 2.36719 8.32031 2.50781L2.39062 7.40625C2.32031 7.45312 2.27344 7.54688 2.27344 7.61719C2.27344 7.6875 2.32031 7.75781 2.34375 7.80469L2.95312 8.53125C3 8.60156 3.07031 8.625 3.16406 8.625C3.23438 8.625 3.30469 8.60156 3.35156 8.55469L8.85938 4.03125C8.90625 3.98438 8.97656 3.96094 9.04688 3.96094C9.09375 3.96094 9.16406 3.98438 9.21094 4.03125L14.7188 8.55469C14.7656 8.60156 14.8359 8.625 14.9062 8.625C15 8.625 15.0703 8.60156 15.1172 8.53125L15.7266 7.80469C15.7734 7.75781 15.7969 7.6875 15.7969 7.61719C15.7969 7.54688 15.75 7.45312 15.6797 7.40625Z' fill='white'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M13.5469 8.53125V12.375C13.5469 12.5859 13.3594 12.75 13.1719 12.75H10.5234C10.3359 12.75 10.1484 12.5859 10.1484 12.375V10.125C10.1484 9.9375 9.98438 9.75 9.77344 9.75H8.27344C8.08594 9.75 7.89844 9.9375 7.89844 10.125V12.375C7.89844 12.5859 7.73438 12.75 7.54688 12.75H4.92188C4.71094 12.75 4.54688 12.5859 4.54688 12.375V8.55469L8.85938 4.99219C8.90625 4.94531 8.97656 4.92188 9.04688 4.92188C9.09375 4.92188 9.16406 4.94531 9.21094 4.99219L13.5469 8.53125ZM14.7188 8.55469C14.7199 8.55582 14.721 8.55693 14.7222 8.55803C14.7604 8.5945 14.8132 8.61608 14.8687 8.62275C14.8811 8.62425 14.8937 8.625 14.9062 8.625C15 8.625 15.0703 8.60156 15.1172 8.53125L15.7266 7.80469C15.7734 7.75781 15.7969 7.6875 15.7969 7.61719C15.7969 7.58321 15.7859 7.54375 15.7667 7.50676C15.7461 7.46721 15.716 7.43047 15.6797 7.40625L13.7344 5.78906V2.55469C13.7344 2.39062 13.5938 2.27344 13.4531 2.27344H12.1406C11.9766 2.27344 11.8594 2.39062 11.8594 2.55469V4.24219L9.75 2.50781C9.7076 2.47601 9.6616 2.44661 9.61282 2.42014C9.4459 2.32958 9.24639 2.27344 9.04688 2.27344C8.76562 2.27344 8.50781 2.36719 8.32031 2.50781L2.39062 7.40625C2.36532 7.42312 2.34306 7.44605 2.32492 7.47178C2.31701 7.483 2.30989 7.49475 2.30364 7.50676C2.30125 7.51134 2.299 7.51595 2.29688 7.52059C2.28184 7.55343 2.27344 7.58741 2.27344 7.61719C2.27344 7.64997 2.28362 7.68274 2.29688 7.71315C2.30676 7.73582 2.31834 7.75718 2.32868 7.77623C2.33421 7.78642 2.33939 7.79596 2.34375 7.80469L2.95312 8.53125C2.95878 8.53973 2.96477 8.54753 2.97111 8.55469C3.0173 8.60688 3.08162 8.625 3.16406 8.625C3.17663 8.625 3.1892 8.62425 3.20163 8.62275C3.25545 8.61627 3.30677 8.59576 3.34472 8.56121C3.34705 8.55909 3.34933 8.55692 3.35156 8.55469L8.85938 4.03125C8.90625 3.98438 8.97656 3.96094 9.04688 3.96094C9.09375 3.96094 9.16406 3.98438 9.21094 4.03125L14.7188 8.55469ZM2.29688 10.7274C1.92098 10.5959 1.51659 10.355 1.18506 9.92451L0.449688 9.04772L0.343607 8.83555C0.343034 8.83449 0.342438 8.83338 0.341816 8.83223C0.327503 8.80565 0.290725 8.73712 0.25148 8.65078C0.185064 8.50467 0.0234375 8.12434 0.0234375 7.61719C0.0234375 7.12558 0.172273 6.71911 0.324604 6.4362C0.462785 6.17958 0.67834 5.88605 0.998912 5.63749L6.92805 0.739506L6.97031 0.707813C7.54728 0.275088 8.27879 0.0234375 9.04688 0.0234375C9.64799 0.0234375 10.2245 0.186404 10.7144 0.458244C11.1195 0.183444 11.61 0.0234375 12.1406 0.0234375H13.4531C14.7135 0.0234375 15.9844 1.02855 15.9844 2.55469V4.73359L17.0756 5.64079C17.3939 5.88864 17.6081 6.18072 17.7457 6.4362C17.898 6.71911 18.0469 7.12558 18.0469 7.61719C18.0469 8.10158 17.902 8.74439 17.4193 9.28773L16.8852 9.92451C16.5606 10.3461 16.1661 10.5858 15.7969 10.719V12.375C15.7969 13.9179 14.5108 15 13.1719 15H10.5234C9.99374 15 9.47232 14.8306 9.03552 14.5304C8.62355 14.823 8.11631 15 7.54688 15H4.92188C3.4683 15 2.29688 13.8286 2.29688 12.375V10.7274Z' fill='%232F2F2F'/%3E%3C/svg%3E" );
--unit-aircraft-status-rtb-red-url: url( "data:image/svg+xml,%3Csvg width='19' height='15' viewBox='0 0 19 15' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M8.83594 4.99219L4.52344 8.55469V12.375C4.52344 12.5859 4.6875 12.75 4.89844 12.75H7.52344C7.71094 12.75 7.875 12.5859 7.875 12.375V10.125C7.875 9.9375 8.0625 9.75 8.25 9.75H9.75C9.96094 9.75 10.125 9.9375 10.125 10.125V12.375C10.125 12.5859 10.3125 12.75 10.5 12.75H13.1484C13.3359 12.75 13.5234 12.5859 13.5234 12.375V8.53125L9.1875 4.99219C9.14062 4.94531 9.07031 4.92188 9.02344 4.92188C8.95312 4.92188 8.88281 4.94531 8.83594 4.99219ZM15.6562 7.40625L13.7109 5.78906V2.55469C13.7109 2.39062 13.5703 2.27344 13.4297 2.27344H12.1172C11.9531 2.27344 11.8359 2.39062 11.8359 2.55469V4.24219L9.72656 2.50781C9.53906 2.36719 9.28125 2.27344 9.02344 2.27344C8.74219 2.27344 8.48438 2.36719 8.29688 2.50781L2.36719 7.40625C2.29688 7.45312 2.25 7.54688 2.25 7.61719C2.25 7.6875 2.29688 7.75781 2.32031 7.80469L2.92969 8.53125C2.97656 8.60156 3.04688 8.625 3.14062 8.625C3.21094 8.625 3.28125 8.60156 3.32812 8.55469L8.83594 4.03125C8.88281 3.98438 8.95312 3.96094 9.02344 3.96094C9.07031 3.96094 9.14062 3.98438 9.1875 4.03125L14.6953 8.55469C14.7422 8.60156 14.8125 8.625 14.8828 8.625C14.9766 8.625 15.0469 8.60156 15.0938 8.53125L15.7031 7.80469C15.75 7.75781 15.7734 7.6875 15.7734 7.61719C15.7734 7.54688 15.7266 7.45312 15.6562 7.40625Z' fill='white'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M13.5234 8.53125V12.375C13.5234 12.5859 13.3359 12.75 13.1484 12.75H10.5C10.3125 12.75 10.125 12.5859 10.125 12.375V10.125C10.125 9.9375 9.96094 9.75 9.75 9.75H8.25C8.0625 9.75 7.875 9.9375 7.875 10.125V12.375C7.875 12.5859 7.71094 12.75 7.52344 12.75H4.89844C4.6875 12.75 4.52344 12.5859 4.52344 12.375V8.55469L8.83594 4.99219C8.88281 4.94531 8.95312 4.92188 9.02344 4.92188C9.07031 4.92188 9.14062 4.94531 9.1875 4.99219L13.5234 8.53125ZM14.6953 8.55469C14.6964 8.55582 14.6976 8.55693 14.6987 8.55803C14.737 8.5945 14.7898 8.61608 14.8452 8.62275C14.8577 8.62425 14.8702 8.625 14.8828 8.625C14.9766 8.625 15.0469 8.60156 15.0938 8.53125L15.7031 7.80469C15.75 7.75781 15.7734 7.6875 15.7734 7.61719C15.7734 7.58321 15.7625 7.54375 15.7432 7.50676C15.7227 7.46721 15.6926 7.43047 15.6562 7.40625L13.7109 5.78906V2.55469C13.7109 2.39062 13.5703 2.27344 13.4297 2.27344H12.1172C11.9531 2.27344 11.8359 2.39062 11.8359 2.55469V4.24219L9.72656 2.50781C9.68416 2.47601 9.63816 2.44661 9.58938 2.42014C9.42246 2.32958 9.22295 2.27344 9.02344 2.27344C8.74219 2.27344 8.48438 2.36719 8.29688 2.50781L2.36719 7.40625C2.34189 7.42312 2.31962 7.44605 2.30148 7.47178C2.29357 7.483 2.28645 7.49475 2.2802 7.50676C2.27782 7.51134 2.27556 7.51595 2.27344 7.52059C2.25841 7.55343 2.25 7.58741 2.25 7.61719C2.25 7.64997 2.26019 7.68274 2.27344 7.71315C2.28332 7.73582 2.29491 7.75718 2.30524 7.77623C2.31078 7.78642 2.31595 7.79596 2.32031 7.80469L2.92969 8.53125C2.93534 8.53973 2.94134 8.54753 2.94767 8.55469C2.99386 8.60688 3.05818 8.625 3.14062 8.625C3.15319 8.625 3.16576 8.62425 3.17819 8.62275C3.23202 8.61627 3.28333 8.59576 3.32129 8.56121C3.32362 8.55909 3.3259 8.55692 3.32812 8.55469L8.83594 4.03125C8.88281 3.98438 8.95312 3.96094 9.02344 3.96094C9.07031 3.96094 9.14062 3.98438 9.1875 4.03125L14.6953 8.55469ZM2.27344 10.7274C1.89755 10.5959 1.49315 10.355 1.16162 9.92451L0.426251 9.04772L0.32017 8.83555C0.319597 8.83449 0.319 8.83338 0.318378 8.83223C0.304066 8.80565 0.267288 8.73712 0.228043 8.65078C0.161627 8.50467 0 8.12434 0 7.61719C0 7.12558 0.148836 6.71911 0.301167 6.4362C0.439348 6.17958 0.654902 5.88605 0.975475 5.63749L6.90462 0.739506L6.94688 0.707813C7.52384 0.275088 8.25535 0.0234375 9.02344 0.0234375C9.62455 0.0234375 10.201 0.186404 10.691 0.458244C11.0961 0.183444 11.5866 0.0234375 12.1172 0.0234375H13.4297C14.6901 0.0234375 15.9609 1.02855 15.9609 2.55469V4.73359L17.0522 5.64079C17.3704 5.88864 17.5847 6.18072 17.7223 6.4362C17.8746 6.71911 18.0234 7.12558 18.0234 7.61719C18.0234 8.10158 17.8785 8.74439 17.3959 9.28773L16.8618 9.92451C16.5372 10.3461 16.1426 10.5858 15.7734 10.719V12.375C15.7734 13.9179 14.4874 15 13.1484 15H10.5C9.9703 15 9.44888 14.8306 9.01208 14.5304C8.60011 14.823 8.09287 15 7.52344 15H4.89844C3.44486 15 2.27344 13.8286 2.27344 12.375V10.7274Z' fill='%23262222'/%3E%3C/svg%3E" );
--unit-aircraft-state-rtb: url( "/themes/olympus/images/state_rtb.svg" );
--unit-aircraft-state-idle: url( "/themes/olympus/images/state_idle.svg" );
--unit-aircraft-state-attack: url( "/themes/olympus/images/state_attack.svg" );
--unit-aircraft-state-follow: url( "/themes/olympus/images/state_follow.svg" );
--unit-aircraft-state-refuel: url( "/themes/olympus/images/state_refuel.svg" );
--unit-aircraft-state-human: url( "/themes/olympus/images/state_human.svg" );
--unit-aircraft-state-dcs: url( "/themes/olympus/images/state_dcs.svg" );
--unit-aircraft-status-hold-height: 50px;
--unit-aircraft-status-hold-width: 50px;
--unit-aircraft-status-hold-blue-url: url( "data:image/svg+xml,%3Csvg width='18' height='17' viewBox='0 0 18 17' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M9.48873 0.900581C10.6482 -0.282964 12.5476 -0.302474 13.7311 0.857004L15.5175 2.607C16.0935 3.17128 16.4181 3.94367 16.4181 4.75C16.4181 4.98835 16.3897 5.22373 16.3349 5.45165C16.7777 5.85549 17.1041 6.39558 17.2419 7.02558L17.3634 7.58115L17.3634 7.58116C18.1864 11.3434 15.254 14.75 11.5216 14.75H9.59627C9.45579 15.0566 9.26081 15.3446 9.01119 15.5994C7.85171 16.783 5.95232 16.8025 4.76878 15.643L2.98245 13.893C2.40646 13.3287 2.08187 12.5563 2.08187 11.75C2.08187 11.5117 2.11023 11.2763 2.16507 11.0484C1.72225 10.6445 1.3958 10.1044 1.258 9.47436L1.13648 8.91882C1.13648 8.91881 1.13648 8.9188 1.13648 8.9188C0.313576 5.15664 3.24591 1.75 6.97832 1.75H8.90365C9.04413 1.44337 9.23911 1.15538 9.48873 0.900581ZM8.90365 7.75H8.85271C8.88343 7.77715 8.91372 7.80505 8.94357 7.83367C8.92981 7.80595 8.9165 7.77805 8.90365 7.75ZM9.55635 8.66633C9.57011 8.69406 9.58342 8.72195 9.59627 8.75H9.64721C9.61649 8.72285 9.5862 8.69496 9.55635 8.66633Z' fill='%23082E44'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M11.0958 2.47515C11.3856 2.17926 11.8605 2.17438 12.1564 2.46425L13.9427 4.21425C14.0867 4.35532 14.1678 4.54842 14.1678 4.75C14.1678 4.95158 14.0867 5.14468 13.9427 5.28575L12.1564 7.03575C11.8605 7.32562 11.3856 7.32074 11.0958 7.02486C10.8059 6.72897 10.8108 6.25412 11.1067 5.96425L11.5805 5.5H6.9781C5.54192 5.5 4.50895 6.78851 4.79965 8.11751L4.79965 8.11751L4.92117 8.67308C5.00967 9.07772 4.75339 9.4775 4.34875 9.56601C3.9441 9.65452 3.54432 9.39824 3.45581 8.99359L3.33429 8.43803C3.33429 8.43803 3.33429 8.43803 3.33429 8.43802C2.83071 6.13576 4.62343 4 6.9781 4H11.5805L11.1067 3.53575C10.8108 3.24588 10.8059 2.77103 11.0958 2.47515ZM14.1507 6.93399C14.5554 6.84548 14.9552 7.10175 15.0437 7.5064L15.1652 8.06196L14.4609 8.21604L15.1652 8.06196C15.6688 10.3642 13.8761 12.5 11.5214 12.5H6.91894L7.39283 12.9643C7.68872 13.2541 7.69359 13.729 7.40372 14.0249C7.11385 14.3207 6.63901 14.3256 6.34312 14.0357L4.5568 12.2857C4.4128 12.1447 4.33165 11.9516 4.33165 11.75C4.33165 11.5484 4.4128 11.3553 4.5568 11.2143L6.34312 9.46425C6.63901 9.17438 7.11385 9.17926 7.40372 9.47515C7.69359 9.77103 7.68872 10.2459 7.39283 10.5357L6.91894 11H11.5214C12.9576 11 13.9906 9.71149 13.6998 8.38251L13.5783 7.82694C13.4898 7.42229 13.7461 7.02251 14.1507 6.93399Z' fill='white'/%3E%3C/svg%3E" );
--unit-aircraft-status-hold-neutral-url: url( "data:image/svg+xml,%3Csvg width='17' height='17' viewBox='0 0 17 17' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8.5356 0.900581C9.69508 -0.282964 11.5945 -0.302474 12.778 0.857004L14.5643 2.607C15.1403 3.17128 15.4649 3.94367 15.4649 4.75C15.4649 4.98835 15.4366 5.22373 15.3817 5.45165C15.8245 5.85549 16.151 6.39558 16.2888 7.02558L16.4103 7.58115L16.4103 7.58116C17.2333 11.3434 14.3009 14.75 10.5685 14.75H8.64315C8.50267 15.0566 8.30769 15.3446 8.05807 15.5994C6.89859 16.783 4.99919 16.8025 3.81565 15.643L2.02933 13.893C1.45334 13.3287 1.12875 12.5563 1.12875 11.75C1.12875 11.5117 1.15711 11.2763 1.21194 11.0484C0.769126 10.6445 0.442675 10.1044 0.30487 9.47436L0.183357 8.91882C0.183355 8.91881 0.183354 8.9188 0.183352 8.9188C-0.639549 5.15664 2.29279 1.75 6.02519 1.75H7.95052C8.09101 1.44337 8.28598 1.15538 8.5356 0.900581ZM7.95052 7.75H7.89958C7.93031 7.77715 7.9606 7.80505 7.99045 7.83367C7.97668 7.80595 7.96338 7.77805 7.95052 7.75ZM8.60322 8.66633C8.61699 8.69406 8.6303 8.72195 8.64315 8.75H8.69409C8.66337 8.72285 8.63307 8.69496 8.60322 8.66633Z' fill='%232F2F2F'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10.1426 2.47515C10.4325 2.17926 10.9074 2.17438 11.2032 2.46425L12.9896 4.21425C13.1336 4.35532 13.2147 4.54842 13.2147 4.75C13.2147 4.95158 13.1336 5.14468 12.9896 5.28575L11.2032 7.03575C10.9074 7.32562 10.4325 7.32074 10.1426 7.02486C9.85276 6.72897 9.85764 6.25412 10.1535 5.96425L10.6274 5.5H6.02497C4.5888 5.5 3.55582 6.78851 3.84652 8.11751L3.84652 8.11751L3.96804 8.67308C4.05655 9.07772 3.80027 9.4775 3.39562 9.56601C2.99097 9.65452 2.59119 9.39824 2.50268 8.99359L2.38117 8.43803C2.38117 8.43803 2.38117 8.43803 2.38117 8.43802C1.87759 6.13576 3.6703 4 6.02497 4H10.6274L10.1535 3.53575C9.85764 3.24588 9.85276 2.77103 10.1426 2.47515ZM13.1976 6.93399C13.6022 6.84548 14.002 7.10175 14.0905 7.5064L14.2121 8.06196L13.5077 8.21604L14.2121 8.06196C14.7157 10.3642 12.9229 12.5 10.5683 12.5H5.96582L6.4397 12.9643C6.73559 13.2541 6.74047 13.729 6.4506 14.0249C6.16073 14.3207 5.68588 14.3256 5.38999 14.0357L3.60367 12.2857C3.45967 12.1447 3.37853 11.9516 3.37853 11.75C3.37853 11.5484 3.45967 11.3553 3.60367 11.2143L5.38999 9.46425C5.68588 9.17438 6.16073 9.17926 6.4506 9.47515C6.74047 9.77103 6.73559 10.2459 6.4397 10.5357L5.96582 11H10.5683C12.0044 11 13.0374 9.71149 12.7467 8.38251L12.6252 7.82694C12.5367 7.42229 12.7929 7.02251 13.1976 6.93399Z' fill='white'/%3E%3C/svg%3E" );
--unit-aircraft-status-hold-red-url: url( "data:image/svg+xml,%3Csvg width='17' height='17' viewBox='0 0 17 17' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M8.51217 0.900581C9.67164 -0.282964 11.571 -0.302474 12.7546 0.857004L14.5409 2.607C15.1169 3.17128 15.4415 3.94367 15.4415 4.75C15.4415 4.98835 15.4131 5.22373 15.3583 5.45165C15.8011 5.85549 16.1275 6.39558 16.2654 7.02558L16.3869 7.58115L16.3869 7.58116C17.2098 11.3434 14.2774 14.75 10.5451 14.75H8.61971C8.47923 15.0566 8.28425 15.3446 8.03463 15.5994C6.87515 16.783 4.97576 16.8025 3.79221 15.643L2.00589 13.893C1.4299 13.3287 1.10531 12.5563 1.10531 11.75C1.10531 11.5117 1.13367 11.2763 1.1885 11.0484C0.745688 10.6445 0.419237 10.1044 0.281433 9.47436L0.159919 8.91882C0.159918 8.91881 0.159916 8.9188 0.159915 8.9188C-0.662986 5.15664 2.26935 1.75 6.00175 1.75H7.92709C8.06757 1.44337 8.26255 1.15538 8.51217 0.900581ZM7.92709 7.75H7.87615C7.90687 7.77715 7.93716 7.80505 7.96701 7.83367C7.95325 7.80595 7.93994 7.77805 7.92709 7.75ZM8.57979 8.66633C8.59355 8.69406 8.60686 8.72195 8.61971 8.75H8.67065C8.63993 8.72285 8.60963 8.69496 8.57979 8.66633Z' fill='%23262222'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M10.1192 2.47515C10.4091 2.17926 10.8839 2.17438 11.1798 2.46425L12.9661 4.21425C13.1101 4.35532 13.1913 4.54842 13.1913 4.75C13.1913 4.95158 13.1101 5.14468 12.9661 5.28575L11.1798 7.03575C10.8839 7.32562 10.4091 7.32074 10.1192 7.02486C9.82932 6.72897 9.8342 6.25412 10.1301 5.96425L10.604 5.5H6.00153C4.56536 5.5 3.53239 6.78851 3.82309 8.11751L3.82309 8.11751L3.9446 8.67308C4.03311 9.07772 3.77683 9.4775 3.37218 9.56601C2.96754 9.65452 2.56775 9.39824 2.47925 8.99359L2.35773 8.43803C2.35773 8.43803 2.35773 8.43803 2.35773 8.43802C1.85415 6.13576 3.64687 4 6.00153 4H10.604L10.1301 3.53575C9.8342 3.24588 9.82932 2.77103 10.1192 2.47515ZM13.1742 6.93399C13.5788 6.84548 13.9786 7.10175 14.0671 7.5064L14.1886 8.06196L13.4843 8.21604L14.1886 8.06196C14.6922 10.3642 12.8995 12.5 10.5448 12.5H5.94238L6.41627 12.9643C6.71215 13.2541 6.71703 13.729 6.42716 14.0249C6.13729 14.3207 5.66244 14.3256 5.36656 14.0357L3.58023 12.2857C3.43624 12.1447 3.35509 11.9516 3.35509 11.75C3.35509 11.5484 3.43624 11.3553 3.58023 11.2143L5.36656 9.46425C5.66244 9.17438 6.13729 9.17926 6.42716 9.47515C6.71703 9.77103 6.71215 10.2459 6.41627 10.5357L5.94238 11H10.5448C11.981 11 13.014 9.71149 12.7233 8.38251L12.6018 7.82694C12.5132 7.42229 12.7695 7.02251 13.1742 6.93399Z' fill='white'/%3E%3C/svg%3E" );
/*** Ground ***/
--unit-groundunit-marker-height: 50px;
--unit-groundunit-marker-width: 50px;

295
client/routes/api/atc.js Normal file
View File

@@ -0,0 +1,295 @@
var express = require('express');
var app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false}));
app.use(bodyParser.json());
/*
Flight:
"name"
"take-off time"
"priority"
"status"
//*/
function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
function Flight( name, boardId, unitId ) {
this.assignedAltitude = 0;
this.assignedSpeed = 0;
this.id = uuidv4();
this.boardId = boardId;
this.name = name;
this.status = "unknown";
this.takeoffTime = -1;
this.unitId = parseInt( unitId );
}
Flight.prototype.getData = function() {
return {
"assignedAltitude" : this.assignedAltitude,
"assignedSpeed" : this.assignedSpeed,
"id" : this.id,
"boardId" : this.boardId,
"name" : this.name,
"status" : this.status,
"takeoffTime" : this.takeoffTime,
"unitId" : this.unitId
};
}
Flight.prototype.setAssignedAltitude = function( assignedAltitude ) {
if ( isNaN( assignedAltitude ) ) {
return "Altitude must be a number"
}
this.assignedAltitude = parseInt( assignedAltitude );
return true;
}
Flight.prototype.setAssignedSpeed = function( assignedSpeed ) {
if ( isNaN( assignedSpeed ) ) {
return "Speed must be a number"
}
this.assignedSpeed = parseInt( assignedSpeed );
return true;
}
Flight.prototype.setOrder = function( order ) {
this.order = order;
return true;
}
Flight.prototype.setStatus = function( status ) {
if ( [ "unknown", "checkedin", "readytotaxi", "clearedtotaxi", "halted", "terminated" ].indexOf( status ) < 0 ) {
return "Invalid status";
}
this.status = status;
return true;
}
Flight.prototype.setTakeoffTime = function( takeoffTime ) {
if ( takeoffTime === "" || takeoffTime === -1 ) {
this.takeoffTime = -1;
}
if ( isNaN( takeoffTime ) ) {
return "Invalid takeoff time"
}
this.takeoffTime = parseInt( takeoffTime );
return true;
}
function ATCDataHandler( data ) {
this.data = data;
}
ATCDataHandler.prototype.addFlight = function( flight ) {
if ( flight instanceof Flight === false ) {
throw new Error( "Given flight is not an instance of Flight" );
}
this.data.flights[ flight.id ] = flight;
}
ATCDataHandler.prototype.deleteFlight = function( flightId ) {
delete this.data.flights[ flightId ];
}
ATCDataHandler.prototype.getFlight = function( flightId ) {
return this.data.flights[ flightId ] || false;
}
ATCDataHandler.prototype.getFlights = function() {
return this.data.flights;
}
const dataHandler = new ATCDataHandler( {
"flights": {}
} );
/**************************************************************************************************************/
// Endpoints
/**************************************************************************************************************/
app.get( "/flight", ( req, res ) => {
let flights = Object.values( dataHandler.getFlights() );
if ( flights && req.query.boardId ) {
flights = flights.reduce( ( acc, flight ) => {
if ( flight.boardId === req.query.boardId ) {
acc[ flight.id ] = flight;
}
return acc;
}, {} );
}
res.json( flights );
});
app.patch( "/flight/:flightId", ( req, res ) => {
const flightId = req.params.flightId;
const flight = dataHandler.getFlight( flightId );
if ( !flight ) {
res.status( 400 ).send( `Unrecognised flight ID (given: "${req.params.flightId}")` );
}
if ( req.body.hasOwnProperty( "assignedAltitude" ) ) {
const altitudeChangeSuccess = flight.setAssignedAltitude( req.body.assignedAltitude );
if ( altitudeChangeSuccess !== true ) {
res.status( 400 ).send( altitudeChangeSuccess );
}
}
if ( req.body.hasOwnProperty( "assignedSpeed" ) ) {
const speedChangeSuccess = flight.setAssignedSpeed( req.body.assignedSpeed );
if ( speedChangeSuccess !== true ) {
res.status( 400 ).send( speedChangeSuccess );
}
}
if ( req.body.status ) {
const statusChangeSuccess = flight.setStatus( req.body.status );
if ( statusChangeSuccess !== true ) {
res.status( 400 ).send( statusChangeSuccess );
}
}
if ( req.body.hasOwnProperty( "takeoffTime" ) ) {
const takeoffChangeSuccess = flight.setTakeoffTime( req.body.takeoffTime );
if ( takeoffChangeSuccess !== true ) {
res.status( 400 ).send( takeoffChangeSuccess );
}
}
res.json( flight.getData() );
});
app.post( "/flight/order", ( req, res ) => {
if ( !req.body.boardId ) {
res.status( 400 ).send( "Invalid/missing boardId" );
}
if ( !req.body.order || !Array.isArray( req.body.order ) ) {
res.status( 400 ).send( "Invalid/missing boardId" );
}
req.body.order.forEach( ( flightId, i ) => {
dataHandler.getFlight( flightId ).setOrder( i );
});
res.send( "" );
});
app.post( "/flight", ( req, res ) => {
if ( !req.body.boardId ) {
res.status( 400 ).send( "Invalid/missing boardId" );
}
if ( !req.body.name ) {
res.status( 400 ).send( "Invalid/missing flight name" );
}
if ( !req.body.unitId || isNaN( req.body.unitId ) ) {
res.status( 400 ).send( "Invalid/missing unitId" );
}
const flight = new Flight( req.body.name, req.body.boardId, req.body.unitId );
dataHandler.addFlight( flight );
res.status( 201 );
res.json( flight.getData() );
});
app.delete( "/flight/:flightId", ( req, res ) => {
const flight = dataHandler.getFlight( req.params.flightId );
if ( !flight ) {
res.status( 400 ).send( `Unrecognised flight ID (given: "${req.params.flightId}")` );
}
dataHandler.deleteFlight( req.params.flightId );
res.status( 204 ).send( "" );
});
module.exports = app;

View File

@@ -29,18 +29,23 @@ interface MissionData {
}
interface FormationData {
formation: string;
isLeader: boolean;
isWingman: boolean;
leaderID: number;
wingmenIDs: number[];
}
interface TaskData {
currentState: string;
currentTask: string;
activePath: any;
targetSpeed: number;
targetAltitude: number;
isTanker: boolean;
isAWACS: boolean;
TACANChannel: number;
TACANXY: string;
TACANCallsign: string;
radioFrequency: number;
radioCallsign: number;
radioCallsignNumber: number;
}
interface OptionsData {

View File

@@ -8,7 +8,7 @@ export class AICFormation_Single extends AICFormation implements AICFormationInt
"name" = "single";
"numGroups" = 1;
"summary" = "One contact on its own";
"unitBreakdown" = [];
"unitBreakdown": string[] = [];
constructor() {

View File

@@ -1,86 +1,181 @@
import { ToggleableFeature } from "../toggleablefeature";
import Sortable from 'sortablejs';
import { ATCFLightList } from "./flightlist";
import { ATCBoard } from "./atcboard";
import { ATCBoardGround } from "./board/ground";
import { ATCBoardTower } from "./board/tower";
export class ATC extends ToggleableFeature {
export interface FlightInterface {
assignedSpeed: any;
assignedAltitude : any;
id : string;
boardId : string;
name : string;
order : number;
status : "unknown";
takeoffTime : number;
unitId : number;
}
constructor() {
super( true );
//this.#generateFlightList();
class ATCDataHandler {
let $list = document.getElementById( "atc-strip-board-arrivals" );
#atc:ATC;
#flights:{[key:string]: FlightInterface} = {};
if ( $list instanceof HTMLElement ) {
Sortable.create( $list, {
"handle": ".handle"
});
}
#updateInterval:number|undefined = undefined;
#updateIntervalDelay:number = 2500; // Wait between unit update requests
constructor( atc:ATC ) {
this.#atc = atc;
}
#generateFlightList() {
getFlights( boardId:string ) {
const flightList = new ATCFLightList();
const flights:any = flightList.getFlights( true );
return Object.values( this.#flights ).reduce( ( acc:{[key:string]: FlightInterface}, flight ) => {
if ( flight.boardId === boardId ) {
acc[ flight.id ] = flight;
}
const $tbody = document.getElementById( "atc-flight-list-table-body" );
return acc;
}, {} );
}
if ( $tbody instanceof HTMLElement ) {
if ( flights.length > 0 ) {
startUpdates() {
this.#updateInterval = window.setInterval( () => {
let flight:any = {};
const aBoardIsVisible = this.#atc.getBoards().some( board => board.boardIsVisible() );
let $button, i;
if ( aBoardIsVisible ) {
fetch( '/api/atc/flight', {
method: 'GET',
headers: {
'Accept': '*/*',
'Content-Type': 'application/json'
}
})
.then( response => response.json() )
.then( data => {
this.setFlights( data );
});
}
}, this.#updateIntervalDelay );
for ( [ i, flight ] of flights.entries() ) {
const $row = document.createElement( "tr" );
$row.dataset.status = flight.status
let $td = document.createElement( "td" );
$td.innerText = flight.name;
$row.appendChild( $td );
$td = document.createElement( "td" );
$td.innerText = flight.takeOffTime;
$row.appendChild( $td );
$td = document.createElement( "td" );
$td.innerText = "00:0" + ( 5 + i );
$row.appendChild( $td );
$td = document.createElement( "td" );
$td.innerText = flight.status;
$row.appendChild( $td );
}
setFlights( flights:{[key:string]: any} ) {
this.#flights = flights;
}
stopUpdates() {
clearInterval( this.#updateInterval );
}
}
export class ATC {
#boards:ATCBoard[] = [];
#dataHandler:ATCDataHandler;
#initDate:Date = new Date();
constructor() {
this.#dataHandler = new ATCDataHandler( this );
this.lookForBoards();
}
addBoard<T extends ATCBoard>( board:T ) {
board.startUpdates();
this.#boards.push( board );
}
getBoards() {
return this.#boards;
}
getDataHandler() {
return this.#dataHandler;
}
getMissionElapsedSeconds() : number {
return new Date().getTime() - this.#initDate.getTime();
}
getMissionStartDateTime() : Date {
return new Date( 1990, 3, 1, 18, 0, 0 );
}
getMissionDateTime() : Date {
return new Date( this.getMissionStartDateTime().getTime() + this.getMissionElapsedSeconds() );
}
lookForBoards() {
document.querySelectorAll( ".ol-strip-board" ).forEach( board => {
if ( board instanceof HTMLElement ) {
switch ( board.dataset.boardType ) {
case "ground":
this.addBoard( new ATCBoardGround( this, board ) );
return;
$td = document.createElement( "td" );
$button = document.createElement( "button" );
$button.innerText = "...";
case "tower":
this.addBoard( new ATCBoardTower( this, board ) );
return;
default:
console.warn( "Unknown board type for ATC board, got: " + board.dataset.boardType );
$td.appendChild( $button );
$row.appendChild( $td );
$tbody.appendChild( $row );
}
}
}
});
}
startUpdates() {
this.#dataHandler.startUpdates();
}
protected onStatusUpdate(): void {
document.body.classList.toggle( "atc-enabled", this.getStatus() );
stopUpdates() {
this.#dataHandler.stopUpdates();
}

514
client/src/atc/atcboard.ts Normal file
View File

@@ -0,0 +1,514 @@
import { Dropdown } from "../controls/dropdown";
import { zeroAppend } from "../other/utils";
import { ATC } from "./atc";
import { Unit } from "../units/unit";
import { getUnitsManager } from "..";
import Sortable from "sortablejs";
import { FlightInterface } from "./atc";
export interface StripBoardStripInterface {
"id": string,
"element": HTMLElement,
"dropdowns": {[key:string]: Dropdown},
"isDeleted"?: boolean,
"unitId": number
}
export abstract class ATCBoard {
#atc:ATC;
#boardId:string = "";
#templates: {[key:string]: string} = {};
// Elements
#boardElement:HTMLElement;
#clockElement:HTMLElement;
#stripBoardElement:HTMLElement;
// Content
#isAddFlightByClickEnabled:boolean = false;
#strips:{[key:string]: StripBoardStripInterface} = {};
#unitIdsBeingMonitored:number[] = [];
// Update timing
#updateInterval:number|undefined = undefined;
#updateIntervalDelay:number = 1000;
constructor( atc:ATC, boardElement:HTMLElement, options?:{[key:string]: any} ) {
options = options || {};
this.#atc = atc;
this.#boardElement = boardElement;
this.#stripBoardElement = <HTMLElement>this.getBoardElement().querySelector( ".ol-strip-board-strips" );
this.#clockElement = <HTMLElement>this.getBoardElement().querySelector( ".ol-strip-board-clock" );
new MutationObserver( () => {
if ( this.boardIsVisible() ) {
this.startUpdates();
} else {
this.stopUpdates();
}
}).observe( this.getBoardElement(), {
"attributes": true,
"childList": false,
"subtree": false
});
new Sortable( this.getStripBoardElement(), {
"handle": ".handle",
"onUpdate": ev => {
const order = [].slice.call( this.getStripBoardElement().children ).map( ( strip:HTMLElement ) => {
return strip.dataset.flightId
});
fetch( '/api/atc/flight/order', {
method: 'POST',
headers: {
'Accept': '*/*',
'Content-Type': 'application/json'
},
"body": JSON.stringify({
"boardId" : this.getBoardId(),
"order" : order
})
});
}
});
window.setInterval( () => {
this.updateClock();
}, 1000 );
if ( this.#boardElement.classList.contains( "ol-draggable" ) ) {
let options:any = {};
let handle = this.#boardElement.querySelector( ".handle" );
if ( handle instanceof HTMLElement ) {
options.handle = handle;
}
}
this.#setupAddFlight();
// this.#_setupDemoData();
}
addFlight( unit:Unit ) {
const baseData = unit.getBaseData();
const unitCanBeAdded = () => {
if ( baseData.category !== "Aircraft" ) {
return false;
}
if ( baseData.AI === true ) {
// return false;
}
if ( this.#unitIdsBeingMonitored.includes( unit.ID ) ) {
return false;
}
return true;
}
if ( !unitCanBeAdded() ) {
return;
}
this.#unitIdsBeingMonitored.push( unit.ID );
return fetch( '/api/atc/flight/', {
method: 'POST',
headers: {
'Accept': '*/*',
'Content-Type': 'application/json'
},
"body": JSON.stringify({
"boardId" : this.getBoardId(),
"name" : baseData.unitName,
"unitId" : unit.ID
})
});
}
addStrip( strip:StripBoardStripInterface ) {
this.#strips[ strip.id ] = strip;
strip.element.querySelectorAll( "button.deleteFlight" ).forEach( btn => {
btn.addEventListener( "click", ev => {
ev.preventDefault();
this.deleteFlight( strip.id );
});
});
}
boardIsVisible() {
return ( !this.getBoardElement().classList.contains( "hide" ) );
}
calculateTimeToGo( fromTimestamp:number, toTimestamp:number ) {
let timestamp = ( toTimestamp - fromTimestamp ) / 1000;
const hasElapsed = ( timestamp < 0 ) ? true : false;
if ( hasElapsed ) {
timestamp = -( timestamp );
}
const hours = ( timestamp < 3600 ) ? "00" : zeroAppend( Math.floor( timestamp / 3600 ), 2 );
const rMinutes = timestamp % 3600;
const minutes = ( timestamp < 60 ) ? "00" : zeroAppend( Math.floor( rMinutes / 60 ), 2 );
const seconds = zeroAppend( Math.floor( rMinutes % 60 ), 2 );
return {
"elapsedMarker": ( hasElapsed ) ? "+" : "-",
"hasElapsed": hasElapsed,
"hours": hours,
"minutes": minutes,
"seconds": seconds,
"time": `${hours}:${minutes}:${seconds}`,
"totalSeconds": timestamp
};
}
deleteStrip( flightId:string ) {
if ( this.#strips.hasOwnProperty( flightId ) ) {
this.#strips[ flightId ].element.remove();
this.#strips[ flightId ].isDeleted = true;
window.setTimeout( () => {
delete this.#strips[ flightId ];
}, 10000 );
}
}
deleteFlight( flightId:string ) {
this.deleteStrip( flightId );
fetch( '/api/atc/flight/' + flightId, {
method: 'DELETE',
headers: {
'Accept': '*/*',
'Content-Type': 'application/json'
},
"body": JSON.stringify({
"boardId": this.getBoardId()
})
});
}
getATC() {
return this.#atc;
}
getBoardElement() {
return this.#boardElement;
}
getBoardId(): string {
return this.getBoardElement().id;
}
getStripBoardElement() {
return this.#stripBoardElement;
}
getStrips() {
return this.#strips;
}
getStrip( id:string ) {
return this.#strips[ id ] || false;
}
getTemplate( key:string ) {
return this.#templates[ key ] || false;
}
getUnitIdsBeingMonitored() {
return this.#unitIdsBeingMonitored;
}
setTemplates( templates:{[key:string]: string} ) {
this.#templates = templates;
}
#setupAddFlight() {
const toggleIsAddFlightByClickEnabled = () => {
this.#isAddFlightByClickEnabled = ( !this.#isAddFlightByClickEnabled );
this.getBoardElement().classList.toggle( "add-flight-by-click", this.#isAddFlightByClickEnabled );
}
document.addEventListener( "unitSelection", ( ev:CustomEventInit ) => {
if ( this.#isAddFlightByClickEnabled !== true ) {
return;
}
this.addFlight( ev.detail );
toggleIsAddFlightByClickEnabled();
});
const form = <HTMLElement>this.getBoardElement().querySelector( "form.ol-strip-board-add-flight" );
const suggestions = <HTMLElement>form.querySelector( ".ol-auto-suggest" );
const unitName = <HTMLInputElement>form.querySelector( "input[name='unitName']" );
const toggleSuggestions = ( bool:boolean ) => {
suggestions.toggleAttribute( "data-has-suggestions", bool );
}
let searchTimeout:number|null;
unitName.addEventListener( "keyup", ev => {
if ( searchTimeout ) {
clearTimeout( searchTimeout );
}
const resetSuggestions = () => {
suggestions.innerHTML = "";
toggleSuggestions( false );
}
resetSuggestions();
searchTimeout = window.setTimeout( () => {
const searchString = unitName.value.toLowerCase();
if ( searchString === "" ) {
return;
}
const units = getUnitsManager().getSelectableAircraft();
const unitIdsBeingMonitored = this.getUnitIdsBeingMonitored();
const results = Object.keys( units ).reduce( ( acc:Unit[], unitId:any ) => {
const unit = units[ unitId ];
const baseData = unit.getBaseData();
if ( !unitIdsBeingMonitored.includes( parseInt( unitId ) ) && baseData.unitName.toLowerCase().indexOf( searchString ) > -1 ) {
acc.push( unit );
}
return acc;
}, [] );
toggleSuggestions( results.length > 0 );
results.forEach( unit => {
const baseData = unit.getBaseData();
const a = document.createElement( "a" );
a.innerText = baseData.unitName;
a.addEventListener( "click", ev => {
this.addFlight( unit );
resetSuggestions();
unitName.value = "";
});
suggestions.appendChild( a );
});
}, 1000 );
});
form.querySelectorAll( ".add-flight-by-click" ).forEach( el => {
el.addEventListener( "click", ev => {
ev.preventDefault();
toggleIsAddFlightByClickEnabled();
});
});
}
sortFlights( flights:FlightInterface[] ) {
flights.sort( ( a, b ) => {
const aVal = a.order;
const bVal = b.order;
return ( aVal > bVal ) ? 1 : -1;
});
return flights;
}
startUpdates() {
if ( !this.boardIsVisible() ) {
return;
}
this.#updateInterval = window.setInterval( () => {
this.update();
}, this.#updateIntervalDelay );
}
stopUpdates() {
clearInterval( this.#updateInterval );
}
timestampToLocaleTime( timestamp:number ) {
return ( timestamp === -1 ) ? "-" : new Date( timestamp ).toLocaleTimeString();
}
timeToGo( timestamp:number ) {
const timeData = this.calculateTimeToGo( this.getATC().getMissionDateTime().getTime(), timestamp );
return ( timestamp === -1 ) ? "-" : timeData.elapsedMarker + timeData.time;
}
protected update() {
console.warn( "No custom update method defined." );
}
updateClock() {
const now = this.#atc.getMissionDateTime();
this.#clockElement.innerText = now.toLocaleTimeString();
}
updateFlight( flightId:string, reqBody:object ) {
return fetch( '/api/atc/flight/' + flightId, {
method: 'PATCH',
headers: {
'Accept': '*/*',
'Content-Type': 'application/json'
},
"body": JSON.stringify( reqBody )
});
}
#_setupDemoData() {
fetch( '/api/atc/flight/', {
method: 'POST',
headers: {
'Accept': '*/*',
'Content-Type': 'application/json'
},
"body": JSON.stringify({
"boardId" : this.getBoardId(),
"name" : this.getBoardId() + " 1",
"unitId" : 1
})
});
// fetch( '/api/atc/flight/', {
// method: 'POST',
// headers: {
// 'Accept': '*/*',
// 'Content-Type': 'application/json'
// },
// "body": JSON.stringify({
// "boardId" : this.getBoardId(),
// "name" : this.getBoardId() + " 2",
// "unitId" : 2
// })
// });
// fetch( '/api/atc/flight/', {
// method: 'POST',
// headers: {
// 'Accept': '*/*',
// 'Content-Type': 'application/json'
// },
// "body": JSON.stringify({
// "boardId" : this.getBoardId(),
// "name" : this.getBoardId() + " 3",
// "unitId" : 9
// })
// });
}
}

View File

@@ -1,7 +0,0 @@
export abstract class ATCMockAPI {
constructor() {}
generateMockData() {}
}

View File

@@ -1,40 +0,0 @@
import { ATCMockAPI } from "../atcmockapi";
export class ATCMockAPI_Flights extends ATCMockAPI {
generateMockData() {
let data = [];
const statuses = [ "unknown", "checkedIn", "readyToTaxi" ]
for ( const [ i, flightName ] of [ "Shark", "Whale", "Dolphin" ].entries() ) {
data.push({
"name": flightName,
"status": statuses[ i ],
"takeOffTime": "18:0" + i
});
}
localStorage.setItem( "flightList", JSON.stringify( data ) );
}
get( generateMockDataIfEmpty?:boolean ) : object {
generateMockDataIfEmpty = generateMockDataIfEmpty || false;
let data = localStorage.getItem( "flightList" ) || "[]";
if ( data === "[]" && generateMockDataIfEmpty ) {
this.generateMockData();
}
return JSON.parse( data );
}
}

View File

@@ -0,0 +1,200 @@
import { Dropdown } from "../../controls/dropdown";
import { ATC } from "../atc";
import { ATCBoard } from "../atcboard";
export class ATCBoardGround extends ATCBoard {
constructor( atc:ATC, element:HTMLElement ) {
super( atc, element );
}
update() {
const flights = this.sortFlights( Object.values( this.getATC().getDataHandler().getFlights( this.getBoardId() ) ) );
const stripBoard = this.getStripBoardElement();
const missionTime = this.getATC().getMissionDateTime().getTime();
for( const strip of stripBoard.children ) {
strip.toggleAttribute( "data-updating", true );
}
flights.forEach( flight => {
let strip = this.getStrip( flight.id );
if ( !strip ) {
const template = `<div class="ol-strip-board-strip" data-flight-id="${flight.id}" data-flight-status="${flight.status}">
<div class="handle"></div>
<div data-point="name">${flight.name}</div>
<div id="flight-status-${flight.id}" class="ol-select narrow" data-point="status">
<div class="ol-select-value">${flight.status}</div>
<div class="ol-select-options"></div>
</div>
<div data-point="takeoffTime"><input type="text" name="takeoffTime" value="${this.timestampToLocaleTime( flight.takeoffTime )}" /></div>
<div data-point="timeToGo">${this.timeToGo( flight.takeoffTime )}</div>
<button class="deleteFlight">&times;</button>
</div>`;
stripBoard.insertAdjacentHTML( "beforeend", template );
strip = {
"id": flight.id,
"element": <HTMLElement>stripBoard.lastElementChild,
"dropdowns": {},
"unitId": -1
};
strip.element.querySelectorAll( ".ol-select" ).forEach( select => {
switch( select.getAttribute( "data-point" ) ) {
case "status":
strip.dropdowns.status = new Dropdown( select.id, ( value:string, ev:MouseEvent ) => {
fetch( '/api/atc/flight/' + flight.id, {
method: 'PATCH',
headers: {
'Accept': '*/*',
'Content-Type': 'application/json'
},
"body": JSON.stringify({
"status": value
})
});
}, [
"unknown", "checkedin", "readytotaxi", "clearedtotaxi", "halted", "terminated"
]);
break;
}
});
strip.element.querySelectorAll( `input[type="text"]` ).forEach( input => {
if ( input instanceof HTMLInputElement ) {
input.addEventListener( "blur", ( ev ) => {
const target = ev.target;
if ( target instanceof HTMLInputElement ) {
if ( /^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$/.test( target.value ) ) {
target.value += ":00";
}
const value = target.value;
if ( value === target.dataset.previousValue ) {
return;
} else if ( value === "" ) {
this.#updateTakeoffTime( flight.id, -1 );
} else if ( /^([0-1]?[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$/.test( value ) ) {
let [ hours, minutes, seconds ] = value.split( ":" ).map( str => parseInt( str ) );
const missionStart = this.getATC().getMissionStartDateTime();
this.#updateTakeoffTime( flight.id, new Date(
missionStart.getFullYear(),
missionStart.getMonth(),
missionStart.getDate(),
hours,
minutes,
seconds
).getTime() );
} else {
target.value === target.dataset.previousValue
}
}
});
}
});
this.addStrip( strip );
} else {
if ( flight.status !== strip.element.getAttribute( "data-flight-status" ) ) {
strip.element.setAttribute( "data-flight-status", flight.status );
strip.dropdowns.status.selectText( flight.status );
}
strip.element.querySelectorAll( `input[name="takeoffTime"]:not(:focus)` ).forEach( el => {
if ( el instanceof HTMLInputElement ) {
el.value = this.timestampToLocaleTime( flight.takeoffTime );
el.dataset.previousValue = el.value;
}
});
strip.element.querySelectorAll( `[data-point="timeToGo"]` ).forEach( el => {
if ( flight.takeoffTime > 0 && this.calculateTimeToGo( missionTime, flight.takeoffTime ).totalSeconds <= 120 ) {
strip.element.setAttribute( "data-time-warning", "level-1" );
}
if ( el instanceof HTMLElement ) {
el.innerText = this.timeToGo( flight.takeoffTime );
}
});
}
strip.element.toggleAttribute( "data-updating", false );
});
stripBoard.querySelectorAll( `[data-updating]` ).forEach( strip => {
this.deleteStrip( strip.getAttribute( "data-flight-id" ) || "" );
});
}
#updateTakeoffTime = function( flightId:string, time:number ) {
fetch( '/api/atc/flight/' + flightId, {
method: 'PATCH',
headers: {
'Accept': '*/*',
'Content-Type': 'application/json'
},
"body": JSON.stringify({
"takeoffTime": time
})
});
}
}

View File

@@ -0,0 +1,193 @@
import { getUnitsManager } from "../..";
import { Dropdown } from "../../controls/dropdown";
import { ATC } from "../atc";
import { ATCBoard } from "../atcboard";
export class ATCBoardTower extends ATCBoard {
constructor( atc:ATC, element:HTMLElement ) {
super( atc, element );
}
update() {
const flights = this.sortFlights( Object.values( this.getATC().getDataHandler().getFlights( this.getBoardId() ) ) );
const missionTime = this.getATC().getMissionDateTime().getTime();
const selectableUnits = getUnitsManager().getSelectableAircraft();
const stripBoard = this.getStripBoardElement();
for( const strip of stripBoard.children ) {
strip.toggleAttribute( "data-updating", true );
}
flights.forEach( flight => {
let strip = this.getStrip( flight.id );
if ( strip.isDeleted === true ) {
return;
}
const flightData:FlightData = {
latitude: -1,
longitude: -1,
altitude: -1,
heading: -1,
speed: -1,
...( selectableUnits.hasOwnProperty( flight.unitId ) ? selectableUnits[flight.unitId].getFlightData() : {} )
};
if ( !strip ) {
const template = `<div class="ol-strip-board-strip" data-flight-id="${flight.id}" data-flight-status="${flight.status}">
<div class="handle"></div>
<div data-point="name"><a href="#" class="select-unit">${flight.name}</a></div>
<div data-point="assignedAltitude"><input type="text" name="assignedAltitude" value="${flight.assignedAltitude}" size="2" /> 000</div>
<div data-point="altitude">-</div>
<div data-point="assignedSpeed"><input type="text" name="assignedSpeed" value="${flight.assignedSpeed}" size="3" /></div>
<div data-point="speed">-</div>
<button class="deleteFlight">&times;</button>
</div>`;
stripBoard.insertAdjacentHTML( "beforeend", template );
strip = {
"id": flight.id,
"element": <HTMLElement>stripBoard.lastElementChild,
"dropdowns": {},
"unitId": flight.unitId
};
strip.element.querySelectorAll( `input[type="text"]` ).forEach( input => {
if ( input instanceof HTMLInputElement ) {
switch ( input.name ) {
case "assignedAltitude":
input.addEventListener( "change", ( ev ) => {
let val = parseInt( input.value.replace( /[^\d]/g, "" ) );
if ( isNaN( val ) || val < 0 || val > 40 ) {
val = 0;
}
this.updateFlight( flight.id, {
"assignedAltitude": val
});
});
break;
case "assignedSpeed":
input.addEventListener( "change", ( ev ) => {
let val = parseInt( input.value.replace( /[^\d]/g, "" ) );
if ( isNaN( val ) || val < 0 || val > 750 ) {
val = 0;
}
this.updateFlight( flight.id, {
"assignedSpeed": val
});
});
break;
}
}
});
strip.element.querySelectorAll( ".select-unit" ).forEach( el => {
el.addEventListener( "click", ev => {
ev.preventDefault();
getUnitsManager().selectUnit( flight.unitId );
});
});
this.addStrip( strip );
} else {
//
// Altitude
//
let assignedAltitude = <HTMLInputElement>strip.element.querySelector( `input[name="assignedAltitude"]`);
if ( !assignedAltitude.matches( ":focus" ) && assignedAltitude.value !== flight.assignedAltitude ) {
assignedAltitude.value = flight.assignedAltitude;
}
flightData.altitude = Math.floor( flightData.altitude / 0.3048 );
strip.element.querySelectorAll( `[data-point="altitude"]` ).forEach( el => {
if ( el instanceof HTMLElement ) {
el.innerText = "" + flightData.altitude;
}
});
const altitudeDelta = ( flight.assignedAltitude === 0 ) ? 0 : ( flight.assignedAltitude * 1000 ) - flightData.altitude;
strip.element.toggleAttribute( "data-altitude-assigned", ( flight.assignedAltitude > 0 ) );
strip.element.toggleAttribute( "data-warning-altitude", ( altitudeDelta >= 300 || altitudeDelta <= -300 ) );
//
// Speed
//
let assignedSpeed = <HTMLInputElement>strip.element.querySelector( `input[name="assignedSpeed"]`);
if ( !assignedSpeed.matches( ":focus" ) && assignedSpeed.value !== flight.assignedSpeed ) {
assignedSpeed.value = flight.assignedSpeed;
}
flightData.speed = Math.floor( flightData.speed * 1.94384 );
strip.element.querySelectorAll( `[data-point="speed"]` ).forEach( el => {
if ( el instanceof HTMLElement ) {
el.innerText = "" + flightData.speed;
}
});
const speedDelta = ( flight.assignedSpeed === 0 ) ? 0 : flight.assignedSpeed - flightData.speed;
strip.element.toggleAttribute( "data-speed-assigned", ( flight.assignedSpeed > 0 ) );
strip.element.toggleAttribute( "data-warning-speed", ( speedDelta >= 25 || speedDelta <= -25 ) );
}
strip.element.toggleAttribute( "data-updating", false );
});
stripBoard.querySelectorAll( `[data-updating]` ).forEach( strip => {
this.deleteStrip( strip.getAttribute( "data-flight-id" ) || "" );
});
}
}

View File

@@ -1,18 +0,0 @@
import { ATCMockAPI_Flights } from "./atcmockapi/flights";
export class ATCFLightList {
constructor() {
}
getFlights( generateMockDataIfEmpty?:boolean ) {
let api = new ATCMockAPI_Flights();
return api.get( generateMockDataIfEmpty );
}
}

View File

@@ -49,12 +49,12 @@ export class ContextMenu {
if (this.#x + this.#container.offsetWidth < window.innerWidth)
this.#container.style.left = this.#x + "px";
else
this.#container.style.left = window.innerWidth - this.#container.offsetWidth + "px";
this.#container.style.left = window.innerWidth - this.#container.offsetWidth - 10 + "px";
if (this.#y + this.#container.offsetHeight < window.innerHeight)
this.#container.style.top = this.#y + "px";
else
this.#container.style.top = window.innerHeight - this.#container.offsetHeight + "px";
this.#container.style.top = window.innerHeight - this.#container.offsetHeight - 10 + "px";
}
}
}

View File

@@ -5,46 +5,121 @@ export class Dropdown {
#callback: CallableFunction;
#defaultValue: string;
#optionsList: string[] = [];
#index: number = 0;
constructor(ID: string, callback: CallableFunction, options: string[] | null = null)
{
this.#element = <HTMLElement>document.getElementById(ID);
this.#options = <HTMLElement>this.#element.querySelector(".ol-select-options");
this.#value = <HTMLElement>this.#element.querySelector(".ol-select-value");
this.#element = <HTMLElement>document.getElementById(ID);
this.#options = <HTMLElement>this.#element.querySelector(".ol-select-options");
this.#value = <HTMLElement>this.#element.querySelector(".ol-select-value");
this.#defaultValue = this.#value.innerText;
this.#callback = callback;
if (options != null)
this.#callback = callback;
if (options != null) {
this.setOptions(options);
}
this.#value.addEventListener("click", (ev) => {
this.#element.classList.toggle("is-open");
this.#options.classList.toggle("scrollbar-visible", this.#options.scrollHeight > this.#options.clientHeight);
this.#clip();
});
document.addEventListener("click", (ev) => {
if (!(this.#value.contains(ev.target as Node) || this.#options.contains(ev.target as Node) || this.#element.contains(ev.target as Node))) {
this.#element.classList.remove("is-open");
}
});
this.#options.classList.add( "ol-scrollable" );
}
setOptions(optionsList: string[])
{
this.#optionsList = optionsList;
this.#options.replaceChildren(...optionsList.map((option: string) => {
this.#options.replaceChildren(...optionsList.map((option: string, idx: number) => {
var div = document.createElement("div");
var button = document.createElement("button");
button.textContent = option;
div.appendChild(button);
if (option === this.#defaultValue)
this.#index = idx;
button.addEventListener("click", (e: MouseEvent) => {
this.#value.innerText = option;
this.#callback(option);
e.stopPropagation();
this.#value.innerHTML = `<div class = "ol-ellipsed"> ${option} </div>`;
this.#close();
this.#callback(option, e);
this.#index = idx;
});
return div;
}));
}
selectText( text:string ) {
const index = [].slice.call( this.#options.children ).findIndex( ( opt:Element ) => opt.querySelector( "button" )?.innerText === text );
if ( index > -1 ) {
this.selectValue( index );
}
}
selectValue(idx: number)
{
if (idx < this.#optionsList.length)
{
var option = this.#optionsList[idx];
this.#value.innerText = option;
this.#value.innerHTML = `<div class = "ol-ellipsed"> ${option} </div>`;
this.#index = idx;
this.#close();
this.#callback(option);
return true;
}
else
return false;
}
reset() {
this.#options.replaceChildren();
this.#value.innerText = this.#defaultValue;
}
getValue() {
return this.#value.innerText;
}
setValue(value: string) {
var index = this.#optionsList.findIndex((option) => {return option === value});
if (index > -1)
this.selectValue(index);
}
getIndex() {
return this.#index;
}
#clip() {
const options = this.#options;
const bounds = options.getBoundingClientRect();
this.#element.dataset.position = ( bounds.bottom > window.innerHeight ) ? "top" : "";
}
#close() {
this.#element.classList.remove( "is-open" );
this.#element.dataset.position = "";
}
#open() {
this.#element.classList.add( "is-open" );
}
#toggle() {
if ( this.#element.classList.contains( "is-open" ) ) {
this.#close();
} else {
this.#open();
}
}
}

View File

@@ -1,5 +1,5 @@
import { LatLng } from "leaflet";
import { getActiveCoalition, setActiveCoalition } from "..";
import { getActiveCoalition, getMap, setActiveCoalition } from "..";
import { spawnAircraft, spawnGroundUnit, spawnSmoke } from "../server/server";
import { aircraftDatabase } from "../units/aircraftdatabase";
import { groundUnitsDatabase } from "../units/groundunitsdatabase";
@@ -25,7 +25,8 @@ export class MapContextMenu extends ContextMenu {
constructor(id: string) {
super(id);
this.getContainer()?.querySelector("#context-menu-switch")?.addEventListener('change', (e) => this.#onSwitch(e));
this.getContainer()?.querySelector("#context-menu-switch")?.addEventListener('click', (e) => this.#onToggleLeftClick(e));
this.getContainer()?.querySelector("#context-menu-switch")?.addEventListener('contextmenu', (e) => this.#onToggleRightClick(e));
this.#aircraftRoleDropdown = new Dropdown("aircraft-role-options", (role: string) => this.#setAircraftRole(role));
this.#aircraftTypeDropdown = new Dropdown("aircraft-type-options", (type: string) => this.#setAircraftType(type));
@@ -41,14 +42,20 @@ export class MapContextMenu extends ContextMenu {
this.hide();
this.#spawnOptions.coalition = getActiveCoalition();
if (this.#spawnOptions)
{
getMap().addTemporaryMarker(this.#spawnOptions.latlng);
spawnAircraft(this.#spawnOptions);
}
});
document.addEventListener("contextMenuDeployGroundUnit", () => {
this.hide();
this.#spawnOptions.coalition = getActiveCoalition();
if (this.#spawnOptions)
{
getMap().addTemporaryMarker(this.#spawnOptions.latlng);
spawnGroundUnit(this.#spawnOptions);
}
});
document.addEventListener("contextMenuDeploySmoke", (e: any) => {
@@ -97,15 +104,28 @@ export class MapContextMenu extends ContextMenu {
this.#spawnOptions.latlng = latlng;
}
#onSwitch(e: any) {
#onToggleLeftClick(e: any) {
if (this.getContainer() != null) {
if (e.srcElement.checked)
if (e.srcElement.dataset.activeCoalition == "blue")
setActiveCoalition("neutral");
else if (e.srcElement.dataset.activeCoalition == "neutral")
setActiveCoalition("red");
else
setActiveCoalition("blue");
}
}
#onToggleRightClick(e: any) {
if (this.getContainer() != null) {
if (e.srcElement.dataset.activeCoalition == "red")
setActiveCoalition("neutral");
else if (e.srcElement.dataset.activeCoalition == "neutral")
setActiveCoalition("blue");
else
setActiveCoalition("red");
}
}
/********* Aircraft spawn menu *********/
#setAircraftRole(role: string) {
this.#spawnOptions.role = role;
@@ -135,7 +155,6 @@ export class MapContextMenu extends ContextMenu {
image.src = `images/units/${aircraftDatabase.getByLabel(label)?.filename}`;
image.classList.toggle("hide", false);
}
this.clip();
}
@@ -168,8 +187,12 @@ export class MapContextMenu extends ContextMenu {
/********* Ground unit spawn menu *********/
#setGroundUnitRole(role: string) {
this.#spawnOptions.role = role;
this.#resetGroundUnitRole();
this.#groundUnitTypeDropdown.setOptions(groundUnitsDatabase.getByRole(role).map((blueprint) => { return blueprint.label }));
this.#resetGroundUnitType();
const types = groundUnitsDatabase.getByRole(role).map((blueprint) => { return blueprint.label } );
types.sort();
this.#groundUnitTypeDropdown.setOptions( types );
this.#groundUnitTypeDropdown.selectValue(0);
this.clip();
}
@@ -179,7 +202,11 @@ export class MapContextMenu extends ContextMenu {
(<HTMLButtonElement>this.getContainer()?.querySelector("#loadout-list")).replaceChildren();
this.#groundUnitRoleDropdown.reset();
this.#groundUnitTypeDropdown.reset();
this.#groundUnitRoleDropdown.setOptions(groundUnitsDatabase.getRoles());
const roles = groundUnitsDatabase.getRoles();
roles.sort();
this.#groundUnitRoleDropdown.setOptions( roles );
this.clip();
}

View File

@@ -1,16 +1,54 @@
import { getUnitsManager } from "..";
import { deg2rad } from "../other/utils";
import { ContextMenu } from "./contextmenu";
export class UnitContextMenu extends ContextMenu {
#customFormationCallback: CallableFunction | null = null;
constructor(id: string) {
super(id);
document.addEventListener("applyCustomFormation", () => {
var dialog = document.getElementById("custom-formation-dialog");
if (dialog)
{
dialog.classList.add("hide");
var clock = 1;
while (clock < 8)
{
if ((<HTMLInputElement> dialog.querySelector(`#formation-${clock}`)).checked)
break
clock++;
}
var angleDeg = 360 - (clock - 1) * 45;
var angleRad = deg2rad(angleDeg);
var distance = parseInt((<HTMLInputElement> dialog.querySelector(`#distance`)?.querySelector("input")).value) * 0.3048;
var upDown = parseInt((<HTMLInputElement> dialog.querySelector(`#up-down`)?.querySelector("input")).value) * 0.3048;
// X: front-rear, positive front
// Y: top-bottom, positive top
// Z: left-right, positive right
var x = distance * Math.cos(angleRad);
var y = upDown;
var z = distance * Math.sin(angleRad);
if (this.#customFormationCallback)
this.#customFormationCallback({"x": x, "y": y, "z": z})
}
})
}
setOptions(options: string[], callback: CallableFunction)
setCustomFormationCallback(callback: CallableFunction) {
this.#customFormationCallback = callback;
}
setOptions(options: {[key: string]: string}, callback: CallableFunction)
{
this.getContainer()?.replaceChildren(...options.map((option: string) =>
this.getContainer()?.replaceChildren(...Object.keys(options).map((option: string, idx: number) =>
{
var button = document.createElement("button");
button.innerText = option;
button.innerHTML = options[option];
button.addEventListener("click", () => callback(option));
return (button);
}));

View File

@@ -90,7 +90,7 @@ export class FeatureSwitches {
}),
new FeatureSwitch({
"defaultEnabled": false,
"defaultEnabled": true,
"label": "Show splash screen",
"masterSwitch": true,
"name": "splashScreen"
@@ -116,36 +116,24 @@ export class FeatureSwitches {
#testSwitches() {
for ( const featureSwitch of this.#featureSwitches ) {
if ( featureSwitch.isEnabled() ) {
if ( typeof featureSwitch.onEnabled === "function" ) {
featureSwitch.onEnabled();
}
} else {
document.querySelectorAll( "[data-feature-switch='" + featureSwitch.name + "']" ).forEach( el => {
if ( featureSwitch.removeArtifactsIfDisabled === false ) {
el.remove();
} else {
el.classList.add( "hide" );
}
});
}
document.body.classList.toggle( "feature-" + featureSwitch.name, featureSwitch.isEnabled() );
}
}
savePreferences() {
let preferences:any = {};

View File

@@ -9,8 +9,11 @@ import { AIC } from "./aic/aic";
import { ATC } from "./atc/atc";
import { FeatureSwitches } from "./featureswitches";
import { LogPanel } from "./panels/logpanel";
import { getAirbases, getBullseye as getBullseyes, getConfig, getMission, getUnits, setAddress, toggleDemoEnabled } from "./server/server";
import { getAirbases, getBullseye, getConfig, getFreezed, getMission, getUnits, setAddress, setCredentials, setFreezed, startUpdate, toggleDemoEnabled } from "./server/server";
import { UnitDataTable } from "./units/unitdatatable";
import { keyEventWasInInput } from "./other/utils";
import { Popup } from "./popups/popup";
import { Dropdown } from "./controls/dropdown";
var map: Map;
@@ -26,19 +29,18 @@ var unitControlPanel: UnitControlPanel;
var mouseInfoPanel: MouseInfoPanel;
var logPanel: LogPanel;
var connected: boolean = false;
var infoPopup: Popup;
var activeCoalition: string = "blue";
var sessionHash: string | null = null;
var unitDataTable: UnitDataTable;
var featureSwitches;
function setup() {
featureSwitches = new FeatureSwitches();
/* Initialize base functionalitites*/
/* Initialize base functionalitites */
map = new Map('map-container');
unitsManager = new UnitsManager();
missionHandler = new MissionHandler();
@@ -50,104 +52,59 @@ function setup() {
mouseInfoPanel = new MouseInfoPanel("mouse-info-panel");
//logPanel = new LogPanel("log-panel");
/* Popups */
infoPopup = new Popup("info-popup");
/* Controls */
new Dropdown("app-icon", () => { });
/* Unit data table */
unitDataTable = new UnitDataTable("unit-data-table");
/* AIC */
let aicFeatureSwitch = featureSwitches.getSwitch("aic");
if (aicFeatureSwitch?.isEnabled()) {
aic = new AIC();
// TODO: add back buttons
}
/* ATC */
let atcFeatureSwitch = featureSwitches.getSwitch("atc");
if (atcFeatureSwitch?.isEnabled()) {
atc = new ATC();
// TODO: add back buttons
atc.startUpdates();
}
/* Setup event handlers */
setupEvents();
getConfig(readConfig)
/* Load the config file */
getConfig(readConfig);
}
function readConfig(config: any)
{
if (config && config["server"] != undefined && config["server"]["address"] != undefined && config["server"]["port"] != undefined)
{
const address = config["server"]["address"];
const port = config["server"]["port"];
if ((typeof address === 'string' || address instanceof String) && typeof port == 'number')
{
setAddress(<string>address, <number>port);
}
/* On the first connection, force request of full data */
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
getBullseyes((data: BullseyesData) => getMissionData()?.update(data));
getMission((data: any) => {getMissionData()?.update(data)});
getUnits((data: UnitsData) => getUnitsManager()?.update(data), true /* Does a full refresh */);
/* Start periodically requesting updates */
startPeriodicUpdate();
function readConfig(config: any) {
if (config && config["address"] != undefined && config["port"] != undefined) {
const address = config["address"];
const port = config["port"];
if (typeof address === 'string' && typeof port == 'number')
setAddress(address == "*" ? window.location.hostname : address, <number>port);
}
else {
throw new Error('Could not read configuration file!');
}
}
function startPeriodicUpdate() {
requestUpdate();
requestRefresh();
}
function requestUpdate() {
/* Main update rate = 250ms is minimum time, equal to server update time. */
getUnits((data: UnitsData) => {
getUnitsManager()?.update(data);
checkSessionHash(data.sessionHash);
}, false);
setTimeout(() => requestUpdate(), getConnected() ? 250 : 1000);
getConnectionStatusPanel()?.update(getConnected());
}
function requestRefresh() {
/* Main refresh rate = 5000ms. */
getUnits((data: UnitsData) => {
getUnitsManager()?.update(data);
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
getBullseyes((data: BullseyesData) => getMissionData()?.update(data));
getMission((data: any) => {getMissionData()?.update(data)});
// Update the list of existing units
getUnitDataTable()?.update();
checkSessionHash(data.sessionHash);
}, true);
setTimeout(() => requestRefresh(), 5000);
}
function checkSessionHash(newSessionHash: string) {
if (sessionHash != null) {
if (newSessionHash != sessionHash)
location.reload();
}
else
sessionHash = newSessionHash;
}
function setupEvents() {
/* Generic clicks */
document.addEventListener("click", (ev) => {
if (ev instanceof PointerEvent && ev.target instanceof HTMLElement) {
if (ev instanceof MouseEvent && ev.target instanceof HTMLElement) {
const target = ev.target;
if (target.classList.contains("olympus-dialog-close")) {
target.closest("div.olympus-dialog")?.classList.add("hide");
}
const triggerElement = target.closest("[data-on-click]");
if (triggerElement instanceof HTMLElement) {
const eventName: string = triggerElement.dataset.onClick || "";
let params = JSON.parse(triggerElement.dataset.onClickParams || "{}");
@@ -164,73 +121,79 @@ function setupEvents() {
/* Keyup events */
document.addEventListener("keyup", ev => {
if (keyEventWasInInput(ev)) {
return;
}
switch (ev.code) {
case "KeyL":
document.body.toggleAttribute("data-hide-labels");
break;
case "KeyD":
case "KeyT":
toggleDemoEnabled();
break;
case "Minus": // For Veltro's italian layout keyboard, which lacks a quote
case "Quote":
unitDataTable.toggle();
break
case "Space":
setFreezed(!getFreezed());
break;
case "KeyW":
case "KeyA":
case "KeyS":
case "KeyD":
case "ArrowLeft":
case "ArrowRight":
case "ArrowUp":
case "ArrowDown":
getMap().handleMapPanning(ev);
break;
}
});
/*
const unitName = document.getElementById( "unit-name" );
if ( unitName instanceof HTMLInputElement ) {
unitName.addEventListener( "change", ev => {
unitName.setAttribute( "disabled", "true" );
unitName.setAttribute( "readonly", "true" );
// Do something with this:
});
document.addEventListener( "editUnitName", ev => {
unitName.removeAttribute( "disabled" );
unitName.removeAttribute( "readonly" );
unitName.focus();
});
}
//*/
document.addEventListener( "closeDialog", (ev: CustomEventInit) => {
ev.detail._element.closest( ".ol-dialog" ).classList.add( "hide" );
/* Keydown events */
document.addEventListener("keydown", ev => {
if (keyEventWasInInput(ev)) {
return;
}
switch (ev.code) {
case "KeyW":
case "KeyA":
case "KeyS":
case "KeyD":
case "ArrowLeft":
case "ArrowRight":
case "ArrowUp":
case "ArrowDown":
getMap().handleMapPanning(ev);
break;
}
});
document.addEventListener( "toggleElements", (ev: CustomEventInit) => {
document.querySelectorAll( ev.detail.selector ).forEach( el => {
el.classList.toggle( "hide" );
document.addEventListener("closeDialog", (ev: CustomEventInit) => {
ev.detail._element.closest(".ol-dialog").classList.add("hide");
});
document.addEventListener("toggleElements", (ev: CustomEventInit) => {
document.querySelectorAll(ev.detail.selector).forEach(el => {
el.classList.toggle("hide");
})
});
/** Olympus UI ***/
document.querySelectorAll(".ol-select").forEach(select => {
document.addEventListener("tryConnection", () => {
const form = document.querySelector("#splash-content")?.querySelector("#authentication-form");
const username = (<HTMLInputElement> (form?.querySelector("#username"))).value;
const password = (<HTMLInputElement> (form?.querySelector("#password"))).value;
setCredentials(username, btoa("admin" + ":" + password));
// Do open/close toggle
select.addEventListener("click", ev => {
/* Start periodically requesting updates */
startUpdate();
if ( ev.target instanceof HTMLElement && ev.target.nodeName !== "A" ) {
ev.preventDefault();
}
ev.stopPropagation();
select.classList.toggle("is-open");
});
setConnectionStatus("connecting");
})
// Autoclose on mouseleave
select.addEventListener("mouseleave", ev => {
select.classList.remove("is-open");
});
});
document.addEventListener("reloadPage", () => {
location.reload();
})
}
export function getMap() {
@@ -278,12 +241,14 @@ export function getActiveCoalition() {
return activeCoalition;
}
export function setConnected(newConnected: boolean) {
connected = newConnected
export function setConnectionStatus(status: string) {
const el = document.querySelector("#connection-status") as HTMLElement;
if (el)
el.dataset["status"] = status;
}
export function getConnected() {
return connected;
export function getInfoPopup() {
return infoPopup;
}
window.onload = setup;

View File

@@ -45,25 +45,28 @@ export var BoxSelect = Handler.extend({
},
_onMouseDown: function (e: any) {
if (((e.which !== 1) && (e.button !== 0))) { return false; }
if ((e.which == 1 && e.button == 0 && e.shiftKey)) {
// Clear the deferred resetState if it hasn't executed yet, otherwise it
// will interrupt the interaction and orphan a box element in the container.
this._clearDeferredResetState();
this._resetState();
// Clear the deferred resetState if it hasn't executed yet, otherwise it
// will interrupt the interaction and orphan a box element in the container.
this._clearDeferredResetState();
this._resetState();
DomUtil.disableTextSelection();
DomUtil.disableImageDrag();
DomUtil.disableTextSelection();
DomUtil.disableImageDrag();
this._startPoint = this._map.mouseEventToContainerPoint(e);
this._startPoint = this._map.mouseEventToContainerPoint(e);
//@ts-ignore
DomEvent.on(document, {
contextmenu: DomEvent.stop,
mousemove: this._onMouseMove,
mouseup: this._onMouseUp,
keydown: this._onKeyDown
}, this);
//@ts-ignore
DomEvent.on(document, {
contextmenu: DomEvent.stop,
mousemove: this._onMouseMove,
mouseup: this._onMouseUp,
keydown: this._onKeyDown
}, this);
} else {
return false;
}
},
_onMouseMove: function (e: any) {
@@ -114,7 +117,7 @@ export var BoxSelect = Handler.extend({
if (!this._moved) { return; }
// Postpone to next JS tick so internal click event handling
// still see it as "moved".
setTimeout(Util.bind(this._resetState, this), 0);
window.setTimeout(Util.bind(this._resetState, this), 0);
var bounds = new LatLngBounds(
this._map.containerPointToLatLng(this._startPoint),
this._map.containerPointToLatLng(this._point));

View File

@@ -1,24 +1,56 @@
import * as L from "leaflet"
import { MiniMap, MiniMapOptions } from "leaflet-control-mini-map";
import { getUnitsManager } from "..";
import { BoxSelect } from "./boxselect";
import { MapContextMenu } from "../controls/mapcontextmenu";
import { MapContextMenu, SpawnOptions } from "../controls/mapcontextmenu";
import { UnitContextMenu } from "../controls/unitcontextmenu";
import { AirbaseContextMenu } from "../controls/airbasecontextmenu";
import { Dropdown } from "../controls/dropdown";
import { Airbase } from "../missionhandler/airbase";
import { Unit } from "../units/unit";
// TODO a bit of a hack, this module is provided as pure javascript only
require("../../node_modules/leaflet.nauticscale/dist/leaflet.nauticscale.js")
export const IDLE = "IDLE";
export const MOVE_UNIT = "MOVE_UNIT";
L.Map.addInitHook('addHandler', 'boxSelect', BoxSelect);
var temporaryIcon = new L.Icon({
iconUrl: 'images/icon-temporary.png',
iconSize: [52, 52],
iconAnchor: [26, 26]
});
export class ClickableMiniMap extends MiniMap {
constructor(layer: L.TileLayer | L.LayerGroup, options?: MiniMapOptions) {
super(layer, options);
}
getMap() {
//@ts-ignore needed to access not exported member. A bit of a hack, required to access click events
return this._miniMap;
}
}
export class Map extends L.Map {
#state: string;
#layer: L.TileLayer | null = null;
#preventLeftClick: boolean = false;
#leftClickTimer: number = 0;
#deafultPanDelta: number = 100;
#panInterval: number | null = null;
#panLeft: boolean = false;
#panRight: boolean = false;
#panUp: boolean = false;
#panDown: boolean = false;
#lastMousePosition: L.Point = new L.Point(0, 0);
#centerUnit: Unit | null = null;
#miniMap: ClickableMiniMap | null = null;
#miniMapLayerGroup: L.LayerGroup;
#temporaryMarkers: L.Marker[] = [];
#mapContextMenu: MapContextMenu = new MapContextMenu("map-contextmenu");
#unitContextMenu: UnitContextMenu = new UnitContextMenu("unit-contextmenu");
@@ -29,17 +61,67 @@ export class Map extends L.Map {
constructor(ID: string) {
/* Init the leaflet map */
//@ts-ignore
super(ID, { doubleClickZoom: false, zoomControl: false, boxZoom: false, boxSelect: true });
this.setView([37.23, -115.8], 12);
super(ID, { doubleClickZoom: false, zoomControl: false, boxZoom: false, boxSelect: true, zoomAnimation: true, maxBoundsViscosity: 1.0, minZoom: 7, keyboard: true, keyboardPanDelta: 0 });
this.setView([37.23, -115.8], 10);
this.setLayer("ArcGIS Satellite");
/* Minimap */
/* Draw the limits of the maps in the minimap*/
var latlngs = [[ // NTTR
new L.LatLng(39.7982463, -119.985425),
new L.LatLng(34.4037128, -119.7806729),
new L.LatLng(34.3483316, -112.4529351),
new L.LatLng(39.7372411, -112.1130805),
new L.LatLng(39.7982463, -119.985425)
],
[ // Syria
new L.LatLng(37.3630556, 29.2686111),
new L.LatLng(31.8472222, 29.8975),
new L.LatLng(32.1358333, 42.1502778),
new L.LatLng(37.7177778, 42.3716667),
new L.LatLng(37.3630556, 29.2686111)
],
[ // Caucasus
new L.LatLng(39.6170191, 27.634935),
new L.LatLng(38.8735863, 47.1423108),
new L.LatLng(47.3907982, 49.3101946),
new L.LatLng(48.3955879, 26.7753625),
new L.LatLng(39.6170191, 27.634935)
],
[ // Persian Gulf
new L.LatLng(32.9355285, 46.5623682),
new L.LatLng(21.729393, 47.572675),
new L.LatLng(21.8501348, 63.9734737),
new L.LatLng(33.131584, 64.7313594),
new L.LatLng(32.9355285, 46.5623682)
],
[ // Marianas
new L.LatLng(22.09, 135.0572222),
new L.LatLng(10.5777778, 135.7477778),
new L.LatLng(10.7725, 149.3918333),
new L.LatLng(22.5127778, 149.5427778),
new L.LatLng(22.09, 135.0572222)
]
];
var minimapLayer = new L.TileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', { minZoom: 0, maxZoom: 13 });
this.#miniMapLayerGroup = new L.LayerGroup([minimapLayer]);
var miniMapPolyline = new L.Polyline(latlngs, { color: '#202831' });
miniMapPolyline.addTo(this.#miniMapLayerGroup);
/* Scale */
//@ts-ignore TODO more hacking because the module is provided as a pure javascript module only
L.control.scalenautic({ position: "topright", maxWidth: 300, nautic: true, metric: true, imperial: false }).addTo(this);
/* Init the state machine */
this.#state = IDLE;
/* Register event handles */
this.on("click", (e: any) => this.#onClick(e));
this.on("dblclick", (e: any) => this.#onDoubleClick(e));
this.on("dblclick", (e: any) => this.#onDoubleClick(e));
this.on("zoomstart", (e: any) => this.#onZoom(e));
this.on("drag", (e: any) => this.centerOnUnit(null));
this.on("contextmenu", (e: any) => this.#onContextMenu(e));
this.on('selectionend', (e: any) => this.#onSelectionEnd(e));
this.on('mousedown', (e: any) => this.#onMouseDown(e));
@@ -51,13 +133,23 @@ export class Map extends L.Map {
document.body.toggleAttribute("data-hide-" + ev.detail.coalition);
Object.values(getUnitsManager().getUnits()).forEach((unit: Unit) => unit.updateVisibility());
});
document.addEventListener("toggleUnitVisibility", (ev: CustomEventInit) => {
document.body.toggleAttribute("data-hide-" + ev.detail.category);
Object.values(getUnitsManager().getUnits()).forEach((unit: Unit) => unit.updateVisibility());
});
document.addEventListener("unitUpdated", (ev: CustomEvent) => {
if (this.#centerUnit != null && ev.detail == this.#centerUnit)
this.#panToUnit(this.#centerUnit);
});
this.#mapSourceDropdown = new Dropdown("map-type", (layerName: string) => this.setLayer(layerName), this.getLayers())
this.#panInterval = window.setInterval(() => {
this.panBy(new L.Point( ((this.#panLeft? -1: 0) + (this.#panRight? 1: 0)) * this.#deafultPanDelta,
((this.#panUp? -1: 0) + (this.#panDown? 1: 0)) * this.#deafultPanDelta));
}, 20);
}
setLayer(layerName: string) {
@@ -112,10 +204,10 @@ export class Map extends L.Map {
setState(state: string) {
this.#state = state;
if (this.#state === IDLE) {
L.DomUtil.removeClass(this.getContainer(),'crosshair-cursor-enabled');
L.DomUtil.removeClass(this.getContainer(), 'crosshair-cursor-enabled');
}
else if (this.#state === MOVE_UNIT) {
L.DomUtil.addClass(this.getContainer(),'crosshair-cursor-enabled');
L.DomUtil.addClass(this.getContainer(), 'crosshair-cursor-enabled');
}
document.dispatchEvent(new CustomEvent("mapStateChanged"));
}
@@ -125,8 +217,7 @@ export class Map extends L.Map {
}
/* Context Menus */
hideAllContextMenus()
{
hideAllContextMenus() {
this.hideMapContextMenu();
this.hideUnitContextMenu();
this.hideAirbaseContextMenu();
@@ -145,7 +236,7 @@ export class Map extends L.Map {
document.dispatchEvent(new CustomEvent("mapContextMenu"));
}
getMapContextMenu(){
getMapContextMenu() {
return this.#mapContextMenu;
}
@@ -156,7 +247,7 @@ export class Map extends L.Map {
this.#unitContextMenu.show(x, y, e.latlng);
}
getUnitContextMenu(){
getUnitContextMenu() {
return this.#unitContextMenu;
}
@@ -172,7 +263,7 @@ export class Map extends L.Map {
this.#airbaseContextMenu.setAirbase(airbase);
}
getAirbaseContextMenu(){
getAirbaseContextMenu() {
return this.#airbaseContextMenu;
}
@@ -190,17 +281,135 @@ export class Map extends L.Map {
}
/* Spawn from air base */
spawnFromAirbase(e: any)
{
spawnFromAirbase(e: any) {
//this.#aircraftSpawnMenu(e);
}
centerOnUnit(ID: number | null) {
if (ID != null) {
this.options.scrollWheelZoom = 'center';
this.#centerUnit = getUnitsManager().getUnitByID(ID);
}
else {
this.options.scrollWheelZoom = undefined;
this.#centerUnit = null;
}
}
setTheatre(theatre: string) {
var bounds = new L.LatLngBounds([-90, -180], [90, 180]);
var miniMapZoom = 5;
if (theatre == "Syria")
bounds = new L.LatLngBounds([31.8472222, 29.8975], [37.7177778, 42.3716667]);
else if (theatre == "MarianaIslands")
bounds = new L.LatLngBounds([10.5777778, 135.7477778], [22.5127778, 149.5427778]);
else if (theatre == "Nevada")
bounds = new L.LatLngBounds([34.4037128, -119.7806729], [39.7372411, -112.1130805])
else if (theatre == "PersianGulf")
bounds = new L.LatLngBounds([21.729393, 47.572675], [33.131584, 64.7313594])
else if (theatre == "Falklands") {
// TODO
}
else if (theatre == "Caucasus") {
bounds = new L.LatLngBounds([39.6170191, 27.634935], [47.3907982, 49.3101946])
miniMapZoom = 4;
}
this.setView(bounds.getCenter(), 8);
//this.setMaxBounds(bounds);
if (this.#miniMap)
this.#miniMap.remove();
//@ts-ignore // Needed because some of the inputs are wrong in the original module interface
this.#miniMap = new ClickableMiniMap(this.#miniMapLayerGroup, { position: "topright", width: 192 * 1.5, height: 108 * 1.5, zoomLevelFixed: miniMapZoom, centerFixed: bounds.getCenter() }).addTo(this);
this.#miniMap.disableInteractivity();
this.#miniMap.getMap().on("click", (e: any) => {
if (this.#miniMap)
this.setView(e.latlng);
})
}
getMiniMapLayerGroup() {
return this.#miniMapLayerGroup;
}
handleMapPanning(e: any) {
if (e.type === "keyup"){
switch (e.code) {
case "KeyA":
case "ArrowLeft":
this.#panLeft = false;
break;
case "KeyD":
case "ArrowRight":
this.#panRight = false;
break;
case "KeyW":
case "ArrowUp":
this.#panUp = false;
break;
case "KeyS":
case "ArrowDown":
this.#panDown = false;
break;
}
}
else {
switch (e.code)
{
case 'KeyA':
case 'ArrowLeft':
this.#panLeft = true;
break;
case 'KeyD':
case 'ArrowRight':
this.#panRight = true;
break;
case 'KeyW':
case 'ArrowUp':
this.#panUp = true;
break;
case 'KeyS':
case 'ArrowDown':
this.#panDown = true;
break;
}
}
}
addTemporaryMarker(latlng: L.LatLng) {
var marker = new L.Marker(latlng, {icon: temporaryIcon});
marker.addTo(this);
this.#temporaryMarkers.push(marker);
}
removeTemporaryMarker(latlng: L.LatLng) {
var d: number | null = null;
var closest: L.Marker | null = null;
var i: number = 0;
this.#temporaryMarkers.forEach((marker: L.Marker, idx: number) => {
var t = latlng.distanceTo(marker.getLatLng());
if (d == null || t < d) {
d = t;
closest = marker;
i = idx;
}
});
if (closest)
{
this.removeLayer(closest);
delete this.#temporaryMarkers[i];
}
}
/* Event handlers */
#onClick(e: any) {
if (!this.#preventLeftClick) {
this.hideAllContextMenus();
if (this.#state === IDLE) {
}
else if (this.#state === MOVE_UNIT) {
this.setState(IDLE);
@@ -210,7 +419,7 @@ export class Map extends L.Map {
}
#onDoubleClick(e: any) {
}
#onContextMenu(e: any) {
@@ -228,32 +437,34 @@ export class Map extends L.Map {
}
}
#onSelectionEnd(e: any)
{
#onSelectionEnd(e: any) {
clearTimeout(this.#leftClickTimer);
this.#preventLeftClick = true;
this.#leftClickTimer = setTimeout(() => {
this.#preventLeftClick = false;
this.#leftClickTimer = window.setTimeout(() => {
this.#preventLeftClick = false;
}, 200);
getUnitsManager().selectFromBounds(e.selectionBounds);
}
#onMouseDown(e: any)
{
#onMouseDown(e: any) {
this.hideAllContextMenus();
if ((e.originalEvent.which == 1) && (e.originalEvent.button == 0))
this.dragging.disable();
}
#onMouseUp(e: any)
{
if ((e.originalEvent.which == 1) && (e.originalEvent.button == 0))
this.dragging.enable();
#onMouseUp(e: any) {
}
#onMouseMove(e: any)
{
#onMouseMove(e: any) {
this.#lastMousePosition.x = e.originalEvent.x;
this.#lastMousePosition.y = e.originalEvent.y;
}
#onZoom(e: any) {
if (this.#centerUnit != null)
this.#panToUnit(this.#centerUnit);
}
#panToUnit(unit: Unit) {
var unitPosition = new L.LatLng(unit.getFlightData().latitude, unit.getFlightData().longitude);
this.setView(unitPosition, this.getZoom(), { animate: false });
}
}

View File

@@ -1,5 +1,5 @@
import { Marker, LatLng, Icon } from "leaflet";
import { getMap, getUnitsManager } from "..";
import { getInfoPopup, getMap } from "..";
import { Airbase } from "./airbase";
var bullseyeIcons = [
@@ -43,21 +43,12 @@ export class MissionHandler
if ("mission" in data)
{
if (data.mission.theatre != this.#theatre)
if (data.mission != null && data.mission.theatre != this.#theatre)
{
this.#theatre = data.mission.theatre
if (this.#theatre == "Syria")
getMap().setView(new LatLng(34.5, 36.0), 8);
else if (this.#theatre == "MarianaIslands")
getMap().setView(new LatLng(16.7, 145.7), 7);
else if (this.#theatre == "Nevada")
getMap().setView(new LatLng(37.1, -115.2), 8);
else if (this.#theatre == "PersianGulf")
getMap().setView(new LatLng(26.5, 55.3), 8);
else if (this.#theatre == "Falklands")
getMap().setView(new LatLng(-50.6, -42.7), 7);
else if (this.#theatre == "Caucasus")
getMap().setView(new LatLng(42.1, 42.3), 8);
this.#theatre = data.mission.theatre;
getMap().setTheatre(this.#theatre);
getInfoPopup().setText("Map set to " + this.#theatre);
}
}
}
@@ -93,8 +84,8 @@ export class MissionHandler
{
this.#airbasesMarkers[idx].setLatLng(new LatLng(airbase.latitude, airbase.longitude));
this.#airbasesMarkers[idx].setCoalition(airbase.coalition);
this.#airbasesMarkers[idx].setProperties(["Runway 1: 31L / 13R", "Runway 2: 31R / 13L", "TCN: 17X", "ILS: ---" ]);
this.#airbasesMarkers[idx].setParkings(["2x big", "5x small"]);
//this.#airbasesMarkers[idx].setProperties(["Runway 1: 31L / 13R", "Runway 2: 31R / 13L", "TCN: 17X", "ILS: ---" ]);
//this.#airbasesMarkers[idx].setParkings(["2x big", "5x small"]);
}
}
}

View File

@@ -69,6 +69,23 @@ export function distance(lat1: number, lon1: number, lat2: number, lon2: number)
}
export function generateUUIDv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
export function keyEventWasInInput( event:KeyboardEvent ) {
const target = event.target;
return ( target instanceof HTMLElement && ( [ "INPUT", "TEXTAREA" ].includes( target.nodeName ) ) );
}
export function rad2deg(rad: number) {
var pi = Math.PI;
return rad / (pi / 180);

View File

@@ -18,7 +18,7 @@ export class MouseInfoPanel extends Panel {
this.#measureMarker = new Marker([0, 0], {icon: this.#measureIcon, interactive: false});
this.#measureBox = document.createElement("div");
this.#measureBox.classList.add("ol-measure-box");
this.#measureBox.classList.add("ol-measure-box", "hide");
document.body.appendChild(this.#measureBox);
getMap()?.on("click", (e: any) => this.#onMapClick(e));
@@ -36,10 +36,17 @@ export class MouseInfoPanel extends Panel {
var el = <HTMLElement>this.getElement().querySelector(`#bullseye-${idx}`);
if ( el != null ) {
var dist = distance(bullseyes[idx].latitude, bullseyes[idx].longitude, mousePosition.lat, mousePosition.lng);
var bear = bearing(bullseyes[idx].latitude, bullseyes[idx].longitude, mousePosition.lat, mousePosition.lng);
el.dataset.bearing = zeroAppend(Math.floor(bear), 3);
let bng = zeroAppend(Math.floor(bear), 3);
if ( bng === "000" ) {
bng = "360";
}
el.dataset.bearing = bng;
el.dataset.distance = zeroAppend(Math.floor(dist*0.000539957), 3);
el.dataset.distanceUnits = "NM";
}
@@ -75,7 +82,7 @@ export class MouseInfoPanel extends Panel {
el.dataset.bearing = zeroAppend(Math.floor(bear), 3);
el.dataset.distance = zeroAppend(Math.floor(dist*0.000539957), 3);
el.dataset.distanceUnits = "nm";
el.dataset.distanceUnits = "NM";
}
}
@@ -169,7 +176,7 @@ export class MouseInfoPanel extends Panel {
bng = "360";
}
let data = [ `${bng}°`, `${Math.floor(dist*0.000539957)}nm`, `${reciprocal}°` ];
let data = [ `${bng}°`, `${Math.floor(dist*0.000539957)}NM`, `${reciprocal}°` ];
if ( bear < 180 ) {
data = data.reverse();
@@ -222,7 +229,7 @@ export class MouseInfoPanel extends Panel {
pos.dataset.bearing = "---";
pos.dataset.distance = "---";
pos.dataset.distanceUnits = "nm";
pos.dataset.distanceUnits = "NM";
}
}

View File

@@ -1,4 +1,5 @@
import { getUnitsManager } from "..";
import { Dropdown } from "../controls/dropdown";
import { Slider } from "../controls/slider";
import { dataPointMap } from "../other/utils";
import { aircraftDatabase } from "../units/aircraftdatabase";
@@ -7,30 +8,47 @@ import { Aircraft, GroundUnit, Unit } from "../units/unit";
import { UnitDatabase } from "../units/unitdatabase";
import { Panel } from "./panel";
// const ROEs: string[] = ["Free", "Designated free", "Designated", "Return", "Hold"]; // Full list
// const reactionsToThreat: string[] = ["None", "Passive", "Evade", "Escape", "Abort"]; // Full list
const ROEs: string[] = [ "Hold", "Return", "Designated", "Free" ];
const reactionsToThreat: string[] = [ "None", "Passive", "Evade" ];
const ROEs: string[] = ["Hold", "Return", "Designated", "Free"];
const reactionsToThreat: string[] = ["None", "Passive", "Evade"];
const minSpeedValues: { [key: string]: number } = { Aircraft: 100, Helicopter: 0, NavyUnit: 0, GroundUnit: 0 };
const maxSpeedValues: { [key: string]: number } = { Aircraft: 800, Helicopter: 300, NavyUnit: 60, GroundUnit: 60 };
const speedIncrements: { [key: string]: number } = { Aircraft: 25, Helicopter: 10, NavyUnit: 5, GroundUnit: 5 };
const minAltitudeValues: { [key: string]: number } = { Aircraft: 0, Helicopter: 0 };
const maxAltitudeValues: { [key: string]: number } = { Aircraft: 50000, Helicopter: 10000 };
const altitudeIncrements: { [key: string]: number } = { Aircraft: 2500, Helicopter: 1000 };
const altitudeIncrements: { [key: string]: number } = { Aircraft: 500, Helicopter: 100 };
export class UnitControlPanel extends Panel {
#altitudeSlider: Slider;
#airspeedSlider: Slider;
#TACANXYDropdown: Dropdown;
#radioDecimalsDropdown: Dropdown;
#radioCallsignDropdown: Dropdown;
#expectedAltitude: number = -1;
#expectedSpeed: number = -1;
#optionButtons: { [key: string]: HTMLButtonElement[] } = {}
#advancedSettingsDialog: HTMLElement;
constructor(ID: string) {
super(ID);
/* Unit control sliders */
this.#altitudeSlider = new Slider("altitude-slider", 0, 100, "ft", (value: number) => getUnitsManager().selectedUnitsSetAltitude(value * 0.3048));
this.#airspeedSlider = new Slider("airspeed-slider", 0, 100, "kts", (value: number) => getUnitsManager().selectedUnitsSetSpeed(value / 1.94384));
this.#altitudeSlider = new Slider("altitude-slider", 0, 100, "ft", (value: number) => {
this.#expectedAltitude = value;
getUnitsManager().selectedUnitsSetAltitude(value * 0.3048)
});
this.#airspeedSlider = new Slider("airspeed-slider", 0, 100, "kts", (value: number) => {
this.#expectedSpeed = value;
getUnitsManager().selectedUnitsSetSpeed(value / 1.94384)
});
/* Advanced settings dropdowns */
this.#TACANXYDropdown = new Dropdown("TACAN-XY", () => {});
this.#TACANXYDropdown.setOptions(["X", "Y"]);
this.#radioDecimalsDropdown = new Dropdown("radio-decimals", () => {});
this.#radioDecimalsDropdown.setOptions([".000", ".250", ".500", ".750"]);
this.#radioCallsignDropdown = new Dropdown("radio-callsign", () => {});
/* Option buttons */
this.#optionButtons["ROE"] = ROEs.map((option: string, index: number) => {
@@ -52,18 +70,32 @@ export class UnitControlPanel extends Panel {
this.getElement().querySelector("#roe-buttons-container")?.append(...this.#optionButtons["ROE"]);
this.getElement().querySelector("#reaction-to-threat-buttons-container")?.append(...this.#optionButtons["reactionToThreat"]);
document.addEventListener("unitUpdated", (e: CustomEvent<Unit>) => { if (e.detail.getSelected()) this.update() });
document.addEventListener("unitsSelection", (e: CustomEvent<Unit[]>) => { this.show(); this.update() });
this.#advancedSettingsDialog = <HTMLElement> document.querySelector("#advanced-settings-dialog");
window.setInterval(() => {this.update();}, 25);
document.addEventListener("unitsSelection", (e: CustomEvent<Unit[]>) => { this.show(); this.addButtons();});
document.addEventListener("clearSelection", () => { this.hide() });
document.addEventListener("applyAdvancedSettings", () => {this.#applyAdvancedSettings();})
document.addEventListener("showAdvancedSettings", () => {
this.#updateAdvancedSettingsDialog(getUnitsManager().getSelectedUnits());
this.#advancedSettingsDialog.classList.remove("hide");
})
this.hide();
}
update() {
var units = getUnitsManager().getSelectedUnits();
if (this.getElement() != null && units.length > 0) {
this.#showFlightControlSliders(units);
// Do this after panel is hidden (make sure there's a reset)
hide() {
super.hide();
this.#expectedAltitude = -1;
this.#expectedSpeed = -1;
}
addButtons() {
var units = getUnitsManager().getSelectedUnits();
if (units.length < 20) {
this.getElement().querySelector("#selected-units-container")?.replaceChildren(...units.map((unit: Unit, index: number) => {
let database: UnitDatabase | null;
if (unit instanceof Aircraft)
@@ -73,52 +105,71 @@ export class UnitControlPanel extends Panel {
else
database = null; // TODO add databases for other unit types
if (index === 0) {
this.getElement().querySelectorAll(`[data-object|="unit"]`).forEach(marker => {
marker.setAttribute("data-coalition", unit.getMissionData().coalition);
dataPointMap( this.getElement(), {
"shortLabel" : database?.getByName(unit.getBaseData().name)?.shortLabel,
"unitName": unit.getBaseData().unitName
});
});
}
var button = document.createElement("button");
var callsign = unit.getBaseData().unitName || "";
button.innerText = unit.getBaseData().unitName;
button.setAttribute("data-short-label", database?.getByName(unit.getBaseData().name)?.shortLabel || "");
button.setAttribute("data-short-label", database?.getByName(unit.getBaseData().name)?.shortLabel || unit.getBaseData().name);
button.setAttribute("data-callsign", callsign);
button.setAttribute("data-coalition", unit.getMissionData().coalition);
button.classList.add("pill", "highlight-coalition")
button.addEventListener("click", () => getUnitsManager().selectUnit(unit.ID, true));
button.addEventListener("click", () => {
getUnitsManager().deselectAllUnits();
getUnitsManager().selectUnit(unit.ID, true);
});
return (button);
}));
this.#optionButtons["ROE"].forEach((button: HTMLButtonElement) => {
button.classList.toggle("selected", units.every((unit: Unit) => unit.getOptionsData().ROE === button.value))
});
this.#optionButtons["reactionToThreat"].forEach((button: HTMLButtonElement) => {
button.classList.toggle("selected", units.every((unit: Unit) => unit.getOptionsData().reactionToThreat === button.value))
});
} else {
var el = document.createElement("div");
el.innerText = "Too many units selected"
this.getElement().querySelector("#selected-units-container")?.replaceChildren(el);
}
}
#showFlightControlSliders(units: Unit[])
{
if (getUnitsManager().getSelectedUnitsType() !== undefined)
this.#airspeedSlider.show()
update() {
if (this.getVisible()){
var units = getUnitsManager().getSelectedUnits();
this.getElement().querySelector("#advanced-settings-div")?.classList.toggle("hide", units.length != 1);
if (this.getElement() != null && units.length > 0) {
this.#showFlightControlSliders(units);
this.#optionButtons["ROE"].forEach((button: HTMLButtonElement) => {
button.classList.toggle("selected", units.every((unit: Unit) => unit.getOptionsData().ROE === button.value))
});
this.#optionButtons["reactionToThreat"].forEach((button: HTMLButtonElement) => {
button.classList.toggle("selected", units.every((unit: Unit) => unit.getOptionsData().reactionToThreat === button.value))
});
}
}
}
// Update function will only be allowed to update the sliders once it's matched the expected value for the first time (due to lag of Ajax request)
#updateCanSetAltitudeSlider(altitude: number) {
if (this.#expectedAltitude < 0 || altitude === this.#expectedAltitude) {
this.#expectedAltitude = -1;
return true;
}
return false;
}
#updateCanSetSpeedSlider(altitude: number) {
if (this.#expectedSpeed < 0 || altitude === this.#expectedSpeed) {
this.#expectedSpeed = -1;
return true;
}
return false;
}
#showFlightControlSliders(units: Unit[]) {
if (getUnitsManager().getSelectedUnitsType() !== undefined)
this.#airspeedSlider.show()
else
this.#airspeedSlider.hide();
if (getUnitsManager().getSelectedUnitsType() === "Aircraft" || getUnitsManager().getSelectedUnitsType() === "Helicopter")
this.#altitudeSlider.show()
if (getUnitsManager().getSelectedUnitsType() === "Aircraft" || getUnitsManager().getSelectedUnitsType() === "Helicopter")
this.#altitudeSlider.show()
else
this.#altitudeSlider.hide();
@@ -138,16 +189,113 @@ export class UnitControlPanel extends Panel {
this.#altitudeSlider.setIncrement(altitudeIncrements[unitsType]);
this.#airspeedSlider.setActive(targetSpeed != undefined);
if (targetSpeed != undefined)
this.#airspeedSlider.setValue(targetSpeed * 1.94384);
if (targetSpeed != undefined) {
targetSpeed *= 1.94384;
if (this.#updateCanSetSpeedSlider(targetSpeed)) {
this.#airspeedSlider.setValue(targetSpeed);
}
}
this.#altitudeSlider.setActive(targetAltitude != undefined);
if (targetAltitude != undefined)
this.#altitudeSlider.setValue(targetAltitude / 0.3048);
if (targetAltitude != undefined) {
targetAltitude /= 0.3048;
if (this.#updateCanSetAltitudeSlider(targetAltitude)) {
this.#altitudeSlider.setValue(targetAltitude);
}
}
}
else {
this.#airspeedSlider.setActive(false);
this.#altitudeSlider.setActive(false);
}
}
#updateAdvancedSettingsDialog(units: Unit[])
{
if (units.length == 1)
{
const unit = units[0];
(<HTMLElement>this.#advancedSettingsDialog.querySelector("#unit-name")).innerText = unit.getBaseData().unitName;
if (getUnitsManager().getSelectedUnits().length == 1)
{
var radioMHz = Math.floor(unit.getTaskData().radioFrequency / 1000000);
var radioDecimals = (unit.getTaskData().radioFrequency / 1000000 - radioMHz) * 1000;
// Default values for "normal" units
this.#radioCallsignDropdown.setOptions(["Enfield", "Springfield", "Uzi", "Colt", "Dodge", "Ford", "Chevy", "Pontiac"]);
this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign - 1);
// Input values
var tankerCheckbox = this.#advancedSettingsDialog.querySelector("#tanker-checkbox")?.querySelector("input")
var AWACSCheckbox = this.#advancedSettingsDialog.querySelector("#AWACS-checkbox")?.querySelector("input")
var TACANChannelInput = this.#advancedSettingsDialog.querySelector("#TACAN-channel")?.querySelector("input");
var TACANCallsignInput = this.#advancedSettingsDialog.querySelector("#tacan-callsign")?.querySelector("input");
var radioMhzInput = this.#advancedSettingsDialog.querySelector("#radio-mhz")?.querySelector("input");
var radioCallsignNumberInput = this.#advancedSettingsDialog.querySelector("#radio-callsign-number")?.querySelector("input");
if (tankerCheckbox) tankerCheckbox.checked = unit.getTaskData().isTanker;
if (AWACSCheckbox) AWACSCheckbox.checked = unit.getTaskData().isAWACS;
if (TACANChannelInput) TACANChannelInput.value = String(unit.getTaskData().TACANChannel);
if (TACANCallsignInput) TACANCallsignInput.value = String(unit.getTaskData().TACANCallsign);
if (radioMhzInput) radioMhzInput.value = String(radioMHz);
if (radioCallsignNumberInput) radioCallsignNumberInput.value = String(unit.getTaskData().radioCallsignNumber);
this.#TACANXYDropdown.setValue(unit.getTaskData().TACANXY);
this.#radioDecimalsDropdown.setValue("." + radioDecimals);
// Make sure its in the valid range
if (!this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign - 1))
this.#radioCallsignDropdown.selectValue(0);
// Set options for tankers
var roles = aircraftDatabase.getByName(unit.getBaseData().name)?.loadouts.map((loadout) => {return loadout.roles})
if (roles != undefined && Array.prototype.concat.apply([], roles)?.includes("Tanker")){
this.#advancedSettingsDialog.querySelector("#tanker-checkbox")?.classList.remove("hide");
this.#radioCallsignDropdown.setOptions(["Texaco", "Arco", "Shell"]);
this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign - 1);
}
else {
this.#advancedSettingsDialog.querySelector("#tanker-checkbox")?.classList.add("hide");
}
// Set options for AWACS
if (roles != undefined && Array.prototype.concat.apply([], roles)?.includes("AWACS")){
this.#advancedSettingsDialog.querySelector("#AWACS-checkbox")?.classList.remove("hide");
this.#radioCallsignDropdown.setOptions(["Overlord", "Magic", "Wizard", "Focus", "Darkstar"]);
this.#radioCallsignDropdown.selectValue(unit.getTaskData().radioCallsign - 1);
} else {
this.#advancedSettingsDialog.querySelector("#AWACS-checkbox")?.classList.add("hide");
}
}
}
}
#applyAdvancedSettings()
{
const isTanker = this.#advancedSettingsDialog.querySelector("#tanker-checkbox")?.querySelector("input")?.checked? true: false;
const isAWACS = this.#advancedSettingsDialog.querySelector("#AWACS-checkbox")?.querySelector("input")?.checked? true: false;
const TACANChannel = Number(this.#advancedSettingsDialog.querySelector("#TACAN-channel")?.querySelector("input")?.value);
const TACANXY = this.#TACANXYDropdown.getValue();
const TACANCallsign = <string> this.#advancedSettingsDialog.querySelector("#tacan-callsign")?.querySelector("input")?.value
const radioMHz = Number(this.#advancedSettingsDialog.querySelector("#radio-mhz")?.querySelector("input")?.value);
const radioDecimals = this.#radioDecimalsDropdown.getValue();
const radioCallsign = this.#radioCallsignDropdown.getIndex() + 1;
const radioCallsignNumber = Number(this.#advancedSettingsDialog.querySelector("#radio-callsign-number")?.querySelector("input")?.value);
var radioFrequency = (radioMHz * 1000 + Number(radioDecimals.substring(1))) * 1000;
var units = getUnitsManager().getSelectedUnits();
if (units.length > 0)
units[0].setAdvancedOptions(isTanker, isAWACS, TACANChannel, TACANXY, TACANCallsign, radioFrequency, radioCallsign, radioCallsignNumber);
this.#advancedSettingsDialog.classList.add("hide");
}
}

View File

@@ -42,7 +42,7 @@ export class UnitInfoPanel extends Panel {
document.addEventListener("unitsSelection", (e: CustomEvent<Unit[]>) => this.#onUnitsSelection(e.detail));
document.addEventListener("unitsDeselection", (e: CustomEvent<Unit[]>) => this.#onUnitsDeselection(e.detail));
document.addEventListener("clearSelection", () => this.#onUnitsDeselection([]));
document.addEventListener("clearSelection", (e: CustomEvent<Unit[]>) => this.#onUnitsDeselection([]));
document.addEventListener("unitUpdated", (e: CustomEvent<Unit>) => this.#onUnitUpdate(e.detail));
this.hide();
@@ -54,7 +54,7 @@ export class UnitInfoPanel extends Panel {
const baseData = unit.getBaseData();
/* Set the unit info */
this.#unitLabel.innerText = aircraftDatabase.getByName(baseData.name)?.label || "";
this.#unitLabel.innerText = aircraftDatabase.getByName(baseData.name)?.label || baseData.name;
this.#unitName.innerText = baseData.unitName;
this.#unitControl.innerText = ( ( baseData.AI ) ? "AI" : "Human" ) + " controlled";
// this.#groupName.innerText = baseData.groupName;

View File

@@ -0,0 +1,26 @@
import { Panel } from "../panels/panel";
export class Popup extends Panel {
#fadeTime: number = 2000; // Milliseconds
#hideTimer: number | undefined = undefined;
#visibilityTimer: number | undefined = undefined;
setFadeTime(fadeTime: number) {
this.#fadeTime = fadeTime;
}
setText(text: string) {
(<HTMLElement> this.getElement().querySelector("div")).innerText = text;
this.show();
this.getElement().classList.remove("invisible");
this.getElement().classList.add("visible");
clearTimeout(this.#visibilityTimer);
clearTimeout(this.#hideTimer);
this.#visibilityTimer = window.setTimeout(() => {
this.getElement().classList.remove("visible");
this.getElement().classList.add("invisible");
this.#hideTimer = window.setTimeout(() => this.hide(), 2000);
}, this.#fadeTime);
}
}

View File

@@ -1,7 +1,10 @@
import * as L from 'leaflet'
import { setConnected } from '..';
import { getConnectionStatusPanel, getInfoPopup, getMissionData, getUnitDataTable, getUnitsManager, setConnectionStatus } from '..';
import { SpawnOptions } from '../controls/mapcontextmenu';
var connected: boolean = false;
var freezed: boolean = false;
var REST_ADDRESS = "http://localhost:30000/olympus";
var DEMO_ADDRESS = window.location.href + "demo";
const UNITS_URI = "units";
@@ -10,24 +13,46 @@ const AIRBASES_URI = "airbases";
const BULLSEYE_URI = "bullseyes";
const MISSION_URI = "mission";
var username = "";
var credentials = "";
var sessionHash: string | null = null;
var lastUpdateTime = 0;
var demoEnabled = false;
export function toggleDemoEnabled()
{
export function toggleDemoEnabled() {
demoEnabled = !demoEnabled;
}
export function GET(callback: CallableFunction, uri: string){
export function setCredentials(newUsername: string, newCredentials: string) {
username = newUsername;
credentials = newCredentials;
}
export function GET(callback: CallableFunction, uri: string, options?: string) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", `${demoEnabled? DEMO_ADDRESS: REST_ADDRESS}/${uri}`, true);
xmlHttp.open("GET", `${demoEnabled? DEMO_ADDRESS: REST_ADDRESS}/${uri}${options? options: ''}`, true);
if (credentials)
xmlHttp.setRequestHeader("Authorization", "Basic " + credentials);
xmlHttp.onload = function (e) {
var data = JSON.parse(xmlHttp.responseText);
callback(data);
lastUpdateTime = parseInt(data.time);
setConnected(true);
if (xmlHttp.status == 200) {
var data = JSON.parse(xmlHttp.responseText);
if (uri !== UNITS_URI || parseInt(data.time) > lastUpdateTime)
{
callback(data);
lastUpdateTime = parseInt(data.time);
if (isNaN(lastUpdateTime))
lastUpdateTime = 0;
setConnected(true);
}
} else if (xmlHttp.status == 401) {
console.error("Incorrect username/password");
setConnectionStatus("failed");
} else {
setConnected(false);
}
};
xmlHttp.onerror = function () {
xmlHttp.onerror = function (res) {
console.error("An error occurred during the XMLHttpRequest");
setConnected(false);
};
@@ -35,13 +60,15 @@ export function GET(callback: CallableFunction, uri: string){
}
export function POST(request: object, callback: CallableFunction){
var xhr = new XMLHttpRequest();
xhr.open("PUT", demoEnabled? DEMO_ADDRESS: REST_ADDRESS);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = () => {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("PUT", demoEnabled? DEMO_ADDRESS: REST_ADDRESS);
xmlHttp.setRequestHeader("Content-Type", "application/json");
if (credentials)
xmlHttp.setRequestHeader("Authorization", "Basic " + credentials);
xmlHttp.onreadystatechange = () => {
callback();
};
xhr.send(JSON.stringify(request));
xmlHttp.send(JSON.stringify(request));
}
export function getConfig(callback: CallableFunction) {
@@ -50,7 +77,6 @@ export function getConfig(callback: CallableFunction) {
xmlHttp.onload = function (e) {
var data = JSON.parse(xmlHttp.responseText);
callback(data);
lastUpdateTime = parseInt(data.time);
};
xmlHttp.onerror = function () {
console.error("An error occurred during the XMLHttpRequest, could not retrieve configuration file");
@@ -80,7 +106,7 @@ export function getMission(callback: CallableFunction) {
}
export function getUnits(callback: CallableFunction, refresh: boolean = false) {
GET(callback, `${UNITS_URI}?time=${refresh? 0: lastUpdateTime}`);
GET(callback, `${UNITS_URI}`, `?time=${refresh? 0: lastUpdateTime}`);
}
export function addDestination(ID: number, path: any) {
@@ -113,6 +139,16 @@ export function attackUnit(ID: number, targetID: number) {
POST(data, () => { });
}
export function followUnit(ID: number, targetID: number, offset: {"x": number, "y": number, "z": number}) {
// X: front-rear, positive front
// Y: top-bottom, positive bottom
// Z: left-right, positive right
var command = { "ID": ID, "targetID": targetID, "offsetX": offset["x"], "offsetY": offset["y"], "offsetZ": offset["z"]};
var data = { "followUnit": command }
POST(data, () => { });
}
export function cloneUnit(ID: number, latlng: L.LatLng) {
var command = { "ID": ID, "location": latlng };
var data = { "cloneUnit": command }
@@ -172,3 +208,103 @@ export function setReactionToThreat(ID: number, reactionToThreat: string) {
var data = {"setReactionToThreat": command}
POST(data, () => { });
}
export function refuel(ID: number) {
var command = { "ID": ID };
var data = { "refuel": command }
POST(data, () => { });
}
export function setAdvacedOptions(ID: number, isTanker: boolean, isAWACS: boolean, TACANChannel: number, TACANXY: string, TACANCallsign: string, radioFrequency: number, radioCallsign: number, radioCallsignNumber: number)
{
var command = { "ID": ID,
"isTanker": isTanker,
"isAWACS": isAWACS,
"TACANChannel": TACANChannel,
"TACANXY": TACANXY,
"TACANCallsign": TACANCallsign,
"radioFrequency": radioFrequency,
"radioCallsign": radioCallsign,
"radioCallsignNumber": radioCallsignNumber
};
var data = { "setAdvancedOptions": command };
POST(data, () => { });
}
export function startUpdate() {
/* On the first connection, force request of full data */
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
getBullseye((data: BullseyesData) => getMissionData()?.update(data));
getMission((data: any) => { getMissionData()?.update(data) });
getUnits((data: UnitsData) => getUnitsManager()?.update(data), true /* Does a full refresh */);
requestUpdate();
requestRefresh();
}
export function requestUpdate() {
/* Main update rate = 250ms is minimum time, equal to server update time. */
getUnits((data: UnitsData) => {
if (!getFreezed()) {
getUnitsManager()?.update(data);
checkSessionHash(data.sessionHash);
}
}, false);
window.setTimeout(() => requestUpdate(), getConnected() ? 250 : 1000);
getConnectionStatusPanel()?.update(getConnected());
}
export function requestRefresh() {
/* Main refresh rate = 5000ms. */
getUnits((data: UnitsData) => {
if (!getFreezed()) {
getUnitsManager()?.update(data);
getAirbases((data: AirbasesData) => getMissionData()?.update(data));
getBullseye((data: BullseyesData) => getMissionData()?.update(data));
getMission((data: any) => {
getMissionData()?.update(data)
});
// Update the list of existing units
getUnitDataTable()?.update();
checkSessionHash(data.sessionHash);
}
}, true);
window.setTimeout(() => requestRefresh(), 5000);
}
export function checkSessionHash(newSessionHash: string) {
if (sessionHash != null) {
if (newSessionHash != sessionHash)
location.reload();
}
else
sessionHash = newSessionHash;
}
export function setConnected(newConnected: boolean) {
if (connected != newConnected)
newConnected ? getInfoPopup().setText("Connected to DCS Olympus server") : getInfoPopup().setText("Disconnected from DCS Olympus server");
connected = newConnected;
if (connected) {
document.querySelector("#splash-screen")?.classList.add("hide");
document.querySelector("#gray-out")?.classList.add("hide");
}
}
export function getConnected() {
return connected;
}
export function setFreezed(newFreezed: boolean) {
freezed = newFreezed;
freezed ? getInfoPopup().setText("Freezed") : getInfoPopup().setText("Unfreezed");
}
export function getFreezed() {
return freezed;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,571 @@
import { UnitDatabase } from "./unitdatabase"
export class HelicopterDatabase extends UnitDatabase {
constructor() {
super();
this.blueprints = {
"AH-64D_BLK_II": {
"name": "AH-64D_BLK_II",
"label": "AH-64D Apache",
"shortLabel": "AH64",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "AGM-114k Hellfire",
"quantity": 8
},
{
"name": "M151 Rocket Pod",
"quantity": 2
}
],
"roles": [
"CAS"
],
"code": "2 * M261: M151 (6PD), 2 * Hellfire station: 4*AGM-114K",
"name": "Gun / ATGM / Rocket"
},
{
"fuel": 1,
"items": [
{
"name": "AGM-114K Hellfire",
"quantity": 16
}
],
"roles": [
"CAS"
],
"code": "4 * Hellfire station: 4*AGM-114K",
"name": "Gun / ATGM"
},
{
"fuel": 1,
"items": [
],
"roles": [
""
],
"code": "",
"name": "Empty Loadout"
}
],
"filename": "ah-64.png"
},
"Ka-50_3": {
"name": "Ka-50_3",
"label": "Ka-50 Hokum A",
"shortLabel": "K50",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "Igla",
"quantity": 4
}
],
"roles": [
"CAP"
],
"code": "4xIgla",
"name": "Gun / Fox 2"
},
{
"fuel": 1,
"items": [
{
"name": "Igla",
"quantity": 4
},
{
"name": "S-13",
"quantity": 10
},
{
"name": "Kh-25ML",
"quantity": 2
}
],
"roles": [
"Anti-Ship"
],
"code": "2xKh-25ML, 10xS-13, 4xIgla",
"name": "Gun / ASM / Rockets / Fox 2"
},
{
"fuel": 1,
"items": [
{
"name": "Igla",
"quantity": 4
},
{
"name": "S-80FP",
"quantity": 40
},
{
"name": "Vikhr-M",
"quantity": 12
}
],
"roles": [
"CAS"
],
"code": "12x9A4172, 40xS-8OFP, 4xIgla",
"name": "Gun / ATGM / Rockets / Fox 2"
},
{
"fuel": 1,
"items": [
{
"name": "Igla",
"quantity": 4
},
{
"name": "S-80FP",
"quantity": 40
},
{
"name": "Vikhr-M",
"quantity": 12
}
],
"roles": [
"CAS"
],
"code": "12x9A4172, 40xS-8OFP, 4xIgla",
"name": "Gun / ATGM"
},
{
"fuel": 1,
"items": [
{
"name": "Igla",
"quantity": 4
},
{
"name": "FAB-500",
"quantity": 2
},
{
"name": "S-13",
"quantity": 10
}
],
"roles": [
"Strike"
],
"code": "10xS-13, 2xFAB-500, 4xIgla",
"name": "Gun / Bombs / Rockets / Fox 2"
},
{
"fuel": 1,
"items": [
],
"roles": [
""
],
"code": "",
"name": "Empty Loadout"
}
],
"filename": "ka-50.png"
},
"Mi-24P": {
"name": "Mi-24P",
"label": "Mi-24P Hind",
"shortLabel": "Mi24",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "S-8KOM",
"quantity": 40
},
{
"name": "9M114 ATGM",
"quantity": 8
}
],
"roles": [
"CAS"
],
"code": "2xB8V20 (S-8KOM)+8xATGM 9M114",
"name": "Gun / ATGM / Rockets"
},
{
"fuel": 1,
"items": [
{
"name": "S-24B",
"quantity": 4
},
{
"name": "9M114 ATGM",
"quantity": 4
}
],
"roles": [
"Strike"
],
"code": "4xS-24B+4xATGM 9M114",
"name": "Gun / ATGM / Rockets"
},
{
"fuel": 1,
"items": [
{
"name": "GUV-1 Grenade Launcher",
"quantity": 4
},
{
"name": "9M114 ATGM",
"quantity": 4
}
],
"roles": [
"CAS"
],
"code": "4xGUV-1 AP30+4xATGM 9M114",
"name": "Gun / ATGM / Grenade Launcher"
},
{
"fuel": 1,
"items": [
],
"roles": [
""
],
"code": "",
"name": "Empty Loadout"
}
],
"filename": "mi-24.png"
},
"SA342L": {
"name": "SA342L",
"label": "SA342L Gazelle",
"shortLabel": "342",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "20mm Cannon",
"quantity": 1
},
{
"name": "SNEB68",
"quantity": 8
}
],
"roles": [
"Recon"
],
"code": "M621, 8xSNEB68 EAP",
"name": "Gun / ATGM / Rockets"
}
],
"filename": "sa-342.png"
},
"SA342M": {
"name": "SA342M",
"label": "SA342M Gazelle",
"shortLabel": "342",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "HOT3",
"quantity": 4
}
],
"roles": [
"CAS"
],
"code": "HOT3x4",
"name": "ATGM"
}
],
"filename": "sa-342.png"
},
"SA342Mistral": {
"name": "SA342Mistral",
"label": "SA342Mistral Gazelle",
"shortLabel": "342",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "Mistral",
"quantity": 4
}
],
"roles": [
"CAP"
],
"code": "Mistral x 4",
"name": "Fox 2"
},
{
"fuel": 1,
"items": [
],
"roles": [
""
],
"code": "",
"name": "Empty Loadout"
}
],
"filename": "sa-342.png"
},
"AH-1W": {
"name": "AH-1W",
"label": "AH-1W Cobra",
"shortLabel": "AH1",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "BGM-71 TOW",
"quantity": 8
},
{
"name": "Hydra-70 WP",
"quantity": 38
}
],
"roles": [
"CAS"
],
"code": "8xBGM-71, 38xHYDRA-70 WP",
"name": "TOW / Hydra"
},
{
"fuel": 1,
"items": [
{
"name": "Hydra-70",
"quantity": 76
}
],
"roles": [
"CAS"
],
"code": "76xHYDRA-70",
"name": "Hydra"
},
{
"fuel": 1,
"items": [
],
"roles": [
""
],
"code": "",
"name": "Empty Loadout"
}
],
"filename": "ah-1.png"
},
"Mi-26": {
"name": "Mi-26",
"label": "Mi-26 Halo",
"shortLabel": "M26",
"loadouts": [
{
"fuel": 1,
"items": [
],
"roles": [
"Transport"
],
"code": "",
"name": "Empty Loadout"
}
],
"filename": "mi-26.png"
},
"Mi-28N": {
"name": "Mi-28N",
"label": "Mi-28N Havoc",
"shortLabel": "M28",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "9M114 Shturm",
"quantity": 16
},
{
"name": "S-8",
"quantity": 40
}
],
"roles": [
"CAS"
],
"code": "16x9M114, 40xS-8",
"name": "ATGM / S-8"
},
{
"fuel": 1,
"items": [
],
"roles": [
""
],
"code": "",
"name": "Empty Loadout"
}
],
"filename": "mi-28.png"
},
"Mi-8MT": {
"name": "Mi-8MT",
"label": "Mi-8MT Hip",
"shortLabel": "Mi8",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "UPK",
"quantity": 2
},
{
"name": "B8",
"quantity": 2
}
],
"roles": [
"CAS"
],
"code": "2 x UPK +2 x B8",
"name": "Rockets / Gunpods"
},
{
"fuel": 1,
"items": [
],
"roles": [
"Transport"
],
"code": "",
"name": "Empty Loadout"
}
],
"filename": "mi-8.png"
},
"SH-60B": {
"name": "SH-60B",
"label": "SH-60B Blackhawk",
"shortLabel": "S60",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "AGM-119 ASM",
"quantity": 1
}
],
"roles": [
"CAS"
],
"code": "AGM-119",
"name": "ASM"
},
{
"fuel": 1,
"items": [
],
"roles": [
"Transport"
],
"code": "",
"name": "Empty Loadout"
}
],
"filename": "uh-60.png"
},
"UH-60A": {
"name": "UH-60A",
"label": "UH-60A Blackhawk",
"shortLabel": "U60",
"loadouts": [
{
"fuel": 1,
"items": [
],
"roles": [
"Transport"
],
"code": "",
"name": "Empty Loadout"
}
],
"filename": "uh-60.png"
},
"UH-1H": {
"name": "UH-1H",
"label": "UH-1H Huey",
"shortLabel": "UH1",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "M134 Minigun",
"quantity": 2
},
{
"name": "XM-158",
"quantity": 2
}
],
"roles": [
"CAS"
],
"code": "M134 Minigun*2, XM158*2",
"name": "Miniguns / XM158"
},
{
"fuel": 1,
"items": [
],
"roles": [
"Transport"
],
"code": "",
"name": "Empty Loadout"
}
],
"filename": "uh-1.png"
}
}
}
}
export var helicopterDatabase = new HelicopterDatabase();

View File

@@ -1,9 +1,10 @@
import { Marker, LatLng, Polyline, Icon, DivIcon } from 'leaflet';
import { Marker, LatLng, Polyline, Icon, DivIcon, CircleMarker, Map } from 'leaflet';
import { getMap, getUnitsManager } from '..';
import { rad2deg } from '../other/utils';
import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, getUnits, landAt, setAltitude, setReactionToThreat, setROE, setSpeed } from '../server/server';
import { addDestination, attackUnit, changeAltitude, changeSpeed, createFormation as setLeader, deleteUnit, getUnits, landAt, setAltitude, setReactionToThreat, setROE, setSpeed, refuel, setAdvacedOptions, followUnit } from '../server/server';
import { aircraftDatabase } from './aircraftdatabase';
import { groundUnitsDatabase } from './groundunitsdatabase';
import { field } from 'geomag'
var pathIcon = new Icon({
iconUrl: 'images/marker-icon.png',
@@ -39,17 +40,22 @@ export class Unit extends Marker {
coalition: "",
},
formationData: {
formation: "",
isLeader: false,
isWingman: false,
leaderID: 0,
wingmenIDs: [],
leaderID: 0
},
taskData: {
currentState: "IDLE",
currentTask: "",
activePath: {},
targetSpeed: 0,
targetAltitude: 0,
isTanker: false,
isAWACS: false,
TACANChannel: 0,
TACANXY: "X",
TACANCallsign: "",
radioFrequency: 0,
radioCallsign: 0,
radioCallsignNumber: 0
},
optionsData: {
ROE: "",
@@ -59,6 +65,7 @@ export class Unit extends Marker {
#selectable: boolean;
#selected: boolean = false;
#hovered: boolean = false;
#hidden: boolean = false;
#preventClick: boolean = false;
@@ -66,9 +73,9 @@ export class Unit extends Marker {
#pathMarkers: Marker[] = [];
#pathPolyline: Polyline;
#targetsPolylines: Polyline[];
#miniMapMarker: CircleMarker | null = null;
#timer: number = 0;
#forceUpdate: boolean = false;
static getConstructor(type: string) {
if (type === "GroundUnit") return GroundUnit;
@@ -80,7 +87,7 @@ export class Unit extends Marker {
}
constructor(ID: number, data: UpdateData) {
super(new LatLng(0, 0), { riseOnHover: true });
super(new LatLng(0, 0), { riseOnHover: true, keyboard: false });
this.ID = ID;
@@ -89,6 +96,8 @@ export class Unit extends Marker {
this.on('click', (e) => this.#onClick(e));
this.on('dblclick', (e) => this.#onDoubleClick(e));
this.on('contextmenu', (e) => this.#onContextMenu(e));
this.on('mouseover', () => { this.#hovered = true;})
this.on('mouseout', () => { this.#hovered = false;})
this.#pathPolyline = new Polyline([], { color: '#2d3e50', weight: 3, opacity: 0.5, smoothFactor: 1 });
this.#pathPolyline.addTo(getMap());
@@ -96,11 +105,11 @@ export class Unit extends Marker {
/* Deselect units if they are hidden */
document.addEventListener("toggleCoalitionVisibility", (ev: CustomEventInit) => {
setTimeout(() => {this.setSelected(this.getSelected() && !this.getHidden())}, 300);
window.setTimeout(() => {this.setSelected(this.getSelected() && !this.getHidden())}, 300);
});
document.addEventListener("toggleUnitVisibility", (ev: CustomEventInit) => {
setTimeout(() => {this.setSelected(this.getSelected() && !this.getHidden())}, 300);
window.setTimeout(() => {this.setSelected(this.getSelected() && !this.getHidden())}, 300);
});
/* Set the unit data */
@@ -110,10 +119,10 @@ export class Unit extends Marker {
var icon = new DivIcon({
html: this.getMarkerHTML(),
className: 'leaflet-unit-marker',
iconAnchor: [0, 0]
iconAnchor: [25, 25],
iconSize: [50, 50],
});
this.setIcon(icon);
}
getMarkerHTML() {
@@ -130,15 +139,14 @@ export class Unit extends Marker {
return "";
}
/********************** Unit data *************************/
setData(data: UpdateData) {
document.dispatchEvent(new CustomEvent("unitUpdated", { detail: this }));
var updateMarker = false;
if ((data.flightData.latitude != undefined && data.flightData.longitude != undefined && (this.getFlightData().latitude != data.flightData.latitude || this.getFlightData().longitude != data.flightData.longitude))
|| (data.flightData.heading != undefined && this.getFlightData().heading != data.flightData.heading)
|| (data.baseData.alive != undefined && this.getBaseData().alive != data.baseData.alive)
|| this.#forceUpdate || !getMap().hasLayer(this))
updateMarker = true;
/* Check if data has changed comparing new values to old values */
const positionChanged = (data.flightData != undefined && data.flightData.latitude != undefined && data.flightData.longitude != undefined && (this.getFlightData().latitude != data.flightData.latitude || this.getFlightData().longitude != data.flightData.longitude));
const headingChanged = (data.flightData != undefined && data.flightData.heading != undefined && this.getFlightData().heading != data.flightData.heading);
const aliveChanged = (data.baseData != undefined && data.baseData.alive != undefined && this.getBaseData().alive != data.baseData.alive);
var updateMarker = (positionChanged || headingChanged || aliveChanged || !getMap().hasLayer(this))
if (data.baseData != undefined)
{
@@ -201,6 +209,8 @@ export class Unit extends Marker {
}
else
this.#clearPath();
document.dispatchEvent(new CustomEvent("unitUpdated", { detail: this }));
}
getData() {
@@ -255,22 +265,7 @@ export class Unit extends Marker {
return this.#selectable;
}
addDestination(latlng: L.LatLng) {
var path: any = {};
if (this.getTaskData().activePath != undefined) {
path = this.getTaskData().activePath;
path[(Object.keys(path).length + 1).toString()] = latlng;
}
else {
path = { "1": latlng };
}
addDestination(this.ID, path);
}
clearDestinations() {
this.getTaskData().activePath = undefined;
}
/********************** Visibility *************************/
updateVisibility()
{
this.setHidden( document.body.getAttribute(`data-hide-${this.getMissionData().coalition}`) != null ||
@@ -301,78 +296,114 @@ export class Unit extends Marker {
return getUnitsManager().getUnitByID(this.getFormationData().leaderID);
}
getFormation() {
return [<Unit>this].concat(this.getWingmen())
/********************** Unit commands *************************/
addDestination(latlng: L.LatLng) {
if (!this.getMissionData().flags.Human) {
var path: any = {};
if (this.getTaskData().activePath != undefined) {
path = this.getTaskData().activePath;
path[(Object.keys(path).length + 1).toString()] = latlng;
}
else {
path = { "1": latlng };
}
addDestination(this.ID, path);
}
}
getWingmen() {
var wingmen: Unit[] = [];
if (this.getFormationData().wingmenIDs != undefined) {
for (let ID of this.getFormationData().wingmenIDs) {
var unit = getUnitsManager().getUnitByID(ID)
if (unit)
wingmen.push(unit);
}
}
return wingmen;
clearDestinations() {
if (!this.getMissionData().flags.Human)
this.getTaskData().activePath = undefined;
}
attackUnit(targetID: number) {
/* Call DCS attackUnit function */
if (this.ID != targetID) {
attackUnit(this.ID, targetID);
}
else {
// TODO: show a message
}
/* Units can't attack themselves */
if (!this.getMissionData().flags.Human)
if (this.ID != targetID)
attackUnit(this.ID, targetID);
}
followUnit(targetID: number, offset: {"x": number, "y": number, "z": number}) {
/* Units can't follow themselves */
if (!this.getMissionData().flags.Human)
if (this.ID != targetID)
followUnit(this.ID, targetID, offset);
}
landAt(latlng: LatLng) {
landAt(this.ID, latlng);
if (!this.getMissionData().flags.Human)
landAt(this.ID, latlng);
}
changeSpeed(speedChange: string) {
changeSpeed(this.ID, speedChange);
if (!this.getMissionData().flags.Human)
changeSpeed(this.ID, speedChange);
}
changeAltitude(altitudeChange: string) {
changeAltitude(this.ID, altitudeChange);
if (!this.getMissionData().flags.Human)
changeAltitude(this.ID, altitudeChange);
}
setSpeed(speed: number) {
setSpeed(this.ID, speed);
if (!this.getMissionData().flags.Human)
setSpeed(this.ID, speed);
}
setAltitude(altitude: number) {
setAltitude(this.ID, altitude);
if (!this.getMissionData().flags.Human)
setAltitude(this.ID, altitude);
}
setROE(ROE: string) {
setROE(this.ID, ROE);
if (!this.getMissionData().flags.Human)
setROE(this.ID, ROE);
}
setReactionToThreat(reactionToThreat: string) {
setReactionToThreat(this.ID, reactionToThreat);
if (!this.getMissionData().flags.Human)
setReactionToThreat(this.ID, reactionToThreat);
}
setLeader(isLeader: boolean, wingmenIDs: number[] = []) {
setLeader(this.ID, isLeader, wingmenIDs);
if (!this.getMissionData().flags.Human)
setLeader(this.ID, isLeader, wingmenIDs);
}
delete() {
// TODO: add confirmation popup
deleteUnit(this.ID);
}
refuel() {
if (!this.getMissionData().flags.Human)
refuel(this.ID);
}
setAdvancedOptions(isTanker: boolean, isAWACS: boolean, TACANChannel: number, TACANXY: string, TACANcallsign: string, radioFrequency: number, radioCallsign: number, radioCallsignNumber: number) {
if (!this.getMissionData().flags.Human)
setAdvacedOptions(this.ID, isTanker, isAWACS, TACANChannel, TACANXY, TACANcallsign, radioFrequency, radioCallsign, radioCallsignNumber);
}
/***********************************************/
onAdd(map: Map): this {
super.onAdd(map);
getMap().removeTemporaryMarker(new LatLng(this.getFlightData().latitude, this.getFlightData().longitude));
return this;
}
/***********************************************/
#onClick(e: any) {
this.#timer = setTimeout(() => {
if (!this.#preventClick) {
if (getMap().getState() === 'IDLE' || getMap().getState() === 'MOVE_UNIT' || e.originalEvent.ctrlKey) {
if (!e.originalEvent.ctrlKey) {
getUnitsManager().deselectAllUnits();
}
this.setSelected(true);
if (!this.#preventClick) {
if (getMap().getState() === 'IDLE' || getMap().getState() === 'MOVE_UNIT' || e.originalEvent.ctrlKey) {
if (!e.originalEvent.ctrlKey) {
getUnitsManager().deselectAllUnits();
}
this.setSelected(!this.getSelected());
}
}
this.#timer = window.setTimeout(() => {
this.#preventClick = false;
}, 200);
}
@@ -383,66 +414,185 @@ export class Unit extends Marker {
}
#onContextMenu(e: any) {
var options = [
'Attack'
]
if (getUnitsManager().getSelectedUnits().length > 0 && !(getUnitsManager().getSelectedUnits().includes(this)))
var options: {[key: string]: string} = {};
options["Center"] = `<div id="center-map">Center map</div>`;
if (getUnitsManager().getSelectedUnits().length > 0 && !(getUnitsManager().getSelectedUnits().length == 1 && (getUnitsManager().getSelectedUnits().includes(this))))
{
options['Attack'] = `<div id="attack">Attack</div>`;
if (getUnitsManager().getSelectedUnitsType() === "Aircraft")
options['Follow'] = `<div id="follow">Follow</div>`;
}
else if ((getUnitsManager().getSelectedUnits().length > 0 && (getUnitsManager().getSelectedUnits().includes(this))) || getUnitsManager().getSelectedUnits().length == 0)
{
if (this.getBaseData().category == "Aircraft")
{
options["Refuel"] = `<div id="refuel">Refuel</div>`; // TODO Add some way of knowing which aircraft can AAR
}
}
if (Object.keys(options).length > 0)
{
getMap().showUnitContextMenu(e);
getMap().getUnitContextMenu().setOptions(options, (option: string) => {
getMap().hideUnitContextMenu();
this.#executeAction(option);
this.#executeAction(e, option);
});
}
}
#executeAction(action: string) {
#executeAction(e: any, action: string) {
if (action === "Center")
getMap().centerOnUnit(this.ID);
if (action === "Attack")
getUnitsManager().selectedUnitsAttackUnit(this.ID);
else if (action === "Refuel")
getUnitsManager().selectedUnitsRefuel();
else if (action === "Follow")
this.#showFollowOptions(e);
}
#showFollowOptions(e: any) {
var options: {[key: string]: string} = {};
options = {
'Trail': `<div id="trail">Trail</div>`,
'Echelon (LH)': `<div id="echelon-lh">Echelon (left)</div>`,
'Echelon (RH)': `<div id="echelon-rh">Echelon (right)</div>`,
'Line abreast (LH)': `<div id="line-abreast">Line abreast (left)</div>`,
'Line abreast (RH)': `<div id="line-abreast">Line abreast (right)</div>`,
'Front': `<div id="front">In front</div>`,
'Diamond': `<div id="diamond">Diamond</div>`,
'Custom': `<div id="custom">Custom</div>`
}
getMap().getUnitContextMenu().setOptions(options, (option: string) => {
getMap().hideUnitContextMenu();
this.#applyFollowOptions(option);
});
getMap().showUnitContextMenu(e);
}
#applyFollowOptions(action: string)
{
if (action === "Custom")
{
document.getElementById("custom-formation-dialog")?.classList.remove("hide");
getMap().getUnitContextMenu().setCustomFormationCallback((offset: {x: number, y: number, z: number}) => {
getUnitsManager().selectedUnitsFollowUnit(this.ID, offset);
})
}
else {
getUnitsManager().selectedUnitsFollowUnit(this.ID, undefined, action);
}
}
#updateMarker() {
this.updateVisibility();
if (!this.getHidden()) {
/* Draw the minimap marker */
if (this.getBaseData().alive )
{
if (this.#miniMapMarker == null)
{
this.#miniMapMarker = new CircleMarker(new LatLng(this.getFlightData().latitude, this.getFlightData().longitude), {radius: 0.5});
if (this.getMissionData().coalition == "neutral")
this.#miniMapMarker.setStyle({color: "#CFD9E8"});
else if (this.getMissionData().coalition == "red")
this.#miniMapMarker.setStyle({color: "#ff5858"});
else
this.#miniMapMarker.setStyle({color: "#247be2"});
this.#miniMapMarker.addTo(getMap().getMiniMapLayerGroup());
this.#miniMapMarker.bringToBack();
}
else {
this.#miniMapMarker.setLatLng(new LatLng(this.getFlightData().latitude, this.getFlightData().longitude));
this.#miniMapMarker.bringToBack();
}
}
else {
if (this.#miniMapMarker != null && getMap().getMiniMapLayerGroup().hasLayer(this.#miniMapMarker)) {
getMap().getMiniMapLayerGroup().removeLayer(this.#miniMapMarker);
this.#miniMapMarker = null;
}
}
/* Draw the marker */
if (!this.getHidden()) {
this.setLatLng(new LatLng(this.getFlightData().latitude, this.getFlightData().longitude));
var element = this.getElement();
if (element != null) {
/* Draw the velocity vector */
element.querySelector(".unit-vvi")?.setAttribute("style", `height: ${15 + this.getFlightData().speed / 5}px;`);
element.querySelector(".unit")?.setAttribute("data-pilot", this.getMissionData().flags.human? "human": "ai");
/* Set fuel data */
element.querySelector(".unit-fuel-level")?.setAttribute("style", `width: ${this.getMissionData().fuel}%`);
element.querySelector(".unit")?.toggleAttribute("data-has-low-fuel", this.getMissionData().fuel < 20);
/* Set dead/alive flag */
element.querySelector(".unit")?.toggleAttribute("data-is-dead", !this.getBaseData().alive);
var unitHeadingDiv = element.querySelector(".unit-heading");
if (unitHeadingDiv != null)
unitHeadingDiv.innerHTML = String(Math.floor(rad2deg(this.getFlightData().heading)));
/* Set current unit state */
if (this.getMissionData().flags.Human) // Unit is human
element.querySelector(".unit")?.setAttribute("data-state", "human");
else if (!this.getBaseData().AI) // Unit is under DCS control (not Olympus)
element.querySelector(".unit")?.setAttribute("data-state", "dcs");
else // Unit is under Olympus control
element.querySelector(".unit")?.setAttribute("data-state", this.getTaskData().currentState.toLowerCase());
var unitAltitudeDiv = element.querySelector(".unit-altitude");
if (unitAltitudeDiv != null) {
unitAltitudeDiv.innerHTML = String(Math.floor(this.getFlightData().altitude / 0.3048 / 1000));
}
/* Set altitude and speed */
if (element.querySelector(".unit-altitude"))
(<HTMLElement> element.querySelector(".unit-altitude")).innerText = "FL" + String(Math.floor(this.getFlightData().altitude / 0.3048 / 1000));
if (element.querySelector(".unit-speed"))
(<HTMLElement> element.querySelector(".unit-speed")).innerHTML = String(Math.floor(this.getFlightData().speed * 1.94384 ) );
/* Rotate elements according to heading */
element.querySelectorAll( "[data-rotate-to-heading]" ).forEach( el => {
const headingDeg = rad2deg( this.getFlightData().heading );
let currentStyle = el.getAttribute( "style" ) || "";
el.setAttribute( "style", currentStyle + `transform:rotate(${headingDeg}deg);` );
});
var unitSpeedDiv = element.querySelector(".unit-speed");
if (unitSpeedDiv != null)
unitSpeedDiv.innerHTML = String(Math.floor(this.getFlightData().speed * 1.94384 ) );
/* Turn on ordnance indicators */
var hasFox1 = element.querySelector(".unit")?.hasAttribute("data-has-fox-1");
var hasFox2 = element.querySelector(".unit")?.hasAttribute("data-has-fox-2");
var hasFox3 = element.querySelector(".unit")?.hasAttribute("data-has-fox-3");
var hasOtherAmmo = element.querySelector(".unit")?.hasAttribute("data-has-other-ammo");
var newHasFox1 = false;
var newHasFox2 = false;
var newHasFox3 = false;
var newHasOtherAmmo = false;
Object.values(this.getMissionData().ammo).forEach((ammo: any) => {
if (ammo.desc.category == 1 && ammo.desc.missileCategory == 1) {
if (ammo.desc.guidance == 4 || ammo.desc.guidance == 5) {
newHasFox1 = true;
}
else if (ammo.desc.guidance == 2) {
newHasFox2 = true;
}
else if (ammo.desc.guidance == 3) {
newHasFox3 = true;
}
}
else {
newHasOtherAmmo = true;
}
});
if (hasFox1 != newHasFox1) element.querySelector(".unit")?.toggleAttribute("data-has-fox-1", newHasFox1);
if (hasFox2 != newHasFox2) element.querySelector(".unit")?.toggleAttribute("data-has-fox-2", newHasFox2);
if (hasFox3 != newHasFox3) element.querySelector(".unit")?.toggleAttribute("data-has-fox-3", newHasFox3);
if (hasOtherAmmo != newHasOtherAmmo) element.querySelector(".unit")?.toggleAttribute("data-has-other-ammo", newHasOtherAmmo);
}
/* Set vertical offset for altitude stacking */
var pos = getMap().latLngToLayerPoint(this.getLatLng()).round();
this.setZIndexOffset(1000 + Math.floor(this.getFlightData().altitude) - pos.y);
this.setZIndexOffset(1000 + Math.floor(this.getFlightData().altitude) - pos.y + (this.#hovered || this.#selected? 5000: 0));
}
this.#forceUpdate = false;
}
#drawPath() {
@@ -469,6 +619,9 @@ export class Unit extends Marker {
points.push(new LatLng(destination.lat, destination.lng));
this.#pathPolyline.setLatLngs(points);
}
if (points.length == 1)
this.#clearPath();
}
}
@@ -498,7 +651,7 @@ export class Unit extends Marker {
color = "#00FF00";
else
color = "#FFFFFF";
var targetPolyline = new Polyline([startLatLng, endLatLng], { color: color, weight: 3, opacity: 1, smoothFactor: 1 });
var targetPolyline = new Polyline([startLatLng, endLatLng], { color: color, weight: 3, opacity: 0.4, smoothFactor: 1 });
targetPolyline.addTo(getMap());
this.#targetsPolylines.push(targetPolyline)
}
@@ -524,10 +677,10 @@ export class Aircraft extends AirUnit {
getMarkerHTML()
{
return `<div class="unit" data-object="unit-aircraft" data-status="" data-coalition="${this.getMissionData().coalition}">
return `<div class="unit" data-object="unit-aircraft" data-coalition="${this.getMissionData().coalition}">
<div class="unit-selected-spotlight"></div>
<div class="unit-marker-border"></div>
<div class="unit-status"></div>
<div class="unit-state"></div>
<div class="unit-vvi" data-rotate-to-heading></div>
<div class="unit-hotgroup">
<div class="unit-hotgroup-id"></div>

View File

@@ -1,13 +1,15 @@
import { LatLng, LatLngBounds } from "leaflet";
import { getMap, getUnitDataTable } from "..";
import { getInfoPopup, getMap, getUnitDataTable } from "..";
import { Unit } from "./unit";
import { cloneUnit } from "../server/server";
import { IDLE, MOVE_UNIT } from "../map/map";
import { keyEventWasInInput } from "../other/utils";
export class UnitsManager {
#units: { [ID: number]: Unit };
#copiedUnits: Unit[];
#selectionEventDisabled: boolean = false;
#pasteDisabled: boolean = false;
constructor() {
this.#units = {};
@@ -18,7 +20,18 @@ export class UnitsManager {
document.addEventListener('unitSelection', (e: CustomEvent) => this.#onUnitSelection(e.detail));
document.addEventListener('unitDeselection', (e: CustomEvent) => this.#onUnitDeselection(e.detail));
document.addEventListener('keydown', (event) => this.#onKeyDown(event));
document.addEventListener('deleteSelectedUnits', () => this.selectedUnitsDelete() )
document.addEventListener('deleteSelectedUnits', () => this.selectedUnitsDelete())
}
getSelectableAircraft() {
const units = this.getUnits();
return Object.keys(units).reduce((acc: { [key: number]: Unit }, unitId: any) => {
const baseData = units[unitId].getBaseData();
if (baseData.category === "Aircraft" && baseData.alive === true) {
acc[unitId] = units[unitId];
}
return acc;
}, {});
}
getUnits() {
@@ -39,58 +52,57 @@ export class UnitsManager {
this.#units[ID] = new constructor(ID, data);
}
}
removeUnit(ID: number) {
}
update(data: UnitsData) {
Object.keys(data.units)
.filter((ID: string) => !(ID in this.#units))
.reduce((timeout: number, ID: string) => {
setTimeout(() => {
if (!(ID in this.#units))
this.addUnit(parseInt(ID), data.units[ID]);
this.#units[parseInt(ID)]?.setData(data.units[ID]);
}, timeout);
return timeout + 10;
}, 10);
.filter((ID: string) => !(ID in this.#units))
.reduce((timeout: number, ID: string) => {
window.setTimeout(() => {
if (!(ID in this.#units))
this.addUnit(parseInt(ID), data.units[ID]);
this.#units[parseInt(ID)]?.setData(data.units[ID]);
}, timeout);
return timeout + 10;
}, 10);
Object.keys(data.units)
.filter((ID: string) => ID in this.#units)
.forEach((ID: string) => this.#units[parseInt(ID)]?.setData(data.units[ID]));
.filter((ID: string) => ID in this.#units)
.forEach((ID: string) => this.#units[parseInt(ID)]?.setData(data.units[ID]));
}
selectUnit(ID: number, deselectAllUnits: boolean = true)
{
if (deselectAllUnits)
this.getSelectedUnits().filter((unit: Unit) => unit.ID !== ID ).forEach((unit: Unit) => unit.setSelected(false));
selectUnit(ID: number, deselectAllUnits: boolean = true) {
if (deselectAllUnits)
this.getSelectedUnits().filter((unit: Unit) => unit.ID !== ID).forEach((unit: Unit) => unit.setSelected(false));
this.#units[ID]?.setSelected(true);
}
selectFromBounds(bounds: LatLngBounds)
{
selectFromBounds(bounds: LatLngBounds) {
this.deselectAllUnits();
for (let ID in this.#units)
{
if (this.#units[ID].getHidden() == false)
{
for (let ID in this.#units) {
if (this.#units[ID].getHidden() == false) {
var latlng = new LatLng(this.#units[ID].getFlightData().latitude, this.#units[ID].getFlightData().longitude);
if (bounds.contains(latlng))
{
if (bounds.contains(latlng)) {
this.#units[ID].setSelected(true);
}
}
}
}
getSelectedUnits() {
getSelectedUnits(options?: {excludeHumans?: boolean}) {
var selectedUnits = [];
for (let ID in this.#units) {
if (this.#units[ID].getSelected()) {
selectedUnits.push(this.#units[ID]);
}
}
if (options) {
if (options.excludeHumans)
selectedUnits = selectedUnits.filter((unit: Unit) => {return !unit.getMissionData().flags.Human});
}
return selectedUnits;
}
@@ -100,247 +112,225 @@ export class UnitsManager {
}
}
getSelectedLeaders() {
var leaders: Unit[] = [];
for (let idx in this.getSelectedUnits())
{
var unit = this.getSelectedUnits()[idx];
if (unit.getFormationData().isLeader)
leaders.push(unit);
else if (unit.getFormationData().isWingman)
{
var leader = unit.getLeader();
if (leader && !leaders.includes(leader))
leaders.push(leader);
}
}
return leaders;
}
getSelectedSingletons() {
var singletons: Unit[] = [];
for (let idx in this.getSelectedUnits())
{
var unit = this.getSelectedUnits()[idx];
if (!unit.getFormationData().isLeader && !unit.getFormationData().isWingman)
singletons.push(unit);
}
return singletons;
}
getSelectedUnitsType () {
getSelectedUnitsType() {
if (this.getSelectedUnits().length == 0)
return undefined;
return this.getSelectedUnits().map((unit: Unit) => {
return unit.constructor.name
})?.reduce((a: any, b: any) => {
return a == b? a: undefined
return a == b ? a : undefined
});
};
getSelectedUnitsTargetSpeed () {
getSelectedUnitsTargetSpeed() {
if (this.getSelectedUnits().length == 0)
return undefined;
return this.getSelectedUnits().map((unit: Unit) => {
return unit.getTaskData().targetSpeed
})?.reduce((a: any, b: any) => {
return a == b? a: undefined
return a == b ? a : undefined
});
};
getSelectedUnitsTargetAltitude () {
getSelectedUnitsTargetAltitude() {
if (this.getSelectedUnits().length == 0)
return undefined;
return this.getSelectedUnits().map((unit: Unit) => {
return unit.getTaskData().targetAltitude
})?.reduce((a: any, b: any) => {
return a == b? a: undefined
return a == b ? a : undefined
});
};
getSelectedUnitsCoalition () {
getSelectedUnitsCoalition() {
if (this.getSelectedUnits().length == 0)
return undefined;
return this.getSelectedUnits().map((unit: Unit) => {
return unit.getMissionData().coalition
})?.reduce((a: any, b: any) => {
return a == b? a: undefined
return a == b ? a : undefined
});
};
/*********************** Actions on selected units ************************/
selectedUnitsAddDestination(latlng: L.LatLng) {
var selectedUnits = this.getSelectedUnits();
var selectedUnits = this.getSelectedUnits({excludeHumans: true});
for (let idx in selectedUnits) {
var commandedUnit = selectedUnits[idx];
commandedUnit.addDestination(latlng);
const unit = selectedUnits[idx];
/* If a unit is following another unit, and that unit is also selected, send the command to the followed unit */
if (unit.getTaskData().currentState === "Follow") {
const leader = this.getUnitByID(unit.getFormationData().leaderID)
if (leader && leader.getSelected())
leader.addDestination(latlng);
else
unit.addDestination(latlng);
}
else
unit.addDestination(latlng);
}
this.#showActionMessage(selectedUnits, " new destination added");
}
selectedUnitsClearDestinations() {
var selectedUnits = this.getSelectedUnits();
var selectedUnits = this.getSelectedUnits({excludeHumans: true});
for (let idx in selectedUnits) {
var commandedUnit = selectedUnits[idx];
commandedUnit.clearDestinations();
const unit = selectedUnits[idx];
if (unit.getTaskData().currentState === "Follow") {
const leader = this.getUnitByID(unit.getFormationData().leaderID)
if (leader && leader.getSelected())
leader.clearDestinations();
else
unit.clearDestinations();
}
else
unit.clearDestinations();
}
}
selectedUnitsLandAt(latlng: LatLng)
{
var selectedUnits = this.getSelectedUnits();
for (let idx in selectedUnits)
{
selectedUnitsLandAt(latlng: LatLng) {
var selectedUnits = this.getSelectedUnits({excludeHumans: true});
for (let idx in selectedUnits) {
selectedUnits[idx].landAt(latlng);
}
this.#showActionMessage(selectedUnits, " landing");
}
selectedUnitsChangeSpeed(speedChange: string)
{
var selectedUnits = this.getSelectedUnits();
for (let idx in selectedUnits)
{
selectedUnitsChangeSpeed(speedChange: string) {
var selectedUnits = this.getSelectedUnits({excludeHumans: true});
for (let idx in selectedUnits) {
selectedUnits[idx].changeSpeed(speedChange);
}
}
selectedUnitsChangeAltitude(altitudeChange: string)
{
var selectedUnits = this.getSelectedUnits();
for (let idx in selectedUnits)
{
selectedUnitsChangeAltitude(altitudeChange: string) {
var selectedUnits = this.getSelectedUnits({excludeHumans: true});
for (let idx in selectedUnits) {
selectedUnits[idx].changeAltitude(altitudeChange);
}
}
selectedUnitsSetSpeed(speed: number)
{
var selectedUnits = this.getSelectedUnits();
for (let idx in selectedUnits)
{
selectedUnitsSetSpeed(speed: number) {
var selectedUnits = this.getSelectedUnits({excludeHumans: true});
for (let idx in selectedUnits) {
selectedUnits[idx].setSpeed(speed);
}
this.#showActionMessage(selectedUnits, `setting speed to ${speed * 1.94384} kts`);
}
selectedUnitsSetAltitude(altitude: number)
{
var selectedUnits = this.getSelectedUnits();
for (let idx in selectedUnits)
{
selectedUnitsSetAltitude(altitude: number) {
var selectedUnits = this.getSelectedUnits({excludeHumans: true});
for (let idx in selectedUnits) {
selectedUnits[idx].setAltitude(altitude);
}
this.#showActionMessage(selectedUnits, `setting altitude to ${altitude / 0.3048} ft`);
}
selectedUnitsSetROE(ROE: string)
{
var selectedUnits = this.getSelectedUnits();
for (let idx in selectedUnits)
{
selectedUnitsSetROE(ROE: string) {
var selectedUnits = this.getSelectedUnits({excludeHumans: true});
for (let idx in selectedUnits) {
selectedUnits[idx].setROE(ROE);
}
this.#showActionMessage(selectedUnits, `ROE set to ${ROE}`);
}
selectedUnitsSetReactionToThreat(reactionToThreat: string)
{
var selectedUnits = this.getSelectedUnits();
for (let idx in selectedUnits)
{
selectedUnitsSetReactionToThreat(reactionToThreat: string) {
var selectedUnits = this.getSelectedUnits({excludeHumans: true});
for (let idx in selectedUnits) {
selectedUnits[idx].setReactionToThreat(reactionToThreat);
}
this.#showActionMessage(selectedUnits, `reaction to threat set to ${reactionToThreat}`);
}
selectedUnitsAttackUnit(ID: number) {
var selectedUnits = this.getSelectedUnits();
var selectedUnits = this.getSelectedUnits({excludeHumans: true});
for (let idx in selectedUnits) {
/* If a unit is a wingman, send the command to its leader */
var commandedUnit = selectedUnits[idx];
//if (selectedUnits[idx].wingman)
//{
// commandedUnit = this.getLeader(selectedUnits[idx].ID);
//}
commandedUnit.attackUnit(ID);
selectedUnits[idx].attackUnit(ID);
}
this.#showActionMessage(selectedUnits, `attacking unit ${this.getUnitByID(ID)?.getBaseData().unitName}`);
}
selectedUnitsCreateFormation(ID: number | null = null)
{
var selectedUnits = this.getSelectedUnits();
if (selectedUnits.length >= 2)
{
if (ID == null)
ID = selectedUnits[0].ID
var wingmenIDs = [];
for (let idx in selectedUnits)
{
if (selectedUnits[idx].getFormationData().isWingman)
{
//console.log(selectedUnits[idx].unitName + " is already in a formation.");
return;
}
else if (selectedUnits[idx].getFormationData().isLeader)
{
//console.log(selectedUnits[idx].unitName + " is already in a formation.");
return;
}
else
{
/* TODO
if (selectedUnits[idx].category !== this.getUnitByID(ID).category)
{
showMessage("All units must be of the same category to create a formation.");
}
*/
if (selectedUnits[idx].ID != ID)
{
wingmenIDs.push(selectedUnits[idx].ID);
}
}
}
if (wingmenIDs.length > 0)
{
this.getUnitByID(ID)?.setLeader(true, wingmenIDs);
}
else
{
//console.log("At least 2 units must be selected to create a formation.");
}
}
}
selectedUnitsUndoFormation()
{
for (let leader of this.getSelectedLeaders())
{
leader.setLeader(false);
}
}
selectedUnitsDelete()
{
var selectedUnits = this.getSelectedUnits();
for (let idx in selectedUnits)
{
selectedUnitsDelete() {
var selectedUnits = this.getSelectedUnits(); /* Can be applied to humans too */
for (let idx in selectedUnits) {
selectedUnits[idx].delete();
}
this.#showActionMessage(selectedUnits, `deleted`);
}
copyUnits()
{
this.#copiedUnits = this.getSelectedUnits();
selectedUnitsRefuel() {
var selectedUnits = this.getSelectedUnits({excludeHumans: true});
for (let idx in selectedUnits) {
selectedUnits[idx].refuel();
}
this.#showActionMessage(selectedUnits, `sent to nearest tanker`);
}
pasteUnits()
{
for (let idx in this.#copiedUnits)
{
var unit = this.#copiedUnits[idx];
cloneUnit(unit.ID, getMap().getMouseCoordinates());
selectedUnitsFollowUnit(ID: number, offset?: { "x": number, "y": number, "z": number }, formation?: string) {
if (offset == undefined) {
/* Simple formations with fixed offsets */
// X: front-rear, positive front
// Y: top-bottom, positive top
// Z: left-right, positive right
offset = { "x": 0, "y": 0, "z": 0 };
if (formation === "Trail") { offset.x = -50; offset.y = -30; offset.z = 0; }
else if (formation === "Echelon (LH)") { offset.x = -50; offset.y = -10; offset.z = -50; }
else if (formation === "Echelon (RH)") { offset.x = -50; offset.y = -10; offset.z = 50; }
else if (formation === "Line abreast (RH)") { offset.x = 0; offset.y = 0; offset.z = 50; }
else if (formation === "Line abreast (LH)") { offset.x = 0; offset.y = 0; offset.z = -50; }
else if (formation === "Front") { offset.x = 100; offset.y = 0; offset.z = 0; }
else offset = undefined;
}
var selectedUnits = this.getSelectedUnits({excludeHumans: true});
var count = 1;
var xr = 0; var yr = 1; var zr = -1;
var layer = 1;
for (let idx in selectedUnits) {
var unit = selectedUnits[idx];
if (offset != undefined)
/* Offset is set, apply it */
unit.followUnit(ID, { "x": offset.x * count, "y": offset.y * count, "z": offset.z * count });
else {
/* More complex formations with variable offsets */
if (formation === "Diamond") {
var xl = xr * Math.cos(Math.PI / 4) - yr * Math.sin(Math.PI / 4);
var yl = xr * Math.sin(Math.PI / 4) + yr * Math.cos(Math.PI / 4);
unit.followUnit(ID, { "x": -yl * 50, "y": zr * 10, "z": xl * 50 });
if (yr == 0) { layer++; xr = 0; yr = layer; zr = -layer; }
else {
if (xr < layer) { xr++; zr--; }
else { yr--; zr++; }
}
}
}
count++;
}
this.#showActionMessage(selectedUnits, `following unit ${this.getUnitByID(ID)?.getBaseData().unitName}`);
}
/***********************************************/
copyUnits() {
this.#copiedUnits = this.getSelectedUnits(); /* Can be applied to humans too */
this.#showActionMessage(this.#copiedUnits, `copied`);
}
pasteUnits() {
if (!this.#pasteDisabled) {
for (let idx in this.#copiedUnits) {
var unit = this.#copiedUnits[idx];
getMap().addTemporaryMarker(getMap().getMouseCoordinates());
cloneUnit(unit.ID, getMap().getMouseCoordinates());
this.#showActionMessage(this.#copiedUnits, `pasted`);
}
this.#pasteDisabled = true;
window.setTimeout(() => this.#pasteDisabled = false, 250);
}
}
#onKeyDown(event: KeyboardEvent)
{
if (event.key === "Delete")
{
/***********************************************/
#onKeyDown(event: KeyboardEvent) {
if (!keyEventWasInInput(event) && event.key === "Delete") {
this.selectedUnitsDelete();
}
}
@@ -349,12 +339,11 @@ export class UnitsManager {
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 */
if (!this.#selectionEventDisabled)
{
setTimeout(() => {
document.dispatchEvent(new CustomEvent("unitsSelection", {detail: this.getSelectedUnits()}));
if (!this.#selectionEventDisabled) {
window.setTimeout(() => {
document.dispatchEvent(new CustomEvent("unitsSelection", { detail: this.getSelectedUnits() }));
this.#selectionEventDisabled = false;
}, 300);
}, 100);
this.#selectionEventDisabled = true;
}
}
@@ -369,7 +358,14 @@ export class UnitsManager {
getMap().setState(IDLE);
document.dispatchEvent(new CustomEvent("clearSelection"));
}
else
document.dispatchEvent(new CustomEvent("unitsDeselection", {detail: this.getSelectedUnits()}));
else
document.dispatchEvent(new CustomEvent("unitsDeselection", { detail: this.getSelectedUnits() }));
}
#showActionMessage(units: Unit[], message: string) {
if (units.length == 1)
getInfoPopup().setText(`${units[0].getBaseData().unitName} ${message}`);
else if (units.length > 1)
getInfoPopup().setText(`${units[0].getBaseData().unitName} and ${units.length - 1} other units ${message}`);
}
}

View File

@@ -9,7 +9,7 @@
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "es2017", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
"target": "ES2017", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
@@ -33,14 +33,15 @@
], /* Specify multiple folders that act like './node_modules/@types'. */
"types": [
"leaflet",
"geojson"
"geojson",
"node"
], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "resolveJsonModule": true, /* Enable importing .json files. */
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
"allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */

View File

@@ -1,106 +1,11 @@
<div id="atc-control-panel" data-feature-switch="atc">
<div class="ol-button" id="atc-toggle-button"></div>
</div>
<div id="atc-flight-list" class="atc-tool hide" data-feature-switch="atc">
<table>
<thead>
<tr>
<th>Flight</th>
<th>T/O</th>
<th>TTG</th>
<th>Status</th>
<th> </th>
</tr>
</thead>
<tbody id="atc-flight-list-table-body"></tbody>
</table>
</div>
<div class="atc-strip-board" data-feature-switch="atc">
<div class="atc-strip-board-header">
<div class="name">Name</div>
<div class="bearing-range">BR</div>
<div class="target-altitude">t. Alt</div>
<div class="current-altitude">Alt</div>
<div class="target-speed">t. Spd</div>
<div class="current-speed">Speed</div>
<div class="runway">RWY</div>
<div class="line">Line</div>
</div>
<div id="atc-strip-board-arrivals" class="atc-strip-board-strips ol-panel">
<div class="atc-strip-board-strip">
<div class="handle"></div>
<div class="rectangular-container">
<div class="name">Shark 3</div>
<div class="bearing-range">250 / 28</div>
<div class="target-altitude">-</div>
<div class="current-altitude">10000</div>
<div class="target-speed">-</div>
<div class="current-speed">421</div>
<div class="runway">-</div>
<div class="line">-</div>
</div>
</div>
<div class="atc-strip-board-strip">
<div class="handle"></div>
<div class="rectangular-container">
<div class="name">Shark 2</div>
<div class="bearing-range">250 / 24</div>
<div class="target-altitude">6000</div>
<div class="current-altitude">6000</div>
<div class="target-speed">-</div>
<div class="current-speed">400</div>
<div class="runway">-</div>
<div class="line">-</div>
</div>
</div>
<div class="atc-strip-board-strip">
<div class="handle"></div>
<div class="rectangular-container">
<div class="name">Shark 1</div>
<div class="bearing-range link-warning">262 / 12</div>
<div class="target-altitude">5000</div>
<div class="current-altitude">5100</div>
<div class="target-speed">-</div>
<div class="current-speed">367</div>
<div class="runway warning">-</div>
<div class="line">-</div>
</div>
</div>
<div class="atc-strip-board-strip">
<div class="handle"></div>
<div class="rectangular-container">
<div class="name">Dolphin 1</div>
<div class="bearing-range">250 / 4</div>
<div class="target-altitude link-warning">3000</div>
<div class="current-altitude warning">4100</div>
<div class="target-speed">-</div>
<div class="current-speed">511</div>
<div class="runway">25L</div>
<div class="line">2nd</div>
</div>
</div>
<div class="atc-strip-board-strip">
<div class="handle"></div>
<div class="rectangular-container">
<div class="name">Whale 1</div>
<div class="bearing-range">070 / 2</div>
<div class="target-altitude">1500</div>
<div class="current-altitude">1650</div>
<div class="target-speed link-warning">350</div>
<div class="current-speed warning">312</div>
<div class="runway">25L</div>
<div class="line">1st</div>
</div>
</div>
</div>
</div>
<%- include('atc/board.ejs', {
"boardId": "strip-board-tower",
"boardType": "tower",
"headers": [ "Flight", "a. Alt", "alt", "a. Speed", "Speed" ]
}) %>
<%- include('atc/board.ejs', {
"boardId": "strip-board-ground",
"boardType": "ground",
"headers": [ "Flight", "Status", "T/O Time", "TTG" ]
}) %>

View File

@@ -0,0 +1,5 @@
<form class="ol-strip-board-add-flight">
<div class="ol-auto-suggest"></div>
<input type="text" name="unitName" placeholder="Flight search" />
<button class="add-flight-by-click" title="Add unit via click"><img src="/images/icons/bullseye-solid.svg" /></button>
</form>

View File

@@ -0,0 +1,25 @@
<div id="<%= boardId %>" class="ol-panel ol-dialog ol-strip-board ol-draggable" data-board-type="<%= boardType %>" data-feature-switch="atc">
<div class="ol-dialog-close" data-on-click="closeDialog"></div>
<div class="ol-dialog-header">
<h3><%= boardType %></h3>
<div class="ol-strip-board-clock"></div>
</div>
<div class="ol-dialog-content">
<div class="ol-strip-board-headers">
<div><!-- handles --></div>
<% headers.forEach( header => { %>
<div><%= header %></div>
<% }); %>
<div><!-- delete --></div>
</div>
<div class="ol-strip-board-strips ol-sortable"></div>
</div>
<div class="ol-dialog-footer">
<%- include('addflight.ejs') %>
</div>
</div>

View File

@@ -1,4 +1,4 @@
<div id="connection-status-panel" class="ol-panel">
<div id="connection-status-panel" class="ol-panel" oncontextmenu="return false;">
<dl class="ol-data-grid">
<dt></dt>
<dd></dd>

View File

@@ -1,8 +1,7 @@
<div id="map-contextmenu">
<div id="map-contextmenu" oncontextmenu="return false;">
<div id="active-coalition-label" data-active-coalition="blue"></div>
<div id="upper-bar" class="ol-panel">
<label id="context-menu-switch" class="toggle" for="context-menu-toggle">
<input class="toggle-input" name="" type="checkbox" id="context-menu-toggle">
<div data-active-coalition="blue" class="toggle-fill"></div>
</label>
<button data-active-coalition="blue" id="aircraft-spawn-button" title="Spawn aircraft" data-on-click="contextMenuShow"
@@ -75,11 +74,11 @@
</div>
</div>
<div id="unit-contextmenu" class="ol-panel">
<div id="unit-contextmenu" class="ol-panel" oncontextmenu="return false;">
<!-- Here the available unit options will be shown -->
</div>
<div id="airbase-contextmenu" class="ol-panel">
<div id="airbase-contextmenu" class="ol-panel" oncontextmenu="return false;">
<h3 id="airbase-name"></h3>

View File

@@ -1,181 +1,196 @@
<div id="splash-screen" class="ol-dialog" data-on-click="closeDialog">
<div id="splash-screen" class="ol-dialog" oncontextmenu="return false;">
<div id="splash-content" class="ol-dialog-content">
<div id="app-summary">
<h2>DCS Olympus</h2>
<h4>Dynamic Unit Command</h4>
<div class="app-version">Version <span class="app-version-number">v0.1.0</span></div>
<div class="app-version">Version <span class="app-version-number">v0.2.1</span></div>
</div>
<div id="authentication-form">
<div><h5>Username</h5> <input type="text" id="username" name="username" required autocomplete="username" placeholder="Enter username..."></div>
<div><h5>Password</h5> <input type="password" id="password" name="password" minlength="8" required autocomplete="current-password" placeholder="Enter password..."></div>
<button id="connection-button" class="ol-button-apply" data-on-click="tryConnection">Connect</button>
</div>
<h5 id="connection-status"><br></h5>
<div id="legal-stuff">
<h4>Disclaimer</h4>
<p>We ain't no friends with no Eagle Dynamics.</p>
<h5>DISCLAIMER</h5>
<p> DCS Olympus (the "MATERIAL" or "Software") is provided completely free to users subject to the terms of the <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0 Licence</a> except where such terms conflict with this disclaimer, in which case, the terms of this disclaimer shall prevail.
The authors and/or copyright holders of the Software have not received any financial benefit in connection with the Software. In any event, the Software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and non-infringement. In no event shall the authors and/or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the Software or the use or other dealings in the Software. Any party making use of the Software in any manner agrees to be bound by the terms set out in this disclaimer. THIS MATERIAL IS NOT MADE OR SUPPORTED BY EAGLE DYNAMICS SA.
</div>
</div>
</div>
<div id="advanced-settings-dialog" class="ol-panel ol-dialog olympus-dialog-close hide" oncontextmenu="return false;">
<div class="ol-dialog-close" data-on-click="closeDialog"></div>
<div class="ol-dialog-header">
<h3 id="unit-name">Olympus 1-1</h3>
</div>
<div class="ol-dialog-content">
<!--
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Use ECM when available
</label>
</div>
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Prohibit jettison
</label>
</div>
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Prohibit afterburner
</label>
</div>
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Prohibit A/A
</label>
</div>
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Prohibit A/G
</label>
</div>
-->
<div id="tanker-checkbox" class="ol-checkbox">
<label>
<input type="checkbox" />
Operate as AAR tanker
</label>
</div>
<div id="AWACS-checkbox" class="ol-checkbox">
<label>
<input type="checkbox" />
Operate as AWACS
</label>
</div>
<div class="ol-group">
<label>A/A TACAN: </label>
<div class="ol-group">
<div id="TACAN-channel" class="ol-text-input">
<input type="number" min="1" max="126" step="1" value="40">
</div>
<div id="TACAN-XY" class="ol-select">
<div class="ol-select-value">X</div>
<div class="ol-select-options">
</div>
</div>
<div id="TACAN-callsign" class="ol-text-input">
<input type="text" maxlength="3" value="TKR" style="width: 50px">
</div>
</div>
</div>
<div class="ol-group">
<label> Radio frequency: </label>
<div class="ol-group">
<div id="radio-mhz" class="ol-text-input">
<input type="number" min="1" max="999" step="1" value="260">
</div>
<div id="radio-decimals" class="ol-select">
<div class="ol-select-value">.000</div>
<div class="ol-select-options">
</div>
</div>
</div>
</div>
<div class="ol-group">
<label> Radio callsign: </label>
<div class="ol-group">
<div id="radio-callsign" class="ol-select">
<div class="ol-select-value"></div>
<div class="ol-select-options">
</div>
</div>
<label>
-
</label>
<div id="radio-callsign-number" class="ol-text-input">
<input type="number" min="1" max="999" step="1" value="1">
</div>
</div>
</div>
</div>
<div class="ol-dialog-footer ol-group">
<button class="ol-button-apply" data-on-click="applyAdvancedSettings">Apply</button>
<button class="ol-button-close" data-on-click="closeDialog">Close</button>
</div>
</div>
<div id="aircraft-settings-dialog" class="ol-panel ol-dialog hide" >
<div id="custom-formation-dialog" class="ol-panel ol-dialog olympus-dialog-close hide" oncontextmenu="return false;">
<div class="ol-dialog-close" data-on-click="closeDialog"></div>
<div class="ol-dialog-header">
<h3>Olympus 1-1</h3>
<h3 id="unit-name">Custom formation</h3>
</div>
<div class="ol-dialog-content">
<div class="formation-position-clock">
<div class="clock-hand" style="top: 0px; left: 50px;"><input type="radio" id="formation-1" name="formation-position" value="1"></div>
<div class="clock-hand" style="top: 14px; left: 14px;"><input type="radio" id="formation-2" name="formation-position" value="2"></div>
<div class="clock-hand" style="top: 50px; left: 0px; "><input type="radio" id="formation-3" name="formation-position" value="3"></div>
<div class="clock-hand" style="top: 86px; left: 14px;"><input type="radio" id="formation-4" name="formation-position" value="4"></div>
<div class="clock-hand" style="top: 100px; left: 50px;"><input type="radio" id="formation-5" name="formation-position" value="5"></div>
<div class="clock-hand" style="top: 86px; left: 86px;"><input type="radio" id="formation-6" name="formation-position" value="6" checked></div>
<div class="clock-hand" style="top: 50px; left: 100px"><input type="radio" id="formation-7" name="formation-position" value="7"></div>
<div class="clock-hand" style="top: 14px; left: 86px;"><input type="radio" id="formation-8" name="formation-position" value="8"></div>
<div style="top: 50px; left: 50px;" id="reference-system"></div>
</div>
<form>
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Use ECM when available
</label>
</div>
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Prohibit jettison
</label>
</div>
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Prohibit afterburner
</label>
</div>
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Prohibit A/A
</label>
</div>
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Prohibit A/G
</label>
</div>
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Enable TACAN:
</label>
</div>
<div class="ol-group">
<label>Distance: </label>
<div class="ol-group">
<div class="ol-select">
<div class="ol-select-value">40</div>
<div class="ol-select-options">
<div>
<button>40</button>
</div>
<div>
<button>41</button>
</div>
<div>
<button>42</button>
</div>
<div>
<button>43</button>
</div>
<div>
<button>44</button>
</div>
<div>
<button>45</button>
</div>
</div>
<div id="distance" class="ol-text-input">
<input type="number" min="0" max="999999" step="1" value="150">
</div>
<div class="ol-select">
<div class="ol-select-value">X</div>
<div class="ol-select-options">
<div>
<button>X</button>
</div>
<div>
<button>Y</button>
</div>
</div>
</div>
<label>ft</label>
</div>
<div class="ol-checkbox">
<label>
<input type="checkbox" />
Use radio frequency:
</label>
</div>
</div>
<div class="ol-group">
<label>Up-down: </label>
<div class="ol-group">
<div class="ol-select">
<div class="ol-select-value">120</div>
<div class="ol-select-options">
<div>
<button>120</button>
</div>
<div>
<button>121</button>
</div>
<div>
<button>122</button>
</div>
<div>
<button>123</button>
</div>
<div>
<button>124</button>
</div>
<div>
<button>125</button>
</div>
</div>
<div id="up-down" class="ol-text-input">
<input type="number" min="-99999" max="99999" step="1" value="30">
</div>
<div class="ol-select">
<div class="ol-select-value">.750</div>
<div class="ol-select-options">
<div>
<button>.000</button>
</div>
<div>
<button>.250</button>
</div>
<div>
<button>.500</button>
</div>
<div>
<button>.750</button>
</div>
</div>
</div>
<label>ft</label>
</div>
</form>
</div>
</div>
<div class="ol-dialog-footer">
<div class="ol-dialog-footer ol-group">
<button class="ol-button-apply" data-on-click="applyCustomFormation">Apply</button>
<button class="ol-button-close" data-on-click="closeDialog">Close</button>
</div>
</div>

View File

@@ -33,10 +33,14 @@
<%- include('connectionstatuspanel.ejs') %>
<%- include('dialogs.ejs') %>
<%- include('unitdatatable.ejs') %>
<%- include('popups.ejs') %>
<div id="gray-out"></div>
<% /* %>
<%- include('log.ejs') %>
<% */ %>
<script src="javascripts/bundle.js"></script>
</body>

View File

@@ -1,20 +1,20 @@
<div id="mouse-info-panel" class="ol-panel">
<div id="mouse-info-panel" class="ol-panel" oncontextmenu="return false;">
<div>
<dl class="ol-data-grid">
<dt id="ref-measure-position" data-tooltip="CTRL-click on the map to activate the measuring tool."></dt>
<dd id="measure-position" class="br-info" data-bearing="---" data-distance="---" data-distance-units="nm"></dd>
<dd id="measure-position" class="br-info" data-bearing="---" data-distance="---" data-distance-units="NM"></dd>
<dt id="ref-unit-position" data-tooltip="Bearing/range from selected unit."></dt>
<dd id="unit-position" class="br-info" data-bearing="---" data-distance="---" data-distance-units="nm"></dd>
<dd id="unit-position" class="br-info" data-bearing="---" data-distance="---" data-distance-units="NM"></dd>
</dl>
</div>
<div>
<dl class="ol-data-grid">
<dt id="ref-bullseye-2" data-tooltip="Bearing/range from this bullseye." data-label="BE" data-coalition="blue"></dt>
<dd id="bullseye-2" class="br-info" data-bearing="---" data-distance="---" data-distance-units="nm"></dd>
<dd id="bullseye-2" class="br-info" data-bearing="---" data-distance="---" data-distance-units="NM"></dd>
<dt id="ref-bullseye-1" data-tooltip="Bearing/range from this bullseye." data-label="BE" data-coalition="red"></dt>
<dd id="bullseye-1" class="br-info" data-bearing="---" data-distance="---" data-distance-units="nm"></dd>
<dd id="bullseye-1" class="br-info" data-bearing="---" data-distance="---" data-distance-units="NM"></dd>
</dl>
</div>

View File

@@ -1,4 +1,4 @@
<nav id="primary-toolbar" class="ol-panel">
<nav id="primary-toolbar" class="ol-panel" oncontextmenu="return false;">
<div id="app-icon" class="ol-select ol-select-image">
<div class="ol-select-value icon">
@@ -6,8 +6,8 @@
</div>
<div class="ol-select-options">
<div id="olympus-toolbar-summary">
<h3>Olympus</h3>
<div class="accent-green app-version-number">v0.1.1</div>
<h3>DCS Olympus</h3>
<div class="accent-green app-version-number">version v0.2.1</div>
</div>
<div>
<a href="https://www.discord.com" target="_blank">Discord</a>
@@ -15,6 +15,9 @@
<div>
<a href="https://github.com/Pax1601/DCSOlympus" target="_blank">Github</a>
</div>
<div data-on-click="reloadPage">
<a href="" target="_blank" data-on-click="reloadPage">Restart Olyumpus</a>
</div>
</div>
</div>
@@ -50,4 +53,13 @@
</div>
</div>
<div id="atc-navbar-control" class="ol-group-container" data-feature-switch="atc">
<div class="ol-group-header">ATC</div>
<div class="ol-group">
<button data-on-click="toggleElements" data-on-click-params='{"selector": "#strip-board-ground"}'>GND</button>
<button data-on-click="toggleElements" data-on-click-params='{"selector": "#strip-board-tower"}'>TWR</button>
</div>
</div>
</nav>

5
client/views/popups.ejs Normal file
View File

@@ -0,0 +1,5 @@
<div id="info-popup" class="ol-panel ol-popup hide" oncontextmenu="return false;">
<div>
<!-- Here the content of the popup will be shown -->
</div>
</div>

View File

@@ -502,9 +502,9 @@
<div class="example">
<div data-object="unit-aircraft" data-status="rtb" data-pilot="ai">
<div data-object="unit-aircraft" data-state="rtb" data-pilot="ai">
<div class="unit-selected-spotlight"></div>
<div class="unit-status"></div>
<div class="unit-state"></div>
<div class="unit-vvi" style="height: 50px; transform:rotate(135deg);"></div>
<div class="unit-hotgroup">
<div class="unit-hotgroup-id">4</div>
@@ -532,9 +532,9 @@
<div class="example">
<div data-object="unit-aircraft" data-status="rtb" data-coalition="blue" data-is-in-hotgroup data-is-selected>
<div data-object="unit-aircraft" data-state="rtb" data-coalition="blue" data-is-in-hotgroup data-is-selected>
<div class="unit-selected-spotlight"></div>
<div class="unit-status"></div>
<div class="unit-state"></div>
<div class="unit-vvi" style="height: 50px; transform:rotate(315deg);"></div>
<div class="unit-hotgroup">
<div class="unit-hotgroup-id">4</div>
@@ -561,9 +561,9 @@
<div class="example">
<div data-object="unit-aircraft" data-status="rtb" data-pilot="ai" data-coalition="red" data-is-in-hotgroup>
<div data-object="unit-aircraft" data-state="rtb" data-pilot="ai" data-coalition="red" data-is-in-hotgroup>
<div class="unit-selected-spotlight"></div>
<div class="unit-status"></div>
<div class="unit-state"></div>
<div class="unit-vvi" style="height: 50px; transform:rotate(270deg);"></div>
<div class="unit-hotgroup">
<div class="unit-hotgroup-id">4</div>
@@ -591,9 +591,9 @@
<div class="example">
<div data-object="unit-aircraft" data-status="hold" data-pilot="ai">
<div data-object="unit-aircraft" data-state="hold" data-pilot="ai">
<div class="unit-selected-spotlight"></div>
<div class="unit-status"></div>
<div class="unit-state"></div>
<div class="unit-vvi" style="height: 50px; transform:rotate(135deg);"></div>
<div class="unit-hotgroup">
<div class="unit-hotgroup-id">4</div>
@@ -621,9 +621,9 @@
<div class="example">
<div data-object="unit-aircraft" data-status="hold" data-coalition="blue" data-is-in-hotgroup data-is-selected>
<div data-object="unit-aircraft" data-state="hold" data-coalition="blue" data-is-in-hotgroup data-is-selected>
<div class="unit-selected-spotlight"></div>
<div class="unit-status"></div>
<div class="unit-state"></div>
<div class="unit-vvi" style="height: 50px; transform:rotate(315deg);"></div>
<div class="unit-hotgroup">
<div class="unit-hotgroup-id">4</div>
@@ -650,9 +650,9 @@
<div class="example">
<div data-object="unit-aircraft" data-status="hold" data-pilot="ai" data-coalition="red" data-is-in-hotgroup>
<div data-object="unit-aircraft" data-state="hold" data-pilot="ai" data-coalition="red" data-is-in-hotgroup>
<div class="unit-selected-spotlight"></div>
<div class="unit-status"></div>
<div class="unit-state"></div>
<div class="unit-vvi" style="height: 50px; transform:rotate(280deg);"></div>
<div class="unit-hotgroup">
<div class="unit-hotgroup-id">4</div>
@@ -688,9 +688,9 @@
<div class="example">
<div data-object="unit-aircraft" data-status="hold" data-pilot="ai" data-is-dead>
<div data-object="unit-aircraft" data-state="hold" data-pilot="ai" data-is-dead>
<div class="unit-selected-spotlight"></div>
<div class="unit-status"></div>
<div class="unit-state"></div>
<div class="unit-vvi" style="height: 50px; transform:rotate(135deg);"></div>
<div class="unit-hotgroup">
<div class="unit-hotgroup-id">4</div>
@@ -718,9 +718,9 @@
<div class="example">
<div data-object="unit-aircraft" data-status="hold" data-coalition="blue" data-is-in-hotgroup data-is-selected data-is-dead>
<div data-object="unit-aircraft" data-state="hold" data-coalition="blue" data-is-in-hotgroup data-is-selected data-is-dead>
<div class="unit-selected-spotlight"></div>
<div class="unit-status"></div>
<div class="unit-state"></div>
<div class="unit-vvi" style="height: 50px; transform:rotate(315deg);"></div>
<div class="unit-hotgroup">
<div class="unit-hotgroup-id">4</div>
@@ -747,9 +747,9 @@
<div class="example">
<div data-object="unit-aircraft" data-status="hold" data-pilot="ai" data-coalition="red" data-is-dead>
<div data-object="unit-aircraft" data-state="hold" data-pilot="ai" data-coalition="red" data-is-dead>
<div class="unit-selected-spotlight"></div>
<div class="unit-status"></div>
<div class="unit-state"></div>
<div class="unit-vvi" style="height: 50px; transform:rotate(280deg);"></div>
<div class="unit-hotgroup">
<div class="unit-hotgroup-id">4</div>
@@ -982,6 +982,42 @@
</div>
</div>
<div class="example">
<div class="ol-select">
<div class="ol-select-value">
The selected value goes here
</div>
<div class="ol-select-options">
<div>
<button>Option 1</button>
</div>
<div>
<button>Option 2</button>
</div>
</div>
</div>
</div>
<div class="example">
<div class="ol-select" data-position="top">
<div class="ol-select-value">
Options go up
</div>
<div class="ol-select-options">
<div>
<button>Option 1</button>
</div>
<div>
<button>Option 2</button>
</div>
</div>
</div>
</div>
</div>
</div>
@@ -991,7 +1027,7 @@
<div class="content-body">
<div class="example">
<div id="airbase-contextmenu" class="ol-panel">
<div id="airbase-contextmenu" class="ol-panel" style="position:relative;">
<h3 id="airbase-name">Al Alhambra</h3>
<dl id="airbase-properties" class="ol-data-grid">
<dt>Runway 1</dt>
@@ -1048,6 +1084,77 @@
</div>
<div id="fuel-percentage" data-percentage="45"></div>
<div id="fuel-display">
<div id="fuel-bar" class="highlight-coalition" data-coalition="blue" style="width:0%;"></div>
</div>
</div>
</div>
</div>
</div>
<div class="example">
<div id="unit-info-panel" class="ol-panel" style="position:relative;">
<div class="ol-panel-board">
<div id="general" class="panel-section">
<h3 class="unit-name">Olympus 1-1</h3>
<div class="ol-group">
<div class="unit-label">Name</div>
<div class="unit-control">AI Controlled</div>
</div>
<div id="current-task" class="pill highlight-coalition" data-coalition="blue" data-current-task="Awaiting tasking"></div>
</div>
<div id="loadout-container" class="panel-section">
<div id="loadout">
<div id="loadout-silhouette" style="--loadout-background-image:url('/images/units/f-15.png');"></div>
<div id="loadout-items">
<div data-qty="1150" data-item="30mm AP"></div>
<div data-qty="2" data-item="AIM-9M"></div>
<div data-qty="6" data-item="Mk-82"></div>
</div>
</div>
<div id="fuel-percentage" data-percentage="45"></div>
<div id="fuel-display">
<div id="fuel-bar" class="highlight-coalition" data-coalition="blue" style="width:0%;"></div>
</div>
</div>
</div>
</div>
</div>
<div class="example">
<div id="unit-info-panel" class="ol-panel" style="position:relative;">
<div class="ol-panel-board">
<div id="loadout-container" class="panel-section">
<div id="loadout">
<div id="loadout-silhouette" style="--loadout-background-image:url('/images/units/f-15.png');"></div>
<div id="loadout-items">
<div data-qty="1150" data-item="30mm AP"></div>
<div data-qty="2" data-item="AIM-9M with a really long name for no reason"></div>
<div data-qty="6" data-item="Mk-82"></div>
</div>
</div>
<div id="fuel-percentage" data-percentage="45"></div>
<div id="fuel-display">
<div id="fuel-bar" class="highlight-coalition" data-coalition="blue" style="width:0%;"></div>

View File

@@ -1,29 +1,22 @@
<div id="unit-control-panel" class="ol-panel ol-panel-padding-lg">
<div id="unit-control-panel" class="ol-panel ol-panel-padding-lg" oncontextmenu="return false;">
<h3>Selected Units</h3>
<div id="unit-selection">
<div id="unit-identification">
<div data-object="unit-aircraft">
<div class="unit-marker"></div>
<div class="unit-short-label" data-point="shortLabel"></div>
</div>
<input id="unit-name" value="" data-point="unitName" readonly disabled />
<!-- <button id="edit-unit-name" data-on-click="editUnitName"></button> -->
</div>
<div id="selected-units-container" class="ol-scroll">
<div id="selected-units-container" class="ol-scrollable">
<!-- This is where all the unit selection buttons will be shown-->
<!-- <button class="pill highlight-coalition" data-coalition="blue" data-short-label="18">Olympus 1-1</button> -->
</div>
<hr />
<div id="flight-data">
<h4>Flight controls</h4>
<div class="slider-container flight-control-slider" id="airspeed-slider">
<dl class="ol-data-grid">
<dt>Speed</dt>
<dd class="flight-control-value" id="value">451kts</dd>
<dd class="flight-control-value" id="value"></dd>
</dl>
<input type="range" min="0" max="100" value="0" class="slider">
</div>
@@ -31,7 +24,7 @@
<div class="slider-container flight-control-slider" id="altitude-slider">
<dl class="ol-data-grid">
<dt>Altitude</dt>
<dd class="flight-control-value" id="value">21,594ft</dd>
<dd class="flight-control-value" id="value"></dd>
</dl>
<input type="range" min="0" max="100" value="0" class="slider">
</div>
@@ -52,16 +45,19 @@
</div>
</div>
<h4>Reaction to threat</h4>
<div id="reaction-to-threat-buttons-container" class="ol-group ol-button-box">
<!-- This is where the reaction to threat buttons will be shown -->
<div id="threat">
<h4>Reaction to threat</h4>
<div id="reaction-to-threat-buttons-container" class="ol-group ol-button-box">
<!-- This is where the reaction to threat buttons will be shown -->
</div>
</div>
<hr />
<!--<button class="ol-button-settings" data-on-click="toggleElements" data-on-click-params='{"selector": "#aircraft-settings-dialog"}'>Adjust settings</button>
Hidden unit implemented
<hr />-->
<div id="advanced-settings-div">
<button id="advanced-settings-button" class="ol-button-settings" data-on-click="showAdvancedSettings">Adjust settings</button>
<hr />
</div>
<button class="ol-button-warning" data-on-click="deleteSelectedUnits">Delete unit</button>

View File

@@ -1,4 +1,4 @@
<div id="unit-data-table" class="ol-panel ol-dialog scrollable">
<div id="unit-data-table" class="ol-panel ol-dialog scrollable" oncontextmenu="return false;">
<div class="ol-dialog-close" data-on-click="closeDialog"></div>

View File

@@ -1,4 +1,4 @@
<div id="unit-info-panel" class="ol-panel" >
<div id="unit-info-panel" class="ol-panel" oncontextmenu="return false;">
<div class="ol-panel-board">

View File

@@ -1,9 +1,9 @@
#define nwjsFolder "C:\Users\dpass\Documents\nwjs\"
#define version "v0.1.1-alpha"
#define version "v0.2.1-alpha"
[Setup]
AppName=DCS Olympus
AppVerName={#version}
AppVerName=DCS Olympus {#version}
DefaultDirName={usersavedgames}\DCS.openbeta
DefaultGroupName=DCSOlympus
OutputBaseFilename=DCSOlympus_{#version}
@@ -23,7 +23,7 @@ Source: "..\olympus.json"; DestDir: "{app}\Mods\Services\Olympus"; Flags: onlyif
Source: "..\scripts\OlympusCommand.lua"; DestDir: "{app}\Mods\Services\Olympus\Scripts"; Flags: ignoreversion
Source: "..\scripts\unitPayloads.lua"; DestDir: "{app}\Mods\Services\Olympus\Scripts"; Flags: ignoreversion
;Source: "..\scripts\OlympusMission.lua"; DestDir: "{app}\Mods\Services\Olympus\Scripts"; Flags: ignoreversion
Source: "..\scripts\mist_4_4_90.lua"; DestDir: "{app}\Mods\Services\Olympus\Scripts"; Flags: ignoreversion
Source: "..\scripts\mist.lua"; DestDir: "{app}\Mods\Services\Olympus\Scripts"; Flags: ignoreversion
Source: "..\mod\*"; DestDir: "{app}\Mods\Services\Olympus"; Flags: ignoreversion recursesubdirs;
Source: "..\bin\*.dll"; DestDir: "{app}\Mods\Services\Olympus\bin"; Flags: ignoreversion;
Source: "..\client\bin\*"; DestDir: "{app}\Mods\Services\Olympus\client\bin"; Flags: ignoreversion;

View File

@@ -2,5 +2,8 @@
"server": {
"address": "localhost",
"port": 30000
},
"authentication": {
"password": "password"
}
}

View File

@@ -1,4 +1,4 @@
local version = "v0.1.1-alpha"
local version = "v0.2.1-alpha"
local debug = false
@@ -38,7 +38,7 @@ end
function Olympus.getUnitByID(ID)
for name, table in pairs(mist.DBs.unitsByName) do
local unit = Unit.getByName(name)
if unit and unit:getObjectID() == ID then
if unit and unit["getObjectID"] and unit:getObjectID() == ID then
return unit
end
end
@@ -48,9 +48,11 @@ end
function Olympus.getCountryIDByCoalition(coalition)
local countryID = 0
if coalition == 'red' then
countryID = country.id.RUSSIA
countryID = country.id.CJTF_RED
elseif coalition == 'blue' then
countryID = country.id.CJTF_BLUE
else
countryID = country.id.USA
countryID = country.id.UN_PEACEKEEPERS
end
return countryID
end
@@ -79,6 +81,18 @@ function Olympus.buildEnrouteTask(options)
}
}
end
-- Start being an active tanker
elseif options['id'] == 'Tanker' then
task = {
id = 'Tanker',
params = {},
}
-- Start being an active AWACS
elseif options['id'] == 'AWACS' then
task = {
id = 'AWACS',
params = {},
}
end
return task
end
@@ -86,18 +100,44 @@ end
-- Builds a valid task depending on the provided options
function Olympus.buildTask(options)
local task = nil
-- Engage specific target by ID. Checks if target exists.
if options['id'] == 'FollowUnit' and options['leaderID'] and options['offset'] then
local leader = Olympus.getUnitByID(options['leaderID'])
if leader and leader:isExist() then
if (Olympus.isArray(options)) then
local tasks = {}
for idx, subOptions in pairs(options) do
tasks[idx] = Olympus.buildTask(subOptions) or Olympus.buildEnrouteTask(subOptions)
end
task = {
id = 'ComboTask',
params = {
tasks = tasks
}
}
Olympus.debug(Olympus.serializeTable(task), 30)
else
if options['id'] == 'FollowUnit' and options['leaderID'] and options['offset'] then
local leader = Olympus.getUnitByID(options['leaderID'])
if leader and leader:isExist() then
task = {
id = 'Follow',
params = {
groupId = leader:getGroup():getID(),
pos = options['offset'],
lastWptIndexFlag = false,
lastWptIndex = 1
}
}
end
elseif options['id'] == 'Refuel' then
task = {
id = 'Follow',
params = {
groupId = leader:getGroup():getID(),
pos = options['offset'],
lastWptIndexFlag = false,
lastWptIndex = 1
}
id = 'Refueling',
params = {}
}
elseif options['id'] == 'Orbit' then
task = {
id = 'Orbit',
params = {
pattern = options['pattern'] or "Circle"
}
}
end
end
@@ -253,6 +293,7 @@ function Olympus.spawnAircraft(coalition, unitType, lat, lng, spawnOptions)
["payload"] =
{
["pylons"] = payload,
["fuel"] = 999999,
["flare"] = 60,
["ammo_type"] = 1,
["chaff"] = 60,
@@ -282,13 +323,13 @@ function Olympus.spawnAircraft(coalition, unitType, lat, lng, spawnOptions)
{
[1] =
{
["action"] = "From Runway",
["action"] = "From Parking Area Hot",
["task"] =
{
["id"] = "ComboTask",
["params"] = {["tasks"] = {},},
},
["type"] = "TakeOff",
["type"] = "TakeOffParkingHot",
["ETA"] = 0,
["ETA_locked"] = true,
["x"] = spawnLocation.x,
@@ -322,17 +363,20 @@ function Olympus.spawnAircraft(coalition, unitType, lat, lng, spawnOptions)
end
-- Clones a unit by ID. Will clone the unit with the same original payload as the source unit. TODO: only works on Olympus unit not ME units.
function Olympus.clone(ID, lat, lng)
Olympus.debug("Olympus.clone " .. ID, 2)
function Olympus.clone(ID, lat, lng, category)
Olympus.debug("Olympus.clone " .. ID .. ", " .. category, 2)
local unit = Olympus.getUnitByID(ID)
if unit then
local coalition = Olympus.getCoalitionByCoalitionID(unit:getCoalition())
-- TODO: only works on Aircraft
local spawnOptions = {
payload = Olympus.payloadRegistry[unit:getName()]
}
Olympus.spawnAircraft(coalition, unit:getTypeName(), lat, lng, spawnOptions)
if category == "Aircraft" then
local spawnOptions = {
payload = Olympus.payloadRegistry[unit:getName()]
}
Olympus.spawnAircraft(coalition, unit:getTypeName(), lat, lng, spawnOptions)
elseif category == "GroundUnit" then
Olympus.spawnGroundUnit(coalition, unit:getTypeName(), lat, lng)
end
end
Olympus.debug("Olympus.clone completed successfully", 2)
end
@@ -341,8 +385,13 @@ function Olympus.delete(ID, lat, lng)
Olympus.debug("Olympus.delete " .. ID, 2)
local unit = Olympus.getUnitByID(ID)
if unit then
unit:destroy();
Olympus.debug("Olympus.delete completed successfully", 2)
if unit:getPlayerName() then
trigger.action.explosion(unit:getPoint() , 250 ) --consider replacing with forcibly deslotting the player, however this will work for now
Olympus.debug("Olympus.delete completed successfully", 2)
else
unit:destroy(); --works for AI units not players
Olympus.debug("Olympus.delete completed successfully", 2)
end
end
end
@@ -351,6 +400,7 @@ function Olympus.setTask(ID, taskOptions)
local unit = Olympus.getUnitByID(ID)
if unit then
local task = Olympus.buildTask(taskOptions);
Olympus.debug("Olympus.setTask " .. Olympus.serializeTable(task), 20)
if task then
unit:getGroup():getController():setTask(task)
Olympus.debug("Olympus.setTask completed successfully", 2)
@@ -377,7 +427,7 @@ function Olympus.setCommand(ID, command)
end
function Olympus.setOption(ID, optionID, optionValue)
Olympus.debug("Olympus.setCommand " .. ID .. " " .. optionID .. " " .. optionValue, 2)
Olympus.debug("Olympus.setOption " .. ID .. " " .. optionID .. " " .. optionValue, 2)
local unit = Olympus.getUnitByID(ID)
if unit then
unit:getGroup():getController():setOption(optionID, optionValue)
@@ -417,6 +467,16 @@ function Olympus.serializeTable(val, name, skipnewlines, depth)
return tmp
end
function Olympus.isArray(t)
local i = 0
for _ in pairs(t) do
i = i + 1
if t[i] == nil then return false end
end
return true
end
function Olympus.setMissionData(arg, time)
local missionData = {}
@@ -436,40 +496,42 @@ function Olympus.setMissionData(arg, time)
local startIndex = Olympus.groupIndex
local endIndex = startIndex + Olympus.groupStep
local index = 0
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
local controller = group:getController()
for index, unit in pairs(group:getUnits()) do
local table = {}
table["targets"] = {}
table["targets"]["visual"] = controller:getDetectedTargets(1)
table["targets"]["radar"] = controller:getDetectedTargets(4)
table["targets"]["rwr"] = controller:getDetectedTargets(16)
table["targets"]["other"] = controller:getDetectedTargets(2, 8, 32)
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
local controller = group:getController()
for index, unit in pairs(group:getUnits()) do
local table = {}
table["targets"] = {}
table["targets"]["visual"] = controller:getDetectedTargets(1)
table["targets"]["radar"] = controller:getDetectedTargets(4)
table["targets"]["rwr"] = controller:getDetectedTargets(16)
table["targets"]["other"] = controller:getDetectedTargets(2, 8, 32)
table["hasTask"] = controller:hasTask()
table["ammo"] = unit:getAmmo()
table["fuel"] = unit:getFuel()
table["life"] = unit:getLife() / unit:getLife0()
unitsData[unit:getObjectID()] = table
table["hasTask"] = controller:hasTask()
table["ammo"] = unit:getAmmo()
table["fuel"] = unit:getFuel()
table["life"] = unit:getLife() / unit:getLife0()
unitsData[unit:getObjectID()] = table
end
end
end
end
if index >= endIndex then
break
end
end
if index >= endIndex then
break
if index ~= endIndex then
Olympus.groupIndex = 0
else
Olympus.groupIndex = endIndex
end
end
if index ~= endIndex then
Olympus.groupIndex = 0
else
Olympus.groupIndex = endIndex
end
-- Airbases data
local base = world.getAirbases()
@@ -496,6 +558,10 @@ function Olympus.setMissionData(arg, time)
local mission = {}
mission.theatre = env.mission.theatre
mission.elapsedTime = DCS.getRealTime()
mission.time = mist.time.getDHMS(timer.getAbsTime())
mission.startTime = env.mission.start_time
mission.date = env.mission.date
-- Assemble missionData table
missionData["bullseyes"] = bullseyes

View File

@@ -1,4 +1,4 @@
local version = 'v0.1.1-alpha'
local version = 'v0.2.1-alpha'
Olympus = {}
Olympus.OlympusDLL = nil

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -185,7 +185,7 @@
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PrecompiledHeaderFile>
</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>include;..\..\third-party\lua\include;..\utils\include;..\shared\include;..\dcstools\include;..\logger\include;..\luatools\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>include;..\..\third-party\base64\include;..\..\third-party\lua\include;..\utils\include;..\shared\include;..\dcstools\include;..\logger\include;..\luatools\include</AdditionalIncludeDirectories>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>

View File

@@ -23,8 +23,6 @@ protected:
virtual void setState(int newState);
bool isDestinationReached();
bool setActiveDestination();
void createHoldingPattern();
bool updateActivePath(bool looping);
void goToDestination(wstring enrouteTask = L"nil");
void taskWingmen();
};

View File

@@ -7,10 +7,6 @@ namespace CommandPriority {
enum CommandPriorities { LOW, MEDIUM, HIGH };
};
namespace CommandType {
enum CommandTypes { NO_TYPE, MOVE, SMOKE, SPAWN_AIR, SPAWN_GROUND, CLONE, FOLLOW, RESET_TASK, SET_OPTION, SET_COMMAND, SET_TASK };
};
namespace SetCommandType {
enum SetCommandTypes {
ROE = 0,
@@ -61,29 +57,25 @@ class Command
{
public:
int getPriority() { return priority; }
int getType() { return type; }
virtual wstring getString(lua_State* L) = 0;
virtual int getLoad() = 0;
protected:
int priority = CommandPriority::LOW;
int type = CommandType::NO_TYPE;
};
/* Simple low priority move command (from user click) */
class Move : public Command
{
public:
Move(int ID, Coords destination, double speed, double altitude, wstring unitCategory, wstring taskOptions):
Move(int ID, Coords destination, double speed, double altitude, wstring taskOptions):
ID(ID),
destination(destination),
speed(speed),
altitude(altitude),
unitCategory(unitCategory),
taskOptions(taskOptions)
{
priority = CommandPriority::HIGH;
type = CommandType::MOVE;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 5; }
@@ -91,7 +83,6 @@ public:
private:
const int ID;
const Coords destination;
const wstring unitCategory;
const double speed;
const double altitude;
const wstring taskOptions;
@@ -106,7 +97,6 @@ public:
location(location)
{
priority = CommandPriority::LOW;
type = CommandType::SMOKE;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 5; }
@@ -126,7 +116,6 @@ public:
location(location)
{
priority = CommandPriority::LOW;
type = CommandType::SPAWN_GROUND;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 100; }
@@ -149,7 +138,6 @@ public:
airbaseName(airbaseName)
{
priority = CommandPriority::LOW;
type = CommandType::SPAWN_AIR;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 100; }
@@ -171,7 +159,6 @@ public:
location(location)
{
priority = CommandPriority::LOW;
type = CommandType::CLONE;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 100; }
@@ -189,7 +176,6 @@ public:
ID(ID)
{
priority = CommandPriority::HIGH;
type = CommandType::CLONE;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 20; }
@@ -207,7 +193,6 @@ public:
task(task)
{
priority = CommandPriority::MEDIUM;
type = CommandType::FOLLOW;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 10; }
@@ -225,7 +210,6 @@ public:
ID(ID)
{
priority = CommandPriority::HIGH;
type = CommandType::RESET_TASK;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 10; }
@@ -243,7 +227,6 @@ public:
command(command)
{
priority = CommandPriority::HIGH;
type = CommandType::RESET_TASK;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 10; }
@@ -263,7 +246,6 @@ public:
optionValue(optionValue)
{
priority = CommandPriority::HIGH;
type = CommandType::RESET_TASK;
};
virtual wstring getString(lua_State* L);
virtual int getLoad() { return 10; }

View File

@@ -27,5 +27,7 @@ private:
void task();
atomic<bool> runListener;
wstring password = L"";
};

View File

@@ -34,6 +34,7 @@ public:
void updateExportData(json::value json);
void updateMissionData(json::value json);
json::value getData(long long time);
virtual wstring getCategory() { return L"No category"; };
/********** Base data **********/
void setAI(bool newAI) { AI = newAI; addMeasure(L"AI", json::value(newAI)); }
@@ -79,17 +80,9 @@ public:
json::value getFlags() { return flags; }
/********** Formation data **********/
void setIsLeader(bool newIsLeader);
void setIsWingman(bool newIsWingman);
void setLeader(Unit* newLeader);
void setWingmen(vector<Unit*> newWingmen);
void setFormation(wstring newFormation) { formation = newFormation; addMeasure(L"formation", json::value(formation));}
void setLeaderID(int newLeaderID) { leaderID = newLeaderID; addMeasure(L"leaderID", json::value(newLeaderID)); }
void setFormationOffset(Offset formationOffset);
bool getIsLeader() { return isLeader; }
bool getIsWingman() { return isWingman; }
Unit* getLeader() { return leader; }
vector<Unit*> getWingmen() { return wingmen; }
wstring getFormation() { return formation; }
int getLeaderID() { return leaderID; }
Offset getFormationoffset() { return formationOffset; }
/********** Task data **********/
@@ -103,13 +96,32 @@ public:
void pushActivePathBack(Coords newActivePathBack);
void popActivePathFront();
void setTargetID(int newTargetID) { targetID = newTargetID; addMeasure(L"targetID", json::value(newTargetID));}
void setIsTanker(bool newIsTanker);
void setIsAWACS(bool newIsAWACS);
void setTACANChannel(int newTACANChannel);
void setTACANXY(wstring newTACANXY);
void setTACANCallsign(wstring newTACANCallsign);
void setTACAN();
void setEPLRS(bool state);
void setRadioFrequency(int newRadioFrequency);
void setRadioCallsign(int newRadioCallsign);
void setRadioCallsignNumber(int newRadioCallsignNumber);
void setRadio();
wstring getCurrentTask() { return currentTask; }
virtual double getTargetSpeed() { return targetSpeed; };
virtual double getTargetAltitude() { return targetAltitude; };
Coords getActiveDestination() { return activeDestination; }
list<Coords> getActivePath() { return activePath; }
int getTargetID() { return targetID; }
bool getIsTanker() { return isTanker; }
bool getIsAWACS() { return isAWACS; }
int getTACANChannel() { return TACANChannel; }
wstring getTACANXY() { return TACANXY; }
wstring getTACANCallsign() { return TACANCallsign; }
int getRadioFrequency() { return radioFrequency; }
int getRadioCallsign() { return radioCallsign; }
int getRadioCallsignNumber() { return radioCallsignNumber; }
/********** Options data **********/
void setROE(wstring newROE);
void setReactionToThreat(wstring newReactionToThreat);
@@ -147,6 +159,7 @@ protected:
/********** Mission data **********/
double fuel = 0;
double initialFuel = 0; // Used internally to detect refueling completed
json::value ammo = json::value::null();
json::value targets = json::value::null();
bool hasTask = false;
@@ -154,11 +167,7 @@ protected:
json::value flags = json::value::null();
/********** Formation data **********/
bool isLeader = false;
bool isWingman = false;
wstring formation = L"";
Unit *leader = nullptr;
vector<Unit *> wingmen;
int leaderID = NULL;
Offset formationOffset = Offset(NULL);
/********** Task data **********/
@@ -168,6 +177,14 @@ protected:
list<Coords> activePath;
Coords activeDestination = Coords(0);
int targetID = NULL;
bool isTanker = false;
bool isAWACS = false;
int TACANChannel = 40;
wstring TACANXY = L"X";
wstring TACANCallsign = L"TKR";
int radioFrequency = 260000000; // MHz
int radioCallsign = 1;
int radioCallsignNumber = 1;
/********** Options data **********/
wstring ROE = L"";
@@ -180,9 +197,10 @@ protected:
Coords oldPosition = Coords(0); // Used to approximate speed
/********** Functions **********/
virtual wstring getCategory() { return L"No category"; };
wstring getTargetName();
wstring getLeaderName();
bool isTargetAlive();
bool isLeaderAlive();
virtual void AIloop() = 0;
void addMeasure(wstring key, json::value value);
};

View File

@@ -22,6 +22,7 @@ void AirUnit::setState(int newState)
{
if (state != newState)
{
/************ Perform any action required when LEAVING a certain state ************/
switch (state) {
case State::IDLE: {
break;
@@ -34,27 +35,30 @@ void AirUnit::setState(int newState)
break;
}
case State::FOLLOW: {
break;
}
case State::WINGMAN: {
if (isWingman)
return;
setLeaderID(NULL);
break;
}
case State::LAND: {
break;
}
case State::REFUEL: {
break;
}
default:
break;
}
/************ Perform any action required when ENTERING a certain state ************/
switch (newState) {
case State::IDLE: {
clearActivePath();
resetActiveDestination();
addMeasure(L"currentState", json::value(L"Idle"));
break;
}
case State::REACH_DESTINATION: {
resetActiveDestination();
addMeasure(L"currentState", json::value(L"Reach destination"));
break;
}
case State::ATTACK: {
@@ -64,19 +68,26 @@ void AirUnit::setState(int newState)
clearActivePath();
pushActivePathFront(targetPosition);
resetActiveDestination();
addMeasure(L"currentState", json::value(L"Attack"));
}
break;
}
case State::FOLLOW: {
clearActivePath();
resetActiveDestination();
break;
}
case State::WINGMAN: {
resetActiveDestination();
addMeasure(L"currentState", json::value(L"Follow"));
break;
}
case State::LAND: {
resetActiveDestination();
addMeasure(L"currentState", json::value(L"Land"));
break;
}
case State::REFUEL: {
initialFuel = fuel;
clearActivePath();
resetActiveDestination();
addMeasure(L"currentState", json::value(L"Refuel"));
break;
}
default:
@@ -125,23 +136,6 @@ bool AirUnit::setActiveDestination()
}
}
void AirUnit::createHoldingPattern()
{
/* Air units must ALWAYS have a destination or they will RTB and become uncontrollable */
clearActivePath();
Coords point1;
Coords point2;
Coords point3;
Geodesic::WGS84().Direct(latitude, longitude, 45, 10000, point1.lat, point1.lng);
Geodesic::WGS84().Direct(point1.lat, point1.lng, 135, 10000, point2.lat, point2.lng);
Geodesic::WGS84().Direct(point2.lat, point2.lng, 225, 10000, point3.lat, point3.lng);
pushActivePathBack(point1);
pushActivePathBack(point2);
pushActivePathBack(point3);
pushActivePathBack(Coords(latitude, longitude));
log(unitName + L" holding pattern created");
}
bool AirUnit::updateActivePath(bool looping)
{
if (activePath.size() > 0)
@@ -162,7 +156,7 @@ void AirUnit::goToDestination(wstring enrouteTask)
{
if (activeDestination != NULL)
{
Command* command = dynamic_cast<Command*>(new Move(ID, activeDestination, getTargetSpeed(), getTargetAltitude(), getCategory(), enrouteTask));
Command* command = dynamic_cast<Command*>(new Move(ID, activeDestination, getTargetSpeed(), getTargetAltitude(), enrouteTask));
scheduler->appendCommand(command);
hasTask = true;
}
@@ -170,63 +164,50 @@ void AirUnit::goToDestination(wstring enrouteTask)
log(unitName + L" error, no active destination!");
}
void AirUnit::taskWingmen()
{
switch (state) {
case State::IDLE:
case State::REACH_DESTINATION:
case State::ATTACK:{
int idx = 1;
for (auto const& wingman : wingmen)
{
if (!wingman->getIsWingman())
{
wingman->setIsWingman(true);
wingman->setLeader(this);
}
if (wingman->getFormation().compare(formation) != 0)
{
wingman->resetTask();
wingman->setFormation(formation);
if (formation.compare(L"Line abreast") == 0)
wingman->setFormationOffset(Offset(0 * idx, 0 * idx, 1852 * idx));
idx++;
}
}
break;
}
default:
break;
}
}
void AirUnit::AIloop()
{
/* State machine */
switch (state) {
case State::IDLE: {
wstring enrouteTask = L"nil";
currentTask = L"Idle";
if (activeDestination == NULL || !hasTask)
if (!hasTask)
{
createHoldingPattern();
setActiveDestination();
goToDestination(enrouteTask);
std::wostringstream taskSS;
if (isTanker) {
taskSS << "{ [1] = { id = 'Tanker' }, [2] = { id = 'Orbit', pattern = 'Race-Track' } }";
}
else if (isAWACS) {
taskSS << "{ [1] = { id = 'AWACS' }, [2] = { id = 'Orbit', pattern = 'Circle' } }";
}
else {
taskSS << "{ id = 'Orbit', pattern = 'Circle' }";
}
Command* command = dynamic_cast<Command*>(new SetTask(ID, taskSS.str()));
scheduler->appendCommand(command);
hasTask = true;
}
else {
if (isDestinationReached() && updateActivePath(true) && setActiveDestination())
goToDestination(enrouteTask);
}
if (isLeader)
taskWingmen();
break;
}
case State::REACH_DESTINATION: {
wstring enrouteTask = L"nil";
currentTask = L"Reaching destination";
wstring enrouteTask = L"";
bool looping = false;
if (isTanker)
{
enrouteTask = L"{ id = 'Tanker' }";
currentTask = L"Tanker";
}
else if (isAWACS)
{
enrouteTask = L"{ id = 'AWACS' }";
currentTask = L"AWACS";
}
else
{
enrouteTask = L"nil";
currentTask = L"Reaching destination";
}
if (activeDestination == NULL || !hasTask)
{
@@ -235,23 +216,18 @@ void AirUnit::AIloop()
}
else {
if (isDestinationReached()) {
if (updateActivePath(false) && setActiveDestination())
if (updateActivePath(looping) && setActiveDestination())
goToDestination(enrouteTask);
else {
setState(State::IDLE);
break;
}
}
}
if (isLeader)
taskWingmen();
}
break;
}
case State::LAND: {
wstring enrouteTask = L"{" "id = 'land' }";
wstring enrouteTask = L"{ id = 'Land' }";
currentTask = L"Landing";
if (activeDestination == NULL)
@@ -259,10 +235,6 @@ void AirUnit::AIloop()
setActiveDestination();
goToDestination(enrouteTask);
}
if (isLeader)
taskWingmen();
break;
}
case State::ATTACK: {
@@ -282,42 +254,27 @@ void AirUnit::AIloop()
wstring enrouteTask = enrouteTaskSS.str();
currentTask = L"Attacking " + getTargetName();
if (activeDestination == NULL || !hasTask)
if (!hasTask)
{
setActiveDestination();
goToDestination(enrouteTask);
}
else {
if (isDestinationReached()) {
if (updateActivePath(false) && setActiveDestination())
goToDestination(enrouteTask);
else {
setState(State::IDLE);
break;
}
}
}
if (isLeader)
taskWingmen();
break;
}
case State::FOLLOW: {
/* TODO */
setState(State::IDLE);
break;
}
case State::WINGMAN: {
/* In the WINGMAN state, the unit relinquishes control to the leader */
clearActivePath();
activeDestination = Coords(NULL);
if (leader == nullptr || !leader->getAlive())
{
this->setFormation(L"");
this->setIsWingman(false);
/* If the leader is not alive (either not set or was destroyed) go back to IDLE */
if (!isLeaderAlive()) {
setState(State::IDLE);
break;
}
currentTask = L"Following " + getTargetName();
Unit* leader = unitsManager->getUnit(leaderID);
if (!hasTask) {
if (leader != nullptr && leader->getAlive() && formationOffset != NULL)
{
@@ -338,7 +295,27 @@ void AirUnit::AIloop()
}
break;
}
case State::REFUEL: {
currentTask = L"Refueling";
if (!hasTask) {
if (fuel <= initialFuel) {
std::wostringstream taskSS;
taskSS << "{"
<< "id = 'Refuel'"
<< "}";
Command* command = dynamic_cast<Command*>(new SetTask(ID, taskSS.str()));
scheduler->appendCommand(command);
hasTask = true;
}
else {
setState(State::IDLE);
}
}
}
default:
break;
}
addMeasure(L"currentTask", json::value(currentTask));
}

View File

@@ -1,21 +1,33 @@
#include "commands.h"
#include "logger.h"
#include "dcstools.h"
#include "unit.h"
#include "unitsmanager.h"
extern UnitsManager* unitsManager;
/* Move command */
wstring Move::getString(lua_State* L)
{
std::wostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.move, "
<< ID << ", "
<< destination.lat << ", "
<< destination.lng << ", "
<< altitude << ", "
<< speed << ", "
<< "\"" << unitCategory << "\"" << ", "
<< taskOptions;
return commandSS.str();
Unit* unit = unitsManager->getUnit(ID);
if (unit != nullptr)
{
std::wostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.move, "
<< ID << ", "
<< destination.lat << ", "
<< destination.lng << ", "
<< altitude << ", "
<< speed << ", "
<< "\"" << unit->getCategory() << "\"" << ", "
<< taskOptions;
return commandSS.str();
}
else
{
return L"";
}
}
/* Smoke command */
@@ -67,13 +79,22 @@ wstring SpawnAircraft::getString(lua_State* L)
/* Clone unit command */
wstring Clone::getString(lua_State* L)
{
std::wostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.clone, "
<< ID << ", "
<< location.lat << ", "
<< location.lng;
return commandSS.str();
Unit* unit = unitsManager->getUnit(ID);
if (unit != nullptr)
{
std::wostringstream commandSS;
commandSS.precision(10);
commandSS << "Olympus.clone, "
<< ID << ", "
<< location.lat << ", "
<< location.lng << ", "
<< "\"" << unit->getCategory() << "\"";
return commandSS.str();
}
else
{
return L"";
}
}
/* Delete unit command */

Some files were not shown because too many files have changed in this diff Show More