Compare commits

...

306 commits

Author SHA1 Message Date
f034ae4220
4.5! 2022-09-19 18:08:43 +02:00
d97499778c
docs: clarified when StreamAttack updates information
fixes #155
2022-09-15 15:17:39 +02:00
d78cf17b6b
docs: added reloading the profile / restarting VA to installation instructions
fixes #154
2022-09-15 15:15:41 +02:00
0d44828422
docs: clarified that neutron router plugin is optional
fixes #153
2022-09-15 15:13:20 +02:00
022c3ac25c
fixed VERSION 2022-09-15 15:08:54 +02:00
fd0bbaa3a9
added StyleCop.ruleset to make that one shut up 2022-09-15 15:07:15 +02:00
cc2694fc49
RatAttack: support for new Horizons 3.8 / 4.0 / Odyssey RATSIGNALs
fixes #159
2022-09-15 15:06:49 +02:00
9db6785ef1
RatAttack: fixed RATSIGNAL regex
Apparently `^` can be part of both CMDR names and IRC nicks.
2022-09-10 03:43:19 +02:00
1135efd761
EliteAttack: fixed potential race condition in the discovery scan event command queue 2022-09-06 00:29:51 +02:00
7c361e9bf7
EliteAttack: added option to exclude settlements from the outdated stations list
fixes #119
2022-09-05 19:21:12 +02:00
54cd1e6fa2
EliteAttack: target nearest […] commands now log the result 2022-08-31 10:26:12 +02:00
3775d3f911
docs: added troubleshooting section about Geforce Now 2022-08-23 22:26:11 +02:00
alterNERDtive
1357bde807
Merge pull request #151 from alterNERDtive/feature/auto-pull-request 2022-07-13 22:26:07 +02:00
db85c2b793
auto-pull-request workflow: fixed branch name 2022-07-13 22:25:13 +02:00
4f9e4799bf
workflows: open pr on branch push 2022-07-13 22:23:45 +02:00
5af0aff95c
workflows: fixed release author 2022-07-13 21:15:35 +02:00
e2789623cd
cleaned up dependency mess 2022-07-12 00:40:55 +02:00
c615af5324
updated CHANGELOG 2022-07-11 19:52:39 +02:00
Ant
4e9a9b4517
Black out the grey censory block 2022-07-11 19:45:29 +02:00
Ant
38ea143ea7
SpanshAttack.md: fix column width 2022-07-11 19:45:25 +02:00
Ant
0ee7701590
EliteAttack: hyperlink path fix - DOH 2022-07-11 19:45:21 +02:00
Ant
05a56d5d85
index.md: correction to hyperlink markdown syntax 2022-07-11 19:45:05 +02:00
Ant
2ec9c2afbe
EliteAttack.md: correction to hyperlink markdown syntax 2022-07-11 19:44:49 +02:00
Ant
3cbfe62ae1
docs markdown fixes & author privacy on screenshot 2022-07-11 19:44:19 +02:00
dependabot[bot]
9cc9965d7c Bump Newtonsoft.Json from 6.0.4 to 13.0.1 in /plugins/VoiceAttack-base
Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 6.0.4 to 13.0.1.
- [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases)
- [Commits](https://github.com/JamesNK/Newtonsoft.Json/compare/6.0.4...13.0.1)

---
updated-dependencies:
- dependency-name: Newtonsoft.Json
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-08 17:52:13 +02:00
acf43b42a0 added .github as solution items 2022-07-08 17:52:09 +02:00
55fa3579cf fixed gh-pages workflow 2022-07-08 17:45:39 +02:00
d1af3ebdcc Merge branch 'release' into devel 2022-07-04 01:32:38 +02:00
b10e2bb2c4 added ko-fi / sponsors 2022-07-04 01:32:29 +02:00
91c47efbef fixed create-release workflow
fixes #148
2022-07-04 00:33:28 +02:00
1cdd9c98bd EliteAttack: fixed Docked event for Oddity settlements
fixes #145
2022-06-16 12:10:49 +02:00
35c26e930f mics fixes 2022-06-16 12:06:28 +02:00
bb8d1067b5 RatAttack: made case list thread safe
My specific setup leads to lots of incoming cases at once when starting VA after boot, when the IRC backlog is parsed.

Probably not relevant in the wild, but still a huge 🤦.
2022-06-03 16:45:12 +02:00
6ec8d7c35e stylecop compliance, round 3 of >3 2022-06-02 17:41:49 +02:00
55f10a1117 all plugins: fixed possible race condition introduced in 4.4 2022-06-02 15:28:17 +02:00
35057b3f35 dependabot 2022-06-01 09:12:01 +02:00
a2f6cc864c auto-deploy gh-pages 2022-06-01 09:11:57 +02:00
9beb6dfa41 Merge branch 'devel' into release 2022-05-31 19:31:28 +02:00
2dae2abc4c workflows: fixed(?) release glob 2022-05-31 19:29:08 +02:00
99305cfb5d 4.4! 2022-05-31 19:23:00 +02:00
bc5addd22a base: removed delays.keyPressDuration option since that isn’t actually used rn 2022-05-30 23:38:21 +02:00
64a096dae7 StyleCop compliance, round 2 of 3 … 2022-05-30 23:22:48 +02:00
33a4fb8e3d base: made config GUI buttons wider 2022-05-30 21:59:52 +02:00
3cbca1e542 base: config GUI now .Activate()s immediately 2022-05-30 21:58:46 +02:00
55a031686c auto draft a release on tag push 2022-05-30 21:28:09 +02:00
02a401a047 housekeeping 2022-05-30 21:25:08 +02:00
e36358be9f stylecop compliance, round 1 2022-05-29 22:16:17 +02:00
999d2b6883 alterNERDtive-base: configuration GUI now has an “Apply” button 2022-05-29 21:32:43 +02:00
e73b8c04f9 bump to c# 10 because why not 2022-05-29 21:14:54 +02:00
931ee4c4e7 RatAttack: added warning when running VA as Admin
fixes #138
2022-05-29 11:13:49 +02:00
751f80461f RatAttack-cli: added error message for running VA as Admin
see #138

Writing to other users’ pipes will cause an exception. You should not run VA elevated.

Needs a warning in VA too.
2022-05-29 10:51:51 +02:00
c9d39f6cc7 docs: typos 2022-05-28 15:09:00 +02:00
f8dd1ff464 docs: added upgrading EDDI event handlers to upgrading.md 2022-05-28 15:05:08 +02:00
f7328e31e2 bumped VERSION
I feel like I should do that whenever I bump it in base.cs …
2022-05-28 14:27:44 +02:00
2b0d2245e2 RatAttack: fixed superfluous “ly” output in distance to commands
fixes #140
2022-05-28 14:19:35 +02:00
dc42912cbe EliteAttack: fixed auto station services option
fixes #142
2022-05-28 14:19:08 +02:00
b3ad1ae799 switched for make to msbuild
Build file still private, since it relies on my local folder structure.
2022-05-27 20:20:41 +02:00
5421478d6e SpanshAttack: fixed getting current jump range from EDDI
Not waiting for the plugin context to finish running caused it to pretty consistently fail on the first attempt, and return the last value for attempts after that.
2022-05-22 12:49:06 +02:00
d771d0b403 docs: fixed weird character in general.md 2022-05-22 12:46:50 +02:00
b371523910 EliteAttack: added options from #133 i forgot
* auto retract landing gear
* auto disable SRV lights

fixes #133
2022-05-19 13:16:00 +02:00
8572d0ec4c CHANGELOG: typo 2022-05-19 12:54:22 +02:00
c00c1d9bbe Merge branch 'devel' into release 2022-05-19 12:49:30 +02:00
0c0cf068c4 4.3! 2022-05-19 12:46:31 +02:00
42faaa20d5 SpanshAttack: no longer pretends there’s a route if there isn’t
fixes #104
2022-05-19 12:40:38 +02:00
da9a6f6107 SpanshAttack: moved jumps announcement to end of jump instead of start
fixes #124
2022-05-19 12:19:47 +02:00
a5b22a8908 EliteAttack: workaround for bugged Body scanned EDDI events
fixes #121
2022-05-19 12:13:26 +02:00
20599fef88 EliteAttack: added logging to find nearest […] command
fixes #96
2022-05-19 12:08:00 +02:00
99438b4ed3 RatAttack: no longer sliently swallows calls if confirmation is disabled
fixes #128
2022-05-19 12:00:53 +02:00
368b7ca771 alterNERDtive-base: no longer cuts off EDDI’s “update available” TTS on startup
fixes #120
2022-05-19 11:58:47 +02:00
5442738a21 RatAttack: clarified call confirmation TTS
fixes #101

Also clarified that there _is_ call confirmation in the documentation.
2022-05-19 11:55:02 +02:00
d6cd7da11c docs: reordered setup instructions to clarify that the profile example already comes with a startup command
fixes #126
2022-05-19 11:48:44 +02:00
2f4015001f docs: clarified not having to install bundled dependencies manually
fixes #127
2022-05-19 11:44:08 +02:00
81b83bba2d docs: now mentions reloading the custom profile after initially adding its startup command
fixes #129
2022-05-19 11:41:48 +02:00
2544be701c RatAttack: added option for auto copying a client’s system on opening a case
Also updated the documentation to mention copying happens in the first place; fixes #130
2022-05-19 11:39:09 +02:00
9a8d7b646f CHANGELOG: forgot to add last fix 2022-05-19 11:33:05 +02:00
999650e84f docs: added HCS compatibility bit to troubleshooting.md
fixes #132
2022-05-19 11:31:23 +02:00
f69e3c03bd EliteAttack: make all docking actions optional
fixes #133
2022-05-19 11:18:52 +02:00
e81f3961ea alterNERDtive-base: fixed settings dialog closing prematurely 2022-05-18 13:55:35 +02:00
8a3b17d674 added rudimentary settings UI
Accessible by plugin context `config.dialog` or saying `customize settings`.

fixes #80
2022-05-18 13:50:14 +02:00
d038c58595 RatAttack: accounting for . in the lang part of a RATSIGNAL 2022-04-19 11:45:56 +02:00
08aaa3db8a RatAttack: fixed edge case with off duty + nearest CMDR
No longer announces the nearest CMDR if that option is turned off while
also being off duty alltogether. There was a missing condition there …
2022-04-18 13:36:30 +02:00
7cad49a6c2 general: added open documentation command 2022-04-18 12:48:31 +02:00
2997b8335c docs: added EDDI quiet mode info to requirements.md 2022-03-04 15:25:28 +01:00
5bf21a48ba docs: added tidbit about galaxy map vs. interface bindings conflict 2021-09-29 10:26:27 +02:00
28854968fd RatAttack: now gives feedback after asking for call confirmation 2021-09-18 14:26:14 +02:00
00923f3da5 EliteAttack: now throttling down on FSD engage, too 2021-09-18 14:23:42 +02:00
fa4e9535ba EliteAttack: added INFO logging for carrier events 2021-09-11 16:38:30 +02:00
302fd9f512 docs: mild un-doxxing 2021-08-26 15:05:39 +02:00
0e757eaf76 Merge branch 'devel' of https://github.com/alterNERDtive/VoiceAttack-profiles into devel 2021-08-26 14:59:34 +02:00
7bc58f19ef docs: fixed some typos/inconsistencies/mistakerinos 2021-08-26 14:51:11 +02:00
4836273007 RatAttack: allow , in lang strings 2021-07-19 19:45:16 +02:00
adcb01bead docs: added link to CHANGELOG on Github 2021-07-04 21:00:57 +02:00
61e7f00c1f RatAttack: fixed “Not Set” case number when asking for details about an invalid case 2021-07-04 03:58:02 +02:00
a57daf35a7 CHANGELOG: typo corrected 2021-06-23 09:45:02 +02:00
e12bb8a2ea docs: added disclaimer on Oddity development 2021-06-23 09:12:11 +02:00
f00fd22234 docs: update installation instructions 2021-06-23 09:06:17 +02:00
2715fa2a48 RatAttack: fixed RATSIGNAL parsing for system information containing /
e.g. “Herbig AE/BE star”
2021-06-18 11:37:05 +02:00
36abf8b53b sorted out the utf-8 crap 2021-06-14 11:50:15 +02:00
bcbde1dd47 mkdocs: mark external links 2021-06-14 11:24:41 +02:00
ec87397a92 .editorconfig: default to utf-8 2021-06-14 11:21:46 +02:00
4483945f6a SpanshAttack: OBOE on last jump
Introduced when I switched to announcing jumps on FSD engage. Or rather side effect of correcting the OBOE in the Spansh plugin + that change.
2021-06-14 09:12:17 +02:00
3261c11d70 docs: removed the 32/64 bit thing
VoiceAttack is now 64bit by default, if anyone insists on running the 32bit one they can sort it out for themselves :)
2021-06-14 09:10:24 +02:00
7c1c75ec98 RatAttack: turns out there can be & in a lang identifier 2021-06-01 20:51:20 +02:00
f6b5621bb2 docs: typo 2021-05-27 12:32:42 +02:00
a1ddb987e0 RatAttack: No longer trying to get nearest CMDR for the new “Unconfirmed” system info. 2021-05-26 17:17:15 +02:00
3c46b20a23 Merge branch 'devel' into release 2021-05-23 20:36:24 +02:00
b633d8791c 4.2.3! 2021-05-23 20:32:41 +02:00
a5a3740799 updated .editorconfig 2021-05-23 20:28:45 +02:00
1d6ee3953e updated .editorconfig 2021-05-23 20:26:54 +02:00
d47ea2597c 4.2.2! 2021-05-19 17:45:29 +02:00
42488b3bcf RatAttack: slightly changed case announcements 2021-05-19 17:44:21 +02:00
25a7440c7b CHANGELOG: bindED 4.0 tidbit 2021-05-19 12:41:34 +02:00
254ada7318 Preemptively changed VERSION before I forget it again … 2021-05-19 10:02:04 +02:00
aed4609ed8 RatAttack: fixed code red detection
… broke with the reworked case announcement.

fixes #115
2021-05-19 09:54:40 +02:00
1991e6b5f6 RatAttack: correctly handles "" system now
Still not sure if a completely empty system (happens on manual RATSIGNAL) is intentional; but I’m handling it gracefully now, defaulting to “None”.
2021-05-19 09:53:31 +02:00
b30074317f RatAttack: support for Odyssey
Due to split instancing between Horizons and Odyssey the RATSIGNAL announcement now contains extra info on that.

fixes #114
2021-05-19 09:51:00 +02:00
3b9031ae59 forgot to bump VERSION … 2021-05-03 10:39:32 +02:00
2d8b923d0e 4.2.1! 2021-05-03 10:30:48 +02:00
c546c22bc4 CHANGELOG: clarified not-fixed #105 2021-05-03 10:28:13 +02:00
387f17db1d docs: temporarily disabled pdf 2021-05-03 10:17:15 +02:00
ef86f0a517 docs: reworded the 32/64-bit section of INSTALLING 2021-05-03 09:16:18 +02:00
2411514643 spring cleaning 2021-05-02 16:17:29 +02:00
7aaf8d62b1 RatAttack: implemented new RATSIGNAL format
… also now stripping IRC formatting for my own sanity’s sake

fixes #111
2021-05-02 16:09:52 +02:00
68716bb45b EliteAttack: fixed on-demand outdated station check invocation
fixes #108
2021-04-27 17:38:52 +02:00
9705bba899 RatAttack: RATSIGNAL parsing fixed for landmarks with alternate name 2021-04-05 15:51:19 +02:00
2cda77edda RatAttack: RATSIGNAL parsing fixed for proc gen landmarks 2021-04-05 15:37:35 +02:00
ffad1ffa28 RatAttack: fixed “unknown system” in RATSIGNAL 2021-04-03 21:39:50 +02:00
0c592af8e2 EliteAttack: don’t honk after a hyperdiction
fixes #105
2021-03-18 22:41:27 +01:00
9745e1ccb1 base: no longer warn on missing init command 2021-03-15 18:38:09 +01:00
4fcca54ff0 EliteAttack: fixed variable names in the gear/scoop/hardpoints command 2021-03-12 22:32:03 +01:00
71615e366c RatAttack: fixed language string parsing for numbers 2021-03-10 19:57:37 +01:00
26dd98f050 docs: note on mIRC and hex for IRC setup 2021-03-10 13:36:42 +01:00
fd0e07ecfa RatAttack: removed TTS&logging from invalid signals, for real this time 2021-03-10 13:31:43 +01:00
eda735a426 4.2! 2021-03-09 20:13:19 +01:00
4495d9ead2 RatAttack: amended regex for special character in language strings 2021-03-09 20:09:25 +01:00
1904dd6d41 RatAttack: various RATSIGNAL regex fixes
* numbers in IRC nick
* proper detection of language, pervented IRC nick from being found in the first place
* fix to cardinal direction estimation detection
2021-03-08 21:25:28 +01:00
a5b0d175a2 EliteAttack: "limpet check" configuration option 2021-03-08 20:38:50 +01:00
b2f8ec96d6 RatAttack: fixed RATSIGNAL parsing for “cardinal direction” addition to distance estimates for proc gen systems. 2021-03-08 19:37:28 +01:00
7511d59641 RatAttack: added distance to latest rat case command
… also fixed some dumb bug in the other distance commands.
2021-03-07 22:04:00 +01:00
e4ea1abb5e docs: typo 2021-03-04 23:27:46 +01:00
5e94677048 docs: note about no VA update checking in the Steam version 2021-03-04 23:22:53 +01:00
99dfc2cf09 docs: fixed misspelt/dead link 2021-03-04 23:18:11 +01:00
9ce06804f4 README: explicitly mentioned installation guide in the docs 2021-03-04 23:11:07 +01:00
4fba3ef79b RatAttack: Fixed RATSIGNAL parsing for new wording of injected cases with no system given. 2021-02-24 19:08:15 +01:00
2d6c96fce0 SpanshAttack: moved EDTS stuff to plugin code
see #62
2021-02-22 21:28:53 +01:00
fdccb3a4ff RatAttack: Fixed RATSIGNAL parsing for “Sagittarius A*” landmark. 2021-02-21 07:13:44 +01:00
5d429d463a 4.1! 2021-02-19 23:14:14 +01:00
b4f26f33c8 RatAttack: latest rat case details command 2021-02-19 23:11:54 +01:00
bc902310f8 EliteAttack: AFMU repairs & Synthesis repairs
see #86
2021-02-18 12:06:06 +01:00
eee768896b RatAttack: attempt at narrowing down the Regex
Too lenient systemInfo part was gobbling up the permit stuff; might be fixed now, hopefully …
2021-02-18 01:04:15 +01:00
4c3b890120 RatAttack: Updated RATSIGNAL parsing for new nick announcement
see 1686fced33
2021-02-17 13:24:44 +01:00
d210779967 SpanshAttack: fixed summary for doing 0j 2021-02-16 21:47:03 +01:00
14092bf174 RatAttack: removed “Valid system name” thing from the regex
Mecha now gives an estimation based on the sector name!
2021-02-16 12:08:44 +01:00
c47c26482c RatAttack: narrowed down sys name regex for landmark
Seems to not cause issues so far ;)
2021-02-16 12:07:32 +01:00
6cd7722db1 RatAttack: fixerinoed the colour thing for invalid systems in a RATSGINAL line 2021-02-14 01:34:13 +01:00
72633273e1 RatAttack: updated RATSIGNAL parsing for “Invalid system name” and colouration 2021-02-12 22:28:02 +01:00
dc216dade8 EliteAttack: fixed Material Threshold event logging 2021-02-12 18:42:50 +01:00
62b94b000e SpanshAttack: added actual jump count
fixes #82
2021-02-12 14:51:30 +01:00
4bd6ccc7a7 SpanshAttack: skip [this;current] neutron waypoint command
Skips the next neutron waypoint.

fixes #94
2021-02-12 14:40:36 +01:00
bd94f2e0f8 RatAttack: now makes use of Mecha’s system info
* announces it with an incoming case
* no longer looks up your nearest CMDR if the system is neither in Mecha’s galaxy database nor a potentially valid system name (fixes #89)
2021-02-12 13:46:31 +01:00
0d0fdc58a8 CHANGELOG: format fix, added line between early versions 2021-02-12 12:07:43 +01:00
f2ca6dd0ad CHANGELOG: fixed RatAttack version typo 2021-02-12 11:39:30 +01:00
fa645fc369 EliteAttack: new config option “route jump count”
Give a jump count on plotting a route.
2021-02-12 11:38:17 +01:00
f0a006a113 docs: fixed borked link 2021-02-12 11:15:16 +01:00
ec7f6798eb RatAttack: call jumps [left;] command 2021-02-12 05:37:05 +01:00
4affcb85ff EliteAttack: how many jumps left command 2021-02-12 05:20:04 +01:00
27dbffbe79 EliteAttack: restricted outdated stations check to inhabited systems again 2021-02-09 13:27:19 +01:00
205f90870b RatAttack: Updated RATSIGNAL parsing to correctly handle new format for landmark systems. 2021-02-08 18:56:47 +01:00
d512b5edbc RatAttack: removed TTS from invalid RATSIGNAL trigger 2021-02-08 18:28:53 +01:00
9c1406c08b docs: RatAttack links back to IRC settings now 2021-02-04 19:08:33 +01:00
c7cbaec218 4.0.2! 2021-02-04 06:13:56 +01:00
7c7a6b8718 RatAttack: RATSIGNAL parsing fixed for latest changes
fixes #93
2021-02-03 23:54:28 +01:00
0e350ccc3d docs: added troubleshooting stuff
Also removed the “VoiceAttack Tips” section for now, empty anyway and probably redundant.
2021-01-31 15:26:30 +01:00
32f43660fd docs: slightly more inclusive upgrading instructions 2021-01-30 18:52:35 +01:00
e1b42b8c0c 4.0.1! 2021-01-30 18:48:08 +01:00
dcd58e1d23 SpanshAttack: fixed not getting next waypoint correctly 2021-01-30 18:42:45 +01:00
1106aafffe CHANGELOG: link fixed 2021-01-30 14:37:48 +01:00
fe3c84b4f2 docs: typo 2021-01-30 12:52:47 +01:00
7669290a65 docs: fixed to EliteAttack.md 2021-01-29 19:04:00 +01:00
94a5429818 docs: moved CHANGELOG link to the UPGRADING section 2021-01-29 19:03:42 +01:00
9495117a4a docs: added recognition issues to troubleshooting.md 2021-01-29 17:22:05 +01:00
78f6f955e3 4.0! 2021-01-29 14:58:26 +01:00
788b8a9d7b RatAttack: made code reds more prominent in the VA log. 2021-01-28 15:42:16 +01:00
13e812e310 SpanshAttack: moved logic from Jumped to FSD engaged
Now pulling/announcing the next neutron waypoint at the start of a jump instead of at the end.
2021-01-28 15:41:58 +01:00
c0875cde48 EliteAttack: moved logic from Jumped to FSD engaged
Getting the EDSM body count and outdated stations will now happen on
engaging FSD instead of finishing the jump.

With the increased latency on the EDSM API I’m seeing lately this was
very much needed to get the body count in time for the discovery scan
after the jump.

fixes #85
2021-01-28 15:30:21 +01:00
c2e30eb9da docs: another round of fixerinos 2021-01-28 02:37:49 +01:00
8c80a4389c EliteAttack: fixed TTS for trying to log out while in danger 2021-01-27 14:45:03 +01:00
58b4860a58 docs: proof reading, round 1 2021-01-25 17:56:21 +01:00
a355af016d docs: DONE! 2021-01-25 14:34:14 +01:00
ddc5bd9bcb MOAR DOCS (we’re getting there :D) 2021-01-25 12:04:28 +01:00
53d6472e01 alterNERDtive-base: fixed reload elite key binds command 2021-01-25 12:02:20 +01:00
e6766e67a8 RatAttack-cli: case-insenstive flag parameter 2021-01-25 11:01:36 +01:00
6731dfd44e alterNERDtive-base: re-implemented auto update check 2021-01-25 10:44:57 +01:00
8330e181db docs: upgrading & general settings 2021-01-25 01:09:46 +01:00
d3d668f65b RatAttack: added Mecha-provided system info to VA log 2021-01-23 19:18:11 +01:00
b8d811bca3 RatAttack: more RATSIGNAL fixes for Mecha3 changes 2021-01-21 23:04:25 +01:00
cc9b382d72 docs: added version warning 2021-01-21 16:25:27 +01:00
4befa49fe2 merged origin/devel 2021-01-21 15:45:49 +01:00
580abc8300 first round of new documentation! 2021-01-21 15:42:00 +01:00
da81ae5985 preliminary CHANGELOG 2021-01-21 15:32:05 +01:00
2bdab1a4c7 alterNERDtive-base: added open [docs;documentation;help] file command 2021-01-21 15:30:59 +01:00
a3cef9d365 alterNERDtive-base: added open [docs;documentation;help] command 2021-01-21 14:58:42 +01:00
6f6fb9219b removed file logging, because TRACEing apparently doesn’t work properly everywhere 2021-01-20 12:31:13 +01:00
a3bd10f4ae added mkdocs 2021-01-20 12:29:15 +01:00
abd3b07e60 EliteAttack: fixed Material threshold event 2021-01-20 11:35:33 +01:00
f153d3aa75 RatAttack: RATSIGNAL no longer has not in databes info 2021-01-20 11:32:32 +01:00
526730902f RatAttack: RATSIGNALs now have system names in quotes … 2021-01-19 23:16:04 +01:00
2306beb801 SpanshAttack: typon in token 2021-01-18 10:16:18 +01:00
4bab6a13e8 POG 2021-01-17 23:52:05 +01:00
1fb6d57cce SpanshAttack: print calculated jumps to VoiceAttack log 2021-01-17 19:13:47 +01:00
327be7a5c4 build prep 2021-01-16 14:09:39 +01:00
8d7ff42a48 CHANGELOG mistake 2021-01-16 11:02:13 +01:00
1a3846896a Merge branch 'plugin-rewrite' into devel 2021-01-16 11:00:25 +01:00
08ea88fbb9 alterNERDtive-base: update mechanism
Reverted to semi-manual aprroach.

fixes #65
2021-01-16 09:29:52 +01:00
22505515d3 alterNERDtive-base: changed some voice triggers 2021-01-16 04:30:47 +01:00
525e777913 alterNERDtive-base: added config.list plugin context
… and voice commands for listing both available settings (`… list [options;settings]`) and dumping them (`… report [options;settings]`).
2021-01-16 03:56:58 +01:00
ffa7ebcf5d alterNERDtive-base: revised config voice triggers, added descriptions 2021-01-16 03:39:40 +01:00
21a7e8cf50 now using type hint’s for EDDI’s {P("thing")} 2021-01-16 01:15:00 +01:00
2586d438b3 alterNERDtive-base: fixed race condition
Need to wait for the VA command to return when loading config variables from the profile.
2021-01-08 16:46:10 +01:00
44806fee9a 3.2.1! 2021-01-02 20:41:39 +01:00
faa38b194b RatAttack: backported RATSIGNAL regex fix 2021-01-02 18:53:42 +01:00
7cb429455c RatAttack: oh look, RATSIGNAL format changed. Again.
This time “Case #X” got delimited by ^B / \x02. Cool.
2021-01-02 18:27:22 +01:00
49ed63b421 removed deprecated VERSION file 2020-12-31 01:38:58 +01:00
55e008108a 3.2.0! 2020-12-31 01:34:18 +01:00
49ca50589a changed update command in preparation for 4.0 2020-12-31 01:28:20 +01:00
55b2ce9f6b RatAttack: backported Mecha3 permit colour change 2020-12-31 01:20:16 +01:00
0e199f88dc RatAttack: permit stuff in RATSIGNALS has been changed from red to orange … 2020-12-31 01:06:30 +01:00
ad55954f65 RatAttack: killed Settings stuff that has been accidentally generated at some point … 2020-12-29 19:19:32 +01:00
3e5430431f RatAttack: added constraints for “platforms” config option 2020-12-29 19:16:07 +01:00
4c75dbd236 Reworked logging.
No more cross-logging, using Trace for file logging.
2020-12-29 19:08:14 +01:00
6186d24096 EliteAttack: added “auto honk all systems” option 2020-12-29 13:21:15 +01:00
afc49ed7e5 alterNERDtive-base: fixed active profiles list, added “installed” list 2020-12-29 13:18:18 +01:00
4d4f22e216 EliteAttack: made scanner fire group configurable 2020-12-26 01:13:26 +01:00
7d104a2be2 EliteAttack: added options to auto honking
You can now a) disable auto honking new systems and b) set the discovery scanner to primary fire.
2020-12-25 18:23:51 +01:00
87610b1bbd EliteAttack: made EDDI discovery scan use command queue for TTS
Should fix ordering issues with the 2 TTS parts.
2020-12-25 15:44:38 +01:00
6f51333bd4 RatAttack: changed RATSIGNAL separator from | to \x02
Apparently `|` are valid in CMDR names. So now we’re using a proper separator character instead.
2020-12-19 13:26:04 +01:00
a9a1a84aa7 alterNERDtive-base: removd Python.scriptPath config
Scripts aren’t being called from VoiceAttack commands anymore.
2020-12-10 20:20:40 +01:00
0569a90aa3 SpanshAttack: added plugin, moved script execution there 2020-12-10 20:11:53 +01:00
dc71f21fe4 Moved all but SpanshAttack from having the profile invoke the Python scripts to the plugin wrapper. 2020-12-09 21:19:47 +01:00
aea70224da RatAttack: updated RATSIGNAL regex to the latest Mecha changes
Platform `PS` changed to `Playstation`.

In before it changes to `PlayStation` next week.
2020-12-09 21:01:36 +01:00
c1dcbb0817 removed VoiceAttack logging from all EDDI event handlers
If you want to see them, set DEBUG log level.

see #77
2020-12-09 00:40:54 +01:00
82c1cc065e misc profile fixes 2020-12-09 00:15:44 +01:00
03bfc512fc alterNERDtive-base: made startup command more robust
If you somehow prevented the active profile from resetting (e.g. by hitting the edit button while the startup command was still running) you’d get the config loaded flag to stick around, causing profile change/reload to not reset options anymore.

