321 Commits

Author SHA1 Message Date
Pax1601
283b9e682e v0.4.7 2023-11-17 22:04:21 +01:00
Pax1601
8b5956e76b Merge pull request #536 from Pax1601/489-show-all-the-action-options-of-the-selected-units-even-if-some-units-dont-have-them
489 show all the action options of the selected units even if some units dont have them
2023-11-17 22:02:51 +01:00
Pax1601
017a89b945 getDesc().category reimplemented
unit:getCategory() reports "Airplane" for Helicopters
2023-11-17 22:02:32 +01:00
Pax1601
5bc685182b Merge branch 'main' into 489-show-all-the-action-options-of-the-selected-units-even-if-some-units-dont-have-them 2023-11-17 21:40:09 +01:00
Pax1601
f47fc2fb19 Merge pull request #535 from Pax1601/534-olympus-not-sending-data-with-dcs-open-beta-29148111
Changed unit:getCategory to Object.getCategory(unit)
2023-11-17 21:35:20 +01:00
Pax1601
11d6f25606 Changed unit:getCategory to Object.getCategory(unit)
And added some isExist guards
2023-11-17 21:34:50 +01:00
Pax1601
331692e3d3 Merge branch '489-show-all-the-action-options-of-the-selected-units-even-if-some-units-dont-have-them' of https://github.com/Pax1601/DCSOlympus into 489-show-all-the-action-options-of-the-selected-units-even-if-some-units-dont-have-them 2023-11-17 21:10:49 +01:00
Pax1601
7483225e0d Small tweak to login page 2023-11-17 21:10:46 +01:00
Pax1601
22ae882032 Unit gets forcefully deselected when hidden 2023-11-17 17:45:10 +01:00
Pax1601
fbab82e4de Merge branch 'main' into 489-show-all-the-action-options-of-the-selected-units-even-if-some-units-dont-have-them 2023-11-17 17:26:56 +01:00
Pax1601
ca81d1c4ce Merge pull request #530 from Pax1601/529-add-favicon
Favicons
2023-11-17 17:24:03 +01:00
Pax1601
a1884ab19f Merge pull request #527 from Pax1601/522-flashpulse-robot-lock-when-trying-to-give-orders-to-protected-units
Lock flashes on protected robot interaction
2023-11-17 17:23:18 +01:00
Pax1601
8905cd5e85 Merge pull request #526 from Pax1601/523-selected-units-dont-get-hidden
Selected units now hidden on request
2023-11-17 17:22:36 +01:00
PeekabooSteam
8d5ed33ad8 Favicons 2023-11-17 11:35:55 +00:00
Pax1601
b747752b76 Fixed error in follow command 2023-11-17 07:59:04 +01:00
PeekabooSteam
4e13daa270 Lock flashes on protected robot interaction 2023-11-16 23:08:01 +00:00
PeekabooSteam
c00096bd9a Selected units now hidden on request 2023-11-16 22:26:09 +00:00
Pax1601
4a54011aac Large rework of context menus for units and map 2023-11-16 15:31:07 +01:00
Pax1601
0c50141be6 v0.4.6 2023-11-15 16:42:24 +01:00
Pax1601
a71b8806e7 Update groundunitdatabase.json 2023-11-15 16:06:52 +01:00
Pax1601
e0a27c574f Merge pull request #519 from Pax1601/493-for-ground-units-add-marker-symbol-in-database
493 for ground units add marker symbol in database
2023-11-15 15:38:59 +01:00
Pax1601
8d7a49a31f Created group handlers 2023-11-15 15:38:16 +01:00
Pax1601
25e2c50438 Added unit marker to database and implemented better grouping 2023-11-14 17:43:24 +01:00
Pax1601
e3423ea9a3 Merged new databases 2023-11-14 07:53:01 +01:00
Pax1601
812112858c Merge branch 'main' into 493-for-ground-units-add-marker-symbol-in-database 2023-11-13 19:27:41 +01:00
Pax1601
8db1357904 Merge branch 'main' of https://github.com/Pax1601/DCSOlympus 2023-11-13 18:55:19 +01:00
Pax1601
bba0aa9f52 Fixed databasemanager overflow 2023-11-13 18:54:11 +01:00
Pax1601
1cc549b24a Added entry to databases 2023-11-13 18:02:08 +01:00
Pax1601
7cafeb73ca Added tags to unit spawn menu 2023-11-13 16:04:53 +01:00
Pax1601
772f082913 Tweaked installer message 2023-11-13 09:08:40 +01:00
Pax1601
9f7efe3018 Merge pull request #517 from Pax1601/437-f-14b-not-spawning-with-weapons
Fixed errors in loadouts scripts
2023-11-12 18:44:18 +01:00
Pax1601
a28584b08b Fixed errors in loadouts scripts 2023-11-12 18:43:49 +01:00
Pax1601
5cba46a482 Merge pull request #516 from Pax1601/437-f-14b-not-spawning-with-weapons
Fixed loadout generator adding exceptions for Tomcats
2023-11-12 17:43:37 +01:00
Pax1601
a15b7620eb Fixed loadout generator adding exceptions for Tomcats 2023-11-12 17:42:54 +01:00
Pax1601
49bff88c4e Radio and TACAN frequencies are now clamped 2023-11-12 17:18:18 +01:00
Pax1601
80af34fa3e Merge pull request #515 from Pax1601/265-cloning-a-dead-unit-fails
Dead units can now be cloned
2023-11-12 16:36:04 +01:00
Pax1601
1d6f2644aa Dead units can now be cloned 2023-11-12 16:35:31 +01:00
Pax1601
dc61d364d1 Merge pull request #514 from Pax1601/448-on-chrome-fps-drops-to-single-digits-when-zoomed-in
Implemented custom fast renderer for range circles
2023-11-12 15:50:44 +01:00
Pax1601
78de9dd538 Implemented custom fast renderer for range circles
It's a bit hacky since I had to override a default leaflet renderer function. Works well but may be injected in a more elegant way.
2023-11-12 15:49:46 +01:00
Pax1601
ccaea5b9d1 Better unit explosion buttons design 2023-11-12 14:08:10 +01:00
Pax1601
e02e9de55d Updated databases 2023-11-09 19:27:32 +01:00
Pax1601
40da192dbb Merge pull request #512 from Pax1601/486-add-more-advanced-effects
486 add more advanced effects
2023-11-09 08:27:06 +01:00
Pax1601
c8254238c7 Scrollable unit control panel tweak 2023-11-09 08:26:43 +01:00
Pax1601
9caee0c77c Implemented buttons to apply advanced controls directly to units 2023-11-08 23:33:27 +01:00
Pax1601
b9830f0190 Merge branch 'main' into 486-add-more-advanced-effects 2023-11-08 22:04:52 +01:00
Pax1601
02a0a9b783 Merge pull request #504 from Pax1601/484-add-life-meter-to-ground-units
484 add life meter to ground units
2023-11-08 21:57:27 +01:00
Pax1601
ea1758a1a9 Added backend code for health display
And fixed the issue of ground units not being deleted correctly
2023-11-08 21:56:39 +01:00
Pax1601
d5d8391f63 Merge pull request #508 from Pax1601/494-make-the-installer-more-clear-specify-that-olympus-must-be-installed-in-savedgames
Changed message and fixed wrong installation folder after user selection
2023-11-08 10:17:40 +01:00
Pax1601
b508d2301b Changed message and fixed wrong installation folder after user selection 2023-11-08 10:16:33 +01:00
Pax1601
01b3336709 Merge pull request #507 from Pax1601/495-make-ui-port-configurable-from-olympusjson
Added port selection to config
2023-11-08 09:59:50 +01:00
Pax1601
6ba37aefd6 Added port selection to config 2023-11-08 09:59:21 +01:00
Pax1601
a804904ff5 Merge pull request #506 from Pax1601/dynamic-resizing
Dynamic resizing
2023-11-07 19:36:08 +01:00
Pax1601
eacb89176c Completed new resizable design 2023-11-07 17:37:19 +01:00
PeekabooSteam
ec971aa822 Merge branch 'main' into 484-add-life-meter-to-ground-units 2023-11-06 22:29:23 +00:00
PeekabooSteam
e1f404c647 Added some doc comments 2023-11-06 22:28:44 +00:00
PeekabooSteam
5f1e32d610 Conflict fix 2023-11-06 21:51:45 +00:00
PeekabooSteam
732ee2bbb9 Added + for naval and ground units 2023-11-06 21:49:54 +00:00
Pax1601
1e461250d5 Added advanced effects 2023-11-06 19:26:15 +01:00
Pax1601
f727174044 Testing of dynamic resizing 2023-11-06 18:30:59 +01:00
Pax1601
7edc687f7b Merge pull request #501 from Pax1601/499-spawn-menu-reorganisation
Air defence has its own spawn icon
2023-11-06 11:13:12 +01:00
Pax1601
596fbf0b87 Merge branch 'main' into 499-spawn-menu-reorganisation 2023-11-06 11:12:46 +01:00
PeekabooSteam
5db90e5896 Changed air defence form to extend ground units' form 2023-11-05 19:24:23 +00:00
PeekabooSteam
dd811def07 Added health bar 2023-11-05 19:11:42 +00:00
Pax1601
5273291e9a Merge pull request #503 from Pax1601/485-improve-miss-on-purpose
485 improve miss on purpose
2023-11-05 17:35:03 +01:00
Pax1601
130dbda499 Merge branch 'main' into 485-improve-miss-on-purpose 2023-11-05 17:34:56 +01:00
Pax1601
769aea7e4e Merge pull request #502 from Pax1601/500-log-in-form-needs-to-submit-when-pressing-enterreturn
500 log in form needs to submit when pressing enterreturn
2023-11-05 17:28:42 +01:00
Pax1601
fa3d65bde6 Completed miss on purpose functionality 2023-11-05 17:26:39 +01:00
PeekabooSteam
073281135c Fixed odd 'undefined' bug 2023-11-05 13:15:41 +00:00
PeekabooSteam
4c7f979e56 Merge branch '498-set-ucp-and-uip-toggles-into-olympus-context' into 500-log-in-form-needs-to-submit-when-pressing-enterreturn 2023-11-05 13:08:24 +00:00
PeekabooSteam
a5bfb4f8d2 Form submits on return press 2023-11-05 13:05:46 +00:00
PeekabooSteam
a04780f311 Merge branch 'main' into 500-log-in-form-needs-to-submit-when-pressing-enterreturn 2023-11-05 12:37:36 +00:00
PeekabooSteam
aad0fd22ad Air defence has its own spawn icon 2023-11-05 10:57:53 +00:00
Pax1601
bc1c3994d3 Merge branch 'main' into 485-improve-miss-on-purpose 2023-11-04 10:21:37 +01:00
Pax1601
840033aa6a Merge pull request #496 from Pax1601/468-robot-protection-toggle
468 robot protection toggle
2023-11-04 10:10:09 +01:00
Pax1601
9cc6e9e790 More work on miss on purpose 2023-11-04 09:57:18 +01:00
PeekabooSteam
b1ad2f409e Controlling panels and spawn menu from context 2023-11-03 22:36:35 +00:00
PeekabooSteam
7106646042 Updated landAtPoint logic 2023-11-03 18:28:05 +00:00
PeekabooSteam
31405119f0 Enabled mixed-group actions, fixed some helicopter messages. 2023-11-03 18:17:40 +00:00
PeekabooSteam
2e5ee93361 Tweaked colours. 2023-11-03 14:05:39 +00:00
PeekabooSteam
f981a661d5 Added lock image and tooltip/titles. 2023-11-03 13:29:09 +00:00
Pax1601
7e05bbf5e3 Improved scheduler logging 2023-11-03 11:37:09 +01:00
PeekabooSteam
4465f4a3bb PoC of robot protection 2023-11-02 23:03:17 +00:00
PeekabooSteam
ade4f183cd Commit so I can switch to another branch. 2023-11-02 18:22:42 +00:00
Pax1601
99dc61799f Merge branch 'main' of https://github.com/Pax1601/DCSOlympus 2023-11-02 17:24:39 +01:00
Pax1601
a213b94606 Minor fixes 2023-11-02 17:24:35 +01:00
Pax1601
6600ed8cbb Merge pull request #473 from Pax1601/357-map-context-switching
357 map context switching
2023-11-02 09:46:09 +01:00
PeekabooSteam
826bf12bd6 Merge branch 'main' into 357-map-context-switching 2023-10-31 20:30:18 +00:00
Pax1601
528e0db79c Updated demo.js 2023-10-31 17:48:09 +01:00
Pax1601
11a5fec195 Added effect of vertical velocity and of scatter and intensity 2023-10-30 15:56:10 +01:00
Pax1601
c0f3f3a40a Added scatter and intensity selectors in UI 2023-10-30 12:46:49 +01:00
Pax1601
88844db23a Added shots scatter and intensity variables to backend 2023-10-30 10:09:49 +01:00
Pax1601
31710b4e28 Updated legal text 2023-10-30 09:56:07 +01:00
Pax1601
42d2f6400b Merge pull request #476 from Pax1601/edits_legal
Update and rename COPYING to LEGAL
2023-10-28 14:42:03 +02:00
Pax1601
2701d6adc0 Merge pull request #472 from Pax1601/464-proposed-hot-group-behaviour-tweak-to-be-like-lakecraft-shift-+-1-appends-to-group
464 proposed hot group behaviour tweak to be like lakecraft shift + 1 appends to group
2023-10-28 14:40:06 +02:00
Pax1601
5a4b203937 Merge pull request #477 from Pax1601/463-delete-needs-three-buttons
Added new delete method dialog
2023-10-28 14:38:42 +02:00
Pax1601
74cb7877cb Merge pull request #474 from Pax1601/460-sam-threat-rings-appear-when-they-shouldnt
460 sam threat rings appear when they shouldnt
2023-10-28 14:36:24 +02:00
PeekabooSteam
f954338c27 Added new delete method dialog 2023-10-27 17:26:41 +01:00
Shredmetal
cc729b1d25 Update and rename COPYING to LEGAL
Cleaned up the legal text
2023-10-26 16:45:58 +08:00
PeekabooSteam
4a4b1d6b00 Merge branch 'main' of https://github.com/Pax1601/DCSOlympus into main 2023-10-20 11:04:24 +01:00
Pax1601
d14741f3b1 Merge pull request #471 from Pax1601/470-spawn-menu-qty-sorted-alphabetically-not-numerically
Unit spawn qty now sorted numerically.
2023-10-19 01:29:45 +02:00
PeekabooSteam
94684fff9f More spacing tweaking 2023-10-18 13:54:33 +01:00
PeekabooSteam
44deef4a5a Tweaked spacing 2023-10-18 13:23:25 +01:00
PeekabooSteam
67079e1c0b Munitions constrained to a scrollable 2023-10-18 13:20:54 +01:00
PeekabooSteam
005ffc55ce var => let 2023-10-18 12:15:59 +01:00
PeekabooSteam
1691b0b30c Range rings only showing when necessary 2023-10-18 12:13:51 +01:00
PeekabooSteam
e4e55430ca Optimised quantity option generator 2023-10-18 11:17:05 +01:00
PeekabooSteam
4d31d9d748 Unit spawn qty now sorted numerically. 2023-10-18 10:23:50 +01:00
PeekabooSteam
1413f596fb Improved filter logic 2023-10-17 11:27:21 +01:00
PeekabooSteam
c0aee94da5 Hotgroup logic updated 2023-10-16 19:45:51 +01:00
PeekabooSteam
8e545346e6 Exploratory tweaks 2023-10-16 09:13:44 +01:00
PeekabooSteam
2b1272c70d Removed needless [] 2023-10-15 11:53:12 +01:00
PeekabooSteam
121f9b6ec3 Tweaked string functions 2023-10-15 11:51:49 +01:00
PeekabooSteam
6f9722143e Took shift and alt requirements from T key for demo data 2023-10-15 10:59:39 +01:00
PeekabooSteam
5bf62f4b93 Removed needless context.ts ref 2023-10-15 10:24:41 +01:00
PeekabooSteam
79319dd006 Shortcuts can be set to a context 2023-10-15 10:22:03 +01:00
PeekabooSteam
fdcff53697 Shortcuts now settable to a context. 2023-10-15 09:43:26 +01:00
Pax1601
24cd2729db Startup script updated 2023-10-15 09:54:57 +02:00
Pax1601
9ca2703f16 More package build updates 2023-10-14 12:32:24 +02:00
Pax1601
1a579c5755 Build scripts updated 2023-10-14 12:13:32 +02:00
Pax1601
7344c761fe Small bugfixes 2023-10-14 11:07:39 +02:00
Pax1601
203a981fed Merge pull request #459 from Pax1601/small-issues
Modified isTanker and isAWACS to isActiveTanker and isActiveAWACS
2023-10-13 16:35:52 +02:00
Pax1601
d3faf65900 Modified isTanker and isAWACS to isActiveTanker and isActiveAWACS 2023-10-13 16:35:11 +02:00
Pax1601
5efbf81090 Merge pull request #458 from Pax1601/small-issues
Fixed wrong cursor type
2023-10-13 15:23:51 +02:00
Pax1601
9ffab7d531 Fixed wrong cursor type 2023-10-13 15:23:29 +02:00
Pax1601
0886ff1be1 Merge pull request #456 from Pax1601/small-issues
Removed preferCanvas option for map
2023-10-13 12:49:12 +02:00
Pax1601
2893182713 Removed preferCanvas option for map
Which apparently causes Chrome to slow down when zoomed in. More test required to check performance.
2023-10-13 12:48:51 +02:00
Pax1601
478bb18ab2 Updated version number 2023-10-11 18:05:58 +02:00
Pax1601
eae07ca6cc Merge pull request #455 from Pax1601/small-issues
Small issues
2023-10-11 18:01:46 +02:00
Pax1601
2264faabfc Updated databases 2023-10-11 18:01:27 +02:00
Pax1601
4cdf82cb14 Database fixes 2023-10-11 15:20:24 +02:00
Pax1601
5a7e511dac Merge pull request #450 from Pax1601/small-issues
Small issues
2023-10-11 12:56:04 +02:00
Pax1601
a29eb3d343 Added stop command to helicopters 2023-10-11 12:55:41 +02:00
Pax1601
3c65aefe61 Fixed destination preview handle showing incorrectly 2023-10-11 12:49:44 +02:00
Pax1601
867d7697d2 Moved tanker/AWACS button to control panel 2023-10-11 12:37:16 +02:00
Pax1601
ebee6610a3 Added tanker and off state icons 2023-10-11 08:00:43 +02:00
Pax1601
c26691c2fc Merge pull request #449 from Pax1601/small-issues
Added "land at point" state for helicopters
2023-10-10 17:11:05 +02:00
Pax1601
a038d6e999 Added "land at point" state for helicopters 2023-10-10 17:10:29 +02:00
Pax1601
aa1550ca01 Merge pull request #446 from Pax1601/small-issues
TACAN and radio can now be set on carriers
2023-10-10 15:49:15 +02:00
Pax1601
80eaa643c9 TACAN and radio can now be set on carriers 2023-10-10 15:27:42 +02:00
Pax1601
d67d9c1afd Merge pull request #445 from Pax1601/small-issues
Added Strike Eagle
2023-10-10 15:18:43 +02:00
Pax1601
af15fc123d Added Strike Eagle 2023-10-10 15:18:19 +02:00
Pax1601
0ce56e6529 Merge pull request #444 from Pax1601/metadata
Added abilities and description to spawn menu
2023-10-10 14:34:37 +02:00
Pax1601
258164c285 Added abilities and description to spawn menu 2023-10-10 14:34:19 +02:00
Pax1601
746617deb0 Merge pull request #443 from Pax1601/427-toggle-mouse-info-format-latlng-grid-decimals
Can now get LatLng, MGRS and UTM location data
2023-10-09 10:46:15 +02:00
Pax1601
c51d00673d Merge pull request #441 from Pax1601/440-refuelling-misspelled-as-refueling
Missing Ls added
2023-10-09 10:45:32 +02:00
PeekabooSteam
bedd21522a Can now get LatLng, MGRS and UTM location data 2023-10-08 16:44:55 +01:00
PeekabooSteam
382013d0ca Missing Ls added 2023-10-06 16:56:09 +01:00
Pax1601
3794207d97 Added missing button 2023-10-06 16:20:43 +02:00
Pax1601
2805323cfa Merge pull request #439 from Pax1601/small-bugfixes
Small bugfixes
2023-10-06 16:08:38 +02:00
Pax1601
0db2e56e32 Completed range rings 2023-10-06 16:07:54 +02:00
Pax1601
a33ad18322 Merge pull request #438 from Pax1601/432-display-in-game-time-and-elapsed-time
432 display in game time and elapsed time
2023-10-06 14:28:40 +02:00
PeekabooSteam
885ef6b357 Time font weight now bold 2023-10-05 17:59:09 +01:00
PeekabooSteam
2435072b07 'Connected' messaged is now a clock/timer 2023-10-05 15:12:07 +01:00
Pax1601
d462bd16b5 Implemented range rings 2023-10-05 13:51:13 +02:00
Pax1601
b08a3835dc Some database changes, started to add threat rings 2023-10-05 11:02:02 +02:00
Pax1601
ace0908d84 Merge pull request #436 from Pax1601/328-add-simple-miss-on-purpose-mode-for-aaa
328 add simple miss on purpose mode for aaa
2023-10-05 10:04:52 +02:00
Pax1601
5186fffb5e Merge commit 2023-10-05 10:04:40 +02:00
Pax1601
c5160c9baa Modified database editor 2023-10-05 10:02:23 +02:00
Pax1601
63acc94558 Merge pull request #434 from Pax1601/433-remove-scale-tool-replace-with-space-efficient-version-of-server-performance-monitor
433 remove scale tool replace with space efficient version of server performance monitor
2023-10-05 09:11:38 +02:00
PeekabooSteam
fc82407d9a Grammatical update 2023-10-04 20:55:01 +01:00
Pax1601
a0ac9eb285 Merge branch 'main' into 328-add-simple-miss-on-purpose-mode-for-aaa 2023-10-04 21:21:08 +02:00
PeekabooSteam
fc835eaba7 Remove debugger line 2023-10-04 20:11:55 +01:00
PeekabooSteam
f7b3e5bf77 Moved server performance indicators; control tips working again. 2023-10-04 20:07:49 +01:00
Pax1601
e41484186b Merge pull request #431 from Pax1601/422-coalitions-can-see-each-others-bullseye
Bullseyes now coalition-limited
2023-10-04 14:55:02 +02:00
PeekabooSteam
e0bfe6a96c Bullseyes now coalilition limited 2023-10-04 13:14:36 +01:00
Pax1601
228f184548 Merge pull request #430 from Pax1601/423-some-improvements-on-units-list
Improved visuals and truncated unit names
2023-10-04 14:11:44 +02:00
PeekabooSteam
892ce4c453 Improved visuals and truncated unit names 2023-10-03 21:57:51 +01:00
Pax1601
569d45d58a Added "operate as" toggle 2023-10-03 17:31:44 +02:00
Pax1601
ce5f00e075 Added options for miss on purpose and scenic AAA 2023-10-03 15:25:45 +02:00
Pax1601
4da407008e More work on miss on purpose 2023-10-02 21:52:04 +02:00
Pax1601
96e79cc8ae Merge pull request #429 from Pax1601/map-bugfixes
Multiple bugfixes
2023-10-02 17:30:59 +02:00
Pax1601
ee93806e19 Multiple bugfixes 2023-10-02 17:29:54 +02:00
Pax1601
fcb02602a0 Reformatted some files 2023-10-02 10:12:24 +02:00
Pax1601
5d4fdf1e76 Merge pull request #411 from Pax1601/410-update-shortcuts-to-plugin-friendly-format
Converted for plugin use
2023-10-02 09:03:30 +02:00
Pax1601
9af59fb51c Merge pull request #418 from Pax1601/417-unit-list
417 unit list
2023-10-02 09:01:28 +02:00
Pax1601
6493d37b7c Merge pull request #421 from Pax1601/419-server-is-paused
User now alerted when server is paused.
2023-10-02 08:59:48 +02:00
PeekabooSteam
a82c033da0 Timeout much shorter when server is paused to reduce update lag 2023-10-02 07:15:00 +01:00
PeekabooSteam
91484e1c98 Can now toggle unit labels with L 2023-10-01 21:42:23 +01:00
PeekabooSteam
3db5202cdf User now alerted when server is paused. 2023-10-01 20:53:30 +01:00
PeekabooSteam
5a28974027 Added additive hotgroup select 2023-10-01 20:12:36 +01:00
PeekabooSteam
4d694f1f74 Added Escape and no-tab-swap-hotgroups 2023-10-01 20:02:45 +01:00
Pax1601
5035c408e7 Basic scenic and miss on purpose AAA modes 2023-10-01 19:15:56 +02:00
Pax1601
d209f98265 Fixed wrong init of altitude sliders in spawn menu 2023-10-01 15:47:23 +02:00
PeekabooSteam
85b1404321 More sorting, changed keybind to U 2023-10-01 12:00:10 +01:00
PeekabooSteam
72c6e4e94e Using proper add and not being lazy 2023-09-30 22:33:47 +01:00
PeekabooSteam
eb46ed2768 Emitted decs 2023-09-30 22:30:29 +01:00
PeekabooSteam
7f4f01c9e8 Alpha of unit list 2023-09-30 22:19:48 +01:00
Pax1601
691d2746e6 Merge pull request #416 from Pax1601/385-setting-altitude-to-silly-number
Fixed wrong callback call from slider
2023-09-30 19:27:33 +02:00
Pax1601
d41dfc1e0d Fixed wrong callback call from slider 2023-09-30 19:27:16 +02:00
Pax1601
493898bd4a Merge pull request #414 from Pax1601/329-add-basic-automatic-firefight
329 add basic automatic firefight
2023-09-30 19:04:18 +02:00
Pax1601
8ebe427269 Enabled direction randomization 2023-09-30 19:03:59 +02:00
Pax1601
48d4ff97a0 Fixed elevation calculations 2023-09-30 18:53:32 +02:00
PeekabooSteam
83769bf539 Converted for plugin use 2023-09-29 18:09:38 +01:00
Pax1601
0954bf2923 Merge branch 'main' of https://github.com/Pax1601/DCSOlympus 2023-09-29 17:21:58 +02:00
Pax1601
a2f5f82e28 Removed redundant loadout roles 2023-09-29 17:21:53 +02:00
Pax1601
a82af04fca Merge pull request #409 from Pax1601/Pax1601-patch-1
Update ci.yml
2023-09-29 15:35:03 +02:00
Pax1601
a1a876429c Update ci.yml 2023-09-29 15:34:54 +02:00
Pax1601
58830fa53e Update package-lock.json 2023-09-29 15:30:50 +02:00
Pax1601
15c8e32fef Merge pull request #408 from Pax1601/407-create-a-simple-plugin-to-manage-units-database
407 create a simple plugin to manage units database
2023-09-29 15:28:07 +02:00
Pax1601
59c915d8bc Updated lock file for checks 2023-09-29 15:26:06 +02:00
Pax1601
968ff61979 Database editor (almost) completed
Liveries editor still to add, but no one in his right mind would change them manually since we have scripts for that
2023-09-29 15:24:08 +02:00
Pax1601
94901849e6 More work on database editing 2023-09-28 17:33:38 +02:00
Pax1601
ff42126b0e Merge branch '329-add-basic-automatic-firefight' into 407-create-a-simple-plugin-to-manage-units-database 2023-09-28 09:09:02 +02:00
Pax1601
39ddf10ca7 Added code to save edited database to disk 2023-09-27 21:46:05 +02:00
Pax1601
7a24e5d39d More work on database manager 2023-09-27 17:08:15 +02:00
Pax1601
e9100504a0 More work on database manager 2023-09-25 17:35:17 +02:00
Pax1601
099cbfdf75 Added more code to handle loadouts 2023-09-24 20:03:21 +02:00
Pax1601
28afef8847 Merge branch 'main' into 407-create-a-simple-plugin-to-manage-units-database 2023-09-24 10:22:45 +02:00
Pax1601
010b1e1cce Exported definitions and fixed interfaces 2023-09-24 10:21:28 +02:00
Pax1601
274ce76c2b Basic plugin structure 2023-09-22 17:58:37 +02:00
Pax1601
f3155e618b Added target altitude effect to simulated fire fight 2023-09-22 16:05:03 +02:00
Pax1601
18307caab3 Merge branch 'main' into 329-add-basic-automatic-firefight 2023-09-22 15:15:58 +02:00
Pax1601
2e279b8876 Update .gitignore 2023-09-22 15:15:22 +02:00
Pax1601
0da878f50f Merge pull request #396 from Pax1601/391-control-tips-mouseover-option
Tips added for formations
2023-09-22 15:06:33 +02:00
Pax1601
ecfb3644be Merge pull request #403 from Pax1601/388-double-click-select-all-only-on-unselected
Unit doubleclick fixed
2023-09-22 15:05:42 +02:00
Pax1601
c87d18fd8e Merge pull request #406 from Pax1601/394-retrieve-ground-altitude-at-mouse-coordinates-location
394 retrieve ground altitude at mouse coordinates location
2023-09-22 15:03:55 +02:00
Pax1601
5810f9232a Completed ground elevation provider and added to mouse info panel 2023-09-22 15:03:35 +02:00
PeekabooSteam
fb8eb6f357 Unit doubleclick fixed 2023-09-22 08:36:07 +01:00
PeekabooSteam
7eb76ff32d Added hotgroup 2023-09-21 22:54:09 +01:00
PeekabooSteam
c3d3de9984 Conflict 2023-09-21 22:23:47 +01:00
PeekabooSteam
cc2549dbdf Tips added for formations 2023-09-21 22:19:01 +01:00
Pax1601
7efa8eab18 Added api enpoint to retrieve altitude at coordinates 2023-09-21 17:37:13 +02:00
Pax1601
376ae9ec1c Update ci.yml 2023-09-21 15:03:59 +02:00
Pax1601
9882b2999f Update ci.yml 2023-09-21 14:58:54 +02:00
Pax1601
3667a75244 Merge pull request #393 from Pax1601/Pax1601-patch-1
Update ci.yml
2023-09-21 14:53:19 +02:00
Pax1601
4089448b53 Update ci.yml 2023-09-21 14:53:09 +02:00
Pax1601
fec11869a8 Update ci.yml 2023-09-21 13:31:21 +02:00
Pax1601
e7e56d1cdb Removed caching 2023-09-21 13:28:32 +02:00
Pax1601
9db01d6060 Modified deploy 2023-09-21 13:23:39 +02:00
Pax1601
ed38397631 Removed types definitions 2023-09-21 13:17:44 +02:00
Pax1601
b3dddc0570 Added types folder 2023-09-21 13:10:39 +02:00
Pax1601
6fa06de245 Added job needs 2023-09-21 13:06:10 +02:00
Pax1601
834ddde1d0 Merged actions 2023-09-21 13:03:14 +02:00
Pax1601
5d4348f8a7 Create static.yml 2023-09-21 12:54:55 +02:00
Pax1601
36f2917995 Synced lock file 2023-09-21 11:03:03 +02:00
Pax1601
eedbec175d Fixed working directory 2023-09-21 10:58:18 +02:00
Pax1601
344ec86722 Executing workflow in client directory 2023-09-21 10:56:17 +02:00
Pax1601
952d1e5895 Added typescript dependency 2023-09-21 10:51:31 +02:00
Pax1601
a371484f38 Removed wrong workflow steps 2023-09-21 10:48:43 +02:00
Pax1601
1567a6fd27 Workflow test 2023-09-21 10:42:12 +02:00
Pax1601
e0f96b5cca Added package.json 2023-09-21 10:38:51 +02:00
Pax1601
8f6e48642c Added package-lock 2023-09-21 10:34:48 +02:00
Pax1601
0c4c10dc1a Fixed folder typo 2023-09-21 10:27:38 +02:00
Pax1601
de6b78d762 Automatic workflow test 2023-09-21 10:24:15 +02:00
Pax1601
6b77f32548 Merge pull request #392 from Pax1601/391-control-tips-mouseover-option
Can now specify a selector or a mouseover
2023-09-21 10:09:10 +02:00
Pax1601
fd2b7a00e1 Moved gun data into databases jsons, made core read from databases 2023-09-20 18:58:21 +02:00
PeekabooSteam
818886a65e Can now specify a selector or a mouseover 2023-09-20 17:30:58 +01:00
Pax1601
0ca31afc91 Merge branch 'main' into 329-add-basic-automatic-firefight 2023-09-20 17:34:02 +02:00
Pax1601
024a73da63 Merge pull request #384 from Pax1601/poc-plugins-v1
Poc plugins v1
2023-09-20 16:27:29 +02:00
Pax1601
744b0063d8 Merge pull request #390 from Pax1601/308-desired-speed-sliders-dots-not-showing-in-client
Fix issue #308 - remove color-mix and set precomputed css variable value
2023-09-20 16:26:29 +02:00
amouillard
355923f680 Fix issue #308 - remove color-mix and set precomputed css variable value 2023-09-20 16:19:24 +02:00
Pax1601
44332a2004 Moved server code to dedicated ServerManager class 2023-09-18 17:10:14 +02:00
Pax1601
2f125e3d0e Completed plugins framework
More work required to define all interfaces for the useful classes in the @types folder
2023-09-15 23:07:15 +02:00
Pax1601
588228c050 Implemented basic Plugin handling 2023-09-15 17:05:26 +02:00
Pax1601
8977ba9b6d Added basic simulated firefight state 2023-09-15 09:36:27 +02:00
PeekabooSteam
ad06117b78 Refined a bit more. 2023-09-14 21:10:52 +01:00
PeekabooSteam
01b30ccf12 Refined the options a bit. 2023-09-14 20:56:34 +01:00
PeekabooSteam
7f75905d5d Resolved conflicts 2023-09-14 18:59:20 +01:00
PeekabooSteam
798856c649 Nearly final commit of control tips' v1 2023-09-14 17:55:01 +01:00
Pax1601
9acd358080 Merge pull request #383 from Pax1601/374-right-click-drag-error
Fix issue #374
2023-09-13 19:15:27 +02:00
amouillard
31c112157a Fix issue #374 2023-09-13 18:47:24 +02:00
PeekabooSteam
d2e162edbf Removed directory creation. 2023-09-12 19:07:36 +01:00
PeekabooSteam
6aaffe20d9 Plugin (not) work. 2023-09-12 19:04:52 +01:00
Pax1601
6d32b20117 More documentation 2023-09-12 17:54:59 +02:00
Pax1601
bd894704b1 v0.4.4 2023-09-10 17:26:33 +02:00
Pax1601
7af2162b50 Merge pull request #379 from Pax1601/368-spawn-points-can-integer-overflow-on-the-server-side
Switched from unsigned int to int for spawn points
2023-09-09 19:15:34 +02:00
Pax1601
c735d108d4 Merge pull request #378 from Pax1601/refactor
Refactor
2023-09-09 19:08:31 +02:00
Pax1601
6a2ffc936e More bugfixing, set CAS and ASL to be default modes 2023-09-09 19:07:09 +02:00
Pax1601
74d5480587 Minor refactor and bug fixing 2023-09-08 22:41:37 +02:00
Pax1601
89c39c7038 Code documentation and refactoring 2023-09-08 17:40:53 +02:00
Pax1601
61f955cfeb Added copy ability in RTS mode 2023-09-08 16:25:12 +02:00
Pax1601
744adee94c Merge branch 'main' into 345-allow-for-copy-and-paste-in-rts-mode 2023-09-07 16:56:55 +02:00
Pax1601
267c0b037d Merge branch 'main' into 345-allow-for-copy-and-paste-in-rts-mode 2023-09-07 13:03:50 +02:00
Pax1601
860414b7b2 Merge pull request #377 from Pax1601/370-write-better-method-of-determining-if-a-command-has-been-completed
370 write better method of determining if a command has been completed
2023-09-07 13:03:05 +02:00
Pax1601
09bf361d44 Added ability to delete original cloned units
Mostly useful to group units together
2023-09-07 13:02:14 +02:00
Pax1601
e2f80c5788 Fixed table deepcopy 2023-09-06 20:19:47 +02:00
Pax1601
a96a6eb57d Added command hash control 2023-09-05 17:25:32 +02:00
PeekabooSteam
803f9a7fd6 Started working on shurtcuts plugin 2023-09-05 09:43:36 +01:00
Pax1601
71a141e0b8 Merge pull request #373 from Pax1601/372-pan-up-doesnt-work-via-keyboard
Pan up now pans
2023-09-05 09:42:55 +02:00
PeekabooSteam
a99b85e646 More plugin design 2023-09-04 23:56:48 +01:00
PeekabooSteam
333169d18c Pan up now pans 2023-09-04 22:57:32 +01:00
PeekabooSteam
a08eb418a6 Stash commit to open a new branch. 2023-09-04 22:54:01 +01:00
Pax1601
cbb878cf96 Fixed errors in lua clone units 2023-09-04 21:44:22 +02:00
Pax1601
d684f91a5a Merge branch '370-write-better-method-of-determining-if-a-command-has-been-completed' into 345-allow-for-copy-and-paste-in-rts-mode 2023-09-04 19:02:10 +02:00
Pax1601
f2de4cd34c Completed implementation 2023-09-04 19:01:50 +02:00
Pax1601
3d076a605b Merge branch '370-write-better-method-of-determining-if-a-command-has-been-completed' into 345-allow-for-copy-and-paste-in-rts-mode 2023-09-04 17:31:58 +02:00
Pax1601
3607f88e18 Converted clone function to pure lua 2023-09-04 17:27:09 +02:00
Pax1601
a0d2bb11ed Switched from unsigned int to int for spawn points 2023-09-04 16:06:41 +02:00
Pax1601
ede245a37d Implemented executed commands provider 2023-09-04 12:41:54 +02:00
Pax1601
aca1e112d2 Merge pull request #371 from Pax1601/369-coalition-colour-incorrectly-set-on-spawn-menu-in-rts-mode
Minor bugfix
2023-09-04 11:00:46 +02:00
Pax1601
bf5d6dac18 Minor bugfix 2023-09-04 11:00:28 +02:00
Pax1601
182ce4da42 Hotfix 2023-09-03 17:55:58 +02:00
Pax1601
41e2e6fa59 Updated documentation 2023-09-03 16:45:48 +02:00
Pax1601
fe0e964a5a Merge pull request #367 from Pax1601/343-add-ability-to-select-unit-nation-and-livery
v0.4.4
2023-09-03 16:34:34 +02:00
Pax1601
bee35f9ee9 v0.4.4 2023-09-03 16:34:11 +02:00
Pax1601
e66a1bb5b4 Merge pull request #366 from Pax1601/343-add-ability-to-select-unit-nation-and-livery
343 add ability to select unit nation and livery
2023-09-03 16:32:06 +02:00
Pax1601
8490997604 Merge branch 'main' into 343-add-ability-to-select-unit-nation-and-livery 2023-09-03 15:18:35 +02:00
Pax1601
6898d1df6d Completed unit nation selection and new spawn menu 2023-09-03 15:15:11 +02:00
PeekabooSteam
4d863bb894 First commit 2023-09-03 12:08:35 +01:00
Pax1601
a338e5fa26 Added docs folder 2023-09-01 16:44:47 +02:00
Pax1601
695adc8acb More work on units spawn menu and started to add documentation 2023-09-01 16:13:15 +02:00
Pax1601
fab7d26191 More work on scripted spawn menu 2023-08-31 17:25:47 +02:00
Pax1601
3959139dd8 Started conversion to scripted unit spawn menu 2023-08-30 20:01:25 +02:00
Pax1601
1298669f1c Merge pull request #365 from Pax1601/358-right-click-long-press-for-unit-action-context-menu
358 right click long press for unit action context menu
2023-08-30 09:13:13 +02:00
Pax1601
4fe40f5ff7 Merge branch 'main' into 358-right-click-long-press-for-unit-action-context-menu 2023-08-30 09:13:06 +02:00
Pax1601
a10c113c42 Right click long press menu completed 2023-08-30 09:10:42 +02:00
Pax1601
d5f4b5c711 More work on country selection 2023-08-29 19:17:36 +02:00
Pax1601
93707af56b Merge pull request #363 from Pax1601/350-in-rts-mode-helicopters-are-shown-with-a-distinctive-shape-that-allows-to-identify-them
Non visually detected units are now drawn with generic symbol
2023-08-29 14:59:42 +02:00
Pax1601
0ae694c1a8 Non visually detected units are now drawn with generic symbol 2023-08-29 14:59:23 +02:00
Pax1601
0b53fb19b7 Merge pull request #362 from Pax1601/356-add-marker-for-deployed-smoke
Create colored smoke markers
2023-08-29 10:02:50 +02:00
Pax1601
cc386e86b9 Create colored smoke markers 2023-08-29 10:02:18 +02:00
Pax1601
a922d7de31 Merge pull request #361 from Pax1601/349-add-ability-to-hide-units-names
349 add ability to hide units names
2023-08-29 09:39:27 +02:00
Pax1601
8e7d64f0e4 Remove shortcut and added option in dropdown 2023-08-29 09:39:07 +02:00
Pax1601
0bc406538b Merge pull request #360 from Pax1601/351-double-click-on-a-unit-should-select-all-units-of-that-time-on-the-screen
351 double click on a unit should select all units of that time on the screen
2023-08-28 17:14:23 +02:00
Pax1601
9547559e00 Refactoring and merge 2023-08-28 17:14:03 +02:00
Pax1601
70783dc828 Merge branch 'main' into 351-double-click-on-a-unit-should-select-all-units-of-that-time-on-the-screen 2023-08-28 17:05:34 +02:00
Pax1601
85bdd791b8 Implemented long press right click menu 2023-08-28 15:48:46 +02:00
Pax1601
9d7e61556d Added unit country selection 2023-08-27 15:59:50 +02:00
Pax1601
eb80c39b98 Loadouts changes and spawn menu update 2023-08-24 16:16:59 +02:00
PeekabooSteam
07b69fe96f Added dbl-click select but it's buggy AF 2023-08-12 19:31:08 +01:00
PeekabooSteam
e0a3fd1795 Corrected some variable names. 2023-08-12 16:46:37 +01:00
327 changed files with 122596 additions and 19569 deletions

