Compare commits

...

412 Commits

Author SHA1 Message Date
Olivier Gagnon
faf8389bef v1.3 2022-01-04 20:46:10 -05:00
Olivier Gagnon
50919a88cd update doc 2022-01-04 19:12:20 -05:00
Olivier Gagnon
4860d6dc83 Merge branch 'dev' of github.com:danielyxie/bitburner into dev 2022-01-04 19:09:38 -05:00
Olivier Gagnon
c59a267437 change sf4 2022-01-04 19:09:34 -05:00
hydroflame
f9fd7a48f8 Merge pull request #2339 from SlyCedix/patch-1
Improve grammar in hacking algorithms readme
2022-01-04 19:04:41 -05:00
hydroflame
07b12ca6fb Merge pull request #2332 from woody-lam-cwl/nuke-runtime-error
Fix #2329 NUKE.exe runtime error
2022-01-04 19:04:11 -05:00
Cyn
707a68dae9 Improve grammar in hacking algorithms readme 2022-01-04 19:03:45 -05:00
hydroflame
1f46d69430 Merge pull request #2334 from woody-lam-cwl/getweakentime-typo
Fix #2330 typo
2022-01-04 19:03:31 -05:00
hydroflame
f2fa7a3c2d Merge pull request #2335 from nickofolas/clickaway-notifications
Allow notifications to be dismissed by clicking
2022-01-04 19:03:05 -05:00
hydroflame
100ac2db95 Merge pull request #2333 from smolgumball/patch-1
Add invite link to Discord
2022-01-04 19:02:49 -05:00
hydroflame
338953fa1a Merge pull request #2338 from MartinFournier/fix/electron-unresponsive-handler
Fix unresponsive handler being attached many times
2022-01-04 19:02:34 -05:00
Martin Fournier
de8e5ef441 Fix unresponsive handler being attached many times 2022-01-04 18:16:07 -05:00
Olivier Gagnon
c06087c634 Merge branch 'dev' of github.com:danielyxie/bitburner into dev 2022-01-04 18:03:56 -05:00
Olivier Gagnon
8587625bd6 hacking algos 2022-01-04 18:03:44 -05:00
Woody Lam
c5fb744a39 Merge branch 'getweakentime-typo' of github.com-woody-lam-cwl:woody-lam-cwl/bitburner into getweakentime-typo 2022-01-04 22:40:46 +00:00
Woody Lam
d7cd5b0d96 Fix #2230 typo (again) 2022-01-04 22:40:41 +00:00
nickofolas
c445df4168 Allow notifications to be dismissed by clicking 2022-01-04 16:25:00 -06:00
Woody Lam
f8cba0ddc8 Fix #2330 typo 2022-01-04 21:50:30 +00:00
smolgumball
e3a181faf2 Add invite link to Discord 2022-01-04 14:44:17 -07:00
Woody Lam
f65e546c32 Fix #2329 NUKE.exe runtime error 2022-01-04 21:40:21 +00:00
hydroflame
772317a4f1 Merge pull request #2317 from nickofolas/validate-ram-purchase
Validate RAM amount in ns.purchaseServer()
2022-01-04 12:58:27 -05:00
hydroflame
225de0faf6 Merge pull request #2316 from nickofolas/fix-newline
Fix whitespace in Bladeburner console
2022-01-04 12:57:17 -05:00
hydroflame
0dbb067eae Merge pull request #2318 from nickofolas/fix-throw-undefined
Fix throw {nullish} errors
2022-01-04 12:57:04 -05:00
hydroflame
0d02ce6308 Merge pull request #2326 from MartinFournier/feature/editor-wordwrap-option
Add wordWrap option to Monaco
2022-01-04 12:54:50 -05:00
hydroflame
042189b187 Merge pull request #2324 from Dexalt142/editor-theme-one-dark
feat (editor theme): atom one dark theme
2022-01-04 12:54:34 -05:00
hydroflame
52ca4c177a Merge pull request #2325 from MartinFournier/feature/electron-add-sourcemaps
Include source maps in electron package
2022-01-04 12:54:21 -05:00
hydroflame
b38e411cd0 Merge pull request #2327 from MartinFournier/doc/faq
Update doc & add FAQs
2022-01-04 12:54:06 -05:00
Olivier Gagnon
c9d40ccf95 added new exploit 2022-01-04 12:21:17 -05:00
Martin Fournier
438ae51fcd Add Game Stuck FAQ 2022-01-04 11:11:17 -05:00
Martin Fournier
2747bf4439 Update doc & add FAQs 2022-01-04 11:03:01 -05:00
Olivier Gagnon
dd720897e8 fix tuto 2022-01-04 11:01:45 -05:00
Olivier Gagnon
449df63dd8 fix tuto 2022-01-04 10:58:47 -05:00
Martin Fournier
f0161367af Add wordWrap option to Monaco 2022-01-04 09:41:44 -05:00
Martin Fournier
ac0bcbca8e Include source maps in electron package
This will make the electron dev tools work like the web version.
2022-01-04 08:26:10 -05:00
Dexalt142
914b06ec88 feat (editor theme): atom one dark theme 2022-01-04 18:39:09 +07:00
hydroflame
d5561abd46 Merge pull request #2320 from Kebap/patch-1
fix copy/paste error
2022-01-03 22:26:28 -05:00
Kebap
53e3547d87 move sentence around 2022-01-04 03:09:20 +01:00
Kebap
501cabfdc5 Update bitburner.ns.getweakentime.md 2022-01-04 02:46:47 +01:00
nickofolas
fff1de63d3 Fix throw (nullish) errors 2022-01-03 17:26:22 -06:00
nickofolas
23b21e63a0 Validate RAM amount in ns.purchaseServer() 2022-01-03 17:00:32 -06:00
nickofolas
88db255f29 Fix whitespace in Bladeburner console 2022-01-03 16:42:49 -06:00
Olivier Gagnon
dfae337d26 Merge branch 'dev' of github.com:danielyxie/bitburner into dev 2022-01-03 15:49:05 -05:00
Olivier Gagnon
7655b91e2a rm some bullshit 2022-01-03 15:45:56 -05:00
hydroflame
0368456d1e Merge pull request #2313 from MartinFournier/fix/import-save
Fix import save issue with large files
2022-01-03 15:44:53 -05:00
hydroflame
8191716562 Merge pull request #2306 from MartinFournier/fix/storage-tooltip
Fix new lines in corp storage tooltip
2022-01-03 15:44:31 -05:00
hydroflame
3ceed8cf24 Merge pull request #2291 from Kebap/work_simultaneously
Mention doing things simultaneously
2022-01-03 15:44:24 -05:00
hydroflame
69ed320b93 Merge pull request #2287 from daanflore/dev
Saw in vscode that some typedefenitions where not the same as how they work in the game
2022-01-03 15:44:08 -05:00
hydroflame
8e0b5e3ecd Merge pull request #2288 from pan-kuleczka/dev
ns.hackAnalyze definition fix to match markdown
2022-01-03 15:43:48 -05:00
hydroflame
ea3a1e5a2a Merge pull request #2309 from erplsf/dev
fix ns.run args type definition
2022-01-03 15:43:29 -05:00
hydroflame
1372c28a1b Merge pull request #2312 from MartinFournier/feature/electron-toasts
Electron toasts & terminal access + information
2022-01-03 15:43:09 -05:00
hydroflame
b123d191c0 Merge pull request #2289 from nickofolas/patch-1
Update ns.toast() signature
2022-01-03 14:58:21 -05:00
hydroflame
82c963c04e Merge pull request #2315 from ApatheticsAnonymous/Clarify_server_ram_doc
Help clarify the behavior of server RAM to executing a script with mu…
2022-01-03 14:58:11 -05:00
ApatheticsAnonymous
df37f884ed Help clarify the behavior of server RAM to executing a script with multiple threads 2022-01-03 14:21:58 -05:00
Martin Fournier
dfabc0ac11 Fix import save issue with large files
The base64 regex was throwing a maximum stack size exceeded error with
large files.
The whole check was a bit redundant since we already try to parse the
file from base64 just below.
2022-01-03 11:02:29 -05:00
Martin Fournier
6c3618cb65 Check userAgent before running electron init 2022-01-03 10:33:58 -05:00
Martin Fournier
6d8df6744e Add toasts & terminal funcs to electron app
Attach functions to the window object so that the wrapper can executeJs
to display messages to the player
2022-01-03 10:32:01 -05:00
Martin Fournier
bdef14b029 Add API server information menu item 2022-01-03 10:29:56 -05:00
Andriy Mykhaylyk
38923af436 fix ns.run args type definition 2022-01-03 16:10:22 +01:00
Martin Fournier
057a229759 Fix new lines in corp storage tooltip
Use react fragments instead of strings so that the <br /> is not
escaped.
2022-01-03 09:31:07 -05:00
Kebap
5c57bd43f6 Mention doing things simultaneously 2022-01-02 22:20:45 +01:00
daan flore
8c851b577a Adding correct types at run args command 2022-01-02 20:40:57 +01:00
nickofolas
3ac26594db Update ns.toast() signature 2022-01-02 13:11:03 -06:00
daan flore
409fa29b65 Merge branch 'dev' of https://github.com/daanflore/bitburner-1 into dev 2022-01-02 19:24:19 +01:00
daan flore
74ee7f371d String value should also be possible to write 2022-01-02 19:24:16 +01:00
pan-kuleczka
62c19c9078 hackAnalyze definition fix to match markdown 2022-01-02 18:56:52 +01:00
daanflore
f1592a77fb Merge branch 'danielyxie:dev' into dev 2022-01-02 18:55:27 +01:00
daan flore
f8607ce73e Adding dorgotten typescript defenitions to file 2022-01-02 18:54:11 +01:00
Olivier Gagnon
d0214c1fed fix some weird eval 2022-01-02 12:41:54 -05:00
Olivier Gagnon
4fb1dbf2e3 fix some weird eval 2022-01-02 12:13:01 -05:00
Olivier Gagnon
1e0e9f7bd7 change button text 2022-01-02 11:55:06 -05:00
hydroflame
1819e5a98a Merge pull request #2247 from MartinFournier/feature/alert-close-browser
Add warning on game close if user launched external browser
2022-01-02 11:44:56 -05:00
hydroflame
a2d75ae10c Merge branch 'dev' into feature/alert-close-browser 2022-01-02 11:44:47 -05:00
hydroflame
cd9fad06d0 Merge pull request #2231 from ErzengelLichtes/use-numeraljs-for-ram
Use numeral.js to format memory, allow use of GiB with an option
2022-01-02 11:43:33 -05:00
hydroflame
d4eab92ed0 Merge pull request #2224 from MartinFournier/fix/joesguns-symbol
Update JoesGuns StockSymbols to match new key
2022-01-02 11:42:54 -05:00
hydroflame
93c833a211 Merge pull request #2238 from MartinFournier/feature/export-save-flag
Add electron launch option to directly export save game
2022-01-02 11:42:32 -05:00
hydroflame
29aca108fb Merge pull request #2237 from MartinFournier/fix/electron-handlers
Fix: Use global references for electron event handlers
2022-01-02 11:42:15 -05:00
hydroflame
01cb0cca81 Merge pull request #2227 from FaintSpeaker/alias-regex-not-matching-exactly
Alias command regular expression mismatch
2022-01-02 11:41:50 -05:00
hydroflame
a1ec54ff90 Merge pull request #2241 from billyvg/fix/vim-save
fix(editor): Fix vim mode quit and add `wq`
2022-01-02 11:40:40 -05:00
hydroflame
52c82f026c Merge pull request #2240 from JotaroS/stock-market-ui-fix
UI Fix: text style on Investopedia
2022-01-02 11:40:32 -05:00
hydroflame
b80cc31cb0 Merge pull request #2245 from MartinFournier/doc/electron
Add documentation for electron app build
2022-01-02 11:40:17 -05:00
hydroflame
a6be7ecc3e Merge pull request #2243 from TheMas3212/dev
Add Function Call signatures to ns.kill so typescript is able to call ns.kill correctly
2022-01-02 11:39:56 -05:00
hydroflame
1a07399312 Merge pull request #2248 from MartinFournier/feature/confirm-save-import
Add validation & confirm prompt for save import
2022-01-02 11:39:10 -05:00
hydroflame
8cfb355ca2 Merge pull request #2250 from MartinFournier/feature/backdoored-loc-tooltip
Add tooltip on backdoored location name
2022-01-02 11:38:01 -05:00
hydroflame
c5248fabb3 Merge pull request #2249 from MartinFournier/feature/add-themes
Add new community themes from discord
2022-01-02 11:37:51 -05:00
hydroflame
d53b87b8ce Merge pull request #2251 from MartinFournier/fix/corp-storage-tooltip
Fix #2129: Add linebreaks in corp storage tooltips
2022-01-02 11:37:45 -05:00
hydroflame
ca51e2144f Merge pull request #2253 from MartinFournier/fix/disable-alpha-color-picker
Remove alpha from color picker
2022-01-02 11:37:30 -05:00
hydroflame
c8667b5194 Merge pull request #2259 from jhollowe-forks/jhollowe-patch-1
Fix typo in AugmentationHelpers.tsx
2022-01-02 11:37:19 -05:00
hydroflame
4486d7d454 Merge pull request #2266 from TheMas3212/fix-1752
fixes #1752 add check when applying for job to make sure company actually has that job position
2022-01-02 11:36:44 -05:00
hydroflame
7f812f56d9 Merge pull request #2277 from pan-kuleczka/dev
Fixed ambiguous NS.hackAnalyze description
2022-01-02 11:36:14 -05:00
hydroflame
4810a9004d Merge pull request #2283 from jasonhaxstuff/patch-1
docs: update the markdown documentation for commitCrime()
2022-01-02 11:35:52 -05:00
hydroflame
b9b4ee23fe Merge pull request #2270 from thadguidry/patch-1
fix typo for @param host in getScriptRam()
2022-01-02 11:35:38 -05:00
Brandon Bothell
dd4b548917 docs: comma for good measure 2022-01-02 02:40:03 -05:00
Brandon Bothell
5aa08f4123 docs: commitCrime() return millseconds, not seconds 2022-01-02 02:37:25 -05:00
pan-kuleczka
8428264f05 Fixed ambiguous NS.hackAnalyze() description 2022-01-02 01:09:44 +01:00
Thad Guidry
4096ce4a9d fix typo for @param host in getScriptRam() 2022-01-01 14:08:45 -06:00
TheMas3212
1dcde649be fixes #1752 add check when applying for job to make sure company
actually has that job position
2022-01-02 03:08:16 +11:00
John Hollowell
2e0242ccbf Fix typo in AugmentationHelpers.tsx 2021-12-31 18:59:39 -05:00
Martin Fournier
59d8e1f979 Remove alpha from color picker
rgba is not currently supported in the themes, so might as well remove
the option from the picker.
2021-12-31 10:13:53 -05:00
TheMas3212
8707dc7079 remove extra function signature for ns.kill() 2021-12-31 23:33:23 +11:00
TheMas3212
e3e1770439 Fix Typedef for getScriptIncome/getScriptExpGain
Current Typedef does not allow using the run with no arguments for
totals versions
2021-12-31 23:31:46 +11:00
Martin Fournier
c6ec27781b Fix #2129: Add linebreaks in corp storage tooltips 2021-12-31 06:45:49 -05:00
Martin Fournier
50f41e79e6 Add tooltip on backdoored location name 2021-12-31 06:23:52 -05:00
Martin Fournier
2637653d29 Add new community themes from discord 2021-12-31 05:55:46 -05:00
Martin Fournier
2b7464ebb7 Add validation & confirm prompt for save import 2021-12-31 05:32:52 -05:00
Martin Fournier
b402cc7f6e Add warning on game close if user launched browser 2021-12-31 04:22:04 -05:00
Martin Fournier
2189c5b663 Add documentation for electron app build
Also adds a step in the build to run npm install in the electron
subfolder
2021-12-30 21:45:57 -05:00
TheMas3212
f3aed87fa4 Fix Typing on kill in NetscriptFunctions.ts
forgot to mark hostname as optional
2021-12-31 11:12:43 +11:00
TheMas3212
31ed5d8f64 Add Function Call signatures to ns.kill so typescript is able to call
ns.kill(pid)
previously it will fail to compile due to not providing a host argument
2021-12-31 10:58:56 +11:00
Billy Vong
38366e45db fix(editor): Fix vim mode quit and add "wq"
This changes `:q` to be quit (w/o saving) and added `:wq` to save *and* close.
2021-12-30 13:14:54 -05:00
JotaroS
351d4151bb fixed text style Investopedia 2021-12-30 18:50:22 +01:00
Martin Fournier
bc0791840f Add launch option to directly export save game
If --export-save is set, it will not launch the index.html and instead
launch a blank page. It then reads from the IndexedDb to fetch the
bitburnerSave value and prompts a save file dialog.
2021-12-30 11:51:15 -05:00
Martin Fournier
bf1a2b56ba Use global references for electron event handlers
I messed up the handlers reference in the last commit so the events
were not properly attached. Changed it to use global variables for now.
2021-12-30 09:12:55 -05:00
ErzengelLichtes
8f3da16ecf Use numeral.js to format memory, allow use of GiB with an option
numeral.js has a formatter for both kilobyte and kibibyte, so why use a custom formatter that only goes up to exabyte?
Also added a setting to allow people who really want to see GiB to enable that, even if it doesn't make sense.
2021-12-29 15:51:59 -08:00
hydroflame
b578e09986 Merge pull request #2218 from MartinFournier/feature/http-server-auth
Add authorization token to file system api
2021-12-29 14:26:16 -05:00
FaintSpeaker
d823b5f28f Update the addAlias/addGlobalAlias calls to fetch the correct capturing groups. 2021-12-29 14:04:58 -05:00
FaintSpeaker
7a0fdb9ce9 This regular expression expects 7 potential matches.
1: The whole string
2: the alias name
3 & 4: the command text in two locations
5 & 6: the quoted command text in two styles
7: the group that selects between the two qoted styles.
2021-12-29 13:56:26 -05:00
Martin Fournier
1b41e3326e Update JoesGuns StockSymbols to match new key 2021-12-29 12:03:29 -05:00
Olivier Gagnon
72d9770a8e Merge branch 'dev' of github.com:danielyxie/bitburner into dev 2021-12-29 12:02:23 -05:00
hydroflame
5c5cc9708d Merge pull request #2172 from theit8514/script-caching
Cache the blobs generated by scripts
2021-12-29 11:53:30 -05:00
hydroflame
636fc7cda0 Merge pull request #2204 from ErzengelLichtes/fix-port-validation
DRY: Consolidated the code for retrieving a port so it will have consistent errors checks.
2021-12-29 11:30:18 -05:00
Martin Fournier
a098289856 Refactor electron app into multiple files
Gracefully handle http-server start error & cleanup logs
2021-12-29 08:46:56 -05:00
Olivier Gagnon
383e56e9c8 floor thread count 2021-12-29 02:51:41 -05:00
hydroflame
91243f4742 Merge pull request #2213 from dou867/dev
fix joes guns org name and stock name do not match.
2021-12-29 02:25:51 -05:00
Olivier Gagnon
04f2cfe522 Merge branch 'dev' of github.com:danielyxie/bitburner into dev 2021-12-29 02:04:28 -05:00
Olivier Gagnon
0fc95e6215 text editor improvements 2021-12-29 02:04:24 -05:00
hydroflame
9673b6f31d Merge pull request #2170 from theit8514/mv-overwrite
Fix mv overwriting script files
2021-12-29 01:58:37 -05:00
hydroflame
3c3f482e7b Merge pull request #2153 from MartinFournier/fix/sleeves-skill-progress
Fix #2021: Handle sleeves xp in stats overview
2021-12-29 01:54:28 -05:00
Martin Fournier
5d7d72a3e2 Add authorization token to file system api 2021-12-28 15:37:22 -05:00
hydroflame
cc4f07d037 Merge pull request #2175 from Xynrati/patch-3
Removing old comment about removed parameter
2021-12-28 11:59:41 -05:00
hydroflame
6eb8b2adf9 Merge pull request #2214 from alkemann/patch-2
Fixed typo
2021-12-28 11:28:16 -05:00
Alexander Morland
aaf1ad4ae5 Fixed typo
needed to fix docs
2021-12-28 17:27:21 +01:00
Xynrati
ab5a2a8297 Update bitburner.ns.getweakentime.md 2021-12-28 08:07:56 -08:00
Xynrati
f98968f8b2 Update bitburner.ns.getgrowtime.md 2021-12-28 08:07:35 -08:00
dou
1b7a0224c5 fix joes guns org name and stock name do not match. 2021-12-29 03:06:37 +11:00
Xynrati
26ab62eea6 More comments to be removed 2021-12-28 08:04:50 -08:00
hydroflame
9f9ce40ef0 Merge pull request #2179 from antonvmironov/fix-CorporationInfo.state
Fix CorporationInfo.state
2021-12-28 10:37:42 -05:00
hydroflame
39e6c5ca35 Merge pull request #2177 from locriacyber/dev
Add peer dependencies for material-ui-color
2021-12-28 10:37:11 -05:00
hydroflame
39c7a7781a Merge pull request #2162 from mikomyazaki/concise_exp_job_gains
Concise exp job gains
2021-12-28 10:37:01 -05:00
hydroflame
f674d2d253 Merge pull request #2169 from maxtimum/feature/add_grep_option_to_ps
Feature/add grep option to ps
2021-12-28 10:35:26 -05:00
hydroflame
b27bb36a95 Merge pull request #2196 from sporkwitch/dev
Update parseAliasDeclaration to match single quote
2021-12-28 10:34:16 -05:00
hydroflame
329221a974 Merge pull request #2183 from MageKing17/patch-1
Get rid of console spam in NetscriptFunctions.ts
2021-12-28 10:34:01 -05:00
hydroflame
952ea89777 Merge pull request #2185 from MageKing17/patch-2
Allow shortcuts to work while doing unfocused work.
2021-12-28 10:33:16 -05:00
hydroflame
5aff5fc944 Merge pull request #2193 from Frank-py/patch-2
Updated Terminal.tsx to add keypress event.
2021-12-28 10:33:04 -05:00
hydroflame
d181ac4104 Merge pull request #2197 from ReeseJones/fixStockDoc
Changed setting to selling in getSaleGain
2021-12-28 10:32:37 -05:00
hydroflame
e583b46b16 Merge pull request #2202 from amclark42/help-analyze-typo-fix
Fix two typos in `help` command text
2021-12-28 10:32:19 -05:00
hydroflame
8b42703f95 Merge pull request #2199 from theit8514/log-window-improvements
Log window improvements
2021-12-28 10:32:04 -05:00
hydroflame
91d9549999 Merge pull request #2200 from 2PacIsAlive/dev
Fix "Terminal capacity" option description typo
2021-12-28 10:31:06 -05:00
hydroflame
a29ffead78 Merge pull request #2211 from anthonydroberts/buy-all-option
Add buy all option to buy terminal command
2021-12-28 10:30:54 -05:00
hydroflame
dd3ab9ca48 Merge pull request #2207 from mikomyazaki/scp-mem-docs
Fixes scp and mem helptext
2021-12-28 10:30:03 -05:00
hydroflame
c7657e5ec8 Merge pull request #2208 from Hedrauta/fix#2206
fix typo for #2206
2021-12-28 10:29:41 -05:00
hydroflame
0842aba6cf Merge pull request #2212 from alkemann/patch-1
Fixed typo
2021-12-28 10:29:01 -05:00
Alexander Morland
8b33f72703 Fixed typo 2021-12-28 11:01:22 +01:00
Tony Roberts
e9fd5f46eb Add buy all option to buy terminal command 2021-12-28 03:15:29 -05:00
Hedrauta
8aae2c9b7f fix typo for #2206 2021-12-28 03:54:04 +01:00
Andrew Cooper
33e4e31099 Fixes scp and mem helptext. 2021-12-28 00:54:35 +00:00
ErzengelLichtes
b13f146bc3 Changed writing specific text to be more generic 2021-12-27 11:36:14 -08:00
BrokenName
90ca9407d5 Update NetscriptFunctions.ts
Undid removal of writePort data validation
2021-12-27 10:38:00 -08:00
BrokenName
7c846abb65 DRY: Consolidated the code for retrieving a port so it will give consistent errors. 2021-12-27 10:06:38 -08:00
Ash Clark
58dd450aca Fix two typos in help command text 2021-12-27 11:47:02 -05:00
Jared Jolton
e3a9f9edab Fix "Terminal capacity" option description typo 2021-12-26 20:21:35 -07:00
theit8514
5607561c50 Add minimize button to log windows 2021-12-26 18:52:14 -05:00
theit8514
169d3e6c77 Add title attribute to log title bar 2021-12-26 17:47:32 -05:00
ReeseJones
1087db9f33 changed setting to selling in getSaleGain 2021-12-26 14:35:46 -08:00
Robert Klebes
6a9f6c05ec Update parseAliasDeclaration to match single quote
- Matches foo="bar" and foo='bar'
- Does not match foo="bar' or foo='bar"
2021-12-26 14:14:37 -05:00
Frank-py
a4eddb4691 Fixed typo in CONTRIBUTING.md file.
Changed naviguate to navigate.
2021-12-25 23:18:49 +01:00
Frank-py
73adc71965 Updated Terminal.tsx to add keypress event.
Added keypress event to delete the word after input by pressing "alt" + "d".
2021-12-25 23:11:21 +01:00
MageKing17
eb137455f5 Allow shortcuts to work while doing unfocused work.
A lot of people thought keyboard shortcuts weren't working because the code to make them stop working was only checking if the player was working without checking if the player was also focused. If doing unfocused work, there's no reason not to allow keyboard shortcuts to keep working.
2021-12-24 21:22:46 -08:00
MageKing17
a16cb745c5 Get rid of console spam in NetscriptFunctions.ts
This was filling up the console and making it hard to debug anything other than `exec` calls.
2021-12-24 19:34:34 -08:00
Anton Mironov
3dd818cb7b Updating doc for CorporationInfo.state
Now includes a list of possible values.
2021-12-24 17:35:23 +01:00
Anton Mironov
23683d3482 Fixes CorporationInfo.state
Before:
CorporationInfo.state was returning "[Object object]".

After:
CorporationInfo.state returns an actual state like START, PURCHASE, PRODUCTION, SALE, EXPORT
2021-12-24 17:32:51 +01:00
Locria Cyber
3b8bdb7449 Add peer dependencies for material-ui-color 2021-12-24 22:32:03 +08:00
Xynrati
072653674e Removing old comment about removed parameter
Because "no it don't"
2021-12-24 06:11:45 -08:00
maxtimum
07b00bc377 add -g, --grep flags to ps command, documentation 2021-12-23 22:31:07 -08:00
maxtimum
f28ddd3b3f update docs for -g flag 2021-12-23 21:39:34 -08:00
theit8514
fd93c6d338 Fix linting errors 2021-12-23 23:26:05 -05:00
theit8514
8f77f720e6 Cache the blobs generated by scripts 2021-12-23 23:06:01 -05:00
hydroflame
d99b03d12e Merge pull request #2164 from Hedrauta/fix#2155
fix docu for #2155
2021-12-23 21:47:19 -05:00
theit8514
2d949c076b Fix mv overwriting script files 2021-12-23 21:31:59 -05:00
maxtimum
13e68ba48e update documentation for ps 2021-12-23 17:43:52 -08:00
maxtimum
deb6d6cc0a add option to pass grep pattern to ps 2021-12-23 17:39:45 -08:00
Hedrauta
3eedd9df88 empty host = current host 2021-12-24 00:23:38 +01:00
Olivier Gagnon
ed86577d6c imports are more flexible 2021-12-23 15:57:32 -05:00
Olivier Gagnon
16c51e8e8e Merge branch 'dev' of github.com:danielyxie/bitburner into dev 2021-12-23 15:35:45 -05:00
Olivier Gagnon
87d6c18254 ext push now save folder correctly 2021-12-23 15:34:01 -05:00
Andrew Cooper
12ba68a375 XP gain summaries now only show non-zero xp gains. 2021-12-23 19:15:39 +00:00
Andrew Cooper
4861ac4153 Fixes penalty message for quitting work early. 2021-12-23 19:15:22 +00:00
hydroflame
b33af9df20 Merge pull request #2150 from Hedrauta/new-Editor-theme_dracula
New Editor Theme: Dracula ( from VSCode )
2021-12-23 13:36:16 -05:00
Olivier Gagnon
fcb876695d remove leading slash when saving via http 2021-12-23 12:23:50 -05:00
hydroflame
0bddb7d349 Merge pull request #2152 from MartinFournier/fix/kill-rendering-process
Crash render process when javascript won't execute
2021-12-23 12:04:35 -05:00
Martin Fournier
6458440193 Fix #2021: Handle sleeves xp in stats overview 2021-12-23 09:11:08 -05:00
Martin Fournier
ea03889082 Crash render process when javascript won't execute
Prevents the renderer process staying up when the user scripts are
waiting for an unresolved promise.
2021-12-23 07:48:01 -05:00
Hedrauta
693c6480a0 as close as possible
Sadly, i can't color specific variables, because of monaco itself.
Did my best for this. 😉
2021-12-23 07:27:58 +01:00
hydroflame
c056ef2854 Merge pull request #2145 from mikomyazaki/2137-run-cct
Helptext for run now mentions coding contracts
2021-12-22 23:20:27 -05:00
hydroflame
eee72aa8d2 Merge pull request #2148 from TheMas3212/dev
modify BasicHGWOptions definition to mark threads parameter as optional
2021-12-22 22:56:23 -05:00
TheMas3212
e0aaa383a4 modify BasicHGWOptions definition to mark threads parameter as optional
this is used by hack, grow and weaken all of which dont require it to be defined
2021-12-23 14:42:06 +11:00
Andrew Cooper
7805b72457 'help run' docs now mentions coding contracts. 2021-12-23 01:23:57 +00:00
Olivier Gagnon
88151efa61 ext use base64 2021-12-22 19:56:43 -05:00
hydroflame
795f8b4d2b Merge pull request #2140 from danielyxie/mychanges
mychanges
2021-12-22 19:19:39 -05:00
hydroflame
bfdfee2a68 Merge branch 'dev' into mychanges 2021-12-22 16:16:24 -05:00
Olivier Gagnon
d2d6c33fc8 mychanges 2021-12-22 16:15:56 -05:00
hydroflame
dce7217fc5 Merge pull request #2062 from MartinFournier/fix/dangling-process
Handle electron process uncaught exceptions
2021-12-22 15:30:33 -05:00
Martin Fournier
6363c704db Handle electron process uncaught exceptions
Handling the exceptions and closing the app seem to properly kill the
dangling processes that appear at launch in Windows 10. Without this, if
an exception is throw before the window is active (ie: no
steamapp_id.txt file), there will be remaining processes.

Added electron-log to additionally log to a text file.
2021-12-22 15:28:55 -05:00
hydroflame
9ea66e8743 Merge pull request #2110 from MartinFournier/feature/themes
Add community themes from discord
2021-12-22 15:22:08 -05:00
hydroflame
7c599f2005 Merge pull request #2123 from MartinFournier/feature/reload-unresponsive
Add dialog when app is unresponsive to reload
2021-12-22 15:21:58 -05:00
hydroflame
fba2265cce Merge pull request #2118 from Icehawk78/feat/add-ns2-examples-docs
Add ns2 examples to the netscript docs
2021-12-22 15:21:06 -05:00
Martin Fournier
9ce8bdd29b Add dialog when app is unresponsive to reload
Checks the electron event 'unresponsive' and triggers a reload / cancel
dialog. Allows all scripts to be killed, checked by default.
Also adds a warning to the terminal when noScript has been executed.
2021-12-22 15:14:03 -05:00
Nicholas Galauxy
35cfa9492e Fix unintended spacing change 2021-12-22 13:38:32 -06:00
Nicholas Galauxy
ed4d4d091c Update docs to include NS2 examples 2021-12-22 13:36:44 -06:00
hydroflame
a97d2a93cb Merge pull request #2112 from theit8514/cp-2099
Fix cp from another folder to current folder
2021-12-22 14:30:29 -05:00
hydroflame
dbf8c788e0 Merge pull request #2111 from mikomyazaki/2027-documentation-updates
Documentation updates
2021-12-22 14:30:14 -05:00
hydroflame
76d67fdba5 Merge pull request #2113 from Xynrati/patch-2
Add ns2 example for scp
2021-12-22 14:30:05 -05:00
Martin Fournier
f2141dd83d Add community themes from discord 2021-12-22 13:54:04 -05:00
Xynrati
21ac94dbb3 Add ns2 example for scp 2021-12-22 09:38:21 -08:00
theit8514
06ec11a107 Fix cp from another folder to current folder
src is already passed through getFilepath. Doing it again roots the file in the current directory.
2021-12-22 12:34:08 -05:00
Andrew Cooper
c2e5c9f371 Documentation updates to getgrowtime, gethacktime, getweakentime, hack, hackanalyze and weaken. 2021-12-22 17:25:09 +00:00
hydroflame
7260d5fe35 Merge pull request #2100 from mikomyazaki/empty-editor-to-terminal
Closing the final script in your editor will take you to the terminal
2021-12-22 12:17:32 -05:00
hydroflame
366bffad85 Merge pull request #2098 from FOLLGAD/patch-2
Fix incorrect help entry for "weaken" command
2021-12-22 12:17:11 -05:00
hydroflame
1c7b0ab9a3 Merge pull request #2101 from Hedrauta/fix_commiitCrime_docu_description
Fix for ns.commitCrime description in the Documentation
2021-12-22 12:16:08 -05:00
hydroflame
ce0fb7a383 Merge pull request #2102 from mikomyazaki/2023-hack-analyze-threads-no-money
hackAnalyzeThreads will no longer return NaN under some circumstances
2021-12-22 12:14:57 -05:00
hydroflame
91ac40efd0 Merge pull request #2106 from MartinFournier/fix/ci
Split GitHub workflow into multiple jobs to get clearer results
2021-12-22 12:14:46 -05:00
hydroflame
e83c38b5fb Merge pull request #2103 from mikomyazaki/dev-options-add-minimise-server-money
Adds dev options to set server(s) cash to zero
2021-12-22 12:14:31 -05:00
hydroflame
50a85b61e2 Merge pull request #2109 from hexnaught/remove-timestamp-newline-buy-list-patch
fix(command:buy) don't wrap in typography
2021-12-22 12:05:39 -05:00
Dan
64dea97e3c fix(command:buy) don't wrap in typography
Warpping the output in typography inserts a newline before/after, this fine until timestamps are enabled and the components don't fall inline, and the typography newline is then visible.

Resolves danielyxie/bitburner#2108
2021-12-22 13:27:06 +00:00
Martin Fournier
d6c1f3bfca Split CI into multiple jobs to get clearer results 2021-12-22 04:45:16 -05:00
Martin Fournier
6b59a58ea3 Fix linter errors 2021-12-22 04:44:07 -05:00
Andrew Cooper
17b11f107f hackAnalyzeThreads will return zero instead of NaN when checking the effect of zero threads on a server with zero cash. 2021-12-22 01:12:45 +00:00
Andrew Cooper
7baacf4e1b Adds dev options to set server cash to zero. 2021-12-22 01:12:08 +00:00
Hedrauta
7f3f5c7648 commitCrime will return milliseconds 😉 2021-12-22 02:00:22 +01:00
Andrew Cooper
f2bdf00aba Closing the final script in your editor will take you to the terminal. 2021-12-22 00:26:01 +00:00
Emil Ahlbäck
e7e1e82394 Update HelpText.ts 2021-12-21 22:16:12 +01:00
Olivier Gagnon
ea0be338e1 dont make new copies when injecting via localhost 2021-12-21 15:40:23 -05:00
Olivier Gagnon
b2b682fa04 fix editor not loading files 2021-12-21 13:44:18 -05:00
Olivier Gagnon
41593e0dce fix editor not loading 2021-12-21 12:02:06 -05:00
hydroflame
79eb2f7e0b Merge pull request #2092 from theit8514/script-focus-v2
Add focus parameter to workForCompany/workForFaction
2021-12-21 11:02:26 -05:00
hydroflame
5021013cb7 Merge pull request #2078 from billyvg/feat/open-multiple-files-from-cli
feat: open multiple files from cli
2021-12-21 11:02:11 -05:00
hydroflame
c1c7131545 Merge branch 'dev' into feat/open-multiple-files-from-cli 2021-12-21 11:02:06 -05:00
hydroflame
81e3f2afd1 Merge pull request #1986 from billyvg/feat/add-vim-command
feat: add `vim` terminal command
2021-12-21 11:00:33 -05:00
hydroflame
f01b12a56a Merge pull request #2095 from MartinFournier/fix/bladeburner
Bladeburner console fixes & command checks
2021-12-21 10:59:47 -05:00
hydroflame
26106fa71d Merge pull request #2077 from MartinFournier/feature/get-theme
Add ns.ui.getTheme() api function
2021-12-21 10:57:58 -05:00
hydroflame
4be5e45740 Merge pull request #2073 from billyvg/fix/window-resizing
fix: Update editor height when resizing window
2021-12-21 10:56:51 -05:00
hydroflame
94d695bb12 Merge pull request #2082 from MartinFournier/fix/purchase-server-test
Fix tests by passing args to dynamic function test
2021-12-21 10:50:05 -05:00
hydroflame
1830287a6e Merge pull request #2079 from sschmidTU/dev
Fix typo (order -> orders)
2021-12-21 10:49:33 -05:00
hydroflame
7a9e8936ee Merge pull request #2083 from 65-7a/txt-file-editor-patch
Script editor fixes for .txt files
2021-12-21 10:49:08 -05:00
hydroflame
4183ed6f2b Merge pull request #2087 from 2PacIsAlive/dev
Fix typo on Augmentations page
2021-12-21 10:45:55 -05:00
hydroflame
ede6be3d0d Merge pull request #2085 from hexnaught/get-player-ramcost-doc-patch
docs(ns.getPlayer): update doc to have ram cost
2021-12-21 10:45:34 -05:00
Martin Fournier
2d269c7a4e Fix #2018: Blade console check blackops order
Prevents you from running blackops if you have not completed the
preceeding one.
2021-12-21 10:13:12 -05:00
theit8514
d873f7279b Add focus parameter to workForCompany/workForFaction
Defaults to true to keep previous behavior.
2021-12-21 08:13:18 -05:00
Martin Fournier
dbe36fd6b7 Fix #1916: Check blade console blackops rank
This prevents the player from starting a blackops without having the
rank requirements
2021-12-21 07:48:09 -05:00
Martin Fournier
f2ccc63b2d Fix #1915: Check blade console skill max level
Prevents you from leveling up a skill past its max level.
2021-12-21 07:48:09 -05:00
Martin Fournier
1427993a25 Fix #1901: Fix blade console command history
Up or down would not properly update the visible input value
2021-12-21 07:48:09 -05:00
Martin Fournier
0b71a83cfe Fix blade console input visibility on scroll
Before this, when scrolling up the input would be hidden.
2021-12-21 07:38:39 -05:00
Jared Jolton
bd375851a4 Fix typo on Augmentations page 2021-12-20 22:28:55 -07:00
Dan
8ccb128e6f docs(ns.getPlayer): update doc to have ram cost
Resolves danielyxie/bitburner#2084
2021-12-21 01:44:32 +00:00
65-7a
a6aebd4a29 Change model to plaintext for txt files 2021-12-21 10:35:03 +11:00
65-7a
56e540802b Disable RAM calculation for txt files 2021-12-21 10:21:22 +11:00
Martin Fournier
99f1e67224 Fix tests by passing args to dynamic function test
Function purchaseServer would throw with null arguments
2021-12-20 17:37:56 -05:00
Billy Vong
bb2f8e883c feat: Support opening multiple files from command line 2021-12-20 16:55:17 -05:00
sschmidTU
9a1437559a fix typo (order -> orders) 2021-12-20 22:39:33 +01:00
Billy Vong
d30edc7f59 feat: Add vim terminal command 2021-12-20 16:20:50 -05:00
Olivier Gagnon
009bae5870 catch scripts taht end too early 2021-12-20 16:06:19 -05:00
Olivier Gagnon
b57ac45698 doc 2021-12-20 15:59:46 -05:00
Olivier Gagnon
41a7109baa fix 2021-12-20 15:48:26 -05:00
Martin Fournier
65d0877edc Add ns.ui.getTheme() api function 2021-12-20 14:37:10 -05:00
Olivier Gagnon
ddd0eaaf5c weaken message 2021-12-20 14:13:56 -05:00
Billy Vong
63891351be remove TODO 2021-12-20 14:05:59 -05:00
Billy Vong
60749eefa7 remove console + format 2021-12-20 14:05:22 -05:00
Billy Vong
ee177393fa fix: Update editor height when resizing window 2021-12-20 14:04:42 -05:00
Olivier Gagnon
4ec021c8f0 cores explanation 2021-12-20 14:03:25 -05:00
Olivier Gagnon
e9886cc6bc fix uncaught promise 2021-12-20 13:57:07 -05:00
Olivier Gagnon
5dc9ac040a toast time config 2021-12-20 13:29:04 -05:00
hydroflame
25f78f2b30 Merge pull request #1984 from billyvg/feat/add-vim-mode
feat: Add vim mode to script editor
2021-12-20 12:03:05 -05:00
hydroflame
df265df9ce Merge pull request #2070 from hexnaught/show-owned-in-buy-list-patch
feat(command:buy): show owned items in buy list
2021-12-20 12:02:07 -05:00
Dan
388a3f56c3 feat(command:buy): show owned items in buy list
Just a little output change when you `buy -l`, to show you which items
you already own.
I couldn't access the theme when importing it here for use, it kept
crashing the app so the [OWNED} shows up always as green.. Which isn't
the end of the world considering the money always shows up in Yellow.
I think this area of code/output could do with a little bit of love at
some point.

Resolves danielyxie/bitburner#2069
2021-12-20 16:51:08 +00:00
Billy Vong
3fd904ff87 format 2021-12-20 10:48:32 -05:00
Billy Vong
6641ca9c73 fix ts 2021-12-20 10:45:44 -05:00
Billy Vong
517066a710 fix missed conflicts 2021-12-20 10:44:17 -05:00
Billy Vong
d372166c8b Merge branch 'dev' into feat/add-vim-mode 2021-12-20 10:36:58 -05:00
hydroflame
00b3cb61f4 Merge pull request #2065 from JJTech0130/patch-1
Disable Jekyll in GitHub Pages builds
2021-12-20 10:20:18 -05:00
hydroflame
8be201cd93 Merge pull request #2064 from MartinFournier/feature/focus-editor-on-open
Give focus to editor when opening or changing tabs
2021-12-20 10:19:14 -05:00
hydroflame
ab0ed5d6a4 Merge pull request #2061 from 65-7a/allow-cat-on-scripts-patch
Allow cat to work on scripts
2021-12-20 10:18:17 -05:00
hydroflame
87bf23b6f4 Merge pull request #2063 from MartinFournier/fix/lint
Linting ScriptEditor
2021-12-20 10:00:12 -05:00
JJTech0130
afdac4e9cc Disable Jekyll in GitHub Pages builds 2021-12-20 07:26:20 -05:00
Martin Fournier
e60996b86c Focus editor when opening or changing tabs 2021-12-20 07:15:53 -05:00
Martin Fournier
08a4a1649f Linting ScriptEditor 2021-12-20 07:01:34 -05:00
65-7a
3df0fd3945 Add script files to tab completion for cat 2021-12-20 21:11:58 +11:00
65-7a
14532cd0a8 Allow cat to work on scripts 2021-12-20 21:11:28 +11:00
Olivier Gagnon
f72d4b89d4 text editor improvements 2021-12-20 03:02:23 -05:00
hydroflame
53ce11c33a Merge pull request #2044 from Rez855/feature/multi-tab-script-editor
Script Editor Refactor
2021-12-20 02:45:57 -05:00
BuildTools
302af48be4 Fixed merge conflict 2021-12-20 01:44:51 -06:00
BuildTools
6d90025370 Adapted PR #2055 to the refacted script editor code 2021-12-20 01:40:01 -06:00
BuildTools
e5c4c8f64b Rebased
Added hostname to tab name
Removed -tas arg from the rm command
2021-12-20 01:40:01 -06:00
BuildTools
9c19ddf6a7 fixed git issue 2021-12-20 01:40:01 -06:00
BuildTools
cbfdfa5753 Removed testing log statements 2021-12-20 01:40:01 -06:00
BuildTools
3120d97cfa Update 2021-12-20 01:40:01 -06:00
BuildTools
6dc7dc42c5 resolved merge issue 2021-12-20 01:39:20 -06:00
hydroflame
3255768259 Merge pull request #1993 from Nick-Colclasure/file-read-patch
Fix problems finding root files in cat and ns.read
2021-12-20 01:56:20 -05:00
hydroflame
7215e73f41 Merge pull request #2055 from hexnaught/s-key-editor-save-patch
Change editor save keybind to be CTRL/CMD + S
2021-12-20 01:50:05 -05:00
hydroflame
e4345ebf68 Merge pull request #2057 from hexnaught/remove-partial-exe-on-buy-patch
Remove any partially built/created .EXE files on buy from darknet
2021-12-20 01:08:07 -05:00
hydroflame
2267845e2d Merge pull request #2049 from Kejikus/dev
Issue #2048 fix
2021-12-20 01:07:12 -05:00
Dan
b95261d905 fix(darkweb:buy) remove partial exe on buy
Remove any matching partial .exe item when buying it from the dark web.

Resolves danielyxie/bitburner#2024
2021-12-20 05:55:35 +00:00
Dan
6ec7fcb9fa refactor(keybinds): change editor save keybind S
We need to stop the event from bubbling up to the browser and opening a
'save html' window to keep support in the browser, other than that,
straight forward change to swap keybinding to 'S' for saving in the
editor.

Resolves danielyxie/bitburner#2053
2021-12-20 04:34:27 +00:00
hydroflame
82f6bbee13 Merge pull request #2046 from MartinFournier/fix/tests
Fix jest unit tests & add a github action workflow to build, test & lint
2021-12-19 22:35:25 -05:00
hydroflame
565e7677f8 Merge pull request #2045 from 2PacIsAlive/dev
Fix typo for Neuregen Augmentation
2021-12-19 22:33:31 -05:00
hydroflame
d1abe27484 Merge pull request #2047 from TheCoderJT/nuke-github-clarity
Fix Docs: made it more clear what nuke exe does
2021-12-19 22:32:41 -05:00
hydroflame
7710ae5564 Merge pull request #2050 from MageKing17/patch-1
Update NetscriptFunctions.ts
2021-12-19 22:32:02 -05:00
MageKing17
e521415273 Update NetscriptFunctions.ts
Just a simple change to make `alert` and `toast` reuse `argsToString` instead of `toNative` and `JSON.stringify` directly.

Fixes #2015.
2021-12-19 16:58:49 -08:00
Nicholas Colclasure
61dde4cfac Fix issue introduced handling files in subdirectories ._. 2021-12-19 13:03:50 -08:00
Kejikus
fcbf8a3824 Fixed bug with limited height of terminal screen
Needs testing.
2021-12-20 00:03:13 +03:00
Jordan Turner
f678574a6c made it more clear what nuke exe does 2021-12-19 13:47:34 -07:00
Martin Fournier
8b355c365e Add github workflow to run tests, linter & build 2021-12-19 15:43:13 -05:00
Martin Fournier
2bbb767575 Fix remaining unit test issues 2021-12-19 15:42:40 -05:00
Jared Jolton
06acccdfe1 Fix typo for Neuregen Augmentation 2021-12-19 13:42:09 -07:00
Martin Fournier
3b99da8474 Lint current problems & fix ignore paths 2021-12-19 13:17:44 -05:00
Martin Fournier
92e8b42d18 Fix renamed functions from 1.0 release in tests 2021-12-19 12:37:42 -05:00
Martin Fournier
d1696148c4 Fix tests syntax for jest
Most tests could not run with jest because of syntax difference between
the old test runner.
2021-12-19 12:37:42 -05:00
hydroflame
890b1df593 Merge pull request #2041 from hexnaught/job-shortcut-key-patch
Only run job shortcut if the player has a job
2021-12-19 10:28:42 -05:00
hydroflame
3ed5aa8045 Merge pull request #2038 from MartinFournier/fix/skill-progress
Fix skills tooltip edge cases
2021-12-19 10:22:43 -05:00
Dan
2f9eb324b4 fix(shortcut): job shortcut only run when have job
The shortcut was always allowed to run, meaning when the player doesn't
have a job, they were sent to the job screen with no job and lost the
view context/sidebar.

- Add utility method to check if the player 'hasJob', being at least 1
job.
- Check if player has job when the key combination is pressed

Resolves danielyxie/bitburner#2013
2021-12-19 15:20:02 +00:00
hydroflame
8c2b969026 Merge pull request #2036 from millennIumAMbiguity/patch-2
Improve the readability of text in the theme editor.
2021-12-19 10:13:57 -05:00
hydroflame
29f1bed823 Merge pull request #2037 from millennIumAMbiguity/patch-3
Fixed grammar issues in NS.purchaseServer()
2021-12-19 10:13:44 -05:00
Martin Fournier
05ed3f5461 Fix skills tooltip edge cases 2021-12-19 05:51:35 -05:00
millennIumAMbiguity
69fda94808 Fixed grammar issues in NS.purchaseServer()
Removed the article: the it will -> it will
Changed the quantifier: the amount of servers -> the number of servers
2021-12-19 11:30:44 +01:00
millennIumAMbiguity
a9cf635a84 Improve the readability of text in the theme editor.
Copy the string above if you want to backup or share your theme with others. -> Backup your theme or share it with others by copying the string above.
Use the buttons below to replace the current theme with a pre-built template -> Replace the current theme with a pre-built template using the buttons below.
2021-12-19 11:14:16 +01:00
Olivier Gagnon
efc3992c78 Merge branch 'dev' of github.com:danielyxie/bitburner into dev 2021-12-19 00:44:03 -05:00
Olivier Gagnon
76890ad1b9 update doc 2021-12-19 00:43:58 -05:00
hydroflame
3a21beb708 Merge pull request #2003 from MartinFournier/feature/predetermined-themes
Add easily switchable predefined themes
2021-12-19 00:40:59 -05:00
hydroflame
a76f67ade5 Merge pull request #2010 from hexnaught/server-purchase-naming-patch
Fix issue of space in server name and server counting when made with same name
2021-12-19 00:35:24 -05:00
hydroflame
24f0c9e65d Merge pull request #2007 from hexnaught/alias-hyphen-allowed-patch
Allow hyphens in command aliases
2021-12-19 00:28:11 -05:00
hydroflame
e6b84a73b2 Merge pull request #2031 from MageKing17/patch-1
Update ls.tsx
2021-12-19 00:24:58 -05:00
hydroflame
b6df183953 Merge pull request #2008 from hexnaught/lowercase-exe-call-patch
Allow `.exe` (programs) to be ran in a case-insensitive `run`
2021-12-19 00:23:52 -05:00
hydroflame
f5f206561c Merge pull request #2009 from hexnaught/script-exists-command-errors-patch
Better feedback when looking for a running script.
2021-12-19 00:23:30 -05:00
hydroflame
1ea8c62d4f Create check.ts 2021-12-19 00:23:10 -05:00
hydroflame
bc7f94ddda Update check.ts 2021-12-19 00:23:01 -05:00
MageKing17
1dcc17c4fb Update ls.tsx
`args[numArgs - 1]` is the last argument in the list, so correct usage was being flagged as incorrect, and incorrect usage wasn't working anyway because the filter was `"undefined"`.

Additionally, the function seemed confused as to whether or not `ls` counted as an argument (AFAICT, it isn't).

Fixes #1994.
2021-12-18 21:22:34 -08:00
Dan
6d79561859 fix(servers): fix issue of space in server name
Replace the space in a server name with a hyphen (-), also noticed some
interesting behaviour with the 'count up naming', so tweaked that.

Resolves danielyxie/bitburner#1999
2021-12-19 04:03:14 +00:00
Dan
b8b3897e64 fix(commands): tweak wording for consistency 2021-12-19 03:23:26 +00:00
Dan
b2add6c26b fix(commands): error feedback, wording consistency
Found most (hopefully all) places where the error message wording
incorrectly was shown to the tune of 'no script exists', where it should
have been showing to the effect of 'script is not running'.
Also cleaned up some of the consistency in the wording and added a
'helper' export for knowing valid script extensions used in validation
of 'isScriptFilename', so we can have consistent error messaging.

Resolves danielyxie/bitburner#1966
2021-12-19 03:10:43 +00:00
Dan
24c7fb2b92 fix(cli:run) case insensitive calls to program run
Allow the user to run programs (.exe) in a case insensitive manor

Resolves danielyxie/bitburner#1958
2021-12-19 02:41:21 +00:00
Dan
1f6954b393 fix(command:alias) allow hyphen in aliases
- Allow hyphens in aliases
- Remove redundant underscore, covered by '\w'

Resolves danielyxie/bitburner#2000
2021-12-19 02:09:47 +00:00
Olivier Gagnon
790ffeb8a1 Merge branch 'dev' of github.com:danielyxie/bitburner into dev 2021-12-18 18:15:19 -05:00
Olivier Gagnon
555216a39b Add confirmation to installing 2021-12-18 18:13:49 -05:00
hydroflame
aad4024e0f Merge branch 'master' into dev 2021-12-18 16:29:22 -05:00
Martin Fournier
db64d9869c Add easily switchable predefined themes
Includes the default theme and a Monokai-ish variant
2021-12-18 16:28:15 -05:00
hydroflame
eec9fbf997 Merge pull request #1989 from Xynrati/patch-1
Incorrect threadcount for n00dles
2021-12-18 10:56:41 -05:00
Nicholas Colclasure
8ba5199e54 Fix problems finding root files in cat and ns.read
Cat ends up translating the path it receives from relative to absolute twice, which I fix by changing the filename to an absolute path before it's passed to getTextFile with a leading "/" so that it doesn't interpret the filename as being relative.

Read I fixed by causing getTextFile to remove the leading "/" from files that are in the root directory, since that is required to translate their name into the native "filesystem"s format.
2021-12-17 20:40:46 -08:00
Xynrati
160682f25a Incorrect threadcount for n00dles 2021-12-17 18:12:46 -08:00
hydroflame
ecc650576e Merge pull request #1967 from 2PacIsAlive/patch-1
Fix typo in sleeves.rst
2021-12-17 12:57:57 -05:00
Billy Vong
b3f9380ebd prettier 2021-12-17 12:56:48 -05:00
Billy Vong
6fb5565b08 remove unused code 2021-12-17 12:48:50 -05:00
Billy Vong
cdd85c09e1 Merge branch 'dev' into feat/add-vim-mode 2021-12-17 12:38:16 -05:00
Billy Vong
fb5d374279 feat: Add vim mode to script editor
This adds an option to turn on vim mode using the `monaco-vim` library.
2021-12-17 12:34:00 -05:00
Jared Jolton
c4bd6d8e11 Fix typo in sleeves.rst 2021-12-17 00:09:52 -07:00
hydroflame
88666ec3fa Merge pull request #1953 from danielyxie/dev
doc
2021-12-16 15:30:22 -05:00
hydroflame
c080f367b8 Merge pull request #1950 from danielyxie/dev
regen doc
2021-12-16 12:59:52 -05:00
hydroflame
c38992be8d Merge pull request #1949 from danielyxie/dev
build
2021-12-16 12:58:30 -05:00
hydroflame
9346979e2b Merge pull request #1943 from Hedrauta/master
fix for a typo at "Spiralize Matrix"s description
2021-12-16 12:30:41 -05:00
Hedrauta
9e9a1ca882 Update codingcontracttypes.ts 2021-12-16 16:05:46 +01:00
hydroflame
a8f764bb8c Merge pull request #1879 from danielyxie/dev
bugfix
2021-12-14 15:56:31 -05:00
hydroflame
dfdb940aa6 Merge pull request #1872 from danielyxie/dev
doc fix
2021-12-13 15:00:33 -05:00
hydroflame
154f467935 Merge pull request #1866 from danielyxie/dev
getServer of hacknet doesn't return undefined
2021-12-12 13:48:39 -05:00
hydroflame
7e474da3fe Merge pull request #1865 from danielyxie/dev
many fixes
2021-12-12 13:30:41 -05:00
hydroflame
12114f0146 Merge pull request #1850 from danielyxie/dev
boost noodle bar
2021-12-09 16:49:27 -05:00
hydroflame
246e088365 Merge pull request #1849 from danielyxie/dev
nerf manualHack int gain but differently
2021-12-09 16:32:20 -05:00
hydroflame
638e0e8a13 Merge pull request #1848 from danielyxie/dev
regen doc
2021-12-09 16:26:57 -05:00
hydroflame
d86986555c Merge pull request #1847 from danielyxie/dev
formulas for ascension
2021-12-09 12:53:04 -05:00
hydroflame
1d046d7d87 Merge pull request #1846 from danielyxie/dev
tighten bn13
2021-12-09 10:45:53 -05:00
hydroflame
b326bd26bc Merge pull request #1845 from danielyxie/dev
make BN13 harder
2021-12-09 10:16:09 -05:00
hydroflame
3cdb73be6c Merge pull request #1844 from danielyxie/dev
Added option to suppress TIX limit/stop orders
2021-12-08 20:21:59 -05:00
hydroflame
4c88ab7794 Merge pull request #1843 from danielyxie/dev
corp doc
2021-12-08 20:03:44 -05:00
hydroflame
30af70c4ab Merge pull request #1842 from danielyxie/dev
Formulas doc
2021-12-08 19:19:42 -05:00
hydroflame
63c5387cfe Merge pull request #1841 from danielyxie/dev
rename functions I just created
2021-12-08 18:42:07 -05:00
hydroflame
6b0c4471a6 Merge pull request #1840 from danielyxie/dev
formulas for gang stuff
2021-12-08 18:19:58 -05:00
hydroflame
beaa60c967 Merge pull request #1837 from danielyxie/dev
few bugfix
2021-12-08 17:39:17 -05:00
hydroflame
aa7cf7469e Merge pull request #1824 from danielyxie/dev
add bn14 location
2021-12-04 23:50:00 -05:00
hydroflame
fa1dd4d0cf Merge pull request #1823 from danielyxie/dev
rm tail bound
2021-12-04 18:58:42 -05:00
hydroflame
181b7f39e5 Merge pull request #1822 from danielyxie/dev
corp api
2021-12-03 23:08:30 -05:00
hydroflame
a48cd2f1b4 Merge pull request #1819 from danielyxie/dev
wd diff increase
2021-12-03 16:28:00 -05:00
hydroflame
403ab167b5 Merge pull request #1817 from danielyxie/dev
BN13: They're Lunatics
2021-12-03 16:14:51 -05:00
hydroflame
043aaeab8a Merge pull request #1814 from danielyxie/dev
many bugfix
2021-12-03 15:31:41 -05:00
hydroflame
cf11def6b9 Merge pull request #1813 from danielyxie/dev
many bugfix
2021-12-03 14:12:47 -05:00
hydroflame
ff4bcb26f4 Merge pull request #1810 from danielyxie/dev
fix log isue
2021-12-03 13:55:03 -05:00
hydroflame
1e9cf015e9 Merge pull request #1809 from danielyxie/dev
getOwnedSF is not sing anymore
2021-12-02 12:43:29 -05:00
hydroflame
326cd5afa0 Merge pull request #1804 from danielyxie/dev
community fixes
2021-11-30 11:15:09 -05:00
hydroflame
ff8cd8b3e2 Merge pull request #1798 from danielyxie/dev
Buncha fix
2021-11-27 11:45:06 -05:00
hydroflame
01a6dd7aab Merge pull request #1787 from danielyxie/dev
Scripting stuff
2021-11-25 11:47:56 -05:00
hydroflame
c2b58ffcce Merge pull request #1781 from danielyxie/dev
gang with 0 territory cannot fight
2021-11-24 17:58:37 -05:00
hydroflame
f42bc288a6 Merge pull request #1780 from danielyxie/dev
Prevent browser back
2021-11-24 16:15:55 -05:00
hydroflame
d6cbca94bd Merge pull request #1764 from danielyxie/dev
few bugfix
2021-11-22 11:36:34 -05:00
hydroflame
d169d2af4c Merge pull request #1759 from danielyxie/dev
fix tprintf printing filename
2021-11-20 15:01:33 -05:00
hydroflame
ac74d6a46b Merge pull request #1751 from danielyxie/dev
fix some coloring stuff
2021-11-19 23:55:21 -05:00
hydroflame
41592a199a Merge pull request #1750 from danielyxie/dev
fix tprintf catching errors
2021-11-19 22:58:56 -05:00
hydroflame
7764afaf31 Merge pull request #1748 from danielyxie/dev
v1.0.2
2021-11-19 15:50:51 -05:00
hydroflame
73bbf4d454 Merge pull request #1743 from danielyxie/dev
spawn defaults to 1 thread
2021-11-18 18:01:04 -05:00
hydroflame
ced4ac2502 Merge pull request #1742 from danielyxie/dev
Add button to donate blood.
2021-11-18 15:23:50 -05:00
hydroflame
6e7ca6a9b5 Merge pull request #1741 from danielyxie/dev
v1.0.1
2021-11-18 11:33:10 -05:00
hydroflame
3b13db1e33 Merge pull request #1736 from danielyxie/dev
few bugfix
2021-11-17 17:50:14 -05:00
hydroflame
cd8da81c97 Merge pull request #1735 from danielyxie/dev
tail box can rerun scripts
2021-11-17 17:33:58 -05:00
hydroflame
b222b1ecbf Merge pull request #1729 from danielyxie/dev
plenty of bf
2021-11-15 23:49:47 -05:00
hydroflame
b990e0e71c Merge pull request #1723 from danielyxie/dev
boost terminal grow
2021-11-14 08:36:46 -05:00
hydroflame
154936c1c5 Merge pull request #1720 from danielyxie/dev
revert omuretsu fix
2021-11-13 20:49:57 -05:00
hydroflame
5ef51d521b Merge pull request #1718 from danielyxie/dev
few bugfix
2021-11-13 19:51:14 -05:00
hydroflame
db6452ee3c Merge pull request #1715 from danielyxie/dev
fix doc
2021-11-13 09:35:33 -05:00
hydroflame
89dffa6dfc Merge pull request #1711 from danielyxie/dev
Make alter reality harder
2021-11-12 19:29:15 -05:00
hydroflame
ffb390fe7d Merge pull request #1710 from danielyxie/dev
fix bladeburner action cancel
2021-11-12 16:54:45 -05:00
hydroflame
83eb4afdf0 Merge pull request #1708 from danielyxie/dev
Improved 404
2021-11-12 16:26:08 -05:00
hydroflame
bc0ab1077c Merge pull request #1707 from danielyxie/dev
Added 404
2021-11-12 16:16:08 -05:00
hydroflame
018dc7c579 Merge pull request #1706 from danielyxie/dev
fix bn5 not giving formulas.exe
2021-11-12 15:48:47 -05:00
hydroflame
ef5fbb7e49 Merge pull request #1705 from danielyxie/dev
rename some stuff and close some exploits
2021-11-12 15:44:11 -05:00
hydroflame
ca50123d1a Merge pull request #1701 from danielyxie/dev
fix more bugs
2021-11-12 10:10:42 -05:00
hydroflame
6b7a468688 Merge pull request #1700 from danielyxie/dev
few more bugfixes
2021-11-11 23:28:28 -05:00
hydroflame
9f14c38396 Merge pull request #1698 from danielyxie/dev
fix corp not loading
2021-11-11 22:45:40 -05:00
hydroflame
724914b85c Merge pull request #1696 from danielyxie/dev
build
2021-11-11 21:35:44 -05:00
174 changed files with 6699 additions and 2912 deletions

View File

@@ -1,7 +1,27 @@
node_modules/
doc/build/
dist/
tests/*.bundle.*
input/
.dist
.tmp
.package
assets/
css/
.cypress/
cypress/
doc/
markdown/
netscript_tests/
scripts/
electron/lib
electron/greenworks.js
src/ThirdParty/*
src/JSInterpreter.js
main.bundle.js
test/*.bundle.*
editor.main.js
main.bundle.js
webpack.config.js
webpack.config-test.js

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

@@ -0,0 +1,55 @@
name: CI
on:
# Triggers the workflow on push or pull request events but only for the dev branch
push:
branches: [ dev ]
pull_request:
branches: [ dev ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js 16.13.1
uses: actions/setup-node@v2
with:
node-version: 16.13.1
cache: 'npm'
- name: Install npm dependencies
run: npm ci
- name: Build the production app
run: npm run build
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js 16.13.1
uses: actions/setup-node@v2
with:
node-version: 16.13.1
cache: 'npm'
- name: Install npm dependencies
run: npm ci
- name: Run linter
run: npm run lint:report
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js 16.13.1
uses: actions/setup-node@v2
with:
node-version: 16.13.1
cache: 'npm'
- name: Install npm dependencies
run: npm ci
- name: Run linter
run: npm run test

1
.gitignore vendored
View File

@@ -4,6 +4,7 @@ Changelog.txt
Netburner.txt
/doc/build
/node_modules
/electron/node_modules
/dist/*.map
/test/*.map
/test/*.bundle.*

1
.nojekyll Normal file
View File

@@ -0,0 +1 @@

View File

@@ -6,7 +6,7 @@ The game is made better because the community as a whole speaks up about
ways to improve the game. Here's some of the ways you can make your voice
heard:
- [Discord](https://discordapp.com)
- [Discord](https://discord.gg/XKEGvHqVr3)
There is a dedicated Discord instance set up for more free-form chats
between all members of the community. Regular players, heavy scripters,
Bitburner contributors, and everyone in between can be found on the
@@ -84,7 +84,9 @@ changes are okay to contribute:
- Changes that directly affect the game's balance
- New gameplay mechanics
### How to setup fork properly
---
## How to setup fork properly
Fork and clone the repo
@@ -106,7 +108,15 @@ Fork and clone the repo
# Makes sure you always start from `danielyxie/dev` to avoid merge conflicts.
```
### Running locally.
## Development Workflow Best Practices
- Work in a new branch forked from the `dev` branch to isolate your new code
- Keep code-changes on a branch as small as possible. This makes it easier for code review. Each branch should be its own independent feature.
- Regularly rebase your branch against `dev` to make sure you have the latest updates pulled.
- When merging, always merge your branch into `dev`. When releasing a new update, then merge `dev` into `master`
## Running locally.
Install
@@ -118,10 +128,32 @@ Inside the root of the repo run
`npm install` to install all the dependencies
`npm run start:dev` to launch the game in dev mode.
After that you can open any browser and naviguate to `localhost:8000` and play the game.
After that you can open any browser and navigate to `localhost:8000` and play the game.
Saving a file will reload the game automatically.
#### Submitting a Pull Request
### How to build the electron app
Tested on Node v16.13.1 (LTS) on Windows
These steps only work in a bash-like environment, like MinGW for Windows.
```sh
# Install the main game dependencies & build the app in debug mode
npm install
npm run build:dev
# Use electron-packager to build the app to the .build/ folder
npm run electron
# When launching the .exe directly, you'll need the steam_appid.txt file in the root
# If not using windows, change this line accordingly
cp .build/bitburner-win32-x64/resources/app/steam_appid.txt .build/bitburner-win32-x64/steam_appid.txt
# And run the game...
.build/bitburner-win32-x64/bitburner.exe
```
### Submitting a Pull Request
When submitting a pull request with your code contributions, please abide by
the following rules:
@@ -146,9 +178,14 @@ the following rules:
## As a Documentor
To contribute to and view your changes to the BitBurner documentation, you will
To contribute to and view your changes to the BitBurner documentation on [Read The
Docs](http://bitburner.readthedocs.io/), you will
need to have Python installed, along with [Sphinx](http://www.sphinx-doc.org).
To make change to the [in-game documentation](./markdown/bitburner.md), you will need to modify the [TypeScript definitions](./src/ScriptEditor/NetscriptDefinitions.d.ts), not the markdown files.
We are using [API Extractor](https://api-extractor.com/pages/tsdoc/doc_comment_syntax/) (tsdoc hints) to generate the markdown doc. Make your changes to the TypeScript definitions and then run `npm run doc`.
Before submitting your code for a pull request, please try to follow these
rules:
@@ -160,3 +197,14 @@ rules:
_danielyxie/bitburner_ and the base is _dev_.
- Do not check in any generated files under `doc\`. The documentation is built
automatically by ReadTheDocs.
## Deploying a new version
Update the following
- `src/Constants.ts` `Version` and `LatestUpdate`
- `package.json` `version`
- `doc/source/conf.py` `version` and `release`
- `doc/source/changelog.rst`
- post to discord
- post to reddit.com/r/Bitburner

87
FAQ.md Normal file
View File

@@ -0,0 +1,87 @@
# Frequently Asked Questions
## Can I donate to the project?
No, the project does not take donation.
If you still want to donate, go donate blood to your local blood bank or donate to the [Electronic Frontier Foundation](https://www.eff.org/) or [Médecins Sans Frontières](https://www.msf.org/)
---
## I need help / Where can I learn?
The best way to get help is to join the [official discord server](https://discord.gg/TFc3hKD). People of all skill levels will be able to give you hints and tips.
---
## Can I play the same save on browser & steam?
Yes, just export the save file from the options menu & import it in the other platform.
---
## Game is stuck after running scripts!
You may have created an infinite loop with no sleep. You'll have to restart the game by killing all scripts.
* On Browser: Stick `?noScript` at the end of the URL
* On Steam:
* In the menu, "Reloads" -> "Reload & Kill All Scripts".
* If this does not work, when launching the game, use the kill all script options.
---
## Steam: Where is the save game located?
To maintain compatibility with the web browser version, the save game is not stored as a file on your filesystem. It lives inside the localStorage of the WebKit instance. You may export the save (and should backup it!) in the option menu.
---
## Steam: Game won't stop / Game is shown as "Running"
Due to a limitation with the way Steam tracks the game, if you launch an external link (such as documentation), Steam may keep tracking the game as "Running" even after it is closed. You should simply have to close your web browser to fix this.
---
## Steam: How do I get to the game files? <a name="game-files"></a>
You can navigate to the game files by right-clicking the game in your library and then go into "Manage" -> "Browse Local Files". The game can be launched directly from that location, if you're having issues with Steam.
---
## Steam: Game won't launch
### **On Windows**
If the game is installed on a network drive, it will fail to start due to a [limitation in Chromium](https://github.com/electron/electron/issues/27356).
If you cannot move the game to another drive, you'll have to add the `--no-sandbox` launch option. In your Steam Library, Right click the game and hit "Properties". You'll see the launch option section in the "General" window.
### **On Linux**
The game is built natively, do not use Proton unless native does not work.
When launching the game, you will be prompted with three options. If the standard launch does not work, you may attempt the `--disable-seccomp-filter-sandbox` or `--no-sandbox` launch option. If this still does not work, the game should be able to start by launching it directly or through the terminal. See [How do I get to the game files?](#game-files).
---
## Steam: File locations
### Logs (using [electron-log](https://github.com/megahertz/electron-log#readme))
You may want access the logs to get information about crashes or such.
* on Linux: `~/.config/bitburner/logs/main.log`
* on macOS: `~/Library/Logs/bitburner/main.log`
* on Windows: `%USERPROFILE%\AppData\Roaming\bitburner\logs\main.log`
### Config (using [electron-store](https://github.com/sindresorhus/electron-store#readme))
Configuration file will be written to disk in the application data directory.
* on Linux: `~/.config/bitburner/config.json`
* on macOS: `~/Library/Application\ Support/bitburner/config.json`
* on Windows: `%USERPROFILE%\AppData\Roaming\bitburner\config.json`
---
## Steam: What is the API Server?
The API Server allows the official [Visual Studio Code Extension](https://github.com/bitburner-official/bitburner-vscode) to push script file from VSCode to your in-game home.

View File

@@ -1,16 +1,19 @@
# Bitburner
[![Build Status](https://github.com/danielyxie/bitburner/actions/workflows/ci.yml/badge.svg?branch=dev)](https://github.com/danielyxie/bitburner/actions/workflows/ci.yml)
Bitburner is a programming-based [incremental game](https://en.wikipedia.org/wiki/Incremental_game)
that revolves around hacking and cyberpunk themes.
The game can be played at https://danielyxie.github.io/bitburner.
The game can be played at https://danielyxie.github.io/bitburner or installed through [Steam](https://store.steampowered.com/app/1812820/Bitburner/).
See the [frequently asked questions](./FAQ.md) for more information . To discuss the game or get help, join the [official discord server](https://discord.gg/TFc3hKD)
# Documentation
The game's official documentation can be found on [Read The
Docs](http://bitburner.readthedocs.io/). Please note that this is still a
work-in-progress.
Docs](http://bitburner.readthedocs.io/). Please note that this is still a work-in-progress.
The documentation is created using [Sphinx](http://www.sphinx-doc.org).
The [in-game documentation](./markdown/bitburner.md) is generated from the [TypeScript definitions](./src/ScriptEditor/NetscriptDefinitions.d.ts).
Anyone is welcome to contribute to the documentation by editing the [source
files](/doc/source) and then making a pull request with your contributions.

View File

@@ -1,21 +0,0 @@
## Deploying a new version
Update the following
- `src/Constants.ts` `Version` and `LatestUpdate`
- `package.json` `version`
- `doc/source/conf.py` `version` and `release`
- `doc/source/changelog.rst`
- post to discord
- post to reddit.com/r/Bitburner
## Deploying `dev` to the Beta Branch
TODO
## Development Workflow Best Practices
- Work in a new branch forked from the `dev` branch to isolate your new code
- Keep code-changes on a branch as small as possible. This makes it easier for code review. Each branch should be its own independent feature.
- Regularly rebase your branch against `dev` to make sure you have the latest updates pulled.
- When merging, always merge your branch into `dev`. When releasing a new update, then merge `dev` into `master`

13
dist/bitburner.d.ts vendored
View File

@@ -2720,7 +2720,7 @@ export declare interface NS extends Singularity {
* @param args - Additional arguments to pass into the new script that is being run. Note that if any arguments are being passed into the new script, then the second argument numThreads must be filled in with a value.
* @returns Returns the PID of a successfully started script, and 0 otherwise.
*/
run(script: string, numThreads?: number, ...args: string[]): number;
run(script: string, numThreads?: number, ...args: Array<string | number | boolean>): number;
/**
* Start another script on any server.
@@ -2760,7 +2760,7 @@ export declare interface NS extends Singularity {
* @param args - Additional arguments to pass into the new script that is being run. Note that if any arguments are being passed into the new script, then the third argument numThreads must be filled in with a value.
* @returns Returns the PID of a successfully started script, and 0 otherwise.
*/
exec(script: string, host: string, numThreads?: number, ...args: string[]): number;
exec(script: string, host: string, numThreads?: number, ...args: Array<string | number | boolean>): number;
/**
* Terminate current script and start another in 10s.
@@ -3498,7 +3498,7 @@ export declare interface NS extends Singularity {
* Returns 0 if the script does not exist.
*
* @param script - Filename of script. This is case-sensitive.
* @param host - Host of target server the script is located on. This is optional, If it is not specified then the function will se the current server as the target server.
* @param host - Host of target server the script is located on. This is optional, If it is not specified then the function will use the current server as the target server.
* @returns Amount of RAM required to run the specified script on the target server, and 0 if the script does not exist.
*/
getScriptRam(script: string, host?: string): number;
@@ -3538,13 +3538,13 @@ export declare interface NS extends Singularity {
* @remarks
* RAM cost: 0.05 GB
*
* Returns the amount of time in milliseconds it takes to execute the weaken() Netscript function on the target server.
* Returns the amount of time in milliseconds it takes to execute the weaken Netscript function on the target server.
* The function takes in an optional hackLvl parameter that can be specified to see what the weaken time would be at different hacking levels.
*
* @param host - Host of target server.
* @param hackLvl - Optional hacking level for the calculation. Defaults to players current hacking level.
* @param intLvl - Optional intelligence level for the calculation. Defaults to players current intelligence level. (Intelligence is unlocked after obtaining Source-File 5).
* @returns Returns the amount of time in milliseconds it takes to execute the grow Netscript function. Returns Infinity if called on a Hacknet Server.
* @returns Returns the amount of time in milliseconds it takes to execute the weaken Netscript function. Returns Infinity if called on a Hacknet Server.
*/
getWeakenTime(host: string): number;
@@ -3678,8 +3678,9 @@ export declare interface NS extends Singularity {
* Queue a toast (bottom-right notification).
* @param msg - Message in the toast.
* @param variant - Type of toast, must be one of success, info, warning, error. Defaults to success.
* @param duration - Duration of toast in ms, defaults to 2000
*/
toast(msg: any, variant?: string): void;
toast(msg: any, variant?: string, duration?: number): void;
/**
* Download a file from the internet.

7
dist/ext/monaco-vim.js vendored Normal file

File diff suppressed because one or more lines are too long

74
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -12,3 +12,4 @@ must be unlocked.
Source-Files <advancedgameplay/sourcefiles>
Intelligence <advancedgameplay/intelligence>
Sleeves <advancedgameplay/sleeves>
Hacking algorithms <advancedgameplay/hackingalgorithms>

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

@@ -0,0 +1,126 @@
Hacking algorithms
==================
There are three primary families of hacking algorithms. This guide will go over each of them and advise on how they can be implemented.
Self-contained algorithms
-------------------------
**Difficulty**: Easy
Pros:
* Easy to implement
* Does not require other scripts to work
* Works at any stage of the game
Cons:
* Limits income generation
* Extremely RAM inefficient
* Utilizes script online time poorly
* Risk of over hacking
Self-contained algorithms are the simplest family of hacking algorithms to implement. Each script is tasked with choosing which function to execute based on the status of the target server. Because of this, they guarantee a consistent, but relatively small, flow of money.
The general logic goes like this:
.. code-block:: javascript
loop forever {
if security is not minimum {
weaken(target)
} else if money is not maximum {
grow(target)
} else {
hack(target)
}
}
This algorithm is perfectly capable of paving the way through the majority of the game, but it has a few significant issues.
- It tends to make all your scripts on every server do the same thing. (e.g. If the target is 0.01 security above the minimum, all scripts will decide to weaken, when only a handful of threads should be devoted to the task)
- At higher thread counts, these scripts have the potential to hack the server to $0, or maximum security, requiring a long setup time while the scripts return the server to the best stats.
- Requires function calls such as `getServerSecurityLevel()` and `getServerMoneyAvailable()`, as well as calling all three hacking functions, increasing RAM cost which is multiplied by the number of allocated threads
Loop algorithms
---------------
**Difficulty**: Easy to Medium
Pros:
* Simple to understand
* Works at any stage of the game
* Maximize RAM usage
Cons:
* Requires a script that handles deployment
By splitting our hack, weaken, and grow functions into three separate scripts, we can both remove our reliance on functions such as `getServerSecurityLevel()` as well as removing functions that cannot work concurrently, reducing RAM requirements, and thus increasing our thread limits. Loop scripts are formatted like this:
.. code-block:: javascript
loop forever {
hack(target) // or grow, or weaken
}
Now we can take the total amount of threads available and split it and allocate, for example:
- 1 part to the hack scripts
- 10 parts to the grow scripts
- 2 parts to the weaken scripts
Meaning if we have space for 100 threads across the entire network 7 threads will go to the hack scripts, 76 threads will go to the grow scripts and 15 threads will go to the weaken scripts. The ratios described here are arbitrary and can be greatly improved through the use of the analyze functions, and later, through the use of Formulas.exe.
When utilizing this strategy, monitor the amount of money and security on the target server, if the money is not hovering around maximum and the security around the minimum, the ratios should be tweaked until that is the case.
Growth can be made more efficient by dividing it into many processes, instead of one script with a high thread count. Four grow scripts with 20 threads will outperform one grow script with 80 threads.
Utilizing `sleep()` or `asleep()` to ensure that your scripts do not all start at the same time can decrease the chance of issues associated with overhacking occurring. Both functions have a ram cost of zero.
Batch algorithms (HGW, HWGW, or Cycles)
---------------------------------------
**Difficulty**: Hard
Pros:
* Maximum potential income
Cons:
* Very difficult to implement without prior programming knowledge
* Very difficult to make work on servers with less than 1TB of RAM
Batch algorithms utilize a master script that uses `exec()` many scripts which utilize a relevant hacking function in batches.
The scripts used to execute the hacking functions are even simpler than the previous algorithms but a complex controller is required to calculate the effect, time taken, and the necessary delay.
.. code-block:: javascript
sleep(a bit)
hack(target) // or grow, or weaken
A few things need to be known before this algorithm can be implemented:
- The effects of hack and grow depend on the server security level, a higher security level results in a reduced effect. You only want these effects to occur when the security level is minimized.
- The time taken to execute hack, grow, or weaken is determined when the function is called and is based on the security level of the target server and your hacking level. You only want these effects to start when the security level is minimized.
- The effects of hack, grow, and weaken, are determined when the time is completed, rather than at the beginning. Hack should finish when security is minimum and money is maximum. Grow should finish when security is minimum, shortly after a hack occurred. Weaken should occur when security is not at a minimum due to a hack or grow increasing it.
A single batch consists of four actions:
1. A hack script removes a predefined, precalculated amount of money from the target server.
2. A weaken script counters the security increase of the hack script.
3. A grow script counters the money decrease caused by the hack script.
4. A weaken script counters the security increase caused by the grow script.
It is also important that these 4 scripts finish in the order specified above, and all of their effects be precalculated to optimize the ratios between them. This is the reason for the delay in the scripts.
It is possible to create batches with 3 scripts (HGW) but the efficiency of grow will be harmed by the security increase caused by the hack scripts.
The following is an image demonstrating batches in action:
.. image:: batch.png
Batches only function predictably when the target server is at minimum security and maximum money, so your script must also handle preparing a server for your batches. You can utilize batches to prepare a server by using no hack threads during preparation.
Depending on your computer's performance as well as a few other factors, the necessary delay between script execution times may range between 20ms and 200ms, you want to fine-tune this value to be as low as possible while also avoiding your scripts finishing out of order. Anything lower than 20ms will not work due to javascript limitations.

View File

@@ -18,7 +18,7 @@ Sleeve technology is unlocked in :ref:`BitNode-10 <gameplay_bitnodes>`.
Duplicate Sleeves
^^^^^^^^^^^^^^^^^
Duplicate Sleeves are MK-V Synthoids (synthetic androids) into which your consciuosness
Duplicate Sleeves are MK-V Synthoids (synthetic androids) into which your consciousness
has been copied. In other words, these Synthoids contain a perfect duplicate of your mind.
Duplicate Sleeves are essentially clones which you can use to perform work-type actions,

View File

@@ -28,7 +28,7 @@ List of all Source-Files
|| || * Increases the player's charisma and company salary multipliers by 8%/12%/14%. |
+-------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|| BitNode-4: The Singularity || * Let the player access and use Netscript Singularity Functions in other BitNodes. |
|| || * Each level of this Source-File opens up more of the Singularity Functions to use. |
|| || * Each level of this Source-File reduces the RAM cost of singularity functions. |
+-------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|| BitNode-5: Artificial Intelligence || * Unlocks :ref:`gameplay_intelligence`. |
|| || * Unlocks :js:func:`getBitNodeMultipliers` and start with Formulas.exe. |

View File

@@ -13,7 +13,8 @@ Server RAM
Perhaps the most important property of a server to make note of is its RAM,
which refers to how much memory is available on that machine. RAM is
important because it is required to run Scripts. More RAM allows
the user to run more powerful and complicated scripts.
the user to run more powerful and complicated scripts as well as executing
a script with :ref:`more threads <gameplay_scripts_multithreadingscripts>`.
The `free`, `scan-analyze`, and `analyze` Terminal commands
can be used to check how much RAM a server has.

View File

@@ -432,7 +432,10 @@ empty file will be created.
ps
^^
$ ps [-g, --grep pattern]
Prints all scripts that are currently running on the current server.
The :code:`-g, --grep pattern` option will only output running scripts where the name matches the provided pattern.
rm
^^

View File

@@ -3,6 +3,93 @@
Changelog
=========
v1.3.0 - 2022-01-04 Cleaning up
-------------------------------
** External IDE integration **
* The Steam version has a webserver that allows integration with external IDEs.
A VSCode extension is available on the market place. (The documentation for the ext. isn't
written yet)
** Source-Files **
* SF4 has been reworked.
* New SF -1.
** UI **
* Fix some edge case with skill bat tooltips (@MartinFournier)
* Made some background match theme color (@Kejikus)
* Fix problem with script editor height not adjusting correctly (@billyvg)
* Fix some formatting issues with Bladeburner (@MartinFournier, @nickofolas)
* Fix some functions like 'alert' format messages better (@MageKing17)
* Many community themes added.
* New script editor theme (@Hedrauta, @Dexalt142)
* Improvements to tail windows (@theit8514)
* Training is more consise (@mikomyazaki)
* Fix Investopedia not displaying properly (@JotaroS)
* Remove alpha from theme editor (@MartinFournier)
* Fix corporation tooltip not displaying properly (@MartinFournier)
* Add tooltip on backdoored location names (@MartinFournier)
* Allow toasts to be dismissed by clicking them (@nickofolas)
* Darkweb item listing now shows what you own. (@hexnaught)
** Bug fix **
* Fix unit tests (@MartinFournier)
* Fixed issue with 'cat' and 'read' not finding foldered files (@Nick-Colclasure)
* Buying on the dark web will remove incomplete exe (@hexnaught)
* Fix bug that would cause the game to crash trying to go to a job without a job (@hexnaught)
* purchaseServer validation (@nickofolas)
* Script Editor focuses code when changing tab (@MartinFournier)
* Fix script editor for .txt files (@65-7a)
* Fix 'buy' command not displaying correctly. (@hexnaught)
* Fix hackAnalyzeThread returning NaN (@mikomyazaki)
* Electron handles exceptions better (@MageKing17)
* Electron will handle 'unresponsive' event and present the opportunity to reload the game with no scripts (@MartinFournier)
* Fix 'cp' between folders (@theit8514)
* Fix throwing null/undefined errors (@nickofolas)
* Allow shortcuts to work when unfocused (@MageKing17)
* Fix some dependency issue (@locriacyber)
* Fix corporation state returning an object instead of a string (@antonvmironov)
* Fix 'mv' overwriting files (@theit8514)
* Fix joesguns not being influenced by hack/grow (@dou867, @MartinFournier)
* Added warning when opening external links. (@MartinFournier)
* Prevent applying for positions that aren't offered (@TheMas3212)
* Import has validation (@MartinFournier)
** Misc. **
* Added vim mode to script editor (@billyvg)
* Clean up script editor code (@Rez855)
* 'cat' works on scripts (@65-7a)
* Add wordWrap for Monaco (@MartinFournier)
* Include map bundles in electron for easier debugging (@MartinFournier)
* Fix importing very large files (@MartinFournier)
* Cache program blob, reducing ram usage of the game (@theit8514)
* Dev menu can set server to $0 (@mikomyazaki)
* 'backdoor' allows direct connect (@mikomyazaki)
* Github workflow work (@MartinFournier)
* workForFaction / workForCompany have a new parameter (@theit8514)
* Alias accept single quotes (@sporkwitch, @FaintSpeaker)
* Add grep options to 'ps' (@maxtimum)
* Added buy all option to 'buy' (@anthonydroberts)
* Added more shortcuts to terminal input (@Frank-py)
* Refactor some port code (@ErzengelLichtes)
* Settings to control GiB vs GB (@ErzengelLichtes)
* Add electron option to export save game (@MartinFournier)
* Electron improvements (@MartinFournier)
* Expose some notifications functions to electron (@MartinFournier)
* Documentation (@MartinFournier, @cyn, @millennIumAMbiguity, @2PacIsAlive,
@TheCoderJT, @hexnaught, @sschmidTU, @FOLLGAD, @Hedrauta, @Xynrati,
@mikomyazaki, @Icehawk78, @aaronransley, @TheMas3212, @Hedrauta, @alkemann,
@ReeseJones, @amclark42, @thadguidry, @jasonhaxstuff, @pan-kuleczka, @jhollowe,
@ApatheticsAnonymous, @erplsf, @daanflore, @nickofolas, @Kebap, @smolgumball,
@woody-lam-cwl)
v1.1.0 - 2021-12-18 You guys are awesome (community because they're god damn awesome)
-------------------------------------------------------------------------------------

View File

@@ -56,7 +56,7 @@ master_doc = 'index'
# General information about the project.
project = 'Bitburner'
author = 'Bitburner'
copyright = '2018, {0}'.format(author)
copyright = '2016, {0}'.format(author)
documentation_title = '{0} Documentation'.format(project)
# The version info for the project you're documenting, acts as replacement for
@@ -64,9 +64,9 @@ documentation_title = '{0} Documentation'.format(project)
# built documents.
#
# The short X.Y version.
version = '1.2'
version = '1.3'
# The full version, including alpha/beta/rc tags.
release = '1.2.0'
release = '1.3.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View File

@@ -520,10 +520,12 @@ will appear that simply says :code:`Work`. Click this to start working.
Working at :code:`Joe's Guns` earns $110 per second and also grants some experience
for every stat except hacking.
Working for a company is completely passive. However, you will not be able to do anything
else in the game while you work. You can cancel working at any time. You'll notice that
cancelling your work early causes you to lose out on some reputation gains, but
you shouldn't worry about this. Company reputation isn't important right now.
Working for a company is completely passive. You can choose to focus on your work, do
something else simultaneously, or switch between those two. While you focus on work,
you will not be able to do anything else in the game. If you do something else meanwhile,
you will not gain reputation at the same speed. You can cancel working at any time.
You'll notice that cancelling your work early causes you to lose out on some reputation
gains, but you shouldn't worry about this. Company reputation isn't important right now.
Once your hacking hits level 75, you can visit :code:`Carmichael Security` in the city
and get a software job there. This job offers higher pay and also earns you
@@ -720,9 +722,10 @@ navigation menu, and from there select |CyberSec|. In the middle of
the page there should be a button for :code:`Hacking Contracts`.
Click it to start earning reputation for the |CyberSec| faction (as well
as some hacking experience). The higher your hacking level, the more reputation you
will gain. Note that while you are working for a faction, you cannot interact with
the rest of the game in any way. You can cancel your faction work at any time
with no penalty.
will gain. Note that while you are working for a faction, you can choose to not interact
with the rest of the game in any way to gain reputation at full speed. You can also select to
do something else simultaneously, gaining reputation a bit more slowly, until you focus again.
You can cancel your faction work at any time with no penalty to your reputation gained so far.
Purchasing Upgrades and Augmentations
-------------------------------------

View File

@@ -3,7 +3,8 @@
Netscript Basic Functions
=========================
This page contains the complete documentation for all functions that are available in Netscript.
This page contains a subset of functions that are available in Bitburner.
For the complete list see https://github.com/danielyxie/bitburner/tree/dev/markdown
This includes information such as function signatures, what they do, and their return values.
.. toctree::

View File

@@ -1,16 +0,0 @@
canPlace() Netscript Function
=======================================
.. js:function:: canPlace(worldX, worldY, rotation, fragmentId)
:RAM cost: 0.5 GB
:param int worldX: World X against which to align the top left of the fragment.
:param int worldY: World Y against which to align the top left of the fragment.
:param int rotation: A number from 0 to 3, the mount of 90 degree turn to take.
:param int fragmentId: ID of the fragment to place.
:returns: `true` if the fragment can be placed at that position. `false` otherwise.
Example:
.. code-block:: javascript
canPlace(0, 4, 17); // returns true

View File

@@ -1,21 +0,0 @@
charge() Netscript Function
=======================================
.. js:function:: charge(worldX, worldY)
:RAM cost: 0.4 GB
:param int worldX: World X of the fragment to charge.
:param int worldY: World Y of the fragment to charge.
Charge a fragment, increasing it's power but also it's heat. The
effectiveness of the charge depends on the amount of ram the running script
consumes as well as the fragments current heat. This operation takes time to
complete.
Example:
.. code-block:: javascript
charge(0, 4); // Finishes 5 seconds later.
.. warning::
Netscript JS users: This function is `async`

View File

@@ -1,13 +0,0 @@
clear() Netscript Function
=======================================
.. js:function:: clear()
:RAM cost: 0 GB
Completely clear Stanek's Gift.
Example:
.. code-block:: javascript
clear(); // No more fragments.

View File

@@ -1,16 +0,0 @@
deleteAt() Netscript Function
=======================================
.. js:function:: deleteAt(worldX, worldY)
:RAM cost: 0.15 GB
:param int worldX: World X coordinate of the fragment to delete.
:param int worldY: World Y coordinate of the fragment to delete.
:returns: `true` if the fragment was deleted. `false` otherwise.
Delete the fragment located at `[worldX, worldY]`.
Example:
.. code-block:: javascript
deleteAt(0, 4); // returns true

View File

@@ -1,28 +0,0 @@
fragmentAt() Netscript Function
=======================================
.. js:function:: fragmentAt(worldX, worldY)
:RAM cost: 2 GB
:param int worldX: World X coordinate of the fragment.
:param int worldY: World Y coordinate of the fragment.
:returns: The fragment located at `[worldX, worldY]` in Stanek's Gift, or null.
.. code-block:: typescript
{
// In world coordinates
x: number;
y: number;
heat: number;
charge: number;
id: number;
shape: boolean[][];
type: string;
magnitude: number;
limit: number;
}
Example:
.. code-block:: javascript
var fragment = fragmentAt(0, 4);
print(fragment); // {'heat': 50, 'charge': 98}

View File

@@ -1,23 +0,0 @@
fragmentDefinitions() Netscript Function
=======================================
.. js:function:: fragmentDefinitions()
:RAM cost: 0 GB
:returns: The list of all fragment that can be embedded in Stanek's Gift.
.. code-block:: typescript
[
{
id: number;
shape: boolean[][];
type: string;
magnitude: number;
limit: number;
}
]
Example:
.. code-block:: javascript
var fragments = fragmentDefinitions();
print(fragment); // prints all possible fragments

View File

@@ -1,16 +0,0 @@
place() Netscript Function
=======================================
.. js:function:: place(worldX, worldY, fragmentId)
:RAM cost: 5 GB
:param int worldX: World X against which to align the top left of the fragment.
:param int worldY: World Y against which to align the top left of the fragment.
:param int rotation: A number from 0 to 3, the mount of 90 degree turn to take.
:param int fragmentId: ID of the fragment to place.
:returns: `true` if the fragment has been placed at that position. `false` otherwise.
Example:
.. code-block:: javascript
place(0, 4, 17); // returns true

View File

@@ -1,26 +0,0 @@
placedFragments() Netscript Function
=======================================
.. js:function:: placedFragments()
:RAM cost: 5 GB
:returns: The list of all fragment that are embedded in Stanek's Gift.
.. code-block:: typescript
[
{
// In world coordinates
x: number;
y: number;
charge: number;
id: number;
shape: boolean[][];
type: string;
power: number;
limit: number;
}
]
Example:
.. code-block:: javascript
var myFragments = placedFragments();

35
electron/achievements.js Normal file
View File

@@ -0,0 +1,35 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const greenworks = require("./greenworks");
function enableAchievementsInterval(window) {
// This is backward but the game fills in an array called `document.achievements` and we retrieve it from
// here. Hey if it works it works.
const steamAchievements = greenworks.getAchievementNames();
const intervalID = setInterval(async () => {
try {
const playerAchievements = await window.webContents.executeJavaScript("document.achievements");
for (const ach of playerAchievements) {
if (!steamAchievements.includes(ach)) continue;
greenworks.activateAchievement(ach, () => undefined);
}
} catch (error) {
log.error(error);
// The interval probably did not get cleared after a window kill
log.warn('Clearing achievements timer');
clearInterval(intervalID);
return;
}
}, 1000);
window.achievementsIntervalID = intervalID;
}
function disableAchievementsInterval(window) {
if (window.achievementsIntervalID) {
clearInterval(window.achievementsIntervalID);
}
}
module.exports = {
enableAchievementsInterval, disableAchievementsInterval
}

147
electron/api-server.js Normal file
View File

@@ -0,0 +1,147 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const http = require("http");
const crypto = require("crypto");
const log = require("electron-log");
const Config = require("electron-config");
const config = new Config();
let server;
let window;
async function initialize(win) {
window = win;
server = http.createServer(async function (req, res) {
let body = "";
req.on("data", (chunk) => {
body += chunk.toString(); // convert Buffer to string
});
req.on("end", () => {
const providedToken = req.headers?.authorization?.replace('Bearer ', '') ?? '';
const isValid = providedToken === getAuthenticationToken();
if (isValid) {
log.debug('Valid authentication token');
} else {
log.log('Invalid authentication token');
res.writeHead(401);
res.write('Invalid authentication token');
res.end();
return;
}
let data;
try {
data = JSON.parse(body);
} catch (error) {
log.warn(`Invalid body data`);
res.writeHead(400);
res.write('Invalid body data');
res.end();
return;
}
if (data) {
window.webContents.executeJavaScript(`document.saveFile("${data.filename}", "${data.code}")`).then((result) => {
res.write(result);
res.end();
});
}
});
});
const autostart = config.get('autostart', false);
if (autostart) {
try {
await enable()
} catch (error) {
return Promise.reject(error);
}
}
return Promise.resolve();
}
function enable() {
if (isListening()) {
log.warn('API server already listening');
return Promise.resolve();
}
const port = config.get('port', 9990);
log.log(`Starting http server on port ${port}`);
// https://stackoverflow.com/a/62289870
let startFinished = false;
return new Promise((resolve, reject) => {
server.listen(port, "127.0.0.1", () => {
if (!startFinished) {
startFinished = true;
resolve();
}
});
server.once('error', (err) => {
if (!startFinished) {
startFinished = true;
console.log(
'There was an error starting the server in the error listener:',
err
);
reject(err);
}
});
});
}
function disable() {
if (!isListening()) {
log.warn('API server not listening');
return Promise.resolve();
}
log.log('Stopping http server');
return server.close();
}
function toggleServer() {
if (isListening()) {
return disable();
} else {
return enable();
}
}
function isListening() {
return server?.listening ?? false;
}
function toggleAutostart() {
const newValue = !isAutostart();
config.set('autostart', newValue);
log.log(`New autostart value is '${newValue}'`);
}
function isAutostart() {
return config.get('autostart');
}
function getAuthenticationToken() {
const token = config.get('token');
if (token) return token;
const newToken = generateToken();
config.set('token', newToken);
return newToken;
}
function generateToken() {
const buffer = crypto.randomBytes(48);
return buffer.toString('base64')
}
module.exports = {
initialize,
enable, disable, toggleServer,
toggleAutostart, isAutostart,
getAuthenticationToken, isListening,
}

30
electron/exit.html Normal file
View File

@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>Bitburner</title>
<link rel="stylesheet" href="main.css" />
<style>
body {
background-color: black;
color: #0c0;
}
div {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
h1 {
text-align: center;
}
</style>
</head>
<body>
<div>
<h1>Exiting ...</h1>
</div>
</body>
</html>

30
electron/export.html Normal file
View File

@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>Bitburner</title>
<link rel="stylesheet" href="main.css" />
<style>
body {
background-color: black;
color: #0c0;
}
div {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
h1 {
text-align: center;
}
</style>
</head>
<body>
<div>
<h1>Close me when operation is completed.</h1>
</div>
</body>
</html>

56
electron/gameWindow.js Normal file
View File

@@ -0,0 +1,56 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const { app, BrowserWindow } = require("electron");
const log = require("electron-log");
const utils = require("./utils");
const achievements = require("./achievements");
const menu = require("./menu");
const api = require("./api-server");
const debug = process.argv.includes("--debug");
async function createWindow(killall) {
const setStopProcessHandler = global.app_handlers.stopProcess
const window = new BrowserWindow({
show: false,
backgroundThrottling: false,
backgroundColor: "#000000",
});
window.removeMenu();
window.maximize();
noScripts = killall ? { query: { noScripts: killall } } : {};
window.loadFile("index.html", noScripts);
window.show();
if (debug) window.webContents.openDevTools();
window.webContents.on("new-window", function (e, url) {
// make sure local urls stay in electron perimeter
if (url.substr(0, "file://".length) === "file://") {
return;
}
// and open every other protocols on the browser
e.preventDefault();
utils.openExternal(url);
});
window.webContents.backgroundThrottling = false;
achievements.enableAchievementsInterval(window);
utils.attachUnresponsiveAppHandler(window);
try {
await api.initialize(window);
} catch (error) {
log.error(error);
utils.showErrorBox('Error starting http server', error);
}
menu.refreshMenu(window);
setStopProcessHandler(app, window, true);
return window;
}
module.exports = {
createWindow,
}

View File

@@ -1,146 +1,116 @@
const { app, BrowserWindow, Menu, shell } = require("electron");
/* eslint-disable no-process-exit */
/* eslint-disable @typescript-eslint/no-var-requires */
const { app, dialog, BrowserWindow } = require("electron");
const log = require("electron-log");
const greenworks = require("./greenworks");
const api = require("./api-server");
const gameWindow = require("./gameWindow");
const achievements = require("./achievements");
const utils = require("./utils");
log.catchErrors();
log.info(`Started app: ${JSON.stringify(process.argv)}`);
process.on('uncaughtException', function () {
// The exception will already have been logged by electron-log
process.exit(1);
});
if (greenworks.init()) {
console.log("Steam API has been initialized.");
log.info("Steam API has been initialized.");
} else {
console.log("Steam API has failed to initialize.");
}
const debug = false;
function createWindow(killall) {
const win = new BrowserWindow({
show: false,
backgroundThrottling: false,
backgroundColor: "#000000",
});
win.removeMenu();
win.maximize();
noScripts = killall ? { query: { noScripts: killall } } : {};
win.loadFile("index.html", noScripts);
win.show();
if (debug) win.webContents.openDevTools();
win.webContents.on("new-window", function (e, url) {
// make sure local urls stay in electron perimeter
if (url.substr(0, "file://".length) === "file://") {
return;
}
// and open every other protocols on the browser
e.preventDefault();
shell.openExternal(url);
});
win.webContents.backgroundThrottling = false;
// This is backward but the game fills in an array called `document.achievements` and we retrieve it from
// here. Hey if it works it works.
const achievements = greenworks.getAchievementNames();
const intervalID = setInterval(async () => {
const achs = await win.webContents.executeJavaScript("document.achievements");
console.log(achs);
for (const ach of achs) {
if (!achievements.includes(ach)) continue;
greenworks.activateAchievement(ach, () => undefined);
}
}, 1000);
win.achievementsIntervalID = intervalID;
// Create the Application's main menu
Menu.setApplicationMenu(
Menu.buildFromTemplate([
{
label: "Edit",
submenu: [
{ label: "Undo", accelerator: "CmdOrCtrl+Z", selector: "undo:" },
{ label: "Redo", accelerator: "Shift+CmdOrCtrl+Z", selector: "redo:" },
{ type: "separator" },
{ label: "Cut", accelerator: "CmdOrCtrl+X", selector: "cut:" },
{ label: "Copy", accelerator: "CmdOrCtrl+C", selector: "copy:" },
{ label: "Paste", accelerator: "CmdOrCtrl+V", selector: "paste:" },
{ label: "Select All", accelerator: "CmdOrCtrl+A", selector: "selectAll:" },
],
},
{
label: "reloads",
submenu: [
{
label: "reload",
accelerator: "f5",
click: () => {
win.loadFile("index.html");
},
},
{
label: "reload & kill all scripts",
click: () => {
setStopProcessHandler(app, win, false);
if (intervalID) clearInterval(intervalID);
win.webContents.forcefullyCrashRenderer();
win.close();
createWindow(true);
},
},
],
},
{
label: "fullscreen",
submenu: [
{
label: "toggle",
accelerator: "f9",
click: (() => {
let full = false;
return () => {
full = !full;
win.setFullScreen(full);
};
})(),
},
],
},
{
label: "debug",
submenu: [
{
label: "activate",
click: () => win.webContents.openDevTools(),
},
],
},
]),
);
return win;
log.warn("Steam API has failed to initialize.");
}
function setStopProcessHandler(app, window, enabled) {
const clearWindowHandler = () => {
if (window.achievementsIntervalID) {
clearInterval(window.achievementsIntervalID);
const closingWindowHandler = async (e) => {
// We need to prevent the default closing event to add custom logic
e.preventDefault();
// First we clear the achievement timer
achievements.disableAchievementsInterval(window);
// Shutdown the http server
api.disable();
// Because of a steam limitation, if the player has launched an external browser,
// steam will keep displaying the game as "Running" in their UI as long as the browser is up.
// So we'll alert the player to close their browser.
if (global.app_playerOpenedExternalLink) {
await dialog.showMessageBox({
title: 'Bitburner',
message: 'You may have to close your browser to properly exit the game.',
detail: 'Steam will keep tracking Bitburner as "Running" if any process started within the game is still running.' +
' This includes launching an external link, which opens up your browser.',
type: 'warning', buttons: ['OK']
});
}
// We'll try to execute javascript on the page to see if we're stuck
let canRunJS = false;
window.webContents.executeJavaScript('window.stop(); document.close()', true)
.then(() => canRunJS = true);
setTimeout(() => {
// Wait a few milliseconds to prevent a race condition before loading the exit screen
window.webContents.stop();
window.loadFile("exit.html")
}, 20);
// Wait 200ms, if the promise has not yet resolved, let's crash the process since we're possibly in a stuck scenario
setTimeout(() => {
if (!canRunJS) {
// We're stuck, let's crash the process
log.warn('Forcefully crashing the renderer process');
window.webContents.forcefullyCrashRenderer();
}
log.debug('Destroying the window');
window.destroy();
}, 200);
}
const clearWindowHandler = () => {
window = null;
};
const stopProcessHandler = () => {
if (process.platform !== "darwin") {
app.quit();
process.exit(0);
}
log.info('Quitting the app...');
app.isQuiting = true;
app.quit();
process.exit(0);
};
if (enabled) {
log.debug('Adding closing handlers');
window.on("closed", clearWindowHandler);
window.on("close", closingWindowHandler)
app.on("window-all-closed", stopProcessHandler);
} else {
log.debug('Removing closing handlers');
window.removeListener("closed", clearWindowHandler);
window.removeListener("close", closingWindowHandler);
app.removeListener("window-all-closed", stopProcessHandler);
}
}
app.whenReady().then(() => {
const win = createWindow(process.argv.includes("--no-scripts"));
setStopProcessHandler(app, win, true);
function startWindow(noScript) {
gameWindow.createWindow(noScript);
}
global.app_handlers = {
stopProcess: setStopProcessHandler,
createWindow: startWindow,
}
app.whenReady().then(async () => {
log.info('Application is ready!');
if (process.argv.includes("--export-save")) {
const window = new BrowserWindow({ show: false });
await window.loadFile("export.html", false);
window.show();
setStopProcessHandler(app, window, true);
await utils.exportSave(window);
} else {
startWindow(process.argv.includes("--no-scripts"));
}
});

140
electron/menu.js Normal file
View File

@@ -0,0 +1,140 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const { Menu, clipboard, dialog } = require("electron");
const log = require("electron-log");
const api = require("./api-server");
const utils = require("./utils");
function getMenu(window) {
return Menu.buildFromTemplate([
{
label: "Edit",
submenu: [
{ label: "Undo", accelerator: "CmdOrCtrl+Z", selector: "undo:" },
{ label: "Redo", accelerator: "Shift+CmdOrCtrl+Z", selector: "redo:" },
{ type: "separator" },
{ label: "Cut", accelerator: "CmdOrCtrl+X", selector: "cut:" },
{ label: "Copy", accelerator: "CmdOrCtrl+C", selector: "copy:" },
{ label: "Paste", accelerator: "CmdOrCtrl+V", selector: "paste:" },
{ label: "Select All", accelerator: "CmdOrCtrl+A", selector: "selectAll:" },
],
},
{
label: "Reloads",
submenu: [
{
label: "Reload",
accelerator: "f5",
click: () => window.loadFile("index.html"),
},
{
label: "Reload & Kill All Scripts",
click: () => utils.reloadAndKill(window, true),
},
],
},
{
label: "Fullscreen",
submenu: [
{
label: "Toggle",
accelerator: "f9",
click: (() => {
let full = false;
return () => {
full = !full;
window.setFullScreen(full);
};
})(),
},
],
},
{
label: "API Server",
submenu: [
{
label: api.isListening() ? 'Disable Server' : 'Enable Server',
click: (async () => {
let success = false;
try {
await api.toggleServer();
success = true;
} catch (error) {
log.error(error);
utils.showErrorBox('Error Toggling Server', error);
}
if (success && api.isListening()) {
utils.writeToast(window, "Started API Server", "success");
} else if (success && !api.isListening()) {
utils.writeToast(window, "Stopped API Server", "success");
} else {
utils.writeToast(window, 'Error Toggling Server', "error");
}
refreshMenu(window);
})
},
{
label: api.isAutostart() ? 'Disable Autostart' : 'Enable Autostart',
click: (async () => {
api.toggleAutostart();
if (api.isAutostart()) {
utils.writeToast(window, "Enabled API Server Autostart", "success");
} else {
utils.writeToast(window, "Disabled API Server Autostart", "success");
}
refreshMenu(window);
})
},
{
label: 'Copy Auth Token',
click: (async () => {
const token = api.getAuthenticationToken();
log.log('Wrote authentication token to clipboard');
clipboard.writeText(token);
utils.writeToast(window, "Copied Authentication Token to Clipboard", "info");
})
},
{
type: 'separator',
},
{
label: 'Information',
click: () => {
dialog.showMessageBox({
type: 'info',
title: 'Bitburner > API Server Information',
message: 'The API Server is used to write script files to your in-game home.',
detail: 'There is an official Visual Studio Code extension that makes use of that feature.\n\n' +
'It allows you to write your script file in an external IDE and have them pushed over to the game automatically.\n' +
'If you want more information, head over to: https://github.com/bitburner-official/bitburner-vscode.',
buttons: ['Dismiss', 'Open Extension Link (GitHub)'],
defaultId: 0,
cancelId: 0,
noLink: true,
}).then(({response}) => {
if (response === 1) {
utils.openExternal('https://github.com/bitburner-official/bitburner-vscode');
}
});
}
}
]
},
{
label: "Debug",
submenu: [
{
label: "Activate",
click: () => window.webContents.openDevTools(),
},
],
},
]);
}
function refreshMenu(window) {
Menu.setApplicationMenu(getMenu(window));
}
module.exports = {
getMenu, refreshMenu,
}

325
electron/package-lock.json generated Normal file
View File

@@ -0,0 +1,325 @@
{
"name": "bitburner",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "bitburner",
"version": "1.0.0",
"dependencies": {
"electron-config": "^2.0.0",
"electron-log": "^4.4.4"
}
},
"node_modules/conf": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/conf/-/conf-1.4.0.tgz",
"integrity": "sha512-bzlVWS2THbMetHqXKB8ypsXN4DQ/1qopGwNJi1eYbpwesJcd86FBjFciCQX/YwAhp9bM7NVnPFqZ5LpV7gP0Dg==",
"dependencies": {
"dot-prop": "^4.1.0",
"env-paths": "^1.0.0",
"make-dir": "^1.0.0",
"pkg-up": "^2.0.0",
"write-file-atomic": "^2.3.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/dot-prop": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.1.tgz",
"integrity": "sha512-l0p4+mIuJIua0mhxGoh4a+iNL9bmeK5DvnSVQa6T0OhrVmaEa1XScX5Etc673FePCJOArq/4Pa2cLGODUWTPOQ==",
"dependencies": {
"is-obj": "^1.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/electron-config": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/electron-config/-/electron-config-2.0.0.tgz",
"integrity": "sha512-5mGwRK4lsAo6tiy4KNF/zUInYpUGr7JJzLA8FHOoqBWV3kkKJWSrDXo4Uk2Ffm5aeQ1o73XuorfkYhaWFV2O4g==",
"deprecated": "Renamed to `electron-store`.",
"dependencies": {
"conf": "^1.0.0"
}
},
"node_modules/electron-log": {
"version": "4.4.4",
"resolved": "https://registry.npmjs.org/electron-log/-/electron-log-4.4.4.tgz",
"integrity": "sha512-jcNtrVmKXG+CHchLo/jnjjQ9K4/ORguWD23H2nqApTwisQ4Qo3IRQtLiorubajX0Uxg76Xm/Yt+eNfQMoHVr5w=="
},
"node_modules/env-paths": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-1.0.0.tgz",
"integrity": "sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA=",
"engines": {
"node": ">=4"
}
},
"node_modules/find-up": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
"integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
"dependencies": {
"locate-path": "^2.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/graceful-fs": {
"version": "4.2.8",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz",
"integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg=="
},
"node_modules/imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
"engines": {
"node": ">=0.8.19"
}
},
"node_modules/is-obj": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
"integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/locate-path": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
"integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
"dependencies": {
"p-locate": "^2.0.0",
"path-exists": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/make-dir": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
"integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
"dependencies": {
"pify": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/p-limit": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
"integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
"dependencies": {
"p-try": "^1.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/p-locate": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
"integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
"dependencies": {
"p-limit": "^1.1.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/p-try": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
"integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
"engines": {
"node": ">=4"
}
},
"node_modules/path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
"engines": {
"node": ">=4"
}
},
"node_modules/pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
"engines": {
"node": ">=4"
}
},
"node_modules/pkg-up": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz",
"integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=",
"dependencies": {
"find-up": "^2.1.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/signal-exit": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz",
"integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ=="
},
"node_modules/write-file-atomic": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz",
"integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==",
"dependencies": {
"graceful-fs": "^4.1.11",
"imurmurhash": "^0.1.4",
"signal-exit": "^3.0.2"
}
}
},
"dependencies": {
"conf": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/conf/-/conf-1.4.0.tgz",
"integrity": "sha512-bzlVWS2THbMetHqXKB8ypsXN4DQ/1qopGwNJi1eYbpwesJcd86FBjFciCQX/YwAhp9bM7NVnPFqZ5LpV7gP0Dg==",
"requires": {
"dot-prop": "^4.1.0",
"env-paths": "^1.0.0",
"make-dir": "^1.0.0",
"pkg-up": "^2.0.0",
"write-file-atomic": "^2.3.0"
}
},
"dot-prop": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.1.tgz",
"integrity": "sha512-l0p4+mIuJIua0mhxGoh4a+iNL9bmeK5DvnSVQa6T0OhrVmaEa1XScX5Etc673FePCJOArq/4Pa2cLGODUWTPOQ==",
"requires": {
"is-obj": "^1.0.0"
}
},
"electron-config": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/electron-config/-/electron-config-2.0.0.tgz",
"integrity": "sha512-5mGwRK4lsAo6tiy4KNF/zUInYpUGr7JJzLA8FHOoqBWV3kkKJWSrDXo4Uk2Ffm5aeQ1o73XuorfkYhaWFV2O4g==",
"requires": {
"conf": "^1.0.0"
}
},
"electron-log": {
"version": "4.4.4",
"resolved": "https://registry.npmjs.org/electron-log/-/electron-log-4.4.4.tgz",
"integrity": "sha512-jcNtrVmKXG+CHchLo/jnjjQ9K4/ORguWD23H2nqApTwisQ4Qo3IRQtLiorubajX0Uxg76Xm/Yt+eNfQMoHVr5w=="
},
"env-paths": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-1.0.0.tgz",
"integrity": "sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA="
},
"find-up": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
"integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
"requires": {
"locate-path": "^2.0.0"
}
},
"graceful-fs": {
"version": "4.2.8",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz",
"integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg=="
},
"imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
},
"is-obj": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
"integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8="
},
"locate-path": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
"integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
"requires": {
"p-locate": "^2.0.0",
"path-exists": "^3.0.0"
}
},
"make-dir": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
"integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
"requires": {
"pify": "^3.0.0"
}
},
"p-limit": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
"integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
"requires": {
"p-try": "^1.0.0"
}
},
"p-locate": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
"integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
"requires": {
"p-limit": "^1.1.0"
}
},
"p-try": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
"integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M="
},
"path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
},
"pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
},
"pkg-up": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz",
"integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=",
"requires": {
"find-up": "^2.1.0"
}
},
"signal-exit": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz",
"integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ=="
},
"write-file-atomic": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz",
"integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==",
"requires": {
"graceful-fs": "^4.1.11",
"imurmurhash": "^0.1.4",
"signal-exit": "^3.0.2"
}
}
}
}

View File

@@ -5,20 +5,24 @@
"main": "main.js",
"author": "Daniel Xie & Olivier Gagnon",
"mac": {
"icon": "./public/icons/mac/icon.icns",
"icon": "./public/icons/mac/icon.icns",
"category": "public.app-category.games"
},
"win": {
"icon": "./public/icons/png/256x256.png"
"icon": "./public/icons/png/256x256.png"
},
"files": [
"./build/**/*",
"./dist/**/*",
"./node_modules/**/*",
"./public/**/*",
"./public/**/*",
"*.js"
],
"directories": {
"buildResources": "public"
},
"dependencies": {
"electron-config": "^2.0.0",
"electron-log": "^4.4.4"
}
}

116
electron/utils.js Normal file
View File

@@ -0,0 +1,116 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const { app, dialog, shell } = require("electron");
const log = require("electron-log");
const achievements = require("./achievements");
const api = require("./api-server");
function reloadAndKill(window, killScripts) {
const setStopProcessHandler = global.app_handlers.stopProcess
const createWindowHandler = global.app_handlers.createWindow;
log.info('Reloading & Killing all scripts...');
setStopProcessHandler(app, window, false);
achievements.disableAchievementsInterval(window);
api.disable();
window.webContents.forcefullyCrashRenderer();
window.on('closed', () => {
// Wait for window to be closed before opening the new one to prevent race conditions
log.debug('Opening new window');
createWindowHandler(killScripts);
})
window.close();
}
function promptForReload(window) {
detachUnresponsiveAppHandler(window);
dialog.showMessageBox({
type: 'error',
title: 'Bitburner > Application Unresponsive',
message: 'The application is unresponsive, possibly due to an infinite loop in your scripts.',
detail:' Did you forget a ns.sleep(x)?\n\n' +
'The application will be restarted for you, do you want to kill all running scripts?',
buttons: ['Restart', 'Cancel'],
defaultId: 0,
checkboxLabel: 'Kill all running scripts',
checkboxChecked: true,
noLink: true,
}).then(({response, checkboxChecked}) => {
if (response === 0) {
reloadAndKill(window, checkboxChecked);
} else {
attachUnresponsiveAppHandler(window);
}
});
}
function attachUnresponsiveAppHandler(window) {
window.unresponsiveHandler = () => promptForReload(window);
window.on('unresponsive', window.unresponsiveHandler);
}
function detachUnresponsiveAppHandler(window) {
window.off('unresponsive', window.unresponsiveHandler);
}
function showErrorBox(title, error) {
dialog.showErrorBox(
title,
`${error.name}\n\n${error.message}`
);
}
function exportSaveFromIndexedDb() {
return new Promise((resolve) => {
const dbRequest = indexedDB.open("bitburnerSave");
dbRequest.onsuccess = () => {
const db = dbRequest.result;
const transaction = db.transaction(['savestring'], "readonly");
const store = transaction.objectStore('savestring');
const request = store.get('save');
request.onsuccess = () => {
const file = new Blob([request.result], {type: 'text/plain'});
const a = document.createElement("a");
const url = URL.createObjectURL(file);
a.href = url;
a.download = 'save.json';
document.body.appendChild(a);
a.click();
setTimeout(function () {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
resolve();
}, 0);
}
}
});
}
async function exportSave(window) {
await window.webContents
.executeJavaScript(`${exportSaveFromIndexedDb.toString()}; exportSaveFromIndexedDb();`, true);
}
async function writeTerminal(window, message, type = null) {
await window.webContents
.executeJavaScript(`window.appNotifier.terminal("${message}", "${type}");`, true)
}
async function writeToast(window, message, type = "info", duration = 2000) {
await window.webContents
.executeJavaScript(`window.appNotifier.toast("${message}", "${type}", ${duration});`, true)
}
function openExternal(url) {
shell.openExternal(url);
global.app_playerOpenedExternalLink = true;
}
module.exports = {
reloadAndKill, showErrorBox, exportSave,
attachUnresponsiveAppHandler, detachUnresponsiveAppHandler,
openExternal, writeTerminal, writeToast,
}

View File

@@ -17,12 +17,13 @@
<link rel="stylesheet" data-name="vs/editor/editor.main" href="dist/ext/monaco-editor/min/vs/editor/editor.main.css"/>
<script>
var require = { paths: { vs: "dist/ext/monaco-editor/min/vs" } };
var require = { paths: { vs: "dist/ext/monaco-editor/min/vs", "monaco-vim": "dist/ext/monaco-vim" } };
</script>
<script src="dist/ext/monaco-editor/min/vs/loader.js"></script>
<script src="dist/ext/monaco-editor/min/vs/editor/editor.main.nls.js"></script>
<script src="dist/ext/monaco-editor/min/vs/editor/editor.main.js"></script>
<script src="dist/ext/monaco-vim.js"></script>
<!-- Google Analytics -->
<script>

View File

@@ -4,6 +4,8 @@ module.exports = {
transform: {
"^.+\\.(js|jsx|ts|tsx)$": "babel-jest",
},
// testMatch: ["**/?(*.)+(test).[jt]s?(x)"],
testPathIgnorePatterns: [
'.cypress', 'node_modules', 'dist',
],
testEnvironment: "jsdom",
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -18,7 +18,7 @@
| [CharacterInfo](./bitburner.characterinfo.md) | |
| [CharacterMult](./bitburner.charactermult.md) | |
| [CodingAttemptOptions](./bitburner.codingattemptoptions.md) | Options to affect the behavior of [CodingContract](./bitburner.codingcontract.md) attempt. |
| [CodingContract](./bitburner.codingcontract.md) | Coding Contact API |
| [CodingContract](./bitburner.codingcontract.md) | Coding Contract API |
| [Corporation](./bitburner.corporation.md) | Corporation API |
| [CorporationInfo](./bitburner.corporationinfo.md) | General info about a corporation |
| [CrimeStats](./bitburner.crimestats.md) | Data representing the internal values of a crime. |
@@ -66,6 +66,7 @@
| [StockOrder](./bitburner.stockorder.md) | Return value of [getOrders](./bitburner.tix.getorders.md) |
| [StockOrderObject](./bitburner.stockorderobject.md) | Value in map of [StockOrder](./bitburner.stockorder.md) |
| [TIX](./bitburner.tix.md) | Stock market API |
| [UserInterface](./bitburner.userinterface.md) | User Interface API. |
| [Warehouse](./bitburner.warehouse.md) | Warehouse for a division in a city |
| [WarehouseAPI](./bitburner.warehouseapi.md) | Corporation Warehouse API |

View File

@@ -28,5 +28,5 @@ Returns the amount of time in milliseconds it takes to execute the grow Netscrip
RAM cost: 0.05 GB
Returns the amount of time in milliseconds it takes to execute the grow Netscript function on the target server. The function takes in an optional hackLvl parameter that can be specified to see what the grow time would be at different hacking levels.
Returns the amount of time in milliseconds it takes to execute the grow Netscript function on the target server.

View File

@@ -28,5 +28,5 @@ Returns the amount of time in milliseconds it takes to execute the hack Netscrip
RAM cost: 0.05 GB
Returns the amount of time in milliseconds it takes to execute the hack Netscript function on the target server. The function takes in an optional hackLvl parameter that can be specified to see what the hack time would be at different hacking levels.
Returns the amount of time in milliseconds it takes to execute the hack Netscript function on the target server.

View File

@@ -22,11 +22,11 @@ getWeakenTime(host: string): number;
number
Returns the amount of time in milliseconds it takes to execute the grow Netscript function. Returns Infinity if called on a Hacknet Server.
Returns the amount of time in milliseconds it takes to execute the weaken() Netscript function on the target server. Returns Infinity if called on a Hacknet Server.
## Remarks
RAM cost: 0.05 GB
Returns the amount of time in milliseconds it takes to execute the weaken() Netscript function on the target server. The function takes in an optional hackLvl parameter that can be specified to see what the weaken time would be at different hacking levels.

View File

@@ -4,7 +4,7 @@
## NS.hackAnalyze() method
Get the percent of money stolen with a single thread.
Get the part of money stolen with a single thread.
<b>Signature:</b>
@@ -22,13 +22,13 @@ hackAnalyze(host: string): number;
number
The percentage of money you will steal from the target server with a single hack.
The part of money you will steal from the target server with a single thread hack.
## Remarks
RAM cost: 1 GB
Returns the percentage of the specified servers money you will steal with a single hack. This value is returned in percentage form, not decimal (Netscript functions typically return in decimal form, but not this one).
Returns the part of the specified servers money you will steal with a single thread hack.
## Example
@@ -36,6 +36,6 @@ Returns the percentage of the specified servers money you will steal with a s
```ts
//For example, assume the following returns 0.01:
hackAnalyze("foodnstuff");
//This means that if hack the foodnstuff server, then you will steal 1% of its total money. If you hack using N threads, then you will steal N*0.01 times its total money.
//This means that if hack the foodnstuff server using a single thread, then you will steal 1%, or 0.01 of its total money. If you hack using N threads, then you will steal N*0.01 times its total money.
```

View File

@@ -51,6 +51,7 @@ export async function main(ns) {
| [sleeve](./bitburner.ns.sleeve.md) | [Sleeve](./bitburner.sleeve.md) | Namespace for sleeve functions. |
| [stanek](./bitburner.ns.stanek.md) | [Stanek](./bitburner.stanek.md) | Namespace for stanek functions. RAM cost: 0 GB |
| [stock](./bitburner.ns.stock.md) | [TIX](./bitburner.tix.md) | Namespace for stock functions. |
| [ui](./bitburner.ns.ui.md) | [UserInterface](./bitburner.userinterface.md) | Namespace for user interface functions. RAM cost: 0 GB |
## Methods
@@ -110,7 +111,7 @@ export async function main(ns) {
| [growthAnalyze(host, growthAmount, cores)](./bitburner.ns.growthanalyze.md) | Calculate the number of grow thread needed to grow a server by a certain multiplier. |
| [growthAnalyzeSecurity(threads)](./bitburner.ns.growthanalyzesecurity.md) | Calculate the security increase for a number of thread. |
| [hack(host, opts)](./bitburner.ns.hack.md) | Steal a servers money. |
| [hackAnalyze(host)](./bitburner.ns.hackanalyze.md) | Get the percent of money stolen with a single thread. |
| [hackAnalyze(host)](./bitburner.ns.hackanalyze.md) | Get the part of money stolen with a single thread. |
| [hackAnalyzeChance(host)](./bitburner.ns.hackanalyzechance.md) | Get the chance of successfully hacking a server. |
| [hackAnalyzeSecurity(threads)](./bitburner.ns.hackanalyzesecurity.md) | Get the security increase for a number of thread. |
| [hackAnalyzeThreads(host, hackAmount)](./bitburner.ns.hackanalyzethreads.md) | Predict the effect of hack. |

View File

@@ -31,9 +31,9 @@ The hostname of the newly purchased server.
Purchased a server with the specified hostname and amount of RAM.
The hostname argument can be any data type, but it will be converted to a string and have whitespace removed. Anything that resolves to an empty string will cause the function to fail. If there is already a server with the specified hostname, then the function will automatically append a number at the end of the hostname argument value until it finds a unique hostname. For example, if the script calls `purchaseServer(“foo”, 4)` but a server named “foo” already exists, the it will automatically change the hostname to `foo-0`<!-- -->. If there is already a server with the hostname `foo-0`<!-- -->, then it will change the hostname to `foo-1`<!-- -->, and so on.
The hostname argument can be any data type, but it will be converted to a string and have whitespace removed. Anything that resolves to an empty string will cause the function to fail. If there is already a server with the specified hostname, then the function will automatically append a number at the end of the hostname argument value until it finds a unique hostname. For example, if the script calls `purchaseServer(“foo”, 4)` but a server named “foo” already exists, it will automatically change the hostname to `foo-0`<!-- -->. If there is already a server with the hostname `foo-0`<!-- -->, then it will change the hostname to `foo-1`<!-- -->, and so on.
Note that there is a maximum limit to the amount of servers you can purchase.
Note that there is a maximum limit to the number of servers you can purchase.
Returns the hostname of the newly purchased server as a string. If the function fails to purchase a server, then it will return an empty string. The function will fail if the arguments passed in are invalid, if the player does not have enough money to purchase the specified server, or if the player has exceeded the maximum amount of servers.

View File

@@ -9,7 +9,7 @@ Start another script on the current server.
<b>Signature:</b>
```typescript
run(script: string, numThreads?: number, ...args: string[]): number;
run(script: string, numThreads?: number, ...args: Array<string | number | boolean>): number;
```
## Parameters
@@ -18,7 +18,7 @@ run(script: string, numThreads?: number, ...args: string[]): number;
| --- | --- | --- |
| script | string | Filename of script to run. |
| numThreads | number | Optional thread count for new script. Set to 1 by default. Will be rounded to nearest integer. |
| args | string\[\] | Additional arguments to pass into the new script that is being run. Note that if any arguments are being passed into the new script, then the second argument numThreads must be filled in with a value. |
| args | Array<string | number | boolean> | Additional arguments to pass into the new script that is being run. Note that if any arguments are being passed into the new script, then the second argument numThreads must be filled in with a value. |
<b>Returns:</b>

View File

@@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [NS](./bitburner.ns.md) &gt; [ui](./bitburner.ns.ui.md)
## NS.ui property
Namespace for user interface functions. RAM cost: 0 GB
<b>Signature:</b>
```typescript
readonly ui: UserInterface;
```

View File

@@ -30,7 +30,7 @@ RAM cost: 5 GB
This function is used to automatically attempt to commit crimes. If you are already in the middle of some working action (such as working for a company or training at a gym), then running this function will automatically cancel that action and give you your earnings.
This function returns the number of seconds it takes to attempt the specified crime (e.g It takes 60 seconds to attempt the Rob Store crime, so running `commitCrime('rob store')` will return 60).
This function returns the number of milliseconds it takes to attempt the specified crime (e.g It takes 60 seconds to attempt the Rob Store crime, so running `commitCrime('rob store')` will return 60,000).
Warning: I do not recommend using the time returned from this function to try and schedule your crime attempts. Instead, I would use the isBusy Singularity function to check whether you have finished attempting a crime. This is because although the game sets a certain crime to be X amount of seconds, there is no guarantee that your browser will follow that time limit.

View File

@@ -0,0 +1,23 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [UserInterface](./bitburner.userinterface.md) &gt; [getTheme](./bitburner.userinterface.gettheme.md)
## UserInterface.getTheme() method
Get the current theme
<b>Signature:</b>
```typescript
getTheme(): UserInterfaceTheme;
```
<b>Returns:</b>
UserInterfaceTheme
An object containing the theme's colors
## Remarks
RAM cost: cost: 0 GB

View File

@@ -0,0 +1,20 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [bitburner](./bitburner.md) &gt; [UserInterface](./bitburner.userinterface.md)
## UserInterface interface
User Interface API.
<b>Signature:</b>
```typescript
interface UserInterface
```
## Methods
| Method | Description |
| --- | --- |
| [getTheme()](./bitburner.userinterface.gettheme.md) | Get the current theme |

551
package-lock.json generated
View File

@@ -1,17 +1,17 @@
{
"name": "bitburner",
"version": "1.1.0",
"version": "1.2.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "bitburner",
"version": "1.1.0",
"version": "1.2.0",
"hasInstallScript": true,
"license": "SEE LICENSE IN license.txt",
"dependencies": {
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0",
"@material-ui/core": "^4.12.3",
"@microsoft/api-documenter": "^7.13.65",
"@microsoft/api-extractor": "^7.18.17",
"@monaco-editor/react": "^4.2.2",
@@ -22,6 +22,7 @@
"@types/escodegen": "^0.0.7",
"@types/numeral": "0.0.25",
"@types/react": "^17.0.21",
"@types/react-beautiful-dnd": "^13.1.2",
"@types/react-dom": "^17.0.9",
"@types/react-resizable": "^1.7.3",
"acorn": "^8.4.1",
@@ -30,17 +31,22 @@
"better-react-mathjax": "^1.0.3",
"clsx": "^1.1.1",
"date-fns": "^2.25.0",
"electron-config": "^2.0.0",
"escodegen": "^1.11.0",
"file-saver": "^1.3.8",
"fs": "^0.0.1-security",
"jquery": "^3.5.0",
"js-sha256": "^0.9.0",
"jszip": "^3.7.0",
"material-ui-color": "^1.2.0",
"material-ui-popup-state": "^1.5.3",
"monaco-editor": "^0.27.0",
"notistack": "^2.0.2",
"numeral": "2.0.6",
"prop-types": "^15.8.0",
"raw-loader": "^4.0.2",
"react": "^17.0.2",
"react-beautiful-dnd": "^13.1.0",
"react-dom": "^17.0.2",
"react-draggable": "^4.4.4",
"react-resizable": "^3.0.4",
@@ -2890,7 +2896,6 @@
"version": "4.12.3",
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.3.tgz",
"integrity": "sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw==",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.4.4",
"@material-ui/styles": "^4.11.4",
@@ -2927,7 +2932,6 @@
"version": "4.11.4",
"resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.4.tgz",
"integrity": "sha512-KNTIZcnj/zprG5LW0Sao7zw+yG3O35pviHzejMdcSGCdWbiO8qzRgOYL8JAxAsWBKOKYwVZxXtHWaB5T2Kvxew==",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.4.4",
"@emotion/hash": "^0.8.0",
@@ -2967,14 +2971,12 @@
"node_modules/@material-ui/styles/node_modules/csstype": {
"version": "2.6.18",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.18.tgz",
"integrity": "sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ==",
"peer": true
"integrity": "sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ=="
},
"node_modules/@material-ui/system": {
"version": "4.12.1",
"resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.1.tgz",
"integrity": "sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw==",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.4.4",
"@material-ui/utils": "^4.11.2",
@@ -3002,14 +3004,12 @@
"node_modules/@material-ui/system/node_modules/csstype": {
"version": "2.6.18",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.18.tgz",
"integrity": "sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ==",
"peer": true
"integrity": "sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ=="
},
"node_modules/@material-ui/types": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz",
"integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==",
"peer": true,
"peerDependencies": {
"@types/react": "*"
},
@@ -3023,7 +3023,6 @@
"version": "4.11.2",
"resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.2.tgz",
"integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.4.4",
"prop-types": "^15.7.2",
@@ -3984,6 +3983,15 @@
"@types/node": "*"
}
},
"node_modules/@types/hoist-non-react-statics": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
"integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
"dependencies": {
"@types/react": "*",
"hoist-non-react-statics": "^3.3.0"
}
},
"node_modules/@types/istanbul-lib-coverage": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz",
@@ -4062,6 +4070,14 @@
"csstype": "^3.0.2"
}
},
"node_modules/@types/react-beautiful-dnd": {
"version": "13.1.2",
"resolved": "https://registry.npmjs.org/@types/react-beautiful-dnd/-/react-beautiful-dnd-13.1.2.tgz",
"integrity": "sha512-+OvPkB8CdE/bGdXKyIhc/Lm2U7UAYCCJgsqmopFmh9gbAudmslkI8eOrPDjg4JhwSE6wytz4a3/wRjKtovHVJg==",
"dependencies": {
"@types/react": "*"
}
},
"node_modules/@types/react-dom": {
"version": "17.0.9",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz",
@@ -4078,6 +4094,17 @@
"@types/react": "*"
}
},
"node_modules/@types/react-redux": {
"version": "7.1.20",
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.20.tgz",
"integrity": "sha512-q42es4c8iIeTgcnB+yJgRTTzftv3eYYvCZOh1Ckn2eX/3o5TdsQYKUWpLoLuGlcY/p+VAhV9IOEZJcWk/vfkXw==",
"dependencies": {
"@types/hoist-non-react-statics": "^3.3.0",
"@types/react": "*",
"hoist-non-react-statics": "^3.3.0",
"redux": "^4.0.0"
}
},
"node_modules/@types/react-resizable": {
"version": "1.7.4",
"resolved": "https://registry.npmjs.org/@types/react-resizable/-/react-resizable-1.7.4.tgz",
@@ -6044,8 +6071,7 @@
"node_modules/classnames": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
"integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==",
"peer": true
"integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
},
"node_modules/clean-css": {
"version": "4.2.3",
@@ -6351,6 +6377,58 @@
"safe-buffer": "~5.1.0"
}
},
"node_modules/conf": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/conf/-/conf-1.4.0.tgz",
"integrity": "sha512-bzlVWS2THbMetHqXKB8ypsXN4DQ/1qopGwNJi1eYbpwesJcd86FBjFciCQX/YwAhp9bM7NVnPFqZ5LpV7gP0Dg==",
"dependencies": {
"dot-prop": "^4.1.0",
"env-paths": "^1.0.0",
"make-dir": "^1.0.0",
"pkg-up": "^2.0.0",
"write-file-atomic": "^2.3.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/conf/node_modules/env-paths": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-1.0.0.tgz",
"integrity": "sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA=",
"engines": {
"node": ">=4"
}
},
"node_modules/conf/node_modules/make-dir": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
"integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
"dependencies": {
"pify": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/conf/node_modules/pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
"engines": {
"node": ">=4"
}
},
"node_modules/conf/node_modules/write-file-atomic": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz",
"integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==",
"dependencies": {
"graceful-fs": "^4.1.11",
"imurmurhash": "^0.1.4",
"signal-exit": "^3.0.2"
}
},
"node_modules/config-chain": {
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
@@ -6659,6 +6737,14 @@
"node": "*"
}
},
"node_modules/css-box-model": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz",
"integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==",
"dependencies": {
"tiny-invariant": "^1.0.6"
}
},
"node_modules/css-select": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz",
@@ -7508,6 +7594,17 @@
"webidl-conversions": "^4.0.2"
}
},
"node_modules/dot-prop": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.1.tgz",
"integrity": "sha512-l0p4+mIuJIua0mhxGoh4a+iNL9bmeK5DvnSVQa6T0OhrVmaEa1XScX5Etc673FePCJOArq/4Pa2cLGODUWTPOQ==",
"dependencies": {
"is-obj": "^1.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/duplexer": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
@@ -7592,6 +7689,15 @@
"node": ">= 8.6"
}
},
"node_modules/electron-config": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/electron-config/-/electron-config-2.0.0.tgz",
"integrity": "sha512-5mGwRK4lsAo6tiy4KNF/zUInYpUGr7JJzLA8FHOoqBWV3kkKJWSrDXo4Uk2Ffm5aeQ1o73XuorfkYhaWFV2O4g==",
"deprecated": "Renamed to `electron-store`.",
"dependencies": {
"conf": "^1.0.0"
}
},
"node_modules/electron-notarize": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/electron-notarize/-/electron-notarize-1.1.1.tgz",
@@ -11230,6 +11336,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-obj": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
"integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-path-cwd": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
@@ -13655,6 +13769,11 @@
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz",
"integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw=="
},
"node_modules/js-sha256": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz",
"integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA=="
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -14498,7 +14617,6 @@
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/material-ui-popup-state/-/material-ui-popup-state-1.9.3.tgz",
"integrity": "sha512-+Ete5Tzw5rXlYfmqptOS8kBUH8vnK5OJsd6IQ7SHtLjU0PsvsmM73M/k8ot0xkX4RmPGuNRsFbK3mlCe/ClQuw==",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.12.5",
"@material-ui/types": "^6.0.1",
@@ -14514,7 +14632,6 @@
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/@material-ui/types/-/types-6.0.2.tgz",
"integrity": "sha512-/XUca4wUb9pWimLLdM1PE8KS8rTbDEGohSGkGtk3WST7lm23m+8RYv9uOmrvOg/VSsl4bMiOv4t2/LCb+RLbTg==",
"peer": true,
"peerDependencies": {
"@types/react": "*"
},
@@ -14566,6 +14683,11 @@
"node": ">= 4.0.0"
}
},
"node_modules/memoize-one": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q=="
},
"node_modules/memory-fs": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
@@ -15955,6 +16077,78 @@
"node": ">=8"
}
},
"node_modules/pkg-up": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz",
"integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=",
"dependencies": {
"find-up": "^2.1.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/pkg-up/node_modules/find-up": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
"integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
"dependencies": {
"locate-path": "^2.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/pkg-up/node_modules/locate-path": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
"integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
"dependencies": {
"p-locate": "^2.0.0",
"path-exists": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/pkg-up/node_modules/p-limit": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
"integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
"dependencies": {
"p-try": "^1.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/pkg-up/node_modules/p-locate": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
"integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
"dependencies": {
"p-limit": "^1.1.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/pkg-up/node_modules/p-try": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
"integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
"engines": {
"node": ">=4"
}
},
"node_modules/pkg-up/node_modules/path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
"engines": {
"node": ">=4"
}
},
"node_modules/plist": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/plist/-/plist-3.0.4.tgz",
@@ -15977,8 +16171,7 @@
"node_modules/popper.js": {
"version": "1.16.1-lts",
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz",
"integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==",
"peer": true
"integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA=="
},
"node_modules/portfinder": {
"version": "1.0.28",
@@ -16131,13 +16324,13 @@
}
},
"node_modules/prop-types": {
"version": "15.7.2",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
"version": "15.8.0",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.0.tgz",
"integrity": "sha512-fDGekdaHh65eI3lMi5OnErU6a8Ighg2KjcjQxO7m8VHyWjcPyj5kiOgV1LQDOOOgVy3+5FgjXvdSSX7B8/5/4g==",
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.8.1"
"react-is": "^16.13.1"
}
},
"node_modules/prop-types/node_modules/react-is": {
@@ -16303,6 +16496,11 @@
}
]
},
"node_modules/raf-schd": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz",
"integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ=="
},
"node_modules/ramda": {
"version": "0.27.1",
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz",
@@ -16429,6 +16627,24 @@
"node": ">=0.10.0"
}
},
"node_modules/react-beautiful-dnd": {
"version": "13.1.0",
"resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.0.tgz",
"integrity": "sha512-aGvblPZTJowOWUNiwd6tNfEpgkX5OxmpqxHKNW/4VmvZTNTbeiq7bA3bn5T+QSF2uibXB0D1DmJsb1aC/+3cUA==",
"dependencies": {
"@babel/runtime": "^7.9.2",
"css-box-model": "^1.2.0",
"memoize-one": "^5.1.1",
"raf-schd": "^4.0.2",
"react-redux": "^7.2.0",
"redux": "^4.0.4",
"use-memo-one": "^1.1.1"
},
"peerDependencies": {
"react": "^16.8.5 || ^17.0.0",
"react-dom": "^16.8.5 || ^17.0.0"
}
},
"node_modules/react-dom": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
@@ -16460,6 +16676,30 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
},
"node_modules/react-redux": {
"version": "7.2.6",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz",
"integrity": "sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ==",
"dependencies": {
"@babel/runtime": "^7.15.4",
"@types/react-redux": "^7.1.20",
"hoist-non-react-statics": "^3.3.2",
"loose-envify": "^1.4.0",
"prop-types": "^15.7.2",
"react-is": "^17.0.2"
},
"peerDependencies": {
"react": "^16.8.3 || ^17"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": true
},
"react-native": {
"optional": true
}
}
},
"node_modules/react-refresh": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.10.0.tgz",
@@ -16625,6 +16865,14 @@
"node": ">=8.10.0"
}
},
"node_modules/redux": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz",
"integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==",
"dependencies": {
"@babel/runtime": "^7.9.2"
}
},
"node_modules/regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -17596,8 +17844,7 @@
"node_modules/signal-exit": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz",
"integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==",
"dev": true
"integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ=="
},
"node_modules/sisteransi": {
"version": "1.0.5",
@@ -19143,6 +19390,11 @@
"resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q="
},
"node_modules/tiny-invariant": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz",
"integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg=="
},
"node_modules/tiny-warning": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
@@ -19717,6 +19969,14 @@
"node": ">=0.10.0"
}
},
"node_modules/use-memo-one": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.2.tgz",
"integrity": "sha512-u2qFKtxLsia/r8qG0ZKkbytbztzRb317XCkT7yP8wxL0tZ/CzK2G+WWie5vWvpyeP7+YoPIwbJoIHJ4Ba4k0oQ==",
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0"
}
},
"node_modules/util": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
@@ -23848,7 +24108,6 @@
"version": "4.12.3",
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.3.tgz",
"integrity": "sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw==",
"peer": true,
"requires": {
"@babel/runtime": "^7.4.4",
"@material-ui/styles": "^4.11.4",
@@ -23868,7 +24127,6 @@
"version": "4.11.4",
"resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.4.tgz",
"integrity": "sha512-KNTIZcnj/zprG5LW0Sao7zw+yG3O35pviHzejMdcSGCdWbiO8qzRgOYL8JAxAsWBKOKYwVZxXtHWaB5T2Kvxew==",
"peer": true,
"requires": {
"@babel/runtime": "^7.4.4",
"@emotion/hash": "^0.8.0",
@@ -23891,8 +24149,7 @@
"csstype": {
"version": "2.6.18",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.18.tgz",
"integrity": "sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ==",
"peer": true
"integrity": "sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ=="
}
}
},
@@ -23900,7 +24157,6 @@
"version": "4.12.1",
"resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.1.tgz",
"integrity": "sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw==",
"peer": true,
"requires": {
"@babel/runtime": "^7.4.4",
"@material-ui/utils": "^4.11.2",
@@ -23911,8 +24167,7 @@
"csstype": {
"version": "2.6.18",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.18.tgz",
"integrity": "sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ==",
"peer": true
"integrity": "sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ=="
}
}
},
@@ -23920,14 +24175,12 @@
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz",
"integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==",
"peer": true,
"requires": {}
},
"@material-ui/utils": {
"version": "4.11.2",
"resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.2.tgz",
"integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==",
"peer": true,
"requires": {
"@babel/runtime": "^7.4.4",
"prop-types": "^15.7.2",
@@ -24597,6 +24850,15 @@
"@types/node": "*"
}
},
"@types/hoist-non-react-statics": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
"integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
"requires": {
"@types/react": "*",
"hoist-non-react-statics": "^3.3.0"
}
},
"@types/istanbul-lib-coverage": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz",
@@ -24675,6 +24937,14 @@
"csstype": "^3.0.2"
}
},
"@types/react-beautiful-dnd": {
"version": "13.1.2",
"resolved": "https://registry.npmjs.org/@types/react-beautiful-dnd/-/react-beautiful-dnd-13.1.2.tgz",
"integrity": "sha512-+OvPkB8CdE/bGdXKyIhc/Lm2U7UAYCCJgsqmopFmh9gbAudmslkI8eOrPDjg4JhwSE6wytz4a3/wRjKtovHVJg==",
"requires": {
"@types/react": "*"
}
},
"@types/react-dom": {
"version": "17.0.9",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz",
@@ -24691,6 +24961,17 @@
"@types/react": "*"
}
},
"@types/react-redux": {
"version": "7.1.20",
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.20.tgz",
"integrity": "sha512-q42es4c8iIeTgcnB+yJgRTTzftv3eYYvCZOh1Ckn2eX/3o5TdsQYKUWpLoLuGlcY/p+VAhV9IOEZJcWk/vfkXw==",
"requires": {
"@types/hoist-non-react-statics": "^3.3.0",
"@types/react": "*",
"hoist-non-react-statics": "^3.3.0",
"redux": "^4.0.0"
}
},
"@types/react-resizable": {
"version": "1.7.4",
"resolved": "https://registry.npmjs.org/@types/react-resizable/-/react-resizable-1.7.4.tgz",
@@ -26256,8 +26537,7 @@
"classnames": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
"integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==",
"peer": true
"integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
},
"clean-css": {
"version": "4.2.3",
@@ -26512,6 +26792,48 @@
}
}
},
"conf": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/conf/-/conf-1.4.0.tgz",
"integrity": "sha512-bzlVWS2THbMetHqXKB8ypsXN4DQ/1qopGwNJi1eYbpwesJcd86FBjFciCQX/YwAhp9bM7NVnPFqZ5LpV7gP0Dg==",
"requires": {
"dot-prop": "^4.1.0",
"env-paths": "^1.0.0",
"make-dir": "^1.0.0",
"pkg-up": "^2.0.0",
"write-file-atomic": "^2.3.0"
},
"dependencies": {
"env-paths": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-1.0.0.tgz",
"integrity": "sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA="
},
"make-dir": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
"integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
"requires": {
"pify": "^3.0.0"
}
},
"pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
},
"write-file-atomic": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz",
"integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==",
"requires": {
"graceful-fs": "^4.1.11",
"imurmurhash": "^0.1.4",
"signal-exit": "^3.0.2"
}
}
}
},
"config-chain": {
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz",
@@ -26762,6 +27084,14 @@
"randomfill": "^1.0.3"
}
},
"css-box-model": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz",
"integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==",
"requires": {
"tiny-invariant": "^1.0.6"
}
},
"css-select": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz",
@@ -27436,6 +27766,14 @@
"webidl-conversions": "^4.0.2"
}
},
"dot-prop": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.1.tgz",
"integrity": "sha512-l0p4+mIuJIua0mhxGoh4a+iNL9bmeK5DvnSVQa6T0OhrVmaEa1XScX5Etc673FePCJOArq/4Pa2cLGODUWTPOQ==",
"requires": {
"is-obj": "^1.0.0"
}
},
"duplexer": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
@@ -27550,6 +27888,14 @@
}
}
},
"electron-config": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/electron-config/-/electron-config-2.0.0.tgz",
"integrity": "sha512-5mGwRK4lsAo6tiy4KNF/zUInYpUGr7JJzLA8FHOoqBWV3kkKJWSrDXo4Uk2Ffm5aeQ1o73XuorfkYhaWFV2O4g==",
"requires": {
"conf": "^1.0.0"
}
},
"electron-notarize": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/electron-notarize/-/electron-notarize-1.1.1.tgz",
@@ -30375,6 +30721,11 @@
"has-tostringtag": "^1.0.0"
}
},
"is-obj": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
"integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8="
},
"is-path-cwd": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
@@ -32184,6 +32535,11 @@
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz",
"integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw=="
},
"js-sha256": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz",
"integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA=="
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -32860,7 +33216,6 @@
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/material-ui-popup-state/-/material-ui-popup-state-1.9.3.tgz",
"integrity": "sha512-+Ete5Tzw5rXlYfmqptOS8kBUH8vnK5OJsd6IQ7SHtLjU0PsvsmM73M/k8ot0xkX4RmPGuNRsFbK3mlCe/ClQuw==",
"peer": true,
"requires": {
"@babel/runtime": "^7.12.5",
"@material-ui/types": "^6.0.1",
@@ -32872,7 +33227,6 @@
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/@material-ui/types/-/types-6.0.2.tgz",
"integrity": "sha512-/XUca4wUb9pWimLLdM1PE8KS8rTbDEGohSGkGtk3WST7lm23m+8RYv9uOmrvOg/VSsl4bMiOv4t2/LCb+RLbTg==",
"peer": true,
"requires": {}
}
}
@@ -32913,6 +33267,11 @@
"fs-monkey": "1.0.3"
}
},
"memoize-one": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q=="
},
"memory-fs": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
@@ -34011,6 +34370,59 @@
}
}
},
"pkg-up": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz",
"integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=",
"requires": {
"find-up": "^2.1.0"
},
"dependencies": {
"find-up": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
"integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
"requires": {
"locate-path": "^2.0.0"
}
},
"locate-path": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
"integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
"requires": {
"p-locate": "^2.0.0",
"path-exists": "^3.0.0"
}
},
"p-limit": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
"integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
"requires": {
"p-try": "^1.0.0"
}
},
"p-locate": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
"integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
"requires": {
"p-limit": "^1.1.0"
}
},
"p-try": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
"integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M="
},
"path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
}
}
},
"plist": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/plist/-/plist-3.0.4.tgz",
@@ -34030,8 +34442,7 @@
"popper.js": {
"version": "1.16.1-lts",
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz",
"integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==",
"peer": true
"integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA=="
},
"portfinder": {
"version": "1.0.28",
@@ -34146,13 +34557,13 @@
}
},
"prop-types": {
"version": "15.7.2",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
"version": "15.8.0",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.0.tgz",
"integrity": "sha512-fDGekdaHh65eI3lMi5OnErU6a8Ighg2KjcjQxO7m8VHyWjcPyj5kiOgV1LQDOOOgVy3+5FgjXvdSSX7B8/5/4g==",
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.8.1"
"react-is": "^16.13.1"
},
"dependencies": {
"react-is": {
@@ -34288,6 +34699,11 @@
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
"dev": true
},
"raf-schd": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz",
"integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ=="
},
"ramda": {
"version": "0.27.1",
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz",
@@ -34384,6 +34800,20 @@
"object-assign": "^4.1.1"
}
},
"react-beautiful-dnd": {
"version": "13.1.0",
"resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.0.tgz",
"integrity": "sha512-aGvblPZTJowOWUNiwd6tNfEpgkX5OxmpqxHKNW/4VmvZTNTbeiq7bA3bn5T+QSF2uibXB0D1DmJsb1aC/+3cUA==",
"requires": {
"@babel/runtime": "^7.9.2",
"css-box-model": "^1.2.0",
"memoize-one": "^5.1.1",
"raf-schd": "^4.0.2",
"react-redux": "^7.2.0",
"redux": "^4.0.4",
"use-memo-one": "^1.1.1"
}
},
"react-dom": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
@@ -34408,6 +34838,19 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
},
"react-redux": {
"version": "7.2.6",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz",
"integrity": "sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ==",
"requires": {
"@babel/runtime": "^7.15.4",
"@types/react-redux": "^7.1.20",
"hoist-non-react-statics": "^3.3.2",
"loose-envify": "^1.4.0",
"prop-types": "^15.7.2",
"react-is": "^17.0.2"
}
},
"react-refresh": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.10.0.tgz",
@@ -34537,6 +34980,14 @@
"picomatch": "^2.2.1"
}
},
"redux": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz",
"integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==",
"requires": {
"@babel/runtime": "^7.9.2"
}
},
"regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -35305,8 +35756,7 @@
"signal-exit": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz",
"integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==",
"dev": true
"integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ=="
},
"sisteransi": {
"version": "1.0.5",
@@ -36569,6 +37019,11 @@
"resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q="
},
"tiny-invariant": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz",
"integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg=="
},
"tiny-warning": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
@@ -37025,6 +37480,12 @@
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
},
"use-memo-one": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.2.tgz",
"integrity": "sha512-u2qFKtxLsia/r8qG0ZKkbytbztzRb317XCkT7yP8wxL0tZ/CzK2G+WWie5vWvpyeP7+YoPIwbJoIHJ4Ba4k0oQ==",
"requires": {}
},
"util": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",

View File

@@ -1,7 +1,7 @@
{
"name": "bitburner",
"license": "SEE LICENSE IN license.txt",
"version": "1.2.0",
"version": "1.3.0",
"main": "electron-main.js",
"author": {
"name": "Daniel Xie & Olivier Gagnon"
@@ -12,6 +12,7 @@
"dependencies": {
"@emotion/react": "^11.4.1",
"@emotion/styled": "^11.3.0",
"@material-ui/core": "^4.12.3",
"@microsoft/api-documenter": "^7.13.65",
"@microsoft/api-extractor": "^7.18.17",
"@monaco-editor/react": "^4.2.2",
@@ -22,6 +23,7 @@
"@types/escodegen": "^0.0.7",
"@types/numeral": "0.0.25",
"@types/react": "^17.0.21",
"@types/react-beautiful-dnd": "^13.1.2",
"@types/react-dom": "^17.0.9",
"@types/react-resizable": "^1.7.3",
"acorn": "^8.4.1",
@@ -30,17 +32,22 @@
"better-react-mathjax": "^1.0.3",
"clsx": "^1.1.1",
"date-fns": "^2.25.0",
"electron-config": "^2.0.0",
"escodegen": "^1.11.0",
"file-saver": "^1.3.8",
"fs": "^0.0.1-security",
"jquery": "^3.5.0",
"js-sha256": "^0.9.0",
"jszip": "^3.7.0",
"material-ui-color": "^1.2.0",
"material-ui-popup-state": "^1.5.3",
"monaco-editor": "^0.27.0",
"notistack": "^2.0.2",
"numeral": "2.0.6",
"prop-types": "^15.8.0",
"raw-loader": "^4.0.2",
"react": "^17.0.2",
"react-beautiful-dnd": "^13.1.0",
"react-dom": "^17.0.2",
"react-draggable": "^4.4.4",
"react-resizable": "^3.0.4",
@@ -104,12 +111,14 @@
"build": "webpack --mode production",
"build:dev": "webpack --mode development",
"lint": "eslint --fix . --ext js,jsx,ts,tsx",
"lint:report": "eslint --ext js,jsx,ts,tsx .",
"preinstall": "node ./scripts/engines-check.js",
"test": "jest",
"test:watch": "jest --watch",
"watch": "webpack --watch --mode production",
"watch:dev": "webpack --watch --mode development",
"electron": "cp -r electron/* .package && cp index.html .package && cp main.bundle.js .package && cp dist/vendor.bundle.js .package/dist/ && cp -r dist/ext .package/dist/ && electron-packager .package bitburner --all --out .build --overwrite --icon .package/icon.png",
"electron": "sh ./package.sh",
"electron:packager": "electron-packager .package bitburner --all --out .build --overwrite --icon .package/icon.png --no-prune",
"allbuild": "npm run build && npm run electron && git add --all && git commit --amend --no-edit && git push -f -u origin dev"
}
}

View File

@@ -1,11 +1,13 @@
# npm install electron --save-dev
# npm install electron-packager --save-dev
#!/bin/sh
mkdir -p .package/dist/src/ThirdParty || true
mkdir -p .package/src/ThirdParty || true
mkdir -p .package/node_modules || true
cp index.html .package
cp electron/* .package
cp -r electron/* .package
cp -r dist/ext .package/dist
# The css files
cp dist/vendor.css .package/dist
cp main.css .package/main.css
@@ -14,6 +16,14 @@ cp main.css .package/main.css
cp dist/vendor.bundle.js .package/dist/vendor.bundle.js
cp main.bundle.js .package/main.bundle.js
cp src/ThirdParty/raphael.min.js .package/src/ThirdParty/raphael.min.js
# Source maps
cp dist/vendor.bundle.js.map .package/dist/vendor.bundle.js.map
cp main.bundle.js.map .package/main.bundle.js.map
npm run package-electron
# Install electron sub-dependencies
cd electron
npm install
cd ..
# And finally build the app.
npm run electron:packager

View File

@@ -36,15 +36,16 @@ export function printAliases(): void {
// Returns true if successful, false otherwise
export function parseAliasDeclaration(dec: string, global = false): boolean {
const re = /^([_|\w|!|%|,|@]+)="(.+)"$/;
const re = /^([\w|!|%|,|@|-]+)=(("(.+)")|('(.+)'))$/;
const matches = dec.match(re);
if (matches == null || matches.length != 3) {
if (matches == null || matches.length != 7) {
return false;
}
if (global) {
addGlobalAlias(matches[1], matches[2]);
addGlobalAlias(matches[1], matches[4] || matches[6]);
} else {
addAlias(matches[1], matches[2]);
addAlias(matches[1], matches[4] || matches[6]);
}
return true;
}

View File

@@ -1844,7 +1844,7 @@ function initAugmentations(): void {
moneyCost: 3.75e8,
info:
"A drug that genetically modifies the neurons in the brain " +
"resulting in neurons never die, continuously " +
"resulting in neurons that never die, continuously " +
"regenerate, and strengthen themselves.",
hacking_exp_mult: 1.4,
});
@@ -1925,7 +1925,7 @@ function initAugmentations(): void {
repCost: 7.5e3,
moneyCost: 3e7,
info:
"A tiny chip that sits behind the retinae. This implant lets the" + "user visually detect infrared radiation.",
"A tiny chip that sits behind the retinae. This implant lets the user visually detect infrared radiation.",
crime_success_mult: 1.25,
crime_money_mult: 1.1,
dexterity_mult: 1.1,

View File

@@ -16,6 +16,8 @@ import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import Tooltip from "@mui/material/Tooltip";
import Box from "@mui/material/Box";
import { Settings } from "../../Settings/Settings";
import { ConfirmationModal } from "../../ui/React/ConfirmationModal";
interface IProps {
exportGameFn: () => void;
@@ -23,6 +25,7 @@ interface IProps {
}
export function AugmentationsRoot(props: IProps): React.ReactElement {
const [installOpen, setInstallOpen] = useState(false);
const player = use.Player();
const setRerender = useState(false)[1];
function rerender(): void {
@@ -43,6 +46,14 @@ export function AugmentationsRoot(props: IProps): React.ReactElement {
return "";
}
function doInstall(): void {
if (!Settings.SuppressBuyAugmentationConfirmation) {
setInstallOpen(true);
} else {
props.installAugmentationsFn();
}
}
return (
<>
<Typography variant="h4">Augmentations</Typography>
@@ -73,11 +84,36 @@ export function AugmentationsRoot(props: IProps): React.ReactElement {
<Box mx={2}>
<Tooltip title={<Typography>'I never asked for this'</Typography>}>
<span>
<Button disabled={player.queuedAugmentations.length === 0} onClick={props.installAugmentationsFn}>
<Button disabled={player.queuedAugmentations.length === 0} onClick={doInstall}>
Install Augmentations
</Button>
</span>
</Tooltip>
<ConfirmationModal
open={installOpen}
onClose={() => setInstallOpen(false)}
onConfirm={props.installAugmentationsFn}
confirmationText={
<>
Installing will reset
<br />
<br />- money
<br />- skill / experience
<br />- every server except home
<br />- factions and reputation
<br />
<br />
You will keep:
<br />
<br />- All scripts on home
<br />- home ram and cores
<br />
<br />
It is recommended to install several Augmentations at once. Preferably everything from any faction of your
chosing.
</>
}
/>
<Tooltip title={<Typography>It's always a good idea to backup/export your save!</Typography>}>
<Button sx={{ mx: 2 }} onClick={doExport} color="error">
Backup Save {exportBonusStr()}

View File

@@ -165,7 +165,7 @@ BitNodes["BitNode4"] = new BitNode(
<br />
Destroying this BitNode will give you Source-File 4, or if you already have this Source-File it will upgrade its
level up to a maximum of 3. This Source-File lets you access and use the Singularity Functions in other BitNodes.
Each level of this Source-File will open up more Singularity Functions that you can use.
Each level of this Source-File reduces the RAM cost of singularity functions.
</>
),
);
@@ -542,7 +542,7 @@ BitNodes["BitNode13"] = new BitNode(
<br />
<br />
Their leader, Allison "Mother" Stanek is said to have created her own Augmentation whose power goes beyond any
other. Find her in Chongquing and gain her trust.
other. Find her in Chongqing and gain her trust.
<br />
<br />
In this BitNode:
@@ -745,7 +745,7 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.StaneksGiftPowerMultiplier = 0.5;
BitNodeMultipliers.StaneksGiftExtraSize = 2;
BitNodeMultipliers.GangSoftcap = 0.8;
BitNodeMultipliers.CorporationSoftCap = 0.9;
BitNodeMultipliers.CorporationSoftCap = 0.7;
BitNodeMultipliers.WorldDaemonDifficulty = 2;
break;
case 10: // Digital Carbon

View File

@@ -34,6 +34,12 @@ import { getTimestamp } from "../utils/helpers/getTimestamp";
import { joinFaction } from "../Faction/FactionHelpers";
import { WorkerScript } from "../Netscript/WorkerScript";
interface BlackOpsAttempt {
error?: string;
isAvailable?: boolean;
action?: BlackOperation;
}
export class Bladeburner implements IBladeburner {
numHosp = 0;
moneyLost = 0;
@@ -113,6 +119,43 @@ export class Bladeburner implements IBladeburner {
return Math.min(1, this.stamina / (0.5 * this.maxStamina));
}
canAttemptBlackOp(actionId: IActionIdentifier): BlackOpsAttempt {
// Safety measure - don't repeat BlackOps that are already done
if (this.blackops[actionId.name] != null) {
return { error: "Tried to start a Black Operation that had already been completed" };
}
const action = this.getActionObject(actionId);
if (!(action instanceof BlackOperation)) throw new Error(`Action should be BlackOperation but isn't`);
if (action == null) throw new Error("Failed to get BlackOperation object for: " + actionId.name);
if (action.reqdRank > this.rank) {
return { error: "Tried to start a Black Operation without the rank requirement" };
}
// Can't start a BlackOp if you haven't done the one before it
const blackops = [];
for (const nm in BlackOperations) {
if (BlackOperations.hasOwnProperty(nm)) {
blackops.push(nm);
}
}
blackops.sort(function (a, b) {
return BlackOperations[a].reqdRank - BlackOperations[b].reqdRank; // Sort black ops in intended order
});
const i = blackops.indexOf(actionId.name);
if (i === -1) {
return { error: `Invalid Black Op: '${name}'` };
}
if (i > 0 && this.blackops[blackops[i - 1]] == null) {
return { error: `Preceding Black Op must be completed before starting '${actionId.name}'.` };
}
return { isAvailable: true, action };
}
startAction(player: IPlayer, actionId: IActionIdentifier): void {
if (actionId == null) return;
this.action = actionId;
@@ -156,18 +199,16 @@ export class Bladeburner implements IBladeburner {
case ActionTypes["BlackOp"]:
case ActionTypes["BlackOperation"]: {
try {
// Safety measure - don't repeat BlackOps that are already done
if (this.blackops[actionId.name] != null) {
const testBlackOp = this.canAttemptBlackOp(actionId);
if (!testBlackOp.isAvailable) {
this.resetAction();
this.log("Error: Tried to start a Black Operation that had already been completed");
this.log(`Error: ${testBlackOp.error}`);
break;
}
const action = this.getActionObject(actionId);
if (action == null) {
throw new Error("Failed to get BlackOperation object for: " + actionId.name);
if (testBlackOp.action === undefined) {
throw new Error("action should not be null");
}
this.actionTimeToComplete = action.getActionTime(this);
this.actionTimeToComplete = testBlackOp.action.getActionTime(this);
} catch (e: any) {
exceptionAlert(e);
}
@@ -502,6 +543,7 @@ export class Bladeburner implements IBladeburner {
const skill = Skills[skillName];
if (skill == null || !(skill instanceof Skill)) {
this.postToConsole("Invalid skill name (Note that it is case-sensitive): " + skillName);
break;
}
if (args[1].toLowerCase() === "list") {
let level = 0;
@@ -515,7 +557,9 @@ export class Bladeburner implements IBladeburner {
currentLevel = this.skills[skillName];
}
const pointCost = skill.calculateCost(currentLevel);
if (this.skillPoints >= pointCost) {
if (skill.maxLvl !== 0 && currentLevel >= skill.maxLvl) {
this.postToConsole(`This skill ${skill.name} is already at max level (${currentLevel}/${skill.maxLvl}).`);
} else if (this.skillPoints >= pointCost) {
this.skillPoints -= pointCost;
this.upgradeSkill(skill);
this.log(skill.name + " upgraded to Level " + this.skills[skillName]);
@@ -2032,44 +2076,9 @@ export class Bladeburner implements IBladeburner {
// Special logic for Black Ops
if (actionId.type === ActionTypes["BlackOp"]) {
// Can't start a BlackOp if you don't have the required rank
const action = this.getActionObject(actionId);
if (action == null) throw new Error(`Action not found ${actionId.type}, ${actionId.name}`);
if (!(action instanceof BlackOperation)) throw new Error(`Action should be BlackOperation but isn't`);
//const blackOp = (action as BlackOperation);
if (action.reqdRank > this.rank) {
workerScript.log("bladeburner.startAction", () => `Insufficient rank to start Black Op '${actionId.name}'.`);
return false;
}
// Can't start a BlackOp if its already been done
if (this.blackops[actionId.name] != null) {
workerScript.log("bladeburner.startAction", () => `Black Op ${actionId.name} has already been completed.`);
return false;
}
// Can't start a BlackOp if you haven't done the one before it
const blackops = [];
for (const nm in BlackOperations) {
if (BlackOperations.hasOwnProperty(nm)) {
blackops.push(nm);
}
}
blackops.sort(function (a, b) {
return BlackOperations[a].reqdRank - BlackOperations[b].reqdRank; // Sort black ops in intended order
});
const i = blackops.indexOf(actionId.name);
if (i === -1) {
workerScript.log("bladeburner.startAction", () => `Invalid Black Op: '${name}'`);
return false;
}
if (i > 0 && this.blackops[blackops[i - 1]] == null) {
workerScript.log(
"bladeburner.startAction",
() => `Preceding Black Op must be completed before starting '${actionId.name}'.`,
);
const canRunOp = this.canAttemptBlackOp(actionId);
if (!canRunOp.isAvailable) {
workerScript.log("bladeburner.startAction", () => canRunOp.error + "");
return false;
}
}

View File

@@ -25,8 +25,8 @@ export const ConsoleHelpText: {
"automate [var] [val] [hi/low]",
"",
"A simple way to automate your Bladeburner actions. This console command can be used " +
"to automatically start an action when your stamina rises above a certain threshold, and " +
"automatically switch to another action when your stamina drops below another threshold.",
"to automatically start an action when your stamina rises above a certain threshold, and " +
"automatically switch to another action when your stamina drops below another threshold.",
" automate status - Check the current status of your automation and get a brief description of what it'll do",
" automate en - Enable the automation feature",
" automate dis - Disable the automation feature",
@@ -39,9 +39,9 @@ export const ConsoleHelpText: {
" automate general 'Field Analysis' low",
"",
"Using the four console commands above will set the automation to perform Tracking contracts " +
"if your stamina is 100 or higher, and then switch to Field Analysis if your stamina drops below " +
"50. Note that when setting the action, the name of the action is CASE-SENSITIVE. It must " +
"exactly match whatever the name is in the UI.",
"if your stamina is 100 or higher, and then switch to Field Analysis if your stamina drops below " +
"50. Note that when setting the action, the name of the action is CASE-SENSITIVE. It must " +
"exactly match whatever the name is in the UI.",
],
clear: ["clear", "", "Clears the console"],
cls: ["cls", "", "Clears the console"],
@@ -49,8 +49,8 @@ export const ConsoleHelpText: {
"help [command]",
"",
"Running 'help' with no arguments displays the general help text, which lists all console commands " +
"and a brief description of what they do. A command can be specified to get more specific help text " +
"about that particular command. For example:",
"and a brief description of what they do. A command can be specified to get more specific help text " +
"about that particular command. For example:",
"",
" help automate",
"",
@@ -60,8 +60,8 @@ export const ConsoleHelpText: {
"log [en/dis] [type]",
"",
"Enable or disable logging. By default, the results of completing actions such as contracts/operations are logged " +
"in the console. There are also random events that are logged in the console as well. The five categories of " +
"things that get logged are:",
"in the console. There are also random events that are logged in the console as well. The five categories of " +
"things that get logged are:",
"",
"[general, contracts, ops, blackops, events]",
"",
@@ -86,10 +86,11 @@ export const ConsoleHelpText: {
" skill list",
"",
"To display information about a specific skill, specify the name of the skill afterwards. " +
"Note that the name of the skill is case-sensitive. Enter it exactly as seen in the UI. If " +
"the name of the skill has whitespace, enclose the name of the skill in double quotation marks:",
"Note that the name of the skill is case-sensitive. Enter it exactly as seen in the UI. If " +
"the name of the skill has whitespace, enclose the name of the skill in double quotation marks:",
"",
" skill list Reaper<br>" + " skill list 'Digital Observer'",
" skill list Reaper",
" skill list 'Digital Observer'",
"",
"This console command can also be used to level up skills:",
"",
@@ -99,9 +100,9 @@ export const ConsoleHelpText: {
"start [type] [name]",
"",
"Start an action. An action is specified by its type and its name. The " +
"name is case-sensitive. It must appear exactly as it does in the UI. If " +
"the name of the action has whitespace, enclose it in double quotation marks. " +
"Valid action types include:",
"name is case-sensitive. It must appear exactly as it does in the UI. If " +
"the name of the action has whitespace, enclose it in double quotation marks. " +
"Valid action types include:",
"",
"[general, contract, op, blackop]",
"",

View File

@@ -54,7 +54,6 @@ interface IProps {
export function Console(props: IProps): React.ReactElement {
const classes = useStyles();
const scrollHook = useRef<HTMLDivElement>(null);
const [command, setCommand] = useState("");
const setRerender = useState(false)[1];
@@ -64,22 +63,14 @@ export function Console(props: IProps): React.ReactElement {
const [consoleHistoryIndex, setConsoleHistoryIndex] = useState(props.bladeburner.consoleHistory.length);
// TODO: Figure out how to actually make the scrolling work correctly.
function scrollToBottom(): void {
if (!scrollHook.current) return;
scrollHook.current.scrollTop = scrollHook.current.scrollHeight;
}
function rerender(): void {
setRerender((old) => !old);
}
useEffect(() => {
const id = setInterval(rerender, 1000);
const id2 = setInterval(scrollToBottom, 100);
return () => {
clearInterval(id);
clearInterval(id2);
};
}, []);
@@ -113,6 +104,7 @@ export function Console(props: IProps): React.ReactElement {
setConsoleHistoryIndex(i);
const prevCommand = consoleHistory[i];
event.currentTarget.value = prevCommand;
setCommand(prevCommand);
}
if (event.keyCode === 40) {
@@ -134,39 +126,69 @@ export function Console(props: IProps): React.ReactElement {
setConsoleHistoryIndex(consoleHistoryIndex + 1);
const prevCommand = consoleHistory[consoleHistoryIndex + 1];
event.currentTarget.value = prevCommand;
setCommand(prevCommand);
}
}
}
return (
<Box height={"60vh"} display={"flex"} alignItems={"stretch"} component={Paper}>
<Box>
<List sx={{ height: "100%", overflow: "auto" }}>
{props.bladeburner.consoleLogs.map((log: any, i: number) => (
<Line key={i} content={log} />
))}
<TextField
classes={{ root: classes.textfield }}
autoFocus
tabIndex={1}
type="text"
value={command}
onChange={handleCommandChange}
onKeyDown={handleKeyDown}
InputProps={{
// for players to hook in
className: classes.input,
startAdornment: (
<>
<Typography>&gt;&nbsp;</Typography>
</>
),
spellCheck: false,
}}
/>
</List>
<div ref={scrollHook}></div>
<Paper>
<Box sx={{
height: '60vh',
paddingBottom: '8px',
display: 'flex',
alignItems: 'stretch',
whiteSpace: 'pre-wrap',
}}>
<Box>
<Logs entries={[...props.bladeburner.consoleLogs]} />
</Box>
</Box>
</Box>
<TextField
classes={{ root: classes.textfield }}
autoFocus
tabIndex={1}
type="text"
value={command}
onChange={handleCommandChange}
onKeyDown={handleKeyDown}
InputProps={{
// for players to hook in
className: classes.input,
startAdornment: (
<>
<Typography>&gt;&nbsp;</Typography>
</>
),
spellCheck: false,
}}
/>
</Paper>
);
}
interface ILogProps {
entries: string[];
}
function Logs({entries}: ILogProps): React.ReactElement {
const scrollHook = useRef<HTMLUListElement>(null);
// TODO: Text gets shifted up as new entries appear, if the user scrolled up it should attempt to keep the text focused
function scrollToBottom(): void {
if (!scrollHook.current) return;
scrollHook.current.scrollTop = scrollHook.current.scrollHeight;
}
useEffect(() => {
scrollToBottom();
}, [entries]);
return (
<List sx={{ height: "100%", overflow: "auto", p: 1 }} ref={scrollHook}>
{entries && entries.map((log: any, i: number) => (
<Line key={i} content={log} />
))}
</List>
);
}

View File

@@ -112,7 +112,7 @@ export const CONSTANTS: {
LatestUpdate: string;
} = {
VersionString: "1.2.0",
VersionNumber: 7,
VersionNumber: 9,
// Speed (in ms) at which the main loop is updated
_idleSpeed: 200,
@@ -273,103 +273,89 @@ export const CONSTANTS: {
TotalNumBitNodes: 24,
LatestUpdate: `
v1.1.0 - 2021-12-18 You guys are awesome (community because they're god damn awesome)
-------------------------------------------------------------------------------------
v1.3.0 - 2022-01-04 Cleaning up
-------------------------------
** Script Editor **
** External IDE integration **
* The Steam version has a webserver that allows integration with external IDEs.
A VSCode extension is available on the market place. (The documentation for the ext. isn't
written yet)
** Source-Files **
* The text editor can open several files at once. (@Rez855 / @Shadow72)
It's not perfect so keep the feedback coming.
* SF4 has been reworked.
* New SF -1.
** Steam **
** UI **
* Windows has a new launch option that lets player start with killing all their scripts
This is a safety net in case all the other safety nets fail.
* Linux has several launch options that use different flags for different OS.
* Debug and Fullscreen are available in the window utility bar.
* Tried (and maybe failed) to make the game completely kill itself after closing.
This one I still don't know wtf is going.
* No longer has background throttling.
* Default color should be pitch black when loading
* Add BN13: Challenge achievement.
* Fix some edge case with skill bat tooltips (@MartinFournier)
* Made some background match theme color (@Kejikus)
* Fix problem with script editor height not adjusting correctly (@billyvg)
* Fix some formatting issues with Bladeburner (@MartinFournier, @nickofolas)
* Fix some functions like 'alert' format messages better (@MageKing17)
* Many community themes added.
* New script editor theme (@Hedrauta, @Dexalt142)
* Improvements to tail windows (@theit8514)
* Training is more consise (@mikomyazaki)
* Fix Investopedia not displaying properly (@JotaroS)
* Remove alpha from theme editor (@MartinFournier)
* Fix corporation tooltip not displaying properly (@MartinFournier)
* Add tooltip on backdoored location names (@MartinFournier)
* Allow toasts to be dismissed by clicking them (@nickofolas)
* Darkweb item listing now shows what you own. (@hexnaught)
** Tutorial **
** Bug fix **
* I watched someone play bitburner on youtube and reworked part of
the tutorial to try to make some parts of the game clearer.
https://www.youtube.com/watch?v=-_JETXff4Zo
* Add option to restart tutorial.
** Netscript **
* getGangInformation returns more information.
* getAscensionResult added
* getMemberInformation returns more info
* Formulas API has new functions for gang.
* Added documentation for corp API.
* exec has clearer error message when you send invalid data.
* getServer returns all defined field for hacknet servers.
* Fix a bug with scp multiple files (@theit8514)
* Stack traces should be smarter at replacing blobs with filenames
* Fix a weird error message that would occur when throwing raw strings.
* Fix shortcuts not working.
* Re-added setFocus and isFocused (@theit8514)
* new function getHashUpgrades (@MartinFournier)
* enableLog accepts "ALL" like disableLog (@wynro)
* toast() doesn't crash on invalid data (@ivanjermakov)
* alert() doesn't crash on invalid data (@Siern)
* Fixed an issue where scripts don't run where they should.
* Sleeve getInformation now returns cha
* getServer does work with no argument now
* workForFaction returns false when it mistakenly returned null
** Character Overview **
* The character overview now shows the amount of exp needed to next level (@MartinFournier)
* Fix unit tests (@MartinFournier)
* Fixed issue with 'cat' and 'read' not finding foldered files (@Nick-Colclasure)
* Buying on the dark web will remove incomplete exe (@hexnaught)
* Fix bug that would cause the game to crash trying to go to a job without a job (@hexnaught)
* purchaseServer validation (@nickofolas)
* Script Editor focuses code when changing tab (@MartinFournier)
* Fix script editor for .txt files (@65-7a)
* Fix 'buy' command not displaying correctly. (@hexnaught)
* Fix hackAnalyzeThread returning NaN (@mikomyazaki)
* Electron handles exceptions better (@MageKing17)
* Electron will handle 'unresponsive' event and present the opportunity to reload the game with no scripts (@MartinFournier)
* Fix 'cp' between folders (@theit8514)
* Fix throwing null/undefined errors (@nickofolas)
* Allow shortcuts to work when unfocused (@MageKing17)
* Fix some dependency issue (@locriacyber)
* Fix corporation state returning an object instead of a string (@antonvmironov)
* Fix 'mv' overwriting files (@theit8514)
* Fix joesguns not being influenced by hack/grow (@dou867, @MartinFournier)
* Added warning when opening external links. (@MartinFournier)
* Prevent applying for positions that aren't offered (@TheMas3212)
* Import has validation (@MartinFournier)
** Misc. **
* Add option to supress Game Saved! toasts (@MartinFournier)
* Fix bug where ctrl+alt+j was eaten by the wrong process. (@billyvg)
* Theme Editor lets you paste colors (@MartinFournier)
* ctrl + u/k/w should work on terminal (@billyvg)
* Game now shows commit number, this is mostly for me. (@MartinFourier)
* running a bad script will give a clearer error message (@TheCoderJT)
* Default terminal capacity is maximum (@SayntGarmo)
* Fix problems with cp and mv (@theit8514)
* Make monaco load fully offline for players behind firewalls.
* change beginer guide to use n00dles instead of foodnstuff
* BN13 is harder
* nerf int gain from manualHack
* Fix UI displaying wrong stats (@DJMatch3000)
* Fix button not disabling as it should.
* New location in Ishima.
* Add setting to suppress stock market popups.
* Typo fixes (@Hedrauta, @cvr-119, @Ationi, @millennIumAMbiguity
@TealKoi, @TheCoderJT, @cblte, @2PacIsAlive, @MageKing17,
@Xynrati, @Adraxas, @pobiega)
* Fix 100% territory achievement.
* Reword message on active scripts page.
* Fix terminal not clearing after BN
* Remove references to .fconf
* Augmentation pages shows BN difficulty with SF5
* Fix scripts saving on wrong server while 'connect'ing
* Fix gym discount not working.
* Fix scan-analyze not working with timestamps
* Hash upgrades remember last choice.
* Save files now sort by date
* The covenant no longer supports negative memory purchases
* Fix corp shares buyback triggering by pressing enter
* Staneks gift display avg / num charges
* Infiltration rewards no longer decay with better stats
* terminal 'true' is parsed as boolean not string
* tail and kill use autocomplete()
* Fix focus for coding contract
* massive boost to noodle bar.
** Special Thanks **
* Special thank you to everyone on Discord who can answer
new player questions so I can focus on more important things.
* Added vim mode to script editor (@billyvg)
* Clean up script editor code (@Rez855)
* 'cat' works on scripts (@65-7a)
* Add wordWrap for Monaco (@MartinFournier)
* Include map bundles in electron for easier debugging (@MartinFournier)
* Fix importing very large files (@MartinFournier)
* Cache program blob, reducing ram usage of the game (@theit8514)
* Dev menu can set server to $0 (@mikomyazaki)
* 'backdoor' allows direct connect (@mikomyazaki)
* Github workflow work (@MartinFournier)
* workForFaction / workForCompany have a new parameter (@theit8514)
* Alias accept single quotes (@sporkwitch, @FaintSpeaker)
* Add grep options to 'ps' (@maxtimum)
* Added buy all option to 'buy' (@anthonydroberts)
* Added more shortcuts to terminal input (@Frank-py)
* Refactor some port code (@ErzengelLichtes)
* Settings to control GiB vs GB (@ErzengelLichtes)
* Add electron option to export save game (@MartinFournier)
* Electron improvements (@MartinFournier)
* Expose some notifications functions to electron (@MartinFournier)
* Documentation (@MartinFournier, @cyn, @millennIumAMbiguity, @2PacIsAlive,
@TheCoderJT, @hexnaught, @sschmidTU, @FOLLGAD, @Hedrauta, @Xynrati,
@mikomyazaki, @Icehawk78, @aaronransley, @TheMas3212, @Hedrauta, @alkemann,
@ReeseJones, @amclark42, @thadguidry, @jasonhaxstuff, @pan-kuleczka, @jhollowe,
@ApatheticsAnonymous, @erplsf, @daanflore, @nickofolas, @Kebap, @smolgumball,
@woody-lam-cwl)
`,
};

View File

@@ -108,35 +108,32 @@ function WarehouseRoot(props: IProps): React.ReactElement {
}
}
let breakdown = <></>;
const breakdownItems: JSX.Element[] = [];
for (const matName in props.warehouse.materials) {
const mat = props.warehouse.materials[matName];
if (!MaterialSizes.hasOwnProperty(matName)) continue;
if (mat.qty === 0) continue;
breakdown = (
<>
{breakdown}
{matName}: {numeralWrapper.format(mat.qty * MaterialSizes[matName], "0,0.0")}
<br />
</>
);
breakdownItems.push(<>{matName}: {numeralWrapper.format(mat.qty * MaterialSizes[matName], "0,0.0")}</>);
}
for (const prodName in division.products) {
const prod = division.products[prodName];
if (prod === undefined) continue;
breakdown = (
<>
{breakdown}
{prodName}: {numeralWrapper.format(prod.data[props.warehouse.loc][0] * prod.siz, "0,0.0")}
</>
);
breakdownItems.push(<>{prodName}: {numeralWrapper.format(prod.data[props.warehouse.loc][0] * prod.siz, "0,0.0")}</>);
}
let breakdown;
if (breakdownItems && breakdownItems.length > 0) {
breakdown = breakdownItems.reduce(
(previous: JSX.Element, current: JSX.Element): JSX.Element => previous && <>{previous}<br />{current}</> || <>{current}</>);
} else {
breakdown = <>No items in storage.</>
}
return (
<Paper>
<Box display="flex" alignItems="center">
<Tooltip title={props.warehouse.sizeUsed !== 0 ? <Typography>{breakdown}</Typography> : ""}>
<Tooltip title={props.warehouse.sizeUsed !== 0 ? <Typography><>{breakdown}</></Typography> : ""}>
<Typography color={props.warehouse.sizeUsed >= props.warehouse.size ? "error" : "primary"}>
Storage: {numeralWrapper.formatBigNumber(props.warehouse.sizeUsed)} /{" "}
{numeralWrapper.formatBigNumber(props.warehouse.size)}

View File

@@ -4,7 +4,9 @@ import { DarkWebItems } from "./DarkWebItems";
import { Player } from "../Player";
import { Terminal } from "../Terminal";
import { SpecialServers } from "../Server/data/SpecialServers";
import { numeralWrapper } from "../ui/numeralFormat";
import { Money } from "../ui/React/Money";
import { DarkWebItem } from "./DarkWebItem";
//Posts a "help" message if connected to DarkWeb
export function checkIfConnectedToDarkweb(): void {
@@ -12,8 +14,8 @@ export function checkIfConnectedToDarkweb(): void {
if (server !== null && SpecialServers.DarkWeb == server.hostname) {
Terminal.print(
"You are now connected to the dark web. From the dark web you can purchase illegal items. " +
"Use the 'buy -l' command to display a list of all the items you can buy. Use 'buy [item-name] " +
"to purchase an item.",
"Use the 'buy -l' command to display a list of all the items you can buy. Use 'buy [item-name]' " +
"to purchase an item. Use the 'buy -a' command to purchase unowned all items.",
);
}
}
@@ -21,9 +23,16 @@ export function checkIfConnectedToDarkweb(): void {
export function listAllDarkwebItems(): void {
for (const key in DarkWebItems) {
const item = DarkWebItems[key];
const cost = Player.getHomeComputer().programs.includes(item.program) ? (
<span style={{ color: `green` }}>[OWNED]</span>
) : (
<Money money={item.price} />
);
Terminal.printRaw(
<>
{item.program} - <Money money={item.price} /> - {item.description}
<span>{item.program}</span> - <span>{cost}</span> - <span>{item.description}</span>
</>,
);
}
@@ -33,7 +42,8 @@ export function buyDarkwebItem(itemName: string): void {
itemName = itemName.toLowerCase();
// find the program that matches, if any
let item = null;
let item: DarkWebItem | null = null;
for (const key in DarkWebItems) {
const i = DarkWebItems[key];
if (i.program.toLowerCase() == itemName) {
@@ -61,8 +71,47 @@ export function buyDarkwebItem(itemName: string): void {
// buy and push
Player.loseMoney(item.price, "other");
const programsRef = Player.getHomeComputer().programs;
// Remove partially created program if there is one
const existingPartialExeIndex = programsRef.findIndex(
(program) => item?.program && program.startsWith(item?.program),
);
// findIndex returns -1 if there is no match, we only want to splice on a match
if (existingPartialExeIndex > -1) {
programsRef.splice(existingPartialExeIndex, 1);
}
// Add the newly bought, full .exe
Player.getHomeComputer().programs.push(item.program);
Terminal.print(
"You have purchased the " + item.program + " program. The new program can be found on your home computer.",
);
}
export function buyAllDarkwebItems(): void {
const itemsToBuy: DarkWebItem[] = [];
let cost = 0;
for (const key in DarkWebItems) {
const item = DarkWebItems[key];
if (!Player.hasProgram(item.program)) {
itemsToBuy.push(item);
cost += item.price;
}
}
if (itemsToBuy.length === 0) {
Terminal.print("All available programs have been purchased already.");
return;
}
if (cost > Player.money) {
Terminal.error("Not enough money to purchase remaining programs, " + numeralWrapper.formatMoney(cost) + " required");
return;
}
for (const item of itemsToBuy) {
buyDarkwebItem(item.program);
}
}

View File

@@ -4,7 +4,7 @@ import { IEngine } from "./IEngine";
import { IRouter } from "./ui/Router";
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
import React from "react";
import React, { useEffect } from "react";
import { General } from "./DevMenu/ui/General";
import { Stats } from "./DevMenu/ui/Stats";
@@ -23,6 +23,7 @@ import { Sleeves } from "./DevMenu/ui/Sleeves";
import { Stanek } from "./DevMenu/ui/Stanek";
import { TimeSkip } from "./DevMenu/ui/TimeSkip";
import Typography from "@mui/material/Typography";
import { Exploit } from "./Exploits/Exploit";
interface IProps {
player: IPlayer;
@@ -31,6 +32,9 @@ interface IProps {
}
export function DevMenuRoot(props: IProps): React.ReactElement {
useEffect(() => {
props.player.giveExploit(Exploit.YoureNotMeantToAccessThis);
}, []);
return (
<>
<Typography>Development Menu - Only meant to be used for testing/debugging</Typography>

View File

@@ -71,6 +71,20 @@ export function Servers(): React.ReactElement {
}
}
function minMoney(): void {
const s = GetServer(server);
if (s === null) return;
if (!(s instanceof Server)) return;
s.moneyAvailable = 0;
}
function minAllMoney(): void {
for (const s of GetAllServers()) {
if (!(s instanceof Server)) return;
s.moneyAvailable = 0;
}
}
return (
<Accordion TransitionProps={{ unmountOnExit: true }}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
@@ -119,6 +133,12 @@ export function Servers(): React.ReactElement {
<td>
<Typography>Money:</Typography>
</td>
<td>
<Button onClick={minMoney}>Min one</Button>
</td>
<td>
<Button onClick={minAllMoney}>Min all</Button>
</td>
<td>
<Button onClick={maxMoney}>Max one</Button>
</td>

View File

@@ -14,11 +14,17 @@ import { HacknetServer } from "./Hacknet/HacknetServer";
import { CityName } from "./Locations/data/CityNames";
import { Player } from "./Player";
import { Programs } from "./Programs/Programs";
import { isScriptFilename } from "./Script/isScriptFilename";
import { Script } from "./Script/Script";
import { GetAllServers, GetServer } from "./Server/AllServers";
import { SpecialServers } from "./Server/data/SpecialServers";
import { Server } from "./Server/Server";
import { Router } from "./ui/GameRoot";
import { Page } from "./ui/Router";
import { removeLeadingSlash } from "./Terminal/DirectoryHelpers";
import { Terminal } from "./Terminal";
import { SnackbarEvents } from "./ui/React/Snackbar";
import { IMap } from "./types";
interface Achievement {
ID: string;
@@ -32,6 +38,7 @@ function bitNodeFinishedState(): boolean {
return Player.bladeburner !== null && Player.bladeburner.blackops.hasOwnProperty("Operation Daedalus");
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function sfAchievement(): Achievement[] {
const achs: Achievement[] = [];
for (let i = 0; i <= 11; i++) {
@@ -232,7 +239,8 @@ const achievements: Achievement[] = [
{
ID: "BLADEBURNER_OVERCLOCK",
Condition: () =>
Player.bladeburner !== null && Player.bladeburner.skills[SkillNames.Overclock] === Skills[SkillNames.Overclock],
Player.bladeburner !== null &&
Player.bladeburner.skills[SkillNames.Overclock] === Skills[SkillNames.Overclock].maxLvl,
},
{
ID: "BLADEBURNER_UNSPENT_100000",
@@ -249,12 +257,14 @@ const achievements: Achievement[] = [
Condition: () => {
if (!hasHacknetServers(Player)) return false;
for (const h of Player.hacknetNodes) {
if (!(h instanceof HacknetServer)) return false;
if (typeof h !== "string") return false;
const hs = GetServer(h);
if (!(hs instanceof HacknetServer)) return false;
if (
h.maxRam === HacknetServerConstants.MaxRam &&
h.cores === HacknetServerConstants.MaxCores &&
h.level === HacknetServerConstants.MaxLevel &&
h.cache === HacknetServerConstants.MaxCache
hs.maxRam === HacknetServerConstants.MaxRam &&
hs.cores === HacknetServerConstants.MaxCores &&
hs.level === HacknetServerConstants.MaxLevel &&
hs.cache === HacknetServerConstants.MaxCache
)
return true;
}
@@ -293,7 +303,7 @@ const achievements: Achievement[] = [
Condition: () =>
Player.bitNodeN === 1 &&
bitNodeFinishedState() &&
Player.getHomeComputer().maxRam <= 32 &&
Player.getHomeComputer().maxRam <= 128 &&
Player.getHomeComputer().cpuCores === 1,
},
{
@@ -407,6 +417,64 @@ function calculateAchievements(): void {
}
export function initElectron(): void {
setAchievements([]);
setInterval(calculateAchievements, 5000);
const userAgent = navigator.userAgent.toLowerCase();
if (userAgent.indexOf(" electron/") > -1) {
// Electron-specific code
setAchievements([]);
initWebserver();
setInterval(calculateAchievements, 5000);
initAppNotifier();
}
}
function initWebserver(): void {
(document as any).saveFile = function (filename: string, code: string): string {
if (removeLeadingSlash(filename).includes("/")) {
filename = "/" + removeLeadingSlash(filename);
}
code = Buffer.from(code, "base64").toString();
const home = GetServer("home");
if (home === null) return "'home' server not found.";
if (isScriptFilename(filename)) {
//If the current script already exists on the server, overwrite it
for (let i = 0; i < home.scripts.length; i++) {
if (filename == home.scripts[i].filename) {
home.scripts[i].saveScript(Player, filename, code, "home", home.scripts);
return "written";
}
}
//If the current script does NOT exist, create a new one
const script = new Script();
script.saveScript(Player, filename, code, "home", home.scripts);
home.scripts.push(script);
return "written";
}
return "not a script file";
};
}
// Expose certain alert functions to allow the wrapper to sends message to the game
function initAppNotifier(): void {
const funcs = {
terminal: (message: string, type?: string) => {
const typesFn: IMap<(s: string) => void> = {
info: Terminal.info,
warn: Terminal.warn,
error: Terminal.error,
success: Terminal.success,
};
let fn;
if (type) fn = typesFn[type];
if (!fn) fn = Terminal.print;
fn.bind(Terminal)(message);
},
toast: (message: string, type: "info" | "success" | "warning" | "error", duration = 2000) =>
SnackbarEvents.emit(message, type, duration),
};
// Will be consumud by the electron wrapper.
// @ts-ignore
window.appNotifier = funcs;
}

View File

@@ -18,6 +18,7 @@ export enum Exploit {
TimeCompression = "TimeCompression",
RealityAlteration = "RealityAlteration",
N00dles = "N00dles",
YoureNotMeantToAccessThis = "YoureNotMeantToAccessThis",
// To the players reading this. Yes you're supposed to add EditSaveFile by
// editing your save file, yes you could add them all, no we don't care
// that's not the point.
@@ -35,6 +36,7 @@ const names: {
UndocumentedFunctionCall: "by looking beyond the documentation.",
RealityAlteration: "by altering reality to suit your whims.",
N00dles: "by harnessing the power of the n00dles.",
YoureNotMeantToAccessThis: "by accessing the dev menu.",
};
export function ExploitName(exploit: string): string {

View File

@@ -24,9 +24,9 @@ function timeCompression(): void {
return;
}
last = now;
window.setTimeout(minute, 1000);
window.setTimeout(minute, 1000 * 60);
}
window.setTimeout(minute, 1000);
window.setTimeout(minute, 1000 * 60);
}
export function startExploits(): void {

View File

@@ -174,7 +174,7 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
<>
<br />
<Typography variant="h4">Purchased Augmentations</Typography>
<Typography>This factions also offers these augmentations but you already own them.</Typography>
<Typography>This faction also offers these augmentations but you already own them.</Typography>
{owned.map((aug) => purchaseableAugmentation(aug, true))}
</>
);

View File

@@ -353,7 +353,7 @@ export class Gang {
const res = member.ascend();
this.respect = Math.max(1, this.respect - res.respect);
if (workerScript) {
workerScript.log("ascend", () => `Ascended Gang member ${member.name}`);
workerScript.log("gang.ascend", () => `Ascended Gang member ${member.name}`);
}
return res;
} catch (e: any) {

View File

@@ -1,6 +1,7 @@
import React from "react";
import Button from "@mui/material/Button";
import Tooltip from "@mui/material/Tooltip";
import Typography from "@mui/material/Typography";
import { IPlayer } from "../../PersonObjects/IPlayer";
@@ -38,6 +39,11 @@ export function CoresButton(props: IProps): React.ReactElement {
}
>
<span>
<br />
<Typography>
<i>"Cores increase the effectiveness of grow() and weaken() on 'home'"</i>
</Typography>
<br />
<Button disabled={!props.p.canAfford(cost)} onClick={buy}>
Upgrade 'home' cores ({homeComputer.cpuCores} -&gt; {homeComputer.cpuCores + 1}) -&nbsp;
<Money money={cost} player={props.p} />

View File

@@ -29,6 +29,7 @@ import { GetServer } from "../../Server/AllServers";
import { CorruptableText } from "../../ui/React/CorruptableText";
import { use } from "../../ui/Context";
import { serverMetadata } from "../../Server/data/servers";
import { Tooltip } from "@mui/material";
type IProps = {
loc: Location;
@@ -92,8 +93,11 @@ export function GenericLocation({ loc }: IProps): React.ReactElement {
return (
<>
<Button onClick={() => router.toCity()}>Return to World</Button>
<Typography variant="h4">
{backdoorInstalled && !Settings.DisableTextEffects ? <CorruptableText content={loc.name} /> : loc.name}
<Typography variant="h4" sx={{ mt: 1 }}>
{backdoorInstalled && !Settings.DisableTextEffects ? (
<Tooltip title={`Backdoor installed on ${loc.name}.`}>
<span><CorruptableText content={loc.name} /></span>
</Tooltip>) : loc.name}
</Typography>
{locContent}
</>

View File

@@ -1,6 +1,7 @@
import React from "react";
import Button from "@mui/material/Button";
import Tooltip from "@mui/material/Tooltip";
import Typography from "@mui/material/Typography";
import { CONSTANTS } from "../../Constants";
import { IPlayer } from "../../PersonObjects/IPlayer";
@@ -37,6 +38,11 @@ export function RamButton(props: IProps): React.ReactElement {
}
>
<span>
<br />
<Typography>
<i>"More RAM means more scripts on 'home'"</i>
</Typography>
<br />
<Button disabled={!props.p.canAfford(cost)} onClick={buy}>
Upgrade 'home' RAM ({numeralWrapper.formatRAM(homeComputer.maxRam)} -&gt;&nbsp;
{numeralWrapper.formatRAM(homeComputer.maxRam * 2)}) -&nbsp;

View File

@@ -86,7 +86,7 @@ export function SpecialLocation(props: IProps): React.ReactElement {
function renderNoodleBar(): React.ReactElement {
function EatNoodles(): void {
SnackbarEvents.emit("You ate some delicious noodles and feel refreshed", "success");
SnackbarEvents.emit("You ate some delicious noodles and feel refreshed", "success", 2000);
N00dles(); // This is the true power of the noodles.
if (player.sourceFiles.length > 0) player.giveExploit(Exploit.N00dles);
if (player.sourceFileLvl(5) > 0 || player.bitNodeN === 5) {

View File

@@ -73,7 +73,7 @@ export function TechVendorLocation(props: IProps): React.ReactElement {
{purchaseServerButtons}
<br />
<Typography>
<i>"You can order bigger servers via scripts. We don't take custom order in person."</i>
<i>"You can order bigger servers via scripts. We don't take custom orders in person."</i>
</Typography>
<br />
<TorButton p={player} rerender={rerender} />

View File

@@ -1,3 +1,4 @@
import { IPlayer } from "src/PersonObjects/IPlayer";
import { IMap } from "../types";
// TODO remember to update RamCalculations.js and WorkerScript.js
@@ -67,6 +68,16 @@ export const RamCostConstants: IMap<number> = {
ScriptStanekDeleteAt: 0.15,
};
function SF4Cost(cost: number): (player: IPlayer) => number {
return (player: IPlayer): number => {
if (player.bitNodeN === 4) return cost;
const sf4 = player.sourceFileLvl(4);
if (sf4 <= 1) return cost * 64;
if (sf4 === 2) return cost * 8;
return cost;
};
}
export const RamCosts: IMap<any> = {
hacknet: {
numNodes: 0,
@@ -196,55 +207,55 @@ export const RamCosts: IMap<any> = {
getFavorToDonate: RamCostConstants.ScriptGetFavorToDonate,
// Singularity Functions
universityCourse: RamCostConstants.ScriptSingularityFn1RamCost,
gymWorkout: RamCostConstants.ScriptSingularityFn1RamCost,
travelToCity: RamCostConstants.ScriptSingularityFn1RamCost,
goToLocation: RamCostConstants.ScriptSingularityFn1RamCost,
purchaseTor: RamCostConstants.ScriptSingularityFn1RamCost,
purchaseProgram: RamCostConstants.ScriptSingularityFn1RamCost,
getCurrentServer: RamCostConstants.ScriptSingularityFn1RamCost,
connect: RamCostConstants.ScriptSingularityFn1RamCost,
manualHack: RamCostConstants.ScriptSingularityFn1RamCost,
installBackdoor: RamCostConstants.ScriptSingularityFn1RamCost,
getStats: RamCostConstants.ScriptSingularityFn1RamCost / 4,
getCharacterInformation: RamCostConstants.ScriptSingularityFn1RamCost / 4,
getPlayer: RamCostConstants.ScriptSingularityFn1RamCost / 4,
hospitalize: RamCostConstants.ScriptSingularityFn1RamCost / 4,
isBusy: RamCostConstants.ScriptSingularityFn1RamCost / 4,
stopAction: RamCostConstants.ScriptSingularityFn1RamCost / 2,
upgradeHomeRam: RamCostConstants.ScriptSingularityFn2RamCost,
upgradeHomeCores: RamCostConstants.ScriptSingularityFn2RamCost,
getUpgradeHomeRamCost: RamCostConstants.ScriptSingularityFn2RamCost / 2,
getUpgradeHomeCoresCost: RamCostConstants.ScriptSingularityFn2RamCost / 2,
workForCompany: RamCostConstants.ScriptSingularityFn2RamCost,
applyToCompany: RamCostConstants.ScriptSingularityFn2RamCost,
getCompanyRep: RamCostConstants.ScriptSingularityFn2RamCost / 3,
getCompanyFavor: RamCostConstants.ScriptSingularityFn2RamCost / 3,
getCompanyFavorGain: RamCostConstants.ScriptSingularityFn2RamCost / 4,
checkFactionInvitations: RamCostConstants.ScriptSingularityFn2RamCost,
joinFaction: RamCostConstants.ScriptSingularityFn2RamCost,
workForFaction: RamCostConstants.ScriptSingularityFn2RamCost,
getFactionRep: RamCostConstants.ScriptSingularityFn2RamCost / 3,
getFactionFavor: RamCostConstants.ScriptSingularityFn2RamCost / 3,
getFactionFavorGain: RamCostConstants.ScriptSingularityFn2RamCost / 4,
donateToFaction: RamCostConstants.ScriptSingularityFn3RamCost,
createProgram: RamCostConstants.ScriptSingularityFn3RamCost,
commitCrime: RamCostConstants.ScriptSingularityFn3RamCost,
getCrimeChance: RamCostConstants.ScriptSingularityFn3RamCost,
getCrimeStats: RamCostConstants.ScriptSingularityFn3RamCost,
getOwnedAugmentations: RamCostConstants.ScriptSingularityFn3RamCost,
getOwnedSourceFiles: RamCostConstants.ScriptSingularityFn3RamCost,
getAugmentationsFromFaction: RamCostConstants.ScriptSingularityFn3RamCost,
getAugmentationCost: RamCostConstants.ScriptSingularityFn3RamCost,
getAugmentationPrereq: RamCostConstants.ScriptSingularityFn3RamCost,
getAugmentationPrice: RamCostConstants.ScriptSingularityFn3RamCost / 2,
getAugmentationRepReq: RamCostConstants.ScriptSingularityFn3RamCost / 2,
getAugmentationStats: RamCostConstants.ScriptSingularityFn3RamCost,
purchaseAugmentation: RamCostConstants.ScriptSingularityFn3RamCost,
softReset: RamCostConstants.ScriptSingularityFn3RamCost,
installAugmentations: RamCostConstants.ScriptSingularityFn3RamCost,
isFocused: 0.1,
setFocus: 0.1,
universityCourse: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost),
gymWorkout: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost),
travelToCity: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost),
goToLocation: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost),
purchaseTor: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost),
purchaseProgram: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost),
getCurrentServer: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost),
connect: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost),
manualHack: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost),
installBackdoor: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost),
getStats: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost / 4),
getCharacterInformation: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost / 4),
getPlayer: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost / 4),
hospitalize: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost / 4),
isBusy: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost / 4),
stopAction: SF4Cost(RamCostConstants.ScriptSingularityFn1RamCost / 2),
upgradeHomeRam: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost),
upgradeHomeCores: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost),
getUpgradeHomeRamCost: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 2),
getUpgradeHomeCoresCost: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 2),
workForCompany: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost),
applyToCompany: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost),
getCompanyRep: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 3),
getCompanyFavor: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 3),
getCompanyFavorGain: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 4),
checkFactionInvitations: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost),
joinFaction: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost),
workForFaction: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost),
getFactionRep: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 3),
getFactionFavor: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 3),
getFactionFavorGain: SF4Cost(RamCostConstants.ScriptSingularityFn2RamCost / 4),
donateToFaction: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost),
createProgram: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost),
commitCrime: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost),
getCrimeChance: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost),
getCrimeStats: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost),
getOwnedAugmentations: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost),
getOwnedSourceFiles: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost),
getAugmentationsFromFaction: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost),
getAugmentationCost: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost),
getAugmentationPrereq: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost),
getAugmentationPrice: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost / 2),
getAugmentationRepReq: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost / 2),
getAugmentationStats: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost),
purchaseAugmentation: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost),
softReset: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost),
installAugmentations: SF4Cost(RamCostConstants.ScriptSingularityFn3RamCost),
isFocused: SF4Cost(0.1),
setFocus: SF4Cost(0.1),
// Gang API
gang: {
@@ -348,13 +359,17 @@ export const RamCosts: IMap<any> = {
remove: RamCostConstants.ScriptStanekDeleteAt,
},
ui: {
getTheme: 0,
},
heart: {
// Easter egg function
break: 0,
},
};
export function getRamCost(...args: string[]): number {
export function getRamCost(player: IPlayer, ...args: string[]): number {
if (args.length === 0) {
console.warn(`No arguments passed to getRamCost()`);
return 0;
@@ -379,6 +394,10 @@ export function getRamCost(...args: string[]): number {
return curr;
}
if (typeof curr === "function") {
return curr(player);
}
console.warn(`Unexpected type (${curr}) for value [${args}]`);
return 0;
}

View File

@@ -1,7 +1,6 @@
import { isString } from "./utils/helpers/isString";
import { GetServer } from "./Server/AllServers";
import { WorkerScript } from "./Netscript/WorkerScript";
import { BlobsMap } from "./NetscriptJSEvaluator";
export function netscriptDelay(time: number, workerScript: WorkerScript): Promise<void> {
return new Promise(function (resolve) {
@@ -22,8 +21,9 @@ export function makeRuntimeRejectMsg(workerScript: WorkerScript, msg: string): s
throw new Error(`WorkerScript constructed with invalid server ip: ${workerScript.hostname}`);
}
for (const url in BlobsMap) {
msg = msg.replace(new RegExp(url, "g"), BlobsMap[url]);
for (const scriptUrl of workerScript.scriptRef.dependencies) {
// Return just the original msg if it's nullish so that we don't get a workerscript error
msg = msg?.replace(new RegExp(scriptUrl.url, "g"), scriptUrl.filename) ?? msg;
}
return "|DELIMITER|" + server.hostname + "|DELIMITER|" + workerScript.name + "|DELIMITER|" + msg;
@@ -45,7 +45,7 @@ export function resolveNetscriptRequestedThreads(
`Invalid thread count passed to ${functionName}: ${requestedThreads}. Threads must be a positive number.`,
);
}
if (requestedThreads > threads) {
if (requestedThreadsAsInt > threads) {
throw makeRuntimeRejectMsg(
workerScript,
`Too many threads requested by ${functionName}. Requested: ${requestedThreads}. Has: ${threads}.`,

View File

@@ -64,12 +64,13 @@ import { NetscriptSleeve } from "./NetscriptFunctions/Sleeve";
import { NetscriptExtra } from "./NetscriptFunctions/Extra";
import { NetscriptHacknet } from "./NetscriptFunctions/Hacknet";
import { NetscriptStanek } from "./NetscriptFunctions/Stanek";
import { NetscriptUserInterface } from "./NetscriptFunctions/UserInterface";
import { NetscriptBladeburner } from "./NetscriptFunctions/Bladeburner";
import { NetscriptCodingContract } from "./NetscriptFunctions/CodingContract";
import { NetscriptCorporation } from "./NetscriptFunctions/Corporation";
import { NetscriptFormulas } from "./NetscriptFunctions/Formulas";
import { NetscriptStockMarket } from "./NetscriptFunctions/StockMarket";
import { IPort } from "./NetscriptPort";
import {
NS as INS,
@@ -304,7 +305,10 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
const checkSingularityAccess = function (func: any, n: any): void {
if (Player.bitNodeN !== 4) {
if (SourceFileFlags[4] < n) {
throw makeRuntimeErrorMsg(func, `This singularity function requires Source-File 4-${n} to run.`);
throw makeRuntimeErrorMsg(
func,
`This singularity function requires Source-File 4-${n} to run. A power up you obtain later in the game. It will be very obvious when and how you can obtain it.`,
);
}
}
};
@@ -439,6 +443,26 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
getServer: safeGetServer,
checkSingularityAccess: checkSingularityAccess,
hack: hack,
getValidPort: (funcName: string, port: any): IPort => {
if (isNaN(port)) {
throw makeRuntimeErrorMsg(
funcName,
`Invalid argument. Must be a port number between 1 and ${CONSTANTS.NumNetscriptPorts}, is ${port}`,
);
}
port = Math.round(port);
if (port < 1 || port > CONSTANTS.NumNetscriptPorts) {
throw makeRuntimeErrorMsg(
funcName,
`Trying to use an invalid port: ${port}. Only ports 1-${CONSTANTS.NumNetscriptPorts} are valid.`,
);
}
const iport = NetscriptPorts[port - 1];
if (iport == null || !(iport instanceof Object)) {
throw makeRuntimeErrorMsg(funcName, `Could not find port: ${port}. This is a bug. Report to dev.`);
}
return iport;
},
};
const gang = NetscriptGang(Player, workerScript, helper);
@@ -452,6 +476,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
const formulas = NetscriptFormulas(Player, workerScript, helper);
const singularity = NetscriptSingularity(Player, workerScript, helper);
const stockmarket = NetscriptStockMarket(Player, workerScript, helper);
const ui = NetscriptUserInterface(Player, workerScript, helper);
const base: INS = {
...singularity,
@@ -462,7 +487,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
sleeve: sleeve,
corporation: corporation,
stanek: stanek,
ui: ui,
formulas: formulas,
stock: stockmarket,
args: workerScript.args,
@@ -470,7 +495,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
sprintf: sprintf,
vsprintf: vsprintf,
scan: function (hostname: any = workerScript.hostname): any {
updateDynamicRam("scan", getRamCost("scan"));
updateDynamicRam("scan", getRamCost(Player, "scan"));
const server = safeGetServer(hostname, "scan");
const out = [];
for (let i = 0; i < server.serversOnNetwork.length; i++) {
@@ -484,11 +509,11 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return out;
},
hack: function (hostname: any, { threads: requestedThreads, stock }: any = {}): any {
updateDynamicRam("hack", getRamCost("hack"));
updateDynamicRam("hack", getRamCost(Player, "hack"));
return hack(hostname, false, { threads: requestedThreads, stock: stock });
},
hackAnalyzeThreads: function (hostname: any, hackAmount: any): any {
updateDynamicRam("hackAnalyzeThreads", getRamCost("hackAnalyzeThreads"));
updateDynamicRam("hackAnalyzeThreads", getRamCost(Player, "hackAnalyzeThreads"));
// Check argument validity
const server = safeGetServer(hostname, "hackAnalyzeThreads");
@@ -505,6 +530,8 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
if (hackAmount < 0 || hackAmount > server.moneyAvailable) {
return -1;
} else if (hackAmount === 0) {
return 0;
}
const percentHacked = calculatePercentMoneyHacked(server, Player);
@@ -512,7 +539,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return hackAmount / Math.floor(server.moneyAvailable * percentHacked);
},
hackAnalyze: function (hostname: any): any {
updateDynamicRam("hackAnalyze", getRamCost("hackAnalyze"));
updateDynamicRam("hackAnalyze", getRamCost(Player, "hackAnalyze"));
const server = safeGetServer(hostname, "hackAnalyze");
if (!(server instanceof Server)) {
@@ -526,7 +553,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return CONSTANTS.ServerFortifyAmount * threads;
},
hackAnalyzeChance: function (hostname: any): any {
updateDynamicRam("hackAnalyzeChance", getRamCost("hackAnalyzeChance"));
updateDynamicRam("hackAnalyzeChance", getRamCost(Player, "hackAnalyzeChance"));
const server = safeGetServer(hostname, "hackAnalyzeChance");
if (!(server instanceof Server)) {
@@ -555,7 +582,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
});
},
grow: function (hostname: any, { threads: requestedThreads, stock }: any = {}): any {
updateDynamicRam("grow", getRamCost("grow"));
updateDynamicRam("grow", getRamCost(Player, "grow"));
const threads = resolveNetscriptRequestedThreads(workerScript, "grow", requestedThreads);
if (hostname === undefined) {
throw makeRuntimeErrorMsg("grow", "Takes 1 argument.");
@@ -613,7 +640,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
});
},
growthAnalyze: function (hostname: any, growth: any, cores: any = 1): any {
updateDynamicRam("growthAnalyze", getRamCost("growthAnalyze"));
updateDynamicRam("growthAnalyze", getRamCost(Player, "growthAnalyze"));
// Check argument validity
const server = safeGetServer(hostname, "growthAnalyze");
@@ -631,7 +658,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return 2 * CONSTANTS.ServerFortifyAmount * threads;
},
weaken: function (hostname: any, { threads: requestedThreads }: any = {}): any {
updateDynamicRam("weaken", getRamCost("weaken"));
updateDynamicRam("weaken", getRamCost(Player, "weaken"));
const threads = resolveNetscriptRequestedThreads(workerScript, "weaken", requestedThreads);
if (hostname === undefined) {
throw makeRuntimeErrorMsg("weaken", "Takes 1 argument.");
@@ -797,7 +824,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
LogBoxEvents.emit(runningScriptObj);
},
nuke: function (hostname: any): boolean {
updateDynamicRam("nuke", getRamCost("nuke"));
updateDynamicRam("nuke", getRamCost(Player, "nuke"));
if (hostname === undefined) {
throw makeRuntimeErrorMsg("nuke", "Takes 1 argument.");
}
@@ -806,22 +833,22 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
workerScript.log("nuke", () => "Cannot be executed on this server.");
return false;
}
if (server.hasAdminRights) {
workerScript.log("nuke", () => `Already have root access to '${server.hostname}'.`);
return true;
}
if (!Player.hasProgram(Programs.NukeProgram.name)) {
throw makeRuntimeErrorMsg("nuke", "You do not have the NUKE.exe virus!");
}
if (server.openPortCount < server.numOpenPortsRequired) {
throw makeRuntimeErrorMsg("nuke", "Not enough ports opened to use NUKE.exe virus.");
}
if (server.hasAdminRights) {
workerScript.log("nuke", () => `Already have root access to '${server.hostname}'.`);
} else {
server.hasAdminRights = true;
workerScript.log("nuke", () => `Executed NUKE.exe virus on '${server.hostname}' to gain root access.`);
}
server.hasAdminRights = true;
workerScript.log("nuke", () => `Executed NUKE.exe virus on '${server.hostname}' to gain root access.`);
return true;
},
brutessh: function (hostname: any): boolean {
updateDynamicRam("brutessh", getRamCost("brutessh"));
updateDynamicRam("brutessh", getRamCost(Player, "brutessh"));
if (hostname === undefined) {
throw makeRuntimeErrorMsg("brutessh", "Takes 1 argument.");
}
@@ -843,7 +870,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return true;
},
ftpcrack: function (hostname: any): boolean {
updateDynamicRam("ftpcrack", getRamCost("ftpcrack"));
updateDynamicRam("ftpcrack", getRamCost(Player, "ftpcrack"));
if (hostname === undefined) {
throw makeRuntimeErrorMsg("ftpcrack", "Takes 1 argument.");
}
@@ -865,7 +892,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return true;
},
relaysmtp: function (hostname: any): boolean {
updateDynamicRam("relaysmtp", getRamCost("relaysmtp"));
updateDynamicRam("relaysmtp", getRamCost(Player, "relaysmtp"));
if (hostname === undefined) {
throw makeRuntimeErrorMsg("relaysmtp", "Takes 1 argument.");
}
@@ -887,7 +914,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return true;
},
httpworm: function (hostname: any): boolean {
updateDynamicRam("httpworm", getRamCost("httpworm"));
updateDynamicRam("httpworm", getRamCost(Player, "httpworm"));
if (hostname === undefined) {
throw makeRuntimeErrorMsg("httpworm", "Takes 1 argument");
}
@@ -909,7 +936,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return true;
},
sqlinject: function (hostname: any): boolean {
updateDynamicRam("sqlinject", getRamCost("sqlinject"));
updateDynamicRam("sqlinject", getRamCost(Player, "sqlinject"));
if (hostname === undefined) {
throw makeRuntimeErrorMsg("sqlinject", "Takes 1 argument.");
}
@@ -931,7 +958,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return true;
},
run: function (scriptname: any, threads: any = 1, ...args: any[]): any {
updateDynamicRam("run", getRamCost("run"));
updateDynamicRam("run", getRamCost(Player, "run"));
if (scriptname === undefined) {
throw makeRuntimeErrorMsg("run", "Usage: run(scriptname, [numThreads], [arg1], [arg2]...)");
}
@@ -943,11 +970,10 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
throw makeRuntimeErrorMsg("run", "Could not find server. This is a bug. Report to dev.");
}
return runScriptFromScript("run", scriptServer, scriptname, args, workerScript, threads);
return runScriptFromScript(Player, "run", scriptServer, scriptname, args, workerScript, threads);
},
exec: function (scriptname: any, hostname: any, threads: any = 1, ...args: any[]): any {
console.log(`${scriptname} ${hostname} ${threads} ${JSON.stringify(args)}`);
updateDynamicRam("exec", getRamCost("exec"));
updateDynamicRam("exec", getRamCost(Player, "exec"));
if (scriptname === undefined || hostname === undefined) {
throw makeRuntimeErrorMsg("exec", "Usage: exec(scriptname, server, [numThreads], [arg1], [arg2]...)");
}
@@ -955,10 +981,10 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
throw makeRuntimeErrorMsg("exec", `Invalid thread count. Must be numeric and > 0, is ${threads}`);
}
const server = safeGetServer(hostname, "exec");
return runScriptFromScript("exec", server, scriptname, args, workerScript, threads);
return runScriptFromScript(Player, "exec", server, scriptname, args, workerScript, threads);
},
spawn: function (scriptname: any, threads: any = 1, ...args: any[]): any {
updateDynamicRam("spawn", getRamCost("spawn"));
updateDynamicRam("spawn", getRamCost(Player, "spawn"));
if (!scriptname || !threads) {
throw makeRuntimeErrorMsg("spawn", "Usage: spawn(scriptname, threads)");
}
@@ -973,7 +999,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
throw makeRuntimeErrorMsg("spawn", "Could not find server. This is a bug. Report to dev");
}
return runScriptFromScript("spawn", scriptServer, scriptname, args, workerScript, threads);
return runScriptFromScript(Player, "spawn", scriptServer, scriptname, args, workerScript, threads);
}, spawnDelay * 1e3);
workerScript.log("spawn", () => `Will execute '${scriptname}' in ${spawnDelay} seconds`);
@@ -983,8 +1009,8 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
workerScript.log("spawn", () => "Exiting...");
}
},
kill: function (filename: any, hostname: any, ...scriptArgs: any): any {
updateDynamicRam("kill", getRamCost("kill"));
kill: function (filename: any, hostname?: any, ...scriptArgs: any): any {
updateDynamicRam("kill", getRamCost(Player, "kill"));
let res;
const killByPid = typeof filename === "number";
@@ -1030,7 +1056,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
}
},
killall: function (hostname: any = workerScript.hostname): any {
updateDynamicRam("killall", getRamCost("killall"));
updateDynamicRam("killall", getRamCost(Player, "killall"));
if (hostname === undefined) {
throw makeRuntimeErrorMsg("killall", "Takes 1 argument");
}
@@ -1056,7 +1082,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
}
},
scp: async function (scriptname: any, hostname1: any, hostname2: any): Promise<boolean> {
updateDynamicRam("scp", getRamCost("scp"));
updateDynamicRam("scp", getRamCost(Player, "scp"));
if (arguments.length !== 2 && arguments.length !== 3) {
throw makeRuntimeErrorMsg("scp", "Takes 2 or 3 arguments");
}
@@ -1209,11 +1235,11 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
resolve(false);
return;
}
newScript.updateRamUsage(destServer.scripts).then(() => resolve(true));
newScript.updateRamUsage(Player, destServer.scripts).then(() => resolve(true));
});
},
ls: function (hostname: any, grep: any): any {
updateDynamicRam("ls", getRamCost("ls"));
updateDynamicRam("ls", getRamCost(Player, "ls"));
if (hostname === undefined) {
throw makeRuntimeErrorMsg("ls", "Usage: ls(hostname/ip, [grep filter])");
}
@@ -1280,7 +1306,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return allFiles;
},
ps: function (hostname: any = workerScript.hostname): any {
updateDynamicRam("ps", getRamCost("ps"));
updateDynamicRam("ps", getRamCost(Player, "ps"));
const server = safeGetServer(hostname, "ps");
const processes = [];
for (const i in server.runningScripts) {
@@ -1295,7 +1321,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return processes;
},
hasRootAccess: function (hostname: any): any {
updateDynamicRam("hasRootAccess", getRamCost("hasRootAccess"));
updateDynamicRam("hasRootAccess", getRamCost(Player, "hasRootAccess"));
if (hostname === undefined) {
throw makeRuntimeErrorMsg("hasRootAccess", "Takes 1 argument");
}
@@ -1303,7 +1329,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return server.hasAdminRights;
},
getHostname: function (): any {
updateDynamicRam("getHostname", getRamCost("getHostname"));
updateDynamicRam("getHostname", getRamCost(Player, "getHostname"));
const scriptServer = GetServer(workerScript.hostname);
if (scriptServer == null) {
throw makeRuntimeErrorMsg("getHostname", "Could not find server. This is a bug. Report to dev.");
@@ -1311,13 +1337,13 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return scriptServer.hostname;
},
getHackingLevel: function (): any {
updateDynamicRam("getHackingLevel", getRamCost("getHackingLevel"));
updateDynamicRam("getHackingLevel", getRamCost(Player, "getHackingLevel"));
Player.updateSkillLevels();
workerScript.log("getHackingLevel", () => `returned ${Player.hacking}`);
return Player.hacking;
},
getHackingMultipliers: function (): any {
updateDynamicRam("getHackingMultipliers", getRamCost("getHackingMultipliers"));
updateDynamicRam("getHackingMultipliers", getRamCost(Player, "getHackingMultipliers"));
return {
chance: Player.hacking_chance_mult,
speed: Player.hacking_speed_mult,
@@ -1326,7 +1352,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
};
},
getHacknetMultipliers: function (): any {
updateDynamicRam("getHacknetMultipliers", getRamCost("getHacknetMultipliers"));
updateDynamicRam("getHacknetMultipliers", getRamCost(Player, "getHacknetMultipliers"));
return {
production: Player.hacknet_node_money_mult,
purchaseCost: Player.hacknet_node_purchase_cost_mult,
@@ -1336,7 +1362,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
};
},
getBitNodeMultipliers: function (): any {
updateDynamicRam("getBitNodeMultipliers", getRamCost("getBitNodeMultipliers"));
updateDynamicRam("getBitNodeMultipliers", getRamCost(Player, "getBitNodeMultipliers"));
if (SourceFileFlags[5] <= 0 && Player.bitNodeN !== 5) {
throw makeRuntimeErrorMsg("getBitNodeMultipliers", "Requires Source-File 5 to run.");
}
@@ -1344,7 +1370,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return copy;
},
getServer: function (hostname: any = workerScript.hostname): any {
updateDynamicRam("getServer", getRamCost("getServer"));
updateDynamicRam("getServer", getRamCost(Player, "getServer"));
const server = safeGetServer(hostname, "getServer");
const copy = Object.assign({}, server) as any;
// These fields should be hidden.
@@ -1367,7 +1393,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return copy;
},
getServerMoneyAvailable: function (hostname: any): any {
updateDynamicRam("getServerMoneyAvailable", getRamCost("getServerMoneyAvailable"));
updateDynamicRam("getServerMoneyAvailable", getRamCost(Player, "getServerMoneyAvailable"));
const server = safeGetServer(hostname, "getServerMoneyAvailable");
if (!(server instanceof Server)) {
workerScript.log("getServerMoneyAvailable", () => "Cannot be executed on this server.");
@@ -1391,7 +1417,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return server.moneyAvailable;
},
getServerSecurityLevel: function (hostname: any): any {
updateDynamicRam("getServerSecurityLevel", getRamCost("getServerSecurityLevel"));
updateDynamicRam("getServerSecurityLevel", getRamCost(Player, "getServerSecurityLevel"));
const server = safeGetServer(hostname, "getServerSecurityLevel");
if (!(server instanceof Server)) {
workerScript.log("getServerSecurityLevel", () => "Cannot be executed on this server.");
@@ -1407,7 +1433,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return server.hackDifficulty;
},
getServerBaseSecurityLevel: function (hostname: any): any {
updateDynamicRam("getServerBaseSecurityLevel", getRamCost("getServerBaseSecurityLevel"));
updateDynamicRam("getServerBaseSecurityLevel", getRamCost(Player, "getServerBaseSecurityLevel"));
workerScript.log(
"getServerBaseSecurityLevel",
() => `getServerBaseSecurityLevel is deprecated because it's not useful.`,
@@ -1427,7 +1453,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return server.baseDifficulty;
},
getServerMinSecurityLevel: function (hostname: any): any {
updateDynamicRam("getServerMinSecurityLevel", getRamCost("getServerMinSecurityLevel"));
updateDynamicRam("getServerMinSecurityLevel", getRamCost(Player, "getServerMinSecurityLevel"));
const server = safeGetServer(hostname, "getServerMinSecurityLevel");
if (!(server instanceof Server)) {
workerScript.log("getServerMinSecurityLevel", () => "Cannot be executed on this server.");
@@ -1443,7 +1469,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return server.minDifficulty;
},
getServerRequiredHackingLevel: function (hostname: any): any {
updateDynamicRam("getServerRequiredHackingLevel", getRamCost("getServerRequiredHackingLevel"));
updateDynamicRam("getServerRequiredHackingLevel", getRamCost(Player, "getServerRequiredHackingLevel"));
const server = safeGetServer(hostname, "getServerRequiredHackingLevel");
if (!(server instanceof Server)) {
workerScript.log("getServerRequiredHackingLevel", () => "Cannot be executed on this server.");
@@ -1459,7 +1485,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return server.requiredHackingSkill;
},
getServerMaxMoney: function (hostname: any): any {
updateDynamicRam("getServerMaxMoney", getRamCost("getServerMaxMoney"));
updateDynamicRam("getServerMaxMoney", getRamCost(Player, "getServerMaxMoney"));
const server = safeGetServer(hostname, "getServerMaxMoney");
if (!(server instanceof Server)) {
workerScript.log("getServerMaxMoney", () => "Cannot be executed on this server.");
@@ -1475,7 +1501,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return server.moneyMax;
},
getServerGrowth: function (hostname: any): any {
updateDynamicRam("getServerGrowth", getRamCost("getServerGrowth"));
updateDynamicRam("getServerGrowth", getRamCost(Player, "getServerGrowth"));
const server = safeGetServer(hostname, "getServerGrowth");
if (!(server instanceof Server)) {
workerScript.log("getServerGrowth", () => "Cannot be executed on this server.");
@@ -1488,7 +1514,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return server.serverGrowth;
},
getServerNumPortsRequired: function (hostname: any): any {
updateDynamicRam("getServerNumPortsRequired", getRamCost("getServerNumPortsRequired"));
updateDynamicRam("getServerNumPortsRequired", getRamCost(Player, "getServerNumPortsRequired"));
const server = safeGetServer(hostname, "getServerNumPortsRequired");
if (!(server instanceof Server)) {
workerScript.log("getServerNumPortsRequired", () => "Cannot be executed on this server.");
@@ -1504,7 +1530,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return server.numOpenPortsRequired;
},
getServerRam: function (hostname: any): any {
updateDynamicRam("getServerRam", getRamCost("getServerRam"));
updateDynamicRam("getServerRam", getRamCost(Player, "getServerRam"));
workerScript.log(
"getServerRam",
() => `getServerRam is deprecated in favor of getServerMaxRam / getServerUsedRam`,
@@ -1517,23 +1543,23 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return [server.maxRam, server.ramUsed];
},
getServerMaxRam: function (hostname: any): any {
updateDynamicRam("getServerMaxRam", getRamCost("getServerMaxRam"));
updateDynamicRam("getServerMaxRam", getRamCost(Player, "getServerMaxRam"));
const server = safeGetServer(hostname, "getServerMaxRam");
workerScript.log("getServerMaxRam", () => `returned ${numeralWrapper.formatRAM(server.maxRam)}`);
return server.maxRam;
},
getServerUsedRam: function (hostname: any): any {
updateDynamicRam("getServerUsedRam", getRamCost("getServerUsedRam"));
updateDynamicRam("getServerUsedRam", getRamCost(Player, "getServerUsedRam"));
const server = safeGetServer(hostname, "getServerUsedRam");
workerScript.log("getServerUsedRam", () => `returned ${numeralWrapper.formatRAM(server.ramUsed)}`);
return server.ramUsed;
},
serverExists: function (hostname: any): any {
updateDynamicRam("serverExists", getRamCost("serverExists"));
updateDynamicRam("serverExists", getRamCost(Player, "serverExists"));
return GetServer(hostname) !== null;
},
fileExists: function (filename: any, hostname: any = workerScript.hostname): any {
updateDynamicRam("fileExists", getRamCost("fileExists"));
updateDynamicRam("fileExists", getRamCost(Player, "fileExists"));
if (filename === undefined) {
throw makeRuntimeErrorMsg("fileExists", "Usage: fileExists(scriptname, [server])");
}
@@ -1560,7 +1586,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return false;
},
isRunning: function (fn: any, hostname: any = workerScript.hostname, ...scriptArgs: any): any {
updateDynamicRam("isRunning", getRamCost("isRunning"));
updateDynamicRam("isRunning", getRamCost(Player, "isRunning"));
if (fn === undefined || hostname === undefined) {
throw makeRuntimeErrorMsg("isRunning", "Usage: isRunning(scriptname, server, [arg1], [arg2]...)");
}
@@ -1571,17 +1597,17 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
}
},
getPurchasedServerLimit: function (): any {
updateDynamicRam("getPurchasedServerLimit", getRamCost("getPurchasedServerLimit"));
updateDynamicRam("getPurchasedServerLimit", getRamCost(Player, "getPurchasedServerLimit"));
return getPurchaseServerLimit();
},
getPurchasedServerMaxRam: function (): any {
updateDynamicRam("getPurchasedServerMaxRam", getRamCost("getPurchasedServerMaxRam"));
updateDynamicRam("getPurchasedServerMaxRam", getRamCost(Player, "getPurchasedServerMaxRam"));
return getPurchaseServerMaxRam();
},
getPurchasedServerCost: function (ram: any): any {
updateDynamicRam("getPurchasedServerCost", getRamCost("getPurchasedServerCost"));
updateDynamicRam("getPurchasedServerCost", getRamCost(Player, "getPurchasedServerCost"));
const cost = getPurchaseServerCost(ram);
if (cost === Infinity) {
@@ -1591,8 +1617,10 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return cost;
},
purchaseServer: function (name: any, ram: any): any {
updateDynamicRam("purchaseServer", getRamCost("purchaseServer"));
purchaseServer: function (aname: any, aram: any): any {
const name = helper.string("purchaseServer", "name", aname);
const ram = helper.number("purchaseServer", "ram", aram);
updateDynamicRam("purchaseServer", getRamCost(Player, "purchaseServer"));
let hostnameStr = String(name);
hostnameStr = hostnameStr.replace(/\s+/g, "");
if (hostnameStr == "") {
@@ -1611,7 +1639,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
const cost = getPurchaseServerCost(ram);
if (cost === Infinity) {
workerScript.log("purchaseServer", () => `Invalid argument: ram='${ram}'`);
workerScript.log("purchaseServer", () => `Invalid argument: ram='${ram}' must be a positive power of 2`);
return "";
}
@@ -1645,7 +1673,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return newServ.hostname;
},
deleteServer: function (name: any): any {
updateDynamicRam("deleteServer", getRamCost("deleteServer"));
updateDynamicRam("deleteServer", getRamCost(Player, "deleteServer"));
let hostnameStr = String(name);
hostnameStr = hostnameStr.replace(/\s\s+/g, "");
const server = GetServer(hostnameStr);
@@ -1721,7 +1749,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return false;
},
getPurchasedServers: function (): any {
updateDynamicRam("getPurchasedServers", getRamCost("getPurchasedServers"));
updateDynamicRam("getPurchasedServers", getRamCost(Player, "getPurchasedServers"));
const res: string[] = [];
Player.purchasedServers.forEach(function (hostname) {
res.push(hostname);
@@ -1729,29 +1757,17 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return res;
},
writePort: function (port: any, data: any = ""): any {
// Write to port
// Port 1-10
if (typeof data !== "string" && typeof data !== "number") {
throw makeRuntimeErrorMsg(
"writePort",
`Trying to write invalid data to a port: only strings and numbers are valid.`,
);
}
port = Math.round(port);
if (port < 1 || port > CONSTANTS.NumNetscriptPorts) {
throw makeRuntimeErrorMsg(
"writePort",
`Trying to write to invalid port: ${port}. Only ports 1-${CONSTANTS.NumNetscriptPorts} are valid.`,
);
}
const iport = NetscriptPorts[port - 1];
if (iport == null || !(iport instanceof Object)) {
throw makeRuntimeErrorMsg("writePort", `Could not find port: ${port}. This is a bug. Report to dev.`);
}
const iport = helper.getValidPort("writePort", port);
return Promise.resolve(iport.write(data));
},
write: function (port: any, data: any = "", mode: any = "a"): any {
updateDynamicRam("write", getRamCost("write"));
updateDynamicRam("write", getRamCost(Player, "write"));
if (isString(port)) {
// Write to script or text file
let fn = port;
@@ -1779,12 +1795,12 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
let script = workerScript.getScriptOnServer(fn, server);
if (script == null) {
// Create a new script
script = new Script(fn, data, server.hostname, server.scripts);
script = new Script(Player, fn, data, server.hostname, server.scripts);
server.scripts.push(script);
return script.updateRamUsage(server.scripts);
return script.updateRamUsage(Player, server.scripts);
}
mode === "w" ? (script.code = data) : (script.code += data);
return script.updateRamUsage(server.scripts);
return script.updateRamUsage(Player, server.scripts);
} else {
// Write to text file
const txtFile = getTextFile(fn, server);
@@ -1804,7 +1820,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
}
},
tryWritePort: function (port: any, data: any = ""): any {
updateDynamicRam("tryWritePort", getRamCost("tryWritePort"));
updateDynamicRam("tryWritePort", getRamCost(Player, "tryWritePort"));
if (!isNaN(port)) {
port = Math.round(port);
if (port < 1 || port > CONSTANTS.NumNetscriptPorts) {
@@ -1824,23 +1840,12 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
},
readPort: function (port: any): any {
// Read from port
// Port 1-10
port = Math.round(port);
if (port < 1 || port > CONSTANTS.NumNetscriptPorts) {
throw makeRuntimeErrorMsg(
"readPort",
`Invalid port: ${port}. Only ports 1-${CONSTANTS.NumNetscriptPorts} are valid.`,
);
}
const iport = NetscriptPorts[port - 1];
if (iport == null || !(iport instanceof Object)) {
throw makeRuntimeErrorMsg("readPort", `Could not find port: ${port}. This is a bug. Report to dev.`);
}
const iport = helper.getValidPort("readPort", port);
const x = iport.read();
return x;
},
read: function (port: any): any {
updateDynamicRam("read", getRamCost("read"));
updateDynamicRam("read", getRamCost(Player, "read"));
if (isString(port)) {
// Read from script or text file
const fn = port;
@@ -1869,29 +1874,13 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
}
},
peek: function (port: any): any {
updateDynamicRam("peek", getRamCost("peek"));
if (isNaN(port)) {
throw makeRuntimeErrorMsg(
"peek",
`Invalid argument. Must be a port number between 1 and ${CONSTANTS.NumNetscriptPorts}, is ${port}`,
);
}
port = Math.round(port);
if (port < 1 || port > CONSTANTS.NumNetscriptPorts) {
throw makeRuntimeErrorMsg(
"peek",
`Invalid argument. Must be a port number between 1 and ${CONSTANTS.NumNetscriptPorts}, is ${port}`,
);
}
const iport = NetscriptPorts[port - 1];
if (iport == null || !(iport instanceof Object)) {
throw makeRuntimeErrorMsg("peek", `Could not find port: ${port}. This is a bug. Report to dev.`);
}
updateDynamicRam("peek", getRamCost(Player, "peek"));
const iport = helper.getValidPort("peek", port);
const x = iport.peek();
return x;
},
clear: function (file: any): any {
updateDynamicRam("clear", getRamCost("clear"));
updateDynamicRam("clear", getRamCost(Player, "clear"));
if (isString(file)) {
// Clear text file
const fn = file;
@@ -1910,42 +1899,16 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
},
clearPort: function (port: any): any {
// Clear port
port = Math.round(port);
if (port < 1 || port > CONSTANTS.NumNetscriptPorts) {
throw makeRuntimeErrorMsg(
"clear",
`Trying to clear invalid port: ${port}. Only ports 1-${CONSTANTS.NumNetscriptPorts} are valid`,
);
}
const iport = NetscriptPorts[port - 1];
if (iport == null || !(iport instanceof Object)) {
throw makeRuntimeErrorMsg("clear", `Could not find port: ${port}. This is a bug. Report to dev.`);
}
const iport = helper.getValidPort("clearPort", port);
return iport.clear();
},
getPortHandle: function (port: any): any {
updateDynamicRam("getPortHandle", getRamCost("getPortHandle"));
if (isNaN(port)) {
throw makeRuntimeErrorMsg(
"getPortHandle",
`Invalid port: ${port} Must be an integer between 1 and ${CONSTANTS.NumNetscriptPorts}.`,
);
}
port = Math.round(port);
if (port < 1 || port > CONSTANTS.NumNetscriptPorts) {
throw makeRuntimeErrorMsg(
"getPortHandle",
`Invalid port: ${port}. Only ports 1-${CONSTANTS.NumNetscriptPorts} are valid.`,
);
}
const iport = NetscriptPorts[port - 1];
if (iport == null || !(iport instanceof Object)) {
throw makeRuntimeErrorMsg("getPortHandle", `Could not find port: ${port}. This is a bug. Report to dev.`);
}
updateDynamicRam("getPortHandle", getRamCost(Player, "getPortHandle"));
const iport = helper.getValidPort("getPortHandle", port);
return iport;
},
rm: function (fn: any, hostname: any): any {
updateDynamicRam("rm", getRamCost("rm"));
updateDynamicRam("rm", getRamCost(Player, "rm"));
if (hostname == null || hostname === "") {
hostname = workerScript.hostname;
@@ -1960,7 +1923,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return status.res;
},
scriptRunning: function (scriptname: any, hostname: any): any {
updateDynamicRam("scriptRunning", getRamCost("scriptRunning"));
updateDynamicRam("scriptRunning", getRamCost(Player, "scriptRunning"));
const server = safeGetServer(hostname, "scriptRunning");
for (let i = 0; i < server.runningScripts.length; ++i) {
if (server.runningScripts[i].filename == scriptname) {
@@ -1970,7 +1933,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return false;
},
scriptKill: function (scriptname: any, hostname: any): any {
updateDynamicRam("scriptKill", getRamCost("scriptKill"));
updateDynamicRam("scriptKill", getRamCost(Player, "scriptKill"));
const server = safeGetServer(hostname, "scriptKill");
let suc = false;
for (let i = 0; i < server.runningScripts.length; i++) {
@@ -1986,7 +1949,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return workerScript.name;
},
getScriptRam: function (scriptname: any, hostname: any = workerScript.hostname): any {
updateDynamicRam("getScriptRam", getRamCost("getScriptRam"));
updateDynamicRam("getScriptRam", getRamCost(Player, "getScriptRam"));
const server = safeGetServer(hostname, "getScriptRam");
for (let i = 0; i < server.scripts.length; ++i) {
if (server.scripts[i].filename == scriptname) {
@@ -1996,7 +1959,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return 0;
},
getRunningScript: function (fn: any, hostname: any, ...args: any[]): any {
updateDynamicRam("getRunningScript", getRamCost("getRunningScript"));
updateDynamicRam("getRunningScript", getRamCost(Player, "getRunningScript"));
let runningScript;
if (fn === undefined && hostname === undefined && args.length === 0) {
@@ -2024,7 +1987,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
};
},
getHackTime: function (hostname: any): any {
updateDynamicRam("getHackTime", getRamCost("getHackTime"));
updateDynamicRam("getHackTime", getRamCost(Player, "getHackTime"));
const server = safeGetServer(hostname, "getHackTime");
if (!(server instanceof Server)) {
workerScript.log("getHackTime", () => "invalid for this kind of server");
@@ -2037,7 +2000,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return calculateHackingTime(server, Player) * 1000;
},
getGrowTime: function (hostname: any): any {
updateDynamicRam("getGrowTime", getRamCost("getGrowTime"));
updateDynamicRam("getGrowTime", getRamCost(Player, "getGrowTime"));
const server = safeGetServer(hostname, "getGrowTime");
if (!(server instanceof Server)) {
workerScript.log("getGrowTime", () => "invalid for this kind of server");
@@ -2050,7 +2013,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return calculateGrowTime(server, Player) * 1000;
},
getWeakenTime: function (hostname: any): any {
updateDynamicRam("getWeakenTime", getRamCost("getWeakenTime"));
updateDynamicRam("getWeakenTime", getRamCost(Player, "getWeakenTime"));
const server = safeGetServer(hostname, "getWeakenTime");
if (!(server instanceof Server)) {
workerScript.log("getWeakenTime", () => "invalid for this kind of server");
@@ -2062,8 +2025,8 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return calculateWeakenTime(server, Player) * 1000;
},
getScriptIncome: function (scriptname: any, hostname: any, ...args: any[]): any {
updateDynamicRam("getScriptIncome", getRamCost("getScriptIncome"));
getScriptIncome: function (scriptname?: any, hostname?: any, ...args: any[]): any {
updateDynamicRam("getScriptIncome", getRamCost(Player, "getScriptIncome"));
if (arguments.length === 0) {
const res = [];
@@ -2091,8 +2054,8 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return runningScriptObj.onlineMoneyMade / runningScriptObj.onlineRunningTime;
}
},
getScriptExpGain: function (scriptname: any, hostname: any, ...args: any[]): any {
updateDynamicRam("getScriptExpGain", getRamCost("getScriptExpGain"));
getScriptExpGain: function (scriptname?: any, hostname?: any, ...args: any[]): any {
updateDynamicRam("getScriptExpGain", getRamCost(Player, "getScriptExpGain"));
if (arguments.length === 0) {
let total = 0;
for (const ws of workerScripts.values()) {
@@ -2124,19 +2087,19 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return convertTimeMsToTimeElapsedString(milliseconds, milliPrecision);
},
getTimeSinceLastAug: function (): any {
updateDynamicRam("getTimeSinceLastAug", getRamCost("getTimeSinceLastAug"));
updateDynamicRam("getTimeSinceLastAug", getRamCost(Player, "getTimeSinceLastAug"));
return Player.playtimeSinceLastAug;
},
alert: function (message: any): void {
message = toNative(message);
dialogBoxCreate(JSON.stringify(message));
message = argsToString([message]);
dialogBoxCreate(message);
},
toast: function (message: any, variant: any = "success"): void {
toast: function (message: any, variant: any = "success", duration: any = 2000): void {
if (!["success", "info", "warning", "error"].includes(variant))
throw new Error(`variant must be one of "success", "info", "warning", or "error"`);
message = toNative(message);
SnackbarEvents.emit(JSON.stringify(message), variant);
message = argsToString([message]);
SnackbarEvents.emit(message, variant, duration);
},
prompt: function (txt: any): any {
if (!isString(txt)) {
@@ -2162,7 +2125,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
function (data) {
let res;
if (isScriptFilename(target)) {
res = s.writeToScriptFile(target, data);
res = s.writeToScriptFile(Player, target, data);
} else {
res = s.writeToTextFile(target, data);
}
@@ -2188,11 +2151,11 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
});
},
getFavorToDonate: function (): any {
updateDynamicRam("getFavorToDonate", getRamCost("getFavorToDonate"));
updateDynamicRam("getFavorToDonate", getRamCost(Player, "getFavorToDonate"));
return Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction);
},
getOwnedSourceFiles: function (): SourceFileLvl[] {
helper.updateDynamicRam("getOwnedSourceFiles", getRamCost("getOwnedSourceFiles"));
helper.updateDynamicRam("getOwnedSourceFiles", getRamCost(Player, "getOwnedSourceFiles"));
const res: SourceFileLvl[] = [];
for (let i = 0; i < Player.sourceFiles.length; ++i) {
res.push({
@@ -2203,7 +2166,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return res;
},
getPlayer: function (): INetscriptPlayer {
helper.updateDynamicRam("getPlayer", getRamCost("getPlayer"));
helper.updateDynamicRam("getPlayer", getRamCost(Player, "getPlayer"));
const data = {
hacking: Player.hacking,
@@ -2310,10 +2273,12 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
...base,
...extra,
};
function getFunctionNames(obj: NS, prefix: string): string[] {
function getFunctionNames(obj: any, prefix: string): string[] {
const functionNames: string[] = [];
for (const [key, value] of Object.entries(obj)) {
if (typeof value == "function") {
if (key === "args") {
continue;
} else if (typeof value == "function") {
functionNames.push(prefix + key);
} else if (typeof value == "object") {
functionNames.push(...getFunctionNames(value, key + "."));

View File

@@ -57,48 +57,48 @@ export function NetscriptBladeburner(
return {
getContractNames: function (): string[] {
helper.updateDynamicRam("getContractNames", getRamCost("bladeburner", "getContractNames"));
helper.updateDynamicRam("getContractNames", getRamCost(player, "bladeburner", "getContractNames"));
checkBladeburnerAccess("getContractNames");
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
return bladeburner.getContractNamesNetscriptFn();
},
getOperationNames: function (): string[] {
helper.updateDynamicRam("getOperationNames", getRamCost("bladeburner", "getOperationNames"));
helper.updateDynamicRam("getOperationNames", getRamCost(player, "bladeburner", "getOperationNames"));
checkBladeburnerAccess("getOperationNames");
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
return bladeburner.getOperationNamesNetscriptFn();
},
getBlackOpNames: function (): string[] {
helper.updateDynamicRam("getBlackOpNames", getRamCost("bladeburner", "getBlackOpNames"));
helper.updateDynamicRam("getBlackOpNames", getRamCost(player, "bladeburner", "getBlackOpNames"));
checkBladeburnerAccess("getBlackOpNames");
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
return bladeburner.getBlackOpNamesNetscriptFn();
},
getBlackOpRank: function (name: any = ""): number {
helper.updateDynamicRam("getBlackOpRank", getRamCost("bladeburner", "getBlackOpRank"));
helper.updateDynamicRam("getBlackOpRank", getRamCost(player, "bladeburner", "getBlackOpRank"));
checkBladeburnerAccess("getBlackOpRank");
const action: any = getBladeburnerActionObject("getBlackOpRank", "blackops", name);
return action.reqdRank;
},
getGeneralActionNames: function (): string[] {
helper.updateDynamicRam("getGeneralActionNames", getRamCost("bladeburner", "getGeneralActionNames"));
helper.updateDynamicRam("getGeneralActionNames", getRamCost(player, "bladeburner", "getGeneralActionNames"));
checkBladeburnerAccess("getGeneralActionNames");
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
return bladeburner.getGeneralActionNamesNetscriptFn();
},
getSkillNames: function (): string[] {
helper.updateDynamicRam("getSkillNames", getRamCost("bladeburner", "getSkillNames"));
helper.updateDynamicRam("getSkillNames", getRamCost(player, "bladeburner", "getSkillNames"));
checkBladeburnerAccess("getSkillNames");
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
return bladeburner.getSkillNamesNetscriptFn();
},
startAction: function (type: any = "", name: any = ""): boolean {
helper.updateDynamicRam("startAction", getRamCost("bladeburner", "startAction"));
helper.updateDynamicRam("startAction", getRamCost(player, "bladeburner", "startAction"));
checkBladeburnerAccess("startAction");
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
@@ -109,21 +109,21 @@ export function NetscriptBladeburner(
}
},
stopBladeburnerAction: function (): void {
helper.updateDynamicRam("stopBladeburnerAction", getRamCost("bladeburner", "stopBladeburnerAction"));
helper.updateDynamicRam("stopBladeburnerAction", getRamCost(player, "bladeburner", "stopBladeburnerAction"));
checkBladeburnerAccess("stopBladeburnerAction");
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
return bladeburner.resetAction();
},
getCurrentAction: function (): BladeburnerCurAction {
helper.updateDynamicRam("getCurrentAction", getRamCost("bladeburner", "getCurrentAction"));
helper.updateDynamicRam("getCurrentAction", getRamCost(player, "bladeburner", "getCurrentAction"));
checkBladeburnerAccess("getCurrentAction");
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
return bladeburner.getTypeAndNameFromActionId(bladeburner.action);
},
getActionTime: function (type: any = "", name: any = ""): number {
helper.updateDynamicRam("getActionTime", getRamCost("bladeburner", "getActionTime"));
helper.updateDynamicRam("getActionTime", getRamCost(player, "bladeburner", "getActionTime"));
checkBladeburnerAccess("getActionTime");
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
@@ -136,7 +136,7 @@ export function NetscriptBladeburner(
getActionEstimatedSuccessChance: function (type: any = "", name: any = ""): [number, number] {
helper.updateDynamicRam(
"getActionEstimatedSuccessChance",
getRamCost("bladeburner", "getActionEstimatedSuccessChance"),
getRamCost(player, "bladeburner", "getActionEstimatedSuccessChance"),
);
checkBladeburnerAccess("getActionEstimatedSuccessChance");
const bladeburner = player.bladeburner;
@@ -148,7 +148,7 @@ export function NetscriptBladeburner(
}
},
getActionRepGain: function (type: any = "", name: any = "", level: any): number {
helper.updateDynamicRam("getActionRepGain", getRamCost("bladeburner", "getActionRepGain"));
helper.updateDynamicRam("getActionRepGain", getRamCost(player, "bladeburner", "getActionRepGain"));
checkBladeburnerAccess("getActionRepGain");
const action = getBladeburnerActionObject("getActionRepGain", type, name);
let rewardMultiplier;
@@ -161,7 +161,7 @@ export function NetscriptBladeburner(
return action.rankGain * rewardMultiplier * BitNodeMultipliers.BladeburnerRank;
},
getActionCountRemaining: function (type: any = "", name: any = ""): number {
helper.updateDynamicRam("getActionCountRemaining", getRamCost("bladeburner", "getActionCountRemaining"));
helper.updateDynamicRam("getActionCountRemaining", getRamCost(player, "bladeburner", "getActionCountRemaining"));
checkBladeburnerAccess("getActionCountRemaining");
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
@@ -172,31 +172,31 @@ export function NetscriptBladeburner(
}
},
getActionMaxLevel: function (type: any = "", name: any = ""): number {
helper.updateDynamicRam("getActionMaxLevel", getRamCost("bladeburner", "getActionMaxLevel"));
helper.updateDynamicRam("getActionMaxLevel", getRamCost(player, "bladeburner", "getActionMaxLevel"));
checkBladeburnerAccess("getActionMaxLevel");
const action = getBladeburnerActionObject("getActionMaxLevel", type, name);
return action.maxLevel;
},
getActionCurrentLevel: function (type: any = "", name: any = ""): number {
helper.updateDynamicRam("getActionCurrentLevel", getRamCost("bladeburner", "getActionCurrentLevel"));
helper.updateDynamicRam("getActionCurrentLevel", getRamCost(player, "bladeburner", "getActionCurrentLevel"));
checkBladeburnerAccess("getActionCurrentLevel");
const action = getBladeburnerActionObject("getActionCurrentLevel", type, name);
return action.level;
},
getActionAutolevel: function (type: any = "", name: any = ""): boolean {
helper.updateDynamicRam("getActionAutolevel", getRamCost("bladeburner", "getActionAutolevel"));
helper.updateDynamicRam("getActionAutolevel", getRamCost(player, "bladeburner", "getActionAutolevel"));
checkBladeburnerAccess("getActionAutolevel");
const action = getBladeburnerActionObject("getActionCurrentLevel", type, name);
return action.autoLevel;
},
setActionAutolevel: function (type: any = "", name: any = "", autoLevel: any = true): void {
helper.updateDynamicRam("setActionAutolevel", getRamCost("bladeburner", "setActionAutolevel"));
helper.updateDynamicRam("setActionAutolevel", getRamCost(player, "bladeburner", "setActionAutolevel"));
checkBladeburnerAccess("setActionAutolevel");
const action = getBladeburnerActionObject("setActionAutolevel", type, name);
action.autoLevel = autoLevel;
},
setActionLevel: function (type: any = "", name: any = "", level: any = 1): void {
helper.updateDynamicRam("setActionLevel", getRamCost("bladeburner", "setActionLevel"));
helper.updateDynamicRam("setActionLevel", getRamCost(player, "bladeburner", "setActionLevel"));
checkBladeburnerAccess("setActionLevel");
const action = getBladeburnerActionObject("setActionLevel", type, name);
if (level < 1 || level > action.maxLevel) {
@@ -208,21 +208,21 @@ export function NetscriptBladeburner(
action.level = level;
},
getRank: function (): number {
helper.updateDynamicRam("getRank", getRamCost("bladeburner", "getRank"));
helper.updateDynamicRam("getRank", getRamCost(player, "bladeburner", "getRank"));
checkBladeburnerAccess("getRank");
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
return bladeburner.rank;
},
getSkillPoints: function (): number {
helper.updateDynamicRam("getSkillPoints", getRamCost("bladeburner", "getSkillPoints"));
helper.updateDynamicRam("getSkillPoints", getRamCost(player, "bladeburner", "getSkillPoints"));
checkBladeburnerAccess("getSkillPoints");
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
return bladeburner.skillPoints;
},
getSkillLevel: function (skillName: any = ""): number {
helper.updateDynamicRam("getSkillLevel", getRamCost("bladeburner", "getSkillLevel"));
helper.updateDynamicRam("getSkillLevel", getRamCost(player, "bladeburner", "getSkillLevel"));
checkBladeburnerAccess("getSkillLevel");
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
@@ -233,7 +233,7 @@ export function NetscriptBladeburner(
}
},
getSkillUpgradeCost: function (skillName: any = ""): number {
helper.updateDynamicRam("getSkillUpgradeCost", getRamCost("bladeburner", "getSkillUpgradeCost"));
helper.updateDynamicRam("getSkillUpgradeCost", getRamCost(player, "bladeburner", "getSkillUpgradeCost"));
checkBladeburnerAccess("getSkillUpgradeCost");
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
@@ -244,7 +244,7 @@ export function NetscriptBladeburner(
}
},
upgradeSkill: function (skillName: any): boolean {
helper.updateDynamicRam("upgradeSkill", getRamCost("bladeburner", "upgradeSkill"));
helper.updateDynamicRam("upgradeSkill", getRamCost(player, "bladeburner", "upgradeSkill"));
checkBladeburnerAccess("upgradeSkill");
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
@@ -255,7 +255,7 @@ export function NetscriptBladeburner(
}
},
getTeamSize: function (type: any = "", name: any = ""): number {
helper.updateDynamicRam("getTeamSize", getRamCost("bladeburner", "getTeamSize"));
helper.updateDynamicRam("getTeamSize", getRamCost(player, "bladeburner", "getTeamSize"));
checkBladeburnerAccess("getTeamSize");
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
@@ -266,7 +266,7 @@ export function NetscriptBladeburner(
}
},
setTeamSize: function (type: any = "", name: any = "", size: any): number {
helper.updateDynamicRam("setTeamSize", getRamCost("bladeburner", "setTeamSize"));
helper.updateDynamicRam("setTeamSize", getRamCost(player, "bladeburner", "setTeamSize"));
checkBladeburnerAccess("setTeamSize");
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
@@ -277,7 +277,10 @@ export function NetscriptBladeburner(
}
},
getCityEstimatedPopulation: function (cityName: any): number {
helper.updateDynamicRam("getCityEstimatedPopulation", getRamCost("bladeburner", "getCityEstimatedPopulation"));
helper.updateDynamicRam(
"getCityEstimatedPopulation",
getRamCost(player, "bladeburner", "getCityEstimatedPopulation"),
);
checkBladeburnerAccess("getCityEstimatedPopulation");
checkBladeburnerCity("getCityEstimatedPopulation", cityName);
const bladeburner = player.bladeburner;
@@ -285,7 +288,7 @@ export function NetscriptBladeburner(
return bladeburner.cities[cityName].popEst;
},
getCityCommunities: function (cityName: any): number {
helper.updateDynamicRam("getCityCommunities", getRamCost("bladeburner", "getCityCommunities"));
helper.updateDynamicRam("getCityCommunities", getRamCost(player, "bladeburner", "getCityCommunities"));
checkBladeburnerAccess("getCityCommunities");
checkBladeburnerCity("getCityCommunities", cityName);
const bladeburner = player.bladeburner;
@@ -293,7 +296,7 @@ export function NetscriptBladeburner(
return bladeburner.cities[cityName].comms;
},
getCityChaos: function (cityName: any): number {
helper.updateDynamicRam("getCityChaos", getRamCost("bladeburner", "getCityChaos"));
helper.updateDynamicRam("getCityChaos", getRamCost(player, "bladeburner", "getCityChaos"));
checkBladeburnerAccess("getCityChaos");
checkBladeburnerCity("getCityChaos", cityName);
const bladeburner = player.bladeburner;
@@ -301,14 +304,14 @@ export function NetscriptBladeburner(
return bladeburner.cities[cityName].chaos;
},
getCity: function (): string {
helper.updateDynamicRam("getCity", getRamCost("bladeburner", "getCity"));
helper.updateDynamicRam("getCity", getRamCost(player, "bladeburner", "getCity"));
checkBladeburnerAccess("getCityChaos");
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
return bladeburner.city;
},
switchCity: function (cityName: any): boolean {
helper.updateDynamicRam("switchCity", getRamCost("bladeburner", "switchCity"));
helper.updateDynamicRam("switchCity", getRamCost(player, "bladeburner", "switchCity"));
checkBladeburnerAccess("switchCity");
checkBladeburnerCity("switchCity", cityName);
const bladeburner = player.bladeburner;
@@ -316,21 +319,21 @@ export function NetscriptBladeburner(
return (bladeburner.city = cityName);
},
getStamina: function (): [number, number] {
helper.updateDynamicRam("getStamina", getRamCost("bladeburner", "getStamina"));
helper.updateDynamicRam("getStamina", getRamCost(player, "bladeburner", "getStamina"));
checkBladeburnerAccess("getStamina");
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
return [bladeburner.stamina, bladeburner.maxStamina];
},
joinBladeburnerFaction: function (): boolean {
helper.updateDynamicRam("joinBladeburnerFaction", getRamCost("bladeburner", "joinBladeburnerFaction"));
helper.updateDynamicRam("joinBladeburnerFaction", getRamCost(player, "bladeburner", "joinBladeburnerFaction"));
checkBladeburnerAccess("joinBladeburnerFaction", true);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
return bladeburner.joinBladeburnerFactionNetscriptFn(workerScript);
},
joinBladeburnerDivision: function (): boolean {
helper.updateDynamicRam("joinBladeburnerDivision", getRamCost("bladeburner", "joinBladeburnerDivision"));
helper.updateDynamicRam("joinBladeburnerDivision", getRamCost(player, "bladeburner", "joinBladeburnerDivision"));
if (player.bitNodeN === 7 || player.sourceFileLvl(7) > 0) {
if (player.bitNodeN === 8) {
return false;
@@ -358,7 +361,7 @@ export function NetscriptBladeburner(
return false;
},
getBonusTime: function (): number {
helper.updateDynamicRam("getBonusTime", getRamCost("bladeburner", "getBonusTime"));
helper.updateDynamicRam("getBonusTime", getRamCost(player, "bladeburner", "getBonusTime"));
checkBladeburnerAccess("getBonusTime");
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");

View File

@@ -31,7 +31,7 @@ export function NetscriptCodingContract(
hostname: any = workerScript.hostname,
{ returnReward }: any = {},
): boolean | string {
helper.updateDynamicRam("attempt", getRamCost("codingcontract", "attempt"));
helper.updateDynamicRam("attempt", getRamCost(player, "codingcontract", "attempt"));
const contract = getCodingContract("attempt", hostname, filename);
// Convert answer to string. If the answer is a 2D array, then we have to
@@ -78,12 +78,12 @@ export function NetscriptCodingContract(
}
},
getContractType: function (filename: any, hostname: any = workerScript.hostname): string {
helper.updateDynamicRam("getContractType", getRamCost("codingcontract", "getContractType"));
helper.updateDynamicRam("getContractType", getRamCost(player, "codingcontract", "getContractType"));
const contract = getCodingContract("getContractType", hostname, filename);
return contract.getType();
},
getData: function (filename: any, hostname: any = workerScript.hostname): any {
helper.updateDynamicRam("getData", getRamCost("codingcontract", "getData"));
helper.updateDynamicRam("getData", getRamCost(player, "codingcontract", "getData"));
const contract = getCodingContract("getData", hostname, filename);
const data = contract.getData();
if (data.constructor === Array) {
@@ -103,12 +103,12 @@ export function NetscriptCodingContract(
}
},
getDescription: function (filename: any, hostname: any = workerScript.hostname): string {
helper.updateDynamicRam("getDescription", getRamCost("codingcontract", "getDescription"));
helper.updateDynamicRam("getDescription", getRamCost(player, "codingcontract", "getDescription"));
const contract = getCodingContract("getDescription", hostname, filename);
return contract.getDescription();
},
getNumTriesRemaining: function (filename: any, hostname: any = workerScript.hostname): number {
helper.updateDynamicRam("getNumTriesRemaining", getRamCost("codingcontract", "getNumTriesRemaining"));
helper.updateDynamicRam("getNumTriesRemaining", getRamCost(player, "codingcontract", "getNumTriesRemaining"));
const contract = getCodingContract("getNumTriesRemaining", hostname, filename);
return contract.getMaxNumTries() - contract.tries;
},

View File

@@ -496,7 +496,7 @@ export function NetscriptCorporation(
shareSaleCooldown: corporation.shareSaleCooldown,
issuedShares: corporation.issuedShares,
sharePrice: corporation.sharePrice,
state: corporation.state + "",
state: corporation.state.getState(),
};
},
};

View File

@@ -47,7 +47,7 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
return {
createGang: function (faction: string): boolean {
helper.updateDynamicRam("createGang", getRamCost("gang", "createGang"));
helper.updateDynamicRam("createGang", getRamCost(player, "gang", "createGang"));
// this list is copied from Faction/ui/Root.tsx
const GangNames = [
"Slum Snakes",
@@ -67,18 +67,18 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
return true;
},
inGang: function (): boolean {
helper.updateDynamicRam("inGang", getRamCost("gang", "inGang"));
helper.updateDynamicRam("inGang", getRamCost(player, "gang", "inGang"));
return player.inGang();
},
getMemberNames: function (): string[] {
helper.updateDynamicRam("getMemberNames", getRamCost("gang", "getMemberNames"));
helper.updateDynamicRam("getMemberNames", getRamCost(player, "gang", "getMemberNames"));
checkGangApiAccess("getMemberNames");
const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang");
return gang.members.map((member) => member.name);
},
getGangInformation: function (): GangGenInfo {
helper.updateDynamicRam("getGangInformation", getRamCost("gang", "getGangInformation"));
helper.updateDynamicRam("getGangInformation", getRamCost(player, "gang", "getGangInformation"));
checkGangApiAccess("getGangInformation");
const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang");
@@ -98,7 +98,7 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
};
},
getOtherGangInformation: function (): GangOtherInfo {
helper.updateDynamicRam("getOtherGangInformation", getRamCost("gang", "getOtherGangInformation"));
helper.updateDynamicRam("getOtherGangInformation", getRamCost(player, "gang", "getOtherGangInformation"));
checkGangApiAccess("getOtherGangInformation");
const cpy: any = {};
for (const gang in AllGangs) {
@@ -108,7 +108,7 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
return cpy;
},
getMemberInformation: function (name: any): GangMemberInfo {
helper.updateDynamicRam("getMemberInformation", getRamCost("gang", "getMemberInformation"));
helper.updateDynamicRam("getMemberInformation", getRamCost(player, "gang", "getMemberInformation"));
checkGangApiAccess("getMemberInformation");
const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang");
@@ -161,14 +161,14 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
};
},
canRecruitMember: function (): boolean {
helper.updateDynamicRam("canRecruitMember", getRamCost("gang", "canRecruitMember"));
helper.updateDynamicRam("canRecruitMember", getRamCost(player, "gang", "canRecruitMember"));
checkGangApiAccess("canRecruitMember");
const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang");
return gang.canRecruitMember();
},
recruitMember: function (name: any): boolean {
helper.updateDynamicRam("recruitMember", getRamCost("gang", "recruitMember"));
helper.updateDynamicRam("recruitMember", getRamCost(player, "gang", "recruitMember"));
checkGangApiAccess("recruitMember");
const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang");
@@ -182,7 +182,7 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
return recruited;
},
getTaskNames: function (): string[] {
helper.updateDynamicRam("getTaskNames", getRamCost("gang", "getTaskNames"));
helper.updateDynamicRam("getTaskNames", getRamCost(player, "gang", "getTaskNames"));
checkGangApiAccess("getTaskNames");
const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang");
@@ -191,7 +191,7 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
return tasks;
},
setMemberTask: function (memberName: any, taskName: any): boolean {
helper.updateDynamicRam("setMemberTask", getRamCost("gang", "setMemberTask"));
helper.updateDynamicRam("setMemberTask", getRamCost(player, "gang", "setMemberTask"));
checkGangApiAccess("setMemberTask");
const member = getGangMember("setMemberTask", memberName);
const success = member.assignToTask(taskName);
@@ -210,7 +210,7 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
return success;
},
getTaskStats: function (taskName: any): GangTaskStats {
helper.updateDynamicRam("getTaskStats", getRamCost("gang", "getTaskStats"));
helper.updateDynamicRam("getTaskStats", getRamCost(player, "gang", "getTaskStats"));
checkGangApiAccess("getTaskStats");
const task = getGangTask("getTaskStats", taskName);
const copy = Object.assign({}, task);
@@ -218,12 +218,12 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
return copy;
},
getEquipmentNames: function (): string[] {
helper.updateDynamicRam("getEquipmentNames", getRamCost("gang", "getEquipmentNames"));
helper.updateDynamicRam("getEquipmentNames", getRamCost(player, "gang", "getEquipmentNames"));
checkGangApiAccess("getEquipmentNames");
return Object.keys(GangMemberUpgrades);
},
getEquipmentCost: function (equipName: any): number {
helper.updateDynamicRam("getEquipmentCost", getRamCost("gang", "getEquipmentCost"));
helper.updateDynamicRam("getEquipmentCost", getRamCost(player, "gang", "getEquipmentCost"));
checkGangApiAccess("getEquipmentCost");
const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang");
@@ -232,14 +232,14 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
return gang.getUpgradeCost(upg);
},
getEquipmentType: function (equipName: any): string {
helper.updateDynamicRam("getEquipmentType", getRamCost("gang", "getEquipmentType"));
helper.updateDynamicRam("getEquipmentType", getRamCost(player, "gang", "getEquipmentType"));
checkGangApiAccess("getEquipmentType");
const upg = GangMemberUpgrades[equipName];
if (upg == null) return "";
return upg.getType();
},
getEquipmentStats: function (equipName: any): EquipmentStats {
helper.updateDynamicRam("getEquipmentStats", getRamCost("gang", "getEquipmentStats"));
helper.updateDynamicRam("getEquipmentStats", getRamCost(player, "gang", "getEquipmentStats"));
checkGangApiAccess("getEquipmentStats");
const equipment = GangMemberUpgrades[equipName];
if (!equipment) {
@@ -249,7 +249,7 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
return Object.assign({}, typecheck) as any;
},
purchaseEquipment: function (memberName: any, equipName: any): boolean {
helper.updateDynamicRam("purchaseEquipment", getRamCost("gang", "purchaseEquipment"));
helper.updateDynamicRam("purchaseEquipment", getRamCost(player, "gang", "purchaseEquipment"));
checkGangApiAccess("purchaseEquipment");
const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang");
@@ -269,7 +269,7 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
return res;
},
ascendMember: function (name: any): GangMemberAscension | undefined {
helper.updateDynamicRam("ascendMember", getRamCost("gang", "ascendMember"));
helper.updateDynamicRam("ascendMember", getRamCost(player, "gang", "ascendMember"));
checkGangApiAccess("ascendMember");
const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang");
@@ -278,7 +278,7 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
return gang.ascendMember(member, workerScript);
},
getAscensionResult: function (name: any): GangMemberAscension | undefined {
helper.updateDynamicRam("getAscensionResult", getRamCost("gang", "getAscensionResult"));
helper.updateDynamicRam("getAscensionResult", getRamCost(player, "gang", "getAscensionResult"));
checkGangApiAccess("getAscensionResult");
const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang");
@@ -290,7 +290,7 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
};
},
setTerritoryWarfare: function (engage: any): void {
helper.updateDynamicRam("setTerritoryWarfare", getRamCost("gang", "setTerritoryWarfare"));
helper.updateDynamicRam("setTerritoryWarfare", getRamCost(player, "gang", "setTerritoryWarfare"));
checkGangApiAccess("setTerritoryWarfare");
const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang");
@@ -303,7 +303,7 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
}
},
getChanceToWinClash: function (otherGang: any): number {
helper.updateDynamicRam("getChanceToWinClash", getRamCost("gang", "getChanceToWinClash"));
helper.updateDynamicRam("getChanceToWinClash", getRamCost(player, "gang", "getChanceToWinClash"));
checkGangApiAccess("getChanceToWinClash");
const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang");
@@ -317,7 +317,7 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
return playerPower / (otherPower + playerPower);
},
getBonusTime: function (): number {
helper.updateDynamicRam("getBonusTime", getRamCost("gang", "getBonusTime"));
helper.updateDynamicRam("getBonusTime", getRamCost(player, "gang", "getBonusTime"));
checkGangApiAccess("getBonusTime");
const gang = player.gang;
if (gang === null) throw new Error("Should not be called without Gang");

View File

@@ -85,15 +85,14 @@ export function NetscriptSingularity(
}
const runningScriptObj = new RunningScript(script, []); // No args
runningScriptObj.threads = 1; // Only 1 thread
startWorkerScript(runningScriptObj, home);
startWorkerScript(player, runningScriptObj, home);
}
}
}
};
return {
getOwnedAugmentations: function (purchased: any = false): any {
helper.updateDynamicRam("getOwnedAugmentations", getRamCost("getOwnedAugmentations"));
helper.checkSingularityAccess("getOwnedAugmentations", 3);
helper.updateDynamicRam("getOwnedAugmentations", getRamCost(player, "getOwnedAugmentations"));
const res = [];
for (let i = 0; i < player.augmentations.length; ++i) {
res.push(player.augmentations[i].name);
@@ -106,8 +105,7 @@ export function NetscriptSingularity(
return res;
},
getAugmentationsFromFaction: function (facname: any): any {
helper.updateDynamicRam("getAugmentationsFromFaction", getRamCost("getAugmentationsFromFaction"));
helper.checkSingularityAccess("getAugmentationsFromFaction", 3);
helper.updateDynamicRam("getAugmentationsFromFaction", getRamCost(player, "getAugmentationsFromFaction"));
const faction = getFaction("getAugmentationsFromFaction", facname);
// If player has a gang with this faction, return all augmentations.
@@ -128,38 +126,32 @@ export function NetscriptSingularity(
return faction.augmentations.slice();
},
getAugmentationCost: function (name: any): any {
helper.updateDynamicRam("getAugmentationCost", getRamCost("getAugmentationCost"));
helper.checkSingularityAccess("getAugmentationCost", 3);
helper.updateDynamicRam("getAugmentationCost", getRamCost(player, "getAugmentationCost"));
const aug = getAugmentation("getAugmentationCost", name);
return [aug.baseRepRequirement, aug.baseCost];
},
getAugmentationPrereq: function (name: any): any {
helper.updateDynamicRam("getAugmentationPrereq", getRamCost("getAugmentationPrereq"));
helper.checkSingularityAccess("getAugmentationPrereq", 3);
helper.updateDynamicRam("getAugmentationPrereq", getRamCost(player, "getAugmentationPrereq"));
const aug = getAugmentation("getAugmentationPrereq", name);
return aug.prereqs.slice();
},
getAugmentationPrice: function (name: any): any {
helper.updateDynamicRam("getAugmentationPrice", getRamCost("getAugmentationPrice"));
helper.checkSingularityAccess("getAugmentationPrice", 3);
helper.updateDynamicRam("getAugmentationPrice", getRamCost(player, "getAugmentationPrice"));
const aug = getAugmentation("getAugmentationPrice", name);
return aug.baseCost;
},
getAugmentationRepReq: function (name: any): any {
helper.updateDynamicRam("getAugmentationRepReq", getRamCost("getAugmentationRepReq"));
helper.checkSingularityAccess("getAugmentationRepReq", 3);
helper.updateDynamicRam("getAugmentationRepReq", getRamCost(player, "getAugmentationRepReq"));
const aug = getAugmentation("getAugmentationRepReq", name);
return aug.baseRepRequirement;
},
getAugmentationStats: function (name: any): any {
helper.updateDynamicRam("getAugmentationStats", getRamCost("getAugmentationStats"));
helper.checkSingularityAccess("getAugmentationStats", 3);
helper.updateDynamicRam("getAugmentationStats", getRamCost(player, "getAugmentationStats"));
const aug = getAugmentation("getAugmentationStats", name);
return Object.assign({}, aug.mults);
},
purchaseAugmentation: function (faction: any, name: any): any {
helper.updateDynamicRam("purchaseAugmentation", getRamCost("purchaseAugmentation"));
helper.checkSingularityAccess("purchaseAugmentation", 3);
helper.updateDynamicRam("purchaseAugmentation", getRamCost(player, "purchaseAugmentation"));
const fac = getFaction("purchaseAugmentation", faction);
const aug = getAugmentation("purchaseAugmentation", name);
@@ -214,8 +206,7 @@ export function NetscriptSingularity(
}
},
softReset: function (cbScript: any): any {
helper.updateDynamicRam("softReset", getRamCost("softReset"));
helper.checkSingularityAccess("softReset", 3);
helper.updateDynamicRam("softReset", getRamCost(player, "softReset"));
workerScript.log("softReset", () => "Soft resetting. This will cause this script to be killed");
setTimeout(() => {
@@ -228,8 +219,7 @@ export function NetscriptSingularity(
killWorkerScript(workerScript);
},
installAugmentations: function (cbScript: any): any {
helper.updateDynamicRam("installAugmentations", getRamCost("installAugmentations"));
helper.checkSingularityAccess("installAugmentations", 3);
helper.updateDynamicRam("installAugmentations", getRamCost(player, "installAugmentations"));
if (player.queuedAugmentations.length === 0) {
workerScript.log("installAugmentations", () => "You do not have any Augmentations to be installed.");
@@ -250,8 +240,7 @@ export function NetscriptSingularity(
},
goToLocation: function (locationName: any): boolean {
helper.updateDynamicRam("goToLocation", getRamCost("goToLocation"));
helper.checkSingularityAccess("goToLocation", 1);
helper.updateDynamicRam("goToLocation", getRamCost(player, "goToLocation"));
const location = Object.values(Locations).find((l) => l.name === locationName);
if (!location) {
workerScript.log("goToLocation", () => `No location named ${locationName}`);
@@ -266,8 +255,7 @@ export function NetscriptSingularity(
return true;
},
universityCourse: function (universityName: any, className: any): any {
helper.updateDynamicRam("universityCourse", getRamCost("universityCourse"));
helper.checkSingularityAccess("universityCourse", 1);
helper.updateDynamicRam("universityCourse", getRamCost(player, "universityCourse"));
if (player.isWorking) {
const txt = player.singularityStopWork();
workerScript.log("universityCourse", () => txt);
@@ -346,8 +334,7 @@ export function NetscriptSingularity(
},
gymWorkout: function (gymName: any, stat: any): any {
helper.updateDynamicRam("gymWorkout", getRamCost("gymWorkout"));
helper.checkSingularityAccess("gymWorkout", 1);
helper.updateDynamicRam("gymWorkout", getRamCost(player, "gymWorkout"));
if (player.isWorking) {
const txt = player.singularityStopWork();
workerScript.log("gymWorkout", () => txt);
@@ -445,8 +432,7 @@ export function NetscriptSingularity(
},
travelToCity: function (cityname: any): any {
helper.updateDynamicRam("travelToCity", getRamCost("travelToCity"));
helper.checkSingularityAccess("travelToCity", 1);
helper.updateDynamicRam("travelToCity", getRamCost(player, "travelToCity"));
switch (cityname) {
case CityName.Aevum:
@@ -470,8 +456,7 @@ export function NetscriptSingularity(
},
purchaseTor: function (): any {
helper.updateDynamicRam("purchaseTor", getRamCost("purchaseTor"));
helper.checkSingularityAccess("purchaseTor", 1);
helper.updateDynamicRam("purchaseTor", getRamCost(player, "purchaseTor"));
if (player.hasTorRouter()) {
workerScript.log("purchaseTor", () => "You already have a TOR router!");
@@ -502,8 +487,7 @@ export function NetscriptSingularity(
return true;
},
purchaseProgram: function (programName: any): any {
helper.updateDynamicRam("purchaseProgram", getRamCost("purchaseProgram"));
helper.checkSingularityAccess("purchaseProgram", 1);
helper.updateDynamicRam("purchaseProgram", getRamCost(player, "purchaseProgram"));
if (!player.hasTorRouter()) {
workerScript.log("purchaseProgram", () => "You do not have the TOR router.");
@@ -541,13 +525,11 @@ export function NetscriptSingularity(
return true;
},
getCurrentServer: function (): any {
helper.updateDynamicRam("getCurrentServer", getRamCost("getCurrentServer"));
helper.checkSingularityAccess("getCurrentServer", 1);
helper.updateDynamicRam("getCurrentServer", getRamCost(player, "getCurrentServer"));
return player.getCurrentServer().hostname;
},
connect: function (hostname: any): any {
helper.updateDynamicRam("connect", getRamCost("connect"));
helper.checkSingularityAccess("connect", 1);
helper.updateDynamicRam("connect", getRamCost(player, "connect"));
if (!hostname) {
throw helper.makeRuntimeErrorMsg("connect", `Invalid hostname: '${hostname}'`);
}
@@ -581,14 +563,12 @@ export function NetscriptSingularity(
return false;
},
manualHack: function (): any {
helper.updateDynamicRam("manualHack", getRamCost("manualHack"));
helper.checkSingularityAccess("manualHack", 1);
helper.updateDynamicRam("manualHack", getRamCost(player, "manualHack"));
const server = player.getCurrentServer();
return helper.hack(server.hostname, true);
},
installBackdoor: function (): any {
helper.updateDynamicRam("installBackdoor", getRamCost("installBackdoor"));
helper.checkSingularityAccess("installBackdoor", 1);
helper.updateDynamicRam("installBackdoor", getRamCost(player, "installBackdoor"));
const baseserver = player.getCurrentServer();
if (!(baseserver instanceof Server)) {
workerScript.log("installBackdoor", () => "cannot backdoor this kind of server");
@@ -623,14 +603,12 @@ export function NetscriptSingularity(
});
},
isFocused: function (): boolean {
helper.updateDynamicRam("isFocused", getRamCost("isFocused"));
helper.checkSingularityAccess("isFocused", 2);
helper.updateDynamicRam("isFocused", getRamCost(player, "isFocused"));
return player.focus;
},
setFocus: function (afocus: any): boolean {
const focus = helper.boolean(afocus);
helper.updateDynamicRam("setFocus", getRamCost("setFocus"));
helper.checkSingularityAccess("setFocus", 2);
helper.updateDynamicRam("setFocus", getRamCost(player, "setFocus"));
if (!player.isWorking) {
throw helper.makeRuntimeErrorMsg("setFocus", "Not currently working");
}
@@ -655,8 +633,7 @@ export function NetscriptSingularity(
return false;
},
getStats: function (): any {
helper.updateDynamicRam("getStats", getRamCost("getStats"));
helper.checkSingularityAccess("getStats", 1);
helper.updateDynamicRam("getStats", getRamCost(player, "getStats"));
workerScript.log("getStats", () => `getStats is deprecated, please use getplayer`);
return {
@@ -670,8 +647,7 @@ export function NetscriptSingularity(
};
},
getCharacterInformation: function (): any {
helper.updateDynamicRam("getCharacterInformation", getRamCost("getCharacterInformation"));
helper.checkSingularityAccess("getCharacterInformation", 1);
helper.updateDynamicRam("getCharacterInformation", getRamCost(player, "getCharacterInformation"));
workerScript.log("getCharacterInformation", () => `getCharacterInformation is deprecated, please use getplayer`);
return {
@@ -718,8 +694,7 @@ export function NetscriptSingularity(
};
},
hospitalize: function (): any {
helper.updateDynamicRam("hospitalize", getRamCost("hospitalize"));
helper.checkSingularityAccess("hospitalize", 1);
helper.updateDynamicRam("hospitalize", getRamCost(player, "hospitalize"));
if (player.isWorking || Router.page() === Page.Infiltration || Router.page() === Page.BitVerse) {
workerScript.log("hospitalize", () => "Cannot go to the hospital because the player is busy.");
return;
@@ -727,13 +702,11 @@ export function NetscriptSingularity(
return player.hospitalize();
},
isBusy: function (): any {
helper.updateDynamicRam("isBusy", getRamCost("isBusy"));
helper.checkSingularityAccess("isBusy", 1);
helper.updateDynamicRam("isBusy", getRamCost(player, "isBusy"));
return player.isWorking || Router.page() === Page.Infiltration || Router.page() === Page.BitVerse;
},
stopAction: function (): any {
helper.updateDynamicRam("stopAction", getRamCost("stopAction"));
helper.checkSingularityAccess("stopAction", 1);
helper.updateDynamicRam("stopAction", getRamCost(player, "stopAction"));
if (player.isWorking) {
if (player.focus) {
Router.toTerminal();
@@ -745,8 +718,7 @@ export function NetscriptSingularity(
return false;
},
upgradeHomeCores: function (): any {
helper.updateDynamicRam("upgradeHomeCores", getRamCost("upgradeHomeCores"));
helper.checkSingularityAccess("upgradeHomeCores", 2);
helper.updateDynamicRam("upgradeHomeCores", getRamCost(player, "upgradeHomeCores"));
// Check if we're at max cores
const homeComputer = player.getHomeComputer();
@@ -775,14 +747,12 @@ export function NetscriptSingularity(
return true;
},
getUpgradeHomeCoresCost: function (): any {
helper.updateDynamicRam("getUpgradeHomeCoresCost", getRamCost("getUpgradeHomeCoresCost"));
helper.checkSingularityAccess("getUpgradeHomeCoresCost", 2);
helper.updateDynamicRam("getUpgradeHomeCoresCost", getRamCost(player, "getUpgradeHomeCoresCost"));
return player.getUpgradeHomeCoresCost();
},
upgradeHomeRam: function (): any {
helper.updateDynamicRam("upgradeHomeRam", getRamCost("upgradeHomeRam"));
helper.checkSingularityAccess("upgradeHomeRam", 2);
helper.updateDynamicRam("upgradeHomeRam", getRamCost(player, "upgradeHomeRam"));
// Check if we're at max RAM
const homeComputer = player.getHomeComputer();
@@ -814,14 +784,12 @@ export function NetscriptSingularity(
return true;
},
getUpgradeHomeRamCost: function (): any {
helper.updateDynamicRam("getUpgradeHomeRamCost", getRamCost("getUpgradeHomeRamCost"));
helper.checkSingularityAccess("getUpgradeHomeRamCost", 2);
helper.updateDynamicRam("getUpgradeHomeRamCost", getRamCost(player, "getUpgradeHomeRamCost"));
return player.getUpgradeHomeRamCost();
},
workForCompany: function (companyName: any): any {
helper.updateDynamicRam("workForCompany", getRamCost("workForCompany"));
helper.checkSingularityAccess("workForCompany", 2);
workForCompany: function (companyName: any, focus = true): any {
helper.updateDynamicRam("workForCompany", getRamCost(player, "workForCompany"));
// Sanitize input
if (companyName == null) {
@@ -848,7 +816,6 @@ export function NetscriptSingularity(
return false;
}
const wasWorking = player.isWorking;
const wasFocused = player.focus;
if (player.isWorking) {
const txt = player.singularityStopWork();
@@ -861,8 +828,13 @@ export function NetscriptSingularity(
player.startWork(companyName);
}
if (!wasWorking || (wasWorking && !wasFocused)) player.stopFocusing();
else if (wasWorking && wasFocused) player.startFocusing();
if (focus) {
player.startFocusing();
Router.toWork();
} else if (wasFocused) {
player.stopFocusing();
Router.toTerminal();
}
workerScript.log(
"workForCompany",
() => `Began working at '${player.companyName}' as a '${companyPositionName}'`,
@@ -870,8 +842,7 @@ export function NetscriptSingularity(
return true;
},
applyToCompany: function (companyName: any, field: any): any {
helper.updateDynamicRam("applyToCompany", getRamCost("applyToCompany"));
helper.checkSingularityAccess("applyToCompany", 2);
helper.updateDynamicRam("applyToCompany", getRamCost(player, "applyToCompany"));
getCompany("applyToCompany", companyName);
player.location = companyName;
@@ -940,32 +911,27 @@ export function NetscriptSingularity(
return res;
},
getCompanyRep: function (companyName: any): any {
helper.updateDynamicRam("getCompanyRep", getRamCost("getCompanyRep"));
helper.checkSingularityAccess("getCompanyRep", 2);
helper.updateDynamicRam("getCompanyRep", getRamCost(player, "getCompanyRep"));
const company = getCompany("getCompanyRep", companyName);
return company.playerReputation;
},
getCompanyFavor: function (companyName: any): any {
helper.updateDynamicRam("getCompanyFavor", getRamCost("getCompanyFavor"));
helper.checkSingularityAccess("getCompanyFavor", 2);
helper.updateDynamicRam("getCompanyFavor", getRamCost(player, "getCompanyFavor"));
const company = getCompany("getCompanyFavor", companyName);
return company.favor;
},
getCompanyFavorGain: function (companyName: any): any {
helper.updateDynamicRam("getCompanyFavorGain", getRamCost("getCompanyFavorGain"));
helper.checkSingularityAccess("getCompanyFavorGain", 2);
helper.updateDynamicRam("getCompanyFavorGain", getRamCost(player, "getCompanyFavorGain"));
const company = getCompany("getCompanyFavorGain", companyName);
return company.getFavorGain();
},
checkFactionInvitations: function (): any {
helper.updateDynamicRam("checkFactionInvitations", getRamCost("checkFactionInvitations"));
helper.checkSingularityAccess("checkFactionInvitations", 2);
helper.updateDynamicRam("checkFactionInvitations", getRamCost(player, "checkFactionInvitations"));
// Make a copy of player.factionInvitations
return player.factionInvitations.slice();
},
joinFaction: function (name: any): any {
helper.updateDynamicRam("joinFaction", getRamCost("joinFaction"));
helper.checkSingularityAccess("joinFaction", 2);
helper.updateDynamicRam("joinFaction", getRamCost(player, "joinFaction"));
getFaction("joinFaction", name);
if (!player.factionInvitations.includes(name)) {
@@ -986,9 +952,8 @@ export function NetscriptSingularity(
workerScript.log("joinFaction", () => `Joined the '${name}' faction.`);
return true;
},
workForFaction: function (name: any, type: any): any {
helper.updateDynamicRam("workForFaction", getRamCost("workForFaction"));
helper.checkSingularityAccess("workForFaction", 2);
workForFaction: function (name: any, type: any, focus = true): any {
helper.updateDynamicRam("workForFaction", getRamCost(player, "workForFaction"));
getFaction("workForFaction", name);
// if the player is in a gang and the target faction is any of the gang faction, fail
@@ -1002,8 +967,7 @@ export function NetscriptSingularity(
return false;
}
const wasWorking = player.isWorking;
const wasFocused = player.focus;
const wasFocusing = player.focus;
if (player.isWorking) {
const txt = player.singularityStopWork();
workerScript.log("workForFaction", () => txt);
@@ -1102,8 +1066,13 @@ export function NetscriptSingularity(
return false;
}
player.startFactionHackWork(fac);
if (!wasWorking || (wasWorking && !wasFocused)) player.stopFocusing();
else if (wasWorking && wasFocused) player.startFocusing();
if (focus) {
player.startFocusing();
Router.toWork();
} else if (wasFocusing) {
player.stopFocusing();
Router.toTerminal();
}
workerScript.log("workForFaction", () => `Started carrying out hacking contracts for '${fac.name}'`);
return true;
case "field":
@@ -1114,8 +1083,13 @@ export function NetscriptSingularity(
return false;
}
player.startFactionFieldWork(fac);
if (!wasWorking || (wasWorking && !wasFocused)) player.stopFocusing();
else if (wasWorking && wasFocused) player.startFocusing();
if (focus) {
player.startFocusing();
Router.toWork();
} else if (wasFocusing) {
player.stopFocusing();
Router.toTerminal();
}
workerScript.log("workForFaction", () => `Started carrying out field missions for '${fac.name}'`);
return true;
case "security":
@@ -1126,8 +1100,13 @@ export function NetscriptSingularity(
return false;
}
player.startFactionSecurityWork(fac);
if (!wasWorking || (wasWorking && !wasFocused)) player.stopFocusing();
else if (wasWorking && wasFocused) player.startFocusing();
if (focus) {
player.startFocusing();
Router.toWork();
} else if (wasFocusing) {
player.stopFocusing();
Router.toTerminal();
}
workerScript.log("workForFaction", () => `Started carrying out security work for '${fac.name}'`);
return true;
default:
@@ -1136,26 +1115,22 @@ export function NetscriptSingularity(
return true;
},
getFactionRep: function (name: any): any {
helper.updateDynamicRam("getFactionRep", getRamCost("getFactionRep"));
helper.checkSingularityAccess("getFactionRep", 2);
helper.updateDynamicRam("getFactionRep", getRamCost(player, "getFactionRep"));
const faction = getFaction("getFactionRep", name);
return faction.playerReputation;
},
getFactionFavor: function (name: any): any {
helper.updateDynamicRam("getFactionFavor", getRamCost("getFactionFavor"));
helper.checkSingularityAccess("getFactionFavor", 2);
helper.updateDynamicRam("getFactionFavor", getRamCost(player, "getFactionFavor"));
const faction = getFaction("getFactionFavor", name);
return faction.favor;
},
getFactionFavorGain: function (name: any): any {
helper.updateDynamicRam("getFactionFavorGain", getRamCost("getFactionFavorGain"));
helper.checkSingularityAccess("getFactionFavorGain", 2);
helper.updateDynamicRam("getFactionFavorGain", getRamCost(player, "getFactionFavorGain"));
const faction = getFaction("getFactionFavorGain", name);
return faction.getFavorGain();
},
donateToFaction: function (name: any, amt: any): any {
helper.updateDynamicRam("donateToFaction", getRamCost("donateToFaction"));
helper.checkSingularityAccess("donateToFaction", 3);
helper.updateDynamicRam("donateToFaction", getRamCost(player, "donateToFaction"));
const faction = getFaction("donateToFaction", name);
if (typeof amt !== "number" || amt <= 0) {
@@ -1191,8 +1166,7 @@ export function NetscriptSingularity(
return true;
},
createProgram: function (name: any): any {
helper.updateDynamicRam("createProgram", getRamCost("createProgram"));
helper.checkSingularityAccess("createProgram", 3);
helper.updateDynamicRam("createProgram", getRamCost(player, "createProgram"));
if (player.isWorking) {
const txt = player.singularityStopWork();
@@ -1232,8 +1206,7 @@ export function NetscriptSingularity(
return true;
},
commitCrime: function (crimeRoughName: any): any {
helper.updateDynamicRam("commitCrime", getRamCost("commitCrime"));
helper.checkSingularityAccess("commitCrime", 3);
helper.updateDynamicRam("commitCrime", getRamCost(player, "commitCrime"));
if (player.isWorking) {
const txt = player.singularityStopWork();
@@ -1252,8 +1225,7 @@ export function NetscriptSingularity(
return crime.commit(Router, player, 1, workerScript);
},
getCrimeChance: function (crimeRoughName: any): any {
helper.updateDynamicRam("getCrimeChance", getRamCost("getCrimeChance"));
helper.checkSingularityAccess("getCrimeChance", 3);
helper.updateDynamicRam("getCrimeChance", getRamCost(player, "getCrimeChance"));
const crime = findCrime(crimeRoughName.toLowerCase());
if (crime == null) {
@@ -1263,8 +1235,7 @@ export function NetscriptSingularity(
return crime.successRate(player);
},
getCrimeStats: function (crimeRoughName: any): any {
helper.updateDynamicRam("getCrimeStats", getRamCost("getCrimeStats"));
helper.checkSingularityAccess("getCrimeStats", 3);
helper.updateDynamicRam("getCrimeStats", getRamCost(player, "getCrimeStats"));
const crime = findCrime(crimeRoughName.toLowerCase());
if (crime == null) {

View File

@@ -32,20 +32,20 @@ export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, hel
return {
getNumSleeves: function (): number {
helper.updateDynamicRam("getNumSleeves", getRamCost("sleeve", "getNumSleeves"));
helper.updateDynamicRam("getNumSleeves", getRamCost(player, "sleeve", "getNumSleeves"));
checkSleeveAPIAccess("getNumSleeves");
return player.sleeves.length;
},
setToShockRecovery: function (asleeveNumber: any = 0): boolean {
const sleeveNumber = helper.number("setToShockRecovery", "sleeveNumber", asleeveNumber);
helper.updateDynamicRam("setToShockRecovery", getRamCost("sleeve", "setToShockRecovery"));
helper.updateDynamicRam("setToShockRecovery", getRamCost(player, "sleeve", "setToShockRecovery"));
checkSleeveAPIAccess("setToShockRecovery");
checkSleeveNumber("setToShockRecovery", sleeveNumber);
return player.sleeves[sleeveNumber].shockRecovery(player);
},
setToSynchronize: function (asleeveNumber: any = 0): boolean {
const sleeveNumber = helper.number("setToSynchronize", "sleeveNumber", asleeveNumber);
helper.updateDynamicRam("setToSynchronize", getRamCost("sleeve", "setToSynchronize"));
helper.updateDynamicRam("setToSynchronize", getRamCost(player, "sleeve", "setToSynchronize"));
checkSleeveAPIAccess("setToSynchronize");
checkSleeveNumber("setToSynchronize", sleeveNumber);
return player.sleeves[sleeveNumber].synchronize(player);
@@ -53,7 +53,7 @@ export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, hel
setToCommitCrime: function (asleeveNumber: any = 0, aCrimeRoughName: any = ""): boolean {
const sleeveNumber = helper.number("setToCommitCrime", "sleeveNumber", asleeveNumber);
const crimeRoughName = helper.string("setToCommitCrime", "crimeName", aCrimeRoughName);
helper.updateDynamicRam("setToCommitCrime", getRamCost("sleeve", "setToCommitCrime"));
helper.updateDynamicRam("setToCommitCrime", getRamCost(player, "sleeve", "setToCommitCrime"));
checkSleeveAPIAccess("setToCommitCrime");
checkSleeveNumber("setToCommitCrime", sleeveNumber);
const crime = findCrime(crimeRoughName);
@@ -66,7 +66,7 @@ export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, hel
const sleeveNumber = helper.number("setToUniversityCourse", "sleeveNumber", asleeveNumber);
const universityName = helper.string("setToUniversityCourse", "universityName", auniversityName);
const className = helper.string("setToUniversityCourse", "className", aclassName);
helper.updateDynamicRam("setToUniversityCourse", getRamCost("sleeve", "setToUniversityCourse"));
helper.updateDynamicRam("setToUniversityCourse", getRamCost(player, "sleeve", "setToUniversityCourse"));
checkSleeveAPIAccess("setToUniversityCourse");
checkSleeveNumber("setToUniversityCourse", sleeveNumber);
return player.sleeves[sleeveNumber].takeUniversityCourse(player, universityName, className);
@@ -74,7 +74,7 @@ export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, hel
travel: function (asleeveNumber: any = 0, acityName: any = ""): boolean {
const sleeveNumber = helper.number("travel", "sleeveNumber", asleeveNumber);
const cityName = helper.string("setToUniversityCourse", "cityName", acityName);
helper.updateDynamicRam("travel", getRamCost("sleeve", "travel"));
helper.updateDynamicRam("travel", getRamCost(player, "sleeve", "travel"));
checkSleeveAPIAccess("travel");
checkSleeveNumber("travel", sleeveNumber);
return player.sleeves[sleeveNumber].travel(player, cityName as CityName);
@@ -82,7 +82,7 @@ export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, hel
setToCompanyWork: function (asleeveNumber: any = 0, acompanyName: any = ""): boolean {
const sleeveNumber = helper.number("setToCompanyWork", "sleeveNumber", asleeveNumber);
const companyName = helper.string("setToUniversityCourse", "companyName", acompanyName);
helper.updateDynamicRam("setToCompanyWork", getRamCost("sleeve", "setToCompanyWork"));
helper.updateDynamicRam("setToCompanyWork", getRamCost(player, "sleeve", "setToCompanyWork"));
checkSleeveAPIAccess("setToCompanyWork");
checkSleeveNumber("setToCompanyWork", sleeveNumber);
@@ -106,7 +106,7 @@ export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, hel
const sleeveNumber = helper.number("setToFactionWork", "sleeveNumber", asleeveNumber);
const factionName = helper.string("setToUniversityCourse", "factionName", afactionName);
const workType = helper.string("setToUniversityCourse", "workType", aworkType);
helper.updateDynamicRam("setToFactionWork", getRamCost("sleeve", "setToFactionWork"));
helper.updateDynamicRam("setToFactionWork", getRamCost(player, "sleeve", "setToFactionWork"));
checkSleeveAPIAccess("setToFactionWork");
checkSleeveNumber("setToFactionWork", sleeveNumber);
@@ -130,7 +130,7 @@ export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, hel
const sleeveNumber = helper.number("setToGymWorkout", "sleeveNumber", asleeveNumber);
const gymName = helper.string("setToUniversityCourse", "gymName", agymName);
const stat = helper.string("setToUniversityCourse", "stat", astat);
helper.updateDynamicRam("setToGymWorkout", getRamCost("sleeve", "setToGymWorkout"));
helper.updateDynamicRam("setToGymWorkout", getRamCost(player, "sleeve", "setToGymWorkout"));
checkSleeveAPIAccess("setToGymWorkout");
checkSleeveNumber("setToGymWorkout", sleeveNumber);
@@ -147,7 +147,7 @@ export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, hel
charisma: number;
} {
const sleeveNumber = helper.number("getSleeveStats", "sleeveNumber", asleeveNumber);
helper.updateDynamicRam("getSleeveStats", getRamCost("sleeve", "getSleeveStats"));
helper.updateDynamicRam("getSleeveStats", getRamCost(player, "sleeve", "getSleeveStats"));
checkSleeveAPIAccess("getSleeveStats");
checkSleeveNumber("getSleeveStats", sleeveNumber);
@@ -171,7 +171,7 @@ export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, hel
factionWorkType: string;
} {
const sleeveNumber = helper.number("getTask", "sleeveNumber", asleeveNumber);
helper.updateDynamicRam("getTask", getRamCost("sleeve", "getTask"));
helper.updateDynamicRam("getTask", getRamCost(player, "sleeve", "getTask"));
checkSleeveAPIAccess("getTask");
checkSleeveNumber("getTask", sleeveNumber);
@@ -186,7 +186,7 @@ export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, hel
},
getInformation: function (asleeveNumber: any = 0): any {
const sleeveNumber = helper.number("getInformation", "sleeveNumber", asleeveNumber);
helper.updateDynamicRam("getInformation", getRamCost("sleeve", "getInformation"));
helper.updateDynamicRam("getInformation", getRamCost(player, "sleeve", "getInformation"));
checkSleeveAPIAccess("getInformation");
checkSleeveNumber("getInformation", sleeveNumber);
@@ -251,7 +251,7 @@ export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, hel
},
getSleeveAugmentations: function (asleeveNumber: any = 0): string[] {
const sleeveNumber = helper.number("getSleeveAugmentations", "sleeveNumber", asleeveNumber);
helper.updateDynamicRam("getSleeveAugmentations", getRamCost("sleeve", "getSleeveAugmentations"));
helper.updateDynamicRam("getSleeveAugmentations", getRamCost(player, "sleeve", "getSleeveAugmentations"));
checkSleeveAPIAccess("getSleeveAugmentations");
checkSleeveNumber("getSleeveAugmentations", sleeveNumber);
@@ -266,7 +266,7 @@ export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, hel
cost: number;
}[] {
const sleeveNumber = helper.number("getSleevePurchasableAugs", "sleeveNumber", asleeveNumber);
helper.updateDynamicRam("getSleevePurchasableAugs", getRamCost("sleeve", "getSleevePurchasableAugs"));
helper.updateDynamicRam("getSleevePurchasableAugs", getRamCost(player, "sleeve", "getSleevePurchasableAugs"));
checkSleeveAPIAccess("getSleevePurchasableAugs");
checkSleeveNumber("getSleevePurchasableAugs", sleeveNumber);
@@ -285,7 +285,7 @@ export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, hel
purchaseSleeveAug: function (asleeveNumber: any = 0, aaugName: any = ""): boolean {
const sleeveNumber = helper.number("purchaseSleeveAug", "sleeveNumber", asleeveNumber);
const augName = helper.string("setToUniversityCourse", "augName", aaugName);
helper.updateDynamicRam("purchaseSleeveAug", getRamCost("sleeve", "purchaseSleeveAug"));
helper.updateDynamicRam("purchaseSleeveAug", getRamCost(player, "sleeve", "purchaseSleeveAug"));
checkSleeveAPIAccess("purchaseSleeveAug");
checkSleeveNumber("purchaseSleeveAug", sleeveNumber);

View File

@@ -32,7 +32,7 @@ export function NetscriptStanek(player: IPlayer, workerScript: WorkerScript, hel
const rootX = helper.number("stanek.charge", "rootX", arootX);
const rootY = helper.number("stanek.charge", "rootY", arootY);
helper.updateDynamicRam("charge", getRamCost("stanek", "charge"));
helper.updateDynamicRam("charge", getRamCost(player, "stanek", "charge"));
checkStanekAPIAccess("charge");
const fragment = staneksGift.findFragment(rootX, rootY);
if (!fragment) throw helper.makeRuntimeErrorMsg("stanek.charge", `No fragment with root (${rootX}, ${rootY}).`);
@@ -47,13 +47,13 @@ export function NetscriptStanek(player: IPlayer, workerScript: WorkerScript, hel
});
},
fragmentDefinitions: function (): IFragment[] {
helper.updateDynamicRam("fragmentDefinitions", getRamCost("stanek", "fragmentDefinitions"));
helper.updateDynamicRam("fragmentDefinitions", getRamCost(player, "stanek", "fragmentDefinitions"));
checkStanekAPIAccess("fragmentDefinitions");
workerScript.log("stanek.fragmentDefinitions", () => `Returned ${Fragments.length} fragments`);
return Fragments.map((f) => f.copy());
},
activeFragments: function (): IActiveFragment[] {
helper.updateDynamicRam("activeFragments", getRamCost("stanek", "activeFragments"));
helper.updateDynamicRam("activeFragments", getRamCost(player, "stanek", "activeFragments"));
checkStanekAPIAccess("activeFragments");
workerScript.log("stanek.activeFragments", () => `Returned ${staneksGift.fragments.length} fragments`);
return staneksGift.fragments.map((af) => {
@@ -61,7 +61,7 @@ export function NetscriptStanek(player: IPlayer, workerScript: WorkerScript, hel
});
},
clear: function (): void {
helper.updateDynamicRam("clear", getRamCost("stanek", "clear"));
helper.updateDynamicRam("clear", getRamCost(player, "stanek", "clear"));
checkStanekAPIAccess("clear");
workerScript.log("stanek.clear", () => `Cleared Stanek's Gift.`);
staneksGift.clear();
@@ -71,7 +71,7 @@ export function NetscriptStanek(player: IPlayer, workerScript: WorkerScript, hel
const rootY = helper.number("stanek.canPlace", "rootY", arootY);
const rotation = helper.number("stanek.canPlace", "rotation", arotation);
const fragmentId = helper.number("stanek.canPlace", "fragmentId", afragmentId);
helper.updateDynamicRam("canPlace", getRamCost("stanek", "canPlace"));
helper.updateDynamicRam("canPlace", getRamCost(player, "stanek", "canPlace"));
checkStanekAPIAccess("canPlace");
const fragment = FragmentById(fragmentId);
if (!fragment) throw helper.makeRuntimeErrorMsg("stanek.canPlace", `Invalid fragment id: ${fragmentId}`);
@@ -83,7 +83,7 @@ export function NetscriptStanek(player: IPlayer, workerScript: WorkerScript, hel
const rootY = helper.number("stanek.place", "rootY", arootY);
const rotation = helper.number("stanek.place", "rotation", arotation);
const fragmentId = helper.number("stanek.place", "fragmentId", afragmentId);
helper.updateDynamicRam("place", getRamCost("stanek", "place"));
helper.updateDynamicRam("place", getRamCost(player, "stanek", "place"));
checkStanekAPIAccess("place");
const fragment = FragmentById(fragmentId);
if (!fragment) throw helper.makeRuntimeErrorMsg("stanek.place", `Invalid fragment id: ${fragmentId}`);
@@ -92,7 +92,7 @@ export function NetscriptStanek(player: IPlayer, workerScript: WorkerScript, hel
get: function (arootX: any, arootY: any): IActiveFragment | undefined {
const rootX = helper.number("stanek.get", "rootX", arootX);
const rootY = helper.number("stanek.get", "rootY", arootY);
helper.updateDynamicRam("get", getRamCost("stanek", "get"));
helper.updateDynamicRam("get", getRamCost(player, "stanek", "get"));
checkStanekAPIAccess("get");
const fragment = staneksGift.findFragment(rootX, rootY);
if (fragment !== undefined) return fragment.copy();
@@ -101,7 +101,7 @@ export function NetscriptStanek(player: IPlayer, workerScript: WorkerScript, hel
remove: function (arootX: any, arootY: any): boolean {
const rootX = helper.number("stanek.remove", "rootX", arootX);
const rootY = helper.number("stanek.remove", "rootY", arootY);
helper.updateDynamicRam("remove", getRamCost("stanek", "remove"));
helper.updateDynamicRam("remove", getRamCost(player, "stanek", "remove"));
checkStanekAPIAccess("remove");
return staneksGift.delete(rootX, rootY);
},

View File

@@ -35,33 +35,33 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
};
return {
getSymbols: function (): any {
helper.updateDynamicRam("getSymbols", getRamCost("stock", "getSymbols"));
helper.updateDynamicRam("getSymbols", getRamCost(player, "stock", "getSymbols"));
checkTixApiAccess("getSymbols");
return Object.values(StockSymbols);
},
getPrice: function (symbol: any): any {
helper.updateDynamicRam("getPrice", getRamCost("stock", "getPrice"));
helper.updateDynamicRam("getPrice", getRamCost(player, "stock", "getPrice"));
checkTixApiAccess("getPrice");
const stock = getStockFromSymbol(symbol, "getPrice");
return stock.price;
},
getAskPrice: function (symbol: any): any {
helper.updateDynamicRam("getAskPrice", getRamCost("stock", "getAskPrice"));
helper.updateDynamicRam("getAskPrice", getRamCost(player, "stock", "getAskPrice"));
checkTixApiAccess("getAskPrice");
const stock = getStockFromSymbol(symbol, "getAskPrice");
return stock.getAskPrice();
},
getBidPrice: function (symbol: any): any {
helper.updateDynamicRam("getBidPrice", getRamCost("stock", "getBidPrice"));
helper.updateDynamicRam("getBidPrice", getRamCost(player, "stock", "getBidPrice"));
checkTixApiAccess("getBidPrice");
const stock = getStockFromSymbol(symbol, "getBidPrice");
return stock.getBidPrice();
},
getPosition: function (symbol: any): any {
helper.updateDynamicRam("getPosition", getRamCost("stock", "getPosition"));
helper.updateDynamicRam("getPosition", getRamCost(player, "stock", "getPosition"));
checkTixApiAccess("getPosition");
const stock = SymbolToStockMap[symbol];
if (stock == null) {
@@ -70,14 +70,14 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
return [stock.playerShares, stock.playerAvgPx, stock.playerShortShares, stock.playerAvgShortPx];
},
getMaxShares: function (symbol: any): any {
helper.updateDynamicRam("getMaxShares", getRamCost("stock", "getMaxShares"));
helper.updateDynamicRam("getMaxShares", getRamCost(player, "stock", "getMaxShares"));
checkTixApiAccess("getMaxShares");
const stock = getStockFromSymbol(symbol, "getMaxShares");
return stock.maxShares;
},
getPurchaseCost: function (symbol: any, shares: any, posType: any): any {
helper.updateDynamicRam("getPurchaseCost", getRamCost("stock", "getPurchaseCost"));
helper.updateDynamicRam("getPurchaseCost", getRamCost(player, "stock", "getPurchaseCost"));
checkTixApiAccess("getPurchaseCost");
const stock = getStockFromSymbol(symbol, "getPurchaseCost");
shares = Math.round(shares);
@@ -100,7 +100,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
return res;
},
getSaleGain: function (symbol: any, shares: any, posType: any): any {
helper.updateDynamicRam("getSaleGain", getRamCost("stock", "getSaleGain"));
helper.updateDynamicRam("getSaleGain", getRamCost(player, "stock", "getSaleGain"));
checkTixApiAccess("getSaleGain");
const stock = getStockFromSymbol(symbol, "getSaleGain");
shares = Math.round(shares);
@@ -123,14 +123,14 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
return res;
},
buy: function (symbol: any, shares: any): any {
helper.updateDynamicRam("buy", getRamCost("stock", "buy"));
helper.updateDynamicRam("buy", getRamCost(player, "stock", "buy"));
checkTixApiAccess("buy");
const stock = getStockFromSymbol(symbol, "buy");
const res = buyStock(stock, shares, workerScript, {});
return res ? stock.getAskPrice() : 0;
},
sell: function (symbol: any, shares: any): any {
helper.updateDynamicRam("sell", getRamCost("stock", "sell"));
helper.updateDynamicRam("sell", getRamCost(player, "stock", "sell"));
checkTixApiAccess("sell");
const stock = getStockFromSymbol(symbol, "sell");
const res = sellStock(stock, shares, workerScript, {});
@@ -138,7 +138,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
return res ? stock.getBidPrice() : 0;
},
short: function (symbol: any, shares: any): any {
helper.updateDynamicRam("short", getRamCost("stock", "short"));
helper.updateDynamicRam("short", getRamCost(player, "stock", "short"));
checkTixApiAccess("short");
if (player.bitNodeN !== 8) {
if (player.sourceFileLvl(8) <= 1) {
@@ -154,7 +154,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
return res ? stock.getBidPrice() : 0;
},
sellShort: function (symbol: any, shares: any): any {
helper.updateDynamicRam("sellShort", getRamCost("stock", "sellShort"));
helper.updateDynamicRam("sellShort", getRamCost(player, "stock", "sellShort"));
checkTixApiAccess("sellShort");
if (player.bitNodeN !== 8) {
if (player.sourceFileLvl(8) <= 1) {
@@ -170,7 +170,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
return res ? stock.getAskPrice() : 0;
},
placeOrder: function (symbol: any, shares: any, price: any, type: any, pos: any): any {
helper.updateDynamicRam("placeOrder", getRamCost("stock", "placeOrder"));
helper.updateDynamicRam("placeOrder", getRamCost(player, "stock", "placeOrder"));
checkTixApiAccess("placeOrder");
if (player.bitNodeN !== 8) {
if (player.sourceFileLvl(8) <= 2) {
@@ -209,7 +209,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
return placeOrder(stock, shares, price, orderType, orderPos, workerScript);
},
cancelOrder: function (symbol: any, shares: any, price: any, type: any, pos: any): any {
helper.updateDynamicRam("cancelOrder", getRamCost("stock", "cancelOrder"));
helper.updateDynamicRam("cancelOrder", getRamCost(player, "stock", "cancelOrder"));
checkTixApiAccess("cancelOrder");
if (player.bitNodeN !== 8) {
if (player.sourceFileLvl(8) <= 2) {
@@ -259,7 +259,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
return cancelOrder(params, workerScript);
},
getOrders: function (): any {
helper.updateDynamicRam("getOrders", getRamCost("stock", "getOrders"));
helper.updateDynamicRam("getOrders", getRamCost(player, "stock", "getOrders"));
checkTixApiAccess("getOrders");
if (player.bitNodeN !== 8) {
if (player.sourceFileLvl(8) <= 2) {
@@ -291,7 +291,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
return orders;
},
getVolatility: function (symbol: any): any {
helper.updateDynamicRam("getVolatility", getRamCost("stock", "getVolatility"));
helper.updateDynamicRam("getVolatility", getRamCost(player, "stock", "getVolatility"));
if (!player.has4SDataTixApi) {
throw helper.makeRuntimeErrorMsg("getVolatility", "You don't have 4S Market Data TIX API Access!");
}
@@ -300,7 +300,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
return stock.mv / 100; // Convert from percentage to decimal
},
getForecast: function (symbol: any): any {
helper.updateDynamicRam("getForecast", getRamCost("stock", "getForecast"));
helper.updateDynamicRam("getForecast", getRamCost(player, "stock", "getForecast"));
if (!player.has4SDataTixApi) {
throw helper.makeRuntimeErrorMsg("getForecast", "You don't have 4S Market Data TIX API Access!");
}
@@ -311,7 +311,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
return forecast / 100; // Convert from percentage to decimal
},
purchase4SMarketData: function () {
helper.updateDynamicRam("purchase4SMarketData", getRamCost("stock", "purchase4SMarketData"));
helper.updateDynamicRam("purchase4SMarketData", getRamCost(player, "stock", "purchase4SMarketData"));
checkTixApiAccess("purchase4SMarketData");
if (player.has4SData) {
@@ -330,7 +330,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
return true;
},
purchase4SMarketDataTixApi: function () {
helper.updateDynamicRam("purchase4SMarketDataTixApi", getRamCost("stock", "purchase4SMarketDataTixApi"));
helper.updateDynamicRam("purchase4SMarketDataTixApi", getRamCost(player, "stock", "purchase4SMarketDataTixApi"));
checkTixApiAccess("purchase4SMarketDataTixApi");
if (player.has4SDataTixApi) {

View File

@@ -0,0 +1,19 @@
import { INetscriptHelper } from "./INetscriptHelper";
import { WorkerScript } from "../Netscript/WorkerScript";
import { IPlayer } from "../PersonObjects/IPlayer";
import { getRamCost } from "../Netscript/RamCostGenerator";
import { UserInterface as IUserInterface, UserInterfaceTheme } from "../ScriptEditor/NetscriptDefinitions";
import { Settings } from "../Settings/Settings";
export function NetscriptUserInterface(
player: IPlayer,
workerScript: WorkerScript,
helper: INetscriptHelper,
): IUserInterface {
return {
getTheme: function (): UserInterfaceTheme {
helper.updateDynamicRam("getTheme", getRamCost(player, "ui", "getTheme"));
return { ...Settings.theme };
},
};
}

View File

@@ -4,6 +4,7 @@ const defaultInterpreter = new Interpreter("", () => undefined);
// the acorn interpreter has a bug where it doesn't convert arrays correctly.
// so we have to more or less copy it here.
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function toNative(pseudoObj: any): any {
if (pseudoObj == null) return null;
if (

View File

@@ -2,15 +2,18 @@ import { makeRuntimeRejectMsg } from "./NetscriptEvaluator";
import { ScriptUrl } from "./Script/ScriptUrl";
import { WorkerScript } from "./Netscript/WorkerScript";
import { Script } from "./Script/Script";
export const BlobsMap: { [key: string]: string } = {};
import { computeHash } from "./utils/helpers/computeHash";
import { BlobCache } from "./utils/BlobCache";
import { ImportCache } from "./utils/ImportCache";
import { areImportsEquals } from "./Terminal/DirectoryHelpers";
import { IPlayer } from "./PersonObjects/IPlayer";
// Makes a blob that contains the code of a given script.
function makeScriptBlob(code: string): Blob {
return new Blob([code], { type: "text/javascript" });
}
export async function compile(script: Script, scripts: Script[]): Promise<void> {
export async function compile(player: IPlayer, script: Script, scripts: Script[]): Promise<void> {
if (!shouldCompile(script, scripts)) return;
// The URL at the top is the one we want to import. It will
// recursively import all the other modules in the urlStack.
@@ -19,15 +22,24 @@ export async function compile(script: Script, scripts: Script[]): Promise<void>
// but not really behaves like import. Particularly, it cannot
// load fully dynamic content. So we hide the import from webpack
// by placing it inside an eval call.
await script.updateRamUsage(scripts);
await script.updateRamUsage(player, scripts);
const uurls = _getScriptUrls(script, scripts, []);
if (script.url) {
URL.revokeObjectURL(script.url); // remove the old reference.
delete BlobsMap[script.url];
const url = uurls[uurls.length - 1].url;
if (script.url && script.url !== url) {
// Thoughts: Should we be revoking any URLs here?
// If a script is modified repeatedly between two states,
// we could reuse the blob at a later time.
// BlobCache.removeByValue(script.url);
// URL.revokeObjectURL(script.url);
// if (script.dependencies.length > 0) {
// script.dependencies.forEach((dep) => {
// removeBlobFromCache(dep.url);
// URL.revokeObjectURL(dep.url);
// });
// }
}
if (script.dependencies.length > 0) script.dependencies.forEach((dep) => URL.revokeObjectURL(dep.url));
script.url = uurls[uurls.length - 1].url;
script.module = new Promise((resolve) => resolve(eval("import(uurls[uurls.length - 1].url)")));
script.url = url;
script.module = new Promise((resolve) => resolve(eval("import(url)")));
script.dependencies = uurls;
}
@@ -39,10 +51,14 @@ export async function compile(script: Script, scripts: Script[]): Promise<void>
// (i.e. hack, grow, etc.).
// When the promise returned by this resolves, we'll have finished
// running the main function of the script.
export async function executeJSScript(scripts: Script[] = [], workerScript: WorkerScript): Promise<void> {
export async function executeJSScript(
player: IPlayer,
scripts: Script[] = [],
workerScript: WorkerScript,
): Promise<void> {
const script = workerScript.getScript();
if (script === null) throw new Error("script is null");
await compile(script, scripts);
await compile(player, script, scripts);
workerScript.ramUsage = script.ramUsage;
const loadedModule = await script.module;
@@ -117,18 +133,27 @@ function _getScriptUrls(script: Script, scripts: Script[], seen: Script[]): Scri
let transformedCode = script.code.replace(
/((?:from|import)\s+(?:'|"))(?:\.\/)?([^'"]+)('|")/g,
(unmodified, prefix, filename, suffix) => {
const isAllowedImport = scripts.some((s) => s.filename == filename);
const isAllowedImport = scripts.some((s) => areImportsEquals(s.filename, filename));
if (!isAllowedImport) return unmodified;
// Find the corresponding script.
const [importedScript] = scripts.filter((s) => s.filename == filename);
const [importedScript] = scripts.filter((s) => areImportsEquals(s.filename, filename));
// Try to get a URL for the requested script and its dependencies.
const urls = _getScriptUrls(importedScript, scripts, seen);
// Check to see if the urls for this script are stored in the cache by the hash value.
let urls = ImportCache.get(importedScript.hash());
// If we don't have it in the cache, then we need to generate the urls for it.
if (!urls) {
// Try to get a URL for the requested script and its dependencies.
urls = _getScriptUrls(importedScript, scripts, seen);
}
// The top url in the stack is the replacement import file for this script.
urlStack.push(...urls);
return [prefix, urls[urls.length - 1].url, suffix].join("");
const blob = urls[urls.length - 1].url;
ImportCache.store(importedScript.hash(), urls);
// Replace the blob inside the import statement.
return [prefix, blob, suffix].join("");
},
);
@@ -136,11 +161,19 @@ function _getScriptUrls(script: Script, scripts: Script[], seen: Script[]): Scri
// accidental calls to window.print() do not bring up the "print screen" dialog
transformedCode += `\n\nfunction print() {throw new Error("Invalid call to window.print(). Did you mean to use Netscript's print()?");}`;
// If we successfully transformed the code, create a blob url for it and
// push that URL onto the top of the stack.
const su = new ScriptUrl(script.filename, URL.createObjectURL(makeScriptBlob(transformedCode)));
urlStack.push(su);
BlobsMap[su.url] = su.filename;
// If we successfully transformed the code, create a blob url for it
// Compute the hash for the transformed code
const transformedHash = computeHash(transformedCode);
// Check to see if this transformed hash is in our cache
let blob = BlobCache.get(transformedHash);
if (!blob) {
blob = URL.createObjectURL(makeScriptBlob(transformedCode));
}
// Store this blob in the cache. Any script that transforms the same
// (e.g. same scripts on server, same hash value, etc) can use this blob url.
BlobCache.store(transformedHash, blob);
// Push the blob URL onto the top of the stack.
urlStack.push(new ScriptUrl(script.filename, blob));
return urlStack;
} catch (err) {
// If there is an error, we need to clean up the URLs.

View File

@@ -34,6 +34,8 @@ import { parse } from "acorn";
import { simple as walksimple } from "acorn-walk";
import { areFilesEqual } from "./Terminal/DirectoryHelpers";
import { Player } from "./Player";
import { Terminal } from "./Terminal";
import { IPlayer } from "./PersonObjects/IPlayer";
// Netscript Ports are instantiated here
export const NetscriptPorts: IPort[] = [];
@@ -54,7 +56,7 @@ export function prestigeWorkerScripts(): void {
// JS script promises need a little massaging to have the same guarantees as netscript
// promises. This does said massaging and kicks the script off. It returns a promise
// that resolves or rejects when the corresponding worker script is done.
function startNetscript2Script(workerScript: WorkerScript): Promise<WorkerScript> {
function startNetscript2Script(player: IPlayer, workerScript: WorkerScript): Promise<WorkerScript> {
workerScript.running = true;
// The name of the currently running netscript function, to prevent concurrent
@@ -80,7 +82,7 @@ function startNetscript2Script(workerScript: WorkerScript): Promise<WorkerScript
if (propName === "asleep") return f(...args); // OK for multiple simultaneous calls to sleep.
const msg =
"Concurrent calls to Netscript functions not allowed! " +
"Concurrent calls to Netscript functions are not allowed! " +
"Did you forget to await hack(), grow(), or some other " +
"promise-returning function? (Currently running: %s tried to run: %s)";
if (runningFn) {
@@ -120,12 +122,13 @@ function startNetscript2Script(workerScript: WorkerScript): Promise<WorkerScript
// Note: the environment that we pass to the JS script only needs to contain the functions visible
// to that script, which env.vars does at this point.
return new Promise<WorkerScript>((resolve, reject) => {
executeJSScript(workerScript.getServer().scripts, workerScript)
executeJSScript(player, workerScript.getServer().scripts, workerScript)
.then(() => {
resolve(workerScript);
})
.catch((e) => reject(e));
}).catch((e) => {
console.log(e);
if (e instanceof Error) {
if (e instanceof SyntaxError) {
workerScript.errorMessage = makeRuntimeRejectMsg(workerScript, e.message + " (sorry we can't be more helpful)");
@@ -455,8 +458,13 @@ function processNetscript1Imports(code: string, workerScript: WorkerScript): any
* @param {Server} server - Server on which the script is to be run
* @returns {number} pid of started script
*/
export function startWorkerScript(runningScript: RunningScript, server: BaseServer, parent?: WorkerScript): number {
if (createAndAddWorkerScript(runningScript, server, parent)) {
export function startWorkerScript(
player: IPlayer,
runningScript: RunningScript,
server: BaseServer,
parent?: WorkerScript,
): number {
if (createAndAddWorkerScript(player, runningScript, server, parent)) {
// Push onto runningScripts.
// This has to come after createAndAddWorkerScript() because that fn updates RAM usage
server.runScript(runningScript);
@@ -476,7 +484,12 @@ export function startWorkerScript(runningScript: RunningScript, server: BaseServ
* @param {Server} server - Server on which the script is to be run
* returns {boolean} indicating whether or not the workerScript was successfully added
*/
function createAndAddWorkerScript(runningScriptObj: RunningScript, server: BaseServer, parent?: WorkerScript): boolean {
function createAndAddWorkerScript(
player: IPlayer,
runningScriptObj: RunningScript,
server: BaseServer,
parent?: WorkerScript,
): boolean {
// Update server's ram usage
let threads = 1;
if (runningScriptObj.threads && !isNaN(runningScriptObj.threads)) {
@@ -520,7 +533,7 @@ function createAndAddWorkerScript(runningScriptObj: RunningScript, server: BaseS
// Start the script's execution
let p: Promise<WorkerScript> | null = null; // Script's resulting promise
if (s.name.endsWith(".js") || s.name.endsWith(".ns")) {
p = startNetscript2Script(s);
p = startNetscript2Script(player, s);
} else {
p = startNetscript1Script(s);
if (!(p instanceof Promise)) {
@@ -605,9 +618,10 @@ export function updateOnlineScriptTimes(numCycles = 1): void {
* Called when the game is loaded. Loads all running scripts (from all servers)
* into worker scripts so that they will start running
*/
export function loadAllRunningScripts(): void {
export function loadAllRunningScripts(player: IPlayer): void {
const skipScriptLoad = window.location.href.toLowerCase().indexOf("?noscripts") !== -1;
if (skipScriptLoad) {
Terminal.warn("Skipped loading player scripts during startup");
console.info("Skipping the load of any scripts during startup");
}
for (const server of GetAllServers()) {
@@ -624,7 +638,7 @@ export function loadAllRunningScripts(): void {
server.runningScripts.length = 0;
} else {
for (let j = 0; j < server.runningScripts.length; ++j) {
createAndAddWorkerScript(server.runningScripts[j], server);
createAndAddWorkerScript(player, server.runningScripts[j], server);
// Offline production
scriptCalculateOfflineProduction(server.runningScripts[j]);
@@ -637,6 +651,7 @@ export function loadAllRunningScripts(): void {
* Run a script from inside another script (run(), exec(), spawn(), etc.)
*/
export function runScriptFromScript(
player: IPlayer,
caller: string,
server: BaseServer,
scriptname: string,
@@ -684,7 +699,7 @@ export function runScriptFromScript(
// Check for admin rights and that there is enough RAM availble to run
const script = server.scripts[i];
let ramUsage = script.ramUsage;
threads = Math.round(Number(threads));
threads = Math.floor(Number(threads));
if (threads === 0) {
return 0;
}
@@ -711,7 +726,7 @@ export function runScriptFromScript(
runningScriptObj.threads = threads;
runningScriptObj.server = server.hostname;
return startWorkerScript(runningScriptObj, server, workerScript);
return startWorkerScript(player, runningScriptObj, server, workerScript);
}
break;
}

View File

@@ -242,6 +242,7 @@ export interface IPlayer {
getIntelligenceBonus(weight: number): number;
getCasinoWinnings(): number;
quitJob(company: string): void;
hasJob(): boolean;
createHacknetServer(): HacknetServer;
startCreateProgramWork(router: IRouter, programName: string, time: number, reqLevel: number): void;
queueAugmentation(augmentationName: string): void;

View File

@@ -247,6 +247,7 @@ export class PlayerObject implements IPlayer {
getIntelligenceBonus: (weight: number) => number;
getCasinoWinnings: () => number;
quitJob: (company: string) => void;
hasJob: () => boolean;
process: (router: IRouter, numCycles?: number) => void;
createHacknetServer: () => HacknetServer;
startCreateProgramWork: (router: IRouter, programName: string, time: number, reqLevel: number) => void;
@@ -531,6 +532,7 @@ export class PlayerObject implements IPlayer {
this.applyForJob = generalMethods.applyForJob;
this.getNextCompanyPosition = generalMethods.getNextCompanyPosition;
this.quitJob = generalMethods.quitJob;
this.hasJob = generalMethods.hasJob;
this.applyForSoftwareJob = generalMethods.applyForSoftwareJob;
this.applyForSoftwareConsultantJob = generalMethods.applyForSoftwareConsultantJob;
this.applyForItJob = generalMethods.applyForItJob;

View File

@@ -26,7 +26,11 @@ import { Locations } from "../../Locations/Locations";
import { CityName } from "../../Locations/data/CityNames";
import { LocationName } from "../../Locations/data/LocationNames";
import { Sleeve } from "../../PersonObjects/Sleeve/Sleeve";
import { calculateSkill as calculateSkillF, calculateSkillProgress as calculateSkillProgressF, getEmptySkillProgress, ISkillProgress } from "../formulas/skill";
import {
calculateSkill as calculateSkillF,
calculateSkillProgress as calculateSkillProgressF,
ISkillProgress,
} from "../formulas/skill";
import { calculateIntelligenceBonus } from "../formulas/intelligence";
import {
getHackingWorkRepGain,
@@ -650,6 +654,8 @@ export function finishWork(this: IPlayer, cancelled: boolean, sing = false): str
this.workRepGained *= this.cancelationPenalty();
}
const penaltyString = this.cancelationPenalty() === 0.5 ? "half" : "three-quarters";
const company = Companies[this.companyName];
company.playerReputation += this.workRepGained;
@@ -661,12 +667,12 @@ export function finishWork(this: IPlayer, cancelled: boolean, sing = false): str
<Money money={this.workMoneyGained} />
<br />
<Reputation reputation={this.workRepGained} /> reputation for the company <br />
{numeralWrapper.formatExp(this.workHackExpGained)} hacking exp <br />
{numeralWrapper.formatExp(this.workStrExpGained)} strength exp <br />
{numeralWrapper.formatExp(this.workDefExpGained)} defense exp <br />
{numeralWrapper.formatExp(this.workDexExpGained)} dexterity exp <br />
{numeralWrapper.formatExp(this.workAgiExpGained)} agility exp <br />
{numeralWrapper.formatExp(this.workChaExpGained)} charisma exp
{this.workHackExpGained > 0 && <>{numeralWrapper.formatExp(this.workHackExpGained)} hacking exp <br /></>}
{this.workStrExpGained > 0 && <>{numeralWrapper.formatExp(this.workStrExpGained)} strength exp <br /></>}
{this.workDefExpGained > 0 && <>{numeralWrapper.formatExp(this.workDefExpGained)} defense exp <br /></>}
{this.workDexExpGained > 0 && <>{numeralWrapper.formatExp(this.workDexExpGained)} dexterity exp <br /></>}
{this.workAgiExpGained > 0 && <>{numeralWrapper.formatExp(this.workAgiExpGained)} agility exp <br /></>}
{this.workChaExpGained > 0 && <>{numeralWrapper.formatExp(this.workChaExpGained)} charisma exp <br /></>}
<br />
</>
);
@@ -676,7 +682,7 @@ export function finishWork(this: IPlayer, cancelled: boolean, sing = false): str
<>
You worked a short shift of {convertTimeMsToTimeElapsedString(this.timeWorked)} <br />
<br />
Since you cancelled your work early, you only gained half of the reputation you earned. <br />
Since you cancelled your work early, you only gained {penaltyString} of the reputation you earned. <br />
<br />
{content}
</>
@@ -1648,7 +1654,7 @@ export function regenerateHp(this: IPlayer, amt: number): void {
export function hospitalize(this: IPlayer): number {
const cost = getHospitalizationCost(this);
SnackbarEvents.emit(`You've been Hospitalized for ${numeralWrapper.formatMoney(cost)}`, "warning");
SnackbarEvents.emit(`You've been Hospitalized for ${numeralWrapper.formatMoney(cost)}`, "warning", 2000);
this.loseMoney(cost, "hospitalization");
this.hp = this.max_hp;
@@ -1684,6 +1690,11 @@ export function applyForJob(this: IPlayer, entryPosType: CompanyPosition, sing =
return false;
}
// Check if this company has the position
if (!company.hasPosition(pos)) {
return false;
}
while (true) {
const newPos = getNextCompanyPositionHelper(pos);
if (newPos == null) {
@@ -1782,6 +1793,15 @@ export function quitJob(this: IPlayer, company: string): void {
delete this.jobs[company];
}
/**
* Method to see if the player has at least one job assigned to them
* @param this The player instance
* @returns Whether the user has at least one job
*/
export function hasJob(this: IPlayer): boolean {
return Boolean(Object.keys(this.jobs).length);
}
export function applyForSoftwareJob(this: IPlayer, sing = false): boolean {
return this.applyForJob(CompanyPositions[posNames.SoftwareCompanyPositions[0]], sing);
}
@@ -1848,9 +1868,14 @@ export function applyForAgentJob(this: IPlayer, sing = false): boolean {
export function applyForEmployeeJob(this: IPlayer, sing = false): boolean {
const company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[1]])) {
const position = posNames.MiscCompanyPositions[1];
// Check if this company has the position
if (!company.hasPosition(position)) {
return false;
}
if (this.isQualified(company, CompanyPositions[position])) {
this.companyName = company.name;
this.jobs[company.name] = posNames.MiscCompanyPositions[1];
this.jobs[company.name] = position;
if (!sing) {
dialogBoxCreate("Congratulations, you are now employed at " + this.location);
}
@@ -1867,8 +1892,13 @@ export function applyForEmployeeJob(this: IPlayer, sing = false): boolean {
export function applyForPartTimeEmployeeJob(this: IPlayer, sing = false): boolean {
const company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[1]])) {
this.jobs[company.name] = posNames.PartTimeCompanyPositions[1];
const position = posNames.PartTimeCompanyPositions[1];
// Check if this company has the position
if (!company.hasPosition(position)) {
return false;
}
if (this.isQualified(company, CompanyPositions[position])) {
this.jobs[company.name] = position;
if (!sing) {
dialogBoxCreate("Congratulations, you are now employed part-time at " + this.location);
}
@@ -1885,9 +1915,14 @@ export function applyForPartTimeEmployeeJob(this: IPlayer, sing = false): boolea
export function applyForWaiterJob(this: IPlayer, sing = false): boolean {
const company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions[posNames.MiscCompanyPositions[0]])) {
const position = posNames.MiscCompanyPositions[0];
// Check if this company has the position
if (!company.hasPosition(position)) {
return false;
}
if (this.isQualified(company, CompanyPositions[position])) {
this.companyName = company.name;
this.jobs[company.name] = posNames.MiscCompanyPositions[0];
this.jobs[company.name] = position;
if (!sing) {
dialogBoxCreate("Congratulations, you are now employed as a waiter at " + this.location);
}
@@ -1902,9 +1937,14 @@ export function applyForWaiterJob(this: IPlayer, sing = false): boolean {
export function applyForPartTimeWaiterJob(this: IPlayer, sing = false): boolean {
const company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[0]])) {
const position = posNames.PartTimeCompanyPositions[0];
// Check if this company has the position
if (!company.hasPosition(position)) {
return false;
}
if (this.isQualified(company, CompanyPositions[position])) {
this.companyName = company.name;
this.jobs[company.name] = posNames.PartTimeCompanyPositions[0];
this.jobs[company.name] = position;
if (!sing) {
dialogBoxCreate("Congratulations, you are now employed as a part-time waiter at " + this.location);
}
@@ -2582,7 +2622,7 @@ export function canAccessResleeving(this: IPlayer): boolean {
export function giveExploit(this: IPlayer, exploit: Exploit): void {
if (!this.exploits.includes(exploit)) {
this.exploits.push(exploit);
SnackbarEvents.emit("SF -1 acquired!", "success");
SnackbarEvents.emit("SF -1 acquired!", "success", 2000);
}
}

View File

@@ -9,9 +9,25 @@ export function calculateExp(skill: number, mult = 1): number {
export function calculateSkillProgress(exp: number, mult = 1): ISkillProgress {
const currentSkill = calculateSkill(exp, mult);
const nextSkill = currentSkill + 1;
let baseExperience = calculateExp(currentSkill, mult);
if (baseExperience < 0) baseExperience = 0;
const nextExperience = calculateExp(nextSkill, mult)
let nextExperience = calculateExp(nextSkill, mult)
if (nextExperience < 0) nextExperience = 0;
const normalize = (value: number): number => ((value - baseExperience) * 100) / (nextExperience - baseExperience);
let progress = (nextExperience - baseExperience !== 0) ? normalize(exp) : 99.99;
// Clamp progress: When sleeves are working out, the player gets way too much progress
if (progress < 0) progress = 0
if (progress > 100) progress = 100;
// Clamp floating point imprecisions
let currentExperience = exp - baseExperience;
let remainingExperience = nextExperience - exp;
if (currentExperience < 0) currentExperience = 0;
if (remainingExperience < 0) remainingExperience = 0;
return {
currentSkill,
@@ -19,7 +35,9 @@ export function calculateSkillProgress(exp: number, mult = 1): ISkillProgress {
baseExperience,
experience: exp,
nextExperience,
progress: exp / nextExperience,
currentExperience,
remainingExperience,
progress
}
}
@@ -29,13 +47,16 @@ export interface ISkillProgress {
baseExperience: number;
experience: number;
nextExperience: number;
currentExperience: number;
remainingExperience: number;
progress: number;
}
export function getEmptySkillProgress() {
export function getEmptySkillProgress(): ISkillProgress {
return {
currentSkill: 0, nextSkill: 0,
baseExperience: 0, experience: 0, nextExperience: 0,
currentExperience: 0, remainingExperience: 0,
progress: 0,
};
}

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