The flag is now a profile-scoped (`>>`) variable to prevent that. There are still some corner cases left, but resetting the profile should always work.
2020-12-08 12:12:13 +01:00
9d8eedd581 alterNERDtive-base: added some parameter checking for contexts that didn’t have it 2020-12-08 12:05:37 +01:00
69b097d7c3 alterNERDtive-base: added base plugin to profiles list
E.g. allows to have specific event handlers in the base profile.

Also fixed missing GUID in the base profile … that would have been a bummer if it made it to release.
2020-12-08 11:44:29 +01:00
c5eb93dd0e alterNERDtive-base: config options now strongly typed with generics 2020-12-08 11:21:58 +01:00
9637975bdb alterNERDtive-base: fixed config change handling 2020-12-08 09:20:37 +01:00
afee22cf62 alterNERDtive-base: moved loglevel setting from context to config option 2020-12-07 21:45:17 +01:00
e8134e240d alterNERDtive-base: fixed non-string config settings commands 2020-12-07 20:56:40 +01:00
e9ea4a2576 hid the log entries for lots of events
* top level `((EDDI <event>))` commands
* profile events (including `((<profile>.startup))`)

see #77
2020-12-07 20:47:07 +01:00
cd4390c9ef alterNERDtive-base: added active profile list logging to startup context 2020-12-07 20:38:49 +01:00
d15fae9197 EliteAttack: migrated to new config
Also changed names `EliteDangerous` -> `EliteAttack`
2020-12-07 20:25:24 +01:00
4bb10e28f5 chaged <profile>.startup to ((<profile>.startup)) 2020-12-07 18:15:49 +01:00
dac75b7af3 added custom profile example 2020-12-07 18:11:12 +01:00
e179fef0d1 SpanshAttack: migrated to new config 2020-12-07 18:09:26 +01:00
f6a4861a06 alterNERDtive-base: added config.dump plugin context
Dumps a list of all configuration options + their current value to the VoiceAttack log. Will also mention if they are set to the default.
2020-12-07 16:29:07 +01:00
58435a350e StreamAttack: fixed distance calculation commands 2020-12-07 14:27:57 +01:00
9baa3a1be4 added wrapper command for EDDI speech responders 2020-12-05 20:18:22 +01:00
ed0c9449c7 alterNERDtive-base: fixed config only being loaded on _initial_ startup 2020-12-04 17:48:32 +01:00
146653bdeb alterNERDtive-base: prevented variable load/save from showing in the log
see #77
2020-12-04 17:42:51 +01:00
c2d5655703 RatAttack: added support for manually injected cases, missing the system
fixes #76
2020-12-03 17:07:37 +01:00
977b0c74d7 Did you know VoiceAttack doesn’t like capitalization in strings? 2020-12-03 16:02:40 +01:00
c17355229f StreamAttack: moved to new config 2020-12-03 13:49:10 +01:00
e5183a6d5f upped version numbers 2020-12-03 02:15:11 +01:00
8bf6135482 alternNERDtive-base: upgraded config migration to INFO 2020-12-03 02:10:55 +01:00
1a5ae485b6 RatAttack: migrated to new configuration 2020-12-03 02:05:16 +01:00
ba0021c3bd alterNERDtive-base: plugin context namespacing 2020-12-03 00:51:51 +01:00
7f79af826f alterNERDtive-base: now also automatically loading config from profile 2020-12-02 20:28:09 +01:00
606f651eb6 alterNERDtive-base: plugin now fully supports the new configuration approach 2020-12-02 19:08:46 +01:00
ca52c39da3 replaced string.equals() with == for consistency 2020-12-02 11:19:37 +01:00
22f6365f60 RatAttack: made RATSIGNAL regex readonly, as it should be 2020-12-02 11:08:10 +01:00
c7c99995d4 RatAttack: extended commands for up to 30 cases 2020-12-01 09:37:31 +01:00
0a3cc4cf3e EliteAttack: added [where's;where is] my landing pad command 2020-12-01 09:36:47 +01:00
10cd0c8811 EliteDangerous: removed outdated IRC nick stuff from the docs
fixes #74
2020-11-29 12:17:37 +01:00
c7404c2563 README: updated bindED bit
fixes #75
2020-11-29 12:15:27 +01:00
01c162c459 RatAttack: fixed case list for >20 cases …
It’s one of these days when you look at your code and you are like “WTF was I thinking?!”.
2020-11-23 20:52:44 +01:00
d9199d0dee README: updated link to bindED 2020-11-22 19:15:09 +01:00
72af5a3683 added GPL license 2020-11-18 17:16:48 +01:00
b09dc47f5c RatAttack: changed platform PS4 to PS to match latest Mecha3 changes 2020-11-18 17:16:36 +01:00
2585a5a4b3 EliteAttack: removed manual cooldown event on carrier jump cancel
EDDI now handles that in the latest beta, so no need to manually fiddle.
2020-11-10 09:25:23 +01:00
77ecc1a2d9 base: added generate missing key binds report command 2020-11-09 10:16:54 +01:00
9f326c88ad base: removed explicit bindED invocation from startup 2020-11-09 08:30:35 +01:00
957caa9780 3.1.3! 2020-11-06 13:19:07 +01:00
caa432859c StreamAttack: jump target now takes Spansh plot target if set 2020-11-03 01:55:31 +01:00
3419aeb44b util: fixed hard-coded pipe name 2020-10-25 20:26:02 +01:00
288f3f3678 RatAttack: backported latest regex changes 2020-10-25 20:20:19 +01:00
a96a3c9d87 RatAttack: Oh look! RSIG announcement format changed again! 2020-10-25 20:18:34 +01:00
12d946f036 RatAttack-cli: fixed timeout, added TimeoutException handling 2020-10-25 12:39:34 +01:00
a63b6f7a87 RatAttack: fixed permit announcement in the VA profile 2020-10-25 00:32:37 +02:00
1d63f58097 RatAttack: fixed setting ~permitName for VoiceAttack 2020-10-24 19:23:54 +02:00
006bbcac3b base: fixed error handling for the distancebetween context 2020-10-24 16:28:24 +02:00
cd9437c59d RatAttack: permit announcements 2020-10-23 17:38:53 +02:00
92eee3f1e7 RatAttack: more backported fixes:
* System names will now be `ToLower()`ed since Mecha3 capitalizes them and EDDI
  likes spelling those out instead of saying the names. Makes them a little
  messy in other ways, but less annoying overall.
* Permit detection part of the RATSIGNAL RegEx fixed for named permits.
* `XB` platform changed to `Xbox` to match Mecha3.
2020-10-23 01:40:31 +02:00
a23dd5816f StreamAttack: fixed missing jumpTarget distance output 2020-10-23 01:26:36 +02:00
6633af6060 RatAttack: added new VA Event ((RatAttack.invalidRatsignal))
Fires when a signal doesn’t match the current RegEx. By default warns with TTS and writes the signal to `%appdata%\RatAttack\ratsignal.error.log`.
2020-10-23 00:05:26 +02:00
e14512f076 RatAttack: apparently Mecha3 also has permit NAMES. 2020-10-22 23:45:27 +02:00
d9f940c7bc RatAttack: apparently the XB platform is now Xbox 2020-10-21 23:26:51 +02:00
5623d47aa9 RatAttack: formatting changes 2020-10-21 20:59:31 +02:00
f1f78e69ce RatAttack: more Mecha3 fixes
I’ve heard there have been a couple other misc changes, reflected now. Also added `PermitLocked` Property to the cases.
2020-10-21 20:32:15 +02:00
77e727bb9c RatAttack: more corner case regex adjustment, and PS4 colour fix 2020-10-21 18:47:38 +02:00
67d4c45102 RatAttack: fixed & refined RATSIGNAL regex, added debug logging 2020-10-21 17:11:41 +02:00
adcec42dbd log missing .startup commands
-> profile is present, but not loaded/included
2020-10-21 16:14:59 +02:00
48593fce9d Let’s not get crazy with the indentations, shall we? 2020-10-21 15:08:34 +02:00
e0b7631eac RatAttack: updated RATSIGNAL parsing for Mecha3 2020-10-21 12:14:06 +02:00
0196a2aaf2 cleaned up some of the projects/solutions mess 2020-10-21 10:25:17 +02:00
c955fe05d6 initial messy plugin rewrite commit 2020-10-21 01:19:34 +02:00
89 changed files with 7151 additions and 1148 deletions

14
.editorconfig Normal file
View file

@ -0,0 +1,14 @@
[*]
guidelines = 80
end_of_line = lf
insert_final_newline = true
charset = utf-8-bom
[*.cs]
guidelines = 80, 120
# IDE0021: Use block body for constructors
csharp_style_expression_bodied_constructors = when_on_single_line
# IDE0024: Use block body for operators
csharp_style_expression_bodied_operators = when_on_single_line

2
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,2 @@
github: alterNERDtive
ko_fi: alterNERDtive

12
.github/dependabot.yaml vendored Normal file
View file

@ -0,0 +1,12 @@
version: 2
updates:
- package-ecosystem: "nuget"
directory: "/"
target-branch: "develop"
schedule:
interval: "daily"
- package-ecosystem: "github-actions"
directory: "/"
target-branch: "develop"
schedule:
interval: "daily"

View file

@ -0,0 +1,20 @@
name: Pull Request on Branch Push
on:
push:
branches-ignore:
- devel
- release
jobs:
auto-pull-request:
name: Open pull request
runs-on: ubuntu-latest
steps:
- name: pull-request-action
uses: vsoch/pull-request-action@1.0.19
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PULL_REQUEST_BRANCH: "devel"
PULL_REQUEST_DRAFT: true
PASS_IF_EXISTS: true

23
.github/workflows/create-release.yaml vendored Normal file
View file

@ -0,0 +1,23 @@
name: Create release on tag push
on:
push:
tags:
- 'releases/*.*'
- 'releases/*.*.*'
jobs:
build:
name: Create draft release
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v2
- name: Draft release
uses: ncipollo/release-action@v1
with:
bodyFile: "CHANGELOG.md"
draft: true
token: ${{ secrets.RELEASE_TOKEN }}

22
.github/workflows/gh-pages.yaml vendored Normal file
View file

@ -0,0 +1,22 @@
name: Deploy github pages on tag push
on:
push:
tags:
- 'release/*.*'
- 'release/*.*.*'
jobs:
build:
name: Deploy documentation
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v2
- name: Deploy docs
uses: mhausenblas/mkdocs-deploy-gh-pages@nomaterial
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REQUIREMENTS: requirements.txt

361
.gitignore vendored Normal file
View file

@ -0,0 +1,361 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
/plugins/build
/build
/alterNERDtive-VoiceAttack-profiles.vax
/Makefile
/site
/src
/build.csproj

View file

@ -1,3 +1,571 @@
# 4.5 (2022-09-19)
This might very well be the last release of this. With how the “Horizons 4.0”
launch went, Frontiers communication around it, and just _how_ horrible 4.0 is,
I currently do not see me being motivated to actually port stuff to 4.0. And,
lets face it, 3.8 will go EoL eventually.
Anyway, I still have some programming pet projects around this stuff that I
might continue with and adapt this for, so I might sneak some fixes / updates
in, and Im not going to say never because who knows how Ill feel about this in
the future. Obviously theres also still the option to _pay_ me to do stuff =p
### Fixed
* Race condition in all plugins that might lead to commands using command-scoped
variables (`~<name>`) not working as intended. This was introduced in
refactoring work that was done for 4.4.
* Documentation proof read and fixed by @ACyprus. Thanks!
### Changed
* Some behind the scenes things regarding how builds work. This will make it
possible to build this entirely on Github (= less potential for human error)
once I have dealt with #62 (see #143 as well).
## EliteAttack 8.5
### Added
* `target nearest […]` commands now log the result (with log level “INFO”).
* `include outdated settlements` option: Include Odyssey settlements in the
outdated stations list. Default: true.
### Fixed
* `Docked` event now handles Odyssey settlements properly (they have no hangar).
(#145)
* Fixed potential race condition with the discovery scan event command queue.
Might have an impact on #64.
## RatAttack 6.4
### Fixed
* Support for new Horizons 3 / Horizons 4 / Odyssey RATSIGNALs. (#159)
* Made case list thread safe. Probably only ever impacted my own specific setup,
but still a huge 🤦.
* Apparently `^` can be part of both CMDR names and IRC nicks (fixed RATSIGNAL
regex).
-----
# 4.4 (2022-05-31)
### Added
* The Configuration GUI now has an “Apply” button.
### Fixed
* Configuration GUI now `.Activate()`s immediately to prevent it from hiding
behind other windows.
## EliteAttack 8.4
### Added
* `auto retract landing gear` setting: Automatically retract landing gear when
lifting off a planet / undocking from a station. Default: true. (#133)
* `auto disable s r v lights` setting: Automatically turn SRV lights off when
deploying one. Default: true. (#133)
### Fixed
* `auto enter station services` option. (#142)
## RatAttack 6.3.1
* Added error message to the CLI tool for running VoiceAttack with elevated
privileges which will cause an `UnAuthorizedAccessException` trying to
communicate with the plugin. (#138)
* Added warning to VoiceAttack when running it with elevated privileges. (#138)
## SpashAttack 7.2.2
* Fixed getting current jump range from EDDI; no longer fails on the first try,
no longer sometimes reports the last requested range instead of current.
-----
# 4.3 (2022-05-19)
**NOTE**: Further development is on hold and Odyssey compatibility will not be
worked on for the time being. See [the corresponding issue on
Github](https://github.com/alterNERDtive/VoiceAttack-profiles/issues/113). Feel
free to file issues for anything that is broken on Odyssey and it will be worked
on when it is worked on.
That said, there is now a settings UI! Its not pretty, its basic, but it does
the job.
* Updated documentation for the switch to 64-bit as the standard VoiceAttack
distribution format.
* Updated included `bindED` plugin.
### Added
* `customize settings` command: Brings up a rudimentary settings UI. (#80)
* `open documentation` command: Opens the profiles documentatin in your
default browser.
* Section about HCS compatibility in “Troubleshooting” documentation (#130).
### Fixed
* Log level settings description no longer contains literal `\n`s.
* Documentation now mentions that you have to reload your custom profile after
creating the `startup` command for the first time. (#129)
* Clarified not having to install bundled dependencies manually. (#127)
* Reordered setup instructions to clarify that the profile example already comes
with a `startup` command. (#126)
* No longer cuts off EDDIs “update available” TTS on VoiceAttack start. (#120)
* Implemented workaround for EDDIs `Body scanned` event sometimes not setting
variables correctly. Might drop some events, will log to `DEBUG`. (#121)
## EliteAttack 8.3
### Added
* `INFO` logging for carrier events.
* `auto refuel` setting: Automatically refuel after docking at a station.
Default: true. (#133)
* `auto repair` setting: Automatically repair after docking at a station.
Default: true. (#133)
* `auto move to hangar` setting: Automatically move the ship to the hanger after
docking at a station. Default: true. (#133)
* `auto enter station services`: Automatically enter the Station Services menu
after docking at a station. Default: true. (#133)
* `find nearest […]` command now logs the result to the VoiceAttack log (log
level `INFO`). (#96)
## RatAttack 6.3
### Added
* Now gives feedback after asking for call confirmation: “Call aborted.” /
“Calling <…>.”.
* `auto copy rat case system` setting: Automatically copy the clients system to
the clipboard when you open a rat case. Default: true.
* Now asks for call confirmation more clearly: “send call \<call\> to fuel
rats?” instead of an easily misinterpreted “call \<call\>?”. The question
inflection is more or less pronounced depending on the TTS voice used and has
led to confusion. (#101)
### Fixed
* No longer trying to get nearest CMDR for the new “Unconfirmed” system info.
* Fixed RATSIGNAL parsing for locales containing `&`.
* Fixed RATSIGNAL parsing for system information containing `/` (e.g. “Herbig
AE/BE star”).
* “Not Set” case number when asking for details about an invalid case.
* Fixed RATSIGNAL parsing for locales containing `,`.
* No longer determines (nor logs) nearest CMDR if announcing nearest CMDR is
turned off while also being off duty.
* No longer silently swallows calls if call confirmation is disabled. (#128)
## SpanshAttack 7.2.1
### Fixed
* OBOE on last jump.
* Moved jumps left announcement from getting the next waypoint (now happens at
the start of a jump) to the `Jumped` event (happens after a jump). (#124)
* Will no longer go to neutron jump mode if no route has been found (= there is
only a single waypoint). (#104)
-----
# 4.2.3 (2021-05-23)
Updated included bindED plugin to version 4.1 that fixes Odyssey compatibility.
No actual code / profile changes.
-----
# 4.2.2 (2021-05-19)
Now comes with Odyssey-compatible bindED.
**DO read [the release notes on
that](https://github.com/alterNERDtive/bindED/releases/tag/release/4.0) before
upgrading!**
## RatAttack 6.2.2
### Fixed
* Added handling for Odyssey clients. (#114)
* Correctly setting system for manual Ratsignals (`""`) to `None` now. IMO a
Mecha bug, but whatever.
* Code reds are now correctly detected again with the new case announcement
format. (#115)
-----
# 4.2.1 (2021-05-03)
This will probably be the last pre-Odyssey release. I am not in the Odyssey
alpha, and I have no ETA on a compatibility release. Please do file issues you
encounter regardless.
Changes to the RATSIGNAL produced by Swiftsqueak broke not only the parsing, but
also the default string used to detect them in AdiIRC. Youll need to listen to
`on *:TEXT:*RATSIGNAL*(??_SIGNAL):#fuelrats:` instead.
## Documentation
* Reworded the 32- vs. 64-bit part of the VoiceAttack installation instructions.
Some scenarios require one or the other, otherwise it probably doesnt matter
which you pick.
## EliteAttack 8.2.1
### Fixed
* ~~No longer tries to auto-honk after a hyperdiction event. (#105)~~ Sadly
doesnt quite work, yet.
* On-demand outdated station check works again. (#108)
## RatAttack 6.2.1
### Fixed
* Fixed RATSIGNAL parsing for new format. Needs adjusting your IRC client, see
above. IRC formatting will now be stripped before sending to VoiceAttack.
(#111)
* Fixed RATSIGNAL parsing for language strings that contain numbers (e.g.
“es-419”).
* Fixed RATSIGNAL parsing for “unknown system” (which contains a zero-width
space …)
* Fixed RATSIGNAL parsing for procedually generated landmark systems.
* Fixed RATSIGNAL parsing landmark systems with alternate names.
### Changed
* Removed the TTS prompt and logging from incoming invalid RATSIGNALs by
default, for real this time. See the `((RatAttack.invalidRatsignal))` command
for info on how to re-enable for yourself.
-----
# 4.2 (2021-03-09)
## EliteAttack 8.2
### Added
* "limpet check" configuration option: Do a limpet check when undocking,
reminding you if you forgot to buy some. Default: true. (see discussion on
#86)
## RatAttack 6.2
### Added
* `distance to latest rat case` command: gives you you current distance to the
latest rat case.
### Fixed
* Fixed RATSIGNAL parsing for “Sagittarius A*” landmark.
* Fixed RATSIGNAL parsing for new wording of injected cases with no system
given.
* Fixed RATSIGNAL parsing for “cardinal direction” addition to distance
estimates for proc gen systems.
## SpanshAttack 7.2
### Changed
* Moved EDTS system coordinate estimation code from Python script to the
VoiceAttack plugin.
### Removed
* `edts.exe` Python script.
-----
# 4.1 (2021-02-19)
## EliteAttack 8.1
### Added
* `how many jumps left` command: Announces the jumps left on a neutron trip
(requires SpanshAttack) or a course plotted via the galaxy map.
* `route jump count` configuration option: Give a jump count on plotting a
route. Default: true.
* Now reports on AFMU repairs.
* `repair reports` configuration option: Report on AFMU repairs. Default: true.
* Now reports on Synthesis.
* `synthesis reports` configuration option: Report on synthesis. Default: true.
### Fixed
* Restricted outdated stations check to systems with stations again.
* `Material Threshold` event should no longer cause logging errors.
## RatAttack 6.1
### Added
* `call jumps [left;]` command: Calls jumps for the currently open case based on
a neutron trip (requires Spanshattack) or a plotted ingame route.
* Now uses Mechas system information in the RATSIGNAL in case announcements.
* `system information for fuel rat case` configuration option: System
information provided by Mecha. Default: true.
* `latest rat case details` command: Will give you the case data for the
latest incoming case.
### Changed
* Removed TTS prompt from the invalid RATSIGNAL trigger. Its still in the log,
but you wont get spammed in voice every time the format changes before an
update to the profiles is out.
* No longer looks up your nearest CMDR to a rat case if the system is neither in
Mechas galaxy database nor a potentially valid system name. (#89)
### Fixed
* Updated RATSIGNAL parsing to correctly handle new format for landmark systems.
* Updated RATSIGNAL parsing to accomodate new “Invalid system name” info and
colouration.
* Updated RATSIGNAL parsing for new nick announcement (if different than CMDR name)
## SpanshAttack 7.1
### Added
* `skip [this;current] neutron waypoint` command: Skips the next neutron
waypoint. (#94)
* Now also announces the actual jump count with the trip time.
-----
# 4.0.2 (2021-02-04)
## RatAttack 6.0.1
### Fixed
* RATSIGNAL parsing updated for latest Mecha3 changes.
-----
# 4.0.1 (2021-01-30)
## SpanshAttack 7.0.1
### Fixed
* Now correctly getting the next neutron waypoint again after reaching the
current one.
-----
# 4.0 (2021-01-29)
This version introduces huge (and _breaking_) changes. **Make sure to refer to
[the “Upgrading”
section](https://alternerdtive.github.io/VoiceAttack-profiles/upgrading/) in the
documentation if you are upgrading from an older version!**
Oh yes, there is [an all new and improved documentation
now](https://alternerdtive.github.io/VoiceAttack-profiles)!
The biggest change is the addition of plugins to supplement the profiles, and
the new `alterNERDtive-base` profile that handles a lot of the plugin-related
tasks including configuration.
Long-term goal is to re-implement the Python scripts in the plugins, too, to
reduce the complexity (= probability of silly errors) and the download size.
The profile package now also includes [my fork of the `bindED`
plugin](https://github.com/alterNERDtive/bindED). If you use other profiles that
expect the old version, you will see error messages in the log about not being
able to invoke that plugin. [You can safely ignore that](https://github.com/alterNERDtive/bindED#migrating-from-the-old-plugin).
## alterNERDtive-base 4.0
### Added
* `alterNERDtive-base` plugin. Provides functionality common to all profiles.
* Proper logging to the VoiceAttack log. You will notice a lot of useful
information, more is available if you change the log level configuration
option. Logging to a file for troubleshooting will be added at a later date.
* `generate missing key binds report` command: Will place a list of missing key
binds (provided by bindED) on your Desktop for troubleshooting.
* Lots of new configuration options, see [the
documentation](https://alternerdtive.github.io/VoiceAttack-profiles/configuration/general).
* You can now have a list of configuration voice commands as well as a list
of all configuration options and their current settings printed to the
VoiceAttack log.
* `open [docs;documentation;help] [site;]` command: Opens the new documentation site.
* `open [docs;documentation;help] file` command: Opens the PDF version of the
new documentation site distributed with the profiles for offline use.
### Removed
* `Python.scriptPath` configuration option: The scripts are basically already
deprecated, and Im from now on assuming that you use the profile package for
installation/upgrades, so I expect the scripts where they are supposed to be.
### Changed
* Completely reworked how the configuration works. It will be trivial to add new
options in the future including voice commands to set them. Adding a GUI is
also possible, but not on the roadmap yet.
* EDDI events (and some other more administrative commands) are now hidden from
the VoiceAttack log.
* The command beep sound used by some commands as acknowledgment has been
changed to a builtin sound effect in VoiceAttack to avoid having to ship a
.wav file of unknown origin.
### EliteAttack 8.0
The `EliteDangerous` profile has been renamed to `EliteAttack` to be consistent
with the other profiles. If you are upgrading instead of installing fresh, your
profile will keep the old name. Feel free to manually rename it.
### Added
* `EliteAttack` plugin. Doesnt do a lot yet.
* Submodule targeting! Say
`target the [drive;drives;power plant;frame shift drive;f s d;shield generator]`
to target submodules on your current target, and `clear sub [module;system]
target` to clear your target.
* `distance [from;to] [Sol;home;the center;Beagle Point;Colonia]` command: Gives
you your current distance to the given POI.
* `[wheres;where is] my landing pad` command: Will tell you the location of
your assigned landing pad on a starport.
* `[dis;]engage silent running` command: Handles silent running.
* `[are there any;] outdated stations [in this system;]` command: Runs an
on-demand check for outdated stations in the current system.
* `open spansh` command: Opens https://spansh.uk in your default browser.
### Changed
* `power to` command now supports of lot more options. `power to X and Y` sets
8/4/0, `balanced power to X and Y` sets 6/6/0, `half power to X` sets 6/3/3,
`half power to X and Y` sets 5/5/2.
* Moved the EDSM body count and outdated station checks from the `Jumped` event
to the pre-jump `FSD engaged` event to work around increased EDSM response
times. (#85)
### Removed
* `[buggy;exploration] power` command.
### Fixed
* `EDDI Material threshold` event now uses the correct variable names. It will
automatically start working properly in a future version of EDDI that fixes
some bugs with setting event variables. (#32)
### RatAttack 6.0
### Added
* `RatAttack` plugin. Responsible for handling case data instead of having a way
too long and convoluted list of VoiceAttack variables. Also provides a way to
send RATSIGNALs to VoiceAttack via IPC.
* `RatAttack-cli.exe` helper tool. Used to send RATSIGNALs to the plugin via IPC.
* Will now announce permit locks, including the name of the permit if available.
* Now supports manually injected cases that might not provide a system. You will
still have to manually copy the system from \#fuelrats or the dispatch board
after it has been set. (#76)
### Changed
* RATSIGNAL handling is no longer done through a file, there is now a helper
tool that communicates with the plugin directly. See “Upgrading” in the
documentation.
* Now supports up to 31 cases (030). Thanks, Epicalypse!
### Fixed
* Updated RATSIGNAL parsing for Mecha3.
### SpanshAttack 7.0
### Added
* `SpanshAttack` plugin. Does miscellaneous things for now, will at some point
replace the dependency on the ED-NeutronRouter plugin.
* Will now log the jumps calculated for a trip to the VoiceAttack log.
### Changed
* Now pulls/announces next neutron waypoint on `FSD engaged` (starting a jump)
instead of `Jumped` (finishing a jump). (#85)
### StreamAttack 2.0
### Added
* `distance [to;from] jump target` command: Tells you the current distance to
the jump target.
### Changed
* Jump target will now be set to SpanshAttacks plot target if the actual target
system is not in the database.
-----
# 3.2.1 (2021-01-02)
## RatAttack 5.0.5
### Fixed
* RATSIGNAL parsing had to be updated _again_. -.-
-----
# 3.2.0 (2020-12-31)
The update mechanism has been changed to manual update in preparation of the
4.0 release that will come with the need to manually change some things around.
So in order to not automatically leave people with a broken state, they will
have to manually go through the update steps for 4.0. To reflect that, 3.2.0
will no longer auto-download a new release and instead send you to the release
page on Github.
## RatAttack 5.0.4
### Fixed
* RATSIGNAL parsing updated for the latest Mecha3 changes. Permits are now
orange instead of red.
## EliteDangerous 7.3
### Changed
* Updates are no longer automatic, instead you will be sent to the release page
on Github.
-----
# 3.1.3 (2020-11-06)
Hopefully last Mecha3 compatibility release.
## RatAttack 5.0.3
### Fixed
* System names will now be `ToLower()`ed since Mecha3 capitalizes them and EDDI
likes spelling those out instead of saying the names. Makes them a little
messy in other ways, but less annoying overall.
* Permit detection part of the RATSIGNAL RegEx fixed for named permits.
* `XB` platform changed to `Xbox` to match Mecha3.
-----
# 3.1.2 (2020-10-22)
Bugfix to the bugfix, anyone?
@ -493,6 +1061,8 @@ a station with data in EDDN >1 year old. Apologies.
* Added new “Navigation” section. This includes the aforementioned new commands
and a bunch of old ones that fit there better than into “Misc”.
-----
# v1.3 (2020-06-14)
## EliteDangerous v5.0
@ -533,6 +1103,8 @@ bindings before even though it needs them …
* Now updates your location when dropping from SC.
* Fixed some copypasta errors in the documentation.
-----
# v1.2 (2020-03-09)
## EliteDangerous v4.0
@ -563,8 +1135,7 @@ up to date in EDDN.
* Added `open [rat;] dispatch board` command. Opens the web dispatch board in
your default browser.
* Added proper handling for multiple ratsignals hitting at once. Thats mainly
an IRC client config thing,
[see the docs](docs/RatAttack.md#getting-case-data-from-irc).
an IRC client config thing, [see the docs](docs/configuration/RatAttack.md).
* Renamed `RatAttack.getInfoFromRatsignal` to
`RatAttack.announceCaseFromRatsignal`. Removed the “open case?” voice input
prompt.
@ -599,6 +1170,8 @@ mine ;)
[See the docs](docs/StreamAttack.md).
-----
# v1.1 (2020-01-30)
The compiled Python scripts are now distributed as two single .exe files. You
@ -668,6 +1241,8 @@ fixes:
* updated for new controls setup: the HOTAS buttons have changed because my
setup has changed. Probably not really relevant for you.
-----
# v1.0 (2019-12-04)
### single-file profile package
@ -712,6 +1287,8 @@ open a bug if it does.
* fixed bug with wonky system names (including e.g. `+` or `[]`)
-----
# v0.5 (2019-11-09)
## RatAttack v0.1
@ -745,6 +1322,8 @@ RatAttack is now a thing! :D
when EDSM knows _fewer_ bodies (there are some issues with duplicate entries
in EDSM, e.g. in Dromi)
-----
# v0.4.1 (2019-10-14)
This is a bug fix release (as the version number indicates). Mainly for changes
@ -764,6 +1343,8 @@ yet, so you do not have to download the new archive.
* fixed discovery scan event for new EDDI variable naming
* fixed srv lauched event to properly turn off the lights
-----
# v0.4 (2019-10-12)
## SpanshAttack v1.3
@ -787,6 +1368,8 @@ yet, so you do not have to download the new archive.
update EDSM) (requires python scripts, see doc)
* added compatibility for SpanshAttacks clear on shutdown
-----
# v0.3 (2019-09-22)
## SpanshAttack v1.2
@ -800,6 +1383,8 @@ Should be usable by other people now without too much hassle. If you run into
problems, please hit me up on [Discord](https://discord.gg/mD6dAb) or file an
issue here.
-----
# v0.2 (2019-08-28)
## SpanshAttack v1.1
@ -818,6 +1403,8 @@ advised for general use, but feel free to dig around and draw inspiration from
it. Soon™ it will be published in a more usable state, but I wanted to get it
out there for reference.
-----
# v0.1 (2019-08-06)
## SpanshAttack v1.0

BIN
Custom Profile Example.vap Normal file

Binary file not shown.

25
Directory.build.props Normal file
View file

@ -0,0 +1,25 @@
<Project>
<PropertyGroup>
<LangVersion>10.0</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
<!-- StyleCop Analyzers configuration -->
<PropertyGroup>
<CodeAnalysisRuleSet>$(SolutionDir)StyleCop.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="StyleCop.Analyzers.Error" Version="1.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="StyleCop.CSharp.Async.Rules" Version="6.1.41">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<AdditionalFiles Include="$(SolutionDir)stylecop.json" Link="stylecop.json" />
</ItemGroup>
</Project>

674
LICENSE Normal file
View file

@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
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
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<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 <http://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
<http://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
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

188
README.md
View file

@ -1,184 +1,42 @@
# Elite Dangerous VoiceAttack Profiles #
# Elite Dangerous VoiceAttack Profiles #
These are various profiles for [VoiceAttack](https://voiceattack.com) (VA) I use
to enhance my Elite experience. They give me important info, facilitate
day-to-day gaming and do some special things for [Fuel
Rats](https://fuelrats.com) and [Hull Seals](https://hullseals.space) work.
Each of the profiles is documented in `docs/`.
**NOTE**: Further development is on hold and Odyssey compatibility will not be
worked on for the time being. See [the corresponding issue on
Github](https://github.com/alterNERDtive/VoiceAttack-profiles/issues/113). This
might or might not change after the Horizons/Odyssey merge when console release
is upon us. Feel free to file issues for anything that is broken on Odyssey and
it will be worked on when it is worked on.
## Available Profiles ##
* [EliteDangerous](docs/EliteDangerous.md): My main Elite VA profile. Here be
dragons; things may be heavily tailored towards how _I_ play the game and may
not apply to how you play it. Included for reference and as a baseline or
inspiration to create your own stuff.
* [RatAttack](docs/RatAttack.md): profile for interactions with the Fuel Rats
IRC server.
* [SpanshAttack](docs/SpanshAttack.md): profile to plot and follow trips along
the neutron highway using [spansh](https://spansh.co.uk/plotter).
* [StreamAttack](docs/StreamAttack.md): profile for writing various things to
files that can then be read by streaming software like OBS.
* EliteAttack: The main Elite VA profile. Anything related to “just” playing the
game.
* RatAttack: Manages interactions with the FuelRats IRC server.
* SpanshAttack: Plots and follows trips along the neutron highway using
[Spanshs neutron plotter](https://spansh.co.uk/plotter).
* StreamAttack: Writes various status things to files that can then be read by
streaming software like OBS.
## Requirements ##
## Documentation & Installation Guide
* [VoiceAttack](https://voiceattack.com): absolutely required (duh).
* [bindED](https://forum.voiceattack.com/smf/index.php?topic=564.0): required
for EliteDangerous and SpanshAttack; makes anything involving hitting E:D key
binds portable.
* [EDDI](https://github.com/EDCD/EDDI) installed as a VoiceAttack plugin:
required for EliteDangerous, SpanshAttack and Streamattack, optional for
RatAttack.
* [ED-NeutronRouter](https://github.com/sc-pulgan/ED-NeutronRouter): required
for SpanshAttack. **Make sure to [grab the pre-release
1.02](https://github.com/sc-pulgan/ED-NeutronRouter/releases/tag/1.02)** since
1.01 has a bug with a hardcoded 50ly jump range.
* [elite-scripts](https://github.com/alterNERDtive/elite-scripts): required for
EliteDangerous, SpanshAttack and StreamAttack, recommended for RatAttack
(included).
Additionally, you need to have keyboard binds setup at least as secondary
bindings in Elites controls options. VA _cannot_ “push” joystick buttons for
you, it can only do keyboard inputs. Hence its only way to interact with Elite
is through keyboard emulation, even if you otherwise play the game with
a controller or HOTAS. Or racing wheel. Or Rock Band set. Or bananas.
## Installing ##
1. Install [VoiceAttack](https://voiceattack.com).
1. Install the plugins listed in [Requirements](#Requirements).
1. Download the profile package (`alterNERDtive-voiceattack-profiles.vax`) from
the [release
page](https://github.com/alterNERDtive/VoiceAttack-profiles/releases/latest)
and import it as a profile into VoiceAttack. This will install all included
profiles, the referenced sound files and the Python scripts.
(You can also download the profiles individually from the `profiles/` folder on
github.)
## Getting Started ##
You will want to create your own profile and then import the downloaded ones
into your custom profile. This way you can easily add commands (to your custom
profile), change commands (by copying them into your custom profile and editing
them) and change settings (by overriding them in your custom profile). Note that
most settings can be changed with voice commands. If you find any that cannot
but you feel should, please file an issue or report it on Discord.
### Creating a Custom Profile ###
Hit the second button next to the profile dropdown menu and choose “Create new
Profile”. Give it a name and add some commands if you want to.
You can also just keep using a profile you have already created.
### Importing profiles ###
First off, create a startup command. You can name it anything you want, but
I recommend calling it “startup” or similar, and to deactivate the “when i say”
checkbox in the command options to make sure you dont accidentally run it via
voice. We will need this command later.
While editing the profile, hit the “Options” button. On the section labeled
“Include commands from other profiles”, hit the “…” button and add all profiles
(`EliteDangerous`, `RatAttack`, `SpanshAttack`, `StreamAttack`). All commands
defined in these profiles will be available to you. Make sure that
“EliteDangerous” is on top of the list.
Now switch to the “Profile Exec” tab. Tick the “Execute a command each time this
profile is loaded” checkbox, and select the “startup” command you have created
earlier.
Edit your startup command. Add a new action using “Other” → “VoiceAttack Action”
→ “Execute Another Command”. Choose “Execute by name (Advanced)” and enter
“EliteDangerous.startup”.
### Settings ###
All profiles will load sane defaults if you havent changed anything. You no
longer need to fiddle with the `startup` commands of each profile, instead you
can use voice commands to change settings! See the `docs/` and the
`_configuration` commands section of each profile.
Basically all the settings are available using the `customize settings` prefix,
then saying `[enable;disable] <setting>` for on/off switches and `set <setting>`
for text variables.
One caveat applies: settings will only be saved in the profile you have
selected, but be preserved if you switch around.
### Making changes ###
If you want to edit a command or add your own, _do not edit the profiles
directly_. Instead create commands in your custom profile, and copy commands you
want to change over to that before editing them. This will make sure no changes
are lost if you update the profiles.
Because of limitations of VoiceAttack itself, only the first matching command
found will be executed, _including EDDI events_. That means that if you create
commands to handle EDDI events, you are going to have to check the imported
profiles if they rely on these event handlers as well, and call them manually if
they do.
E.g. if you want to create a custom `((EDDI Message sent))` handler in your
profile, you will have to make it excute the `EliteDangerous.EDDI Message sent`
and `RatAttack.EDDI Message sent` commands. Otherwise stuff _will_ break.
If you have no idea what the previous two paragraphs were about, you can most
likely just ignore them.
## Updating ##
### The Best™ Way ###
Say “check for profiles update”. If it finds one, say “download profiles
update”. Restart VoiceAttack.
There will also be an update check every time `EliteDangerous.startup` is run.
### The Manual Way ###
If you dont like automation or do not use all provided profiles, youll have to
update semi-manually.
Say “open VoiceAttack import folder”. Download the current release profile
package, drop it in there. Restart VoiceAttack.
### Note about Admin Privileges ###
The update process will run VoiceAttack with admin privileges. If you do not
usually run VoiceAttack with admin privileges, do _not_ have it start
VoiceAttack for you after importing the profiles update. It will keep running
with elevated privileges. Instead restart it manually. If you are not sure if
you are running with elevated privileges check the “VoiceAttack Information”
dialog in VoiceAttack General settings → “System Info >”. It will include a line
about running with admin prvileges if it does.
### Major Version Changes ###
If a profiles major version number changes (e.g. SpanshAttack 1.x.x to 2.0.0)
there _will_ be changes to the profile that include one or any amount of the
following changes:
* command names / command invocation have changed
* configuration variable name or format have changed
* features removed
* _major_ features added
**If you see a major version number change in the release notes, please pay
attention to said notes to know what you might have to change to get it to
work!**
You can find [comprehensive documentation on Github
Pages](https://alternerdtive.github.io/VoiceAttack-profiles).
## Need Help / Want to Contribute? ##
If you run into any errors, please try running the profile in question on its
own / get a fresh version. If that doesnt fix the error, look at the
[devel](https://github.com/alterNERDtive/VoiceAttack-profiles/tree/devel) branch
and see if its fixed there already.
If you run into any errors, please make sure you are running the latest version
of the profiles and all requirements.
If you have no idea what I was saying in that last parargraph and / or the
things mentioned there dont fix your problem, please [file an
If your problem persists, please [file an
issue](https://github.com/alterNERDtive/VoiceAttack-profiles/issues). Thanks! :)
You can also [say “Hi” on Discord](https://discord.gg/kXtXm54) if that is your
thing.
[![GitHub Sponsors](https://img.shields.io/github/sponsors/alterNERDtive?style=for-the-badge)](https://github.com/sponsors/alterNERDtive)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/S6S1DLYBS)

2
StyleCop.ruleset Normal file
View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="StyleCop.Analyzers rules with default action" Description="StyleCop.Analyzers with default action. Rules with IsEnabledByDefault = false are disabled." ToolsVersion="17.0" />

View file

@ -1 +1 @@
3.1.2
4.5

314
docs/EliteAttack.md Normal file
View file

@ -0,0 +1,314 @@
# EliteAttack
This is my personal VoiceAttack profile for Elite: Dangerous. It started out
ages ago as a modification of [MalicVRs public
profile](https://forums.frontier.co.uk/threads/malics-voice-attack-profile-for-vr.351050/),
then looked less and less and less like that and I added and cleaned up a lot of
things while removing the stuff I didnt use anyway. By now it would have
probably been simpler to start from scratch.
Funnily enough it has grown to rely way more on events provided by
[EDDI](https://github.com/EDCD/EDDI) than actual voice commands.
## Chat Commands
These commands will only work with the comms panel active, and you should be in
the edit window ready to send. They will _not_ hit Enter on their own.
* `clear [chat;text]`: Clears the chat window. Use from outside the comms panel.
* `[local;squad;system;wing] chat`: Puts you into the chosen chat channel.
* `salute; oh seven`: Will put “o7” into the chat.
## Engineering/Materials
* `how many [<g5 manufactured materials list>] do i have`: Tells you how many of
the given g5 manufactured material you currently have on board. Ive
restricted it to just those to not spam speech recognition with too many
phrases, and because those are the ones I usually want to know while jumping
around the bubble and having an eye on any HGE that might be around.
* `[launch;open] e d engineer`: Opens the ED Engineer tool.
* `what [mats;materials] do i need?`: Runs the EDDI responder that tells you
which materials are below wanted threshold. Needs setting those first. Gets
very spammy if you do it for all of them; personally I only set them for g5
manufactured, so I can quickly check if its worth looking for HGE in a system
Im in.
## Navigation
There are so many navigation-focused commands now, they deserve their own
category. Basically anything that helps you plot anywhere. A lot of those are
powered by awesome EDDI so I dont have to do the work myself!
* `distance [from;to] [Sol;home;the center;Beagle Point;Colonia]`: Gives you the
current distance to the given POI.
* `[find;target] nearest [encoded;manufactured;raw] material trader`: Targets
the nearest respective material trader.
* `[find;target] nearest [fuel;scoopable] star`: Targets the nearest scoopable
star.
* `[find;target] nearest [guardian;human] tech broker`: Targets the nearest
respective tech broker.
* `[find;target] nearest [interstellar factor;mission system;scoopable star]`:
Well, you know the drill by now.
* `[find;target] nearest mission system`: Targets the nearest system that has a
mission target.
* `how many jumps left`: Announces the jumps left on a neutron trip (requires
SpanshAttack) or a course plotted via the galaxy map.
* `plot course;[target;] next [waypoint;way point]`: Plots a course to the text
in your clipboard.
* `target [bug killer;colonia;davs hope;explorers anchorage;jackson's lighthouse;jamesons cobra;robigo;shinrarta dezhra;sagittarius a*;shinrarta;sothis]`:
Targets the given system on the galaxy map.
* `[wheres;where is] my landing pad`: Will tell you the location of your
assigned landing pad on a starport.
## Ship Controls
Basically anything that is related to directly doing something with your ship.
* `[abort;cancel;stop] jumping`: Stops a currently charging FSD jump.
* `[half;] power to [engines;shields;systems;weapons]`: Sets pips to 6/3/3
(`half`) or 8/2/2 towards the given capacitor.
* `[balanced;half;] power to [engines;shields;systems;weapons] [and engines;and shields;and systems;and weapons;]`:
Sets pips to 6/6/0 (balanced), 5/5/2 (half) or 8/4/0 towards the given capacitors.
* `[close;deploy;extend;open;retract;] [cargo scoop;hard points; landing gear] [up;down;]`:
Overly complicated command to handle everything related to Cargo Scoop, Hard
Points, Landing Gear. You get the gist, I guess. Works in SRV too.
* `[disco;discovery scan]`: Executes a discovery scan. Expects the Discovery
Scanner in your first fire group, secondary fire. [You can change
that](configuration/EliteAttack.md#settings).
* `[dis;]engage silent running`: Turns silent running on and off.
* `[head;spot;] lights [on;off]`: Turns your lights on and off. Works in SRV
too, kinda; turning lights off there relies on the state updating fast enough,
which sometimes leads to weird results.
* `[jump;engage;get me out] [and scan;] [when ready;]`: Retracts everything that
might be protruding from your ship, then jumps to the next system. If the FSD
isnt charging within 1s, it gets you into SC instead (e.g. if your target is
obstructed). If given “and scan” runs a discovery scan. If given “when ready”
waits for mass lock to clear, your FSD to cool down and you to leave scoop
range before jumping.
* `night vision [on;off]`: Toggles your night vision on/off. Works in SRV too.
* `rapid fire lights`: Flashes your lights 5 times in a row.
* `retract [all;everything]`: Retracts, well, everything.
* `[start;stop] [firing;mining]`: Starts/stops holding down primary fire. Mostly
useful when mining. When triggered with “mining”, also deploys the cargo
scoop.
* `[super;] cruise [when ready;]`: Retracts everything, then jumps to SC. If
given “when ready” will wait for mass lock to clear and your FSD to cool down
first.
## SRV Controls
Things relevant to your SRV, but not your ship.
* `[recall;dismiss] ship`: Recalls or dismisses ship. Currently does the same
thing regardless of the state of your ship. I wish it would be possible to
restrict it to doing one thing each, but thats currently not possible sadly.
* `[toggle;enable;disable] drive assist`: Handles all your drive assist needs!
## Targeting
Well … targeting stuff, I guess. Not really sure why I made that its own
category, but oh well :)
* `target the [drive;drives;power plant;frame shift drive;f s d;shield
generator]`: Targets the given submodule on your current target, or your next
target if you dont have one currently. Does not persist between targets.
* `clear sub [module;system] target`: Clears the current submodule target.
* `target next system`: Selects the next system on your route.
* `target wing man [1;2;3]`: Targets your wingmen.
* `targets target`: Targets your targets target (only works on wingmen).
* `wing man [1;2;3] target`: Targets your wingmens target.
* `wing man nav lock`: Toggles wing man nav lock on the selected wing member.
## UI Commands
Everything handling stuff thats not related to controlling your ship, but
manipulating some UI element(s).
* `[enter;leave] F S S`: Opens/closes FSS.
* `[main;game] menu`: Opens the ESC menu.
* `[relog;reset] to [open;solo]`: Relogs to Open or Solo mode, respectively.
* `controls options`: Opens the controls options menu.
* `docking request;request dock[ing;]`: Sends a docking request.
* `galaxy map`: Opens the galaxy map.
* `restart from Desktop`: Quits the game and restarts from an open launcher by
clicking the play button.
* `set [default;star;station;settlement;signal sources;anomaly;unknown;system] filter`:
Sets a nav panel filter setting. See the command or just try different things
for what is possible. You need to clear filters and hover over the filter
button, then run this.
* `system map`: Opens the system map.
* `take [high res;] screenshot`: Takes a (high res) screenshot.
* `toggle orbit lines`: Toggles the visibility of orbit lines.
## Miscellaneous
The commands in here do random more or less useful things.
* `[are there any;] outdated stations [in this system;]`: Runs an on-demand
check for outdated stations in the current system.
* `[bodies;whats;what is] left to [map;be mapped;scan]`: Tells you which bodies
EDDI thinks are worth mapping in the system that you havent mapped yet.
* `copy current system`: Copies the current system name into the clipboard.
* `open [current;] system on EDSM`: Opens your current system on EDSM in your
default browser.
* `open copied system on EDSM`: Opens the system in your clipboard on EDSM in
your default browser.
* `open coriolis`: Opens Coriolis in your default browser.
* `open e d d b [station;system;faction;] [search;]`: Opens EDDB in your default
browser.
* `open e d s m`: Opens EDSM in your default browser.
* `open inara`: Opens Inara in your default browser.
* `open materials finder`: Opens EDTutorials materials finder in your default
browser.
* `open miners tool`: Opens https://edtools.cc/miner in your default browser.
* `open spansh`: Opens https://spansh.uk in your default browser.
## Events
This is a list of ingame Events, [provided by
EDDI](https://github.com/EDCD/EDDI/wiki/VoiceAttack-Integration), that the
profile will act on.
### AFMU Repairs
Reports on the module that has been repaired, and if it has been fully or
partially repaired.
### Body Mapped
Announces an estimate for high-value bodies payouts and the remaining mapping
candidates in the system as given by EDDI.
### Body scanned
Announces any interesting body traits found when scanning:
* terraformable
* Earth-like World, Ammonia World or Water World
* landable and >5g
* semimajor axis <1.5ls (only really interesting for planets, but theres no
proper way to separate them from moons, sadly)
* radius <300km
Feel free to suggest more!
### Carrier Cooldown
Tells you when your carrier is able to do its next jump.
### Carrier Jump Engaged
This event fires when your carrier jumps but you are _not_ docked at it. It
provides way less information than the `Carrier Jumped` event, but hey, I dont
use most of it anyway. Basically just calls `Carrier Jumped`.
### Carrier Jump Request
Announces the system and body your carrier has just been scheduled to jump to.
Use this to double check ingame information; Ive had my carrier accept a body
as jump target, but then end up around the star. This _might_ give you a heads
up on that.
Also starts a command queue to give you advance warnings on carrier lockdown at
-10, -5 and -2 minutes.
### Carrier Jumped
Announces system and body your carrier has just jumped to.
### Carrier Pads Locked
Announces your carriers lockdown procedures.
### Discovery Scan
Announces the number of bodies (and non-body signals) found in the system. Also
compares the number of bodies to the amount reported by EDSM (requires Python
scripts).
### Docked
Automatically refuels, repairs, rearms, then gets your ship into the hangar and
opens station services. Can be individually disabled.
### Docking Denied
Tells you the reason for docking denial.
### Entered Normal Space
Throttles to 0 upon dropping from SC, if the hyperspace dethrottle option is
enabled.
### Fighter Launched
Orders your ship to hold position so it doesnt chase after you immediately.
### Jet Cone Boost
Sets your ship to full throttle immediately after you have supercharged.
### Jumped
* Zeroes throttle if the hyperspace dethrottle option is enabled.
* Gets the systems body count from EDSM if that option is enabled.
* Gets stations with outdated data (by default: older than 1 year) from Spanshs
API. Again, if it is enabled.
* Starts a discovery scan if that is enabled.
* Last but not least tells you about planets worth scanning if you are on the
R2R.
### Liftoff
Retracts landing gear for you. Seriously, is there any occasion in which you
_dont_ immediately want to retract it after takeoff?
### Low Fuel
Warns you when you reach 25% fuel. Also reports number of jumps you have left or
the (rough) range you still have on the fumes left in your tank.
### Material Threshold
Warns you when a monitored material falls below its minimum stock level and
tells you when you reach your desired level or fill up.
You will have to set minimum and desired amounts in EDDIs material monitor
options first for all materials you wish to be monitored.
### Next Jump
Gives you a jump count upon plotting a route using the galaxy map.
### Ship FSD
This event actually is several different events in one. Currently the following
are handled:
* Charging: Warns you if you are jumping with less than 25% fuel.
* Cooldown complete: Announces FSD cooldown if you are currently in normal
space.
### Ship Interdicted
Tells you when you have been interdicted by a player. Is also supposed to target
the interdictor automatically, but randomly sometimes just doesnt work. Yay!
### SRV Launched
Toggles SRV lights off after launching. Might not work if you drop particularly
far after deployment because it works off a timer. Conversely might take a
second to turn your lights off on a short drop and/or in high gravity.
### Synthesis
Reports on the synthesis type and quality.
### System Scan Complete
Lists all bodies EDDI considers worth mapping in the current system.
### Undocked
Retracts landing gear for you. Seriously, is there any occasion in which you
_dont_ immediately want to retract it after takeoff?

View file

@ -1,479 +0,0 @@
# EliteDangerous #
This is my personal VoiceAttack profile for Elite: Dangerous. It started out
ages ago as a modification of [MalicVRs public
profile](https://forums.frontier.co.uk/threads/malics-voice-attack-profile-for-vr.351050/),
then looked less and less and less like that and I added and cleaned up a lot of
things while removing the stuff I didnt use anyway. By now it would have
probably been simpler to start from scratch.
Some of it has grown to a state that it might be useful to others in its own
package, so Ive separated the neutron jumping and Seals stuff into their own
profiles.
The rest is a random conglomerate of all things VA and E:D; from various voice
commands to lots of EDDI event handlers.
Speaking of EDDI; it has become in integral part of my Elite experience,
especially the plethora of information it extracts from the games journal and
presents to you via lots and lots of status variables and by firing various
events that can then be handled through VA commands. Its great. Check it out.
(You might want to make it talk a lot less in its personality options, or
disable the speech responder entirely like I have.)
## Requirements ##
In addition to the bindED and EDDI VoiceAttack plugins, this profiles needs my
[Python elite-scripts](https://github.com/alterNERDtive/elite-scripts) to do
everything properly. The release page here includes a compiled version for
Windows that does not need Python installed. If you use the profile package from
the release page, they will be installed automatically.
## Settings ##
Because Elites keyboard handling is … weird youll have to set the key to use
for pasting text into Elite:Dangerous. If you are not using a “standard”
QWERT[YZ] layout, you will have to change it back to the key that is physically
in the place where `v` would be on QWERTY.
For other settings, see the [Configuration Variables](#Configuration-Variables)
section.
## Including the Profile In Another Profile ##
This is meant to be a standalone profile, including the others in this repo (and
a couple more). It was never designed to be included into your existing profile.
Nevertheless, it _should_ work properly if you follow some guide lines:
* Run the startup command. You will need to have a startup command in your
profile (= one that is run on profile loading) and call
`EliteDangerous.startup` by name from that one.
* Make sure all EDDI events that EliteDangerous needs are correctly handled. For
all events used in EliteDangerous that you already have handlers for in your
profile, youll have to include a call to `EliteDangerous.<event name>`. E.g.
for “EDDI Jumped”, call `EliteDangerous.EDDI Jumped` by name from your `((EDDI
Jumped))` command.
## Usage ##
### Chat Commands ###
Theres a bunch of commands in here to send certain things to chat. Unless
stated otherwise, they will only work with the comms panel active, and you
should be in the edit window ready to send. They will _not_ hit Enter on their
own.
* `clear [chat;text]`: Clears the chat window. Use from outside the comms panel.
* `[local;squad;system;wing] chat`: Puts you into the chosen chat channel.
* `paste text`: Pastes your clipboard into Elite. Works outside the comms panel
too, e.g. on the galaxy map inside the search field.
* `salute; oh seven`: Will put “o7” into the chat.
### Engineering/Materials ###
* `how many [<g5 manufactured materials list>] do i have`: Tells you how many of
the given g5 manufactured material you currently have on board. Ive
restricted it to just those to not spam speech recognition with too many
phrases, and because those are the ones I usually want to know while jumping
around the bubble and having an eye on any HGE that might be around.
* `open e d engineer`: Opens the ED Engineer tool.
* `what [mats;materials] do i need?`: Runs the EDDI responder that tells you
which materials are below wanted threshold. Needs setting those first. Gets
very spammy if you do it for all of them; personally I only set them for g5
manufactured, so I can quickly check if its worth looking for HGE in a system
Im in.
### Events ###
The main point of this profile is to react to Elites journal events (powered by
EDDI). Each of the events listed here will trigger a `((EDDI <event>))` command
in VoiceAttack which in turn triggers `EliteDangerous.EDDI <event>` and all
included profiles similar commands, e.g. `SpanshAttack.EDDI <event>`.
The actual `((EDDI <event>))` command will only be executed once by VoiceAttack,
the first one it can find. Keeping it separate from the actual code to be run
makes it easier to handle (multiple) included profiles.
If the command for an event will send key presses to Elite, it focuses the
client window first to make sure they get registered properly. If it is not in
focus, the first key press might be swallowed otherwise.
For other commands, the profile just assumes that you are actively doing
something in game and it is already focused :)
#### Body Mapped ####
Announces an estimate for high-value bodies payouts and the remaining mapping
candidates in the system as given by EDDI.
#### Body scanned ####
Announces any interesting body traits found when scanning:
* terraformable
* Earth-like World, Ammonia World or Water World
* landable and >5g
* semimajor axis <1.5ls (only really interesting for planets, but theres no
proper way to separate them from moons, sadly)
* radius <300km
Feel free to suggest more!
#### Carrier Cooldown ####
Tells you when your carrier is able to do its next jump. Technically only works
if you were docked at it when it performed the jump, but Im doing some
behind-the-scenes magic if you werent :)
Might be slightly off (too early) in the latter case.
#### Carrier Jumped ####
Announces system and body your carrier has just jumped to.
#### Carrier Jump Engaged ####
This event fires when your carrier jumps but you are _not_ docked at it. It
provides way less information than the `Carrier Jumped` event, but hey, I dont
use most of it anyway.
Basically just calls `Carrier Jumped` (and makes sure that a `Carrier cooldown`
event is triggered manually at approximately the right time).
#### Carrier Jump Request ####
Announces the system and body your carrier has just been scheduled to jump to.
Use this to double check ingame information; Ive had my carrier accept a body
as jump target, but then end up around the star. This _might_ give you a heads
up on that.
#### Carrier Pads Locked ####
Announces your carriers lockdown procedures. This _might_ only work when you are
docked (which would make it pretty useless). Feel free to open in issue if
thats the case.
#### Commander Loading ####
Auto-sets my nick in the FuelRats IRC. Probably largely irrelevant to you.
#### Discovery Scan ####
Announces the number of bodies (and non-body signals) found in the system. Also
compares the number of bodies to the amount reported by EDSM (requires Python
scripts).
#### Docked ####
Automatically gets your ship into the hangar and opens station services.
#### Docking Denied ####
Tells you the reason for docking denial.
#### Entered Normal Space ####
Throttles to 0 upon dropping from SC, if `EliteDangerous.hyperSpaceDethrottle` is set.
#### Fighter Launched ####
Orders your ship to hold position so it doesnt chase after you immediately.
#### Jet Cone Boost ####
Sets your ship to full throttle immediately after you have supercharged.
#### Jumped ####
* zeroes throttle
* gets the systems body count from EDSM (requires Python scripts)
* gets stations with outdated data (older than 1 year) from Spanshs API
* if you havent visited the systems, starts a discovery scan (see the discovery
scan command)
* last but not least tells you about planets worth scanning if you are on the
R2R
#### Liftoff ####
Retracts landing gear for you. Seriously, is there any occasion in which you
_dont_ immediately want to retract it after takeoff?
#### Low Fuel ####
Warns you when you reach 25% fuel. Also reports number of jumps you have left or
the (rough) range you still have on the fumes left in your tank.
#### Material Threshold ####
Warns you when a monitored material falls below its minimum stock level. You
will have to set a minimum desired amount in EDDIs material monitor options
first for all materials you wish to be monitored.
#### Message Sent ####
Checks any message you send for a chat prefix and sends it to the proper chat
window. Probably largely useless to you without modification.
* `.nc`: Actually doesnt send anything, but runs the
`RatAttack.announceNearestCMDR` command with the system given in the rest of
the message.
* `.dc`: Sends the message to the Discord window.
* `.tc`: Sends the message to my twitch channel window (IRC #alternerdtive).
There are similar event commands in RatAttack and SealAttack handling other chat
windows.
#### Ship FSD ####
This event actually is several different events in one. Currently the following
are handled:
* charging: Warns you if your target systems main star is not scoopable,
including an extra warning at low fuel levels. (__Note__: This only works if
the target system is in EDSM. So its kind of useless for its intended use
(exploration) and probably going to be removed at some point.)
* cooldown complete: Announces FSD cooldown if you are currently in normal
space.
#### Ship interdicted ####
Tells you when you have been interdicted by a player. Is also supposed to target
the interdictor automatically, but randomly sometimes just doesnt work. Yay!
#### Ship targeted ####
This currently doesnt do anything. I was fiddling around with automatically
targeting a certain module on ship targeting, but it was more hassle than I had
thought.
#### Shutdown ####
Changes my nick back to default in FuelRats IRC. Probably largely useless to
you. If you are using FuelRats IRC you need to change/deactivate this (see
[below](#Configuration-Variables)) or you will start impersonating me by
accident :)
#### SRV Launched ####
Toggles SRV lights off after launching. Might not work if you drop particularly
far after deployment because it works off a timer. Conversely might take
a second to turn your lights off on a short drop and/or in high gravity.
#### System Scan Complete ####
Lists you all bodies EDDI considers worth mapping in the current system.
#### Undocked ####
Retracts landing gear for you. Seriously, is there any occasion in which you
_dont_ immediately want to retract it after takeoff?
#### VA initialized ####
Fires when the EDDI VoiceAttack plugin is loaded. Makes sure that EDDI is set to
quite mode even if the profile was loaded before plugin initialization had
completed.
### Misc ###
The commands in here do random more or less useful things.
* `bind keys;reset key binds`: Reloads your key binds through the bindED plugin.
You should do that after changing anything in the controls options.
* `copy current system`: Copies the current system name into the clipboard.
* `distance [from;to] […]`: Tells you the distance from your current position to
the other thing you mentioned and is supported in the command. (requires
Python scripts)
* `do a barrow roll`: WHOOOOOOO!
* `fix window dimensions`: When you start the game in VR, it forces into
windowed mode with weird resolution. This changes it back. Hover the “PLAY”
entry in the main menu, then run this. Will need adjustment for different
graphics cards/drivers and the resolution you want.
* `neutron [jump;trip] time`: Shorter version of the same thing in SpanshAttack.
* `neutron jumps left`: Shorter version of the same thing in SpanshAttack.
* `open copied system on EDSM`: Opens the system in your clipboard on EDSM in
your default browser.
* `open coriolis`: Opens Coriolis in your default browser.
* `open [current;] system on EDSM`: Opens your current system on EDSM in your
default browser.
* `open EDDI options; configure EDDI`: Opens the EDDI configuration window.
* `open e d d b [station;system;faction;] [search;]`: Opens EDDB in your default
browser.
* `open e d s m`: Opens EDSM in your default browser.
* `open inara`: Opens Inara in your default browser.
* `open materials finder`: Opens EDTutorials materials finder in your default
browser.
* `open miners tool`: Opens https://edtools.ddns.net/miner in your default
browser.
* `reload bindings`: Reloads your bindings for bindED.
* `shut up EDDI`: Immediately stops any ongoing (and queued) EDDI speech.
* `[start;stop] [EDISON;navigation]`: Hits `CTRL+ALT+E` which just so happens to
be the start/stop hotkey I have set in E.D.I.S.O.N.
* `[bodies;whats;what is] left to [map;be mapped;scan]`: Tells you which bodies
EDDI thinks are worth mapping in the system that you havent mapped yet.
### Navigation ###
There are so many navigation-focused commands now, they deserve there own
category. Basically anything that helps you plot anywhere. A lot of those are
powered by awesome EDDI so I dont have to do the work myself!
* `plot course;[target;] next [waypoint;way point]`: Plots a course to the
system set in `~~system` or the one in your clipboard. The former way is
usually used by other commands to not interfere with your clipboard.
* `[find;target] nearest [encoded;manufactured;raw] material trader`: Targets
the nearest respective material trader.
* `[find;target] nearest [guardian;human] tech broker`: Targets the nearest respective
tech broker.
* `[find;target] nearest [interstellar factor;mission system;scoopable star]`: Well,
you know the drill by now.
* `[find;target] nearest mission system`: Targets the nearest system that has a mission
target.
* `[find;target] [<system>]`: Targets the given system on the galaxy map. Theres
a bunch in there, the list is easily extensible. Drop me a note if you want
something included.
### Ship Controls ###
Basically anything that is related to directly doing something with your ship.
* `[abort;cancel;stop] jumping`: Stops a currently charging FSD jump.
* `[buggy;exploration] power`: Sets your PD to 0/4/2 or 2/4/0 respectively.
Works in SRV too.
* `[close;deploy;extend;open;retract;] […] [up;down;]`: Overly complicated
command to handle everything related to Cargo Scoop, Hard Points, Landing
Gear. You get the gist, I guess. Works in SRV too.
* `[disco;discovery scan]`: Executes a discovery scan. To work properly, youll
have to set the Discovery Scanner to your first fire group, secondary fire.
* `[dis;]engage silent running`: Turns silent running on and off.
* `[head;spot;] lights [on;off]`: Turns your lights on and off. Works in SRV
too, kinda; turning lights off there relies on the state updating fast enough,
which sometimes leads to weird results.
* `[jump;engage;get me out;punch it chewie] [and scan;] [when ready;]`: Retracts
everything that might be protruding from your ship, then jumps to the next
system. If the FSD isnt charging within 1s, it gets you into SC instead (e.g.
if your target is obstructed). If given “and scan” runs a discovery scan. If
given “when ready” waits for mass lock to clear, your FSD to cool down and you
to leave scoop range before jumping.
* `night vision [on;off]`: Toggles your night vision on/off. Works in SRV too.
* `power to [engines;shields;systems;weapons`: Sets 4 pips to the thing you told
it, 1 to the others.
* `rapid fire lights`: Flashes your lights 5 times in a row.
* `retract [all;everything]`: Retracts, well, everything.
* `[start;stop] [firing;mining]`: Starts/stops holding down primary fire. Mostly
useful when mining. When triggered with “mining”, also deploys the cargo
scoop.
* `[super;] cruise [when ready;]`: Retracts everything, then jumps to SC. If
given “when ready” will wait for mass lock to clear and your FSD to cool down
first.
### SRV controls ###
Things relevant to your SRV, but not your ship.
* `[recall;dismiss] ship`: Recalls or dismisses ship. Currently does the same
thing regardless of the state of your ship. I wish it would be possible to
restrict it to doing one thing each, but thats currently not possible sadly.
* `[toggle;enable;disable] drive assist`: Handles all your drive assist needs!
### Targeting ###
Well … targeting stuff, I guess. Not really sure why I made that its own
category, but oh well :)
* `target next system`: Selects the next system on your route.
* `target wing man [1;2;3]`: Targets your wing men.
* `targets target`: Targets your targets target.
* `wing man [1;2;3] target`: Targets your wing mens target.
* `wing man nav lock`: Toggles wing man nav lock on the selected wing member.
### UI Commands ###
Everything handling stuff thats not related to controlling your ship, but
manipulating some UI element(s).
* `controls options`: Opens the controls options menu.
* `docking request;request dock[ing;]`: Sends a docking request.
* `[enter;leave] F S S`: Opens/closes FSS.
* `galaxy map`: Opens the galaxy map.
* `[main;game] menu`: Opens the ESC menu.
* `[relog;reset] to [open;solo]`: Relogs to Open or Solo mode, respectively.
* `restart from Desktop`: Quits the game and restarts from an open launcher by
clicking the play button.
* `set […] filter`: Sets a nav panel filter setting. See the command or just try
different things for what is possible. You need to clear filters and hover
over the filter button, then run this.
* `system map`: Opens the system map.
* `take [high res;] screenshot`: Takes a (high res) screenshot.
* `toggle orbit lines`: Toggles the visibility of orbit lines.
* `[toggle;show;hide] interface`: Toggles the cockpit interface (CTRL+ALT+G).
Probably needs to be adjusted if you are not playing with Neo2 keyboard layout
:)
### Update Commands ###
* `check for profiles update`: Does just that. Is also automatically run each
time the profile is started.
* `download profiles update`: Downloads a profiles update if applicable. Will
prompt you to restart VoiceAttack when the download has finished to import the
updated profiles.
* `open profiles change log`: Opens `CHANGELOG.md` on Github.
## Logging ##
The profile supports logging a bunch of stuff to the VoiceAttack event log. By
default, logging is concise and constrained to basically error messages.
If you need more logging (usually for debugging purposes), say `enable logging`.
If you want to enable verbose logging _by default_, call the
`Logging.enableLogging` command from your custom profiles `startup` command.
## Configuration Variables ##
There are a bunch of configuration variables. You should not overwrite those
manually, instead use the provided commands in the `_configuration` section!
Basically all the settings are available using the `customize settings` prefix,
then saying `[enable;disable] <setting>` for on/off switches and `set <setting>`
for text variables.
* `EDDI.quietMode` (boolean): whether or not to set EDDI to quite mode. Default:
true.
* `Elite.pasteKey` (string): the key used for pasting into Elite. On QWERTY this
is `v`. Default: `p`.
* `EliteDangerous.announceEdsmSystemStatus` (boolean): whether to announce the
system or some of its bodies missing on EDSM. Default: true.
* `EliteDangerous.announceMappingCandidates` (boolean): whether to announce
mapping candidates when they are scanned. Default: true.
* `EliteDangerous.announceOutdatedStationData` (boolean): whether to announce
stations with outdated data in systems you jump to. Default: true.
* `EliteDangerous.announceR2RMappingCandidates` (boolean): whether to announce
planets worth mapping when jumping into a known system. This is useful for
doing some R2R on the side. Default: false.
* `EliteDangerous.autoChangeFuelratsNick` (boolean): whether to change the
FuelRats IRC nickname automatically when changing commanders. Probably largely
irrelevant to you. Default: false.
* `EliteDangerous.enableCarrierAnnouncements` (boolean): whether or not to
process fleet carrier events. Default: true.
* `EliteDangerous.enableAutoUpdateCheck` (boolean): whether or not to
automatically check for updates on profile startup. Default: true.
* `EliteDangerous.flightAssistOff` (boolean): whether to automatically toggle
FlightAssist off on liftoff. Default: true.
* `EliteDangerous.hyperspaceDethrottle` (boolean): same thing as the SC assist
setting; if on, will throttle to 0 automatically after jumping. Default: true.
* `EliteDangerous.oldStationThreshold` (int): Age in days that will cause
station data to be considered outdated. Default: 365 (1year).
* `python.ScriptPath` (string): the path you have placed the compiled python
scripts in. Default: “{VA_DIR}\Sounds\scripts” (the “\Sounds\scripts” folder
in your VoiceAttack installation directory).
#### Delays / Pauses ####
Delays needed e.g. between key presses in UI navigation can vary wildly
depending on your PCs specs and configuration. Therefore they should be
configurable, shouldnt they?
So far those actually are:
* `EliteDangerous.delays.quitToDesktop`: Delay between quitting to desktop and hitting the
play button in the launcher.

View file

@ -1,4 +1,4 @@
# RatAttack #
# RatAttack
This profile facilitates [Fuel Ratting](https://www.fuelrats.com). It aims to
eliminate as much of the required manual task and attention switching as
@ -6,155 +6,52 @@ possible via automation and voice commands.
If you dont know what the Fuel Rats are, come hang out and ask :)
## Requirements ##
Only vanilla VoiceAttack is absolutely required to use this profile. Optionally
you can install EDDI and my elite scripts for advanced features.
* [EDDI](https://github.com/EDCD/EDDI) installed as a VoiceAttack plugin: This
will give you a better (IMO) way of using TTS. Be sure to set
`RatAttack.useEddiForVoice`. It will also enable you to have ingame chat be
transferred to IRC; see below.
* [elite-scripts](https://github.com/alterNERDtive/elite-scripts): Using the
Python scripts will give RatAttack a way to be aware of where your CMDRs are
and give you the nearest one to a rat case. Thats only really needed if you
actually _have_ multiple CMDRs, obviously. If you are using the profile
package from the release page, they will be installed automatically.
### EDDI speech responder ###
For the convenience of people that have not been using EDDI in the past,
RatAttack will deactivate the speech responder automatically to not clutter them
with unwanted TTS.
If you are already an EDDI user and want to keep the default speech responder
functionality, you will have to disable the `EDDI.quietMode` setting by running
the `customize settings disable eddi quiet mode` command.
## Settings ##
There are a lot of preferences you can set, including some you really want to
concern yourself with before you start using the profile. Some of the more
advanced features heavily rely on you giving it the correct things to work with.
See the [Configuration Variables](#Configuration-Variables) section.
## Including the Profile ##
When including the profile, be sure to
* Run the startup command. You will need to have a startup command in your
profile (= one that is run on profile loading) and call `RatAttack.startup`
from that one.
* Make sure all EDDI events that RatAttack needs are correctly handled. For all
events used in RatAttack that you already have handlers for in your profile,
youll have to include a call to `RatAttack.<event name>`. E.g. for “EDDI
Message sent”, call `RatAttack.EDDI Message sent` by name from your `((EDDI
Message sent))` command.
## Usage ##
### Going On/Off Duty ###
## Going On/Off Duty
When you are on duty, RatAttack will automatically announce cases coming in
through IRC. When off duty, it wont.
* `[enable;disable] rat duty`: puts you on/off duty.
* `open [rat;] dispatch board`: opens the web dispatch board.
* `open [fuel rats;] dispatch board`: opens the web dispatch board.
### Handling a Case ###
## Case Handling
#### Getting Case Data From IRC ####
[If you have your IRC client setup
properly](../configuration/RatAttack/#getting-case-data-from-irc), VoiceAttack
will hold a list with all rat cases that have come in while you had it running.
It will save the case number, CMDR name, system, O₂ status and platform. There
are several commands you can run on this list, giving it a case number:
You can setup your IRC client to pass incoming RATSIGNALS to VoiceAttack by
writing them to a file (`%appdata%\Ratattack\ratsignal.pipe`), then calling the
appropriate command (`RatAttack.announceCaseFromRatsignal` for notification,
`RatAttack.getInfoFromRatsignal` for silently putting it into the case list).
### Getting Case Information
This has two purposes:
1. announcing a new incoming case
1. storing case data and making it available to VoiceAttack, e.g. for copying
the cases system into the clipboard
You need to make your IRC client
1. wait until the file disappears (for several cases coming in at once)
1. write the RATSIGNAL to the file
1. run the VoiceAttack command
In my case I am running AdiIRC and have the following script setup for handling
this:
```
on *:TEXT:RATSIGNAL - CMDR*(??_SIGNAL):#fuelrats:{
/mkdir C:\users\<user>\appdata\roaming\RatAttack\
/handleratsignal $1-
}
alias handleratsignal {
if ( $exists(C:\users\<user>\appdata\roaming\RatAttack\ratsignal.pipe) ) {
/sleep 1 /handleratsignal $1-
}
else {
/write C:\users\<user>\appdata\roaming\RatAttack\ratsignal.pipe $1-
if ( $away ) {
/run -h "X:\path\to\VoiceAttack\VoiceAttack.exe" -nofocus -command "RatAttack.getInfoFromRatSignal"
}
else {
/run -h "X:\path\to\VoiceAttack\VoiceAttack.exe" -nofocus -command "RatAttack.announceCaseFromRatSignal"
}
}
}
```
You get the gist; if not and you dont know how to do the same thing for your
IRC client or it doesnt support copying the control characters in the ratsignal
that the profile uses to split the information, either switch to AdiIRC or bribe
me to include some other way to get case data into VoiceAttack.
**Note**: If you are running VoiceAttack as admin you need to run your IRC
client as admin, too! Otherwise it cant talk to VoiceAttack for security
reasons. You really should _not_ run VoiceAttack with elevated privileges
though. Or anything.
#### Internal Case List ####
If you have your IRC client setup properly, VoiceAttack will hold a list with
all rat cases that have come in while you had it running. It will save the case
number, CMDR name, system, O₂ status and platform. There are several commands
you can run on this list, giving it a case number:
* `rat case number [0..19] details`: Will give you all stored info on a case.
* `rat case number [0..30] details`: Will give you all stored info on a case.
* `[current;] rat case details`: Will give you all stored info on the currently
open case.
* `distance to current rat case`: Will give you the distance from your current
location to the currently opened rat case. Requires the use of my
`elite-scripts` Python scripts.
* `distance to rat case number [0..19]`: Will give you the distance from your
current system to a cases system. Requires the use of my `elite-scripts`
Python scripts.
* `nearest commander to rat case number [0..19]`: Will give you the nearest of
your CMDRs with their distance to a cases system. Requires some setup and the
use of my `elite-scripts` Python scripts.
* `nearest commander to [the;] rat case`: Will give you the nearest of your
CMDRs with their distance to the current cases system. Requires some setup
and the use of my `elite-scripts` Python scripts.
location to the currently opened rat case.
* `distance to rat case number [0..30]`: Will give you the distance from your
current system to a cases system.
* `latest rat case details`: Will give you the case data for the latest incoming
case.
* `nearest commander to rat case number [0..30]`: Will give you the nearest of
your CMDRs with their distance to a cases system. [Requires some
setup](../configuration/RatAttack/#announcing-your-nearest-cmdr).
* `nearest commander to [the;] rat case`: Will give you the nearest of your
CMDRs with their distance to the current cases system. [Requires some
setup](../configuration/RatAttack/#announcing-your-nearest-cmdr).
#### Opening a Case ####
### Opening a Case
* `open rat case number [0..19]`: Opens rat case with the given number. If there
* `open rat case number [0..30]`: Opens rat case with the given number. If there
is no case data for that case (e.g. because you dont have your IRC client set
up properly), it will still open it, just not have any data on it.
* `open [latest;] rat case`: Opens the latest rat case that has come in through
IRC. Will probably error out in creative ways if you dont have your IRC
client set up properly. Too tired right now to have proper error handling so
just open an issue if you run into problems (its 7am, I havent slept and
want to finish this doc to get the release out (yes, you are allowed to laugh
at this section)).
* `open [latest;] rat case`: Opens the latest rat case that has come in through
IRC. Will only work if you actually have [your IRC client setup to send case
announcements to
VoiceAttack](../configuration/RatAttack/#getting-case-data-from-irc).
#### Closing a Case ####
* `[close;clear] rat case`: Closes the currently open rat case.
Opening a case will automatically copy the clients system to the clipboard for
easy route plotting. This can be disabled.
### Making Calls ###
@ -164,29 +61,34 @@ will be shortened to the usual IRC short hands (e.g. “sysconf”). If you need
something more unusual you can either still manually type it into your IRC
client or use the “General IRC Integration”, see below.
* `call [1..20] jumps [and login;and takeoff;left;]`: Calls jump for the
* `call [1..20] jumps [and login;and takeoff;left;]`: Calls jumps for the
currently open case. You can optionally include that you will still have to
login to the game or have to take off from your current
station/port/outpost/planet.
* `call friend [positive;negative] [in pg;in private group;in solo;in main
meu;sysconf;system confirmed]`: Friend request confirmations, with all the
* `call jumps [left;]`: Calls jumps for the currently open case based on a
neutron trip (requires SpanshAttack) or a plotted ingame route.
* `call friend [positive;negative] [in pg;in private group;in solo;in main menu;sysconf;system confirmed;]`:
Friend request confirmations, with all the
things you might want to / should call with it.
* `call [beacon;fuel;instance;pos;position;prep;sys;system;wing]
[positive;negative]`: All the stuff you usually need for ratting after you
have received the friend request.
* `call [beacon;fuel;instance;pos;position;prep;sys;system;wing] [positive;negative]`:
All the stuff you usually need for ratting after you have received the friend request.
* `call wing pending`: Calls “wr pending” for when it takes 30s again to
actually show up.
* `call client in [exclusion zone;main menu;open;open sysconf;pg;private
group;solo;super cruise]`: Callouts for all the various things a client could
get themselves into.
* `call client in [exclusion zone;main menu;open;open sysconf;pg;private group;solo;super cruise]`:
Callouts for all the various things a client could get themselves into.
* `call [client destroyed;client offline;sysconf;system confirmed]`: This is the
command you dont want to use. Include sysconf in your “friend+” or “in open”
calls, and make sure you will never have to call “client destroyed”, would
you?
### General IRC Interaction ###
By default, VoiceAttack will ask for confirmation before sending calls to the
`#fuelrats` channel.
(requires EDDI)
### Closing a Case
* `[close;clear] rat case`: Closes the currently open rat case.
## General IRC Interaction
Using EDDI to read the games journal, you can send messages to IRC from Elites
ingame chat.
@ -198,86 +100,11 @@ I recommend using local chat and limiting the use to instances that will
probably not have other players in it (e.g. instanced in normal space with the
client or in SC in some remote system out in the black on a long range rescue).
* #fuelrats: Use “.fr \<message\>” to have VoiceAttack send “#\<caseNumber\>
\<message\>” to the #fuelrats channel or yell at you when you are not on
a case.
* #ratchat: Use “.rc \<message\>” to have VoiceAttack send “\<message\>” to
#ratchat.
* \#fuelrats: Use `.fr <message>` to have VoiceAttack send
`#<caseNumber> <message>` to \#fuelrats or yell at you when you
are not on a case.
* \#ratchat: Use `.rc <message>` to have VoiceAttack send `<message>` to
\#ratchat.
These commands send their text to windows with “#fuelrats” and “#ratchat” in
their title, respectively. If your IRC client does not do that, you will have to
change the “target” window of the `RatAttack.sendToFuelrats` and
`RatAttack.sendToRatchat` commands to reflect the actual window titles on your
system. I will look into making this more elegant to change in the future.
## Logging ##
The profile supports logging a bunch of stuff to the VoiceAttack event log. By
default, logging is concise and constrained to basically error messages.
If you need more logging (usually for debugging purposes), say `enable logging`.
If you want to enable verbose logging _by default_, call the
`Logging.enableLogging` command from your custom profiles `startup` command.
## Exposed Variables ##
The following Variables are _global_ and thus readable (and writeable! Please
dont unless its a config variable …) from other profiles.
### Configuration Variables ###
There are a bunch of configuration variables. You should not overwrite those
manually, instead use the provided commands in the `_configuration` section!
Basically all the settings are available using the `customize settings` prefix,
then saying `[enable;disable] <setting>` for on/off switches and `set <setting>`
for text variables.
* `EDDI.quietMode` (boolean): whether or not to set EDDI to quite mode. Default:
true.
* `EDDI.useEddiForVoice` (boolean): whether to use the EDDI plugin to handle
text-to-speech over VoiceAttacks built-in speech function. Default: false.
* `Elite.pasteKey` (string): the key used for pasting into Elite. On QWERTY this
is `v`. Default: `v`.
* `RatAttack.announceNearestCMDR` (boolean): whether or not to automatically
announce your nearest CMDR to a case. Requires the `elite-scripts` Python
scripts. Will probably break in creative ways if you dont have them and turn
it on anyway. Default: false.
* `RatAttack.announcePlatform` (boolean): whether or not to announce the cases
platform by default. Useful to set if you are active on more than one
platform. Even with this off, you will still be warned when you open a case
that is _not_ on one of your platforms. Default: false.
* `RatAttack.CMDRs` (string): list of your CMDR names, delimited by spaces. If
your names include spaces, you will have to put them in quotes. Default: “"J
Jora Jameson" NameWithNoSpace”.
* `RatAttack.confirmCalls` (boolean): whether VoiceAttack should ask you before
posting to #fuelrats to make sure there hasnt been an error in voice
recognition and you accidentally post the wrong thing. Default: true.
* `RatAttack.autoCloseCase` (boolean): whether or not to automatically close an
open rat case on calling “fuel+”. Default: false.
* `RatAttack.onDuty` (boolean): whether or not you are currently on rat duty.
Default: true.
* `RatAttack.platforms` (string): the platforms you want to be informed of
incoming cases for. If you are on console, you can still have VoiceAttack
running on the PC that you are using for IRC and handle calls and stuff using
voice! Delimited by whatever you want. Can include “PC”, “XB”, “PS4”.
Default: “PC”.
* `python.scriptPath` (string): the path you put the Python scripts in. Default:
“{VA_DIR}\Sounds\scripts”.
### Other Variables ###
Current case data:
* `RatAttack.caseNumber` (int): the number of the case you are currently on.
Will be `Not Set` if you are not on a case.
* `RatAttack.onCase` (boolean): whether or not you are currently on a case.
Case list:
* `RatAttack.caseList.<case#>.cmdr` (string)
* `RatAttack.caseList.<case#>.system` (string)
* `RatAttack.caseList.<case#>.platform` (string)
* `RatAttack.caseList.<case#>.codeRed` (boolean)
… with `<case#>` being a number between 0 and 19.
Make sure [that your IRC client is setup
properly](../configuration/RatAttack/#sending-text-to-fuelrats-irc).

View file

@ -1,99 +1,34 @@
# SpanshAttack #
# SpanshAttack
This profile uses the
[ED-NeutronRouter](https://github.com/sc-pulgan/ED-NeutronRouter) plugin to plot
neutron jumps using [spansh](https://spansh.co.uk/plotter). It fully does
everything you need from within the game and VoiceAttack, you wont have to
visit the site at any point.
[ED-NeutronRouter](https://github.com/sc-pulgan/ED-NeutronRouter) plugin to
plot neutron jumps using [Spansh](https://spansh.co.uk/plotter). It does
everything you need fully from within the game and VoiceAttack, you wont have
to visit the site at any point.
## Requirements ##
In addition to VoiceAttack, you will need the following plugins to use this
profile:
* [bindED](https://forum.voiceattack.com/smf/index.php?topic=564.0)
* [EDDI](https://github.com/EDCD/EDDI) installed as a VoiceAttack plugin
* [ED-NeutronRouter](https://github.com/sc-pulgan/ED-NeutronRouter): required
for SpanshAttack. **Make sure to [grab the pre-release
1.02](https://github.com/sc-pulgan/ED-NeutronRouter/releases/tag/1.02)** since
1.01 has a bug with a hardcoded 50ly jump range.
### EDDI speech responder ###
For the convenience of people that have not been using EDDI in the past,
SpanshAttack will deactivate the speech responder automatically to not clutter
them with unwanted TTS.
If you are already an EDDI user and want to keep the default speech responder
functionality, you will have to disable the `EDDI.quietMode` setting by running
the `customize settings disable eddi quiet mode` command.
## Settings ##
Because Elites keyboard handling is … weird youll have to set the key to use
for pasting text into Elite:Dangerous. If you are not using a “standard”
QWERT[YZ] layout, you will have to change it back to the key that is physically
in the place where `v` would be on QWERTY.
For other settings, see the [Configuration Variables](#Configuration-Variables)
section.
The last “setting” in the not-so-strict sense of the word is the
`SpanshAttack.getShipRange` command. Any ship listed in there will automatically
have its jump range used instead of VA prompting you for it. Since, again, VA
will execute the first matching command found, you can create this command in
your own profile when you are using SpanshAttack by including it. You can
override a saved range for your ship by using the `plot neutron
[course;route;trip] with custom range` command.
The ED-NeutronRouter plugin is technically supposed to read the current jump
range from EDDI; sadly a) its
[bugged](https://github.com/sc-pulgan/ED-NeutronRouter/issues/3) right now, and
b) EDDI is storing the _maximum_ distance for your ship instead of the current
/ full on fuel one.
## Including the Profile ##
When including the profile, be sure to
* Run the startup command. You will need to have a startup command in your
profile (= one that is run on profile loading) and call `SpanshAttack.startup`
from that one.
* Make sure all EDDI events that SpanshAttack needs are correctly handled. For
all events used in SpanshAttack that you already have handlers for in your
profile, youll have to include a call to `SpanshAttack.<event name>`. E.g.
for “EDDI Jumped”, call `SpanshAttack.EDDI Jumped` by name from your `((EDDI
Jumped))` command.
* (Optional) Have a `SpanshAttack.getShipRange` command in your profile to
overwrite the default one with your ships ranges. See the default command for
pointers.
## Usage ##
### Plotting a Route ###
## Plotting a Route
1. _Target_ the system you want to be routed to (target, do not plot to it).
1. Either exit the galaxy map or make sure you are on its first tab (or
auto-plotting will break).
1. Trigger the `SpanshAttack.plotRoute` command either by voice (`plot neutron
[course;route;trip] [with custom range;]`) or calling it from another
command.
1. Trigger the `SpanshAttack.plotRoute` command either by voice
(`plot neutron [course;route;trip] [with custom range;]`) or by
calling it from another command.
1. Enter your ships jump range if prompted.
1. Wait for the route to be calculated. The command will automatically open the
galaxy map and jump to the first waypoint on your route. If you run into
weird behaviour, its probably because your target system is not in EDDB.
galaxy map and search it for the first waypoint on your route.
1. Either target the first waypoint or plot to it.
1. Start jumping!
#### Plotting to a System Unknown to the Neutron Router ####
### Plotting to a System Unknown to the Neutron Router
The router can only plot a route to a system that is in its data base (obviously
can also only give you way points that are). If your target system is not, there
The router can only plot a route to a system that is in its database (obviously
can also only give you waypoints that are). If your target system is not, there
are several levels of fallback handling to find a system that is.
1. Check `Next system` coordinates provided by EDDI. If the system is in EDSM,
but has for some reason not been sent over EDDN to other sites including
Spansh we can get coordinates here.
Spansh, we can get coordinates here.
1. If the system is not in EDSM check EDTS. It can calculate approximate
coordinates for a given procedurally generated system name.
1. If that fails prompt the user for input.
@ -106,39 +41,51 @@ you will be prompted to make sure you are going roughly to the right
coordinates. You will find the system that is used for plotting, its
coordinates and the accuracy in VoiceAttacks log window.
### Neutron Jumping ###
## Neutron Jumping
With standard settings, just supercharge off a neutron cone. You should
automatically be taken to the galaxy map with the next waypoint selected.
In case you have disabled auto-plotting to the next waypoint, manually invoke
the `SpanshAttack.targetNextNeutronWaypoint` command by voice (`[target;] next
neutron [waypoint; way point]`) or calling it from another command.
the `SpanshAttack.targetNextNeutronWaypoint` command by voice
(`[target;] next neutron [waypoint; way point]`) or calling it from
another command.
Additionally, you can use the `SpanshAttack.copyNextNeutronWaypoint`
/ `[get;copy] next neutron [waypoint;way point]` command to copy the next
neutron waypoint to the clipboard.
#### Manual Re-Plot ####
### Skipping a Waypoint
Trigger the `SpanshAttack.replotRoute` command either by voice (`replot neutron
[course;route;trip]`) or calling it from another command. This will start
a re-plot of the current route with the same target system and jump range.
Sometimes, especially in very neutron-sparse areas of the galaxy, the plotter
will give you weird jumps. E.g. I recently got neutron → 37 ly → neutron → 440
ly.
### Refueling ###
In these cases you can use the `SpanshAttack.skipNeutronWaypoint` / `skip
[this;current] neutron waypoint` command to move on to the next one in the
list.
Whenever you refuel off a scoopable star, the profile will automatically
throttle back up to 100% speed. Unless you have disabled it in your
configuration, you will also automatically target the next system on your route
and jump to it once you leave fuel scoop range.
### Manual Re-Plot
### Clearing a Route ###
Trigger the `SpanshAttack.replotRoute` command either by voice
(`replot neutron [course;route;trip]`) or calling it from another command.
This will start a re-plot of the current route with the same target system and
jump range.
When you reach your target system, the neutron route will automatically be
cleared. If you want to prematurely end your trip, call the
## Refueling
Whenever you finish refueling off a scoopable star, the profile will
automatically throttle back up to 100% speed. Unless you have disabled it in
your configuration, you will also automatically target the next system on your
route and jump to it once you leave fuel scoop range.
## Clearing a Route
When you reach your target system the neutron route will automatically be
cleared. If you want to prematurely end your trip, call the
`SpanshAttack.clearRoute` / `clear neutron [course;route;trip]` command.
## Other Commands ##
## Other Commands
### Announcing Jumps Left ###
@ -155,87 +102,4 @@ neutron waypoint_.
SpanshAttack keeps track of your start time, even if you have the option to time
your trip turned off. This way you can get the time youve been jumping with the
`SpanshAttack.announceTripTime` or
`how long have i been [jumping;on this trip;on this neutron trip]?` commands.
### Reload bindings ###
If you change any relevant bindings (e.g. the galaxy map key), you should run
the `reload bindings` command to make sure that SpanshAttack presses the right
thing for you.
Eh, just do it every time you edit your controls without re-starting
VoiceAttack, just to be sure.
### Helper Functions ###
The profile contains a lot of helper functions that get called by the
aforementioned commands. Have a look around, maybe learn something about
VoiceAttack :)
## Logging ##
The profile supports logging a bunch of stuff to the VoiceAttack event log. By
default, logging is concise and constrained to basically error messages.
If you need more logging (usually for debugging purposes), say `enable logging`.
If you want to enable verbose logging _by default_, call the
`Logging.enableLogging` command from your custom profiles `startup` command.
## Exposed Variables ##
The following Variables are _global_ and thus readable (and writeable! Please
dont unless its a config variable …) from other profiles:
### Configuration Variables ###
There are a bunch of configuration variables. You should not overwrite those
manually, instead use the provided commands in the `_configuration` section!
Basically all the settings are available using the `customize settings` prefix,
then saying `[enable;disable] <setting>` for on/off switches and `set <setting>`
for text variables.
* `EDDI.quietMode` (boolean): whether or not to set EDDI to quite mode. Default:
true.
* `EDDI.useEddiForVoice` (boolean): whether to use EDDI over VAs builtin `say`
command. Default: false.
* `Elite.pasteKey` (string): the key used for pasting into Elite. On QWERTY this
is `v`. Default: `v`.
* `SpanshAttack.timeTrip` (boolean): whether to automatically tell you at the
end of a trip how long it took you to get there. Default: false.
* `SpanshAttack.announceWaypoints` (boolean): whether to announce each waypoint
of the neutron route. Default: true.
* `SpanshAttack.announceJumpsLeft` (string): `;`-separated list of remaining
jumps to announce when said amounts are reached. Right now only works if they
are _exactly_ reached when supercharging off a neutron. Note the extra `;` at
the beginning and end of the string. Default: `;1;3;5;10;15;20;30;50;75;100;`
* `SpanshAttack.autoJumpAfterScooping` (boolean): whether to automatically jump
after fuel scooping (and moving out of scoop range). Default: true.
* `SpanshAttack.autoPlot` (boolean): whether to automatically plot to the next
waypoint on supercharging. Default: true.
* `SpanshAttack.clearOnShutdown` (boolean): whether or not to automatically
clear an active neutron route on Elite client shutdown. Default: true.
* `SpanshAttack.defaultToLadenRange` (boolean): whether or not to default to
your ships laden range (as reported by EDDI) instead of asking for user
input. Sadly its with _current_ fuel, not full. Setting a ships jump range
in the `SpanshAttack.getShipRange` command will still overrule this. Default:
false.
* `SpanshAttack.copyWaypointToClipboard` (boolean): whether to copy the next
waypoint into the Windows clipboard for use in other programs. Default: false.
* `python.scriptPath` (string): the path you put the Python scripts in.
Default: “{VA_DIR}\Sounds\scripts”.
### Other Variables ###
These variables can be used to get information about the current neutron route.
Please do not set them manually and / or from outside the SpanshAttack profile.
* `SpanshAttack.plotSystem` (string): the system actually plotted towards using
the neutron router (onley used/set if the target system is not in the data
base)
* `SpanshAttack.targetSystem` (string): the target system for the current
neutron route
* `SpanshAttack.nextNeutronWaypoint` (string): the next waypoint on the current
neutron route
* `SpanshAttack.neutronJumpMode` (boolean): neutron jump mode active/inactive
* `SpanshAttack.jumpRange` (decimal): the current ships jump range
`how long have i been [jumping;on this trip;on this neutron trip]?` commands.

View file

@ -1,120 +1,52 @@
# StreamAttack #
# StreamAttack
This profile uses the [EDDI](https://github.com/EDCD/EDI) plugin to write
This profile uses the [EDDI](https://github.com/EDCD/EDDI) plugin to write
a bunch of information about your commander, your current location and your ship
to files that can be accessed e.g. by your streaming software to be displayed on
stream.
Default folder is `%appdata%\StreamAttack\`.
## Requirements ##
## Commands
In addition to VoiceAttack, you will need the following plugins to use this
profile:
* [EDDI](https://github.com/EDCD/EDDI) installed as a VoiceAttack plugin
### EDDI speech responder ###
For the convenience of people that have not been using EDDI in the past,
StreamAttack will deactivate the speech responder automatically to not clutter
them with unwanted TTS.
If you are already an EDDI user and want to keep the default speech responder
functionality, you will have to disable the `EDDI.quietMode` setting by running
the `customize settings disable eddi quiet mode` command.
## Settings ##
See the [Configuration Variables](#Configuration-Variables) section.
## Including the Profile ##
When including the profile, be sure to
* Run the startup command. You will need to have a startup command in your
profile (= one that is run on profile loading) and call `StreamAttack.startup`
from that one.
* Make sure all EDDI events that StreamAttack needs are correctly handled. For
all events used in StreamAttack that you already have handlers for in your
profile, youll have to include a call to `StreamAttack.<event name>`. E.g.
for “EDDI Jumped”, call `StreamAttack.EDDI Jumped` by name from your `((EDDI
Jumped))` command.
## Commands ##
* `clear jump target`: clears the current jump target.
* `set jump target`: sets the jump target to the currently targeted system.
* `clear jump target`: Clears the current jump target.
* `distance [to;from] jump target`: Tells you the current distance to the jump
target.
* `set jump target`: Sets the jump target to the currently targeted system.
Distance will be written to the configured file.
* `[copy;open] ship build`: copies the current ship build (coriolis) or opens it
* `[copy;open] ship build`: Copies the current ship build (coriolis) or opens it
in your default browser.
* `open StreamAttack folder`: opens the configured folder in Explorer.
* `open StreamAttack folder`: Opens the configured folder in Explorer.
## Files the Profile Provides ##
## Output Files
### Elite ###
### Elite
#### Commander ####
Please do note that information in the output files is only updated when a
journal event that contains the information is detected. E.g. the distance to
your jump target is not constantly calculated, but only updated after a jump.
* `Elite\cmdr\name`: the current commanders name.
#### Commander
#### Jump Target ####
* `Elite\cmdr\name`: The current commanders name.
* `Elite\jumpTarget\distance`: distance to current jump target in light years.
* `Elite\jumpTarget\full`: pretty-printed `<distance> ly to <name>`.
* `Elite\jumpTarget\name`: the current jump targets system name.
#### Jump Target
#### Location ####
* `Elite\jumpTarget\distance`: Distance to current jump target in light years.
* `Elite\jumpTarget\full`: Pretty-printed `<distance> ly to <name>`.
* `Elite\jumpTarget\name`: The current jump targets system name.
* `Elite\location\full`: depending on your status, either the station you are
#### Location
* `Elite\location\full`: Depending on your status, either the station you are
currently docked at (+ system), the body you are currently near, or the system
you are currently in.
* `Elite\location\system`: the system you are currently in.
* `Elite\location\system`: The system you are currently in.
#### Ship ####
#### Ship
* `Elite\ship\build`: your current ships loadout (link to coriolis).
* `Elite\ship\build`: Your current ships loadout (link to coriolis).
* `Elite\ship\full`: `“<name>” | <model> | <build>`.
* `Elite\ship\model`: your current ships model.
* `Elite\ship\name`: your current ships name.
## Logging ##
The profile supports logging a bunch of stuff to the VoiceAttack event log. By
default, logging is concise and constrained to basically error messages.
If you need more logging (usually for debugging purposes), say `enable logging`.
If you want to enable verbose logging _by default_, call the
`Logging.enableLogging` command from your custom profiles `startup` command.
## Exposed Variables ##
The following Variables are _global_ and thus readable (and writeable! Please
dont unless its a config variable …) from other profiles:
### Configuration Variables ###
There are a bunch of configuration variables. You should not overwrite those
manually, instead use the provided commands in the `_configuration` section!
Basically all the settings are available using the `customize settings` prefix,
then saying `[enable;disable] <setting>` for on/off switches and `set <setting>`
for text variables.
* `EDDI.quietMode` (boolean): whether or not to set EDDI to quite mode. Default:
true.
* `EDDI.useEddiForVoice` (boolean): whether to use EDDI over VAs builtin `say`
command. Default: false.
* `StreamAttack.outputDir` (string): the directory StreamAttack will save its
information to. Default: `%appdata%\StreamAttack\`.
* `python.ScriptPath` (string): the path you have placed the compiled Python
scripts in. Default: “{VA_DIR}\Sounds\scripts” (the “\Sounds\scripts” folder
in your VoiceAttack installation directory).
### Other Variables ###
These variables can be used to get information about the current neutron route.
Please do not set them manually and / or from outside the StreamAttack profile.
* `StreamAttack.Elite.jumpTarget` (string): the current jump target.
* `Elite\ship\model`: Your current ships model.
* `Elite\ship\name`: Your current ships name.

4
docs/VoiceAttack.md Normal file
View file

@ -0,0 +1,4 @@
# VoiceAttack Tips
This will fill up eventually with tips on how to properly setup VoiceAttack for
decent recognition.

View file

@ -0,0 +1,53 @@
# EliteAttack
## Settings
Toggles:
* `auto honk all systems`: Automatically honk upon entering a system, each jump,
without constraints. Default: false.
* `auto honk new systems`: Automatically honk upon entering a system if it is
your first visit. Default: true.
* `auto refuel`: Automatically refuel after docking at a station. Default:
true.
* `auto repair`: Automatically repair after docking at a station. Default:
true.
* `auto restock`: Automatically restock after docking at a station. Default:
true.
* `auto move to hangar`: Automatically move the ship to the hangar after docking
at a station. Default: true.
* `auto enter station services`: Automatically enter the Station Services menu
after docking at a station. Default: true.
* `auto retract landing gear`: Automatically retract landing gear when lifting
off a planet / undocking from a station. Default: true. (#133)
* `auto disable s r v lights`: Automatically turn SRV lights off when deploying
one. Default: true. (#133)
* `edsm system status`: Pull system data from EDSM and compare it
against your discovery scan. Default: true.
* `discovery scan on primary fire`: Use primary fire for honking instead of
secondary. Default: false.
* `flight assist off`: Permanent Flight Assist off mode. You should really do
that, its great. Default: false.
* `hyper space dethrottle`: Throttle down after a jump and when dropping from
SC. Like the SC Assist module does. Default: true.
* `limpet check`: Do a limpet check when undocking, reminding you if you forgot
to buy some. Default: true.
* `mapping candidates`: Announce bodies worth mapping when you have finished
scanning a system. (Terraformables, Water Worlds, Earth-Like Worlds and
Ammonia Worlds that have not been mapped yet.) Default: true.
* `outdated stations`: Announce stations with outdated data in the online
databases. Default: true.
* `include outdated settlements` option: Include Odyssey settlements in the
outdated stations list. Default: true.
* `repair reports`: Report on AFMU repairs. Default: true.
* `road to riches`: Announce bodies worth scanning if you are looking for some
starting cash on the Road to Riches. Default: false.
* `route jump count`: Give a jump count on plotting a route. Default: true.
* `synthesis reports`: Report on synthesis. Default: true.
Other settings:
* `outdated station threshold`: The threshold for station data to count as
“outdated”, in days. Default: 365.
* `scanner fire group`: The fire group your discovery scanner is assigned to.
Default: 0 (the first one).

View file

@ -0,0 +1,108 @@
# RatAttack
## Getting Case Data From IRC
You can setup your IRC client to pass incoming RATSIGNALS to VoiceAttack by
calling the `RatAttack-cli.exe` helper tool with the RATSIGNAL as first argument
and an optional boolean as second argument that triggers a TTS case
announcement. You can find it under your VoiceAttack “Apps” folder,
`\alterNERDtive\RatAttack-cli.exe`.
**Note**: If you are running VoiceAttack as admin, you need to run your IRC
client as admin, too! Otherwise they cannot communicate. In general you want to
run both with normal privileges.
This has two purposes:
1. Announcing a new incoming case (if passing `true` as second argument).
1. Storing case data and making it available to VoiceAttack, e.g. for copying
the clients system into the clipboard.
For my AdiIRC, it looks like this (obviously change the path, please):
```adiirc
on *:TEXT:*RATSIGNAL*(??_SIGNAL):#fuelrats:{
if ( $away ) {
/run -h "X:\path\to\VoiceAttack\Apps\alterNERDtive\RatAttack-cli.exe" " $+ $replace($1-,","") $+ " false
}
else {
/run -h "X:\path\to\VoiceAttack\Apps\alterNERDtive\RatAttack-cli.exe" " $+ $replace($1-,","") $+ " true
}
}
```
If I am away it will just add the new case to the list. If I am not away, it
will announce it using TTS.
The “replace” part handles the fact that announcements now put the system in
quotes. They have to be escaped as double quotes (`""`) to create a correct
command invocation.
You get the gist; if not and you dont know how to do the same thing for your
IRC client, either switch to AdiIRC or bribe me to make an example for yours.
mIRC is a straight forward copy & paste job from Adi to mIRC (“Tools” → “Script
Editor” → “Remote”). Make sure you do not strip colour codes from incoming
messages!
Note for Hexchat users: Hexchat doesnt seem to have a simple way of doing this.
If you figure it out, Ill gladly add instructions here.
Keep in mind that if you are not on duty (see below) you will _not_ get case
announcements.
## Announcing Your Nearest CMDR
In case you have more than one CMDR registered as a Fuel Rat you can have
VoiceAttack announce the nearest one to a case and the distance. You will have
to go through a couple steps to set that up:
1. Have all CMDRs on EDSM.
1. Have all profiles on EDSM set to _public_ including your flight log (which
includes the current location).
1. Set the CMDR names you want to use (“customize setting set fuel rat
commanders”).
1. Enable the nearest CMDR announcements (“customize setting enable nearest
commander to fuel rat case”).
You can use this for a single CMDR, too. A less convoluted setup for announcing
the distance to your location in that case is on the list™ but does not have an
ETA yet.
Currently there is no way to specify a platform for each CMDR separately.
## Sending Text to FuelRats IRC
The profile will attempt to send calls to “\#fuelrats”, and you can send
messages from ingame chat to “\#fuelrats” and “\#ratchat”.
That will send text to windows with “\#fuelrats” and “\#ratchat” in
their title, respectively. If your IRC client does not do that, you will have to
change the “target” window of the `RatAttack.sendToFuelrats` and
`RatAttack.sendToRatchat` commands to reflect the actual window titles on your
system. I will look into making this more elegant to change in the future.
## Settings
Toggles:
* `auto close fuel rat case`: Automatically close a rat case when sending
“fuel+” via voice command or ingame chat. Default: false.
* `auto copy rat case system` : Automatically copy the clients system to the
clipboard when you open a rat case. Default: true.
* `fuel rat call confirmation`: Only make calls in #fuelrats after vocal
confirmation to prevent mistakes. Default: true.
* `fuel rat duty`: On duty, receiving case announcements via TTS. Default: true.
* `nearest commander to fuel rat case`: Announce the nearest commander to
incoming rat cases. Default: false.
* `platform for fuel rat case`: Announce the platform for incoming rat cases.
Default: false.
* `system information for fuel rat case`: System information provided by Mecha.
Default: true.
Other Settings:
* `fuel rat commanders`: All your CMDRs that are ready to take rat cases. Use
; as separator, e.g. “Bud Spencer;Terrence Hill”. Default: "".
* `fuel rat platforms`: The platform(s) you want to get case announcements for
(PC, Xbox, Playstation). Use ; as separator, e.g. “PC;Xbox”. Default: "PC".

View file

@ -0,0 +1,47 @@
# SpanshAttack
## Supplying Your Ships Range
The ED-NeutronRouter plugin is technically supposed to read the current jump
range from EDDI; sadly EDDI is storing the _maximum_ distance for your ship
instead of the current / full on fuel one. The “default to laden range” option
works reasonably well, but it has a few quirks. It always assumes full cargo,
and it will take your _current_ fuel levels for range calculations, disregrading
the range loss if you fill your tank.
For any ships that you regularly use for neutron jumping, e.g. long range Fuel
Rat ships, I recommend telling SpanshAttack about the range they are supposed to
have with full fuel and your preferred amount of cargo/limpets.
In order to do that, copy the `SpanshAttack.getShipRange` command from
SpanshAttack or the example profile to your custom profile and add your ships.
Any ship listed in there will automatically have its jump range used instead of
EDDIs reported laden range or VoiceAttack prompting you to manually supply it.
![[SpanshAttack-getshiprange.png]]
You can override a saved range for your ship by using the
`plot neutron [course;route;trip] with custom range` command.
## Settings
Toggles:
* `auto jump after scooping`: Automatically jump out when fuel scooping is
complete. Default: true.
* `auto plot`: Automatically plot to the next waypoint after supercharging.
Default: true.
* `clear neutron route on shutdown`: Clear an active neutron route when the game
is shut down. Default: true.
* `copy neutron waypoints to clipboard`: Copy each neutron waypoint into the
Windows clipboard. Default: false.
* `default to laden range`: Default to the current ships laden range as
reported by EDDI instead of prompting for input. Default: false.
* `time neutron route`: Keep track of how long a neutron route takes you to
complete. Default: false.
* `waypoint announcements`: Announce each waypoint by name. Default: true.
Other Settings:
* `announce jumps left`: Estimated jumps left to announce when reached. NEEDS to
have leading and trailing “;”. Default: ";1;3;5;10;15;20;30;50;75;100;"

View file

@ -0,0 +1,6 @@
# StreamAttack
## Settings
* `StreamAttack output directory`: The directory the status files are written
to. Default: "%appdata%\StreamAttack\"

View file

@ -0,0 +1,77 @@
# General Configuration
## Settings
All profiles will load sane defaults if you havent changed anything. The
configuration is stored in a bunch of VoiceAttack variables which in turn are
stored in your custom profile. You could even have different custom profiles
with their own distinct settings.
The easiest way to change settings is to say `customize settings`. That will
bring up a rudimentary settings UI.
You change also change the configuration directly via voice commands:
* For toggles (booleans): `customize setting [enable;disable] <trigger phrase>`
* For everything else: `customize setting set <trigger phrase>`
You can find a list of trigger phrases on this page, or you can say
`customize setting list [options;settings]` for a list of voice triggers and
what they do. If you dont remember your settings or just want a nice list,
`customize setting report [options;settings]` will print that to the
VoiceAttack log. If you want to reset everything back to default state, say
`customize setting clear all my settings`.
The “customize setting” prefix is kind of a leftover from times long gone and
does not quite fit anymore. Might change in a future version.
Since the settings are saved to your custom profile they will not necessarily be
preserved when you switch profiles. Once you switch back, the correct settings
for the profile are re-loaded.
### General Settings for All Profiles
Toggles:
* `auto update check`: Automatically check Github for profiles updates when the
profile loads. Default: true.
* `eddi quiet mode`: Make EDDI shut up. Disables all built-in speech responders.
Default: true.
Other settings:
* `elite paste key`: The key used to paste in conjunction with CTRL. The
physical key in your layout that would be 'V' on QWERTY. Default: 'v'.
* `log level`: The level of detail for logging to the VoiceAttack log. Valid
levels are "ERROR", "WARN", "NOTICE", "INFO" and "DEBUG". Default: "NOTICE".
* `quit to desktop delay`: The delay before restarting the game after hitting
“Exit to Desktop”, in seconds. Default: 10.0. (Used by the `restart from desktop`
command)
## Note on Non-Standard Keyboard Layouts
Because Elites keyboard handling is … weird youll have to set the key to use
for pasting text into Elite Dangerous if you are not using a keyboard layout
that the game supports by default. You will have to change it to the key that
is physically in the place where `V` would be on QWERTY, e.g. `P` for
[Neo2](https://neo-layout.org).
To set the key, say “customize setting set elite paste key”.
## Adding Commands
If you want to edit a command or add your own, _do not edit the profiles
directly_. Instead create commands in your custom profile, and copy commands you
want to change over to that before editing them. This will make sure no changes
are lost if you update the profiles.
### EDDI Events
Because of limitations of VoiceAttack itself, only the first matching command
found will be executed, _including EDDI events_. That means that if you create
commands to handle EDDI events, you are going to have to make sure that the
appropriate handlers in my profiles are called, too. That is done by invoking
the `eddi.Event` plugin context of the `alterNERDtive-base` plugin. Otherwise
stuff _will_ break.
![[EDDI-event.png]]

41
docs/general.md Normal file
View file

@ -0,0 +1,41 @@
# General Commands
## Configuration
The base profile provides voice commands for changing the profiles settings.
See [the configuration section](../configuration/general#settings).
## Chat
* `paste text`: Pastes the contents of your current clipboard. Note that this
command is supposed to be used for pasting _into Elite_ and hence uses the
configured paste key. If youre using a non-standard layout that means that
you _cannot_ use this command to paste text into other applications.
## Updating
* `check for profiles update`: Checks Github for a new version, and alerts you
if there is one.
* `download profiles update`: Opens the latest release on Github and the
VoiceAttack import folder where you can drop it.
* `open profiles [docs;documentation;help] [file;site;]`: Opens this
documentation, either on the web or the PDF file supplied with the installed
release.
* `open profiles change log`: Opens the CHANGELOG on Github.
* `open voiceattack [apps;import;sounds] [folder;directory]`: Opens the
respective VoiceAttack-related folder.
## Miscellaneous
* `generate missing key binds report`: Generates a report of missing key binds
and places it on your Desktop. Note that this currently uses bindEDs built-in
report which will output _any_ bind that does not have a keyboard key set,
including axis binds and binds that are not actually used by the profiles.
* `open documentation`: Opens the documentation in your default browser.
* `open EDDI options;configure EDDI`: Displays EDDIs configuration window.
* `open elite bindings folder`: Opens Elites bindings folder
(`%localappdata%\Frontier Developments\Elite Dangerous\Options\Bindings`)
* `reload elite key binds`: Forces a reload of your Elite binds. Should not be
necessary.
* `shut up EDDI`: Immediately interrupts any current and pending speech on
EDDIs end.

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
docs/images/EDDI-event.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
docs/images/Elite-COVAS.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

BIN
docs/images/Elite-binds.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

43
docs/index.md Normal file
View file

@ -0,0 +1,43 @@
# Elite Dangerous VoiceAttack Profiles
These are various profiles for [VoiceAttack](https://voiceattack.com) (VA) I use
to enhance my Elite experience. They give me important info, facilitate
day-to-day gaming and do some special things for [Fuel
Rats](https://fuelrats.com) and [Hull Seals](https://hullseals.space) work.
**NOTE**: Further development is on hold and Odyssey compatibility will not be
worked on for the time being. See [the corresponding issue on
Github](https://github.com/alterNERDtive/VoiceAttack-profiles/issues/113). This
might or might not change after the Horizons/Odyssey merge. Feel free to file
issues for anything that is broken on Odyssey and it will be worked on when it
is worked on.
## Available Profiles
* [EliteAttack](EliteAttack): The main Elite VA profile. Anything related to
“just” playing the game.
* [RatAttack](RatAttack): Manages interactions with the FuelRats IRC server.
* [SpanshAttack](SpanshAttack): Plots and follows trips along the neutron
highway using [Spanshs neutron plotter](https://spansh.co.uk/plotter).
* [StreamAttack](StreamAttack): Writes various status things to files that can
then be read by streaming software like OBS.
They all require the `alterNERDtive-base` profile that, well, provides basic
functionality common to all of the above.
## Need Help / Want to Contribute?
Well, you are in the right place. You can find comprehensive documentation right
here.
If you run into any errors, please make sure you are running the latest version
of the profiles and all [requirements](requirements.md).
If your problem persists, please [file an
issue](https://github.com/alterNERDtive/VoiceAttack-profiles/issues). Thanks! :)
You can also [say “Hi” on Discord](https://discord.gg/kXtXm54) if that is your
thing.
[![GitHub Sponsors](https://img.shields.io/github/sponsors/alterNERDtive?style=for-the-badge)](https://github.com/sponsors/alterNERDtive)
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/S6S1DLYBS)

238
docs/installing.md Normal file
View file

@ -0,0 +1,238 @@
# Installing
## Install VoiceAttack
Grab the [most recent VoiceAttack beta
version](https://voiceattack.com/#download-1) off the official site and install
it.
If you are using the standalone version you should probably download the
executable installer.
![[VoiceAttack-download.png]]
If you are using the Steam version of VoiceAttack, you will have to download the
zipped folder and replace your installed version with its contents.
[Here is the first hit on a Google search for finding the installation
folder](https://steamcommunity.com/sharedfiles/filedetails/?id=760447682). It is
for a completely unrelated game, but the steps are the same.
You can potentially also install the latest non-beta version; but I often use
features that have only just been added to the beta, so some things might break
for you if you are not using that. There might not be a beta version at the time
youre reading this, just get the full release then.
### Enable Plugin Support
Make sure you have plugin support enabled:
1. Go to VoiceAttack settings. ![[VoiceAttack-settings.png]]
1. Check “enable plugin support”. ![[VoiceAttack-settings-plugin-support.png]]
While you are there, you might also want to enable the automatic update checks
(Note: those settings do not exist in the Steam version).
![[VoiceAttack-settings-updates.png]]
## Install EDDI
Install [the latest release](https://github.com/EDCD/EDDI/releases/latest) from
Github (The `EDDI-X.Y.Z.exe` file under “Assets”). You will need to [install it
as a VoiceAttack
plugin](https://github.com/EDCD/EDDI/wiki/VoiceAttack-Integration#using-eddi-with-voiceattack).
If you do not want to install it into the VoiceAttack installation folder (or
already have it installed somewhere else) you can instead put it elsewhere and
create a symbolic link. Open a command prompt (Windows key + `R`, enter “cmd”,
hit `Enter`) and do
```cmd
>cd x:\path\to\VoiceAttack\Apps
>mklink /J EDDI x:\path\to\EDDI
```
If you have installed the non-Steam version of VoiceAttack to the default folder
within “Program Files” you will have to run the command prompt as admin (Windows
key + `R`, enter “cmd”, hit `Control` + `Shift` + `Enter`).
## Install ED-NeutronRouter
Grab [the latest release release from
Github](https://github.com/sc-pulgan/ED-NeutronRouter/releases/latest) (The
`EDNeutronRouter.vX.YZ.zip` under “Assets”). You will have to extract the
contents of the release .zip file to your VoiceAttack Apps folder:
1. Go into VoiceAttack settings. ![[VoiceAttack-settings.png]]
1. Click the folder set as “Apps Folder”. ![[VoiceAttack-apps.png]]
Now extract the contents of the downloaded file into there. Make sure that they
are not naked files under “Apps”, but have their own folder
“Apps\ED-NeutronRouter”! The exact folder name does not matter as long as they
_are_ in a subfolder. Otherwise the plugin will not load.
![[ED-NeutronRouter-folder.png]]
Leave the “Apps” folder open in Windows Explorer, you will need it for the next step.
## Import Profiles Package
Acquire [the latest
release](https://github.com/alterNERDtive/VoiceAttack-profiles/releases/latest)
from Github (the `alterNERDtive-voiceattack-profiles.vax` file under “Assets”).
Put it into VoiceAttacks “Import” folder:
1. Go into VoiceAttack settings. ![[VoiceAttack-settings.png]]
1. Click the folder set as “Apps Folder”. ![[VoiceAttack-apps.png]]
1. Create a sub folder named “Import” if it does not exist yet.
1. Drop the downloaded .vax file into the “Import” folder.
1. Restart VoiceAttack.
1. When prompted, import the profile package. VoiceAttack will restart when completed.
## Create a Custom Profile
Last but not least you are going to create your own custom VoiceAttack profile
for Elite. It will allow you to add your own commands, override any commands in
the profiles that you want to change and add voice triggers or hotkeys.
You can either use an existing profile, create a new one or use the provided
profile example as a basis. Regardless of which way you choose, make sure to
read the [Include Profiles](#include-profiles) section and follow the instructions there!
### Option 1: Create a New Profile Or Use an Existing One
1. Click the “Profile Actions” button, then “Create New Profile”.
![[VoiceAttack-new-profile.png]]
1. Give it a name and add some commands if you want to.
1. Hit “Done” to create the new profile.
Alternatively you can keep using your existing profile. You will still have to
follow the rest of the instructions in this case.
#### Create a Startup Command
First off, hit the “Edit” button in VoiceAttack.
![[VoiceAttack-edit.png]]
If you are using your existing profile (or have just created a fresh one) you
will now have to create the startup command. Hit the “New Command” button.
![[VoiceAttack-edit-new-command.png]]
You can name it anything you want but I recommend calling it “startup” or
similar, and to deactivate the “when I say” checkbox in the command options to
make sure you do not accidentally run it via voice.
![[VoiceAttack-edit-startup.png]]
Add a new action using “Other” → “VoiceAttack Action”→ “Execute Another Command”.
![[VoiceAttack-edit-startup-execute.png]]
Choose “Execute by name (Advanced)” and enter `((alterNERDtive-base.startup))`.
![[VoiceAttack-edit-startup-action.png]]
Make sure to leave “Wait until this command completes before continuing” on and
have this action at the top of the action list for the command. That way you can
be sure that my profiles are initialized properly before your personal startup
actions are processed.
![[VoiceAttack-edit-startup-actionlist.png]]
You can add anything else you want your profile to do when it loads below this
action. You do not have to set any configuration options, this can be done way
more elegantly! More on this [later on](general.md#settings).
After adding the startup command you will have to right click VoiceAttacks
title bar and choose “Reload Active Profile” or restart VoiceAttack to see it
executed for the first time.
### Option 2: Use the Profile Example
1. Click the “Profile Actions” button, then “Import Profile”.
![[VoiceAttack-import-profile.png]]
1. Navigate to your VoiceAttack Apps folder (see above), go into the
“alterNERDtive” subfolder, choose the profile example and hit “Open”.
![[VoiceAttack-import-profile-open.png]]
Once you are done with the setup and configuration process, you can find a bunch
of example commands with comments on how to do things in this profile. Make sure
to also rename it to something more exciting than “Custom Profile Example”!
## Include Profiles
In order to use my profiles with your custom profile, you will need to take two
additional steps:
1. Include the profiles in your custom profile. That will make all commands
available when your custom profile is active.
1. Create a startup command for your custom profile. You can use it to do
anything you want when your profile loads, but it will also have to run the
startup command for my profiles.
#### Set Profile Options
While editing the profile, hit the “Options” button.
![[VoiceAttack-profile-options.png]]
On the section labeled “Include commands from other profiles”, hit the “…”
button.
![[VoiceAttack-profile-options-include.png]]
Add all my profiles (“alterNERDtive-base”, “EliteAttack”, “RatAttack”,
“SpanshAttack”, “StreamAttack”).
![[VoiceAttack-profile-options-includelist.png]]
Make sure that “alterNERDtive-base” is on top of the list, the order of the
others does not matter. But I like it nice and alphabetical. Technically you can
leave out any profile you are not planning to use. Practically it probably will
not hurt you to just include everything, and it will then be available for you
in the future should you choose to check it out!
Now switch to the “Profile Exec” tab. Tick the “Execute a command each time this
profile is loaded” checkbox, and select the “startup” command you have created
earlier.
![[VoiceAttack-profile-options-startup.png]]
## Reload the Profile
To make sure everything is loaded correctly, you now need to either reload the
profile by right clicking on VoiceAttacks title bar → “Reset Active Profile” or
by simply restarting VoiceAttack.
You should see a bunch of initialization messages pop up in the VoiceAttack log.
## Set Elite Keyboard Binds
You need to have keyboard binds setup at least as secondary bindings in Elites
controls options. VoiceAttack _cannot_ “push” joystick buttons for you, it can
only do keyboard inputs. Hence its only way to interact with Elite is through
keyboard emulation, even if you otherwise play the game with a controller or
HOTAS. Or racing wheel. Or Rock Band set. Or bananas.
![[Elite-binds.png]]
For the “Galaxy Map” section, make sure that the bindings do not conflict with
the ones in the “Interface Mode” section. The map bindings take precedence and a
conflict leads to VoiceAttack being unable to target systems for you. In that
case you would see it open the map for you and then wiggle the view for a split
second instead of switching tabs over to the system search.
![[Elite-binds-galmap.png]]
Should you use a keyboard layout that is _not_ en-US QWERTY, some keys might not
work out of the box. You can try telling bindED about your keyboard layout by
setting the `bindED.layout#` variable (including the `#`!) to something more
appropriate in your startup command.
![[bindED-layout.png]]
Currently bindED supports the `en-US`, `en-GB` and `de-Neo2` layouts. [You can
find instructions on how to add your own
here](https://alternerdtive.github.io/bindED/troubleshooting/#adding-a-keyboard-layout).

69
docs/requirements.md Normal file
View file

@ -0,0 +1,69 @@
# Requirements
## VoiceAttack
Obviously you will need to install [VoiceAttack](https://voiceattack.com). There
is a free trial version available, but that one is limited to a single profile
and a few commands. This is 5 profiles and … a lot of commands. You will need the
full version, available for $10 (official site) or €11.99 (Steam, IIRC $14.99
for our US-based friends).
I recommend buying on the site. Why? Because on Steam, Valve gets a 30% cut.
Unlike many other developers Gary (the developer of VoiceAttack) remedies that
by having a price on Steam that ends up paying $10 to him. So basically, you are
paying Valve out of your own pocket. Many other developers do not do that, and
by buying from them directly instead of on Steam you are literally giving them
extra money. Please do keep that in mind in the future!
You also will generally need to opt into the beta version. I am usually at the
forefront of bug reports and feature requests, and I do rely on the
fixes/additions in beta versions quite often.
## EDDI
[EDDI](https://github.com/EDCD/EDDI) is a companion application for Elite:
Dangerous, providing responses to events that occur in-game using data from the
game as well as various third-party tools. In this case, you will need to run it
as a VoiceAttack plugin.
EDDI also regularly publishes beta versions. Unless a profiles release
explicitly states it you will _not_ have to run EDDI beta.
Do note that the profiles put EDDI into quiet mode by default, disabling the
built-in speech responders. This can be changed
[via the `EDDI quiet mode` setting](configuration/general.md#general-settings-for-all-profiles).
## bindED
[bindED](https://alterNERDtive.github.io/bindED) reads your Elite Dangerous
binding files and makes them available to VoiceAttack as variables. That way
commands can be portable and you do not have to manually go through them and
change any actions that you happen to not have the standard binds for.
This plugin is _included_ in the release package. You do _not_ have to download
and install it manually, but you _can_ independently update it if a newer
version is available.
## Elite Scripts
I have written a [collection of Python
scripts](https://github.com/alterNERDtive/elite-scripts) to interface with
various 3ʳᵈ party services like EDSM or Spansh. Those are called by the profiles
for various tasks, like checking a systems body count.
In the future they will be replaced by VoiceAttack plugin code.
The scripts are _included_ in the release package. You do _not_ have to download
and install them manually, but you _can_ independently update them if a newer
version is available.
## ED-NeutronRouter
[ED-NeutronRouter](https://github.com/sc-pulgan/ED-NeutronRouter) interfaces
with [Spanshs neutron plotter](https://spansh.uk/plotter) and makes the result
available to VoiceAttack.
This plugin is _only_ required if you intend to use the SpanshAttack profile for
neutron routing. Otherwise you do not have to install it.
This will also eventually be replaced by my own plugins.

100
docs/troubleshooting.md Normal file
View file

@ -0,0 +1,100 @@
# Troubleshooting
This will fill up gradually with Troubleshooting tips as people run into common
ones.
## VoiceAttack does not understand me / mishears me / fires random commands
There is [a thread on the VoiceAttack
forums](https://forum.voiceattack.com/smf/index.php?topic=2667.msg12197#msg12197)
on how to set up your microphone and the speech recognition engine to work best.
If your microphone is bad and you still get erroneous recognitions when you are
not speaking it is probably going to recognize the same command every time. You
can remedy that by blocking the voice trigger. One-syllable triggers are
especially prone to misrecognition.
1. Create a new command in your custom profile.
1. Set the “when I say” field to the trigger that gets misrecognized.
Adding the “Other” → “VoiceAttack Action” → “Ignore an Unrecognized Word or
Phrase” action will also hide it from the VoiceAttack log when it is (wrongly)
recognized. You might or might not want that.
Example for the “cruise” voice trigger of the Supercruise command:
![[troubleshooting-remove-trigger.png]]
Alternatively you can raise the minimum confidence level and call the underlying
command to make misfires less likely:
![[troubleshooting-raise-min-confidence.png]]
There are a few examples in the [Custom Profile
Example](../installing#use-the-profile-example).
## VoiceAttack recognizes a command, but doesnt do anything in game
Make sure you have a keyboard bind for whatever the command is supposed to do as
outlined in [[Installing#Set Elite Keyboard Binds]].
## VoiceAttack talks over the COVAS voice
There is no way to know for sure when the ingame COVAS is talking to you, so
there is no way to always prevent the two from speaking over each other.
You can however either disable TTS responses for events that you know will clash
(or [file a feature
request](https://github.com/alterNERDtive/VoiceAttack-profiles/issues/) if one
is not optional yet). Alternatively, if you prefer the info given by VoiceAttack
over the ingame COVAS, you can deactivate its response to these events in the
ingame Audo settings:
![[Elite-COVAS.png]]
While youre in there you might as well get rid of the spoken FSD countdown that
is off by one second …
## This doesnt work (well) with my HCS pack
My profiles are designed from the ground up to work with whatever else you are
doing with VoiceAttack; that is the reason for importing them into your own
custom profile instead of selecting e.g. `EliteAttack` as your active profile.
HCS on the contrary explicitly expects you do exclusively use HCS with
VoiceAttack. There is the rudimentary way of including simple profiles into
theirs, but the mechanism falls flat in many places. For example you cannot tell
HCS to run an included profiles startup command.
So, in order to mostly make stuff work, you need to treat the HCS profile as
your “custom” profile as per this documentation.
1. Include `alterNERDtive-base` and all profiles you want to use into the active
HCS profile.
1. Include a custom profile that has a startup command with a voice trigger of
your choosing, e.g. “load included profiles”.
1. Set up said startup command as you would normally.
1. Every time you start VA or change profiles, you will have to manually say
“load included profiles”.
That will make most things work. Conflicts may arise if HCS happens to have
voice triggers that are the same as mine, in which case their command will take
priority.
**Note on TTS**: EDDIs TTS (used by my profiles) and HCS TTS / recorded voice
lines act 100% independently. That means they will frequently “speak over each
other”. There is no way to alleviate this.
EDDI does have a mechanism to detect if it is currently speaking it sets a
corresponding VoiceAttack variable. HCS neither does anything similar nor checks
if EDDI is speaking to prevent conflicts. Refer to them if you want that
changed.
## This does not work with Geforce Now
Nope. Just wont. Geforce Now obviously has Elites files, journals and keybinds
stored on some random PC in the cloud. Your local VoiceAttack has no way of
accessing those.
If you can get VoiceAttack to run _on Geforce Now_ in parallel to Elite, I dont
see why it wouldnt work.

103
docs/upgrading.md Normal file
View file

@ -0,0 +1,103 @@
# Upgrading
To upgrade to the latest version, follow these simple steps:
1. Say “download profiles update”.
1. Put the `alterNERDtive-voiceattack-profiles.vax` file from Github into
VoiceAttacks “Import” folder.
1. Restart VoiceAttack.
In general, migration from old versions will be handled automatically. If there
is something you have to do manually you will find the necessary steps below.
You can find the full
[Changelog](https://github.com/alterNERDtive/VoiceAttack-profiles/blob/release/CHANGELOG.md)
on Github.
## 3.x.x to 4.x.x
If you have been using a custom profile as outlined in [[Installing#Create a
Custom Profile]] your settings will be migrated to the new variables
automatically.
If you have not and you have used my “EliteDangerous” profile as the main
profile … well, you will unfortunately have to take note of your settings, and
recreate them after creating a custom profile and including everything.
Please do not fiddle with the configuration variables from your startup command
(or any other, really). It _should_ not break anything, but it might. And it is
entirely unnecessary since configuration will be saved to and loaded from the
profile anyway.
### EDDI Events
The process for adding your own handlers for EDDI events has changed. You no
longer have to check which of my profiles handle them and add the commands for
those manually; instead you need to [run the `eddi.event` context of the
`alterNERDtive-base` plugin](../configuration/general#eddi-events).
### bindED
If you have done anything non-standard with bindED before, it might break. The
profiles now include my fork of bindED which has a lot more features, but
does no longer support a bunch of plugin invocations that have become obsolete.
Please [file an issue with
bindED](https://github.com/alterNERDtive/bindED/issues/new/choose) on Github if
your use case does not work anymore.
### EliteDangerous
The “EliteDangerous” profile is no longer the main profile. Instead you will
_have_ to create a custom profile, and the new “base” profile that the others
require to be included in your custom profile is “alterNERDtive-base”. That way
you can use e.g. RatAttack without having to also use the general Elite profile.
To be consistent with the other profiles it has been renamed to “EliteAttack”.
If you are upgrading from an older version the name will not change for you in
the profiles list. I recommend renaming your “EliteDangerous” profile to
“EliteAttack” to prevent confusion in the future, but it is not strictly
necessary to do so.
### RatAttack
#### Getting Case Data From IRC
Handing a RATSIGNAL from IRC to VoiceAttack via text file is now deprecated and
the feature will be removed in a future version.
Instead you should use the new `RatAttack-cli.exe` helper tool that uses IPC to
talk to the VoiceAttack plugin. For that you have to change the way your IRC
client handles incoming case announcements. Instead of writing the announcement
to the text file and calling VoiceAttack to run a command, it will have to call
the helper tool with a) the announcement and b) an optional true/false switch to
determine if the case should be announced via TTS or just added to the case
list.
For my AdiIRC, it looks like this (obviously change the path, please):
```adiirc
on *:TEXT:*RATSIGNAL*(??_SIGNAL):#fuelrats:{
if ( $away ) {
/run -h "X:\path\to\VoiceAttack\Apps\alterNERDtive\RatAttack-cli.exe" " $+ $replace($1-,","") $+ " false
}
else {
/run -h "X:\path\to\VoiceAttack\Apps\alterNERDtive\RatAttack-cli.exe" " $+ $replace($1-,","") $+ " true
}
}
```
If I am away it will just add the new case to the list. If I am not away, it
will announce it using TTS.
The `$replace` part handles the fact that case announcements now put the system
in quotes. They have to be escaped as double quotes (`""`) to create a correct
command line invocation.
#### Nearest CMDR Announcements
If you have RatAttack set up to announce your nearest commander to a case,
youll have to change the setting to the new format, separated by `;` instead of
whitespace.
Say “customize setting set fuel rat commanders” to update it.

50
mkdocs.yml Normal file
View file

@ -0,0 +1,50 @@
site_name: "alterNERDtive VA profiles"
site_url: https://alterNERDtive.github.io/VoiceAttack-profiles
repo_url: https://github.com/alterNERDtive/VoiceAttack-profiles
edit_uri: "edit/devel/docs/"
site_description: "alterNERDtive VoiceAttack profiles for Elite: Dangerous"
site_author: "alterNERDtive"
remote_name: "origin"
theme:
name: readthedocs
prev_next_buttons_location: both
plugins:
- search
- roamlinks
# - mkpdfs:
# author: 'alterNERDtive'
# output_path: 'pdf/Profiles Documentation.pdf'
markdown_extensions:
- toc:
permalink: True
- sane_lists
nav:
- 'Home': 'index.md'
- 'Install':
- 'requirements.md'
- 'installing.md'
- 'upgrading.md'
- 'Configure':
- 'configuration/general.md'
- 'configuration/EliteAttack.md'
- 'configuration/RatAttack.md'
- 'configuration/SpanshAttack.md'
- 'configuration/StreamAttack.md'
- 'Use':
- 'general.md'
- 'EliteAttack.md'
- 'RatAttack.md'
- 'SpanshAttack.md'
- 'StreamAttack.md'
- 'Issues':
#- 'VoiceAttack Tips': 'VoiceAttack.md'
- 'troubleshooting.md'
- '⎋ Changelog': 'https://github.com/alterNERDtive/VoiceAttack-profiles/blob/release/CHANGELOG.md'
- '⎋ Report a Bug': 'https://github.com/alterNERDtive/VoiceAttack-profiles/issues/'
- 'Watch in Action':
- '⎋ Twitch': 'https://twitch.tv/alterNERDtive'
- '⎋ Youtube': 'https://www.youtube.com/channel/UC3XNZA7xWed1zM1AWOOdmog'

103
plugins.sln Normal file
View file

@ -0,0 +1,103 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.3.32519.111
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VoiceAttack-base", "plugins\VoiceAttack-base\VoiceAttack-base.csproj", "{1C05DB3F-3449-4664-B363-A379892995E5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RatAttack", "plugins\RatAttack\RatAttack.csproj", "{64CD3BA3-7FD2-4360-B055-6927CE92DA68}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RatAttack-cli", "plugins\RatAttack-cli\RatAttack-cli.csproj", "{D72A35EC-8D39-4B96-BBC5-1B330F4CBEEF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EliteAttack", "plugins\EliteAttack\EliteAttack.csproj", "{77CEF35C-C25C-4793-AB2C-0B0C5D9A5BB8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpanshAttack", "plugins\SpanshAttack\SpanshAttack.csproj", "{D2047704-696B-4665-8D37-3AD298A8B9F9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C2B4D94B-8D73-431A-880B-B1E7ADF064B2}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
CHANGELOG.md = CHANGELOG.md
.github\workflows\create-release.yaml = .github\workflows\create-release.yaml
Directory.build.props = Directory.build.props
mkdocs.yml = mkdocs.yml
README.md = README.md
stylecop.json = stylecop.json
VERSION = VERSION
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{5401ADF7-CB6D-448B-A4AC-D8A17B2D841F}"
ProjectSection(SolutionItems) = preProject
docs\EliteAttack.md = docs\EliteAttack.md
docs\general.md = docs\general.md
docs\index.md = docs\index.md
docs\installing.md = docs\installing.md
docs\RatAttack.md = docs\RatAttack.md
docs\requirements.md = docs\requirements.md
docs\SpanshAttack.md = docs\SpanshAttack.md
docs\StreamAttack.md = docs\StreamAttack.md
docs\troubleshooting.md = docs\troubleshooting.md
docs\upgrading.md = docs\upgrading.md
docs\VoiceAttack.md = docs\VoiceAttack.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "configuration", "configuration", "{1AFD9AE6-7D22-4EF4-B0DE-51C9E91370FB}"
ProjectSection(SolutionItems) = preProject
docs\configuration\EliteAttack.md = docs\configuration\EliteAttack.md
docs\configuration\general.md = docs\configuration\general.md
docs\configuration\RatAttack.md = docs\configuration\RatAttack.md
docs\configuration\SpanshAttack.md = docs\configuration\SpanshAttack.md
docs\configuration\StreamAttack.md = docs\configuration\StreamAttack.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{A68BA76B-47FA-4D25-805E-66EBDD8C5223}"
ProjectSection(SolutionItems) = preProject
.github\dependabot.yaml = .github\dependabot.yaml
.github\FUNDING.yml = .github\FUNDING.yml
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{0147AF7E-BB7F-4D5F-96EC-8734393DFF56}"
ProjectSection(SolutionItems) = preProject
.github\workflows\create-release.yaml = .github\workflows\create-release.yaml
.github\workflows\gh-pages.yaml = .github\workflows\gh-pages.yaml
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1C05DB3F-3449-4664-B363-A379892995E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1C05DB3F-3449-4664-B363-A379892995E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1C05DB3F-3449-4664-B363-A379892995E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1C05DB3F-3449-4664-B363-A379892995E5}.Release|Any CPU.Build.0 = Release|Any CPU
{64CD3BA3-7FD2-4360-B055-6927CE92DA68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{64CD3BA3-7FD2-4360-B055-6927CE92DA68}.Debug|Any CPU.Build.0 = Debug|Any CPU
{64CD3BA3-7FD2-4360-B055-6927CE92DA68}.Release|Any CPU.ActiveCfg = Release|Any CPU
{64CD3BA3-7FD2-4360-B055-6927CE92DA68}.Release|Any CPU.Build.0 = Release|Any CPU
{D72A35EC-8D39-4B96-BBC5-1B330F4CBEEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D72A35EC-8D39-4B96-BBC5-1B330F4CBEEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D72A35EC-8D39-4B96-BBC5-1B330F4CBEEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D72A35EC-8D39-4B96-BBC5-1B330F4CBEEF}.Release|Any CPU.Build.0 = Release|Any CPU
{77CEF35C-C25C-4793-AB2C-0B0C5D9A5BB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{77CEF35C-C25C-4793-AB2C-0B0C5D9A5BB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{77CEF35C-C25C-4793-AB2C-0B0C5D9A5BB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{77CEF35C-C25C-4793-AB2C-0B0C5D9A5BB8}.Release|Any CPU.Build.0 = Release|Any CPU
{D2047704-696B-4665-8D37-3AD298A8B9F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D2047704-696B-4665-8D37-3AD298A8B9F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D2047704-696B-4665-8D37-3AD298A8B9F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D2047704-696B-4665-8D37-3AD298A8B9F9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{5401ADF7-CB6D-448B-A4AC-D8A17B2D841F} = {C2B4D94B-8D73-431A-880B-B1E7ADF064B2}
{1AFD9AE6-7D22-4EF4-B0DE-51C9E91370FB} = {5401ADF7-CB6D-448B-A4AC-D8A17B2D841F}
{A68BA76B-47FA-4D25-805E-66EBDD8C5223} = {C2B4D94B-8D73-431A-880B-B1E7ADF064B2}
{0147AF7E-BB7F-4D5F-96EC-8734393DFF56} = {A68BA76B-47FA-4D25-805E-66EBDD8C5223}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {339E6747-C7BF-43C3-99C6-9249C9849A84}
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,175 @@
// <copyright file="EliteAttack.cs" company="alterNERDtive">
// Copyright 20192022 alterNERDtive.
//
// This file is part of alterNERDtive VoiceAttack profiles for Elite Dangerous.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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 alterNERDtive VoiceAttack profiles for Elite Dangerous. If not, see &lt;https://www.gnu.org/licenses/&gt;.
// </copyright>
#nullable enable
using System;
using alterNERDtive.util;
namespace EliteAttack
{
/// <summary>
/// VoiceAttack plugin for the EliteAttack profile.
/// </summary>
public class EliteAttack
{
private static readonly Version VERSION = new ("8.5");
private static VoiceAttackLog? log;
private static VoiceAttackCommands? commands;
private static dynamic? VA { get; set; }
private static VoiceAttackLog Log => log ??= new (VA, "EliteAttack");
private static VoiceAttackCommands Commands => commands ??= new (VA, Log);
/*========================================\
| required VoiceAttack plugin shenanigans |
\========================================*/
/// <summary>
/// The plugins GUID, as required by the VoiceAttack plugin API.
/// </summary>
/// <returns>The GUID.</returns>
public static Guid VA_Id()
=> new ("{5B46321D-2935-4550-BEEA-36C2145547B8}");
/// <summary>
/// The plugins display name, as required by the VoiceAttack plugin API.
/// </summary>
/// <returns>The display name.</returns>
public static string VA_DisplayName()
=> $"EliteAttack {VERSION}";
/// <summary>
/// The plugins description, as required by the VoiceAttack plugin API.
/// </summary>
/// <returns>The description.</returns>
public static string VA_DisplayInfo()
=> "EliteAttack: a plugin for doing Elite-y things.";
/// <summary>
/// The Init method, as required by the VoiceAttack plugin API.
/// Runs when the plugin is initially loaded.
/// </summary>
/// <param name="vaProxy">The VoiceAttack proxy object.</param>
public static void VA_Init1(dynamic vaProxy)
{
VA = vaProxy;
Log.Notice("Initializing …");
VA.SetText("EliteAttack.version", VERSION.ToString());
Log.Notice("Init successful.");
}
/// <summary>
/// The Invoke method, as required by the VoiceAttack plugin API.
/// Runs whenever a plugin context is invoked.
/// </summary>
/// <param name="vaProxy">The VoiceAttack proxy object.</param>
public static void VA_Invoke1(dynamic vaProxy)
{
string context = vaProxy.Context.ToLower();
Log.Debug($"Running context '{context}' …");
try
{
switch (context)
{
case "startup":
Context_Startup(vaProxy);
break;
case "log.log":
// log
Context_Log(vaProxy);
break;
default:
// invalid
Log.Error($"Invalid plugin context '{vaProxy.Context}'.");
break;
}
}
catch (ArgumentNullException e)
{
Log.Error($"Missing parameter '{e.ParamName}' for context '{context}'");
}
catch (Exception e)
{
Log.Error($"Unhandled exception while executing plugin context '{context}'. ({e.Message})");
}
}
/// <summary>
/// The Exit method, as required by the VoiceAttack plugin API.
/// Runs when VoiceAttack is shut down.
/// </summary>
/// <param name="vaProxy">The VoiceAttack proxy object.</param>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "required by VoiceAttack plugin API")]
public static void VA_Exit1(dynamic vaProxy)
{
}
/// <summary>
/// The StopCommand method, as required by the VoiceAttack plugin API.
/// Runs whenever all commands are stopped using the “Stop All Commands”
/// button or action.
/// </summary>
public static void VA_StopCommand()
{
}
/*================\
| plugin contexts |
\================*/
#pragma warning disable IDE0060 // Remove unused parameter
private static void Context_Log(dynamic vaProxy)
{
string message = vaProxy.GetText("~message");
string level = vaProxy.GetText("~level");
if (level == null)
{
Log.Log(message);
}
else
{
try
{
Log.Log(message, (LogLevel)Enum.Parse(typeof(LogLevel), level.ToUpper()));
}
catch (ArgumentNullException)
{
throw;
}
catch (ArgumentException)
{
Log.Error($"Invalid log level '{level}'.");
}
}
}
private static void Context_Startup(dynamic vaProxy)
{
Log.Notice("Starting up …");
Log.Notice("Finished startup.");
}
#pragma warning restore IDE0060 // Remove unused parameter
}
}

View file

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{77CEF35C-C25C-4793-AB2C-0B0C5D9A5BB8}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>EliteAttack</RootNamespace>
<AssemblyName>EliteAttack</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\build\alterNERDtive\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>..\build\alterNERDtive\EliteAttack.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\build\alterNERDtive\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>..\build\alterNERDtive\EliteAttack.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="EliteAttack.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VoiceAttack-base\VoiceAttack-base.csproj">
<Project>{1c05db3f-3449-4664-b363-a379892995e5}</Project>
<Name>VoiceAttack-base</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View file

@ -0,0 +1,55 @@
// <copyright file="AssemblyInfo.cs" company="alterNERDtive">
// Copyright 20192022 alterNERDtive.
//
// This file is part of alterNERDtive VoiceAttack profiles for Elite Dangerous.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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 alterNERDtive VoiceAttack profiles for Elite Dangerous. If not, see &lt;https://www.gnu.org/licenses/&gt;.
// </copyright>
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("EliteAttack")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("EliteAttack")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("77cef35c-c25c-4793-ab2c-0b0c5d9a5bb8")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View file

@ -0,0 +1,55 @@
// <copyright file="AssemblyInfo.cs" company="alterNERDtive">
// Copyright 20192022 alterNERDtive.
//
// This file is part of alterNERDtive VoiceAttack profiles for Elite Dangerous.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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 alterNERDtive VoiceAttack profiles for Elite Dangerous. If not, see &lt;https://www.gnu.org/licenses/&gt;.
// </copyright>
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("RatAttack-cli")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("RatAttack-cli")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("d72a35ec-8d39-4b96-bbc5-1b330f4cbeef")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View file

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{D72A35EC-8D39-4B96-BBC5-1B330F4CBEEF}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>RatAttack_cli</RootNamespace>
<AssemblyName>RatAttack-cli</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\build\alterNERDtive\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>..\build\alterNERDtive\RatAttack-cli.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\build\alterNERDtive\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>..\build\alterNERDtive\RatAttack-cli.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Numerics" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Serialization" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RatAttack_cli.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\RatAttack\RatAttack.csproj">
<Project>{64cd3ba3-7fd2-4360-b055-6927ce92da68}</Project>
<Name>RatAttack</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View file

@ -0,0 +1,68 @@
// <copyright file="RatAttack_cli.cs" company="alterNERDtive">
// Copyright 20192022 alterNERDtive.
//
// This file is part of alterNERDtive VoiceAttack profiles for Elite Dangerous.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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 alterNERDtive VoiceAttack profiles for Elite Dangerous. If not, see &lt;https://www.gnu.org/licenses/&gt;.
// </copyright>
#nullable enable
using System;
using System.IO;
using System.IO.Pipes;
using System.Text.RegularExpressions;
namespace RatAttack
{
/// <summary>
/// CLI helper tool for the RatAttack VoiceAttack plugin. Accepts RATSIGNALs
/// e.g. from an IRC client and passes them to the plugin via named pipe.
/// </summary>
public class RatAttack_cli
{
/// <summary>
/// Main entry point.
/// </summary>
/// <param name="args">The command line arguments.</param>
public static void Main(string[] args)
{
RatAttack.Ratsignal ratsignal = new (StripIrcCodes(args[0]), args.Length > 1 && args[1].ToLower() == "true");
using (NamedPipeClientStream pipeClient = new (".", "RatAttack", PipeDirection.Out))
{
try
{
// try connecting for up to 2minutes; then well assume VoiceAttack just isnt up and wont come up
pipeClient.Connect(120000);
using StreamWriter writer = new (pipeClient);
writer.WriteLine(ratsignal);
}
catch (TimeoutException)
{
Console.Error.WriteLine("Connection to RatAttack pipe has timed out.");
}
catch (UnauthorizedAccessException)
{
Console.Error.WriteLine("Cannot connect to RatAttack pipe. Are you running VoiceAttack as Admin?");
}
}
}
private static string StripIrcCodes(string message)
{
return Regex.Replace(message, @"[\x02\x11\x0F\x1D\x1E\x1F\x16]|\x03(\d\d?(,\d\d?)?)?", string.Empty);
}
}
}

View file

@ -0,0 +1,55 @@
// <copyright file="AssemblyInfo.cs" company="alterNERDtive">
// Copyright 20192022 alterNERDtive.
//
// This file is part of alterNERDtive VoiceAttack profiles for Elite Dangerous.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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 alterNERDtive VoiceAttack profiles for Elite Dangerous. If not, see &lt;https://www.gnu.org/licenses/&gt;.
// </copyright>
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("VoiceAttack-plugins")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("VoiceAttack-plugins")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("64cd3ba3-7fd2-4360-b055-6927ce92da68")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View file

@ -0,0 +1,445 @@
// <copyright file="RatAttack.cs" company="alterNERDtive">
// Copyright 20192022 alterNERDtive.
//
// This file is part of alterNERDtive VoiceAttack profiles for Elite Dangerous.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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 alterNERDtive VoiceAttack profiles for Elite Dangerous. If not, see &lt;https://www.gnu.org/licenses/&gt;.
// </copyright>
#nullable enable
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Text.RegularExpressions;
using alterNERDtive.util;
namespace RatAttack
{
/// <summary>
/// VoiceAttack plugin for the RatAttack profile.
/// </summary>
public class RatAttack
{
private static readonly Version VERSION = new ("6.4");
private static readonly Regex RatsignalRegex = new (
@"^RATSIGNAL Case #(?<number>\d+) (?<platform>(PC|Xbox|Playstation))( )?(?<mode>H3.8|H4.0|ODY)?(?<oxygen> \(Code Red\))? CMDR (?<cmdr>.+) System: (None|u\u200bnknown system|""(?<system>.+)"" \((?<systemInfo>([a-zA-Z0-9\s\(\)\-/]*(~?[0-9,\.]+ LY (""[a-zA-Z\-]+"" of|from) [a-zA-Z0-9\s\*\-]+)?( \([a-zA-Z\s]+\))?|Not found in galaxy database|Invalid system name))\)(?<permit> \(((?<permitName>.*) )?Permit Required\))?) Language: (?<language>[a-zA-z0-9\x7f-\xff\-\(\)&,\s\.]+)( Nick: (?<nick>[a-zA-Z0-9_\[\]\-\^]+))? \((H3|H4|ODY|XB|PS)_SIGNAL\)\v*$");
private static PipeServer<Ratsignal>? ratsignalPipe;
private static VoiceAttackLog? log;
private static VoiceAttackCommands? commands;
private static ConcurrentDictionary<int, RatCase> CaseList { get; } = new ();
private static dynamic? VA { get; set; }
private static PipeServer<Ratsignal> RatsignalPipe
=> ratsignalPipe ??= new (
Log,
"RatAttack",
new PipeServer<Ratsignal>.SignalHandler(On_Ratsignal));
private static VoiceAttackLog Log => log ??= new (VA, "RatAttack");
private static VoiceAttackCommands Commands => commands ??= new (VA, Log);
/*========================================\
| required VoiceAttack plugin shenanigans |
\========================================*/
/// <summary>
/// The plugins GUID, as required by the VoiceAttack plugin API.
/// </summary>
/// <returns>The GUID.</returns>
public static Guid VA_Id()
=> new ("{F2ADF0AE-4837-4E4A-9C87-8A7E2FA63E5F}");
/// <summary>
/// The plugins display name, as required by the VoiceAttack plugin API.
/// </summary>
/// <returns>The display name.</returns>
public static string VA_DisplayName()
=> $"RatAttack {VERSION}";
/// <summary>
/// The plugins description, as required by the VoiceAttack plugin API.
/// </summary>
/// <returns>The description.</returns>
public static string VA_DisplayInfo()
=> "RatAttack: a plugin to handle FuelRats cases.";
/// <summary>
/// The Init method, as required by the VoiceAttack plugin API.
/// Runs when the plugin is initially loaded.
/// </summary>
/// <param name="vaProxy">The VoiceAttack proxy object.</param>
public static void VA_Init1(dynamic vaProxy)
{
VA = vaProxy;
Log.Notice("Initializing …");
VA.SetText("RatAttack.version", VERSION.ToString());
vaProxy.ProfileChanged += new Action<Guid?, Guid?, string, string>(On_ProfileChanged);
Log.Notice("Init successful.");
}
/// <summary>
/// The Invoke method, as required by the VoiceAttack plugin API.
/// Runs whenever a plugin context is invoked.
/// </summary>
/// <param name="vaProxy">The VoiceAttack proxy object.</param>
public static void VA_Invoke1(dynamic vaProxy)
{
string context = vaProxy.Context.ToLower();
Log.Debug($"Running context '{context}' …");
try
{
switch (context)
{
case "getcasedata":
// plugin methods
Context_GetCaseData(vaProxy);
break;
case "parseratsignal":
Context_ParseRatsignal(vaProxy);
break;
case "startup":
Context_Startup(vaProxy);
break;
case "edsm.getnearestcmdr":
// EDSM
Context_EDSM_GetNearestCMDR(vaProxy);
break;
case "log.log":
// log
Context_Log(vaProxy);
break;
default:
// invalid
Log.Error($"Invalid plugin context '{vaProxy.Context}'.");
break;
}
}
catch (ArgumentNullException e)
{
Log.Error($"Missing parameter '{e.ParamName}' for context '{context}'");
}
catch (Exception e)
{
Log.Error($"Unhandled exception while executing plugin context '{context}'. ({e.Message})");
}
}
/// <summary>
/// The Exit method, as required by the VoiceAttack plugin API.
/// Runs when VoiceAttack is shut down.
/// </summary>
/// <param name="vaProxy">The VoiceAttack proxy object.</param>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "required by VoiceAttack plugin API")]
public static void VA_Exit1(dynamic vaProxy)
{
Log.Debug("Starting teardown …");
Log.Debug("Closing RATSIGNAL pipe …");
RatsignalPipe.Stop();
Log.Debug("Teardown finished.");
}
/// <summary>
/// The StopCommand method, as required by the VoiceAttack plugin API.
/// Runs whenever all commands are stopped using the “Stop All Commands”
/// button or action.
/// </summary>
public static void VA_StopCommand()
{
}
/// <summary>
/// Parses a RATSIGNAL and extracts case data for storage.
/// </summary>
/// <param name="ratsignal">The incoming RATSIGNAL.</param>
/// <returns>The case number.</returns>
/// <exception cref="ArgumentException">Thrown on invalid RATSIGNAL.</exception>
private static int ParseRatsignal(string ratsignal)
{
if (!RatsignalRegex.IsMatch(ratsignal))
{
throw new ArgumentException($"Invalid RATSIGNAL format: '{ratsignal}'.", "ratsignal");
}
Match match = RatsignalRegex.Match(ratsignal);
string cmdr = match.Groups["cmdr"].Value;
string? language = match.Groups["language"].Value;
string? system = match.Groups["system"].Value;
string? systemInfo = match.Groups["systemInfo"].Value;
bool permitLocked = match.Groups["permit"].Success;
string? permitName = match.Groups["permitName"].Value;
string platform = match.Groups["platform"].Value;
bool codeRed = match.Groups["oxygen"].Success;
string? mode = match.Groups["mode"].Value;
int number = int.Parse(match.Groups["number"].Value);
if (string.IsNullOrEmpty(system))
{
system = "None";
}
Log.Debug($"New rat case: CMDR “{cmdr}” in “{system}”{(!string.IsNullOrEmpty(systemInfo) ? $" ({systemInfo})" : string.Empty)} on {platform}{(!string.IsNullOrEmpty(mode) ? $" ({mode})" : string.Empty)}, permit locked: {permitLocked}{(permitLocked && !string.IsNullOrEmpty(permitName) ? $" (permit name: {permitName})" : string.Empty)}, code red: {codeRed} (#{number}).");
CaseList[number] = new RatCase(cmdr, language, system, systemInfo, permitLocked, permitName, platform, mode, codeRed, number);
return number;
}
private static void On_Ratsignal(Ratsignal ratsignal)
{
try
{
int number = ParseRatsignal(ratsignal.Signal);
Log.Notice($"New rat case: {CaseList[number]}.");
Commands.TriggerEvent("RatAttack.incomingCase", parameters: new dynamic[] { new int[] { number }, new bool[] { ratsignal.Announce } });
}
catch (ArgumentException e)
{
Log.Error(e.Message);
Commands.TriggerEvent("RatAttack.invalidRatsignal", parameters: new dynamic[] { new string[] { ratsignal.Signal } });
}
catch (Exception e)
{
Log.Error($"Unhandled exception while parsing RATSIGNAL: '{e.Message}'.");
}
}
private static void On_ProfileChanged(Guid? from, Guid? to, string fromName, string toName)
=> VA_Exit1(VA);
/*================\
| plugin contexts |
\================*/
#pragma warning disable IDE0060 // Remove unused parameter
private static void Context_EDSM_GetNearestCMDR(dynamic vaProxy)
{
int caseNo = vaProxy.GetInt("~caseNo") ?? throw new ArgumentNullException("~caseNo");
string cmdrList = vaProxy.GetText("~cmdrs") ?? throw new ArgumentNullException("~cmdrs");
string[] cmdrs = cmdrList.Split(';');
if (cmdrs.Length == 0)
{
throw new ArgumentNullException("~cmdrs");
}
string system = CaseList[caseNo]?.System ?? throw new ArgumentException($"Case #{caseNo} has no system information", "~caseNo");
string path = $@"{vaProxy.SessionState["VA_SOUNDS"]}\Scripts\edsm-getnearest.exe";
string arguments = $@"--short --text --system ""{system}"" ""{string.Join(@""" """, cmdrs)}""";
Process p = PythonProxy.SetupPythonScript(path, arguments);
p.Start();
string stdout = p.StandardOutput.ReadToEnd();
string stderr = p.StandardError.ReadToEnd();
p.WaitForExit();
string message = stdout;
string? errorMessage = null;
bool error;
switch (p.ExitCode)
{
case 0:
error = false;
Log.Info(message);
break;
case 1: // CMDR not found, Server Error, Api Exception (jeez, what a mess did I make there?)
error = true;
Log.Error(message);
break;
case 2: // System not found
error = true;
Log.Warn(message);
break;
default:
error = true;
Log.Error(stderr);
errorMessage = "Unrecoverable error in plugin.";
break;
}
vaProxy.SetText("~message", message);
vaProxy.SetBoolean("~error", error);
vaProxy.SetText("~errorMessage", errorMessage);
vaProxy.SetInt("~exitCode", p.ExitCode);
}
private static void Context_GetCaseData(dynamic vaProxy)
{
int cn = vaProxy.GetInt("~caseNumber");
if (CaseList.ContainsKey(cn))
{
RatCase rc = CaseList[cn];
vaProxy.SetInt("~~caseNumber", rc.Number);
vaProxy.SetText("~~cmdr", rc.Cmdr);
vaProxy.SetText("~~system", rc?.System?.ToLower());
vaProxy.SetText("~~systemInfo", rc?.SystemInfo);
vaProxy.SetBoolean("~~permitLocked", rc?.PermitLocked);
vaProxy.SetText("~~permitName", rc?.PermitName);
vaProxy.SetText("~~platform", rc?.Platform);
vaProxy.SetText("~~mode", rc?.Mode);
vaProxy.SetBoolean("~~codeRed", rc?.CodeRed);
}
else
{
Log.Warn($"Case #{cn} not found in the case list");
}
}
private static void Context_Log(dynamic vaProxy)
{
string message = vaProxy.GetText("~message");
string level = vaProxy.GetText("~level");
if (level == null)
{
Log.Log(message);
}
else
{
try
{
Log.Log(message, (LogLevel)Enum.Parse(typeof(LogLevel), level.ToUpper()));
}
catch (ArgumentNullException)
{
throw;
}
catch (ArgumentException)
{
Log.Error($"Invalid log level '{level}'.");
}
}
}
private static void Context_Startup(dynamic vaProxy)
{
Log.Notice("Starting up …");
_ = RatsignalPipe.Run();
Log.Notice("Finished startup.");
}
private static void Context_ParseRatsignal(dynamic vaProxy)
{
Log.Warn("Passing a RATSIGNAL to VoiceAttack through the clipboard or a file is DEPRECATED and will no longer be supported in the future.");
On_Ratsignal(new Ratsignal(vaProxy.GetText("~ratsignal"), vaProxy.GetBoolean("~announceRatsignal") ?? false));
}
#pragma warning restore IDE0060 // Remove unused parameter
/// <summary>
/// Encapsulates a RATSIGNAL for sending between the CLI helper tool and
/// the plugin via named pipe.
/// </summary>
public class Ratsignal : IPipable
{
private readonly char separator = '\x1F';
/// <summary>
/// Initializes a new instance of the <see cref="Ratsignal"/> class.
/// </summary>
public Ratsignal()
=> (this.Signal, this.Announce) = (string.Empty, false);
/// <summary>
/// Initializes a new instance of the <see cref="Ratsignal"/> class.
/// </summary>
/// <param name="signal">The RATSIGNAL.</param>
/// <param name="announce">Whether or not to announce the new case.</param>
public Ratsignal(string signal, bool announce)
=> (this.Signal, this.Announce) = (signal, announce);
/// <summary>
/// Gets or sets the RATSIGNAL.
/// </summary>
public string Signal { get; set; }
/// <summary>
/// Gets or Sets a value indicating whether to announce the incoming
/// case.
/// </summary>
public bool Announce { get; set; }
/// <summary>
/// Initializes the <see cref="Ratsignal"/> instance from a
/// serialized representation.
/// FIXXME: should probably make this a static factory method.
/// </summary>
/// <param name="serialization">The serialized <see cref="Ratsignal"/>.</param>
/// <exception cref="ArgumentException">Thrown on receiving an invalid signal.</exception>
public void ParseString(string serialization)
{
try
{
string[] parts = serialization.Split(this.separator);
this.Signal = parts[0];
this.Announce = bool.Parse(parts[1]);
}
catch (Exception e)
{
throw new ArgumentException($"Invalid serialized RATSIGNAL: '{serialization}'", e);
}
}
/// <inheritdoc/>
public override string ToString()
=> $"{this.Signal}{this.separator}{this.Announce}";
}
private class RatCase
{
public RatCase(string cmdr, string? language, string? system, string? systemInfo, bool permitLocked, string? permitName, string platform, string mode, bool codeRed, int number)
=> (this.Cmdr, this.Language, this.System, this.SystemInfo, this.PermitLocked, this.PermitName, this.Platform, this.Mode, this.CodeRed, this.Number)
= (cmdr, language, system, systemInfo, permitLocked, permitName, platform, mode, codeRed, number);
public string Cmdr { get; }
public string? Language { get; }
public string? System { get; }
public string? SystemInfo { get; }
public bool PermitLocked { get; }
public string? PermitName { get; }
public string Platform { get; }
public string? Mode { get; }
public bool CodeRed { get; }
public int Number { get; }
public string ShortInfo
{
get => $"#{this.Number}, {this.Platform}{(!string.IsNullOrEmpty(this.Mode) ? $" ({this.Mode})" : string.Empty)}{(this.CodeRed ? ", code red" : string.Empty)}, {this.System ?? "None"}{(!string.IsNullOrEmpty(this.SystemInfo) ? $" ({this.SystemInfo}{(this.PermitLocked ? ", permit required" : string.Empty)})" : string.Empty)}";
}
public override string ToString()
=> this.ShortInfo;
}
}
}

View file

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{64CD3BA3-7FD2-4360-B055-6927CE92DA68}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>RatAttack</RootNamespace>
<AssemblyName>RatAttack</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\build\alterNERDtive\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>..\build\alterNERDtive\RatAttack.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\build\alterNERDtive\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>..\build\alterNERDtive\RatAttack.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Numerics" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Serialization" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RatAttack.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VoiceAttack-base\VoiceAttack-base.csproj">
<Project>{1c05db3f-3449-4664-b363-a379892995e5}</Project>
<Name>VoiceAttack-base</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View file

@ -0,0 +1,55 @@
// <copyright file="AssemblyInfo.cs" company="alterNERDtive">
// Copyright 20192022 alterNERDtive.
//
// This file is part of alterNERDtive VoiceAttack profiles for Elite Dangerous.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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 alterNERDtive VoiceAttack profiles for Elite Dangerous. If not, see &lt;https://www.gnu.org/licenses/&gt;.
// </copyright>
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("SpanshAttack")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SpanshAttack")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("d2047704-696b-4665-8d37-3ad298a8b9f9")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View file

@ -0,0 +1,336 @@
// <copyright file="SpanshAttack.cs" company="alterNERDtive">
// Copyright 20192022 alterNERDtive.
//
// This file is part of alterNERDtive VoiceAttack profiles for Elite Dangerous.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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 alterNERDtive VoiceAttack profiles for Elite Dangerous. If not, see &lt;https://www.gnu.org/licenses/&gt;.
// </copyright>
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics;
using alterNERDtive.edts;
using alterNERDtive.util;
namespace SpanshAttack
{
/// <summary>
/// VoiceAttack plugin for the SpanshAttack profile.
/// </summary>
public class SpanshAttack
{
private static readonly Version VERSION = new ("7.2.2");
private static VoiceAttackLog? log;
private static VoiceAttackCommands? commands;
private static dynamic? VA { get; set; }
private static VoiceAttackLog Log => log ??= new (VA, "SpanshAttack");
private static VoiceAttackCommands Commands => commands ??= new (VA, Log);
/*========================================\
| required VoiceAttack plugin shenanigans |
\========================================*/
/// <summary>
/// The plugins GUID, as required by the VoiceAttack plugin API.
/// </summary>
/// <returns>The GUID.</returns>
public static Guid VA_Id()
=> new ("{e722b29d-898e-47dd-a843-a409c87e0bd8}");
/// <summary>
/// The plugins display name, as required by the VoiceAttack plugin API.
/// </summary>
/// <returns>The display name.</returns>
public static string VA_DisplayName()
=> $"SpanshAttack {VERSION}";
/// <summary>
/// The plugins description, as required by the VoiceAttack plugin API.
/// </summary>
/// <returns>The description.</returns>
public static string VA_DisplayInfo()
=> "SpanshAttack: a plugin for doing routing with spansh.co.uk for Elite: Dangerous.";
/// <summary>
/// The Init method, as required by the VoiceAttack plugin API.
/// Runs when the plugin is initially loaded.
/// </summary>
/// <param name="vaProxy">The VoiceAttack proxy object.</param>
public static void VA_Init1(dynamic vaProxy)
{
VA = vaProxy;
Log.Notice("Initializing …");
VA.SetText("SpanshAttack.version", VERSION.ToString());
Log.Notice("Init successful.");
}
/// <summary>
/// The Invoke method, as required by the VoiceAttack plugin API.
/// Runs whenever a plugin context is invoked.
/// </summary>
/// <param name="vaProxy">The VoiceAttack proxy object.</param>
public static void VA_Invoke1(dynamic vaProxy)
{
string context = vaProxy.Context.ToLower();
Log.Debug($"Running context '{context}' …");
try
{
switch (context)
{
case "startup":
Context_Startup(vaProxy);
break;
case "edts.getcoordinates":
// EDTS
Context_EDTS_GetCoordinates(vaProxy);
break;
case "log.log":
// log
Context_Log(vaProxy);
break;
case "spansh.systemexists":
// Spansh
Context_Spansh_SytemExists(vaProxy);
break;
case "spansh.nearestsystem":
Context_Spansh_Nearestsystem(vaProxy);
break;
default:
// invalid
Log.Error($"Invalid plugin context '{vaProxy.Context}'.");
break;
}
}
catch (ArgumentNullException e)
{
Log.Error($"Missing parameter '{e.ParamName}' for context '{context}'");
}
catch (Exception e)
{
Log.Error($"Unhandled exception while executing plugin context '{context}'. ({e.Message})");
}
}
/// <summary>
/// The Exit method, as required by the VoiceAttack plugin API.
/// Runs when VoiceAttack is shut down.
/// </summary>
/// <param name="vaProxy">The VoiceAttack proxy object.</param>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "required by VoiceAttack plugin API")]
public static void VA_Exit1(dynamic vaProxy)
{
}
/// <summary>
/// The StopCommand method, as required by the VoiceAttack plugin API.
/// Runs whenever all commands are stopped using the “Stop All Commands”
/// button or action.
/// </summary>
public static void VA_StopCommand()
{
}
/*================\
| plugin contexts |
\================*/
#pragma warning disable IDE0060 // Remove unused parameter
private static void Context_EDTS_GetCoordinates(dynamic vaProxy)
{
string name = vaProxy.GetText("~system") ?? throw new ArgumentNullException("~system");
bool success = false;
string? errorType = null;
string? errorMessage = null;
try
{
StarSystem system = EdtsApi.GetCoordinates(name);
if (system.Coords.Precision < 100)
{
Log.Info($@"Coordinates for ""{name}"": ({system.Coords.X}, {system.Coords.Y}, {system.Coords.Z}), precision: {system.Coords.Precision}ly");
}
else
{
Log.Warn($@"Coordinates with low precision for ""{name}"": ({system.Coords.X}, {system.Coords.Y}, {system.Coords.Z}), precision: {system.Coords.Precision}ly");
}
vaProxy.SetInt("~x", system.Coords.X);
vaProxy.SetInt("~y", system.Coords.Y);
vaProxy.SetInt("~z", system.Coords.Z);
vaProxy.SetInt("~precision", system.Coords.Precision);
success = true;
}
catch (ArgumentException e)
{
errorType = "invalid name";
errorMessage = e.Message;
}
catch (Exception e)
{
errorType = "connection error";
errorMessage = e.Message;
}
vaProxy.SetBoolean("~success", success);
if (!string.IsNullOrWhiteSpace(errorType))
{
Log.Error(errorMessage!);
vaProxy.SetText("~errorType", errorType);
vaProxy.SetText("~errorMessage", errorMessage);
}
}
private static void Context_Log(dynamic vaProxy)
{
string message = vaProxy.GetText("~message");
string level = vaProxy.GetText("~level");
if (level == null)
{
Log.Log(message);
}
else
{
try
{
Log.Log(message, (LogLevel)Enum.Parse(typeof(LogLevel), level.ToUpper()));
}
catch (ArgumentNullException)
{
throw;
}
catch (ArgumentException)
{
Log.Error($"Invalid log level '{level}'.");
}
}
}
private static void Context_Spansh_Nearestsystem(dynamic vaProxy)
{
int x = vaProxy.GetInt("~x") ?? throw new ArgumentNullException("~x");
int y = vaProxy.GetInt("~y") ?? throw new ArgumentNullException("~y");
int z = vaProxy.GetInt("~z") ?? throw new ArgumentNullException("~z");
string path = $@"{vaProxy.SessionState["VA_SOUNDS"]}\Scripts\spansh.exe";
string arguments = $@"nearestsystem --parsable {x} {y} {z}";
Process p = PythonProxy.SetupPythonScript(path, arguments);
Dictionary<char, decimal> coords = new () { { 'x', 0 }, { 'y', 0 }, { 'z', 0 } };
string system = string.Empty;
decimal distance = 0;
bool error = false;
string errorMessage = string.Empty;
p.Start();
string stdout = p.StandardOutput.ReadToEnd();
string stderr = p.StandardError.ReadToEnd();
p.WaitForExit();
switch (p.ExitCode)
{
case 0:
string[] stdoutExploded = stdout.Split('|');
system = stdoutExploded[0];
distance = decimal.Parse(stdoutExploded[2]);
string[] stdoutCoords = stdoutExploded[1].Split(',');
coords['x'] = decimal.Parse(stdoutCoords[0]);
coords['y'] = decimal.Parse(stdoutCoords[1]);
coords['z'] = decimal.Parse(stdoutCoords[2]);
Log.Info($"Nearest system to ({x}, {y}, {z}): {system} ({coords['x']}, {coords['y']}, {coords['z']}), distance: {distance}ly");
break;
case 1:
error = true;
errorMessage = stdout;
Log.Error(errorMessage);
break;
default:
error = true;
Log.Error(stderr);
errorMessage = "Unrecoverable error in plugin.";
break;
}
vaProxy.SetText("~system", system);
vaProxy.SetDecimal("~x", coords['x']);
vaProxy.SetDecimal("~y", coords['y']);
vaProxy.SetDecimal("~z", coords['z']);
vaProxy.SetDecimal("~distance", distance);
vaProxy.SetBoolean("~error", error);
vaProxy.SetText("~errorMessage", errorMessage);
vaProxy.SetInt("~exitCode", p.ExitCode);
}
private static void Context_Spansh_SytemExists(dynamic vaProxy)
{
string system = vaProxy.GetText("~system") ?? throw new ArgumentNullException("~system");
string path = $@"{vaProxy.SessionState["VA_SOUNDS"]}\Scripts\spansh.exe";
string arguments = $@"systemexists ""{system}""";
Process p = PythonProxy.SetupPythonScript(path, arguments);
bool exists = true;
bool error = false;
string errorMessage = string.Empty;
p.Start();
string stdout = p.StandardOutput.ReadToEnd();
string stderr = p.StandardError.ReadToEnd();
p.WaitForExit();
switch (p.ExitCode)
{
case 0:
Log.Info($@"System ""{system}"" found in Spanshs DB");
break;
case 1:
error = true;
errorMessage = stdout;
Log.Error(errorMessage);
break;
case 3:
exists = false;
Log.Info($@"System ""{system}"" not found in Spanshs DB");
break;
default:
error = true;
Log.Error(stderr);
errorMessage = "Unrecoverable error in plugin.";
break;
}
vaProxy.SetBoolean("~systemExists", exists);
vaProxy.SetBoolean("~error", error);
vaProxy.SetText("~errorMessage", errorMessage);
vaProxy.SetInt("~exitCode", p.ExitCode);
}
private static void Context_Startup(dynamic vaProxy)
{
Log.Notice("Starting up …");
Log.Notice("Finished startup.");
}
#pragma warning restore IDE0060 // Remove unused parameter
}
}

View file

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{D2047704-696B-4665-8D37-3AD298A8B9F9}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>SpanshAttack</RootNamespace>
<AssemblyName>SpanshAttack</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\build\alterNERDtive\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>..\build\alterNERDtive\SpanshAttack.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\build\alterNERDtive\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>..\build\alterNERDtive\SpanshAttack.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="SpanshAttack.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VoiceAttack-base\VoiceAttack-base.csproj">
<Project>{1c05db3f-3449-4664-b363-a379892995e5}</Project>
<Name>VoiceAttack-base</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View file

@ -0,0 +1,28 @@
// <copyright file="GlobalSuppressions.cs" company="alterNERDtive">
// Copyright 20192022 alterNERDtive.
//
// This file is part of alterNERDtive VoiceAttack profiles for Elite Dangerous.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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 alterNERDtive VoiceAttack profiles for Elite Dangerous. If not, see &lt;https://www.gnu.org/licenses/&gt;.
// </copyright>
using System.Diagnostics.CodeAnalysis;
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
[assembly: SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element should begin with upper-case letter", Justification = "just cause", Scope = "namespace", Target = "~N:alterNERDtive")]
[assembly: SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element should begin with upper-case letter", Justification = "just cause", Scope = "namespace", Target = "~N:alterNERDtive.edts")]
[assembly: SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element should begin with upper-case letter", Justification = "just cause", Scope = "namespace", Target = "~N:alterNERDtive.util")]

View file

@ -0,0 +1,55 @@
// <copyright file="AssemblyInfo.cs" company="alterNERDtive">
// Copyright 20192022 alterNERDtive.
//
// This file is part of alterNERDtive VoiceAttack profiles for Elite Dangerous.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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 alterNERDtive VoiceAttack profiles for Elite Dangerous. If not, see &lt;https://www.gnu.org/licenses/&gt;.
// </copyright>
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("VoiceAttack-base")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("VoiceAttack-base")]
[assembly: AssemblyCopyright("Copyright © 20202022")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("1c05db3f-3449-4664-b363-a379892995e5")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View file

@ -0,0 +1,25 @@
<UserControl x:Class="alterNERDtive.SettingsDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:alterNERDtive"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<StackPanel>
<TabControl Name="tabs">
<TabItem Name="general" Header="general"></TabItem>
<TabItem Name="EliteAttack" Header="EliteAttack"></TabItem>
<TabItem Name="RatAttack" Header="RatAttack"></TabItem>
<TabItem Name="SpanshAttack" Header="SpanshAttack"></TabItem>
<TabItem Name="StreamAttack" Header="StreamAttack"></TabItem>
</TabControl>
<WrapPanel VerticalAlignment="Bottom" HorizontalAlignment="Right">
<Button Name="applyButton" Click="ApplyButton_Click" Padding="5" Margin="5" Width="100">Apply</Button>
<Button Name="okButton" Click="OkButton_Click" Padding="5" Margin="5" Width="100">Done</Button>
<Button Name="cancelButton" Click="CancelButton_Click" Padding="5" Margin="5" Width="100">Cancel</Button>
</WrapPanel>
</StackPanel>
</Grid>
</UserControl>

View file

@ -0,0 +1,188 @@
// <copyright file="SettingsDialog.xaml.cs" company="alterNERDtive">
// Copyright 20192022 alterNERDtive.
//
// This file is part of alterNERDtive VoiceAttack profiles for Elite Dangerous.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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 alterNERDtive VoiceAttack profiles for Elite Dangerous. If not, see &lt;https://www.gnu.org/licenses/&gt;.
// </copyright>
#nullable enable
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace alterNERDtive
{
/// <summary>
/// Interaction logic for SettingsDialog.xaml.
/// </summary>
public partial class SettingsDialog : UserControl
{
private readonly List<Setting> values = new List<Setting>();
private util.Configuration config;
private util.VoiceAttackLog log;
/// <summary>
/// Initializes a new instance of the <see cref="SettingsDialog"/> class.
/// </summary>
/// <param name="config">The plugin Configuration.</param>
/// <param name="log">The plugin Log.</param>
public SettingsDialog(util.Configuration config, util.VoiceAttackLog log)
{
this.InitializeComponent();
this.config = config;
this.log = log;
foreach (TabItem tab in this.tabs.Items)
{
string profile = tab.Name;
if (profile == "general")
{
profile = "alterNERDtive-base";
}
tab.IsEnabled = BasePlugin.IsProfileActive(profile);
StackPanel panel = new StackPanel();
util.Configuration.OptDict<string, util.Configuration.Option> options = util.Configuration.GetOptions(profile);
foreach (dynamic option in options.Values)
{
dynamic value = config.GetConfig(profile, option.Name);
if (option is util.Configuration.Option<bool>)
{
WrapPanel row = new WrapPanel();
CheckBox checkBox = new CheckBox();
checkBox.IsChecked = value;
checkBox.VerticalAlignment = VerticalAlignment.Center;
row.Children.Add(checkBox);
this.values.Add(new Setting(profile, option, value, checkBox));
Label label = new Label();
label.Content = option.Description;
row.Children.Add(label);
panel.Children.Add(row);
}
else
{
StackPanel row = new StackPanel();
Label label = new Label();
label.Content = option.Description;
row.Children.Add(label);
TextBox input = new TextBox();
input.Text = value.ToString();
row.Children.Add(input);
this.values.Add(new Setting(profile, option, value, input));
panel.Children.Add(row);
}
}
tab.Content = panel;
}
}
private bool ApplySettings()
{
bool success = true;
foreach (Setting setting in this.values)
{
dynamic? state = null;
try
{
if (setting.Option is util.Configuration.Option<bool>)
{
state = ((CheckBox)setting.UiElement).IsChecked ?? false;
}
else if (setting.Option is util.Configuration.Option<DateTime>)
{
state = DateTime.Parse(((TextBox)setting.UiElement).Text);
}
else if (setting.Option is util.Configuration.Option<decimal>)
{
state = decimal.Parse(((TextBox)setting.UiElement).Text);
}
else if (setting.Option is util.Configuration.Option<int>)
{
state = int.Parse(((TextBox)setting.UiElement).Text);
}
else if (setting.Option is util.Configuration.Option<short>)
{
state = short.Parse(((TextBox)setting.UiElement).Text);
}
else if (setting.Option is util.Configuration.Option<string>)
{
state = ((TextBox)setting.UiElement).Text;
}
if (state != setting.Value)
{
this.log.Log($@"Configuration changed via settings dialog: ""{setting.Profile}.{setting.Option.Name}"" → ""{state}""", util.LogLevel.DEBUG);
this.config.SetConfig(setting.Profile, setting.Option.Name, state);
}
}
catch (Exception e) when (e is ArgumentNullException || e is FormatException || e is OverflowException)
{
this.log.Log($@"Invalid value for ""{setting.Profile}.{setting.Option.Name}"": ""{((TextBox)setting.UiElement).Text}""", util.LogLevel.ERROR);
success = false;
}
}
return success;
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
Window.GetWindow(this).Close();
this.log.Log("Settings dialog cancelled.", util.LogLevel.DEBUG);
}
private void OkButton_Click(object sender, RoutedEventArgs e)
{
if (this.ApplySettings())
{
Window.GetWindow(this).Close();
}
}
private void ApplyButton_Click(object sender, RoutedEventArgs reeargs)
{
this.ApplySettings();
}
private struct Setting
{
public Setting(string profile, dynamic option, dynamic value, dynamic uiElement)
=> (this.Profile, this.Option, this.Value, this.UiElement) = (profile, option, value, uiElement);
public string Profile { get; }
public dynamic Option { get; }
public dynamic Value { get; }
public dynamic UiElement { get; }
}
}
}

View file

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{1C05DB3F-3449-4664-B363-A379892995E5}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>alterNERDtive</RootNamespace>
<AssemblyName>base</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\build\alterNERDtive\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>..\build\alterNERDtive\base.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\build\alterNERDtive\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>..\build\alterNERDtive\base.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Numerics" />
<Reference Include="System.Xaml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="base.cs" />
<Compile Include="edts.cs">
<ExcludeFromStyleCop>true</ExcludeFromStyleCop>
</Compile>
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SettingsDialog.xaml.cs">
<DependentUpon>SettingsDialog.xaml</DependentUpon>
</Compile>
<Compile Include="util.cs" />
</ItemGroup>
<ItemGroup>
<Page Include="SettingsDialog.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNet.WebApi.Client">
<Version>5.2.9</Version>
</PackageReference>
<PackageReference Include="Newtonsoft.Json">
<Version>13.0.1</Version>
</PackageReference>
<PackageReference Include="System.Net.Http">
<Version>4.3.4</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View file

@ -0,0 +1,691 @@
// <copyright file="base.cs" company="alterNERDtive">
// Copyright 20192022 alterNERDtive.
//
// This file is part of alterNERDtive VoiceAttack profiles for Elite Dangerous.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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 alterNERDtive VoiceAttack profiles for Elite Dangerous. If not, see &lt;https://www.gnu.org/licenses/&gt;.
// </copyright>
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading;
using alterNERDtive.util;
namespace alterNERDtive
{
/// <summary>
/// This is the base plugin orchestrating all the profile-specific plugins
/// to work together properly. It handles things like configuration or
/// subscribing to VoiceAttack-triggered events.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1649:File name should match first type name", Justification = "F off :)")]
public class BasePlugin
{
private static readonly Version VERSION = new ("4.5");
private static readonly Dictionary<Guid, string> Profiles = new ()
{
{ new Guid("{F7F59CFD-1AE2-4A7E-8F62-C62372418BAC}"), "alterNERDtive-base" },
{ new Guid("{f31b575b-6ce4-44eb-91fc-7459e55013cf}"), "EliteAttack" },
{ new Guid("{87276668-2a6e-4d80-af77-80651daa58b7}"), "RatAttack" },
{ new Guid("{e722b29d-898e-47dd-a843-a409c87e0bd8}"), "SpanshAttack" },
{ new Guid("{05580e6c-442c-46cd-b36f-f5a1f967ec59}"), "StreamAttack" },
};
private static readonly List<string> ActiveProfiles = new ();
private static readonly List<string> InstalledProfiles = new ();
private static readonly Regex ConfigurationVariableRegex = new (@$"(?<id>({string.Join("|", Profiles.Values)}))\.(?<name>.+)#");
private static VoiceAttackCommands? commands;
private static Configuration? config;
private static VoiceAttackLog? log;
private static VoiceAttackCommands Commands => commands ??= new (VA, Log);
private static Configuration Config => config ??= new (VA, Log, Commands, "alterNERDtive-base");
private static VoiceAttackLog Log => log ??= new (VA, "alterNERDtive-base");
private static dynamic? VA { get; set; }
/*========================================\
| required VoiceAttack plugin shenanigans |
\========================================*/
/// <summary>
/// The plugins GUID, as required by the VoiceAttack plugin API.
/// </summary>
/// <returns>The GUID.</returns>
public static Guid VA_Id()
=> new ("{F7F59CFD-1AE2-4A7E-8F62-C62372418BAC}");
/// <summary>
/// The plugins display name, as required by the VoiceAttack plugin API.
/// </summary>
/// <returns>The display name.</returns>
public static string VA_DisplayName()
=> $"alterNERDtive-base {VERSION}";
/// <summary>
/// The plugins description, as required by the VoiceAttack plugin API.
/// </summary>
/// <returns>The description.</returns>
public static string VA_DisplayInfo()
=> "The alterNERDtive plugin to manage all the alterNERDtive profiles!";
/// <summary>
/// The Init method, as required by the VoiceAttack plugin API.
/// Runs when the plugin is initially loaded.
/// </summary>
/// <param name="vaProxy">The VoiceAttack proxy object.</param>
public static void VA_Init1(dynamic vaProxy)
{
VA = vaProxy;
Log.Notice("Initializing …");
VA.SetText("alterNERDtive-base.version", VERSION.ToString());
vaProxy.BooleanVariableChanged += new Action<string, bool?, bool?, Guid?>((name, from, to, id) => { ConfigurationChanged(name, from, to, id); });
vaProxy.DateVariableChanged += new Action<string, DateTime?, DateTime?, Guid?>((name, from, to, id) => { ConfigurationChanged(name, from, to, id); });
vaProxy.DecimalVariableChanged += new Action<string, decimal?, decimal?, Guid?>((name, from, to, id) => { ConfigurationChanged(name, from, to, id); });
vaProxy.IntegerVariableChanged += new Action<string, int?, int?, Guid?>((name, from, to, id) => { ConfigurationChanged(name, from, to, id); });
vaProxy.TextVariableChanged += new Action<string, string, string, Guid?>((name, from, to, id) => { ConfigurationChanged(name, from, to, id); });
VA.SetBoolean("alterNERDtive-base.initialized", true);
Commands.TriggerEvent("alterNERDtive-base.initialized", wait: false, logMissing: false);
Log.Notice("Init successful.");
}
/// <summary>
/// The Invoke method, as required by the VoiceAttack plugin API.
/// Runs whenever a plugin context is invoked.
/// </summary>
/// <param name="vaProxy">The VoiceAttack proxy object.</param>
public static void VA_Invoke1(dynamic vaProxy)
{
string context = vaProxy.Context.ToLower();
Log.Debug($"Running context '{context}' …");
try
{
switch (context)
{
case "startup":
Context_Startup(vaProxy);
break;
case "config.dialog":
// config
Context_Config_Dialog(vaProxy);
break;
case "config.dump":
Context_Config_Dump(vaProxy);
break;
case "config.getvariables":
Context_Config_SetVariables(vaProxy);
break;
case "config.list":
Context_Config_List(vaProxy);
break;
case "config.setup":
Context_Config_Setup(vaProxy);
break;
case "config.versionmigration":
Context_Config_VersionMigration(vaProxy);
break;
case "edsm.bodycount":
// EDSM
Context_EDSM_BodyCount(vaProxy);
break;
case "edsm.distancebetween":
Context_EDSM_DistanceBetween(vaProxy);
break;
case "eddi.event":
// EDDI
Context_Eddi_Event(vaProxy);
break;
case "spansh.outdatedstations":
// Spansh
Context_Spansh_OutdatedStations(vaProxy);
break;
case "log.log":
// log
Context_Log(vaProxy);
break;
case "update.check":
// update
Context_Update_Check(vaProxy);
break;
default:
// invalid
Log.Error($"Invalid plugin context '{vaProxy.Context}'.");
break;
}
}
catch (ArgumentNullException e)
{
Log.Error($"Missing parameter '{e.ParamName}' for context '{context}'");
}
catch (Exception e)
{
Log.Error($"Unhandled exception while executing plugin context '{context}'. ({e.Message})");
}
}
/// <summary>
/// The Exit method, as required by the VoiceAttack plugin API.
/// Runs when VoiceAttack is shut down.
/// </summary>
/// <param name="vaProxy">The VoiceAttack proxy object.</param>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "required by VoiceAttack plugin API")]
public static void VA_Exit1(dynamic vaProxy)
{
}
/// <summary>
/// The StopCommand method, as required by the VoiceAttack plugin API.
/// Runs whenever all commands are stopped using the “Stop All Commands”
/// button or action.
/// </summary>
public static void VA_StopCommand()
{
}
/// <summary>
/// Returns whether a given profile is currently active.
/// </summary>
/// <param name="profileName">The name of the profile in question.</param>
/// <returns>The state of the profile in question.</returns>
public static bool IsProfileActive(string profileName) => ActiveProfiles.Contains(profileName);
private static void CheckProfiles(dynamic vaProxy)
{
ActiveProfiles.Clear();
InstalledProfiles.Clear();
foreach (KeyValuePair<Guid, string> profile in Profiles)
{
if (vaProxy.Command.Exists($"(({profile.Value}.startup))"))
{
// Sadly there is no way to find _active_ profiles, so we have to check the one command that always is in them.
ActiveProfiles.Add(profile.Value);
}
if (vaProxy.Profile.Exists(profile.Key))
{
InstalledProfiles.Add(profile.Value);
}
}
Log.Debug($"Profiles found: {string.Join<string>(", ", ActiveProfiles)}");
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "required by VoiceAttack plugin API")]
private static void ConfigurationChanged(string option, dynamic? from, dynamic? to, Guid? guid = null)
{
try
{
Match match = ConfigurationVariableRegex.Match(option);
if (match.Success)
{
string id = match.Groups["id"].Value;
string name = match.Groups["name"].Value;
Log.Debug($"Configuration has changed, '{id}.{name}': '{from}' → '{to}'");
dynamic o = Configuration.GetOption(id, name);
// When loaded from profile but not explicitly set, will be null.
// Then load default.
// Same applies to resetting a saved option (= saving null to the profile).
if (to == null)
{
_ = to ?? Config.ApplyDefault(id, name);
}
else
{
// When not null, check if theres a constraint on valid values.
if (o.ValidValues != null)
{
if (!o.ValidValues.Contains(to))
{
// Handle “arrays” of values
bool valid = false;
if (to is string && ((string)to).Contains(";"))
{
valid = true;
foreach (string value in ((string)to).Split(';'))
{
if (!o.ValidValues.Contains(value))
{
valid = false;
}
}
}
if (!valid)
{
Log.Error($@"Invalid value ""{to}"" for option ""{id}.{option}"", reverting to default …");
Config.ApplyDefault(id, name);
}
}
}
// if null, EDDI isnt up yet
if (option == "alterNERDtive-base.eddi.quietMode#" && VA!.GetText("EDDI version") != null)
{
Log.Debug($"Resetting speech responder ({(to ?? false ? "off" : "on")}) …");
Commands.Run("alterNERDtive-base.setEDDISpeechResponder");
}
else if (option == "alterNERDtive-base.log.logLevel#")
{
Log.SetCurrentLogLevel(to);
}
}
}
}
catch (Exception e)
{
Log.Error($"Unhandled exception while handling changed variable '{option}'. ({e.Message})");
}
}
private static void UpdateCheck()
{
Version latestVersion;
try
{
latestVersion = new Version(new WebClient().DownloadString("https://raw.githubusercontent.com/alterNERDtive/VoiceAttack-profiles/release/VERSION"));
}
catch (Exception)
{
throw new Exception("Error fetching latest profiles version from Github.");
}
Log.Notice($"Local version: {VERSION}, latest release: {latestVersion}.");
Commands.TriggerEvent(
"alterNERDtive-base.updateCheck",
parameters: new dynamic[] { new string[] { VERSION.ToString(), latestVersion.ToString() }, new bool[] { VERSION.CompareTo(latestVersion) < 0 } });
}
/*================\
| plugin contexts |
\================*/
#pragma warning disable IDE0060 // Remove unused parameter
private static void Context_Config_Dialog(dynamic vaProxy)
{
Thread dialogThread = new Thread(new ThreadStart(() =>
{
System.Windows.Window options = new ()
{
Title = "alterNERDtive Profile Options",
Content = new SettingsDialog(Config, Log),
SizeToContent = System.Windows.SizeToContent.WidthAndHeight,
ResizeMode = System.Windows.ResizeMode.NoResize,
WindowStyle = System.Windows.WindowStyle.ToolWindow,
};
options.ShowDialog();
options.Activate();
}));
dialogThread.SetApartmentState(ApartmentState.STA);
dialogThread.IsBackground = true;
dialogThread.Start();
}
private static void Context_Config_Dump(dynamic vaProxy)
{
Config.DumpConfig();
}
private static void Context_Config_List(dynamic vaProxy)
{
Config.ListConfig();
}
private static void Context_Config_Setup(dynamic vaProxy)
{
Log.Debug("Loading default configuration …");
Config.ApplyAllDefaults();
foreach (System.Type type in new List<System.Type> { typeof(bool), typeof(DateTime), typeof(decimal), typeof(int), typeof(short), typeof(string) })
{
Config.SetVoiceTriggers(type);
}
Config.LoadFromProfile();
Log.Debug("Finished loading configuration.");
}
private static void Context_Config_SetVariables(dynamic vaProxy)
{
string trigger = vaProxy.GetText("~trigger") ?? throw new ArgumentNullException("~trigger");
Log.Debug($"Loading variables for trigger '{trigger}' …");
Config.SetVariablesForTrigger(vaProxy, trigger);
}
private static void Context_Config_VersionMigration(dynamic vaProxy)
{
// =============
// === 4.3.1 ===
// =============
// EliteAttack
foreach (string option in new string[] { "autoStationService" })
{
string name = $"EliteAttack.{option}s#";
string oldName = $"EliteAttack.{option}#";
Commands.Run("alterNERDtive-base.loadVariableFromProfile", wait: true, parameters: new dynamic[] { new string[] { $"{oldName}", "boolean" } });
bool? value = vaProxy.GetBoolean(oldName);
if (value != null)
{
Log.Info($"Migrating option {oldName} …");
Commands.Run("alterNERDtive-base.saveVariableToProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}" }, new bool[] { (bool)value } });
Commands.Run("alterNERDtive-base.unsetVariableFromProfile", wait: true, parameters: new dynamic[] { new string[] { $"{oldName}", "boolean" } });
}
}
// ===========
// === 4.2 ===
// ===========
// SpanshAttack
string edtsPath = $@"{vaProxy.SessionState["VA_SOUNDS"]}\scripts\edts.exe";
if (File.Exists(edtsPath))
{
File.Delete(edtsPath);
}
// ===========
// === 4.0 ===
// ===========
// EliteAttack
string prefix = "EliteAttack";
string oldPrefix = "EliteDangerous";
foreach (string option in new string[] { "announceEdsmSystemStatus", "announceMappingCandidates", "announceOutdatedStationData", "announceR2RMappingCandidates", "autoRestock", "flightAssistOff", "hyperspaceDethrottle" })
{
string name = $"{prefix}.{option}";
string oldName = $"{oldPrefix}.{option}";
Commands.Run("alterNERDtive-base.loadVariableFromProfile", wait: true, parameters: new dynamic[] { new string[] { $"{oldName}", "boolean" } });
bool? value = vaProxy.GetBoolean(oldName);
if (value != null)
{
Log.Info($"Migrating option {oldName} …");
Commands.Run("alterNERDtive-base.saveVariableToProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}#" }, new bool[] { (bool)value } });
Commands.Run("alterNERDtive-base.unsetVariableFromProfile", wait: true, parameters: new dynamic[] { new string[] { $"{oldName}", "boolean" } });
}
}
// RatAttack
prefix = "RatAttack";
foreach (string option in new string[] { "autoCloseCase", "announceNearestCMDR", "announcePlatform", "confirmCalls", "onDuty" })
{
string name = $"{prefix}.{option}";
Commands.Run("alterNERDtive-base.loadVariableFromProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}", "boolean" } });
bool? value = vaProxy.GetBoolean(name);
if (value != null)
{
Log.Info($"Migrating option {name} …");
Commands.Run("alterNERDtive-base.saveVariableToProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}#" }, new bool[] { (bool)value } });
Commands.Run("alterNERDtive-base.unsetVariableFromProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}", "boolean" } });
}
}
foreach (string option in new string[] { "CMDRs", "platforms" })
{
string name = $"{prefix}.{option}";
Commands.Run("alterNERDtive-base.loadVariableFromProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}", "text" } });
string value = vaProxy.GetText(name);
if (!string.IsNullOrEmpty(value))
{
Log.Info($"Migrating option {name} …");
Commands.Run("alterNERDtive-base.saveVariableToProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}#", value } });
Commands.Run("alterNERDtive-base.unsetVariableFromProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}", "text" } });
}
}
// SpanshAttack
prefix = "SpanshAttack";
foreach (string option in new string[] { "announceWaypoints", "autoJumpAfterScooping", "autoPlot", "clearOnShutdown", "copyWaypointToClipboard", "defaultToLadenRange", "timeTrip" })
{
string name = $"{prefix}.{option}";
Commands.Run("alterNERDtive-base.loadVariableFromProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}", "boolean" } });
bool? value = vaProxy.GetBoolean(name);
if (value != null)
{
Log.Info($"Migrating option {name} …");
Commands.Run("alterNERDtive-base.saveVariableToProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}#" }, new bool[] { (bool)value } });
Commands.Run("alterNERDtive-base.unsetVariableFromProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}", "boolean" } });
}
}
foreach (string option in new string[] { "announceJumpsLeft" })
{
string name = $"{prefix}.{option}";
Commands.Run("alterNERDtive-base.loadVariableFromProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}", "text" } });
string value = vaProxy.GetText(name);
if (!string.IsNullOrEmpty(value))
{
Log.Info($"Migrating option {name} …");
Commands.Run("alterNERDtive-base.saveVariableToProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}#", value } });
Commands.Run("alterNERDtive-base.unsetVariableFromProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}", "text" } });
}
}
// StreamAttack
prefix = "StreamAttack";
foreach (string option in new string[] { "outputDir" })
{
string name = $"{prefix}.{option}";
Commands.Run("alterNERDtive-base.loadVariableFromProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}", "text" } });
string value = vaProxy.GetText(name);
if (!string.IsNullOrEmpty(value))
{
Log.Info($"Migrating option {name} …");
Commands.Run("alterNERDtive-base.saveVariableToProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}#", value } });
Commands.Run("alterNERDtive-base.unsetVariableFromProfile", wait: true, parameters: new dynamic[] { new string[] { $"{name}", "text" } });
}
}
}
private static void Context_Eddi_Event(dynamic vaProxy)
{
string eddiEvent = vaProxy.Command.Name();
string command = eddiEvent.Substring(2, eddiEvent.Length - 4);
Log.Debug($"Running EDDI event '{command}' …");
Commands.RunAll(ActiveProfiles, command, logMissing: false, subcommand: true); // FIXXME: a) triggerAll or something, b) change all profiles to use "((<name>.<event>))" over "<name>.<event>"
}
private static void Context_EDSM_BodyCount(dynamic vaProxy)
{
string system = vaProxy.GetText("~system") ?? throw new ArgumentNullException("~system");
string path = $@"{vaProxy.SessionState["VA_SOUNDS"]}\scripts\explorationtools.exe";
string arguments = $@"bodycount ""{system}""";
Process p = PythonProxy.SetupPythonScript(path, arguments);
int bodyCount = 0;
bool error = false;
string errorMessage = string.Empty;
p.Start();
string stdout = p.StandardOutput.ReadToEnd();
string stderr = p.StandardError.ReadToEnd();
p.WaitForExit();
switch (p.ExitCode)
{
case 0:
bodyCount = int.Parse(stdout);
Log.Info($"EDSM body count for {system}: {bodyCount}");
break;
case 1:
error = true;
Log.Error(stdout);
errorMessage = stdout;
break;
case 2:
error = true;
Log.Notice($@"System ""{system}"" not found on EDSM");
errorMessage = stdout;
break;
default:
error = true;
Log.Error(stderr);
errorMessage = "Unrecoverable error in plugin.";
break;
}
vaProxy.SetInt("~bodyCount", bodyCount);
vaProxy.SetBoolean("~error", error);
vaProxy.SetText("~errorMessage", errorMessage);
vaProxy.SetInt("~exitCode", p.ExitCode);
}
private static void Context_EDSM_DistanceBetween(dynamic vaProxy)
{
string fromSystem = vaProxy.GetText("~fromSystem") ?? throw new ArgumentNullException("~fromSystem");
string toSystem = vaProxy.GetText("~toSystem") ?? throw new ArgumentNullException("~toSystem");
int roundTo = vaProxy.GetInt("~roundTo") ?? 2;
string path = $@"{vaProxy.SessionState["VA_SOUNDS"]}\Scripts\explorationtools.exe";
string arguments = $@"distancebetween --roundto {roundTo} ""{fromSystem}"" ""{toSystem}""";
Process p = PythonProxy.SetupPythonScript(path, arguments);
decimal distance = 0;
bool error = false;
string errorMessage = string.Empty;
p.Start();
string stdout = p.StandardOutput.ReadToEnd();
string stderr = p.StandardError.ReadToEnd();
p.WaitForExit();
switch (p.ExitCode)
{
case 0:
distance = decimal.Parse(stdout);
Log.Info($"{fromSystem} → {toSystem}: {distance}ly");
break;
case 1:
case 2:
error = true;
Log.Error(stdout);
errorMessage = stdout;
break;
default:
error = true;
Log.Error(stderr);
errorMessage = "Unrecoverable error in plugin.";
break;
}
vaProxy.SetDecimal("~distance", distance);
vaProxy.SetBoolean("~error", error);
vaProxy.SetText("~errorMessage", errorMessage);
vaProxy.SetInt("~exitCode", p.ExitCode);
}
private static void Context_Log(dynamic vaProxy)
{
string message = vaProxy.GetText("~message");
string level = vaProxy.GetText("~level");
if (level == null)
{
Log.Log(message);
}
else
{
try
{
Log.Log(message, (LogLevel)Enum.Parse(typeof(LogLevel), level.ToUpper()));
}
catch (ArgumentNullException)
{
throw;
}
catch (ArgumentException)
{
Log.Error($"Invalid log level '{level}'.");
}
}
}
private static void Context_Spansh_OutdatedStations(dynamic vaProxy)
{
string system = vaProxy.GetText("~system") ?? throw new ArgumentNullException("~system");
int minage = vaProxy.GetInt("~minage") ?? throw new ArgumentNullException("~minage");
bool includeSettlements = vaProxy.GetBoolean("~includeSettlements") ?? throw new ArgumentNullException("~includeSettlements");
string path = $@"{vaProxy.SessionState["VA_SOUNDS"]}\Scripts\spansh.exe";
string arguments = $@"oldstations --system ""{system}"" --minage {minage}{(includeSettlements ? string.Empty : " --nofeet")}";
Process p = PythonProxy.SetupPythonScript(path, arguments);
p.Start();
string stdout = p.StandardOutput.ReadToEnd();
string stderr = p.StandardError.ReadToEnd();
p.WaitForExit();
string message = stdout;
string? errorMessage = null;
bool error = true;
switch (p.ExitCode)
{
case 0:
error = false;
Log.Notice($"Outdated stations for {system}: {message}");
break;
case 1:
error = true;
Log.Error(message);
break;
case 3:
error = true;
Log.Info($@"No outdated stations found for ""{system}""");
break;
default:
error = true;
Log.Error(stderr);
errorMessage = "Unrecoverable error in plugin.";
break;
}
vaProxy.SetText("~message", message);
vaProxy.SetBoolean("~error", error);
vaProxy.SetText("~errorMessage", errorMessage);
vaProxy.SetInt("~exitCode", p.ExitCode);
}
private static void Context_Startup(dynamic vaProxy)
{
Log.Notice("Starting up …");
CheckProfiles(vaProxy);
Log.Notice($"Active profiles: {string.Join(", ", ActiveProfiles)}");
Commands.TriggerEventAll(ActiveProfiles, "startup", logMissing: false);
Log.Notice("Finished startup.");
}
private static void Context_Update_Check(dynamic vaProxy)
{
UpdateCheck();
}
#pragma warning restore IDE0060 // Remove unused parameter
}
}

View file

@ -0,0 +1,81 @@
// <auto-generated/>
// Not really, but this file will not bow to StyleCop tyranny.
// Why? Because it will be obsolete mid term anyway ;)
// <copyright file="edts.cs" company="alterNERDtive">
// Copyright 20192022 alterNERDtive.
//
// This file is part of alterNERDtive VoiceAttack profiles for Elite Dangerous.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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.
//
// alterNERDtive VoiceAttack profiles for Elite Dangerous 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 alterNERDtive VoiceAttack profiles for Elite Dangerous. If not, see &lt;https://www.gnu.org/licenses/&gt;.
// </copyright>
#nullable enable
using System;
using System.Net.Http;
using System.Net.Http.Headers;
namespace alterNERDtive.edts
{
public struct StarSystem
{
public string Name { get; set; }
public Position Coords { get; set; }
}
public struct Position
{
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
public int Precision { get; set; }
}
public class EdtsApi
{
private static readonly string APIURL = "http://edts.thargoid.space/api/v1/";
private static HttpClient ApiClient;
static EdtsApi()
{
ApiClient = new HttpClient
{
BaseAddress = new Uri(APIURL)
};
ApiClient.DefaultRequestHeaders.Accept.Clear();
ApiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
public static StarSystem GetCoordinates(string name)
{
HttpResponseMessage response = ApiClient.GetAsync($"system_position/{name}").Result;
if (response.StatusCode == System.Net.HttpStatusCode.BadRequest) // 400
{
throw new ArgumentException($"“{name}” is not a valid proc gen system name.", "~system");
}
response.EnsureSuccessStatusCode();
dynamic json = response.Content.ReadAsAsync<dynamic>().Result["result"];
int x = json["position"]["x"];
int y = json["position"]["y"];
int z = json["position"]["z"];
int uncertainty = json["uncertainty"];
return new StarSystem { Name=name, Coords=new Position { X=x, Y=y, Z=z, Precision=uncertainty } };
}
}
}

File diff suppressed because it is too large Load diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

1
requirements.txt Normal file
View file

@ -0,0 +1 @@
mkdocs-roamlinks-plugin

16
stylecop.json Normal file
View file

@ -0,0 +1,16 @@
{
"$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
"settings": {
"orderingRules": {
"usingDirectivesPlacement": "outsideNamespace"
},
"documentationRules": {
"companyName": "alterNERDtive",
"copyrightText": "Copyright {year} {companyName}.\n\nThis file is part of {application}.\n\n{application} is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\n{application} is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with {application}. If not, see <https://www.gnu.org/licenses/>.",
"variables": {
"application": "alterNERDtive VoiceAttack profiles for Elite Dangerous",
"year": "20192022"
}
}
}
}