33
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
# ci.yml file for GitHub Actions
name: CI
on: [push]
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: write
pages: write
id-token: write
jobs:
build_docs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
- name: Install dependencies
run: npm ci
working-directory: ./client
- name: Create the docs directory locally in CI
run: npx typedoc --out ../docs/client @types/*.d.ts src/**/*.ts
working-directory: ./client
- name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@v4
with:
folder: docs

5
.gitignore vendored
View File

@@ -10,3 +10,8 @@ node_modules
/client/TODO.txt /client/TODO.txt
/client/public/javascripts/bundle.js /client/public/javascripts/bundle.js
!client/bin !client/bin
/client/public/plugins
/client/plugins/controltips/index.js
hgt
/client/public/databases/units/old
/client/plugins/databasemanager/index.js

View File

@@ -1,4 +1,33 @@
GNU GENERAL PUBLIC LICENSE DCS Olympus
A real-time AI unit control mod for DCS World
Copyright (C) 2023 Veltro & Gang
DCS Olympus (the "MATERIAL" or "Software") is provided completely free
to users subject to the it under both the terms of version 3 of the GNU
General Public License as published by the Free Software Foundation, and
the additional terms set out below; 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 o
ther 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, version 3 of the GNU
General Public Licence, and the Additional Terms below.
THIS MATERIAL IS NOT MADE OR SUPPORTED BY EAGLE DYNAMICS SA.
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007 Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
@@ -618,57 +647,14 @@ an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee. copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS END OF GNU GENERAL PUBLIC LICENCE
How to Apply These Terms to Your New Programs ADDITIONAL TERMS & CONDITIONS
If you develop a new program, and you want it to be of the greatest 1. Governing Law
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest Save where specifically provided for otherwise, the provisions of the
to attach them to the start of each source file to most effectively GNU General Public Licence Version 3 above shall be governed by and
state the exclusion of warranty; and each file should have at least interpreted in accordance with English Law and the parties submit to the
the "copyright" line and a pointer to where the full notice is found. exclusive jurisdiction of the English Courts.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

17
build_package.bat Normal file
View File

@@ -0,0 +1,17 @@
cd src
msbuild olympus.sln /t:Rebuild /p:Configuration=Release
cd ..
cd client
call npm install
rmdir /s /q "hgt"
call npm run emit-declarations
call npm run build
cd "plugins\controltips"
call npm run build
cd "..\.."
cd "plugins\databasemanager"
call npm run build
cd "..\.."
call npm prune --production
cd ..
call "C:\Program Files (x86)\Inno Setup 6\iscc.exe" "installer\olympus.iss"

View File

@@ -4,17 +4,6 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{
"name": "Attach to Chrome",
"port": 9222,
"urlFilter": "http://localhost:3000/*",
"request": "attach",
"type": "chrome",
"webRoot": "${workspaceFolder}/public/",
"sourceMapPathOverrides": {
"src/*": "${workspaceFolder}/src/*"
}
},
{ {
"type": "chrome", "type": "chrome",
"request": "launch", "request": "launch",
@@ -24,7 +13,8 @@
"sourceMapPathOverrides": { "sourceMapPathOverrides": {
"src/*": "${workspaceFolder}/src/*" "src/*": "${workspaceFolder}/src/*"
}, },
"preLaunchTask": "server" "preLaunchTask": "server",
"port": 9222
} }
] ]
} }

View File

@@ -6,7 +6,7 @@
{ {
"label": "server", "label": "server",
"type": "shell", "type": "shell",
"command": "npm run start", "command": "npm run debug",
"isBackground": true "isBackground": true
} }
] ]

2366
client/@types/olympus/index.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -3,25 +3,32 @@ var path = require('path');
var cookieParser = require('cookie-parser'); var cookieParser = require('cookie-parser');
var logger = require('morgan'); var logger = require('morgan');
var fs = require('fs'); var fs = require('fs');
var bodyParser = require('body-parser');
var atcRouter = require('./routes/api/atc'); var atcRouter = require('./routes/api/atc');
var airbasesRouter = require('./routes/api/airbases'); var airbasesRouter = require('./routes/api/airbases');
var elevationRouter = require('./routes/api/elevation');
var databasesRouter = require('./routes/api/databases');
var indexRouter = require('./routes/index'); var indexRouter = require('./routes/index');
var uikitRouter = require('./routes/uikit'); var uikitRouter = require('./routes/uikit');
var usersRouter = require('./routes/users'); var usersRouter = require('./routes/users');
var resourcesRouter = require('./routes/resources'); var resourcesRouter = require('./routes/resources');
var pluginsRouter = require('./routes/plugins');
var app = express(); var app = express();
app.use(logger('dev')); app.use(logger('dev'));
app.use(express.json()); app.use(bodyParser.json({limit: '50mb'}));
app.use(express.urlencoded({ extended: false })); app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));
app.use(cookieParser()); app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public'))); app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter); app.use('/', indexRouter);
app.use('/api/atc', atcRouter); app.use('/api/atc', atcRouter);
app.use('/api/airbases', airbasesRouter); app.use('/api/airbases', airbasesRouter);
app.use('/api/elevation', elevationRouter);
app.use('/api/databases', databasesRouter);
app.use('/plugins', pluginsRouter)
app.use('/users', usersRouter); app.use('/users', usersRouter);
app.use('/uikit', uikitRouter); app.use('/uikit', uikitRouter);
app.use('/resources', resourcesRouter); app.use('/resources', resourcesRouter);

View File

@@ -1,5 +1,9 @@
#!/usr/bin/env node #!/usr/bin/env node
var fs = require('fs');
let rawdata = fs.readFileSync('../olympus.json');
let config = JSON.parse(rawdata);
/** /**
* Module dependencies. * Module dependencies.
*/ */
@@ -12,8 +16,14 @@ var http = require('http');
* Get port from environment and store in Express. * Get port from environment and store in Express.
*/ */
var port = normalizePort(process.env.PORT || '3000'); var configPort = null;
if (config["client"] != undefined && config["client"]["port"] != undefined) {
configPort = config["client"]["port"];
}
var port = normalizePort(configPort || '3000');
app.set('port', port); app.set('port', port);
console.log("Express server listening on port: " + port)
/** /**
* Create HTTP server. * Create HTTP server.

View File

@@ -1,3 +1,4 @@
copy .\\node_modules\\leaflet\\dist\\leaflet.css .\\public\\stylesheets\\leaflet\\leaflet.css copy .\\node_modules\\leaflet\\dist\\leaflet.css .\\public\\stylesheets\\leaflet\\leaflet.css
copy .\\node_modules\\leaflet-gesture-handling\\dist\\leaflet-gesture-handling.css .\\public\\stylesheets\\leaflet\\leaflet-gesture-handling.css
copy .\\node_modules\\leaflet.nauticscale\\dist\\leaflet.nauticscale.js .\\public\\javascripts\\leaflet.nauticscale.js copy .\\node_modules\\leaflet.nauticscale\\dist\\leaflet.nauticscale.js .\\public\\javascripts\\leaflet.nauticscale.js
copy .\\node_modules\\leaflet-path-drag\\dist\\L.Path.Drag.js .\\public\\javascripts\\L.Path.Drag.js copy .\\node_modules\\leaflet-path-drag\\dist\\L.Path.Drag.js .\\public\\javascripts\\L.Path.Drag.js

View File

@@ -1,106 +1,16 @@
const { random } = require('@turf/turf');
var basicAuth = require('express-basic-auth') var basicAuth = require('express-basic-auth')
var enc = new TextEncoder(); var enc = new TextEncoder();
const DEMO_UNIT_DATA = { const aircraftDatabase = require('./public/databases/units/aircraftDatabase.json');
["1"]:{ category: "Aircraft", alive: true, human: false, controlled: true, coalition: 2, country: 0, name: "KC-135", unitName: "Cool guy 1-1 who also has a very long name", groupName: "Cool group 1", state: 3, task: "Being cool!", const helicopterDatabase = require('./public/databases/units/helicopterDatabase.json');
hasTask: true, position: { lat: 37, lng: -116, alt: 1000 }, speed: 200, heading: 45, isTanker: true, isAWACS: false, onOff: true, followRoads: false, fuel: 50, const groundUnitDatabase = require('./public/databases/units/groundUnitDatabase.json');
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0, const navyUnitDatabase = require('./public/databases/units/navyUnitDatabase.json');
formationOffset: { x: 0, y: 0, z: 0 },
targetID: 2, const DEMO_UNIT_DATA = {}
targetPosition: { lat: 0, lng: 0, alt: 0 },
ROE: 1,
reactionToThreat: 1,
emissionsCountermeasures: 1,
TACAN: { isOn: false, XY: 'Y', callsign: 'TKR', channel: 40 },
radio: { frequency: 124000000, callsign: 1, callsignNumber: 1 },
generalSettings: { prohibitAA: false, prohibitAfterburner: false, prohibitAG: false, prohibitAirWpn: false, prohibitJettison: false },
ammo: [{ quantity: 2, name: "A cool missile\0Ciao", guidance: 0, category: 0, missileCategory: 0 } ],
contacts: [{ID: 2, detectionMethod: 1}, {ID: 3, detectionMethod: 4}],
activePath: [{lat: 38, lng: -115, alt: 0}, {lat: 38, lng: -114, alt: 0}]
},
["2"]:{ category: "Aircraft", alive: true, human: false, controlled: false, coalition: 1, country: 0, name: "FA-18C_hornet", unitName: "Cool guy 1-2", groupName: "Cool group 2", state: 1, task: "Being cool",
hasTask: false, position: { lat: 36.9, lng: -116, alt: 1000 }, speed: 200, heading: 315 * Math.PI / 180, isTanker: false, isAWACS: false, onOff: true, followRoads: false, fuel: 50,
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
formationOffset: { x: 0, y: 0, z: 0 },
targetID: 0,
targetPosition: { lat: 0, lng: 0, alt: 0 },
ROE: 1,
reactionToThreat: 1,
emissionsCountermeasures: 1,
TACAN: { isOn: false, XY: 'Y', callsign: 'TKR', channel: 40 },
radio: { frequency: 124000000, callsign: 1, callsignNumber: 1 },
generalSettings: { prohibitAA: false, prohibitAfterburner: false, prohibitAG: false, prohibitAirWpn: false, prohibitJettison: false },
ammo: [{ quantity: 2, name: "A cool missile", guidance: 0, category: 0, missileCategory: 0 } ],
contacts: [{ID: 1, detectionMethod: 16}],
activePath: [ ]
}, ["3"]:{ category: "Helicopter", alive: true, human: false, controlled: false, coalition: 1, country: 0, name: "AH-64D_BLK_II", unitName: "Cool guy 1-4", groupName: "Cool group 3", state: 1, task: "Being cool",
hasTask: false, position: { lat: 37.1, lng: -116.1, alt: 1000 }, speed: 200, heading: 315 * Math.PI / 180, isTanker: false, isAWACS: false, onOff: true, followRoads: false, fuel: 50,
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
formationOffset: { x: 0, y: 0, z: 0 },
targetID: 0,
targetPosition: { lat: 0, lng: 0, alt: 0 },
ROE: 1,
reactionToThreat: 1,
emissionsCountermeasures: 1,
TACAN: { isOn: false, XY: 'Y', callsign: 'TKR', channel: 40 },
radio: { frequency: 124000000, callsign: 1, callsignNumber: 1 },
generalSettings: { prohibitAA: false, prohibitAfterburner: false, prohibitAG: false, prohibitAirWpn: false, prohibitJettison: false },
ammo: [{ quantity: 2, name: "A cool missile", guidance: 0, category: 0, missileCategory: 0 } ],
contacts: [{ID: 1, detectionMethod: 16}],
activePath: [ ]
}, ["4"]:{ category: "GroundUnit", alive: true, human: false, controlled: true, coalition: 1, country: 0, name: "Gepard", unitName: "Cool guy 2-1", groupName: "Cool group 4", state: 1, task: "Being cool",
hasTask: false, position: { lat: 37.2, lng: -116.1, alt: 1000 }, speed: 200, heading: 315 * Math.PI / 180, isTanker: false, isAWACS: false, onOff: true, followRoads: false, fuel: 50,
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
formationOffset: { x: 0, y: 0, z: 0 },
targetID: 0,
targetPosition: { lat: 0, lng: 0, alt: 0 },
ROE: 1,
reactionToThreat: 1,
emissionsCountermeasures: 1,
TACAN: { isOn: false, XY: 'Y', callsign: 'TKR', channel: 40 },
radio: { frequency: 124000000, callsign: 1, callsignNumber: 1 },
generalSettings: { prohibitAA: false, prohibitAfterburner: false, prohibitAG: false, prohibitAirWpn: false, prohibitJettison: false },
ammo: [{ quantity: 2, name: "A cool missile\0Ciao", guidance: 0, category: 0, missileCategory: 0 } ],
contacts: [{ID: 1001, detectionMethod: 16}],
activePath: [ ],
isLeader: true
}, ["5"]:{ category: "GroundUnit", alive: true, human: false, controlled: true, coalition: 1, country: 0, name: "S_75M_Volhov", unitName: "Cool guy 2-2", groupName: "Cool group 4", state: 1, task: "Being cool",
hasTask: false, position: { lat: 37.21, lng: -116.1, alt: 1000 }, speed: 200, heading: 315 * Math.PI / 180, isTanker: false, isAWACS: false, onOff: true, followRoads: false, fuel: 50,
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
formationOffset: { x: 0, y: 0, z: 0 },
targetID: 0,
targetPosition: { lat: 0, lng: 0, alt: 0 },
ROE: 1,
reactionToThreat: 1,
emissionsCountermeasures: 1,
TACAN: { isOn: false, XY: 'Y', callsign: 'TKR', channel: 40 },
radio: { frequency: 124000000, callsign: 1, callsignNumber: 1 },
generalSettings: { prohibitAA: false, prohibitAfterburner: false, prohibitAG: false, prohibitAirWpn: false, prohibitJettison: false },
ammo: [{ quantity: 2, name: "A cool missile", guidance: 0, category: 0, missileCategory: 0 } ],
contacts: [],
activePath: [ ],
isLeader: false
},
["6"]:{ category: "Aircraft", alive: true, human: false, controlled: false, coalition: 1, country: 0, name: "FA-18C_hornet", unitName: "Bad boi 1-2", groupName: "Bad group 1", state: 1, task: "Being bad",
hasTask: false, position: { lat: 36.8, lng: -116, alt: 1000 }, speed: 200, heading: 315 * Math.PI / 180, isTanker: false, isAWACS: false, onOff: true, followRoads: false, fuel: 50,
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
formationOffset: { x: 0, y: 0, z: 0 },
targetID: 0,
targetPosition: { lat: 0, lng: 0, alt: 0 },
ROE: 1,
reactionToThreat: 1,
emissionsCountermeasures: 1,
TACAN: { isOn: false, XY: 'Y', callsign: 'TKR', channel: 40 },
radio: { frequency: 124000000, callsign: 1, callsignNumber: 1 },
generalSettings: { prohibitAA: false, prohibitAfterburner: false, prohibitAG: false, prohibitAirWpn: false, prohibitJettison: false },
ammo: [{ quantity: 2, name: "A cool missile", guidance: 0, category: 0, missileCategory: 0 } ],
contacts: [{ID: 1, detectionMethod: 16}],
activePath: [ ]
},
}
const DEMO_WEAPONS_DATA = { const DEMO_WEAPONS_DATA = {
["1001"]:{ category: "Missile", alive: true, coalition: 2, name: "", position: { lat: 37.1, lng: -116, alt: 1000 }, speed: 200, heading: 45 * Math.PI / 180 }, /*["1001"]:{ category: "Missile", alive: true, coalition: 2, name: "", position: { lat: 37.1, lng: -116, alt: 1000 }, speed: 200, heading: 45 * Math.PI / 180 }, */
} }
class DemoDataGenerator { class DemoDataGenerator {
@@ -112,6 +22,8 @@ class DemoDataGenerator {
app.get('/demo/bullseyes', (req, res) => this.bullseyes(req, res)); app.get('/demo/bullseyes', (req, res) => this.bullseyes(req, res));
app.get('/demo/airbases', (req, res) => this.airbases(req, res)); app.get('/demo/airbases', (req, res) => this.airbases(req, res));
app.get('/demo/mission', (req, res) => this.mission(req, res)); app.get('/demo/mission', (req, res) => this.mission(req, res));
app.get('/demo/commands', (req, res) => this.command(req, res));
app.put('/demo', (req, res) => this.put(req, res));
app.use('/demo', basicAuth({ app.use('/demo', basicAuth({
users: { users: {
@@ -121,6 +33,121 @@ class DemoDataGenerator {
}, },
})) }))
let baseData = { alive: true, human: false, controlled: true, coalition: 2, country: 0, unitName: "Cool guy", groupName: "Cool group 1", state: 1, task: "Being cool!",
hasTask: true, position: { lat: 37, lng: -116, alt: 1000 }, speed: 200, horizontalVelocity: 200, verticalVelicity: 0, heading: 45, isActiveTanker: false, isActiveAWACS: false, onOff: true, followRoads: false, fuel: 50,
desiredSpeed: 300, desiredSpeedType: 1, desiredAltitude: 1000, desiredAltitudeType: 1, leaderID: 0,
formationOffset: { x: 0, y: 0, z: 0 },
targetID: 0,
targetPosition: { lat: 0, lng: 0, alt: 0 },
ROE: 1,
reactionToThreat: 1,
emissionsCountermeasures: 1,
TACAN: { isOn: false, XY: 'Y', callsign: 'TKR', channel: 40 },
radio: { frequency: 124000000, callsign: 1, callsignNumber: 1 },
generalSettings: { prohibitAA: false, prohibitAfterburner: false, prohibitAG: false, prohibitAirWpn: false, prohibitJettison: false },
ammo: [],
contacts: [],
activePath: [],
isLeader: true
}
/*
***************** UNCOMMENT TO TEST ALL UNITS ****************
var databases = Object.assign({}, aircraftDatabase, helicopterDatabase, groundUnitDatabase, navyUnitDatabase);
var t = Object.keys(databases).length;
var l = Math.floor(Math.sqrt(t));
let latIdx = 0;
let lngIdx = 0;
let idx = 1;
console.log(l)
for (let name in databases) {
if (databases[name].enabled) {
DEMO_UNIT_DATA[idx] = JSON.parse(JSON.stringify(baseData));
DEMO_UNIT_DATA[idx].name = name;
DEMO_UNIT_DATA[idx].groupName = `Group-${idx}`;
DEMO_UNIT_DATA[idx].position.lat += latIdx / 5;
DEMO_UNIT_DATA[idx].position.lng += lngIdx / 5;
latIdx += 1;
if (latIdx === l) {
latIdx = 0;
lngIdx += 1;
}
if (name in aircraftDatabase)
DEMO_UNIT_DATA[idx].category = "Aircraft";
else if (name in helicopterDatabase)
DEMO_UNIT_DATA[idx].category = "Helicopter";
else if (name in groundUnitDatabase)
DEMO_UNIT_DATA[idx].category = "GroundUnit";
else if (name in navyUnitDatabase)
DEMO_UNIT_DATA[idx].category = "NavyUnit";
idx += 1;
}
}
*/
let idx = 1;
DEMO_UNIT_DATA[idx] = JSON.parse(JSON.stringify(baseData));
DEMO_UNIT_DATA[idx].name = "S_75M_Volhov";
DEMO_UNIT_DATA[idx].groupName = `Group`;
DEMO_UNIT_DATA[idx].position.lat += idx / 100;
DEMO_UNIT_DATA[idx].category = "GroundUnit";
DEMO_UNIT_DATA[idx].isLeader = true;
idx += 1;
DEMO_UNIT_DATA[idx] = JSON.parse(JSON.stringify(baseData));
DEMO_UNIT_DATA[idx].name = "SNR_75V";
DEMO_UNIT_DATA[idx].groupName = `Group`;
DEMO_UNIT_DATA[idx].position.lat += idx / 100;
DEMO_UNIT_DATA[idx].category = "GroundUnit";
DEMO_UNIT_DATA[idx].isLeader = false;
idx += 1;
DEMO_UNIT_DATA[idx] = JSON.parse(JSON.stringify(baseData));
DEMO_UNIT_DATA[idx].name = "Ural-4320 APA-5D";
DEMO_UNIT_DATA[idx].groupName = `Group`;
DEMO_UNIT_DATA[idx].position.lat += idx / 100;
DEMO_UNIT_DATA[idx].category = "GroundUnit";
DEMO_UNIT_DATA[idx].isLeader = false;
idx += 1;
DEMO_UNIT_DATA[idx] = JSON.parse(JSON.stringify(baseData));
DEMO_UNIT_DATA[idx].name = "F-14B";
DEMO_UNIT_DATA[idx].groupName = `Group-1`;
DEMO_UNIT_DATA[idx].position.lat += idx / 100;
DEMO_UNIT_DATA[idx].category = "Aircraft";
DEMO_UNIT_DATA[idx].isLeader = false;
idx += 1;
DEMO_UNIT_DATA[idx] = JSON.parse(JSON.stringify(baseData));
DEMO_UNIT_DATA[idx].name = "Infantry AK";
DEMO_UNIT_DATA[idx].groupName = `Group-2`;
DEMO_UNIT_DATA[idx].position.lat += idx / 100;
DEMO_UNIT_DATA[idx].category = "GroundUnit";
DEMO_UNIT_DATA[idx].isLeader = true;
idx += 1;
DEMO_UNIT_DATA[idx] = JSON.parse(JSON.stringify(baseData));
DEMO_UNIT_DATA[idx].name = "Infantry AK";
DEMO_UNIT_DATA[idx].groupName = `Group-3`;
DEMO_UNIT_DATA[idx].position.lat += idx / 100;
DEMO_UNIT_DATA[idx].category = "GroundUnit";
DEMO_UNIT_DATA[idx].isLeader = true;
idx += 1;
DEMO_UNIT_DATA[idx] = JSON.parse(JSON.stringify(baseData));
DEMO_UNIT_DATA[idx].name = "KC-135";
DEMO_UNIT_DATA[idx].groupName = `Group-4`;
DEMO_UNIT_DATA[idx].position.lat += idx / 100;
DEMO_UNIT_DATA[idx].category = "Aircraft";
DEMO_UNIT_DATA[idx].isLeader = true;
this.startTime = Date.now(); this.startTime = Date.now();
} }
@@ -128,48 +155,53 @@ class DemoDataGenerator {
var array = new Uint8Array(); var array = new Uint8Array();
var time = Date.now(); var time = Date.now();
array = this.concat(array, this.uint64ToByteArray(BigInt(time))); array = this.concat(array, this.uint64ToByteArray(BigInt(time)));
for (let idx in DEMO_UNIT_DATA) { if (req.query["time"] == 0){
const unit = DEMO_UNIT_DATA[idx]; for (let idx in DEMO_UNIT_DATA) {
array = this.concat(array, this.uint32ToByteArray(idx)); const unit = DEMO_UNIT_DATA[idx];
array = this.appendString(array, unit.category, 1); array = this.concat(array, this.uint32ToByteArray(idx));
array = this.appendUint8(array, unit.alive, 2); array = this.appendString(array, unit.category, 1);
array = this.appendUint8(array, unit.human, 3); array = this.appendUint8(array, unit.alive, 2);
array = this.appendUint8(array, unit.controlled, 4); array = this.appendUint8(array, unit.human, 3);
array = this.appendUint16(array, unit.coalition, 5); array = this.appendUint8(array, unit.controlled, 4);
array = this.appendUint8(array, unit.country, 6); array = this.appendUint16(array, unit.coalition, 5);
array = this.appendString(array, unit.name, 7); array = this.appendUint8(array, unit.country, 6);
array = this.appendString(array, unit.unitName, 8); array = this.appendString(array, unit.name, 7);
array = this.appendString(array, unit.groupName, 9); array = this.appendString(array, unit.unitName, 8);
array = this.appendUint8(array, unit.state, 10); array = this.appendString(array, unit.groupName, 9);
array = this.appendString(array, unit.task, 11); array = this.appendUint8(array, unit.state, 10);
array = this.appendUint8(array, unit.hasTask, 12); array = this.appendString(array, unit.task, 11);
array = this.appendCoordinates(array, unit.position, 13); array = this.appendUint8(array, unit.hasTask, 12);
array = this.appendDouble(array, unit.speed, 14); array = this.appendCoordinates(array, unit.position, 13);
array = this.appendDouble(array, unit.heading, 15); array = this.appendDouble(array, unit.speed, 14);
array = this.appendUint8(array, unit.isTanker, 16); array = this.appendDouble(array, unit.horizontalVelocity, 15);
array = this.appendUint8(array, unit.isAWACS, 17); array = this.appendDouble(array, unit.verticalVelicity, 16);
array = this.appendUint8(array, unit.onOff, 18); array = this.appendDouble(array, unit.heading, 17);
array = this.appendUint8(array, unit.followRoads, 19); array = this.appendUint8(array, unit.isActiveTanker, 18);
array = this.appendUint16(array, unit.fuel, 20); array = this.appendUint8(array, unit.isActiveAWACS, 19);
array = this.appendDouble(array, unit.desiredSpeed, 21); array = this.appendUint8(array, unit.onOff, 20);
array = this.appendUint8(array, unit.desiredSpeedType, 22); array = this.appendUint8(array, unit.followRoads, 21);
array = this.appendDouble(array, unit.desiredAltitude, 23); array = this.appendUint16(array, unit.fuel, 22);
array = this.appendUint8(array, unit.desiredAltitudeType, 24); array = this.appendDouble(array, unit.desiredSpeed, 23);
array = this.appendUint32(array, unit.leaderID, 25); array = this.appendUint8(array, unit.desiredSpeedType, 24);
array = this.appendOffset(array, unit.formationOffset, 26); array = this.appendDouble(array, unit.desiredAltitude, 25);
array = this.appendUint32(array, unit.targetID, 27); array = this.appendUint8(array, unit.desiredAltitudeType, 26);
array = this.appendCoordinates(array, unit.targetPosition, 28); array = this.appendUint32(array, unit.leaderID, 27);
array = this.appendUint8(array, unit.ROE, 29); array = this.appendOffset(array, unit.formationOffset, 28);
array = this.appendUint8(array, unit.reactionToThreat, 30); array = this.appendUint32(array, unit.targetID, 29);
array = this.appendUint8(array, unit.emissionsCountermeasures, 31); array = this.appendCoordinates(array, unit.targetPosition, 30);
array = this.appendTACAN(array, unit.TACAN, 32); array = this.appendUint8(array, unit.ROE, 31);
array = this.appendRadio(array, unit.radio, 33); array = this.appendUint8(array, unit.reactionToThreat, 32);
array = this.appendRadio(array, unit.generalSettings, 34); array = this.appendUint8(array, unit.emissionsCountermeasures, 33);
array = this.appendAmmo(array, unit.ammo, 35); array = this.appendTACAN(array, unit.TACAN, 34);
array = this.appendContacts(array, unit.contacts, 36); array = this.appendRadio(array, unit.radio, 35);
array = this.appendActivePath(array, unit.activePath, 37); array = this.appendRadio(array, unit.generalSettings, 36);
array = this.appendUint8(array, unit.isLeader, 38); array = this.appendAmmo(array, unit.ammo, 37);
array = this.concat(array, this.uint8ToByteArray(255)); array = this.appendContacts(array, unit.contacts, 38);
array = this.appendActivePath(array, unit.activePath, 39);
array = this.appendUint8(array, unit.isLeader, 40);
array = this.appendUint8(array, unit.operateAs, 41);
array = this.concat(array, this.uint8ToByteArray(255));
}
} }
res.end(Buffer.from(array, 'binary')); res.end(Buffer.from(array, 'binary'));
}; };
@@ -409,7 +441,7 @@ class DemoDataGenerator {
ret.time = Date.now(); ret.time = Date.now();
ret.mission.dateAndTime = { ret.mission.dateAndTime = {
time: Date.now(), time: { h: 10, m: 15, s: 34 },
date: "", date: "",
elapsedTime: (Date.now() - this.startTime) / 1000, elapsedTime: (Date.now() - this.startTime) / 1000,
startTime: 0 startTime: 0
@@ -417,21 +449,24 @@ class DemoDataGenerator {
ret.mission.coalitions = { ret.mission.coalitions = {
red: [ red: [
'Russia', 'RUSSIA',
'China' 'CHINA'
], ],
blue: [ blue: [
'United States', 'UK',
'Great Britain' 'USA'
],
neutral: [
'ITALY'
] ]
} }
ret.mission.commandModeOptions = { ret.mission.commandModeOptions = {
restrictSpawns: false, restrictSpawns: true,
restrictToCoalition: true, restrictToCoalition: true,
setupTime: 0, setupTime: 0,
spawnPoints: { spawnPoints: {
red: 1000, red: 400,
blue: 400 blue: 400
}, },
eras: ["WW2", "Early Cold War", "Late Cold War", "Modern"] eras: ["WW2", "Early Cold War", "Late Cold War", "Modern"]
@@ -439,7 +474,7 @@ class DemoDataGenerator {
var auth = req.get("Authorization"); var auth = req.get("Authorization");
if (auth) { if (auth) {
var username = atob(auth.replace("Basic ", "")).split(":")[0]; var username = Buffer.from(auth.replace("Basic ", ""), 'base64').toString('binary').split(":")[0];
switch (username) { switch (username) {
case "admin": case "admin":
ret.mission.commandModeOptions.commandMode = "Game master"; ret.mission.commandModeOptions.commandMode = "Game master";
@@ -455,6 +490,16 @@ class DemoDataGenerator {
res.send(JSON.stringify(ret)); res.send(JSON.stringify(ret));
} }
command(req, res) {
var ret = {commandExecuted: Math.random() > 0.5};
res.send(JSON.stringify(ret));
}
put(req, res) {
var ret = {commandHash: Math.random().toString(36).slice(2, 19)}
res.send(JSON.stringify(ret));
}
} }
module.exports = DemoDataGenerator; module.exports = DemoDataGenerator;

6846
client/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,29 +2,34 @@
"name": "DCSOlympus", "name": "DCSOlympus",
"node-main": "./bin/www", "node-main": "./bin/www",
"main": "http://localhost:3000", "main": "http://localhost:3000",
"version": "v0.4.3-alpha", "version": "v0.4.7-alpha",
"private": true, "private": true,
"scripts": { "scripts": {
"build": "browserify .\\src\\index.ts --debug -o .\\public\\javascripts\\bundle.js -t [ babelify --global true --presets [ @babel/preset-env ] --extensions '.js'] -p [ tsify --noImplicitAny ] && copy.bat",
"emit-declarations": "tsc --project tsconfig.json --declaration --emitDeclarationOnly --outfile ./@types/olympus/index.d.ts",
"copy": "copy.bat", "copy": "copy.bat",
"start": "npm run copy & concurrently --kill-others \"npm run watch\" \"nodemon ./bin/www\"", "start": "node ./bin/www",
"debug": "npm run copy & concurrently --kill-others \"npm run watch\" \"nodemon --ignore ./public/databases/ ./bin/www\"",
"watch": "watchify .\\src\\index.ts --debug -o .\\public\\javascripts\\bundle.js -t [ babelify --global true --presets [ @babel/preset-env ] --extensions '.js'] -p [ tsify --noImplicitAny ]" "watch": "watchify .\\src\\index.ts --debug -o .\\public\\javascripts\\bundle.js -t [ babelify --global true --presets [ @babel/preset-env ] --extensions '.js'] -p [ tsify --noImplicitAny ]"
}, },
"dependencies": { "dependencies": {
"@turf/turf": "^6.5.0",
"body-parser": "^1.20.2",
"cookie-parser": "~1.4.4", "cookie-parser": "~1.4.4",
"debug": "~2.6.9", "debug": "~2.6.9",
"ejs": "^3.1.8", "ejs": "^3.1.8",
"express": "~4.16.1", "express": "~4.16.1",
"express-basic-auth": "^1.2.1",
"leaflet-gesture-handling": "^1.2.2",
"morgan": "~1.9.1", "morgan": "~1.9.1",
"save": "^2.9.0", "save": "^2.9.0",
"express-basic-auth": "^1.2.1" "srtm-elevation": "^2.1.2"
}, },
"devDependencies": { "devDependencies": {
"@babel/preset-env": "^7.21.4", "@babel/preset-env": "^7.21.4",
"@tanem/svg-injector": "^10.1.55", "@tanem/svg-injector": "^10.1.55",
"@turf/turf": "^6.5.0",
"@types/formatcoords": "^1.1.0", "@types/formatcoords": "^1.1.0",
"@types/geojson": "^7946.0.10", "@types/geojson": "^7946.0.10",
"@types/gtag.js": "^0.0.12",
"@types/leaflet": "^1.9.0", "@types/leaflet": "^1.9.0",
"@types/node": "^18.16.1", "@types/node": "^18.16.1",
"@types/sortablejs": "^1.15.0", "@types/sortablejs": "^1.15.0",
@@ -35,14 +40,20 @@
"cp": "^0.2.0", "cp": "^0.2.0",
"esmify": "^2.1.1", "esmify": "^2.1.1",
"formatcoords": "^1.1.3", "formatcoords": "^1.1.3",
"geodesy": "^1.1.2",
"leaflet": "^1.9.3", "leaflet": "^1.9.3",
"leaflet-control-mini-map": "^0.4.0", "leaflet-control-mini-map": "^0.4.0",
"leaflet-path-drag": "*", "leaflet-path-drag": "*",
"leaflet.nauticscale": "^1.1.0", "leaflet.nauticscale": "^1.1.0",
"nodemon": "^2.0.20", "nodemon": "^2.0.20",
"requirejs": "^2.3.6",
"sortablejs": "^1.15.0", "sortablejs": "^1.15.0",
"tsify": "^5.0.4", "tsify": "^5.0.4",
"tslib": "latest",
"typedoc": "^0.24.8",
"typedoc-umlclass": "^0.7.1",
"typescript": "^4.9.4", "typescript": "^4.9.4",
"usng.js": "^0.4.5",
"watchify": "^4.0.0" "watchify": "^4.0.0"
} }
} }

View File

@@ -0,0 +1,5 @@
mkdir .\\..\\..\\public\\plugins\\controltipsplugin
copy .\\index.js .\\..\\..\\public\\plugins\\controltipsplugin\\index.js
copy .\\plugin.json .\\..\\..\\public\\plugins\\controltipsplugin\\plugin.json
copy .\\style.css .\\..\\..\\public\\plugins\\controltipsplugin\\style.css

View File

@@ -0,0 +1,384 @@
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
"use strict";
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _ControlTipsPlugin_instances, _ControlTipsPlugin_element, _ControlTipsPlugin_app, _ControlTipsPlugin_shortcutManager, _ControlTipsPlugin_cursorIsHoveringOverUnit, _ControlTipsPlugin_cursorIsHoveringOverAirbase, _ControlTipsPlugin_mouseoverElement, _ControlTipsPlugin_updateTips;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ControlTipsPlugin = void 0;
const SHOW_CONTROL_TIPS = "Show control tips";
class ControlTipsPlugin {
constructor() {
_ControlTipsPlugin_instances.add(this);
_ControlTipsPlugin_element.set(this, void 0);
_ControlTipsPlugin_app.set(this, void 0);
_ControlTipsPlugin_shortcutManager.set(this, void 0);
_ControlTipsPlugin_cursorIsHoveringOverUnit.set(this, false);
_ControlTipsPlugin_cursorIsHoveringOverAirbase.set(this, false);
_ControlTipsPlugin_mouseoverElement.set(this, void 0);
__classPrivateFieldSet(this, _ControlTipsPlugin_element, document.createElement("div"), "f");
__classPrivateFieldGet(this, _ControlTipsPlugin_element, "f").id = "control-tips-panel";
document.body.appendChild(__classPrivateFieldGet(this, _ControlTipsPlugin_element, "f"));
}
getName() {
return "Control Tips Plugin";
}
initialize(app) {
__classPrivateFieldSet(this, _ControlTipsPlugin_app, app, "f");
__classPrivateFieldSet(this, _ControlTipsPlugin_shortcutManager, __classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getShortcutManager(), "f");
__classPrivateFieldGet(this, _ControlTipsPlugin_shortcutManager, "f").onKeyDown(() => {
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
});
__classPrivateFieldGet(this, _ControlTipsPlugin_shortcutManager, "f").onKeyUp(() => {
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
});
document.addEventListener("airbaseMouseover", (ev) => {
__classPrivateFieldSet(this, _ControlTipsPlugin_cursorIsHoveringOverAirbase, true, "f");
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
});
document.addEventListener("airbaseMouseout", (ev) => {
__classPrivateFieldSet(this, _ControlTipsPlugin_cursorIsHoveringOverAirbase, false, "f");
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
});
document.addEventListener("unitDeselection", (ev) => {
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
});
document.addEventListener("unitMouseover", (ev) => {
__classPrivateFieldSet(this, _ControlTipsPlugin_cursorIsHoveringOverUnit, true, "f");
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
});
document.addEventListener("unitMouseout", (ev) => {
__classPrivateFieldSet(this, _ControlTipsPlugin_cursorIsHoveringOverUnit, false, "f");
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
});
document.addEventListener("unitsSelection", (ev) => {
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
});
document.addEventListener("mapVisibilityOptionsChanged", () => {
this.toggle(!__classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getMap().getVisibilityOptions()[SHOW_CONTROL_TIPS]);
});
document.addEventListener("mouseover", (ev) => {
if (ev.target instanceof HTMLElement) {
__classPrivateFieldSet(this, _ControlTipsPlugin_mouseoverElement, ev.target, "f");
}
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
});
document.addEventListener("mouseup", (ev) => {
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
});
__classPrivateFieldGet(this, _ControlTipsPlugin_instances, "m", _ControlTipsPlugin_updateTips).call(this);
__classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getMap().addVisibilityOption(SHOW_CONTROL_TIPS, true);
return true;
}
getElement() {
return __classPrivateFieldGet(this, _ControlTipsPlugin_element, "f");
}
toggle(bool) {
this.getElement().classList.toggle("hide", bool);
}
}
exports.ControlTipsPlugin = ControlTipsPlugin;
_ControlTipsPlugin_element = new WeakMap(), _ControlTipsPlugin_app = new WeakMap(), _ControlTipsPlugin_shortcutManager = new WeakMap(), _ControlTipsPlugin_cursorIsHoveringOverUnit = new WeakMap(), _ControlTipsPlugin_cursorIsHoveringOverAirbase = new WeakMap(), _ControlTipsPlugin_mouseoverElement = new WeakMap(), _ControlTipsPlugin_instances = new WeakSet(), _ControlTipsPlugin_updateTips = function _ControlTipsPlugin_updateTips() {
const combos = [
{
"keys": [],
"tips": [
{
"key": `SHIFT`,
"action": `Box select`,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false,
"showIfUnitSelected": false
},
{
"key": `Mouse1`,
"action": `Deselect`,
"showIfUnitSelected": true
},
{
"key": `Mouse1+drag`,
"action": `Move map`,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false,
"showIfUnitSelected": false
},
{
"key": `Mouse2`,
"action": `Spawn menu`,
"showIfUnitSelected": false,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false
},
{
"key": `Mouse2`,
"action": `Quick options`,
"showIfUnitSelected": false,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": true
},
{
"key": `Mouse2`,
"action": `Airbase menu`,
"showIfUnitSelected": false,
"showIfHoveringOverAirbase": true,
"showIfHoveringOverUnit": false
},
{
"key": `Mouse2`,
"action": `Set first waypoint`,
"showIfHoveringOverAirbase": false,
"showIfUnitSelected": true,
"unitsMustBeControlled": true
},
{
"key": `Mouse2 (hold)`,
"action": `Interact (ground)`,
"showIfUnitSelected": true,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false,
"unitsMustBeControlled": true
},
{
"key": `Shift`,
"action": "<em> in formation...</em>",
"showIfUnitSelected": true,
"minSelectedUnits": 2
},
{
"key": "CTRL",
"action": "<em> ... more</em>",
"showIfUnitSelected": true,
"showIfHoveringOverAirbase": false,
"unitsMustBeControlled": true
},
{
"key": "CTRL",
"action": " Pin tool",
"showIfUnitSelected": false,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false,
"unitsMustBeControlled": true
},
{
"key": "CTRL+Mouse2",
"action": " Airbase menu",
"showIfUnitSelected": true,
"showIfHoveringOverAirbase": true,
"unitsMustBeControlled": true
},
{
"key": `Mouse1`,
"action": "Toggle Blue/Red",
"mouseoverSelector": "#coalition-switch .ol-switch-fill"
},
{
"key": `Mouse2`,
"action": "Set Neutral",
"mouseoverSelector": "#coalition-switch .ol-switch-fill"
},
{
"key": `Mouse1`,
"action": "Toggle time display",
"mouseoverSelector": "#connection-status-panel[data-is-connected] #connection-status-message abbr"
},
{
"key": `Mouse1 or Z`,
"action": "Change location system",
"mouseoverSelector": "#coordinates-tool, #coordinates-tool *"
},
{
"key": `Comma`,
"action": "Decrease precision",
"mouseoverSelector": `#coordinates-tool[data-location-system="MGRS"], #coordinates-tool[data-location-system="MGRS"] *`
},
{
"key": `Period`,
"action": "Increase precision",
"mouseoverSelector": `#coordinates-tool[data-location-system="MGRS"], #coordinates-tool[data-location-system="MGRS"] *`
}
]
},
{
"keys": ["ControlLeft"],
"tips": [
{
"key": `Mouse1`,
"action": "Toggle pin",
"showIfUnitSelected": false,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false
},
{
"key": `Mouse1`,
"action": "Toggle selection",
"showIfUnitSelected": true,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": true
},
{
"key": `Mouse2`,
"action": `Add waypoint`,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false,
"showIfUnitSelected": true,
"unitsMustBeControlled": true
},
{
"key": `Mouse2`,
"action": `Interact (airbase)`,
"showIfHoveringOverAirbase": true,
"showIfUnitSelected": true,
"unitsMustBeControlled": true
},
{
"key": `Mouse2`,
"action": `Interact (unit)`,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": true,
"showIfUnitSelected": true,
"unitsMustBeControlled": true
},
{
"key": `Shift`,
"action": "<em> in formation...</em>",
"showIfUnitSelected": true,
"minSelectedUnits": 2
},
{
"key": `[Num 1-9]`,
"action": "Set hotgroup",
"showIfUnitSelected": true
}
]
},
{
"keys": ["ShiftLeft"],
"tips": [
{
"key": `Mouse1+drag`,
"action": "Box select",
"showIfUnitSelected": false
},
{
"key": `Mouse2`,
"action": "Set first formation waypoint",
"showIfUnitSelected": true,
"minSelectedUnits": 2
},
{
"key": `[Num 1-9]`,
"action": "Add to hotgroup",
"showIfUnitSelected": true
},
{
"key": "CTRL",
"action": "<em> ... more</em>",
"minSelectedUnits": 2,
"showIfUnitSelected": true,
"showIfHoveringOverAirbase": false,
"unitsMustBeControlled": true
}
]
},
{
"keys": ["ControlLeft", "ShiftLeft"],
"tips": [
{
"key": `Mouse2`,
"action": "Add formation waypoint",
"showIfUnitSelected": true,
"minSelectedUnits": 2,
"unitsMustBeControlled": true
}, {
"key": `[Num 1-9]`,
"action": "Add hotgroup to selection",
"callback": (tip) => {
return (Object.values(__classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getUnitsManager().getUnits()).some((unit) => {
return unit.getHotgroup();
}));
},
"showIfUnitSelected": true,
"minSelectedUnits": 1
}
]
}
];
const currentCombo = combos.find((combo) => __classPrivateFieldGet(this, _ControlTipsPlugin_shortcutManager, "f").keyComboMatches(combo.keys)) || combos[0];
const element = this.getElement();
element.innerHTML = "";
let numSelectedUnits = 0;
let numSelectedControlledUnits = 0;
let unitSelectionContainsControlled = false;
if (__classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getUnitsManager()) {
let selectedUnits = Object.values(__classPrivateFieldGet(this, _ControlTipsPlugin_app, "f").getUnitsManager().getSelectedUnits());
numSelectedUnits = selectedUnits.length;
numSelectedControlledUnits = selectedUnits.filter((unit) => unit.getControlled()).length;
unitSelectionContainsControlled = numSelectedControlledUnits > 0;
}
const tipsIncludesActiveMouseover = (currentCombo.tips.some((tip) => {
if (!tip.mouseoverSelector) {
return false;
}
if (__classPrivateFieldGet(this, _ControlTipsPlugin_mouseoverElement, "f") instanceof HTMLElement === false) {
return false;
}
if (!__classPrivateFieldGet(this, _ControlTipsPlugin_mouseoverElement, "f").matches(tip.mouseoverSelector)) {
return false;
}
return true;
}));
currentCombo.tips.filter((tip) => {
if (numSelectedUnits > 0) {
if (tip.showIfUnitSelected === false) {
return false;
}
if (tip.unitsMustBeControlled === true && unitSelectionContainsControlled === false) {
return false;
}
if (typeof tip.minSelectedUnits === "number" && numSelectedControlledUnits < tip.minSelectedUnits) {
return false;
}
}
if (numSelectedUnits === 0 && tip.showIfUnitSelected === true) {
return false;
}
if (typeof tip.showIfHoveringOverAirbase === "boolean") {
if (tip.showIfHoveringOverAirbase !== __classPrivateFieldGet(this, _ControlTipsPlugin_cursorIsHoveringOverAirbase, "f")) {
return false;
}
}
if (typeof tip.showIfHoveringOverUnit === "boolean") {
if (tip.showIfHoveringOverUnit !== __classPrivateFieldGet(this, _ControlTipsPlugin_cursorIsHoveringOverUnit, "f")) {
return false;
}
}
if (tipsIncludesActiveMouseover && (typeof tip.mouseoverSelector !== "string" || !__classPrivateFieldGet(this, _ControlTipsPlugin_mouseoverElement, "f").matches(tip.mouseoverSelector))) {
return false;
}
if (!tipsIncludesActiveMouseover && typeof tip.mouseoverSelector === "string") {
return false;
}
if (typeof tip.callback === "function" && !tip.callback(tip)) {
return false;
}
element.innerHTML += `<div><span class="key">${tip.key}</span><span class="action">${tip.action}</span></div>`;
});
};
},{}],2:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const controltipsplugin_1 = require("./controltipsplugin");
globalThis.getOlympusPlugin = () => {
return new controltipsplugin_1.ControlTipsPlugin();
};
},{"./controltipsplugin":1}]},{},[2]);

View File

@@ -0,0 +1,162 @@
{
"name": "ControlTipsPlugin",
"version": "v0.0.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"any-promise": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
"integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="
},
"convert-source-map": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
},
"core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
},
"error-ex": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
"requires": {
"is-arrayish": "^0.2.1"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
},
"is-utf8": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
"integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q=="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
},
"parse-json": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
"integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==",
"requires": {
"error-ex": "^1.2.0"
}
},
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"readable-stream": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
},
"strip-bom": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
"integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==",
"requires": {
"is-utf8": "^0.2.0"
}
},
"strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="
},
"through2": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
"integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
"requires": {
"readable-stream": "~2.3.6",
"xtend": "~4.0.1"
}
},
"tsconfig": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-5.0.3.tgz",
"integrity": "sha512-Cq65A3kVp6BbsUgg9DRHafaGmbMb9EhAc7fjWvudNWKjkbWrt43FnrtZt6awshH1R0ocfF2Z0uxock3lVqEgOg==",
"requires": {
"any-promise": "^1.3.0",
"parse-json": "^2.2.0",
"strip-bom": "^2.0.0",
"strip-json-comments": "^2.0.0"
}
},
"tsify": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/tsify/-/tsify-5.0.4.tgz",
"integrity": "sha512-XAZtQ5OMPsJFclkZ9xMZWkSNyMhMxEPsz3D2zu79yoKorH9j/DT4xCloJeXk5+cDhosEibu4bseMVjyPOAyLJA==",
"requires": {
"convert-source-map": "^1.1.0",
"fs.realpath": "^1.0.0",
"object-assign": "^4.1.0",
"semver": "^6.1.0",
"through2": "^2.0.0",
"tsconfig": "^5.0.3"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
}
}
}

View File

@@ -0,0 +1,10 @@
{
"name": "ControlTipsPlugin",
"version": "v0.0.1",
"private": true,
"scripts": {
"build": "browserify ./src/index.ts -p [ tsify --noImplicitAny] > index.js && copy.bat"
},
"dependencies": {},
"devDependencies": {}
}

View File

@@ -0,0 +1,6 @@
{
"name": "Control Tip Plugin",
"version": "0.0.1",
"description": "This plugin shows useful control tips on the right side of the screen. The tips change dynamically depending on what the user does",
"author": "Peekaboo"
}

View File

@@ -0,0 +1,403 @@
import { OlympusPlugin } from "interfaces";
import { OlympusApp } from "olympusapp";
import { Unit } from "unit/unit";
const SHOW_CONTROL_TIPS = "Show control tips"
export class ControlTipsPlugin implements OlympusPlugin {
#element: HTMLElement;
#app: any;
#shortcutManager: any;
#cursorIsHoveringOverUnit: boolean = false;
#cursorIsHoveringOverAirbase: boolean = false;
#mouseoverElement!: HTMLElement;
constructor() {
this.#element = document.createElement("div");
this.#element.id = "control-tips-panel";
document.body.appendChild(this.#element);
}
getName() {
return "Control Tips Plugin"
}
initialize(app: any) {
this.#app = app;
this.#shortcutManager = this.#app.getShortcutManager();
this.#shortcutManager.onKeyDown(() => {
this.#updateTips()
});
this.#shortcutManager.onKeyUp(() => {
this.#updateTips()
});
document.addEventListener("airbaseMouseover", (ev: CustomEventInit) => {
this.#cursorIsHoveringOverAirbase = true;
this.#updateTips();
});
document.addEventListener("airbaseMouseout", (ev: CustomEventInit) => {
this.#cursorIsHoveringOverAirbase = false;
this.#updateTips();
});
document.addEventListener("unitDeselection", (ev: CustomEventInit ) => {
this.#updateTips();
});
document.addEventListener("unitMouseover", (ev: CustomEventInit) => {
this.#cursorIsHoveringOverUnit = true;
this.#updateTips();
});
document.addEventListener("unitMouseout", (ev: CustomEventInit) => {
this.#cursorIsHoveringOverUnit = false;
this.#updateTips();
});
document.addEventListener("unitsSelection", (ev: CustomEventInit ) => {
this.#updateTips();
});
document.addEventListener("mapVisibilityOptionsChanged", () => {
this.toggle( !this.#app.getMap().getVisibilityOptions()[SHOW_CONTROL_TIPS] );
});
document.addEventListener( "mouseover", ( ev: MouseEvent ) => {
if ( ev.target instanceof HTMLElement ) {
this.#mouseoverElement = <HTMLElement>ev.target;
}
this.#updateTips();
});
document.addEventListener( "mouseup", ( ev: MouseEvent ) => {
this.#updateTips();
});
this.#updateTips();
this.#app.getMap().addVisibilityOption(SHOW_CONTROL_TIPS, true);
return true;
}
getElement() {
return this.#element;
}
toggle(bool?: boolean) {
this.getElement().classList.toggle("hide", bool);
}
#updateTips() {
const combos: Array<object> = [
{
"keys": [],
"tips": [
{
"key": `SHIFT`,
"action": `Box select`,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false,
"showIfUnitSelected": false
},
{
"key": `Mouse1`,
"action": `Deselect`,
"showIfUnitSelected": true
},
{
"key": `Mouse1+drag`,
"action": `Move map`,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false,
"showIfUnitSelected": false
},
{
"key": `Mouse2`,
"action": `Spawn menu`,
"showIfUnitSelected": false,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false
},
{
"key": `Mouse2`,
"action": `Quick options`,
"showIfUnitSelected": false,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": true
},
{
"key": `Mouse2`,
"action": `Airbase menu`,
"showIfUnitSelected": false,
"showIfHoveringOverAirbase": true,
"showIfHoveringOverUnit": false
},
{
"key": `Mouse2`,
"action": `Set first waypoint`,
"showIfHoveringOverAirbase": false,
"showIfUnitSelected": true,
"unitsMustBeControlled": true
},
{
"key": `Mouse2 (hold)`,
"action": `Interact (ground)`,
"showIfUnitSelected": true,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false,
"unitsMustBeControlled": true
},
{
"key": `Shift`,
"action": "<em> in formation...</em>",
"showIfUnitSelected": true,
"minSelectedUnits": 2
},
{
"key": "CTRL",
"action": "<em> ... more</em>",
"showIfUnitSelected": true,
"showIfHoveringOverAirbase": false,
"unitsMustBeControlled": true
},
{
"key": "CTRL",
"action": " Pin tool",
"showIfUnitSelected": false,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false,
"unitsMustBeControlled": true
},
{
"key": "CTRL+Mouse2",
"action": " Airbase menu",
"showIfUnitSelected": true,
"showIfHoveringOverAirbase": true,
"unitsMustBeControlled": true
},
{
"key": `Mouse1`,
"action": "Toggle Blue/Red",
"mouseoverSelector": "#coalition-switch .ol-switch-fill"
},
{
"key": `Mouse2`,
"action": "Set Neutral",
"mouseoverSelector": "#coalition-switch .ol-switch-fill"
},
{
"key": `Mouse1`,
"action": "Toggle time display",
"mouseoverSelector": "#connection-status-panel[data-is-connected] #connection-status-message abbr"
},
{
"key": `Mouse1 or Z`,
"action": "Change location system",
"mouseoverSelector": "#coordinates-tool, #coordinates-tool *"
},
{
"key": `Comma`,
"action": "Decrease precision",
"mouseoverSelector": `#coordinates-tool[data-location-system="MGRS"], #coordinates-tool[data-location-system="MGRS"] *`
},
{
"key": `Period`,
"action": "Increase precision",
"mouseoverSelector": `#coordinates-tool[data-location-system="MGRS"], #coordinates-tool[data-location-system="MGRS"] *`
}
]
},
{
"keys": ["ControlLeft"],
"tips": [
{
"key": `Mouse1`,
"action": "Toggle pin",
"showIfUnitSelected": false,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false
},
{
"key": `Mouse1`,
"action": "Toggle selection",
"showIfUnitSelected": true,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": true
},
{
"key": `Mouse2`,
"action": `Add waypoint`,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": false,
"showIfUnitSelected": true,
"unitsMustBeControlled": true
},
{
"key": `Mouse2`,
"action": `Interact (airbase)`,
"showIfHoveringOverAirbase": true,
"showIfUnitSelected": true,
"unitsMustBeControlled": true
},
{
"key": `Mouse2`,
"action": `Interact (unit)`,
"showIfHoveringOverAirbase": false,
"showIfHoveringOverUnit": true,
"showIfUnitSelected": true,
"unitsMustBeControlled": true
},
{
"key": `Shift`,
"action": "<em> in formation...</em>",
"showIfUnitSelected": true,
"minSelectedUnits": 2
},
{
"key": `[Num 1-9]`,
"action": "Set hotgroup",
"showIfUnitSelected": true
}
]
},
{
"keys": ["ShiftLeft"],
"tips": [
{
"key": `Mouse1+drag`,
"action": "Box select",
"showIfUnitSelected": false
},
{
"key": `Mouse2`,
"action": "Set first formation waypoint",
"showIfUnitSelected": true,
"minSelectedUnits": 2
},
{
"key": `[Num 1-9]`,
"action": "Add to hotgroup",
"showIfUnitSelected": true
},
{
"key": "CTRL",
"action": "<em> ... more</em>",
"minSelectedUnits": 2,
"showIfUnitSelected": true,
"showIfHoveringOverAirbase": false,
"unitsMustBeControlled": true
}
]
},
{
"keys": ["ControlLeft", "ShiftLeft"],
"tips": [
{
"key": `Mouse2`,
"action": "Add formation waypoint",
"showIfUnitSelected": true,
"minSelectedUnits": 2,
"unitsMustBeControlled": true
}, {
"key": `[Num 1-9]`,
"action": "Add hotgroup to selection",
"callback": ( tip:object ) => {
return (Object.values<Unit>( this.#app.getUnitsManager().getUnits() ).some( ( unit:Unit ) => {
return unit.getAlive() && unit.getControlled() && unit.getHotgroup();
}));
},
"showIfUnitSelected": true,
"minSelectedUnits": 1
}
]
}
];
const currentCombo: any = combos.find((combo: any) => this.#shortcutManager.keyComboMatches(combo.keys)) || combos[0];
const element = this.getElement();
element.innerHTML = "";
let numSelectedUnits = 0;
let numSelectedControlledUnits = 0;
let unitSelectionContainsControlled = false;
if (this.#app.getUnitsManager()) {
let selectedUnits = Object.values(this.#app.getUnitsManager().getSelectedUnits());
numSelectedUnits = selectedUnits.length;
numSelectedControlledUnits = selectedUnits.filter((unit: any) => unit.getControlled()).length;
unitSelectionContainsControlled = numSelectedControlledUnits > 0;
}
const tipsIncludesActiveMouseover = ( currentCombo.tips.some( ( tip:any ) => {
if ( !tip.mouseoverSelector ) {
return false;
}
if ( this.#mouseoverElement instanceof HTMLElement === false ) {
return false;
}
if ( !this.#mouseoverElement.matches( tip.mouseoverSelector ) ) {
return false;
}
return true;
}));
currentCombo.tips.filter((tip: any) => {
if (numSelectedUnits > 0) {
if (tip.showIfUnitSelected === false) {
return false;
}
if (tip.unitsMustBeControlled === true && unitSelectionContainsControlled === false) {
return false;
}
if ( typeof tip.minSelectedUnits === "number" && numSelectedControlledUnits < tip.minSelectedUnits ) {
return false;
}
}
if (numSelectedUnits === 0 && tip.showIfUnitSelected === true) {
return false;
}
if (typeof tip.showIfHoveringOverAirbase === "boolean") {
if (tip.showIfHoveringOverAirbase !== this.#cursorIsHoveringOverAirbase) {
return false;
}
}
if (typeof tip.showIfHoveringOverUnit === "boolean") {
if (tip.showIfHoveringOverUnit !== this.#cursorIsHoveringOverUnit) {
return false;
}
}
if ( tipsIncludesActiveMouseover && ( typeof tip.mouseoverSelector !== "string" || !this.#mouseoverElement.matches( tip.mouseoverSelector ) ) ) {
return false;
}
if ( !tipsIncludesActiveMouseover && typeof tip.mouseoverSelector === "string" ) {
return false;
}
if ( typeof tip.callback === "function" && !tip.callback( tip ) ) {
return false;
}
element.innerHTML += `<div><span class="key">${tip.key}</span><span class="action">${tip.action}</span></div>`;
});
}
}

View File

@@ -0,0 +1,5 @@
import { ControlTipsPlugin } from "./controltipsplugin";
globalThis.getOlympusPlugin = () => {
return new ControlTipsPlugin();
}

View File

@@ -0,0 +1,33 @@
#control-tips-panel {
align-self: center;
display: flex;
flex-flow: column wrap;
font-size: 13px;
justify-self: flex-end;
position: absolute;
right: 10px;
row-gap: 20px;
text-align: right;
z-index: 999;
}
#control-tips-panel>* {
align-items: center;
align-self: end;
background-color: var(--background-steel);
border-radius: var(--border-radius-md);
color: white;
column-gap: 8px;
display: flex;
justify-items: right;
opacity: .9;
padding: 5px;
width: fit-content;
}
#control-tips-panel>*>.key {
background-color: var(--background-grey);
border-radius: var(--border-radius-sm);
color: white;
padding: 1px 4px;
}

View File

@@ -0,0 +1,104 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
// "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. */
// "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. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
"module": "commonjs", /* Specify what module code is generated. */
"rootDirs": ["./src", "../../@types"], /* Specify the root folder within your source files. */
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
"typeRoots": [
"./node_modules/@types",
"../../@types"
], /* Specify multiple folders that act like './node_modules/@types'. */
"types": [
"olympus"
], /* 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. */
// "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 */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
// "outDir": "./", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
},
"include": [
"src/*.ts",
"../../@types/olympus/*.d.ts"
]
}

View File

@@ -0,0 +1,20 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Attach to Chrome",
"port": 9222,
"urlFilter": "http://localhost:3000/*",
"request": "attach",
"type": "chrome",
"webRoot": "${workspaceFolder}../../public/",
"sourceMapPathOverrides": {
"src/*": "src/*"
},
"preLaunchTask": "start"
}
]
}

View File

@@ -0,0 +1,13 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "start",
"type": "shell",
"command": "npm run start",
"isBackground": true
}
]
}

View File

@@ -0,0 +1,5 @@
mkdir .\\..\\..\\public\\plugins\\databasemanager
copy .\\index.js .\\..\\..\\public\\plugins\\databasemanager\\index.js
copy .\\plugin.json .\\..\\..\\public\\plugins\\databasemanager\\plugin.json
copy .\\style.css .\\..\\..\\public\\plugins\\databasemanager\\style.css

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
{
"name": "DatabaseManagerPlugin",
"version": "v0.0.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "DatabaseManagerPlugin",
"version": "v0.0.1",
"devDependencies": {}
}
}
}

View File

@@ -0,0 +1,13 @@
{
"name": "DatabaseManagerPlugin",
"version": "v0.0.1",
"private": true,
"scripts": {
"build": "browserify ./src/index.ts -p [ tsify --noImplicitAny] > index.js && copy.bat",
"start": "npm run copy & concurrently --kill-others \"npm run watch\"",
"copy": "copy.bat",
"watch": "watchify ./src/index.ts --debug -o ../../public/plugins/databasemanager/index.js -t [ babelify --global true --presets [ @babel/preset-env ] --extensions '.js'] -p [ tsify --noImplicitAny ]"
},
"dependencies": {},
"devDependencies": {}
}

View File

@@ -0,0 +1,6 @@
{
"name": "Control Tip Plugin",
"version": "0.0.1",
"description": "This plugin shows useful control tips on the right side of the screen. The tips change dynamically depending on what the user does",
"author": "Peekaboo"
}

View File

@@ -0,0 +1,110 @@
import { LoadoutBlueprint, UnitBlueprint } from "interfaces";
import { UnitEditor } from "./uniteditor";
import { LoadoutEditor } from "./loadouteditor";
import { addCheckboxInput, addDropdownInput, addLoadoutsScroll, addNewElementInput, addStringInput } from "./utils";
/** Database editor for Air Units, both Aircraft and Helicopter since they are identical in terms of datbase entries.
*
*/
export class AirUnitEditor extends UnitEditor {
#loadoutEditor: LoadoutEditor | null = null;
constructor(contentDiv1: HTMLElement, contentDiv2: HTMLElement, contentDiv3: HTMLElement) {
super(contentDiv1, contentDiv2, contentDiv3);
/* The loadout editor allows to edit the loadout (who could have thought eh?) */
this.#loadoutEditor = new LoadoutEditor(this.contentDiv3);
/* Refresh the loadout editor if needed */
this.contentDiv3.addEventListener("refresh", () => {
if (this.visible)
this.#loadoutEditor?.show();
});
}
/** Sets a unit blueprint as the currently active one
*
* @param blueprint The blueprint to edit
*/
setBlueprint(blueprint: UnitBlueprint) {
this.blueprint = blueprint;
if (this.blueprint !== null) {
this.contentDiv2.replaceChildren();
var title = document.createElement("label");
title.innerText = "Unit properties";
this.contentDiv2.appendChild(title);
addStringInput(this.contentDiv2, "Name", blueprint.name, "text", (value: string) => { blueprint.name = value; }, true);
addStringInput(this.contentDiv2, "Label", blueprint.label, "text", (value: string) => { blueprint.label = value; });
addStringInput(this.contentDiv2, "Short label", blueprint.shortLabel, "text", (value: string) => { blueprint.shortLabel = value; });
addDropdownInput(this.contentDiv2, "Coalition", blueprint.coalition, ["", "blue", "red"], (value: string) => {blueprint.coalition = value; });
addDropdownInput(this.contentDiv2, "Era", blueprint.era, ["WW2", "Early Cold War", "Mid Cold War", "Late Cold War", "Modern"], (value: string) => {blueprint.era = value; });
addStringInput(this.contentDiv2, "Filename", blueprint.filename ?? "", "text", (value: string) => { blueprint.filename = value; });
addStringInput(this.contentDiv2, "Cost", String(blueprint.cost) ?? "", "number", (value: string) => { blueprint.cost = parseFloat(value); });
addCheckboxInput(this.contentDiv2, "Can target point", blueprint.canTargetPoint ?? false, (value: boolean) => {blueprint.canTargetPoint = value;})
addStringInput(this.contentDiv2, "Description", blueprint.description ?? "", "text", (value: string) => {blueprint.description = value; });
addStringInput(this.contentDiv2, "Tags", blueprint.tags ?? "", "text", (value: string) => {blueprint.tags = value; });
/* Add a scrollable list of loadouts that the user can edit */
var title = document.createElement("label");
title.innerText = "Loadouts";
this.contentDiv2.appendChild(title);
addLoadoutsScroll(this.contentDiv2, blueprint.loadouts ?? [], (loadout: LoadoutBlueprint) => {
this.#loadoutEditor?.setLoadout(loadout);
this.#loadoutEditor?.show();
});
addNewElementInput(this.contentDiv2, (ev: MouseEvent, input: HTMLInputElement) => { this.addLoadout(input.value); });
this.#loadoutEditor?.hide();
}
}
/** Add a new empty blueprint
*
* @param key Blueprint key
*/
addBlueprint(key: string) {
if (this.database != null) {
this.database.blueprints[key] = {
name: key,
coalition: "",
label: "",
shortLabel: "",
era: "",
loadouts: [],
enabled: true
}
this.show();
this.setBlueprint(this.database.blueprints[key]);
}
}
/** Add a new empty loadout to the currently active blueprint
*
* @param loadoutName The name of the new loadout
*/
addLoadout(loadoutName: string) {
if (loadoutName && this.blueprint !== null) {
this.blueprint.loadouts?.push({
name: loadoutName,
code: "",
fuel: 1,
items: [],
roles: [],
enabled: true
})
this.setBlueprint(this.blueprint);
}
}
/** Hide the editor
*
*/
hide() {
super.hide();
this.#loadoutEditor?.hide();
}
}

View File

@@ -0,0 +1,412 @@
import { OlympusPlugin, UnitBlueprint } from "interfaces";
import { AirUnitEditor } from "./airuniteditor";
import { OlympusApp } from "olympusapp";
import { GroundUnitEditor } from "./grounduniteditor";
import { PrimaryToolbar } from "toolbars/primarytoolbar";
import { NavyUnitEditor } from "./navyuniteditor";
/** Database Manager
*
* This database provides a user interface to allow easier and convenient unit databases manipulation. It allows to edit all the fields of the units databases, save them
* on the server, and restore the defaults.
*
* TODO:
* Add ability to manage liveries
*
*/
export class DatabaseManagerPlugin implements OlympusPlugin {
#app: OlympusApp | null = null;
#element: HTMLElement;
#mainContentContainer: HTMLElement;
#contentDiv1: HTMLElement;
#contentDiv2: HTMLElement;
#contentDiv3: HTMLElement;
/* Upper tab buttons */
#button1: HTMLButtonElement;
#button2: HTMLButtonElement;
#button3: HTMLButtonElement;
#button4: HTMLButtonElement;
/* Lower operation buttons */
#button5: HTMLButtonElement;
#button6: HTMLButtonElement;
#button7: HTMLButtonElement;
#button8: HTMLButtonElement;
#button9: HTMLButtonElement;
/* Database editors */
#aircraftEditor: AirUnitEditor;
#helicopterEditor: AirUnitEditor;
#groundUnitEditor: GroundUnitEditor;
#navyUnitEditor: NavyUnitEditor;
constructor() {
/* Create main HTML element */
this.#element = document.createElement("div");
this.#element.id = "database-manager-panel";
this.#element.oncontextmenu = () => { return false; }
this.#element.classList.add("ol-dialog");
document.body.appendChild(this.#element);
/* Start hidden */
this.toggle(false);
/* Create the top tab buttons container and buttons */
let topButtonContainer = document.createElement("div");
this.#button1 = document.createElement("button");
this.#button1.classList.add("tab-button");
this.#button1.textContent = "Aircraft database";
this.#button1.onclick = () => { this.#hideAll(); this.#aircraftEditor.show(); this.#button1.classList.add("selected"); };
topButtonContainer.appendChild(this.#button1);
this.#button2 = document.createElement("button");
this.#button2.classList.add("tab-button");
this.#button2.textContent = "Helicopter database";
this.#button2.onclick = () => { this.#hideAll(); this.#helicopterEditor.show(); this.#button2.classList.add("selected"); };
topButtonContainer.appendChild(this.#button2);
this.#button3 = document.createElement("button");
this.#button3.classList.add("tab-button");
this.#button3.textContent = "Ground Unit database";
this.#button3.onclick = () => { this.#hideAll(); this.#groundUnitEditor.show(); this.#button3.classList.add("selected"); };
topButtonContainer.appendChild(this.#button3);
this.#button4 = document.createElement("button");
this.#button4.classList.add("tab-button");
this.#button4.textContent = "Navy Unit database";
this.#button4.onclick = () => { this.#hideAll(); this.#navyUnitEditor.show(); this.#button4.classList.add("selected"); };
topButtonContainer.appendChild(this.#button4);
this.#element.appendChild(topButtonContainer);
/* Create the container for the database editor elements and the elements themselves */
this.#mainContentContainer = document.createElement("div");
this.#mainContentContainer.classList.add("dm-container");
this.#element.appendChild(this.#mainContentContainer);
this.#contentDiv1 = document.createElement("div");
this.#contentDiv1.classList.add("dm-content-container", "ol-scrollable");
this.#mainContentContainer.appendChild(this.#contentDiv1);
this.#contentDiv2 = document.createElement("div");
this.#contentDiv2.classList.add("dm-content-container", "ol-scrollable");
this.#mainContentContainer.appendChild(this.#contentDiv2);
this.#contentDiv3 = document.createElement("div");
this.#contentDiv3.classList.add("dm-content-container", "ol-scrollable");
this.#mainContentContainer.appendChild(this.#contentDiv3);
/* Create the database editors, which use the three divs created before */
this.#aircraftEditor = new AirUnitEditor(this.#contentDiv1, this.#contentDiv2, this.#contentDiv3);
this.#helicopterEditor = new AirUnitEditor(this.#contentDiv1, this.#contentDiv2, this.#contentDiv3);
this.#groundUnitEditor = new GroundUnitEditor(this.#contentDiv1, this.#contentDiv2, this.#contentDiv3);
this.#navyUnitEditor = new NavyUnitEditor(this.#contentDiv1, this.#contentDiv2, this.#contentDiv3);
/* Create the bottom buttons container. These buttons allow to save, restore, reset, and discard the changes */
let bottomButtonContainer = document.createElement("div");
this.#button5 = document.createElement("button");
this.#button5.textContent = "Save";
this.#button5.title = "Save the changes on the server"
this.#button5.onclick = () => { this.#saveDatabases();};
bottomButtonContainer.appendChild(this.#button5);
this.#button6 = document.createElement("button");
this.#button6.textContent = "Discard";
this.#button6.title = "Discard all changes and reload the database from the server";
this.#button6.onclick = () => { this.#loadDatabases(); };
bottomButtonContainer.appendChild(this.#button6);
this.#button7 = document.createElement("button");
this.#button7.textContent = "Reset defaults";
this.#button7.onclick = () => { this.#resetToDefaultDatabases(); };
this.#button7.title = "Reset the databases to the default values";
bottomButtonContainer.appendChild(this.#button7);
this.#button8 = document.createElement("button");
this.#button8.textContent = "Restore previous";
this.#button8.onclick = () => { this.#restoreToPreviousDatabases(); };
this.#button8.title = "Restore the previously saved databases. Use this if you saved a database by mistake.";
bottomButtonContainer.appendChild(this.#button8);
this.#button9 = document.createElement("button");
this.#button9.textContent = "Close";
this.#button9.title = "Close the Database Manager"
this.#button9.onclick = () => { this.toggle(false); };
bottomButtonContainer.appendChild(this.#button9);
this.#element.appendChild(bottomButtonContainer);
}
/**
*
* @returns The name of the plugin
*/
getName() {
return "Database Control Plugin"
}
/** Initialize the plugin
*
* @param app The OlympusApp singleton
* @returns True if successfull
*/
initialize(app: any) {
this.#app = app;
/* Load the databases and initialize the editors */
this.#loadDatabases();
/* Add a button to the main Olympus App to allow the users to open the dialog */
var mainButtonDiv = document.createElement("div");
var mainButton = document.createElement("button");
mainButton.textContent = "Database manager";
mainButtonDiv.appendChild(mainButton);
var toolbar: PrimaryToolbar = this.#app?.getToolbarsManager().get("primaryToolbar") as PrimaryToolbar;
var elements = toolbar.getMainDropdown().getOptionElements();
var arr = Array.prototype.slice.call(elements);
arr.splice(arr.length - 1, 0, mainButtonDiv);
toolbar.getMainDropdown().setOptionsElements(arr);
mainButton.onclick = () => {
toolbar.getMainDropdown().close();
if (this.#app?.getMissionManager().getCommandModeOptions().commandMode === "Game master")
this.toggle();
}
return true;
}
/**
*
* @returns The main container element
*/
getElement() {
return this.#element;
}
/** Toggles the visibility of the dialog
*
* @param bool Force a specific visibility state
*/
toggle(bool?: boolean) {
if (bool)
this.getElement().classList.toggle("hide", !bool);
else
this.getElement().classList.toggle("hide");
}
/** Hide all the editors
*
*/
#hideAll() {
this.#aircraftEditor.hide();
this.#helicopterEditor.hide();
this.#groundUnitEditor.hide();
this.#navyUnitEditor.hide();
this.#button1.classList.remove("selected");
this.#button2.classList.remove("selected");
this.#button3.classList.remove("selected");
this.#button4.classList.remove("selected");
}
/** Load the databases from the app to the editor. Note, this does not reload the databases from the server to the app
*
*/
#loadDatabases() {
var aircraftDatabase = this.#app?.getAircraftDatabase();
if (aircraftDatabase != null)
this.#aircraftEditor.setDatabase(aircraftDatabase);
var helicopterDatabase = this.#app?.getHelicopterDatabase();
if (helicopterDatabase != null)
this.#helicopterEditor.setDatabase(helicopterDatabase);
var groundUnitDatabase = this.#app?.getGroundUnitDatabase();
if (groundUnitDatabase != null)
this.#groundUnitEditor.setDatabase(groundUnitDatabase);
var navyUnitDatabase = this.#app?.getNavyUnitDatabase();
if (navyUnitDatabase != null)
this.#navyUnitEditor.setDatabase(navyUnitDatabase);
this.#hideAll();
this.#aircraftEditor.show();
this.#button1.classList.add("selected");
}
/** Save the databases on the server and reloads it to apply the changes
*
*/
#saveDatabases() {
var aircraftDatabase = this.#aircraftEditor.getDatabase();
if (aircraftDatabase){
this.#uploadDatabase(aircraftDatabase, "aircraftdatabase", "Aircraft database", () => {
var helicopterDatabase = this.#helicopterEditor.getDatabase();
if (helicopterDatabase) {
this.#uploadDatabase(helicopterDatabase, "helicopterDatabase", "Helicopter database", () => {
var groundUnitDatabase = this.#groundUnitEditor.getDatabase();
if (groundUnitDatabase) {
this.#uploadDatabase(groundUnitDatabase, "groundUnitDatabase", "Ground Unit database", () => {
var navyUnitDatabase = this.#navyUnitEditor.getDatabase();
if (navyUnitDatabase) {
this.#uploadDatabase(navyUnitDatabase, "navyUnitDatabase", "Navy Unit database", () => {
this.#app?.getAircraftDatabase().load(() => {});
this.#app?.getHelicopterDatabase().load(() => {});
this.#app?.getGroundUnitDatabase().load(() => {});
this.#app?.getNavyUnitDatabase().load(() => {});
this.#app?.getServerManager().reloadDatabases(() => {
this.#app?.getPopupsManager().get("infoPopup")?.setText("Olympus core databases reloaded");
})
});
}
});
}
});
}
});
}
}
/** Resets the databases to the default values
*
*/
#resetToDefaultDatabases() {
this.#resetToDefaultDatabase("aircraftdatabase", "Aircraft database", () => {
this.#app?.getAircraftDatabase().load(() => {
this.#resetToDefaultDatabase("helicopterdatabase", "Helicopter database", () => {
this.#app?.getHelicopterDatabase().load(() => {
this.#resetToDefaultDatabase("groundunitdatabase", "Ground Unit database", () => {
this.#app?.getGroundUnitDatabase().load(() => {
this.#resetToDefaultDatabase("navyunitdatabase", "Navy Unit database", () => {
this.#app?.getNavyUnitDatabase().load(() => {
this.#loadDatabases();
this.#app?.getServerManager().reloadDatabases(() => {
this.#app?.getPopupsManager().get("infoPopup")?.setText("Olympus core databases reloaded");
})
this.#hideAll();
this.#aircraftEditor.show();
this.#button1.classList.add("selected");
});
});
});
});
});
});
});
});
}
/** Restores the databases to the previous saved values. This is useful if you saved the databases by mistake and want to undo the error.
*
*/
#restoreToPreviousDatabases() {
this.#restoreToPreviousDatabase("aircraftdatabase", "Aircraft database", () => {
this.#app?.getAircraftDatabase().load(() => {
this.#restoreToPreviousDatabase("helicopterdatabase", "Helicopter database", () => {
this.#app?.getHelicopterDatabase().load(() => {
this.#restoreToPreviousDatabase("groundunitdatabase", "Ground Unit database", () => {
this.#app?.getGroundUnitDatabase().load(() => {
this.#restoreToPreviousDatabase("navyunitdatabase", "Navy Unit database", () => {
this.#app?.getNavyUnitDatabase().load(() => {
this.#loadDatabases();
this.#app?.getServerManager().reloadDatabases(() => {
this.#app?.getPopupsManager().get("infoPopup")?.setText("Olympus core databases reloaded");
})
this.#hideAll();
this.#aircraftEditor.show();
this.#button1.classList.add("selected");
});
});
});
});
});
});
});
});
}
/** Upload a single database to the server
*
* @param database The database
* @param name The name of the database as it will be saved on the server
* @param label A label used in the info popup
*/
#uploadDatabase(database: { blueprints: { [key: string]: UnitBlueprint } }, name: string, label: string, callback: CallableFunction) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("PUT", "/api/databases/save/units/" + name);
xmlHttp.setRequestHeader("Content-Type", "application/json");
xmlHttp.onload = (res: any) => {
if (xmlHttp.status == 200) {
this.#app?.getPopupsManager().get("infoPopup")?.setText(label + " saved successfully");
callback();
}
else {
this.#app?.getPopupsManager().get("infoPopup")?.setText("An error has occurred while saving the " + label);
}
};
xmlHttp.onerror = (res: any) => {
this.#app?.getPopupsManager().get("infoPopup")?.setText("An error has occurred while saving the " + label);
}
xmlHttp.send(JSON.stringify(database));
}
/** Resets a database to its default values on the server. NOTE: this only resets the database on the server, it will not reload it in the app.
*
* @param name The name of the database as it is saved on the server
* @param label A label used in the info popup
* @param callback Called when the operation is completed
*/
#resetToDefaultDatabase(name: string, label: string, callback: CallableFunction) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("PUT", "/api/databases/reset/units/" + name);
xmlHttp.setRequestHeader("Content-Type", "application/json");
xmlHttp.onload = (res: any) => {
if (xmlHttp.status == 200) {
this.#app?.getPopupsManager().get("infoPopup")?.setText(label + " reset successfully");
callback();
}
else {
this.#app?.getPopupsManager().get("infoPopup")?.setText("An error has occurred while resetting the " + label);
}
};
xmlHttp.onerror = (res: any) => {
this.#app?.getPopupsManager().get("infoPopup")?.setText("An error has occurred while resetting the " + label)
}
xmlHttp.send("");
}
/** Restores a database to its previously saved values on the server. NOTE: this only restores the database on the server, it will not reload it in the app.
*
* @param name The name of the database as it is saved on the server
* @param label A label used in the info popup
* @param callback Called when the operation is completed
*/
#restoreToPreviousDatabase(name: string, label: string, callback: CallableFunction) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("PUT", "/api/databases/restore/units/" + name);
xmlHttp.setRequestHeader("Content-Type", "application/json");
xmlHttp.onload = (res: any) => {
if (xmlHttp.status == 200) {
this.#app?.getPopupsManager().get("infoPopup")?.setText(label + " restored successfully");
callback();
}
else {
this.#app?.getPopupsManager().get("infoPopup")?.setText("An error has occurred while restoring the " + label);
}
};
xmlHttp.onerror = (res: any) => {
this.#app?.getPopupsManager().get("infoPopup")?.setText("An error has occurred while restoring the " + label)
}
xmlHttp.send("");
}
}

View File

@@ -0,0 +1,77 @@
import { UnitBlueprint } from "interfaces";
import { UnitEditor } from "./uniteditor";
import { addCheckboxInput, addDropdownInput, addStringInput } from "./utils";
/** Database editor for ground units
*
*/
export class GroundUnitEditor extends UnitEditor {
#blueprint: UnitBlueprint | null = null;
constructor(contentDiv1: HTMLElement, contentDiv2: HTMLElement, contentDiv3: HTMLElement) {
super(contentDiv1, contentDiv2, contentDiv3);
}
/** Sets a unit blueprint as the currently active one
*
* @param blueprint The blueprint to edit
*/
setBlueprint(blueprint: UnitBlueprint) {
this.#blueprint = blueprint;
if (this.#blueprint !== null) {
this.contentDiv2.replaceChildren();
var title = document.createElement("label");
title.innerText = "Unit properties";
this.contentDiv2.appendChild(title);
addStringInput(this.contentDiv2, "Name", blueprint.name, "text", (value: string) => {blueprint.name = value; }, true);
addStringInput(this.contentDiv2, "Label", blueprint.label, "text", (value: string) => {blueprint.label = value; });
addStringInput(this.contentDiv2, "Short label", blueprint.shortLabel, "text", (value: string) => {blueprint.shortLabel = value; });
addStringInput(this.contentDiv2, "Type", blueprint.type?? "", "text", (value: string) => {blueprint.type = value; });
addStringInput(this.contentDiv2, "Unit when grouped", blueprint.unitWhenGrouped?? "", "text", (value: string) => {blueprint.unitWhenGrouped = value; });
addDropdownInput(this.contentDiv2, "Coalition", blueprint.coalition, ["", "blue", "red"], (value: string) => {blueprint.coalition = value; });
addDropdownInput(this.contentDiv2, "Era", blueprint.era, ["WW2", "Early Cold War", "Mid Cold War", "Late Cold War", "Modern"], (value: string) => {blueprint.era = value; });
//addStringInput(this.contentDiv2, "Filename", blueprint.filename?? "", "text", (value: string) => {blueprint.filename = value; });
addStringInput(this.contentDiv2, "Cost", String(blueprint.cost)?? "", "number", (value: string) => {blueprint.cost = parseFloat(value); });
addStringInput(this.contentDiv2, "Acquisition range [m]", String(blueprint.acquisitionRange)?? "", "number", (value: string) => {blueprint.acquisitionRange = parseFloat(value); });
addStringInput(this.contentDiv2, "Engagement range [m]", String(blueprint.engagementRange)?? "", "number", (value: string) => {blueprint.engagementRange = parseFloat(value); });
addStringInput(this.contentDiv2, "Targeting range [m]", String(blueprint.targetingRange)?? "", "number", (value: string) => {blueprint.targetingRange = parseFloat(value); });
addStringInput(this.contentDiv2, "Aim method range [m]", String(blueprint.aimMethodRange)?? "", "number", (value: string) => {blueprint.aimMethodRange = parseFloat(value); });
addStringInput(this.contentDiv2, "Barrel height [m]", String(blueprint.barrelHeight)?? "", "number", (value: string) => {blueprint.barrelHeight = parseFloat(value); });
addStringInput(this.contentDiv2, "Muzzle velocity [m/s]", String(blueprint.muzzleVelocity)?? "", "number", (value: string) => {blueprint.muzzleVelocity = parseFloat(value); });
addStringInput(this.contentDiv2, "Aim time [s]", String(blueprint.aimTime)?? "", "number", (value: string) => {blueprint.aimTime = parseFloat(value); });
addStringInput(this.contentDiv2, "Shots to fire", String(blueprint.shotsToFire)?? "", "number", (value: string) => {blueprint.shotsToFire = Math.round(parseFloat(value)); });
addStringInput(this.contentDiv2, "Shots base interval [s]", String(blueprint.shotsBaseInterval)?? "", "number", (value: string) => {blueprint.shotsBaseInterval = Math.round(parseFloat(value)); });
addStringInput(this.contentDiv2, "Shots base scatter [°]", String(blueprint.shotsBaseScatter)?? "", "number", (value: string) => {blueprint.shotsBaseScatter = Math.round(parseFloat(value)); });
addStringInput(this.contentDiv2, "Alertness time constant [s]", String(blueprint.alertnessTimeConstant)?? "", "number", (value: string) => {blueprint.alertnessTimeConstant = Math.round(parseFloat(value)); });
addCheckboxInput(this.contentDiv2, "Can target point", blueprint.canTargetPoint ?? false, (value: boolean) => {blueprint.canTargetPoint = value;})
addCheckboxInput(this.contentDiv2, "Can rearm", blueprint.canRearm ?? false, (value: boolean) => {blueprint.canRearm = value;})
addCheckboxInput(this.contentDiv2, "Can operate as AAA", blueprint.canAAA ?? false, (value: boolean) => {blueprint.canAAA = value;})
addCheckboxInput(this.contentDiv2, "Indirect fire (e.g. mortar)", blueprint.indirectFire ?? false, (value: boolean) => {blueprint.indirectFire = value;})
addStringInput(this.contentDiv2, "Description", blueprint.description ?? "", "text", (value: string) => {blueprint.description = value; });
addStringInput(this.contentDiv2, "Tags", blueprint.tags ?? "", "text", (value: string) => {blueprint.tags = value; });
addStringInput(this.contentDiv2, "Marker file", blueprint.markerFile ?? "", "text", (value: string) => {blueprint.markerFile = value; });
}
}
/** Add a new empty blueprint
*
* @param key Blueprint key
*/
addBlueprint(key: string) {
if (this.database != null) {
this.database.blueprints[key] = {
name: key,
coalition: "",
label: "",
shortLabel: "",
era: "",
enabled: true
}
this.show();
this.setBlueprint(this.database.blueprints[key]);
}
}
}

View File

@@ -0,0 +1,5 @@
import { DatabaseManagerPlugin } from "./databasemanagerplugin";
globalThis.getOlympusPlugin = () => {
return new DatabaseManagerPlugin();
}

View File

@@ -0,0 +1,55 @@
import { LoadoutBlueprint } from "interfaces";
import { addLoadoutItemsEditor, addStringInput, arrayToString, stringToArray } from "./utils";
/** The LoadoutEditor allows the user to edit a loadout
*
*/
export class LoadoutEditor {
#contentDiv: HTMLElement;
#loadout: LoadoutBlueprint | null = null;
#visible: boolean = false;
constructor(contentDiv: HTMLElement) {
this.#contentDiv = contentDiv;
this.#contentDiv.addEventListener("refresh", () => {
if (this.#visible)
this.show();
})
}
/** Set the loadout to edit
*
* @param loadout The loadout to edit
*/
setLoadout(loadout: LoadoutBlueprint) {
this.#loadout = loadout;
}
/** Show the editor
*
*/
show() {
this.#visible = true;
this.#contentDiv.replaceChildren();
var title = document.createElement("label");
title.innerText = "Loadout properties";
this.#contentDiv.appendChild(title);
if (this.#loadout) {
var loadout = this.#loadout;
addStringInput(this.#contentDiv, "Name", loadout.name, "text", (value: string) => {loadout.name = value; this.#contentDiv.dispatchEvent(new Event("refresh"));});
addStringInput(this.#contentDiv, "Code", loadout.code, "text", (value: string) => {loadout.code = value; });
addStringInput(this.#contentDiv, "Roles", arrayToString(loadout.roles), "text", (value: string) => {loadout.roles = stringToArray(value);});
addLoadoutItemsEditor(this.#contentDiv, this.#loadout);
}
}
/** Hide the editor
*
*/
hide() {
this.#visible = false;
this.#contentDiv.replaceChildren();
}
}

View File

@@ -0,0 +1,60 @@
import { UnitBlueprint } from "interfaces";
import { UnitEditor } from "./uniteditor";
import { addDropdownInput, addStringInput } from "./utils";
/** Database editor for navy units
*
*/
export class NavyUnitEditor extends UnitEditor {
#blueprint: UnitBlueprint | null = null;
constructor(contentDiv1: HTMLElement, contentDiv2: HTMLElement, contentDiv3: HTMLElement) {
super(contentDiv1, contentDiv2, contentDiv3);
}
/** Sets a unit blueprint as the currently active one
*
* @param blueprint The blueprint to edit
*/
setBlueprint(blueprint: UnitBlueprint) {
this.#blueprint = blueprint;
if (this.#blueprint !== null) {
this.contentDiv2.replaceChildren();
var title = document.createElement("label");
title.innerText = "Unit properties";
this.contentDiv2.appendChild(title);
addStringInput(this.contentDiv2, "Name", blueprint.name, "text", (value: string) => {blueprint.name = value; }, true);
addStringInput(this.contentDiv2, "Label", blueprint.label, "text", (value: string) => {blueprint.label = value; });
addStringInput(this.contentDiv2, "Short label", blueprint.shortLabel, "text", (value: string) => {blueprint.shortLabel = value; });
addStringInput(this.contentDiv2, "Type", blueprint.type?? "", "text", (value: string) => {blueprint.type = value; });
addDropdownInput(this.contentDiv2, "Coalition", blueprint.coalition, ["", "blue", "red"], (value: string) => {blueprint.coalition = value; });
addDropdownInput(this.contentDiv2, "Era", blueprint.era, ["WW2", "Early Cold War", "Mid Cold War", "Late Cold War", "Modern"], (value: string) => {blueprint.era = value; });
//addStringInput(this.contentDiv2, "Filename", blueprint.filename?? "", "text", (value: string) => {blueprint.filename = value; });
addStringInput(this.contentDiv2, "Cost", String(blueprint.cost)?? "", "number", (value: string) => {blueprint.cost = parseFloat(value); });
addStringInput(this.contentDiv2, "Barrel height [m]", String(blueprint.barrelHeight)?? "", "number", (value: string) => {blueprint.barrelHeight = parseFloat(value); });
addStringInput(this.contentDiv2, "Muzzle velocity [m/s]", String(blueprint.muzzleVelocity)?? "", "number", (value: string) => {blueprint.muzzleVelocity = parseFloat(value); });
}
}
/** Add a new empty blueprint
*
* @param key Blueprint key
*/
addBlueprint(key: string) {
if (this.database != null) {
this.database.blueprints[key] = {
name: key,
coalition: "",
label: "",
shortLabel: "",
era: "",
enabled: true
}
this.show();
this.setBlueprint(this.database.blueprints[key]);
}
}
}

View File

@@ -0,0 +1,117 @@
import { UnitBlueprint } from "interfaces";
import { UnitDatabase } from "unit/databases/unitdatabase";
import { addBlueprintsScroll, addNewElementInput } from "./utils";
/** Base abstract class of Unit database editors
*
*/
export abstract class UnitEditor {
blueprint: UnitBlueprint | null = null;
database: {blueprints: {[key: string]: UnitBlueprint}} | null = null;
visible: boolean = false;
contentDiv1: HTMLElement;
contentDiv2: HTMLElement;
contentDiv3: HTMLElement;
constructor(contentDiv1: HTMLElement, contentDiv2: HTMLElement, contentDiv3: HTMLElement) {
this.contentDiv1 = contentDiv1;
this.contentDiv2 = contentDiv2;
this.contentDiv3 = contentDiv3;
/* Refresh the list of units if it changes */
this.contentDiv1.addEventListener("refresh", () => {
if (this.visible)
this.show();
})
/* If the unit properties or loadout are edited, reload the editor */
this.contentDiv2.addEventListener("refresh", () => {
if (this.visible) {
if (this.blueprint !== null)
this.setBlueprint(this.blueprint);
}
});
this.contentDiv3.addEventListener("refresh", () => {
if (this.visible) {
if (this.blueprint !== null)
this.setBlueprint(this.blueprint);
}
});
}
/**
*
* @param database The database that the editor will operate on
*/
setDatabase(database: UnitDatabase) {
this.database = JSON.parse(JSON.stringify({blueprints: database.getBlueprints(true)}));
}
/** Show the editor
* @param filter String filter
*/
show(filter: string = "") {
this.visible = true;
this.contentDiv1.replaceChildren();
this.contentDiv2.replaceChildren();
this.contentDiv3.replaceChildren();
/* Create the list of units. Each unit is clickable to activate the editor on it */
if (this.database != null) {
var title = document.createElement("label");
title.innerText = "Units list";
this.contentDiv1.appendChild(title);
var filterInput = document.createElement("input");
filterInput.value = filter;
this.contentDiv1.appendChild(filterInput);
filterInput.onchange = (e: Event) => {
this.show((e.target as HTMLInputElement).value);
}
this.addBlueprints(filter);
}
}
/** Hide the editor
*
*/
hide() {
this.visible = false;
this.contentDiv1.replaceChildren();
this.contentDiv2.replaceChildren();
this.contentDiv3.replaceChildren();
}
/**
*
* @returns The edited database
*/
getDatabase() {
return this.database;
}
/**
*
* @param filter String filter
*/
addBlueprints(filter: string = "") {
if (this.database) {
addBlueprintsScroll(this.contentDiv1, this.database, filter, (key: string) => {
if (this.database != null)
this.setBlueprint(this.database.blueprints[key])
});
addNewElementInput(this.contentDiv1, (ev: MouseEvent, input: HTMLInputElement) => {
if (input.value != "")
this.addBlueprint((input).value);
});
}
}
/* Abstract methods which will depend on the specific type of units */
abstract setBlueprint(blueprint: UnitBlueprint): void;
abstract addBlueprint(key: string): void;
}

View File

@@ -0,0 +1,297 @@
import { LoadoutBlueprint, LoadoutItemBlueprint, UnitBlueprint } from "interfaces";
/** This file contains a set of utility functions that are reused in the various editors and allows to declutter the classes
*
*/
/** Add a string input in the form of String: [ value ]
*
* @param div The HTMLElement that will contain the input
* @param key The key of the input, which will be used as label
* @param value The initial value of the input
* @param type The type of the input, e.g. "Text" or "Number" as per html standard
* @param callback Callback called when the user enters a new value
* @param disabled If true, the input will be disabled and read only
*/
export function addStringInput(div: HTMLElement, key: string, value: string, type: string, callback: CallableFunction, disabled?: boolean) {
var row = document.createElement("div");
var dt = document.createElement("dt");
var dd = document.createElement("dd");
dt.innerText = key;
var input = document.createElement("input");
input.value = value;
input.textContent = value;
input.type = type?? "text";
input.disabled = disabled?? false;
input.onchange = () => callback(input.value);
dd.appendChild(input);
row.appendChild(dt);
row.appendChild(dd);
row.classList.add("input-row");
div.appendChild(row);
}
/** Add a dropdown (select) input
*
* @param div The HTMLElement that will contain the input
* @param key The key of the input, which will be used as label
* @param value The initial value of the input
* @param options The dropdown options
*/
export function addDropdownInput(div: HTMLElement, key: string, value: string, options: string[], callback: CallableFunction, disabled?: boolean) {
var row = document.createElement("div");
var dt = document.createElement("dt");
var dd = document.createElement("dd");
dt.innerText = key;
var select = document.createElement("select");
options.forEach((option: string) => {
var el = document.createElement("option");
el.value = option;
el.innerText = option;
select.appendChild(el);
});
select.value = value;
select.disabled = disabled?? false;
select.onchange = () => callback(select.value);
dd.appendChild(select);
row.appendChild(dt);
row.appendChild(dd);
row.classList.add("input-row");
div.appendChild(row);
}
/** Add a checkbox input in the form of String: [ value ]
*
* @param div The HTMLElement that will contain the input
* @param key The key of the input, which will be used as label
* @param value The initial value of the input
* @param callback Callback called when the user enters a new value
* @param disabled If true, the input will be disabled and read only
*/
export function addCheckboxInput(div: HTMLElement, key: string, value: boolean, callback: CallableFunction, disabled?: boolean) {
var row = document.createElement("div");
var dt = document.createElement("dt");
var dd = document.createElement("dd");
dt.innerText = key;
var input = document.createElement("input");
input.checked = value;
input.type = "checkbox";
input.disabled = disabled?? false;
input.onchange = () => callback(input.checked);
dd.appendChild(input);
row.appendChild(dt);
row.appendChild(dd);
row.classList.add("input-row");
div.appendChild(row);
}
/** Create a loadout items editor. This editor allows to add or remove loadout items, as well as changing their name and quantity
*
* @param div The HTMLElement that will contain the editor
* @param loadout The loadout to edit
*/
export function addLoadoutItemsEditor(div: HTMLElement, loadout: LoadoutBlueprint) {
var itemsEl = document.createElement("div");
itemsEl.classList.add("dm-scroll-container", "dm-items-container");
/* Create a row for each loadout item to allow and change the name and quantity of the item itself */
loadout.items.sort((a: LoadoutItemBlueprint, b: LoadoutItemBlueprint) => a.name.localeCompare(b.name, undefined, {sensitivity: 'base'}));
loadout.items.forEach((item: LoadoutItemBlueprint, index: number) => {
var rowDiv = document.createElement("div");
var nameLabel = document.createElement("label");
nameLabel.innerText = "Name"
rowDiv.appendChild(nameLabel);
var nameInput = document.createElement("input");
rowDiv.appendChild(nameInput);
nameInput.textContent = item.name;
nameInput.value = item.name
nameInput.onchange = () => { loadout.items[index].name = nameInput.value; }
var quantityLabel = document.createElement("label");
quantityLabel.innerText = "Quantity"
rowDiv.appendChild(quantityLabel);
var quantityInput = document.createElement("input");
rowDiv.appendChild(quantityInput);
quantityInput.textContent = String(item.quantity);
quantityInput.value = String(item.quantity);
quantityInput.type = "number";
quantityInput.step = "1";
quantityInput.onchange = () => { loadout.items[index].quantity = parseInt(quantityInput.value); }
/* This button allows to remove the item */
var button = document.createElement("button");
button.innerText = "X";
button.onclick = () => {
loadout.items.splice(index, 1);
div.dispatchEvent(new Event("refresh"));
}
rowDiv.appendChild(button);
itemsEl.appendChild(rowDiv);
})
div.appendChild(itemsEl);
/* Button to add a new item to the loadout */
var inputDiv = document.createElement("div");
inputDiv.classList.add("dm-new-item-input");
var button = document.createElement("button");
button.innerText = "Add";
inputDiv.appendChild(button);
div.appendChild(inputDiv);
button.addEventListener("click", (ev: MouseEvent) => {
loadout?.items.push({
name: "",
quantity: 1
})
div.dispatchEvent(new Event("refresh"));
});
}
/** Add a input and button to create a new element in a list. It uses a generic callback to actually add the element.
*
* @param div The HTMLElement that will contain the input and button
* @param callback Callback called when the user clicks on "Add"
*/
export function addNewElementInput(div: HTMLElement, callback: CallableFunction) {
var inputDiv = document.createElement("div");
inputDiv.classList.add("dm-new-element-input");
var input = document.createElement("input");
inputDiv.appendChild(input);
var button = document.createElement("button");
button.innerText = "Add";
button.addEventListener("click", (ev: MouseEvent) => callback(ev, input));
inputDiv.appendChild(button);
div.appendChild(inputDiv);
}
/** Add a scrollable list of blueprints
*
* @param div The HTMLElement that will contain the list
* @param database The database that will be used to fill the list of blueprints
* @param filter A string filter that will be executed to filter the blueprints to add
* @param callback Callback called when the user clicks on one of the elements
*/
export function addBlueprintsScroll(div: HTMLElement, database: {blueprints: {[key: string]: UnitBlueprint}}, filter: string, callback: CallableFunction) {
var scrollDiv = document.createElement("div");
scrollDiv.classList.add("dm-scroll-container");
if (database !== null) {
var blueprints: {[key: string]: UnitBlueprint} = database.blueprints;
for (let key of Object.keys(blueprints).sort((a, b) => a.localeCompare(b, undefined, {sensitivity: 'base'}))) {
var addKey = true;
if (filter !== "") {
try {
var blueprint = blueprints[key];
addKey = eval(filter);
} catch {
console.error("An error has occurred evaluating the blueprint filter")
}
}
if (addKey) {
var rowDiv = document.createElement("div");
scrollDiv.appendChild(rowDiv);
let text = document.createElement("div");
text.innerHTML = `<div>${key}</div> <div>${blueprints[key].label}</div>`;
text.onclick = () => {
callback(key);
const collection = document.getElementsByClassName("blueprint-selected");
for (let i = 0; i < collection.length; i++) {
collection[i].classList.remove("blueprint-selected");
}
text.classList.add("blueprint-selected");
}
rowDiv.appendChild(text);
let checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.checked = blueprints[key].enabled;
checkbox.onclick = () => {
console.log(checkbox.checked);
blueprints[key].enabled = checkbox.checked;
}
rowDiv.appendChild(checkbox);
/* This button allows to remove an element from the list. It requires a refresh. */
var button = document.createElement("button");
button.innerText = "X";
button.onclick = () => {
delete blueprints[key];
div.dispatchEvent(new Event("refresh"));
}
rowDiv.appendChild(button);
}
}
}
div.appendChild(scrollDiv);
}
/** Add a scrollable list of loadouts
*
* @param div The HTMLElement that will contain the list
* @param loadouts The loadouts that will be used to fill the list
* @param callback Callback called when the user clicks on one of the elements
*/
export function addLoadoutsScroll(div: HTMLElement, loadouts: LoadoutBlueprint[], callback: CallableFunction) {
var loadoutsEl = document.createElement("div");
loadoutsEl.classList.add("dm-scroll-container", "dm-loadout-container")
loadouts.sort((a: LoadoutBlueprint, b: LoadoutBlueprint) => a.name.localeCompare(b.name, undefined, {sensitivity: 'base'}));
loadouts.forEach((loadout: LoadoutBlueprint, index: number) => {
var rowDiv = document.createElement("div");
loadoutsEl.appendChild(rowDiv);
var text = document.createElement("label");
text.textContent = loadout.name;
text.onclick = () => { callback(loadout) };
rowDiv.appendChild(text);
/* The "Empty loadout" can not be removed */
if (loadout.name !== "Empty loadout") {
let checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.checked = loadout.enabled;
checkbox.onclick = () => {
console.log(checkbox.checked);
loadout.enabled = checkbox.checked;
}
rowDiv.appendChild(checkbox);
/* This button allows to remove an element from the list. It requires a refresh. */
var button = document.createElement("button");
button.innerText = "X";
button.onclick = () => {
loadouts.splice(index, 1);
div.dispatchEvent(new Event("refresh"));
}
rowDiv.appendChild(button);
}
});
div.appendChild(loadoutsEl);
}
/** Converts an array of string into a single string like [val1, val2, val3]
*
* @param array The input array of strings
* @returns The string
*/
export function arrayToString(array: string[]) {
return "[" + array.join( ", " ) + "]";
}
/** Converts an a single string like [val1, val2, val3] into an array
*
* @param input The input string
* @returns The array
*/
export function stringToArray(input: string) {
return input.match( /(\w)+/g ) ?? [];
}

View File

@@ -0,0 +1,295 @@
#database-manager-panel {
flex-direction: column;
display: flex;
width: 80%;
height: 80%;
padding: 10px;
border-radius: 5px;
background-color: var(--background-steel) !important;
z-index: 9999999;
}
@media (min-width: 1200px) {
.dm-container {
flex-direction: row;
}
}
@media (max-width: 1200px) {
.dm-container {
flex-direction: column;
overflow-y: auto;
}
}
#database-manager-panel * {
font-size: 13;
font-family: 'Open Sans', sans-serif !important;
user-select: none;
}
#database-manager-panel>div:first-child {
display: flex;
align-items: center;
}
#database-manager-panel>div:last-child {
display: flex;
column-gap: 5px;
align-items: center;
justify-content: end;
justify-items: end;
margin-top: 5px;
}
#database-manager-panel>div:last-child>button {
border: 1px solid white;
}
.dm-container {
background-color: var(--background-grey);
border: 2px solid #777777;
position: relative;
display: flex;
width: 100%;
padding: 5px;
height: calc(100% - 64px - 5px);
border-radius: 0px 5px 5px 5px;
}
.dm-content-container {
position: relative;
margin: 10px;
display: flex;
flex-direction: column;
row-gap: 5px;
max-height: 100%;
padding: 10px;
}
@media (min-width: 1200px) {
.dm-content-container {
height: calc(100% - 20px);
}
.dm-content-container:nth-of-type(1) {
width: 400px;
}
.dm-content-container:nth-of-type(2) {
width: 500px;
}
.dm-content-container:nth-of-type(3) {
flex: 1;
}
}
@media (max-width: 1200px) {
.dm-content-container {
width: calc(100% - 20px);
}
.dm-content-container:nth-of-type(1) {
height: 30%;
}
.dm-content-container:nth-of-type(2) {
height: 50%;
}
.dm-content-container:nth-of-type(3) {
flex: 1;
}
}
.dm-content-container>label {
font-size: 18px !important;
font-weight: bold;
}
.dm-scroll-container {
display: flex;
flex-direction: column;
overflow-y: scroll;
max-height: 100%;
color: black;
font-weight: bold;
}
#database-manager-panel input {
font-weight: bold;
}
.dm-scroll-container>div:nth-child(even) {
background-color: gainsboro;
}
.dm-scroll-container>div:nth-child(odd) {
background-color: white;
}
.dm-scroll-container>div *:nth-child(1) {
height: 100%;
width: calc(100% - 25px);
padding: 2px;
word-wrap: break-word;
}
.dm-scroll-container>div *:nth-child(1):hover {
background-color: var(--accent-dark-blue);
color: white;
cursor: pointer;
}
.blueprint-selected {
background-color: var(--accent-light-blue) !important;
color: white;
}
.dm-scroll-container>div {
display: flex;
align-items: center;
justify-content: space-between;
}
.dm-scroll-container>div>div {
display: flex;
align-items: center;
justify-content: space-between;
}
.dm-scroll-container>div>button {
height: 20px;
width: 20px;
padding: 0px;
}
.dm-scroll-container>div>div>div:nth-child(1) {
width: fit-content;
}
.dm-scroll-container>div>div>div:nth-child(2) {
overflow: hidden;
text-wrap: nowrap;
text-overflow: ellipsis;
font-weight: normal;
}
.input-row {
width: 100%;
display: flex;
flex-direction: row;
}
@media (max-width: 1200px) {
.dm-content-container label {
width: 100%;
}
.input-row {
width: 50%;
}
}
.input-row>dt {
width: 250px;
}
.input-row>dd {
width: 100%;
text-align: right;
}
.input-row>dd>* {
width: 100%;
font-weight: bold;
}
.input-row>dd>*[type="checkbox"] {
width: 20px;
font-weight: bold;
}
.dm-loadout-container {
max-height: 100%;
max-width: 500px;
width: 100%;
}
.dm-items-container {
max-height: 100%;
height: fit-content;
}
.dm-items-container>div {
display: flex;
align-items: center;
column-gap: 2px;
}
.dm-items-container>div>label {
width: 80px !important;
}
.dm-items-container div>input:nth-of-type(1) {
flex: 1;
font-weight: bold;
}
.dm-items-container div>input:nth-of-type(2) {
width: 40px;
font-weight: bold;
}
.dm-new-element-input {
display: flex;
flex-direction: row;
column-gap: 2px;
width: 100%;
align-items: center;
}
.dm-new-element-input>input {
width: 100%;
}
.dm-new-element-input>button {
width: 60px;
}
.dm-new-item-input {
display: flex;
justify-content: end;
}
.dm-new-item-input>button {
width: 60px;
}
.tab-button {
transform: translateY(+3px);
background-color: var(--background-steel);
border-radius: 0;
border-bottom: 2px solid transparent !important;
border-top: 2px solid #777777 !important;
border-left: 2px solid #777777 !important;
border-right: 0px solid #777777 !important;
}
.tab-button.selected {
background-color: var(--background-grey);
z-index: 10;
}
.tab-button:first-of-type {
border-top-left-radius: 5px;
}
.tab-button:last-of-type {
border-top-right-radius: 5px;
border-right: 2px solid #777777 !important;
}
#database-manager-panel button :not(.dm-scroll-container>div) {
border: 1px solid white;
}

View File

@@ -0,0 +1,103 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
// "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. */
// "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. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
"module": "commonjs", /* Specify what module code is generated. */
"rootDirs": ["./src"], /* Specify the root folder within your source files. */
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
"typeRoots": [
"./node_modules/@types",
"../../@types"
], /* Specify multiple folders that act like './node_modules/@types'. */
"types": [
"olympus"
], /* 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. */
// "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 */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
// "outDir": "./", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
},
"include": [
"src/*.ts"
]
}

View File

@@ -1,2 +0,0 @@
copy .\\node_modules\\leaflet\\dist\\leaflet.css .\\public\\stylesheets\\leaflet\\leaflet.css
copy .\\node_modules\\leaflet.nauticscale\\dist\\leaflet.nauticscale.js .\\public\\javascripts\\leaflet.nauticscale.js

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,767 +0,0 @@
{
"An-26B": {
"name": "An-26B",
"coalition": "red",
"label": "An-26B Curl",
"era": "Mid Cold War",
"shortLabel": "26",
"loadouts": [
{
"fuel": 1,
"items": [],
"roles": [
"Transport"
],
"code": "",
"name": "Empty Loadout"
}
],
"filename": "an-26.png",
"cost": 0
},
"An-30M": {
"name": "An-30M",
"coalition": "red",
"label": "An-30M Clank",
"era": "Mid Cold War",
"shortLabel": "30",
"loadouts": [
{
"fuel": 1,
"items": [],
"roles": [
"Transport"
],
"code": "",
"name": "Empty Loadout"
}
],
"filename": "a-50.png",
"cost": 0
},
"C-130": {
"name": "C-130",
"label": "C-130 Hercules",
"era": "Early Cold War",
"shortLabel": "130",
"loadouts": [
{
"fuel": 1,
"items": [],
"roles": [
"Transport"
],
"code": "",
"name": "Empty Loadout"
}
],
"filename": "c-130.png",
"cost": 0
},
"F-14A-135-GR": {
"name": "F-14A-135-GR",
"coalition": "blue",
"label": "F-14A-135-GR Tomcat",
"era": "Mid Cold War",
"shortLabel": "14A",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "fuel",
"quantity": 2
},
{
"name": "AIM-54A",
"quantity": 2
},
{
"name": "AIM-7F",
"quantity": 1
},
{
"name": "AIM-9L",
"quantity": 4
}
],
"roles": [
"CAP"
],
"code": "AIM-54A-MK47*2, AIM-7F*1, AIM-9L*4, XT*2",
"name": "Heavy / Fox 3 / Long Range"
},
{
"fuel": 1,
"items": [
{
"name": "fuel",
"quantity": 2
},
{
"name": "AIM-7F",
"quantity": 4
},
{
"name": "AIM-9L",
"quantity": 4
}
],
"roles": [
"CAP"
],
"code": "AIM-7F*4, AIM-9L*4, XT*2",
"name": "Heavy / Fox 1 / Long Range"
},
{
"fuel": 1,
"items": [
{
"name": "fuel",
"quantity": 2
},
{
"name": "AIM-7M",
"quantity": 1
},
{
"name": "AIM-9M",
"quantity": 2
},
{
"name": "GBU-12",
"quantity": 2
},
{
"name": "LANTIRN",
"quantity": 1
}
],
"roles": [
"Strike"
],
"code": "AIM-7M*1, AIM-9M*2, XT*2, GBU-12*2, LANTIRN",
"name": "Heavy / Fox 3, GBU-12 / Long Range"
},
{
"fuel": 1,
"items": [],
"roles": [
""
],
"code": "",
"name": "Empty Loadout"
}
],
"filename": "f-14.png",
"cost": 300,
"liveryID": "IRIAF Asia Minor"
},
"F-4E": {
"name": "F-4E",
"coalition": "blue",
"label": "F-4E Phantom II",
"era": "Mid Cold War",
"shortLabel": "4",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "fuel",
"quantity": 2
},
{
"name": "AIM-7M",
"quantity": 4
},
{
"name": "AIM-9M",
"quantity": 4
}
],
"roles": [
"CAP"
],
"code": "AIM-9*4,AIM-7*4,Fuel*2",
"name": "Heavy / Fox 1 / Long Range"
},
{
"fuel": 1,
"items": [
{
"name": "ECM",
"quantity": 1
},
{
"name": "AIM-7M",
"quantity": 2
},
{
"name": "Mk-82",
"quantity": 18
}
],
"roles": [
"Strike"
],
"code": "Mk-82*18,AIM-7*2,ECM",
"name": "Heavy / Fox 1, Mk-82 / Short Range"
},
{
"fuel": 1,
"items": [],
"roles": [
""
],
"code": "",
"name": "Empty Loadout"
}
],
"filename": "f-4.png",
"cost": 100,
"liveryID": "IRIAF Asia Minor"
},
"F-5E-3": {
"name": "F-5E-3",
"coalition": "blue",
"label": "F-5E Tiger",
"era": "Mid Cold War",
"shortLabel": "5",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "Fuel 275",
"quantity": 3
},
{
"name": "AIM-9P5",
"quantity": 2
}
],
"roles": [
"CAP"
],
"code": "AIM-9P5*2, Fuel 275*3",
"name": "Heavy / Fox 2 / Long Range"
},
{
"fuel": 1,
"items": [
{
"name": "Mk-82",
"quantity": 4
},
{
"name": "AIM-9P5",
"quantity": 2
},
{
"name": "Fuel 275",
"quantity": 1
}
],
"roles": [
"Strike"
],
"code": "Mk-82LD*4,AIM-9P*2,Fuel 275",
"name": "Heavy / Fox 2 / Short Range"
},
{
"fuel": 1,
"items": [],
"roles": [
""
],
"code": "",
"name": "Empty Loadout"
}
],
"liveryID": "ir iriaf 43rd tfs",
"filename": "f-5.png",
"cost": 80
},
"F-86F Sabre": {
"name": "F-86F Sabre",
"coalition": "blue",
"label": "F-86F Sabre",
"era": "Early Cold War",
"shortLabel": "86",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "120gal Fuel",
"quantity": 2
}
],
"roles": [
"CAP"
],
"code": "120gal Fuel*2",
"name": "Light / Guns / Short Range"
},
{
"fuel": 1,
"items": [
{
"name": "HVAR",
"quantity": 16
}
],
"roles": [
"CAS"
],
"code": "HVAR*16",
"name": "Light / HVAR / Short Range"
},
{
"fuel": 1,
"items": [
{
"name": "AN-M64",
"quantity": 2
}
],
"roles": [
"Strike"
],
"code": "AN-M64*2",
"name": "Light / AN-M64 / Short Range"
},
{
"fuel": 1,
"items": [],
"roles": [
""
],
"code": "",
"name": "Light / Guns / Short Range"
}
],
"filename": "f-86.png",
"cost": 40,
"liveryID": "iiaf bare metall"
},
"IL-76MD": {
"name": "IL-76MD",
"label": "IL-76MD Candid",
"era": "Mid Cold War",
"shortLabel": "76",
"loadouts": [
{
"fuel": 1,
"items": [],
"roles": [
"Transport"
],
"code": "",
"name": "Default Transport"
}
],
"filename": "il-76.png",
"cost": 0
},
"MiG-15bis": {
"name": "MiG-15bis",
"coalition": "red",
"label": "MiG-15 Fagot",
"era": "Early Cold War",
"shortLabel": "M15",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "300L Fuel Tanks",
"quantity": 2
}
],
"roles": [
"CAP"
],
"code": "2*300L",
"name": "Medium / Guns / Medium Range"
},
{
"fuel": 1,
"items": [
{
"name": "FAB-100M",
"quantity": 2
}
],
"roles": [
"Strike"
],
"code": "2*FAB-100M",
"name": "Medium / FAB-100M / Short Range"
},
{
"fuel": 1,
"items": [],
"roles": [
"CAP"
],
"code": "",
"name": "Light / Guns / Short Range"
}
],
"filename": "mig-15.png",
"cost": 30,
"liveryID": "Iraqi_Camo"
},
"MiG-21Bis": {
"name": "MiG-21Bis",
"coalition": "red",
"label": "MiG-21 Fishbed",
"era": "Mid Cold War",
"shortLabel": "21",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "R-3 Atoll",
"quantity": 2
},
{
"name": "R-60 Aphid",
"quantity": 2
},
{
"name": "130 gal tanks",
"quantity": 1
},
{
"name": "ASO-2 Countermeasures",
"quantity": 1
}
],
"roles": [
"CAP"
],
"code": "Patrol, short range",
"name": "Light / Fox-2 / Short range"
},
{
"fuel": 1,
"items": [
{
"name": "R-3 Atoll",
"quantity": 2
},
{
"name": "R-60 Aphid",
"quantity": 2
},
{
"name": "210 gal tanks",
"quantity": 1
},
{
"name": "ASO-2 Countermeasures",
"quantity": 1
}
],
"roles": [
"CAP"
],
"code": "Patrol, medium range",
"name": "Medium / Fox-2 / Medium range"
},
{
"fuel": 1,
"items": [
{
"name": "R-3R Atoll",
"quantity": 2
},
{
"name": "R-3S Atoll",
"quantity": 2
},
{
"name": "210 gal tanks",
"quantity": 1
},
{
"name": "ASO-2 Countermeasures",
"quantity": 1
}
],
"roles": [
"CAP"
],
"code": "Patrol, long range",
"name": "Medium / Fox-1, Fox-2 / Medium range"
},
{
"fuel": 1,
"items": [
{
"name": "GROM",
"quantity": 2
},
{
"name": "FAB-250",
"quantity": 2
},
{
"name": "210 gal tanks",
"quantity": 1
},
{
"name": "ASO-2 Countermeasures",
"quantity": 1
}
],
"roles": [
"Strike"
],
"code": "Few big targets, GROM + BOMBS",
"name": "Heavy / GROM, FAB250 / Medium range"
},
{
"fuel": 1,
"items": [],
"roles": [
"CAP"
],
"code": "",
"name": "Empty Loadout"
}
],
"filename": "mig-21.png",
"cost": 100,
"liveryID": "iran - standard"
},
"MiG-23MLD": {
"name": "MiG-23MLD",
"coalition": "red",
"label": "MiG-23 Flogger",
"era": "Mid Cold War",
"shortLabel": "23",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "Fuel-800",
"quantity": 1
},
{
"name": "R-60M",
"quantity": 4
},
{
"name": "R-24R",
"quantity": 2
}
],
"roles": [
"CAP"
],
"code": "R-24R*2,R-60M*4,Fuel-800",
"name": "Heavy / Fox 1 / Long Range"
},
{
"fuel": 1,
"items": [
{
"name": "Fuel-800",
"quantity": 1
},
{
"name": "FAB-500",
"quantity": 2
},
{
"name": "R-60M",
"quantity": 2
}
],
"roles": [
"Strike"
],
"code": "FAB-500*2,R-60M*2,Fuel-800",
"name": "Heavy / FAB-500 / Long Range"
},
{
"fuel": 1,
"items": [],
"roles": [
""
],
"code": "",
"name": "Empty Loadout"
}
],
"filename": "mig-23.png",
"cost": 200
},
"Mirage-F1EE": {
"name": "Mirage-F1EE",
"coalition": "red",
"label": "Mirage-F1EE",
"era": "Mid Cold War",
"shortLabel": "F1EE",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "AIM-9JULI",
"quantity": 2
},
{
"name": "R530EM",
"quantity": 2
},
{
"name": "1137L Fuel Tank",
"quantity": 1
}
],
"roles": [
"CAP"
],
"code": "2*AIM9-JULI, 2*R530EM, 1*Fuel Tank",
"name": "Medium / Fox 1 / Medium Range"
},
{
"fuel": 1,
"items": [
{
"name": "AIM-9JULI",
"quantity": 2
},
{
"name": "SAMP 400 LD",
"quantity": 8
}
],
"roles": [
"Strike"
],
"code": "2*AIM-9JULI, 8*SAMP 400 LD",
"name": "Heavy / SAMP400 / Short Range"
},
{
"fuel": 1,
"items": [],
"roles": [
""
],
"code": "",
"name": "Empty Loadout"
}
],
"filename": "mig-25.png",
"cost": 150,
"liveryID": "iriaf 3-6215 _ 1990-2010s desert (eq variant)"
},
"Mirage-F1CE": {
"name": "Mirage-F1CE",
"coalition": "red",
"label": "Mirage-F1CE",
"era": "Mid Cold War",
"shortLabel": "F1CE",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "AIM-9JULI",
"quantity": 2
},
{
"name": "R530IR",
"quantity": 2
},
{
"name": "1137L Fuel Tank",
"quantity": 1
}
],
"roles": [
"CAP"
],
"code": "2*AIM9-JULI, 2*R530IR, 1*Fuel Tank",
"name": "Medium / Fox 2 / Medium Range"
},
{
"fuel": 1,
"items": [
{
"name": "AIM-9JULI",
"quantity": 2
},
{
"name": "SAMP 400 LD",
"quantity": 8
}
],
"roles": [
"Strike"
],
"code": "2*AIM-9JULI, 8*SAMP 400 LD",
"name": "Heavy / SAMP400 / Short Range"
},
{
"fuel": 1,
"items": [],
"roles": [
""
],
"code": "",
"name": "Empty Loadout"
}
],
"filename": "mig-25.png",
"cost": 150,
"liveryID": "iraq air force (fictional eq version)"
},
"Su-24M": {
"name": "Su-24M",
"coalition": "red",
"label": "Su-24M Fencer",
"era": "Mid Cold War",
"shortLabel": "24",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "R-60M",
"quantity": 2
},
{
"name": "FAB-1500",
"quantity": 2
}
],
"roles": [
"Strike"
],
"code": "FAB-1500*2,R-60M*2",
"name": "Heavy / FAB-500 / Short Range"
},
{
"fuel": 1,
"items": [],
"roles": [
""
],
"code": "",
"name": "Empty Loadout"
}
],
"filename": "su-24.png",
"cost": 250,
"liveryID": "iran air force"
}
}

View File

@@ -1,153 +0,0 @@
{
"BMP-1": {
"name": "BMP-1",
"coalition": "red",
"era": "Mid Cold War",
"label": "BMP-1",
"shortLabel": "BMP-1",
"filename": "",
"type": "IFV",
"cost": 10,
"liveryID": "desert"
},
"Hawk SAM Battery": {
"name": "Hawk SAM Battery",
"coalition": "blue",
"era": "Early Cold War",
"label": "Hawk SAM Battery",
"shortLabel": "Hawk SAM Battery",
"range": "Medium",
"filename": "",
"type": "SAM Site",
"cost": 500
},
"Infantry AK": {
"name": "Infantry AK",
"era": "Mid Cold War",
"label": "Infantry AK",
"shortLabel": "Infantry AK",
"filename": "",
"type": "Infantry",
"cost": 1
},
"M-113": {
"name": "M-113",
"coalition": "blue",
"era": "Early Cold War",
"label": "M-113",
"shortLabel": "M-113",
"filename": "",
"type": "APC",
"cost": 5
},
"M-60": {
"name": "M-60",
"coalition": "blue",
"era": "Early Cold War",
"label": "M-60",
"shortLabel": "M-60",
"filename": "",
"type": "Tank",
"cost": 10
},
"SA-2 SAM Battery": {
"name": "SA-2 SAM Battery",
"coalition": "red",
"era": "Early Cold War",
"label": "SA-2 SAM Battery",
"shortLabel": "SA-2 SAM Battery",
"range": "Long",
"filename": "",
"type": "SAM Site",
"cost": 500
},
"T-55": {
"name": "T-55",
"coalition": "red",
"era": "Early Cold War",
"label": "T-55",
"shortLabel": "T-55",
"filename": "",
"type": "Tank",
"cost": 10,
"liveryID": "desert"
},
"T-72B": {
"name": "T-72B",
"coalition": "red",
"era": "Mid Cold War",
"label": "T-72B",
"shortLabel": "T-72B",
"filename": "",
"type": "Tank",
"cost": 20,
"liveryID": "desert"
},
"ZSU-23-4 Shilka": {
"name": "ZSU-23-4 Shilka",
"era": "Late Cold War",
"label": "ZSU-23-4 Shilka",
"shortLabel": "ZSU-23-4 Shilka",
"filename": "",
"type": "AAA",
"cost": 100
},
"Ural-375 ZU-23": {
"name": "Ural-375 ZU-23",
"era": "Early Cold War",
"label": "Ural-375 ZU-23",
"shortLabel": "Ural-375 ZU-23",
"filename": "",
"type": "AAA",
"cost": 50
},
"SAU Gvozdika": {
"name": "SAU Gvozdika",
"coalition": "red",
"era": "Early Cold War",
"label": "SAU Gvozdika",
"shortLabel": "SAU Gvozdika",
"filename": "",
"type": "Gun Artillery",
"cost": 10,
"liveryID": "desert"
},
"Grad-URAL": {
"name": "Grad-URAL",
"coalition": "blue",
"era": "Early Cold War",
"label": "BM-21",
"shortLabel": "BM-21",
"filename": "",
"type": "Rocket Artillery",
"cost": 10
},
"Chieftain_mk3": {
"name": "Chieftain_mk3",
"coalition": "blue",
"era": "Early Cold War",
"label": "Chieftain Mk3",
"shortLabel": "Chieftain Mk3",
"filename": "",
"type": "Tank",
"cost": 20
},
"Scud_B": {
"name": "Scud_B",
"era": "Early Cold War",
"label": "SCUD",
"shortLabel": "SCUD",
"filename": "",
"type": "Rocket Artillery",
"cost": 10
},
"tt_ZU-23": {
"name": "tt_ZU-23",
"era": "Early Cold War",
"label": "Technical ZSU-23",
"shortLabel": "Technical ZSU-23",
"filename": "",
"type": "AAA",
"cost": 25
}
}

View File

@@ -1,141 +0,0 @@
{
"Mi-24P": {
"name": "Mi-24P",
"coalition": "red",
"era": "Mid Cold War",
"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",
"cost": 150,
"liveryID": "IQAF"
},
"Mi-8MT": {
"name": "Mi-8MT",
"coalition": "blue",
"era": "Mid Cold War",
"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",
"cost": 100,
"liveryID": "IR Iranian Special Police Forces"
},
"SA342M": {
"name": "SA342M",
"coalition": "blue",
"era": "Mid Cold War",
"label": "SA342M Gazelle",
"shortLabel": "342",
"loadouts": [
{
"fuel": 1,
"items": [
{
"name": "HOT3",
"quantity": 4
}
],
"roles": [
"CAS"
],
"code": "4x HOT3, IR Deflector, Sand Filter",
"name": "ATGM"
}
],
"filename": "sa-342.png",
"cost": 80
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -75,7 +75,7 @@
<path d="M232.2 261.4a3.7 3.7 0 0 1 3.7-3 3.7 3.7 0 0 1 3.6 3.7 3.8 3.8 0 0 1-1 2.6"/> <path d="M232.2 261.4a3.7 3.7 0 0 1 3.7-3 3.7 3.7 0 0 1 3.6 3.7 3.8 3.8 0 0 1-1 2.6"/>
<path d="M239.4 261.3a15.5 15.5 0 0 0 6.2-12.4c0-4.1-1.6-8.4-3.6-10"/> <path d="M239.4 261.3a15.5 15.5 0 0 0 6.2-12.4c0-4.1-1.6-8.4-3.6-10"/>
<path stroke-linecap="round" d="M244.7 259.4a16.5 16.5 0 0 1-6.3 6"/> <path stroke-linecap="round" d="M244.7 259.4a16.5 16.5 0 0 1-6.3 6"/>
<path d="M254.6 273.7c-1-2.2-2.8-3.2-5.8-3.5-3-.3-5.5.5-8.2 1.9a18.6 18.6 0 0 0-10.8 17 25 25 0 0 0 2 9.5c.9 1.6 3 9 15.3 14a86.1 86.1 0 0 0 25.7 3.9c10.4.4 20 .8 25.6 7.6"/> <path d="M254.6 273.7c-1-2.2-2.8-3.2-5.8-3.5-3-.3-5.5.5-8.2 1.9a18.6 18.6 0 0 0-10.8 17 25 25 0 0 0 2 9.5c.9 1.6 3 9 15.3 14a86.1 86.1 0 0 0 25.7 3.9c10.4.5 20 .8 25.6 7.6"/>
<path stroke-linecap="round" d="M239.7 275.9c3.3-2.2 9.5-5 15.1-2.2a8 8 0 0 1 4.3 4.4 10 10 0 0 1-1.8 9.5c-.9 1-2.7 2.6-5 2.7-3.8 0-4.7-2.6-4.8-3.2-.4-2.8 1.2-3.9 2-4.2.7-.2 2.8-.1 3.2 1.4.2.5.2 1.3-.2 2"/> <path stroke-linecap="round" d="M239.7 275.9c3.3-2.2 9.5-5 15.1-2.2a8 8 0 0 1 4.3 4.4 10 10 0 0 1-1.8 9.5c-.9 1-2.7 2.6-5 2.7-3.8 0-4.7-2.6-4.8-3.2-.4-2.8 1.2-3.9 2-4.2.7-.2 2.8-.1 3.2 1.4.2.5.2 1.3-.2 2"/>
<path d="M252.7 285.7c.3-1 .2-2.2-.8-3.3a5.1 5.1 0 0 0-6-1c-.7.5-1.6 1-2.4 2.2-.4.4-1 1.1-1.2 1.6-.7 1.1-1 2-1 2.5-2.5 7 1.5 14.4 6.5 17.6 4.4 2.8 8.8 3.6 14.4 4 2.5.3 4 .3 6.5.5h9.6a70.1 70.1 0 0 1 7.2 0c3 .3 5.1.4 7.6.8 1.6.2 3.5.5 5.4 1 .6 0 1.2.2 1.8.4l1.2.3c3.6 1.1 7 2.4 9.8 4.2.8.5 1.8 1 2.5 1.7l1.3 1.2c2 2 4 4 4.4 6.7v1.6c0 1.8-1.4 4.3-5.3 5"/> <path d="M252.7 285.7c.3-1 .2-2.2-.8-3.3a5.1 5.1 0 0 0-6-1c-.7.5-1.6 1-2.4 2.2-.4.4-1 1.1-1.2 1.6-.7 1.1-1 2-1 2.5-2.5 7 1.5 14.4 6.5 17.6 4.4 2.8 8.8 3.6 14.4 4 2.5.3 4 .3 6.5.5h9.6a70.1 70.1 0 0 1 7.2 0c3 .3 5.1.4 7.6.8 1.6.2 3.5.5 5.4 1 .6 0 1.2.2 1.8.4l1.2.3c3.6 1.1 7 2.4 9.8 4.2.8.5 1.8 1 2.5 1.7l1.3 1.2c2 2 4 4 4.4 6.7v1.6c0 1.8-1.4 4.3-5.3 5"/>
<path d="M298.6 328.4c-1 2.2.2 3.2 1.6 3.4 2.2.3 3.3-1.4 3.5-3a4.4 4.4 0 0 0-4.4-4.7 5.5 5.5 0 0 0-5 3.5 6.9 6.9 0 0 0-.5 2.4 5.8 5.8 0 0 0 1.4 4.1 7.5 7.5 0 0 0 5.4 2.5c4.2.1 7.5-3.8 7.5-7.8 0-7.7-11.4-12-16-13a84 84 0 0 0-17.9-2.4c-3.5-.1-6.2 0-10.1-.5-3.5-.3-5.4-.5-9-1.3a27.2 27.2 0 0 1-12.5-6.4 17 17 0 0 1-4.7-22 14.3 14.3 0 0 1 10.3-6.9c3.8-.5 7 1.1 9 4.8 1 1.8.6 4.8-.1 6.2a6 6 0 0 1-4.8 3c-3.8 0-4.7-2.6-4.8-3.2-.4-2.8 1.2-3.9 2-4.2.7-.2 2.8-.1 3.2 1.4.2.5.2 1.3-.2 2"/> <path d="M298.6 328.4c-1 2.2.2 3.2 1.6 3.4 2.2.3 3.3-1.4 3.5-3a4.4 4.4 0 0 0-4.4-4.7 5.5 5.5 0 0 0-5 3.5 6.9 6.9 0 0 0-.5 2.4 5.8 5.8 0 0 0 1.4 4.1 7.5 7.5 0 0 0 5.4 2.5c4.2.1 7.5-3.8 7.5-7.8 0-7.7-11.4-12-16-13a84 84 0 0 0-17.9-2.4c-3.5-.1-6.2 0-10.1-.5-3.5-.3-5.4-.5-9-1.3a27.2 27.2 0 0 1-12.5-6.4 17 17 0 0 1-4.7-22 14.3 14.3 0 0 1 10.3-6.9c3.8-.5 7 1.1 9 4.8 1 1.8.6 4.8-.1 6.2a6 6 0 0 1-4.8 3c-3.8 0-4.7-2.6-4.8-3.2-.4-2.8 1.2-3.9 2-4.2.7-.2 2.8-.1 3.2 1.4.2.5.2 1.3-.2 2"/>

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
width="640"
height="480"
id="svg10"
sodipodi:docname="blue.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"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
id="namedview10"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="0.88166667"
inkscape:cx="497.3535"
inkscape:cy="301.13421"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg10"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata16">
<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="defs14" />
<path
fill="#bc0000"
fill-opacity="1"
d="M 0,0 H 640 V 480 H 0 Z"
id="path2"
style="fill:#0000cd;fill-opacity:1;stroke-width:0.999996" />
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1,84 +1,556 @@
{ {
"RED": "AGGRESSORS", "AGGRESSORS": {
"INS": "INSURGENTS", "flagCode": "RED",
"DZ" : "ALGERIA", "liveryCodes": [
"AR" : "ARGENTINA", "RSO"
"AU" : "AUSTRALIA", ]
"AT" : "AUSTRIA", },
"BH" : "BAHRAIN", "INSURGENTS": {
"BY" : "BELARUS", "flagCode": "UNK",
"BE" : "BELGIUM", "liveryCodes": [
"BO" : "BOLIVIA", "INS"
"BR" : "BRAZIL", ]
"BG" : "BULGARIA", },
"CA" : "CANADA", "ALGERIA": {
"CL" : "CHILE", "flagCode": "DZ",
"CN" : "CHINA", "liveryCodes": [
"HR" : "CROATIA", "DZA"
"CU" : "CUBA", ]
"CY" : "CYPRUS", },
"CZ" : "CHEZH_REPUBLIC", "ARGENTINA": {
"DK" : "DENMARK", "flagCode": "AR",
"EG" : "EGYPT", "liveryCodes": [
"ET" : "ETHIOPIA", "ARG"
"FI" : "FINLAND", ]
"FR" : "FRANCE", },
"GE" : "GEORGIA", "AUSTRALIA": {
"DE" : "GERMANY", "flagCode": "AU",
"GH" : "GHANA", "liveryCodes": [
"GI" : "Gibraltar", "AUS",
"GR" : "GREECE", "AUSAF"
"HN" : "HONDURAS", ]
"HU" : "HUNGARY", },
"IS" : "Iceland", "AUSTRIA": {
"IN" : "INDIA", "flagCode": "AT",
"ID" : "INDONESIA", "liveryCodes": [
"IR" : "IRAN", "AUT"
"IQ" : "IRAQ", ]
"IE" : "Ireland", },
"IM" : "Isle Of Man", "BAHRAIN": {
"IL" : "ISRAEL", "flagCode": "BH",
"IT" : "ITALY", "liveryCodes": [
"JP" : "JAPAN", "BHR"
"JO" : "JORDAN", ]
"KZ" : "KAZAKHSTAN", },
"KR" : "SOUTH_KOREA", "BELARUS": {
"KW" : "KUWAIT", "flagCode": "BY",
"LB" : "LEBANON", "liveryCodes": [
"LY" : "LIBYIA", "BLR"
"MY" : "MALAYSIA", ]
"MX" : "MEXICO", },
"MA" : "MOROCCO", "BELGIUM": {
"NL" : "THE_NETHERLANDS", "flagCode": "BE",
"NG" : "NIGERIA", "liveryCodes": [
"NO" : "NORWAY", "BEL"
"OM" : "OMAN", ]
"PK" : "PAKISTAN", },
"PE" : "PERU", "BOLIVIA": {
"PH" : "PHILIPPINES", "flagCode": "BO",
"PL" : "POLAND", "liveryCodes": [
"PT" : "PORTUGAL", "BOL"
"QA" : "QATAR", ]
"RO" : "ROMANIA", },
"RU" : "RUSSIA", "BRAZIL": {
"SA" : "SAUDI ARABIA", "flagCode": "BR",
"RS" : "SERBIA", "liveryCodes": [
"SK" : "SLOVAKIA", "BRA"
"SI" : "SLOVENIA", ]
"ZA" : "SOUTH AFRICA", },
"ES" : "SPAIN", "BULGARIA": {
"SD" : "SUDAN", "flagCode": "BG",
"SE" : "SWEDEN", "liveryCodes": [
"CH" : "SWITZERLAND", "BGR"
"SY" : "SYRIA", ]
"TH" : "THAILAND", },
"TN" : "TUNISIA", "CANADA": {
"TR" : "TURKEY", "flagCode": "CA",
"UA" : "UKRAINE", "liveryCodes": [
"AE" : "UNITED ARAB EMIRATES", "CAN"
"GB" : "UK", ]
"US" : "USA", },
"VE" : "VENEZUELA", "CHILE": {
"VN" : "VIETNAM", "flagCode": "CL",
"YE" : "YEMEN" "liveryCodes": [
"CHL"
]
},
"CHINA": {
"flagCode": "CN",
"liveryCodes": [
"CHN"
]
},
"CROATIA": {
"flagCode": "HR",
"liveryCodes": [
"HRV"
]
},
"CUBA": {
"flagCode": "CU",
"liveryCodes": [
"CUB"
]
},
"CYPRUS": {
"flagCode": "CY",
"liveryCodes": [
"CYP"
]
},
"CHEZH_REPUBLIC": {
"displayName": "Czech Republic",
"flagCode": "CZ",
"liveryCodes": [
"CZE"
]
},
"DENMARK": {
"flagCode": "DK",
"liveryCodes": [
"DEN"
]
},
"EGYPT": {
"flagCode": "EG",
"liveryCodes": [
"EGY",
"EGP"
]
},
"ETHIOPIA": {
"flagCode": "ET",
"liveryCodes": [
"ETH"
]
},
"FINLAND": {
"flagCode": "FI",
"liveryCodes": [
"FIN"
]
},
"FRANCE": {
"flagCode": "FR",
"liveryCodes": [
"FRA"
]
},
"GEORGIA": {
"flagCode": "GE",
"liveryCodes": [
"GRG"
]
},
"GERMANY": {
"flagCode": "DE",
"liveryCodes": [
"GER"
]
},
"GHANA": {
"flagCode": "GH",
"liveryCodes": [
"GHA"
]
},
"GREECE": {
"flagCode": "GR",
"liveryCodes": [
"GRC"
]
},
"HONDURAS": {
"flagCode": "HN",
"liveryCodes": [
"HND"
]
},
"HUNGARY": {
"flagCode": "HU",
"liveryCodes": [
"HUN"
]
},
"INDIA": {
"flagCode": "IN",
"liveryCodes": [
"IND"
]
},
"INDONESIA": {
"flagCode": "ID",
"liveryCodes": [
"IDN"
]
},
"IRAN": {
"flagCode": "IR",
"liveryCodes": [
"IRN"
]
},
"IRAQ": {
"flagCode": "IQ",
"liveryCodes": [
"IRQ"
]
},
"ISRAEL": {
"flagCode": "IL",
"liveryCodes": [
"ISR"
]
},
"ITALY": {
"flagCode": "IT",
"liveryCodes": [
"ITA"
]
},
"JAPAN": {
"flagCode": "JP",
"liveryCodes": [
"JPN"
]
},
"JORDAN": {
"flagCode": "JO",
"liveryCodes": [
"JOR"
]
},
"KAZAKHSTAN": {
"flagCode": "KZ",
"liveryCodes": [
"KAZ"
]
},
"SOUTH_KOREA": {
"displayName": "South Korea",
"flagCode": "KR",
"liveryCodes": [
"KOR"
]
},
"KUWAIT": {
"flagCode": "KW",
"liveryCodes": [
"KWT"
]
},
"LEBANON": {
"flagCode": "LB",
"liveryCodes": [
"LBN"
]
},
"MALAYSIA": {
"flagCode": "MY",
"liveryCodes": [
"MYS"
]
},
"MEXICO": {
"flagCode": "MX",
"liveryCodes": [
"MEX"
]
},
"MOROCCO": {
"flagCode": "MA",
"liveryCodes": [
"MAR"
]
},
"THE_NETHERLANDS": {
"displayName": "The Netherlands",
"flagCode": "NL",
"liveryCodes": [
"NETH"
]
},
"NIGERIA": {
"flagCode": "NG",
"liveryCodes": [
"NGA"
]
},
"NORWAY": {
"flagCode": "NO",
"liveryCodes": [
"NOR"
]
},
"OMAN": {
"flagCode": "OM",
"liveryCodes": [
"OMN"
]
},
"PAKISTAN": {
"flagCode": "PK",
"liveryCodes": [
"PAK"
]
},
"PERU": {
"flagCode": "PE",
"liveryCodes": [
"PER"
]
},
"PHILIPPINES": {
"flagCode": "PH",
"liveryCodes": [
"PHL"
]
},
"POLAND": {
"flagCode": "PL",
"liveryCodes": [
"POL"
]
},
"PORTUGAL": {
"flagCode": "PT",
"liveryCodes": [
"PRT"
]
},
"QATAR": {
"flagCode": "QA",
"liveryCodes": [
"QAT"
]
},
"ROMANIA": {
"flagCode": "RO",
"liveryCodes": [
"ROU"
]
},
"RUSSIA": {
"flagCode": "RU",
"liveryCodes": [
"RUS"
]
},
"SAUDI_ARABIA": {
"displayName": "Saudi Arabia",
"flagCode": "SA",
"liveryCodes": [
"SAU"
]
},
"SERBIA": {
"flagCode": "RS",
"liveryCodes": [
"SRB"
]
},
"SLOVAKIA": {
"flagCode": "SK",
"liveryCodes": [
"SVK"
]
},
"SLOVENIA": {
"flagCode": "SI",
"liveryCodes": [
"SVN"
]
},
"SOUTH_AFRICA": {
"displayName": "South Africa",
"flagCode": "ZA",
"liveryCodes": []
},
"SPAIN": {
"flagCode": "ES",
"liveryCodes": [
"SPN",
"SPA"
]
},
"SUDAN": {
"flagCode": "SD",
"liveryCodes": [
"SDN",
"SUN"
]
},
"SWEDEN": {
"flagCode": "SE",
"liveryCodes": [
"SWE"
]
},
"SWITZERLAND": {
"flagCode": "CH",
"liveryCodes": [
"SUI"
]
},
"SYRIA": {
"flagCode": "SY",
"liveryCodes": [
"SYR"
]
},
"THAILAND": {
"flagCode": "TH",
"liveryCodes": [
"THA"
]
},
"TUNISIA": {
"flagCode": "TN",
"liveryCodes": [
"TUN"
]
},
"TURKEY": {
"flagCode": "TR",
"liveryCodes": [
"TUR"
]
},
"UKRAINE": {
"flagCode": "UA",
"liveryCodes": [
"UKR"
]
},
"UNITED_ARAB_EMIRATES": {
"displayName": "United Arab Emirates",
"flagCode": "AE",
"liveryCodes": [
"ARE"
]
},
"UK": {
"displayName": "United Kingdom",
"flagCode": "GB",
"liveryCodes": [
"UK"
]
},
"USA": {
"displayName": "United States of America",
"flagCode": "US",
"liveryCodes": [
"USA",
"USAF"
]
},
"VENEZUELA": {
"flagCode": "VE",
"liveryCodes": [
"VEN"
]
},
"VIETNAM": {
"flagCode": "VN",
"liveryCodes": [
"VNM"
]
},
"YEMEN": {
"flagCode": "YE",
"liveryCodes": [
"YEM"
]
},
"CJTF_BLUE": {
"displayName": "Combined Joint Task Force Blue",
"flagCode": "BLUE",
"liveryCodes": [
"BLUE"
]
},
"SOUTH_OSETIA": {
"displayName": "South Ossetia",
"flagCode": "UNK",
"liveryCodes": []
},
"NORTH_KOREA": {
"displayName": "Democratic People's Republic of Korea",
"flagCode": "KP",
"liveryCodes": [
"PRK"
]
},
"CJTF_RED": {
"displayName": "Combined Joint Task Force Red",
"flagCode": "RED",
"liveryCodes": [
"RED"
]
},
"ABKHAZIA": {
"flagCode": "UNK",
"liveryCodes": [
"ABH"
]
},
"ITALIAN_SOCIAL_REPUBLIC": {
"displayName": "Italian Social Republic",
"flagCode": "SOCIAL",
"liveryCodes": [
"RSI"
]
},
"USSR": {
"displayName": "USSR",
"flagCode": "USSR",
"liveryCodes": []
},
"ECUADOR": {
"flagCode": "EC",
"liveryCodes": [
"ECU"
]
},
"LIBYA": {
"flagCode": "LY",
"liveryCodes": [
"LBY",
"LIB"
]
},
"UN_PEACEKEEPERS": {
"displayName": "United Nations",
"flagCode": "UNK",
"liveryCodes": [
"UN"
]
},
"GDR": {
"flagCode": "UNK",
"liveryCodes": [
"GDR"
]
},
"YUGOSLAVIA": {
"flagCode": "YUG",
"liveryCodes": [
"YUG"
]
},
"THIRDREICH": {
"displayName": "Third Reich",
"flagCode": "THIRD",
"liveryCodes": []
}
} }

View File

@@ -216,7 +216,7 @@
<g stroke="#d4af37" stroke-width=".9"> <g stroke="#d4af37" stroke-width=".9">
<path fill="#fff" d="M367.7 432.4c-1.5.5-2.5 1-9 .5-4.6-.3-10.3-1.1-13.2-1.2-5.6 0-5.6.3-15.5 7.1-7 4.8-16 4.4-22.7 3-4-2-5.8-2.3-5.2-1.3 1.1 1.8 9 4.4 13.4 4.4 7 0 12.2-1.8 20.7-7.1 6.6-4.2 9.5-4.5 18.5-2.5 10.6 2.1 12.2 1.2 20.9-2.7-2.6 0-3.2 0-4 .4 1.4-1.6 1.5-3.2 1.8-4.2.4-.6-.8.2-2.1 1.2l-3.6 2.4z" transform="matrix(.59548 0 0 .58466 141.4 62.9)"/> <path fill="#fff" d="M367.7 432.4c-1.5.5-2.5 1-9 .5-4.6-.3-10.3-1.1-13.2-1.2-5.6 0-5.6.3-15.5 7.1-7 4.8-16 4.4-22.7 3-4-2-5.8-2.3-5.2-1.3 1.1 1.8 9 4.4 13.4 4.4 7 0 12.2-1.8 20.7-7.1 6.6-4.2 9.5-4.5 18.5-2.5 10.6 2.1 12.2 1.2 20.9-2.7-2.6 0-3.2 0-4 .4 1.4-1.6 1.5-3.2 1.8-4.2.4-.6-.8.2-2.1 1.2l-3.6 2.4z" transform="matrix(.59548 0 0 .58466 141.4 62.9)"/>
<path fill="#d91023" d="M354 429.8c-4.9-.7-8.2-1.4-11.3-1-3.4.3-5.8 2-9.9 4.5-4 2.7-7.7 4.6-8.1 4.6-.6 0-5.8 1.2-9.8 1.2-1.8 0-5.9-1.3-8.6-2.3-5.7-2.1-7.8 1.4-1.8 3.9a33.4 33.4 0 0 0 15.6 1.8c5-.8 9.6-3 13.4-5.8 7.7-5.6 3.2-3 6.2-4.2 3-1.3 5.9-.9 5.9-.9 4 .2 11.9 1.5 15.9 1.6 7.2-.7 6-.7 8.4-2 .8-.6 3.5-2.3 3.6-2.7.2-.4 1.4-2.7 1.2-2.8-7.5 5.1-11.2 5.1-20.7 4.1z" transform="matrix(.59548 0 0 .58466 141.4 62.9)"/> <path fill="#d91023" d="M354 429.8c-4.9-.7-8.2-1.4-11.3-1-3.4.3-5.8 2-9.9 4.5-4 2.7-7.7 4.6-8.1 4.6-.6 0-5.8 1.2-9.8 1.2-1.8 0-5.9-1.3-8.6-2.3-5.7-2.1-7.8 1.4-1.8 3.9a33.4 33.4 0 0 0 15.6 1.8c5-.8 9.6-3 13.4-5.8 7.7-5.6 3.2-3 6.2-4.2 3-1.3 5.9-.9 5.9-.9 4 .2 11.9 1.5 15.9 1.6 7.2-.7 6-.7 8.4-2 .8-.6 3.5-2.3 3.6-2.7.2-.4 1.4-2.7 1.2-2.8-7.5 5.1-11.2 5.1-20.7 4.1z" transform="matrix(.59548 0 0 .58466 141.4 62.9)"/>
<path fill="#d91023" d="m341 435.4-7.1 4c-6.2 3.8-12 5.6-18.8 5.6-3 .5-13-3.6-11.5-3.1 1.6 3 4 3.4 9.6 4.5 4 .8 6.6.1 11.1-.8 5-.6 7-3 9-4.3a33.5 33.5 0 0 1 14-5.4c1 0 4.7 2.1 8.9 3 4.1.9 6.1 1.1 10.4.4s8.7-4.2 12.8-6.9c-.6.2-2 .2-4 .3-6 3.5-16 4.8-21.2 2.4-5.4-1.3-10.5-1-13.2.3z" transform="matrix(.59548 0 0 .58466 141.4 62.9)"/> <path fill="#d91023" d="m341 435.4-7.1 4c-6.2 3.8-12 5.6-18.8 5.6-3 .5-13-3.6-11.5-3.1 1.6 3 4 3.4 9.6 4.5 4 .8 6.6.1 11.1-.8 5-.6 7-3 9-4.3a33.5 33.5 0 0 1 14-5.4c1 0 4.7 2.1 8.9 3 4.1.9 6.1 1.1 10.4.5s8.7-4.2 12.8-6.9c-.6.2-2 .2-4 .3-6 3.5-16 4.8-21.2 2.4-5.4-1.3-10.5-1-13.2.3z" transform="matrix(.59548 0 0 .58466 141.4 62.9)"/>
</g> </g>
<path fill="#00a854" d="M276.4 176.3a37.7 37.7 0 0 0-17.5 13.2c-1 1.2-1.8 2.2-1.9 2.1 0 0 .4-2.7 1.2-5.7.7-3 1.2-6.1 1.2-6.8 0-1.2-.1-1.1-2 1a41 41 0 0 0-7 13c-.7 2.2-1 4.7-1 9.3l.1 6.3-1.2-4.5c-1.3-4.7-2.6-8-4-9.6-.6-1-.8-1-1.3-.3-1 1.5-.3 7.8 1.4 12.4.1.6-.5-.2-1.4-1.7-1-1.6-2-2.7-2.3-2.6-.6.3-.6 5.3 0 7.4.4 1.4.4 1.4-1.3-.5-2.9-3.3-3.5-3.6-3.5-1.3 0 .9.3 2.4.7 3.4l.8 2-1.6.4c-2.3.4-3 1.1-3 3 0 2 1.4 6.8 2 7.2.9.5 1.1 0 1.8-3l.6-2.6 1.9 2.5a76.7 76.7 0 0 1 8.8 17.7c2.2 6.4 2.3 7.7.3 3.7a72 72 0 0 0-3.2-5.2c-2-2.8-12.6-13.9-13.3-13.9-.8 0 0 3.5 1.3 6.4.7 1.4 2.7 4.2 4.4 6.2l2.9 3.6c-.2 0-1.4-.8-2.7-1.7-2.6-2-5.3-3.5-5.6-3.2-.1.1.9 2.3 2.3 4.8l2.4 4.6-1.6-.3a6 6 0 0 0-2.8.3c-1 .6-1 1.1-1 3.5 0 3.3.8 6.7 1.5 6.7.8 0 2-3.2 2-4.9 0-1.3 0-1.3 2.6 1.1 3.7 3.6 8.6 9.6 13.4 16.6l4 6-4.7-3.6c-4.6-3.3-14-8.6-15.5-8.6-.4 0-.8.2-.8.5 0 .2 3 3.3 6.7 6.8l6.7 6.3-3.5-1.1a71 71 0 0 0-5.3-1.5c-1.7-.4-1.7-.3 2.2 3.3a68 68 0 0 0 8.7 6.7c2.6 1.6 4.3 2.8 3.7 2.7a35.1 35.1 0 0 0-11.5-1.9c0 .7 3.5 3.5 6 4.8 1.4.7 5 2 7.8 3 6 2.1 9.6 4 12.6 6.6l2 1.9-3.5-1.6c-4.1-1.8-15.3-5.5-16.5-5.5s3.8 5 8.8 8.7a80.2 80.2 0 0 0 19.5 9.7c5.2 1.7 9.6 2.6 18 3.6 3.6.5 7 1 7.8 1.3.6.3 5 1 10 1.5a99.7 99.7 0 0 1 30.7 7.2c1.7.8 3.5 1.1 7.2 1.3 5.5.3 5.8.1 4.2-2.9-1.3-2.5-3.7-3.9-8.7-4.8l-9.2-1.8a726.1 726.1 0 0 0-29-5c-14-2.3-20.1-4.7-26.7-10.7A43.3 43.3 0 0 1 269 263c.4-3 .6-5.5.5-5.6-.5-.4-3.7 6.3-4.6 9.4l-1 3.3.3-5.4c.3-8.3 3.5-16.1 8.2-20.6 1-1 1.8-2 1.8-2.2 0-.2-1 0-2.1.2-1.6.4-3 1.3-5 3.2l-2.6 2.7 1.3-2.4a27 27 0 0 1 8.3-9.6l2.9-1.9-1.7-.1c-3.4-.4-9.5 4-12.9 9.3-2 3-2 2.1 0-2.6a41.8 41.8 0 0 1 8-12.5c1.9-1.8 2.2-2.5 1.5-2.5-2.7 0-7.2 3.5-11 8.4-1 1.5-1 1.4.2-1.5a40 40 0 0 1 6.1-9.7c1.6-1.9 1.2-2.1-1.5-1a26.4 26.4 0 0 0-8.6 9.7c-1 2-1.8 3-1.7 2.5a61 61 0 0 0 .8-3.3 46.4 46.4 0 0 1 12.8-22.7c2.4-2.2 3-3.2 2.3-3.2-2 0-6.5 2.6-9.5 5.5-3.1 3-3.2 3-2 .9a57 57 0 0 1 18.3-18.6l4.3-3c0-.8-7.8 1.6-11.3 3.3a42.3 42.3 0 0 0-4.4 3.2c-2.5 2-2.7 2.1-1.8.8 1.7-2.4 7.6-7.7 10-8.9 1.7-.9 2-1.2 1-1.3-2.3-.4-8.9 3-14 7.4l-2.2 1.9 1.2-2a48 48 0 0 1 14.7-15.6 60.5 60.5 0 0 1 4.4-2.6c.3-.1.5-.4.4-.5-.2-.2-2 .2-4 1zm77 145a6 6 0 0 1 1.4 1.9c0 .2-1.1.4-2.5.4-2.5 0-2.6 0-2.6-1.4 0-2.6 1.6-2.9 3.8-.8z"/> <path fill="#00a854" d="M276.4 176.3a37.7 37.7 0 0 0-17.5 13.2c-1 1.2-1.8 2.2-1.9 2.1 0 0 .4-2.7 1.2-5.7.7-3 1.2-6.1 1.2-6.8 0-1.2-.1-1.1-2 1a41 41 0 0 0-7 13c-.7 2.2-1 4.7-1 9.3l.1 6.3-1.2-4.5c-1.3-4.7-2.6-8-4-9.6-.6-1-.8-1-1.3-.3-1 1.5-.3 7.8 1.4 12.4.1.6-.5-.2-1.4-1.7-1-1.6-2-2.7-2.3-2.6-.6.3-.6 5.3 0 7.4.4 1.4.4 1.4-1.3-.5-2.9-3.3-3.5-3.6-3.5-1.3 0 .9.3 2.4.7 3.4l.8 2-1.6.4c-2.3.4-3 1.1-3 3 0 2 1.4 6.8 2 7.2.9.5 1.1 0 1.8-3l.6-2.6 1.9 2.5a76.7 76.7 0 0 1 8.8 17.7c2.2 6.4 2.3 7.7.3 3.7a72 72 0 0 0-3.2-5.2c-2-2.8-12.6-13.9-13.3-13.9-.8 0 0 3.5 1.3 6.4.7 1.4 2.7 4.2 4.4 6.2l2.9 3.6c-.2 0-1.4-.8-2.7-1.7-2.6-2-5.3-3.5-5.6-3.2-.1.1.9 2.3 2.3 4.8l2.4 4.6-1.6-.3a6 6 0 0 0-2.8.3c-1 .6-1 1.1-1 3.5 0 3.3.8 6.7 1.5 6.7.8 0 2-3.2 2-4.9 0-1.3 0-1.3 2.6 1.1 3.7 3.6 8.6 9.6 13.4 16.6l4 6-4.7-3.6c-4.6-3.3-14-8.6-15.5-8.6-.4 0-.8.2-.8.5 0 .2 3 3.3 6.7 6.8l6.7 6.3-3.5-1.1a71 71 0 0 0-5.3-1.5c-1.7-.4-1.7-.3 2.2 3.3a68 68 0 0 0 8.7 6.7c2.6 1.6 4.3 2.8 3.7 2.7a35.1 35.1 0 0 0-11.5-1.9c0 .7 3.5 3.5 6 4.8 1.4.7 5 2 7.8 3 6 2.1 9.6 4 12.6 6.6l2 1.9-3.5-1.6c-4.1-1.8-15.3-5.5-16.5-5.5s3.8 5 8.8 8.7a80.2 80.2 0 0 0 19.5 9.7c5.2 1.7 9.6 2.6 18 3.6 3.6.5 7 1 7.8 1.3.6.3 5 1 10 1.5a99.7 99.7 0 0 1 30.7 7.2c1.7.8 3.5 1.1 7.2 1.3 5.5.3 5.8.1 4.2-2.9-1.3-2.5-3.7-3.9-8.7-4.8l-9.2-1.8a726.1 726.1 0 0 0-29-5c-14-2.3-20.1-4.7-26.7-10.7A43.3 43.3 0 0 1 269 263c.4-3 .6-5.5.5-5.6-.5-.4-3.7 6.3-4.6 9.4l-1 3.3.3-5.4c.3-8.3 3.5-16.1 8.2-20.6 1-1 1.8-2 1.8-2.2 0-.2-1 0-2.1.2-1.6.4-3 1.3-5 3.2l-2.6 2.7 1.3-2.4a27 27 0 0 1 8.3-9.6l2.9-1.9-1.7-.1c-3.4-.4-9.5 4-12.9 9.3-2 3-2 2.1 0-2.6a41.8 41.8 0 0 1 8-12.5c1.9-1.8 2.2-2.5 1.5-2.5-2.7 0-7.2 3.5-11 8.4-1 1.5-1 1.4.2-1.5a40 40 0 0 1 6.1-9.7c1.6-1.9 1.2-2.1-1.5-1a26.4 26.4 0 0 0-8.6 9.7c-1 2-1.8 3-1.7 2.5a61 61 0 0 0 .8-3.3 46.4 46.4 0 0 1 12.8-22.7c2.4-2.2 3-3.2 2.3-3.2-2 0-6.5 2.6-9.5 5.5-3.1 3-3.2 3-2 .9a57 57 0 0 1 18.3-18.6l4.3-3c0-.8-7.8 1.6-11.3 3.3a42.3 42.3 0 0 0-4.4 3.2c-2.5 2-2.7 2.1-1.8.8 1.7-2.4 7.6-7.7 10-8.9 1.7-.9 2-1.2 1-1.3-2.3-.4-8.9 3-14 7.4l-2.2 1.9 1.2-2a48 48 0 0 1 14.7-15.6 60.5 60.5 0 0 1 4.4-2.6c.3-.1.5-.4.4-.5-.2-.2-2 .2-4 1zm77 145a6 6 0 0 1 1.4 1.9c0 .2-1.1.4-2.5.4-2.5 0-2.6 0-2.6-1.4 0-2.6 1.6-2.9 3.8-.8z"/>
<path fill="#9eab05" d="M350.3 320.5c-1.3 1.2-1 3 .3 3.4 2.2.6 5 .4 5-.4s-3.3-3.8-4.1-3.8c-.3 0-.8.3-1.2.8z"/> <path fill="#9eab05" d="M350.3 320.5c-1.3 1.2-1 3 .3 3.4 2.2.6 5 .4 5-.4s-3.3-3.8-4.1-3.8c-.3 0-.8.3-1.2.8z"/>

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
width="640"
height="480"
id="svg10"
sodipodi:docname="red.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"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
id="namedview10"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="0.88166667"
inkscape:cx="497.3535"
inkscape:cy="301.13421"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg10"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata16">
<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="defs14" />
<path
fill="#bc0000"
fill-opacity="1"
d="M 0,0 H 640 V 480 H 0 Z"
id="path2"
style="fill:#cc0000;fill-opacity:1;stroke-width:0.999996" />
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 50 KiB

View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.0"
width="640"
height="480"
viewBox="0 0 640 480"
id="svg8"
sodipodi:docname="third.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="defs12" />
<sodipodi:namedview
id="namedview10"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
width="640px"
inkscape:zoom="1.058"
inkscape:cx="284.97164"
inkscape:cy="274.57467"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<rect
width="640"
height="480"
fill="#dd0000"
id="rect2"
x="0"
y="0"
style="stroke-width:0.999997" />
<circle
cx="320"
cy="240"
r="180"
fill="#ffffff"
id="circle4"
style="stroke-width:1" />
<path
d="M 472.73507,256.97056 387.88225,172.11774 252.11775,307.88225 167.26494,223.02943 M 336.97057,87.264932 252.11775,172.11774 387.88225,307.88225 303.02944,392.73506"
fill="none"
stroke="#000000"
stroke-width="48"
id="path6" />
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
width="640"
height="480"
id="svg10"
sodipodi:docname="unk.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"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
id="namedview10"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="0.88166667"
inkscape:cx="497.3535"
inkscape:cy="300"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg10"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata16">
<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="defs14" />
<path
fill="#bc0000"
fill-opacity="1"
d="M 0,0 H 640 V 480 H 0 Z"
id="path2"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.999996" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:549.6px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1"
x="179.23065"
y="424.19662"
id="text2551"><tspan
sodipodi:role="line"
id="tspan2549"
x="179.23065"
y="424.19662"
style="stroke-width:1">?</tspan></text>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
width="640"
height="480"
id="svg10"
sodipodi:docname="ussr.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"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
id="namedview10"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="0.88166667"
inkscape:cx="497.3535"
inkscape:cy="300"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg10" />
<metadata
id="metadata16">
<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="defs14" />
<path
fill="#bc0000"
fill-opacity="1"
d="M 0,0 H 639.99998 V 480 H 0 Z"
id="path2"
style="fill:#cc0000;fill-opacity:1;stroke-width:0.999997" />
<path
id="path11728"
d="m 160.0004,30 -6.73546,20.729509 H 131.4688 L 149.10222,63.540898 142.36675,84.2704 160.0004,71.458772 177.63406,84.2704 170.89859,63.540898 188.532,50.729509 h -21.79613 z m 0,10.79999 4.31062,13.266778 h 13.94975 l -11.2856,8.199597 4.31061,13.266777 -11.28538,-8.199363 -11.28538,8.199363 4.31062,-13.266777 -11.28561,-8.199597 h 13.94975 z"
style="fill:#ffd700;fill-opacity:1;stroke:none;stroke-width:0.15px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<g
style="fill:#ffd700;fill-opacity:1;stroke-width:1.25"
id="g2900"
transform="matrix(0.79145503,0,0,0.78939049,3.0638126,3.0127518)">
<path
id="rect4165-6"
d="m 137.43744,171.69421 18.86296,18.9937 17.78834,-17.66589 c 27.05847,29.021 55.43807,56.99501 82.28704,86.12782 4.03444,4.06233 10.59815,4.085 14.66056,0.0506 4.06232,-4.03445 4.08499,-10.59815 0.0506,-14.66056 -28.81871,-27.1901 -57.72545,-54.60143 -86.55328,-81.89095 l 23.96499,-23.80003 -33.34026,-4.61605 z"
style="fill:#ffd700;fill-opacity:1;stroke:none;stroke-width:0.611489;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<path
id="path4179-3"
d="m 198.2887,110.1955 c 15.51743,8.7394 27.29872,21.28122 34.2484,34.3924 7.04394,13.28902 10.13959,27.16218 10.20325,38.25433 0.13054,22.74374 -18.43771,41.18184 -41.18183,41.18184 -12.13597,0 -23.04607,-5.24868 -30.58302,-13.60085 l -4.16863,3.51033 c -0.70999,-0.27231 -1.46387,-0.41221 -2.22429,-0.41276 -1.82948,1.9e-4 -3.56621,0.80531 -4.74859,2.20136 -2.97368,0.38896 -5.46251,2.44529 -6.40534,5.29224 -3.13486,6.28843 -8.63524,11.21997 -15.29104,13.4776 -0.0637,0.0216 -0.11992,0.05 -0.1758,0.0783 -3.07749,1.12758 -6.16259,3.1643 -8.78919,5.80245 -5.19155,5.23656 -7.72858,11.93658 -6.30024,16.63822 -0.14098,0.40857 -0.21361,0.83759 -0.21498,1.26979 1.5e-4,2.17082 1.75991,3.93058 3.93073,3.93073 0.54341,-0.002 1.08053,-0.11639 1.57745,-0.33632 4.69369,1.05881 11.06885,-1.54582 16.05444,-6.55917 2.82624,-2.85072 4.94356,-6.22349 5.98303,-9.53062 2.31696,-6.62278 7.29699,-12.01856 13.62281,-15.05312 0.15105,-0.0725 0.27303,-0.14714 0.38218,-0.22358 2.12082,-1.01408 3.67251,-2.92895 4.225,-5.2139 9.70222,11.44481 24.25255,18.75299 40.51876,19.13577 29.83352,0.70205 52.13299,-21.25802 53.16414,-52.83642 0.51894,-15.89259 -5.62993,-36.3847 -19.6412,-53.19089 -10.70835,-12.84441 -26.40987,-23.50795 -44.18699,-28.20777 z"
style="fill:#ffd700;fill-opacity:1;stroke:none;stroke-width:0.625044;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 640 480"
version="1.1"
id="svg8"
sodipodi:docname="yug.svg"
width="640"
height="480"
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="defs12" />
<sodipodi:namedview
id="namedview10"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="0.91840278"
inkscape:cx="253.1569"
inkscape:cy="286.91115"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<path
fill="#dd0000"
d="M 0,320 H 640 V 480 H 0"
id="path2"
style="stroke-width:0.999996" />
<path
fill="#ffffff"
d="M 0,160 H 640 V 320 H 0"
id="path4"
style="stroke-width:0.999996" />
<path
fill="#003893"
d="M 0,0 H 640 V 160 H 0"
id="path6"
style="stroke-width:0.999996" />
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,16 @@
{
"name": "DCS Olympus",
"short_name": "DCS Olympus",
"icons": [{
"src": "/images/favicons/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
}, {
"src": "/images/favicons/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}

View File

@@ -1,194 +0,0 @@
/**************************************/
.olympus-dialog {
align-self: center;
background:white;
border-radius: 10px;
display: flex;
flex-direction: column;
justify-self: center;
padding:10px;
position:absolute;
width:fit-content;
z-index: 9999;
}
.olympus-dialog-close {
cursor:pointer;
position:absolute;
right:10px;
top:5px;
}
.olympus-dialog-header {
font-weight:bold;
}
/**************************************/
/***** AIC *****/
.aic-panel {
z-index: 9999;
}
#aic-control-panel {
bottom:30px;
position: absolute;
left:30px;
}
#aic-control-panel .olympus-button img {
max-width: 32px;
}
#aic-toolbox, #aic-callsign-panel {
align-items: flex-start;
align-self: center;
flex-direction: column;
row-gap: 10px;
display:none;
position:absolute;
}
.aic-panel {
background:#eaeaea;
border-bottom-right-radius: 10px;
border-top-right-radius: 10px;
justify-self: left;
padding:5px 10px;
}
.aic-enabled #aic-toolbox, .aic-enabled #aic-callsign-panel {
display:flex;
}
.aic-enabled #aic-callsign-panel {
align-self: auto;
top: 100px;
}
.aic-panel h2 {
font-size:90%;
margin:0;
padding:0;
text-align: center;
}
#aic-callsign-display {
text-align: center;
}
#aic-formation-list {
display:flex;
flex-direction: column;
justify-content: center;
}
#aic-formation-list > div {
align-items: center;
cursor: pointer;
display:flex;
flex-direction: column;
justify-content: center;
margin-top:10px;
position:relative;
}
#aic-formation-list .aic-formation-image img {
border: 1px solid #ccc;
border-radius: 10px;
max-width: 50px;
}
#aic-formation-list .aic-formation-name {
font-size:90%;
}
#aic-formation-list .aic-formation-descriptor {
background:white;
border-radius: 10px;
left:100px;
padding:5px;
position:absolute;
width: max-content;
}
#aic-teleprompt {
background-color: white;
border:2px solid black;
border-radius: 10px;
bottom: 50px;
color: black;
display: none;
justify-content: center;
justify-self: center;
padding: 10px;
position: absolute;
width: fit-content;
z-index: 9999;
}
.aic-enabled #aic-teleprompt {
display:flex;
}
#aic-descriptor {
display:flex;
flex-direction: row;
}
#aic-descriptor .aic-descriptor-section {
display:flex;
flex-direction: column;
margin:0 10px;
}
#aic-descriptor .aic-descriptor-section-label {
background-color:#eaeaea;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
padding:.25em;
text-align: center;
}
#aic-descriptor .aic-descriptor-phrase {
border-bottom: 1px solid #ccc;
display:flex;
flex-direction: row;
margin-bottom:5px;
padding-bottom:2px;
}
#aic-descriptor .aic-descriptor-phrase:last-of-type {
margin-bottom: 0;
}
#aic-descriptor .aic-descriptor-components .aic-descriptor-component {
margin:0 5px;
text-align: center;
}
#aic-descriptor .aic-descriptor-component-label {
display:none;
}
#aic-descriptor .aic-descriptor-component-value:after {
content:",";
margin-right:5px;
}
#aic-descriptor .aic-descriptor-component:last-of-type .aic-descriptor-component-value:after {
content:"; ";
}
#aic-descriptor .aic-descriptor-section:last-of-type .aic-descriptor-component:last-of-type .aic-descriptor-component-value:after {
content:".";
}
/**************************************/

View File

@@ -1,205 +0,0 @@
.ol-strip-board .ol-dialog-header {
align-items: center;
display:flex;
justify-content: space-between;
}
.ol-strip-board-strips {
display:flex;
flex-direction: column;
row-gap: 4px;
}
.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;
font-size:12px;
font-weight:normal;
outline:none;
padding: 4px 0;
text-align: center;
width:100%;
}
.ol-strip-board-strip[data-time-warning="level-1"] [data-point="timeToGo"] {
border:1px solid #cc0000;
}
.ol-strip-board-headers :nth-child(1) {
width:12px;
}
.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;
}
[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;
}
[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;
row-gap: 4px;
}
.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;
}
[data-board-type="tower"] .ol-auto-suggest {
top:30px;
translate:0;
}

View File

@@ -1,27 +0,0 @@
#unit-list {
display:flex;
flex-direction: column;
font-size:13px;
height: 250px;
width:fit-content;
}
#unit-list > div {
display:flex;
flex-direction: row;
flex-wrap: nowrap;
}
#unit-list > div > div {
text-overflow: ellipsis;
white-space: nowrap;
width:100px;
}
#unit-list > div:first-of-type {
text-align: center;
}
#unit-list > div > div:nth-of-type( 4 ) {
text-align: center;
}

View File

@@ -11,37 +11,12 @@
left: 10px; left: 10px;
position: absolute; position: absolute;
top: 10px; top: 10px;
z-index: 9999; z-index: 99999;
column-gap: 10px; column-gap: 10px;
} row-gap: 10px;
margin-right: 320px;
#primary-toolbar { height: fit-content;
align-items: center; flex-wrap: wrap;
display: flex;
}
#command-mode-toolbar {
align-items: center;
display: flex;
}
#app-icon>.ol-select-options {
width: fit-content;
}
#toolbar-summary {
background-image: url("/images/icon-round.png");
background-position: 20px 22px;
background-repeat: no-repeat;
background-size: 45px 45px;
display: flex;
flex-direction: column;
padding: 20px;
text-indent: 60px;
}
#toolbar-summary {
white-space: nowrap;
} }
#connection-status-panel { #connection-status-panel {
@@ -49,16 +24,7 @@
font-size: 12px; font-size: 12px;
position: absolute; position: absolute;
right: 10px; right: 10px;
width: 180px; width: 190px;
z-index: 9999;
}
#server-status-panel {
bottom: 20px;
font-size: 12px;
position: absolute;
right: 200px;
width: 300px;
z-index: 9999; z-index: 9999;
} }
@@ -70,27 +36,30 @@
position: absolute; position: absolute;
right: 10px; right: 10px;
row-gap: 10px; row-gap: 10px;
width: 180px; width: 190px;
z-index: 9999; z-index: 9999;
} }
#unit-control-panel { #unit-control-panel {
height: fit-content; height: fit-content;
width: fit-content;
left: 10px; left: 10px;
position: absolute; position: absolute;
top: 80px;
width: 320px;
z-index: 9999; z-index: 9999;
} }
#unit-info-panel { #unit-info-panel {
bottom: 20px; bottom: 20px;
font-size: 12px; font-size: 12px;
left: 10px;
position: absolute; position: absolute;
width: fit-content; width: fit-content;
z-index: 9999; z-index: 9999;
padding: 24px 30px; padding: 24px 30px;
display: flex;
flex-direction: row;
justify-content: space-evenly;
right: 210px;
height: 180px;
} }
#info-popup { #info-popup {
@@ -100,15 +69,25 @@
top: 100px; top: 100px;
left: 50%; left: 50%;
translate: -50% 0%; translate: -50% 0%;
z-index: 9999; z-index: 9999999999;
display: flex; display: flex;
align-items: center; align-items: center;
} }
#slow-delete-popup {
align-self: center;
display:flex;
justify-self: center;
position: absolute;
width: fit-content;
height: fit-content;
z-index: 9999999999;
}
#log-panel { #log-panel {
position: absolute; position: absolute;
right: 0px; right: 0px;
top: 220px; top: 170px;
width: 310px; width: 310px;
height: fit-content; height: fit-content;
z-index: 9990; z-index: 9990;

View File

@@ -0,0 +1,47 @@
@-webkit-keyframes leaflet-gestures-fadein {
0% {
opacity: 0; }
100% {
opacity: 1; } }
@keyframes leaflet-gestures-fadein {
0% {
opacity: 0; }
100% {
opacity: 1; } }
.leaflet-container:after {
-webkit-animation: leaflet-gestures-fadein 0.8s backwards;
animation: leaflet-gestures-fadein 0.8s backwards;
color: #fff;
font-family: "Roboto", Arial, sans-serif;
font-size: 22px;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
padding: 15px;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 461;
pointer-events: none; }
.leaflet-gesture-handling-touch-warning:after,
.leaflet-gesture-handling-scroll-warning:after {
-webkit-animation: leaflet-gestures-fadein 0.8s forwards;
animation: leaflet-gestures-fadein 0.8s forwards; }
.leaflet-gesture-handling-touch-warning:after {
content: attr(data-gesture-handling-touch-content); }
.leaflet-gesture-handling-scroll-warning:after {
content: attr(data-gesture-handling-scroll-content); }

View File

@@ -97,6 +97,22 @@
position: absolute; position: absolute;
} }
[data-object|="unit-groundunit"] .unit-short-label {
transform: translateY(7px);
}
/*** Health indicator ***/
[data-object|="unit"] .unit-health {
background: white;
border: var(--unit-health-border-width) solid var(--secondary-dark-steel);
border-radius: var(--border-radius-sm);
display: none;
height: var(--unit-health-height);
position: absolute;
translate: var(--unit-health-x) var(--unit-health-y);
width: var(--unit-health-width);
}
/*** Fuel indicator ***/ /*** Fuel indicator ***/
[data-object|="unit"] .unit-fuel { [data-object|="unit"] .unit-fuel {
background: white; background: white;
@@ -109,7 +125,8 @@
width: var(--unit-fuel-width); width: var(--unit-fuel-width);
} }
[data-object|="unit"] .unit-fuel-level { [data-object|="unit"] .unit-fuel-level,
[data-object|="unit"] .unit-health-level {
background-color: var(--secondary-light-grey); background-color: var(--secondary-light-grey);
height: 100%; height: 100%;
width: 100%; width: 100%;
@@ -178,6 +195,7 @@
/*** Common ***/ /*** Common ***/
[data-object|="unit"]:hover .unit-ammo, [data-object|="unit"]:hover .unit-ammo,
[data-object|="unit"]:hover .unit-health ,
[data-object|="unit"]:hover .unit-fuel { [data-object|="unit"]:hover .unit-fuel {
display: flex; display: flex;
} }
@@ -188,13 +206,14 @@
} }
} }
[data-object|="unit"][data-has-low-fuel] .unit-fuel { [data-object|="unit"][data-has-low-fuel] .unit-fuel, [data-object|="unit"][data-has-low-health] .unit-health {
animation: pulse 1.5s linear infinite; animation: pulse 1.5s linear infinite;
} }
[data-object|="unit"][data-is-in-hotgroup] .unit-hotgroup, [data-object|="unit"][data-is-in-hotgroup] .unit-hotgroup,
[data-object|="unit"][data-is-selected] .unit-ammo, [data-object|="unit"][data-is-selected] .unit-ammo,
[data-object|="unit"][data-is-selected] .unit-fuel, [data-object|="unit"][data-is-selected] .unit-fuel,
[data-object|="unit"][data-is-selected] .unit-health,
[data-object|="unit"][data-is-selected] .unit-selected-spotlight { [data-object|="unit"][data-is-selected] .unit-selected-spotlight {
display: flex; display: flex;
} }
@@ -211,6 +230,7 @@
} }
[data-object|="unit"][data-coalition="blue"] .unit-fuel-level, [data-object|="unit"][data-coalition="blue"] .unit-fuel-level,
[data-object|="unit"][data-coalition="blue"] .unit-health-level,
[data-object|="unit"][data-coalition="blue"][data-has-fox-1] .unit-ammo>div:nth-child(1), [data-object|="unit"][data-coalition="blue"][data-has-fox-1] .unit-ammo>div:nth-child(1),
[data-object|="unit"][data-coalition="blue"][data-has-fox-2] .unit-ammo>div:nth-child(2), [data-object|="unit"][data-coalition="blue"][data-has-fox-2] .unit-ammo>div:nth-child(2),
[data-object|="unit"][data-coalition="blue"][data-has-fox-3] .unit-ammo>div:nth-child(3), [data-object|="unit"][data-coalition="blue"][data-has-fox-3] .unit-ammo>div:nth-child(3),
@@ -227,6 +247,7 @@
} }
[data-object|="unit"][data-coalition="red"] .unit-fuel-level, [data-object|="unit"][data-coalition="red"] .unit-fuel-level,
[data-object|="unit"][data-coalition="red"] .unit-health-level,
[data-object|="unit"][data-coalition="red"][data-has-fox-1] .unit-ammo>div:nth-child(1), [data-object|="unit"][data-coalition="red"][data-has-fox-1] .unit-ammo>div:nth-child(1),
[data-object|="unit"][data-coalition="red"][data-has-fox-2] .unit-ammo>div:nth-child(2), [data-object|="unit"][data-coalition="red"][data-has-fox-2] .unit-ammo>div:nth-child(2),
[data-object|="unit"][data-coalition="red"][data-has-fox-3] .unit-ammo>div:nth-child(3), [data-object|="unit"][data-coalition="red"][data-has-fox-3] .unit-ammo>div:nth-child(3),
@@ -260,14 +281,15 @@
background-image: url("/resources/theme/images/states/idle.svg"); background-image: url("/resources/theme/images/states/idle.svg");
} }
[data-object*="groundunit"][data-state="idle"] .unit-state { [data-object*="groundunit"][data-state="idle"] .unit-state,
[data-object*="navyunit"][data-state="idle"] .unit-state {
background-image: url(""); /* To avoid clutter, dont show the idle state for non flying units */ background-image: url(""); /* To avoid clutter, dont show the idle state for non flying units */
} }
[data-object|="unit"][data-state="attack"] .unit-state, [data-object|="unit"][data-state="attack"] .unit-state,
[data-object|="unit"][data-state="bombing point"] .unit-state, [data-object|="unit"][data-state="bomb-point"] .unit-state,
[data-object|="unit"][data-state="carpet bombing"] .unit-state, [data-object|="unit"][data-state="carpet-bombing"] .unit-state,
[data-object|="unit"][data-state="firing at area"] .unit-state { [data-object|="unit"][data-state="fire-at-area"] .unit-state {
background-image: url("/resources/theme/images/states/attack.svg"); background-image: url("/resources/theme/images/states/attack.svg");
} }
@@ -287,10 +309,40 @@
background-image: url("/resources/theme/images/states/dcs.svg"); background-image: url("/resources/theme/images/states/dcs.svg");
} }
[data-object|="unit"][data-state="land-at-point"] .unit-state {
background-image: url("/resources/theme/images/states/land-at-point.svg");
}
[data-object|="unit"][data-state="no-task"] .unit-state { [data-object|="unit"][data-state="no-task"] .unit-state {
background-image: url("/resources/theme/images/states/no-task.svg"); background-image: url("/resources/theme/images/states/no-task.svg");
} }
[data-object|="unit"][data-state="off"] .unit-state {
background-image: url("/resources/theme/images/states/off.svg");
}
[data-object|="unit"][data-state="tanker"] .unit-state {
background-image: url("/resources/theme/images/states/tanker.svg");
}
[data-object|="unit"][data-state="AWACS"] .unit-state {
background-image: url("/resources/theme/images/states/awacs.svg");
}
[data-object|="unit"] .unit-health::before {
background-image: url("/resources/theme/images/icons/health.svg");
background-repeat: no-repeat;
background-size: contain;
content: " ";
height: 6px;
left: 0;
position: absolute;
top: 0;
translate: -10px -2px;
width: 6px;
}
/*** Dead unit ***/ /*** Dead unit ***/
[data-object|="unit"][data-is-dead] .unit-selected-spotlight, [data-object|="unit"][data-is-dead] .unit-selected-spotlight,
[data-object|="unit"][data-is-dead] .unit-short-label, [data-object|="unit"][data-is-dead] .unit-short-label,
@@ -299,6 +351,7 @@
[data-object|="unit"][data-is-dead] .unit-hotgroup-id, [data-object|="unit"][data-is-dead] .unit-hotgroup-id,
[data-object|="unit"][data-is-dead] .unit-state, [data-object|="unit"][data-is-dead] .unit-state,
[data-object|="unit"][data-is-dead] .unit-fuel, [data-object|="unit"][data-is-dead] .unit-fuel,
[data-object|="unit"][data-is-dead] .unit-health,
[data-object|="unit"][data-is-dead] .unit-ammo, [data-object|="unit"][data-is-dead] .unit-ammo,
[data-object|="unit"][data-is-dead]:hover .unit-fuel, [data-object|="unit"][data-is-dead]:hover .unit-fuel,
[data-object|="unit"][data-is-dead]:hover .unit-ammo { [data-object|="unit"][data-is-dead]:hover .unit-ammo {

File diff suppressed because it is too large Load Diff

View File

@@ -30,12 +30,74 @@
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
row-gap: 5px; row-gap: 5px;
padding: 20px;
} }
#aircraft-spawn-menu, #map-contextmenu>div:nth-child(n+4)>div {
#helicopter-spawn-menu, width: 100%;
#groundunit-spawn-menu, }
#navyunit-spawn-menu {
.contextmenu-advanced-options,
.contextmenu-metadata {
align-items: center;
display: flex;
flex-direction: column;
justify-content: space-between;
row-gap: 5px;
width: 100%;
}
.contextmenu-advanced-options-toggle,
.contextmenu-metadata-toggle {
display: flex;
align-content: center;
text-align: left;
width: 100%;
margin: 5px;
column-gap: 5px;
cursor: pointer;
}
.contextmenu-advanced-options-toggle:after,
.contextmenu-metadata-toggle:after {
content: url(/resources/theme/images/icons/chevron-down.svg);
margin: auto;
}
.contextmenu-advanced-options-toggle div:first-child,
.contextmenu-metadata-toggle div:first-child {
width: fit-content;
white-space: nowrap;
}
.contextmenu-advanced-options>*,
.contextmenu-metadata>* {
width: 100%;
}
.contextmenu-metadata {
display: flex;
flex-direction: row;
flex-wrap: wrap;
padding: 0px 10px 10px 10px;
}
.contextmenu-metadata>div:nth-child(1) {
margin-bottom: 5px;
width: 100%;
}
.contextmenu-metadata>div:nth-child(2) {
display: flex;
flex-direction: row;
flex-wrap: wrap;
row-gap: 5px;
column-gap: 5px;
width: 100%;
margin-top: 10px;
}
.unit-spawn-menu {
height: fit-content; height: fit-content;
} }
@@ -58,11 +120,52 @@
width: 50px; width: 50px;
} }
#aircraft-spawn-menu .ol-select.is-open .ol-select-options, .unit-spawn-menu .ol-select.is-open .ol-select-options {
#helicopter-spawn-menu .ol-select.is-open .ol-select-options {
max-height: 300px; max-height: 300px;
} }
.ol-tag {
background-color: #FFFFFF11;
color: #FFFFFFDD;
border: 1px solid #FFFFFF55;
font-weight: normal;
padding: 2px 5px;
}
/*
.ol-tag-CA {
background-color: #FF000022;
}
.ol-tag-Radar {
background-color: #00FF0022;
}
.ol-tag-IR {
background-color: #0000FF22;
}
*/
.unit-loadout-list {
min-width: 0;
}
.unit-loadout-list div {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
background-color: var(--background-steel);
padding: 2px 5px 2px 5px;
}
.unit-loadout-list div:hover {
overflow: visible;
white-space: nowrap;
background-color: var(--background-steel);
width: fit-content;
border-radius: var(--border-radius-sm);
}
.deploy-unit-button { .deploy-unit-button {
margin-top: 5px; margin-top: 5px;
text-align: center; text-align: center;
@@ -82,7 +185,7 @@
margin: 0px 5px; margin: 0px 5px;
} }
.upper-bar button:nth-child(2) { .upper-bar button:first-of-type {
margin-left: auto; margin-left: auto;
} }
@@ -137,31 +240,45 @@
content: "Create neutral unit"; content: "Create neutral unit";
} }
#aircraft-loadout-preview, .unit-label-count-container {
#helicopter-loadout-preview { display: flex;
flex-direction: row;
align-items: center;
column-gap: 5px;
}
.unit-label-count-container button {
display: flex !important;
flex-direction: row;
align-items: center;
}
.unit-label-count-container button>*:nth-child(1) {
margin-left: auto;
}
.unit-loadout-preview {
align-content: space-between; align-content: space-between;
align-items: center; align-items: center;
column-gap: 20px; column-gap: 10px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
width: 100%; width: 100%;
} }
#aircaft-loadout-list, .unit-loadout-list {
#helicopter-loadout-list {
align-content: center; align-content: center;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
padding: 5px;
} }
#aircraft-unit-image, .unit-image {
#helicopter-unit-image {
filter: invert(100%); filter: invert(100%);
height: 100px; width: 25%;
margin-bottom: 10px; aspect-ratio: 1/1;
margin-top: 10px; margin: 5px 0px;
width: 100px;
} }
#smoke-spawn-menu { #smoke-spawn-menu {
@@ -259,14 +376,25 @@
#unit-contextmenu div:before { #unit-contextmenu div:before {
display: inline-block; display: inline-block;
filter: invert(100%); filter: invert(100%);
height: 16px; height: 20px;
margin-right: 15px; margin-right: 15px;
width: 16px; width: 20px;
} }
.ol-select>.ol-select-options>div button.country-dropdown-element {
display: flex;
flex-direction: row;
align-content: center;
column-gap: 10px;
width: 100%;
}
.country-dropdown-element img {
height: 20px;
aspect-ratio: initial;
}
/* Buttons */ /* Buttons */
#center-map::before { #center-map::before {
content: url("/resources/theme/images/icons/arrows-to-eye-solid.svg"); content: url("/resources/theme/images/icons/arrows-to-eye-solid.svg");
} }
@@ -291,10 +419,34 @@
content: url("/resources/theme/images/icons/crosshairs-solid.svg"); content: url("/resources/theme/images/icons/crosshairs-solid.svg");
} }
#simulate-fire-fight::before {
content: url("/resources/theme/images/icons/crosshairs-solid.svg");
}
#follow::before { #follow::before {
content: url("/resources/theme/images/icons/follow.svg"); content: url("/resources/theme/images/icons/follow.svg");
} }
#scenic-aaa::before {
content: url("/resources/theme/images/icons/scenic.svg");
}
#miss-aaa::before {
content: url("/resources/theme/images/icons/miss.svg");
}
#group-ground::before {
content: url("/resources/theme/images/icons/group-ground.svg");
}
#group-navy::before {
content: url("/resources/theme/images/icons/group-navy.svg");
}
#land-at-point::before {
content: url("/resources/theme/images/icons/land-at-point.svg");
}
#trail::before { #trail::before {
content: url("/resources/theme/images/icons/trail.svg"); content: url("/resources/theme/images/icons/trail.svg");
} }
@@ -487,3 +639,35 @@
#airbase-runways>.runway>.heading:last-of-type { #airbase-runways>.runway>.heading:last-of-type {
flex-direction: row-reverse; flex-direction: row-reverse;
} }
/* Airbase spawn menu */
#airbase-spawn-contextmenu {
display: flex;
flex-direction: column;
height: fit-content;
position: absolute;
row-gap: 5px;
width: 300px;
z-index: 9999;
}
#airbase-spawn-contextmenu>div:nth-child(2) {
align-items: center;
display: flex;
flex-direction: row;
justify-content: space-evenly;
padding-right: 0px;
}
#airbase-spawn-contextmenu >div:nth-child(n+3) {
align-items: center;
display: flex;
flex-direction: column;
justify-content: space-between;
row-gap: 5px;
padding: 20px;
}
#airbase-spawn-contextmenu>div:nth-child(n+3)>div {
width: 100%;
}

View File

@@ -1,8 +1,28 @@
.ol-popup {
display: flex;
flex-direction: column;
row-gap: 5px;
}
.ol-popup > div { .ol-popup > div {
background-color: var(--background-steel);
border-radius: var(--border-radius-md);
box-shadow: 0px 2px 5px #000A;
color: white;
font-size: 12px;
height: fit-content;
width: fit-content;
padding-top: 5px;
padding-bottom: 5px;
padding-left: 15px; padding-left: 15px;
padding-right: 15px; padding-right: 15px;
} }
.ol-popup-stack {
margin-bottom: -20px;
z-index: -1;
}
.visible { .visible {
opacity: 1; opacity: 1;
} }

View File

@@ -0,0 +1,74 @@
#primary-toolbar {
align-items: center;
display: flex;
height: fit-content;
}
#command-mode-toolbar {
align-items: center;
display: flex;
}
#app-icon>.ol-select-options {
width: fit-content;
}
#toolbar-summary {
background-image: url("/images/icon-round.png");
background-position: 20px 22px;
background-repeat: no-repeat;
background-size: 45px 45px;
display: flex;
flex-direction: column;
padding: 20px;
text-indent: 60px;
}
#toolbar-summary {
white-space: nowrap;
}
#toolbar-container>*:nth-child(2)>svg {
display: none;
width: 0px;
height: 0px;
}
#toolbar-container>*:nth-child(3)>svg {
display: none;
}
@media (max-width: 1145px) {
#toolbar-container {
flex-direction: column;
align-items: start;
}
#toolbar-container>*:nth-child(1):not(:hover) {
width: fit-content;
height: fit-content;
}
#toolbar-container>*:nth-child(1):not(:hover)>*:not(:first-child) {
display: none;
}
#toolbar-container>*:not(:first-child):not(:hover) {
height: 52px;
align-items: center;
justify-content: center;
aspect-ratio: 1/1;
}
#toolbar-container>*:not(:first-child):not(:hover)>svg {
display: block;
width: 24px;
height: 24px;
filter: invert();
}
#toolbar-container>*:not(:first-child):not(:hover)>*:not(:first-child) {
display: none;
}
}

View File

@@ -1,8 +1,15 @@
#connection-status-panel dt::before { #connection-status-panel {
align-items: center;
display:flex;
flex-direction: row;
justify-content: space-between;
}
#connection-status-panel #connection-status-message::before {
content: "No connection"; content: "No connection";
} }
#connection-status-panel dd::after { #connection-status-light {
border-radius: 50%; border-radius: 50%;
background: red; background: red;
content: " "; content: " ";
@@ -10,10 +17,48 @@
width: 12px; width: 12px;
} }
#connection-status-panel[data-is-connected] dt::before { #connection-status-panel[data-is-connected] #connection-status-message::before {
content: "Connected"; content: "";
} }
#connection-status-panel[data-is-connected] dd::after { #connection-status-panel .time-display {
cursor:pointer;
display:none;
font-weight: bold;
text-decoration: none;
}
#connection-status-panel[data-is-connected] .mission-elapsed-time,
#connection-status-panel[data-is-connected]:not([data-mission-time]) .mission-time {
display:none;
}
#connection-status-panel[data-is-connected]:not([data-mission-time]) .mission-elapsed-time,
#connection-status-panel[data-is-connected][data-mission-time] .mission-time {
display:block;
}
#connection-status-panel[data-is-connected] #connection-status-light {
background: var(--accent-green); background: var(--accent-green);
} }
#connection-status-panel[data-is-paused] #connection-status-message::before {
content: "Server paused";
}
#connection-status-panel[data-is-paused] #connection-status-light {
animation: pulse 1s infinite;
}
@keyframes pulse {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
#connection-status-panel[data-is-paused] #connection-status-light {
background: var(--accent-amber);
}

View File

@@ -26,3 +26,55 @@
#log-panel.open>div:nth-child(2) { #log-panel.open>div:nth-child(2) {
display: block; display: block;
} }
#log-panel-header-right {
align-items: center;
column-gap: 16px;
display:flex;
flex-flow: row nowrap;
}
#server-status-panel abbr {
text-decoration: none;
}
#server-status-panel dl {
column-gap: 4px;
display:flex;
flex-direction: row;
width:fit-content;
}
#server-status-panel dl > * {
margin:0;
width:fit-content;
}
#server-status-panel dd {
font-weight: bold;
}
.fps-low {
color: red;
}
.fps-medium {
color: orange;
}
.fps-high {
color: lightgreen;
}
.load-low {
color: lightgreen;
}
.load-medium {
color: orange;
}
.load-high {
color: red;
}

View File

@@ -1,9 +1,116 @@
#mouse-info-panel>* { #mouse-info-panel .mouse-tool {
background-color: var(--background-grey); background-color: var(--background-grey);
border-radius: var(--border-radius-sm); border-radius: var(--border-radius-sm);
display:flex;
flex-flow:column wrap;
row-gap: 4px;
padding: 6px; padding: 6px;
} }
#mouse-info-panel .mouse-tool .mouse-tool-item {
align-items: center;
display:flex;
flex-flow: row nowrap;
justify-content: space-between;
}
#mouse-info-panel svg {
padding: 3px;
height: 100%;
width: 100%;
}
#mouse-info-panel svg > * {
fill: black;
stroke: black;
}
#mouse-info-panel .mouse-tool .mouse-tool-item > * {
width:fit-content;
}
#mouse-info-panel .mouse-tool .mouse-tool-item > *:last-child {
text-align: right;
width:100%;
}
#mouse-info-panel .svg-icon, #mouse-info-panel .mouse-tool .mouse-tool-item :first-child {
align-items: center;
background-color: white;
border-radius: var(--border-radius-sm);
color: var(--background-steel);
display: flex;
font-size: 15.6px;
font-weight: bolder;
height: 22px;
justify-content: center;
text-transform: uppercase;
width: 22px;
}
#mouse-info-panel .mouse-tool .mouse-tool-item [data-label]::after {
border-radius: var(--border-radius-sm);
content: attr(data-label);
}
#mouse-info-panel .mouse-tool .mouse-tool-item :last-child {
color: var(--background-offwhite);
font-weight: bold;
font-size: 13px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width:fit-content;
}
/* Bullseye info */
#mouse-info-panel .mouse-tool .mouse-tool-item [data-label][data-coalition="blue"] {
background-color: var(--primary-blue);
}
#mouse-info-panel .mouse-tool .mouse-tool-item [data-label][data-coalition="red"] {
background-color: var(--primary-red);
}
.br-info::after {
content: attr(data-bearing) '\00B0 / ' attr(data-distance) " " attr(data-distance-units);
}
.br-info[data-coalition="blue"]::after {
color: var(--primary-blue)
}
.br-info[data-coalition="red"]::after {
color: var(--primary-red)
}
.br-info[data-message]::after {
content: attr(data-message);
}
/* Coordinates */
#coordinates-tool .elevation::after {
content: attr(data-value)
}
#coordinates-tool[data-location-system] [data-location-system] {
cursor:pointer;
display:none;
}
#coordinates-tool[data-location-system="LatLng"] [data-location-system="LatLng"],
#coordinates-tool[data-location-system="MGRS"] [data-location-system="MGRS"],
#coordinates-tool[data-location-system="UTM"] [data-location-system="UTM"] {
display:flex;
}
/*
#mouse-info-panel dl { #mouse-info-panel dl {
margin-bottom: 4px; margin-bottom: 4px;
row-gap: 5px; row-gap: 5px;
@@ -14,7 +121,7 @@
width: 30%; width: 30%;
} }
#mouse-info-panel dt::after { #mouse-info-panel dt::after, #coordinates-tool [data-label] {
align-items: center; align-items: center;
background-color: white; background-color: white;
border-radius: var(--border-radius-sm); border-radius: var(--border-radius-sm);
@@ -30,6 +137,11 @@
width: 16px; width: 16px;
} }
#coordinates-tool [data-label] {
height:24px;
width:24px;
}
#mouse-info-panel #measuring-tool dt { #mouse-info-panel #measuring-tool dt {
height: 24px; height: 24px;
width: 24px; width: 24px;
@@ -48,7 +160,7 @@
stroke: black; stroke: black;
} }
#mouse-info-panel dt[data-label]::after { #mouse-info-panel [data-label]::after {
content: attr(data-label); content: attr(data-label);
} }
@@ -60,7 +172,7 @@
background-color: var(--primary-red); background-color: var(--primary-red);
} }
#mouse-info-panel dt[data-tooltip]:hover::before { #mouse-info-panel [data-tooltip]:hover::before {
background-color: var(--background-grey); background-color: var(--background-grey);
border-radius: 5px; border-radius: 5px;
content: attr(data-tooltip); content: attr(data-tooltip);
@@ -72,8 +184,30 @@
white-space: nowrap; white-space: nowrap;
} }
#mouse-info-panel dd { #coordinates-tool[data-location-system] [data-location-system] {
width: 70%; display:none;
flex-direction: column;
}
#coordinates-tool[data-location-system="LatLng"] [data-location-system="LatLng"],
#coordinates-tool[data-location-system="MGRS"] [data-location-system="MGRS"] {
display:flex;
}
#coordinates-tool > * > * {
align-items: center;
display:flex;
flex-flow: row nowrap;
}
#coordinates-tool > * > * > * {
display:table-cell;
width:fit-content;
}
#coordinates-tool > * > * > :last-child {
text-align: right;
width:100%;
} }
.br-info::after { .br-info::after {
@@ -107,3 +241,13 @@
white-space: nowrap; white-space: nowrap;
color: var(--background-offwhite); color: var(--background-offwhite);
} }
.elevation::after {
content: attr(data-value);
font-weight: bold;
font-size: 13px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: var(--background-offwhite);
} */

View File

@@ -5,13 +5,24 @@
column-gap: 10px; column-gap: 10px;
} }
#server-status-panel .ol-data-grid {
width: 100%; #log-panel-header-right {
align-items: center;
column-gap: 16px;
display:flex;
flex-flow: row nowrap;
} }
#server-status-panel .ol-data-grid:first-of-type { #server-status-panel dl {
border-right: 1px solid gray; column-gap: 4px;
padding-right: 10px; display:flex;
flex-direction: row;
width:fit-content;
}
#server-status-panel dl > * {
margin:0;
width:fit-content;
} }
#server-status-panel dd { #server-status-panel dd {

View File

@@ -3,11 +3,58 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
} }
#unit-control-panel { #unit-control-panel {
display: flex;
flex-direction: row;
column-gap: 10px;
row-gap: 10px;
}
#unit-control-panel>div:nth-child(2),
#unit-controls {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
row-gap: 10px; row-gap: 10px;
} }
#unit-controls {
padding-right: 10px;
}
#unit-control-panel>div:nth-child(2) {
width: 330px;
}
#unit-control-panel>*:nth-child(1) {
display: none;
padding: 14px;
}
@media (max-width: 1145px) {
#unit-control-panel>*:nth-child(1) {
display: flex;
}
#unit-control-panel>*:nth-child(1) svg {
display: flex;
width: 24px;
height: 24px;
filter: invert(100%);
}
#unit-control-panel:hover>*:nth-child(1) {
display: none;
}
#unit-control-panel:not(:hover) {
width: fit-content;
}
#unit-control-panel:not(:hover)>*:nth-child(2),
#unit-control-panel:not(:hover)>*:nth-child(3) {
display: none;
}
}
#unit-control-panel h3 { #unit-control-panel h3 {
margin-bottom: 8px; margin-bottom: 8px;
} }
@@ -91,8 +138,8 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
justify-content: space-between; justify-content: space-between;
} }
#advanced-settings-dialog h4 { #advanced-settings-dialog>.ol-dialog-content>div input[type="number"] {
white-space: nowrap; width: 60px;
} }
#advanced-settings-dialog hr { #advanced-settings-dialog hr {
@@ -102,6 +149,12 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
#advanced-settings-dialog .ol-text-input input { #advanced-settings-dialog .ol-text-input input {
height: 40px; height: 40px;
width: fit-content;
}
#advanced-settings-dialog h4 {
width: fit-content;
text-wrap: nowrap;
} }
#general-settings-grid { #general-settings-grid {
@@ -136,19 +189,19 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
} }
#altitude-type-switch[data-value="true"]>.ol-switch-fill::before { #altitude-type-switch[data-value="true"]>.ol-switch-fill::before {
content: "AGL";
}
#altitude-type-switch[data-value="false"]>.ol-switch-fill::before {
content: "ASL"; content: "ASL";
} }
#altitude-type-switch[data-value="false"]>.ol-switch-fill::before {
content: "AGL";
}
#speed-type-switch[data-value="true"]>.ol-switch-fill::before { #speed-type-switch[data-value="true"]>.ol-switch-fill::before {
content: "GS"; content: "CAS";
} }
#speed-type-switch[data-value="false"]>.ol-switch-fill::before { #speed-type-switch[data-value="false"]>.ol-switch-fill::before {
content: "CAS"; content: "GS";
} }
#unit-control-panel .ol-slider-value { #unit-control-panel .ol-slider-value {
@@ -160,20 +213,23 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
#unit-control-panel .switch-control { #unit-control-panel .switch-control {
align-items: center; align-items: center;
display: grid; display: flex;
grid-template-columns: 1.35fr 0.65fr; width: 100%;
} justify-content: space-between;
#unit-control-panel .switch-control>*:nth-child(2) {
justify-self: end;
}
#unit-control-panel .switch-control>*:nth-child(3) {
color: var(--secondary-semitransparent-white);
} }
#unit-control-panel .switch-control h4 { #unit-control-panel .switch-control h4 {
margin: 0px; margin: 0px;
display: flex;
align-items: center;
}
#unit-control-panel .switch-control h4 img {
height: 15px;
margin-left: 10px;
cursor: pointer;
filter: invert(100%);
opacity: 80%;
} }
#unit-control-panel .switch-control .ol-switch { #unit-control-panel .switch-control .ol-switch {
@@ -197,19 +253,49 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
content: "NO"; content: "NO";
} }
#operate-as-switch[data-value="true"] .ol-switch-fill {
background-color: var(--accent-light-blue);
}
#operate-as-switch[data-value="false"] .ol-switch-fill {
background-color: var(--primary-red);
}
#operate-as-switch[data-value="true"]>.ol-switch-fill::before {
content: "BLUE" !important;
}
#operate-as-switch[data-value="false"]>.ol-switch-fill::before {
content: "RED" !important;
}
#advanced-settings-div { #advanced-settings-div {
position: relative;
column-gap: 5px; column-gap: 5px;
display: flex; display: flex;
height: fit-content;
} }
#advanced-settings-div>*:nth-child(2) { #advanced-settings-div>*:nth-child(2) {
margin-left: auto; margin-left: auto;
} }
#advanced-settings-div button { #advanced-settings-div>button {
height: 40px; height: 40px;
} }
#delete-options button {
display: flex;
flex-direction: row;
align-content: center;
}
#delete-options button svg {
margin-right: 10px;
width: 18px;
max-height: 18px;
}
/* Element visibility control */ /* Element visibility control */
#unit-control-panel:not([data-show-categories-tooltip]) #categories-tooltip, #unit-control-panel:not([data-show-categories-tooltip]) #categories-tooltip,
#unit-control-panel:not([data-show-speed-slider]) #speed-slider, #unit-control-panel:not([data-show-speed-slider]) #speed-slider,
@@ -217,14 +303,18 @@ body.feature-forceShowUnitControlPanel #unit-control-panel {
#unit-control-panel:not([data-show-roe]) #roe, #unit-control-panel:not([data-show-roe]) #roe,
#unit-control-panel:not([data-show-threat]) #threat, #unit-control-panel:not([data-show-threat]) #threat,
#unit-control-panel:not([data-show-emissions-countermeasures]) #emissions-countermeasures, #unit-control-panel:not([data-show-emissions-countermeasures]) #emissions-countermeasures,
#unit-control-panel:not([data-show-shots-scatter]) #shots-scatter,
#unit-control-panel:not([data-show-shots-intensity]) #shots-intensity,
#unit-control-panel:not([data-show-tanker-button]) #tanker-on,
#unit-control-panel:not([data-show-AWACS-button]) #AWACS-on,
#unit-control-panel:not([data-show-on-off]) #ai-on-off, #unit-control-panel:not([data-show-on-off]) #ai-on-off,
#unit-control-panel:not([data-show-follow-roads]) #follow-roads, #unit-control-panel:not([data-show-follow-roads]) #follow-roads,
#unit-control-panel:not([data-show-operate-as]) #operate-as,
#unit-control-panel:not([data-show-advanced-settings-button]) #advanced-settings-button, #unit-control-panel:not([data-show-advanced-settings-button]) #advanced-settings-button,
#advanced-settings-dialog:not([data-show-settings]) #general-settings, #advanced-settings-dialog:not([data-show-settings]) #general-settings,
#advanced-settings-dialog:not([data-show-tasking]) #tasking, #advanced-settings-dialog:not([data-show-tasking]) #tasking,
#advanced-settings-dialog:not([data-show-tanker]) #tanker-checkbox,
#advanced-settings-dialog:not([data-show-AWACS]) #AWACS-checkbox,
#advanced-settings-dialog:not([data-show-TACAN]) #TACAN-options, #advanced-settings-dialog:not([data-show-TACAN]) #TACAN-options,
#advanced-settings-dialog:not([data-show-radio]) #radio-options { #advanced-settings-dialog:not([data-show-radio]) #radio-options,
#advanced-settings-dialog:not([data-show-air-unit-checkboxes]) .air-unit-checkbox {
display: none; display: none;
} }

View File

@@ -1,15 +1,55 @@
#unit-info-panel>* { #unit-info-panel>* {
position: relative; position: relative;
min-height: 100px;
bottom: 0px; bottom: 0px;
} }
#unit-info-panel>*:nth-child(1) {
display: flex;
width: 24px;
height: 24px;
margin: 6px;
filter: invert(100%);
}
#unit-info-panel:hover>*:nth-child(1) {
display: none;
}
#unit-info-panel:not(:hover) {
width: fit-content;
height: fit-content;
padding: 10px;
margin: 0px;
}
#unit-info-panel:not(:hover)>*:not(:first-child) {
display: none;
}
#unit-info-panel>.panel-section {
border-right: 1px solid #555;
padding: 0 30px;
}
#unit-info-panel>.panel-section:first-of-type {
padding-left: 0px;
}
#unit-info-panel>.panel-section:last-of-type{
padding-right: 0px;
}
#unit-info-panel>.panel-section:last-of-type {
border-right-width: 0;
}
#general { #general {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
row-gap: 4px; row-gap: 4px;
position: relative; position: relative;
width: 300px;
} }
#unit-label { #unit-label {
@@ -24,6 +64,10 @@
#unit-name { #unit-name {
margin-bottom: 4px; margin-bottom: 4px;
padding: 0px 0; padding: 0px 0;
width: 100%;
text-overflow: ellipsis;
text-wrap: nowrap;
overflow: hidden;
} }
#current-task { #current-task {
@@ -48,20 +92,24 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
width: 300px;
} }
#loadout-silhouette { #loadout-silhouette {
filter: invert(100%); filter: invert(100%);
height: 100px; height: 75px;
margin-right: 25px; margin-right: 25px;
width: 100px; width: 75px;
} }
#loadout-items { #loadout-items {
align-self: center; align-self: center;
column-gap: 8px;
display: flex; display: flex;
flex-flow: column nowrap; flex-flow: column nowrap;
row-gap: 8px; height: 100px;
row-gap: 6px;
padding-right: 10px;
} }
#loadout-items>* { #loadout-items>* {
@@ -79,7 +127,7 @@
display: flex; display: flex;
font-size: 11px; font-size: 11px;
font-weight: bold; font-weight: bold;
padding: 4px 6px; padding: 3px 4px;
} }
#loadout-items>*::after { #loadout-items>*::after {
@@ -94,7 +142,7 @@
#fuel-percentage { #fuel-percentage {
align-items: center; align-items: center;
display: flex; display: flex;
margin-top: auto; margin-top: 8px;
} }
#fuel-percentage::before { #fuel-percentage::before {

View File

@@ -0,0 +1,92 @@
#unit-list-panel {
bottom:20px;
display:flex;
flex-direction: column;
justify-self:center;
position: absolute;
z-index:999;
}
#unit-list-panel h3 {
margin-bottom:4px;
}
#unit-list-panel-content {
display:flex;
flex-flow: column nowrap;
max-height: 200px;
row-gap: 4px;
}
.unit-list-unit {
border-radius: var( --border-radius-sm );
column-gap: 2px;
display:flex;
flex-flow: row nowrap;
justify-content: space-between;
}
.unit-list-unit:nth-of-type(even) {
background:#ffffff10;
overflow:visible;
}
.unit-list-unit.headers {
margin-bottom:3px;
margin-right:10px;
overflow: hidden;
}
.unit-list-unit.headers [data-sort-field] {
cursor:pointer;
}
.unit-list-unit.headers > * {
background-color: var( --background-grey );
text-align: center;
}
.unit-list-unit > * {
font-size:13px;
overflow: hidden;
padding:2px;
width:80px;
}
.unit-list-unit :first-child {
overflow-x: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width:150px;
}
.unit-list-unit :first-child:hover {
overflow:visible;
}
.unit-list-unit :first-child:hover span {
position:relative;
z-index:9999;
}
.unit-list-unit :first-child:hover span:hover {
background-color: white;
color: var( --background-steel );
}
.unit-list-unit :nth-child(2) {
width:120px;
}
.unit-list-unit > [data-unit-id] {
cursor:pointer;
}
#unit-list-panel-content > * {
cursor:pointer;
}
#unit-list-panel-content > .unit-list-unit:hover {
background-color: var( --background-grey );
}

File diff suppressed because it is too large Load Diff

View File

@@ -38,6 +38,7 @@
inkscape:window-maximized="1" inkscape:window-maximized="1"
inkscape:current-layer="svg4" /> inkscape:current-layer="svg4" />
<path <path
style="stroke: none"
d="m 7.5000002,0 c 0.498,0 0.9375,0.4395 0.9375,0.9375 V 1.2598 C 11.1621,1.6699 13.3301,3.8379002 13.7402,6.5625002 h 0.3223 c 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 H 13.7402 C 13.3301,11.1914 11.1621,13.3594 8.4375002,13.7695 v 0.293 c 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 v -0.293 C 3.8086002,13.3594 1.6406,11.1914 1.2305,8.4375002 h -0.293 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 h 0.293 C 1.6406,3.8379002 3.8086002,1.6699 6.5625002,1.2598 V 0.9375 c 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 z m -4.3652,8.4375002 c 0.3515,1.7284998 1.6992,3.0761998 3.4277,3.4276998 V 11.25 c 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 0.498,0 0.9375,0.4395 0.9375,0.9375 v 0.6152 C 10.1367,11.5137 11.4844,10.166 11.8359,8.4375002 H 11.25 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 h 0.5859 c -0.3515,-1.6992 -1.6992,-3.0469 -3.3983998,-3.3984 v 0.5859 c 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 v -0.5859 c -1.7285,0.3515 -3.0762,1.6992 -3.4277,3.3984 h 0.6152 c 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 z m 4.3652,0 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 z" d="m 7.5000002,0 c 0.498,0 0.9375,0.4395 0.9375,0.9375 V 1.2598 C 11.1621,1.6699 13.3301,3.8379002 13.7402,6.5625002 h 0.3223 c 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 H 13.7402 C 13.3301,11.1914 11.1621,13.3594 8.4375002,13.7695 v 0.293 c 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 v -0.293 C 3.8086002,13.3594 1.6406,11.1914 1.2305,8.4375002 h -0.293 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 h 0.293 C 1.6406,3.8379002 3.8086002,1.6699 6.5625002,1.2598 V 0.9375 c 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 z m -4.3652,8.4375002 c 0.3515,1.7284998 1.6992,3.0761998 3.4277,3.4276998 V 11.25 c 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 0.498,0 0.9375,0.4395 0.9375,0.9375 v 0.6152 C 10.1367,11.5137 11.4844,10.166 11.8359,8.4375002 H 11.25 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 h 0.5859 c -0.3515,-1.6992 -1.6992,-3.0469 -3.3983998,-3.3984 v 0.5859 c 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 v -0.5859 c -1.7285,0.3515 -3.0762,1.6992 -3.4277,3.3984 h 0.6152 c 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 z m 4.3652,0 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 z"
fill="#5ca7ff" fill="#5ca7ff"
id="path2" /> id="path2" />

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -39,5 +39,6 @@
<path <path
d="m 7.0324294,0 c 0.1172,0 0.2637,0.0293 0.3809,0.0879 l 5.5077996,2.3437 c 0.6445,0.293 1.1425,0.9082 1.1425,1.67 -0.0292,2.9296 -1.2304,8.2324 -6.2694996,10.664 -0.498,0.2344 -1.0547,0.2344 -1.5527,0 -5.0391,-2.4316 -6.24020004,-7.7344 -6.24020004,-10.664 -0.0293,-0.7618 0.4687,-1.377 1.11320004,-1.67 l 5.5078,-2.3437 C 6.7394294,0.0293 6.8859294,0 7.0324294,0 Z m 0,1.9629 V 13.0371 C 11.075429,11.0742 12.159429,6.7676 12.188629,4.1602 Z" d="m 7.0324294,0 c 0.1172,0 0.2637,0.0293 0.3809,0.0879 l 5.5077996,2.3437 c 0.6445,0.293 1.1425,0.9082 1.1425,1.67 -0.0292,2.9296 -1.2304,8.2324 -6.2694996,10.664 -0.498,0.2344 -1.0547,0.2344 -1.5527,0 -5.0391,-2.4316 -6.24020004,-7.7344 -6.24020004,-10.664 -0.0293,-0.7618 0.4687,-1.377 1.11320004,-1.67 l 5.5078,-2.3437 C 6.7394294,0.0293 6.8859294,0 7.0324294,0 Z m 0,1.9629 V 13.0371 C 11.075429,11.0742 12.159429,6.7676 12.188629,4.1602 Z"
fill="#5ca7ff" fill="#5ca7ff"
id="path2" /> id="path2"
style="stroke: none"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -39,5 +39,6 @@
<path <path
d="m 10.796771,3.75 c 0,1.31836 -0.7618,2.46094 -1.8750496,3.13476 v 0.61525 c 0,0.5273 -0.43945,0.9375 -0.9375,0.9375 h -2.8125 c -0.52734,0 -0.9375,-0.4102 -0.9375,-0.9375 V 6.88476 c -1.14258,-0.67382 -1.875,-1.8164 -1.875,-3.13476 0,-2.05078 1.875,-3.75 4.21875,-3.75 2.31445,0 4.2187996,1.69922 4.2187996,3.75 z M 4.9373514,5.15625 c 0.49804,0 0.9375,-0.41016 0.9375,-0.9375 0,-0.49805 -0.43946,-0.9375 -0.9375,-0.9375 -0.52735,0 -0.9375,0.43945 -0.9375,0.9375 0,0.52734 0.41015,0.9375 0.9375,0.9375 z m 4.21872,-0.9375 c 0,-0.49805 -0.43943,-0.9375 -0.93748,-0.9375 -0.52734,0 -0.9375,0.43945 -0.9375,0.9375 0,0.52734 0.41016,0.9375 0.9375,0.9375 0.49805,0 0.93748,-0.41016 0.93748,-0.9375 z M 0.10336144,8.02731 c 0.23438,-0.4687 0.79102,-0.6445 1.25976996,-0.4101 l 5.21484,2.6074 5.1854996,-2.6074 c 0.4688,-0.2344 1.0254,-0.0586 1.2598,0.4101 0.2344,0.4688 0.0586,1.0254 -0.4101,1.2598 l -3.9551196,1.9629 3.9551196,1.9922 c 0.4687,0.2344 0.6445,0.791 0.4101,1.2597 -0.2344,0.4688 -0.791,0.6446 -1.2598,0.4102 l -5.1854996,-2.6074 -5.21484,2.6074 c -0.46874996,0.2344 -1.02538996,0.0586 -1.25976996,-0.4102 -0.234374,-0.4687 -0.058593,-1.0253 0.41016,-1.2597 L 4.4685914,11.25001 0.51352144,9.28711 c -0.468753,-0.2344 -0.644534,-0.791 -0.41016,-1.2598 z" d="m 10.796771,3.75 c 0,1.31836 -0.7618,2.46094 -1.8750496,3.13476 v 0.61525 c 0,0.5273 -0.43945,0.9375 -0.9375,0.9375 h -2.8125 c -0.52734,0 -0.9375,-0.4102 -0.9375,-0.9375 V 6.88476 c -1.14258,-0.67382 -1.875,-1.8164 -1.875,-3.13476 0,-2.05078 1.875,-3.75 4.21875,-3.75 2.31445,0 4.2187996,1.69922 4.2187996,3.75 z M 4.9373514,5.15625 c 0.49804,0 0.9375,-0.41016 0.9375,-0.9375 0,-0.49805 -0.43946,-0.9375 -0.9375,-0.9375 -0.52735,0 -0.9375,0.43945 -0.9375,0.9375 0,0.52734 0.41015,0.9375 0.9375,0.9375 z m 4.21872,-0.9375 c 0,-0.49805 -0.43943,-0.9375 -0.93748,-0.9375 -0.52734,0 -0.9375,0.43945 -0.9375,0.9375 0,0.52734 0.41016,0.9375 0.9375,0.9375 0.49805,0 0.93748,-0.41016 0.93748,-0.9375 z M 0.10336144,8.02731 c 0.23438,-0.4687 0.79102,-0.6445 1.25976996,-0.4101 l 5.21484,2.6074 5.1854996,-2.6074 c 0.4688,-0.2344 1.0254,-0.0586 1.2598,0.4101 0.2344,0.4688 0.0586,1.0254 -0.4101,1.2598 l -3.9551196,1.9629 3.9551196,1.9922 c 0.4687,0.2344 0.6445,0.791 0.4101,1.2597 -0.2344,0.4688 -0.791,0.6446 -1.2598,0.4102 l -5.1854996,-2.6074 -5.21484,2.6074 c -0.46874996,0.2344 -1.02538996,0.0586 -1.25976996,-0.4102 -0.234374,-0.4687 -0.058593,-1.0253 0.41016,-1.2597 L 4.4685914,11.25001 0.51352144,9.28711 c -0.468753,-0.2344 -0.644534,-0.791 -0.41016,-1.2598 z"
fill="#5ca7ff" fill="#5ca7ff"
id="path2" /> id="path2"
style="stroke: none"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -39,5 +39,6 @@
<path <path
d="m 9.103975,1.603975 c 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 l -3.0762,3.0761 -3.1055,-3.0761 c -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 -0.3809,0.3515 -0.3809,0.9668 0,1.3183 l 3.0761,3.0762 -3.0761,3.1055 c -0.3809,0.3515 -0.3809,0.9668 0,1.3183 0.3515,0.3809 0.9668,0.3809 1.3183,0 l 3.1055,-3.0761 3.0762,3.0761 c 0.3515,0.3809 0.9668,0.3809 1.3183,0 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 l -3.0761,-3.1055 z" d="m 9.103975,1.603975 c 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 l -3.0762,3.0761 -3.1055,-3.0761 c -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 -0.3809,0.3515 -0.3809,0.9668 0,1.3183 l 3.0761,3.0762 -3.0761,3.1055 c -0.3809,0.3515 -0.3809,0.9668 0,1.3183 0.3515,0.3809 0.9668,0.3809 1.3183,0 l 3.1055,-3.0761 3.0762,3.0761 c 0.3515,0.3809 0.9668,0.3809 1.3183,0 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 l -3.0761,-3.1055 z"
fill="#5ca7ff" fill="#5ca7ff"
id="path2" /> id="path2"
style="stroke: none"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
version="1.1"
id="svg4"
sodipodi:docname="1.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="defs8" />
<sodipodi:namedview
id="namedview6"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
width="30px"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="16.808938"
inkscape:cx="4.2536893"
inkscape:cy="-1.2195892"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg4"
inkscape:showpageshadow="2"
inkscape:deskcolor="#d1d1d1" />
<rect
style="stroke-width:0.659;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1"
fill="#5ca7ff"
stroke="#5ca7ff"
id="rect1107"
width="2.8299551"
height="3.9513376"
x="1.7056587"
y="9.5718069" />
<rect
style="fill:none;stroke-width:0.659001;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers"
fill="#5ca7ff"
stroke="#5ca7ff"
id="rect1107-7"
width="2.8299551"
height="7.6993432"
x="6.0053182"
y="5.817802" />
<rect
style="fill:none;stroke-width:0.659001;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers"
fill="#5ca7ff"
stroke="#5ca7ff"
id="rect1107-9"
width="2.8299551"
height="11.89354"
x="10.304977"
y="1.7128451" />
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="15"
height="15"
viewBox="0 0 15 15"
fill="none"
version="1.1"
id="svg4"
sodipodi:docname="2.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="defs8" />
<sodipodi:namedview
id="namedview6"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
width="30px"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="16.808938"
inkscape:cx="4.2536893"
inkscape:cy="-1.2195892"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg4"
inkscape:showpageshadow="2"
inkscape:deskcolor="#d1d1d1" />
<rect
style="stroke-width:0.659;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1"
fill="#5ca7ff"
stroke="#5ca7ff"
id="rect1107"
width="2.8299551"
height="3.9513376"
x="1.7056587"
y="9.5718069" />
<rect
style="stroke-width:0.659001;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1"
fill="#5ca7ff"
stroke="#5ca7ff"
id="rect1107-7"
width="2.8299551"
height="7.6993432"
x="6.0053182"
y="5.817802" />
<rect
style="fill:none;stroke-width:0.659001;stroke-linecap:round;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:5.6;stroke-opacity:1;paint-order:stroke fill markers"
fill="#5ca7ff"
stroke="#5ca7ff"
id="rect1107-9"
width="2.8299551"
height="11.89354"
x="10.304977"
y="1.7128451" />
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="15"
height="15"
fill="none"
version="1.1"
viewBox="0 0 15 15"
id="svg8"
sodipodi:docname="3.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="defs12" />
<sodipodi:namedview
id="namedview10"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="55.466667"
inkscape:cx="7.4909856"
inkscape:cy="7.4909856"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<rect
x="1.7057"
y="9.5718"
width="2.83"
height="3.9513"
style="paint-order:stroke fill markers;stroke-dashoffset:5.6;stroke-linecap:round;stroke-linejoin:bevel;stroke-width:.659;"
id="rect2"
fill="#5ca7ff"
stroke="#5ca7ff" />
<rect
x="6.0053"
y="5.8178"
width="2.83"
height="7.6993"
style="paint-order:stroke fill markers;stroke-dashoffset:5.6;stroke-linecap:round;stroke-linejoin:bevel;stroke-width:.659;"
id="rect4"
fill="#5ca7ff"
stroke="#5ca7ff" />
<rect
x="10.305"
y="1.7128"
width="2.83"
height="11.894"
style="paint-order:stroke fill markers;stroke-dashoffset:5.6;stroke-linecap:round;stroke-linejoin:bevel;stroke-width:.659;"
id="rect6"
fill="#5ca7ff"
stroke="#5ca7ff" />
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M352 144c0-44.2 35.8-80 80-80s80 35.8 80 80v48c0 17.7 14.3 32 32 32s32-14.3 32-32V144C576 64.5 511.5 0 432 0S288 64.5 288 144v48H64c-35.3 0-64 28.7-64 64V448c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V256c0-35.3-28.7-64-64-64H352V144z"/></svg>

After

Width:  |  Height:  |  Size: 485 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M144 144v48H304V144c0-44.2-35.8-80-80-80s-80 35.8-80 80zM80 192V144C80 64.5 144.5 0 224 0s144 64.5 144 144v48h16c35.3 0 64 28.7 64 64V448c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V256c0-35.3 28.7-64 64-64H80z"/></svg>

After

Width:  |  Height:  |  Size: 460 B

View File

@@ -40,5 +40,6 @@
<path <path
d="m 7.5000002,0 c 0.498,0 0.9375,0.4395 0.9375,0.9375 V 1.2598 C 11.1621,1.6699 13.3301,3.8379002 13.7402,6.5625002 h 0.3223 c 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 H 13.7402 C 13.3301,11.1914 11.1621,13.3594 8.4375002,13.7695 v 0.293 c 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 v -0.293 C 3.8086002,13.3594 1.6406,11.1914 1.2305,8.4375002 h -0.293 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 h 0.293 C 1.6406,3.8379002 3.8086002,1.6699 6.5625002,1.2598 V 0.9375 c 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 z m -4.3652,8.4375002 c 0.3515,1.7284998 1.6992,3.0761998 3.4277,3.4276998 V 11.25 c 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 0.498,0 0.9375,0.4395 0.9375,0.9375 v 0.6152 C 10.1367,11.5137 11.4844,10.166 11.8359,8.4375002 H 11.25 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 h 0.5859 c -0.3515,-1.6992 -1.6992,-3.0469 -3.3983998,-3.3984 v 0.5859 c 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 v -0.5859 c -1.7285,0.3515 -3.0762,1.6992 -3.4277,3.3984 h 0.6152 c 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 z m 4.3652,0 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 z" d="m 7.5000002,0 c 0.498,0 0.9375,0.4395 0.9375,0.9375 V 1.2598 C 11.1621,1.6699 13.3301,3.8379002 13.7402,6.5625002 h 0.3223 c 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 H 13.7402 C 13.3301,11.1914 11.1621,13.3594 8.4375002,13.7695 v 0.293 c 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 v -0.293 C 3.8086002,13.3594 1.6406,11.1914 1.2305,8.4375002 h -0.293 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 h 0.293 C 1.6406,3.8379002 3.8086002,1.6699 6.5625002,1.2598 V 0.9375 c 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 z m -4.3652,8.4375002 c 0.3515,1.7284998 1.6992,3.0761998 3.4277,3.4276998 V 11.25 c 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 0.498,0 0.9375,0.4395 0.9375,0.9375 v 0.6152 C 10.1367,11.5137 11.4844,10.166 11.8359,8.4375002 H 11.25 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 h 0.5859 c -0.3515,-1.6992 -1.6992,-3.0469 -3.3983998,-3.3984 v 0.5859 c 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 v -0.5859 c -1.7285,0.3515 -3.0762,1.6992 -3.4277,3.3984 h 0.6152 c 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 z m 4.3652,0 c -0.5273,0 -0.9375,-0.4102 -0.9375,-0.9375 0,-0.498 0.4102,-0.9375 0.9375,-0.9375 0.498,0 0.9375,0.4395 0.9375,0.9375 0,0.5273 -0.4395,0.9375 -0.9375,0.9375 z"
fill="#5ca7ff" fill="#5ca7ff"
id="path2" /> id="path2"
style="stroke: none"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -39,5 +39,6 @@
<path <path
d="m 10.796771,3.75 c 0,1.31836 -0.7618,2.46094 -1.8750496,3.13476 v 0.61525 c 0,0.5273 -0.43945,0.9375 -0.9375,0.9375 h -2.8125 c -0.52734,0 -0.9375,-0.4102 -0.9375,-0.9375 V 6.88476 c -1.14258,-0.67382 -1.875,-1.8164 -1.875,-3.13476 0,-2.05078 1.875,-3.75 4.21875,-3.75 2.31445,0 4.2187996,1.69922 4.2187996,3.75 z M 4.9373514,5.15625 c 0.49804,0 0.9375,-0.41016 0.9375,-0.9375 0,-0.49805 -0.43946,-0.9375 -0.9375,-0.9375 -0.52735,0 -0.9375,0.43945 -0.9375,0.9375 0,0.52734 0.41015,0.9375 0.9375,0.9375 z m 4.21872,-0.9375 c 0,-0.49805 -0.43943,-0.9375 -0.93748,-0.9375 -0.52734,0 -0.9375,0.43945 -0.9375,0.9375 0,0.52734 0.41016,0.9375 0.9375,0.9375 0.49805,0 0.93748,-0.41016 0.93748,-0.9375 z M 0.10336144,8.02731 c 0.23438,-0.4687 0.79102,-0.6445 1.25976996,-0.4101 l 5.21484,2.6074 5.1854996,-2.6074 c 0.4688,-0.2344 1.0254,-0.0586 1.2598,0.4101 0.2344,0.4688 0.0586,1.0254 -0.4101,1.2598 l -3.9551196,1.9629 3.9551196,1.9922 c 0.4687,0.2344 0.6445,0.791 0.4101,1.2597 -0.2344,0.4688 -0.791,0.6446 -1.2598,0.4102 l -5.1854996,-2.6074 -5.21484,2.6074 c -0.46874996,0.2344 -1.02538996,0.0586 -1.25976996,-0.4102 -0.234374,-0.4687 -0.058593,-1.0253 0.41016,-1.2597 L 4.4685914,11.25001 0.51352144,9.28711 c -0.468753,-0.2344 -0.644534,-0.791 -0.41016,-1.2598 z" d="m 10.796771,3.75 c 0,1.31836 -0.7618,2.46094 -1.8750496,3.13476 v 0.61525 c 0,0.5273 -0.43945,0.9375 -0.9375,0.9375 h -2.8125 c -0.52734,0 -0.9375,-0.4102 -0.9375,-0.9375 V 6.88476 c -1.14258,-0.67382 -1.875,-1.8164 -1.875,-3.13476 0,-2.05078 1.875,-3.75 4.21875,-3.75 2.31445,0 4.2187996,1.69922 4.2187996,3.75 z M 4.9373514,5.15625 c 0.49804,0 0.9375,-0.41016 0.9375,-0.9375 0,-0.49805 -0.43946,-0.9375 -0.9375,-0.9375 -0.52735,0 -0.9375,0.43945 -0.9375,0.9375 0,0.52734 0.41015,0.9375 0.9375,0.9375 z m 4.21872,-0.9375 c 0,-0.49805 -0.43943,-0.9375 -0.93748,-0.9375 -0.52734,0 -0.9375,0.43945 -0.9375,0.9375 0,0.52734 0.41016,0.9375 0.9375,0.9375 0.49805,0 0.93748,-0.41016 0.93748,-0.9375 z M 0.10336144,8.02731 c 0.23438,-0.4687 0.79102,-0.6445 1.25976996,-0.4101 l 5.21484,2.6074 5.1854996,-2.6074 c 0.4688,-0.2344 1.0254,-0.0586 1.2598,0.4101 0.2344,0.4688 0.0586,1.0254 -0.4101,1.2598 l -3.9551196,1.9629 3.9551196,1.9922 c 0.4687,0.2344 0.6445,0.791 0.4101,1.2597 -0.2344,0.4688 -0.791,0.6446 -1.2598,0.4102 l -5.1854996,-2.6074 -5.21484,2.6074 c -0.46874996,0.2344 -1.02538996,0.0586 -1.25976996,-0.4102 -0.234374,-0.4687 -0.058593,-1.0253 0.41016,-1.2597 L 4.4685914,11.25001 0.51352144,9.28711 c -0.468753,-0.2344 -0.644534,-0.791 -0.41016,-1.2598 z"
fill="#5ca7ff" fill="#5ca7ff"
id="path2" /> id="path2"
style="stroke: none"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -39,5 +39,6 @@
<path <path
d="m 9.103975,1.603975 c 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 l -3.0762,3.0761 -3.1055,-3.0761 c -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 -0.3809,0.3515 -0.3809,0.9668 0,1.3183 l 3.0761,3.0762 -3.0761,3.1055 c -0.3809,0.3515 -0.3809,0.9668 0,1.3183 0.3515,0.3809 0.9668,0.3809 1.3183,0 l 3.1055,-3.0761 3.0762,3.0761 c 0.3515,0.3809 0.9668,0.3809 1.3183,0 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 l -3.0761,-3.1055 z" d="m 9.103975,1.603975 c 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 l -3.0762,3.0761 -3.1055,-3.0761 c -0.3515,-0.3809 -0.9668,-0.3809 -1.3183,0 -0.3809,0.3515 -0.3809,0.9668 0,1.3183 l 3.0761,3.0762 -3.0761,3.1055 c -0.3809,0.3515 -0.3809,0.9668 0,1.3183 0.3515,0.3809 0.9668,0.3809 1.3183,0 l 3.1055,-3.0761 3.0762,3.0761 c 0.3515,0.3809 0.9668,0.3809 1.3183,0 0.3809,-0.3515 0.3809,-0.9668 0,-1.3183 l -3.0761,-3.1055 z"
fill="#5ca7ff" fill="#5ca7ff"
id="path2" /> id="path2"
style="stroke: none"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -39,5 +39,6 @@
<path <path
d="m 7.0324294,0 c 0.1172,0 0.2637,0.0293 0.3809,0.0879 l 5.5077996,2.3437 c 0.6445,0.293 1.1425,0.9082 1.1425,1.67 -0.0292,2.9296 -1.2304,8.2324 -6.2694996,10.664 -0.498,0.2344 -1.0547,0.2344 -1.5527,0 -5.0391,-2.4316 -6.24020004,-7.7344 -6.24020004,-10.664 -0.0293,-0.7618 0.4687,-1.377 1.11320004,-1.67 l 5.5078,-2.3437 C 6.7394294,0.0293 6.8859294,0 7.0324294,0 Z m 0,1.9629 V 13.0371 C 11.075429,11.0742 12.159429,6.7676 12.188629,4.1602 Z" d="m 7.0324294,0 c 0.1172,0 0.2637,0.0293 0.3809,0.0879 l 5.5077996,2.3437 c 0.6445,0.293 1.1425,0.9082 1.1425,1.67 -0.0292,2.9296 -1.2304,8.2324 -6.2694996,10.664 -0.498,0.2344 -1.0547,0.2344 -1.5527,0 -5.0391,-2.4316 -6.24020004,-7.7344 -6.24020004,-10.664 -0.0293,-0.7618 0.4687,-1.377 1.11320004,-1.67 l 5.5078,-2.3437 C 6.7394294,0.0293 6.8859294,0 7.0324294,0 Z m 0,1.9629 V 13.0371 C 11.075429,11.0742 12.159429,6.7676 12.188629,4.1602 Z"
fill="#5ca7ff" fill="#5ca7ff"
id="path2" /> id="path2"
style="stroke: none"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

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