mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-09 17:23:53 +01:00
Merge branch 'dev' into issues/1944
This commit is contained in:
commit
e0377980a5
12
.eslintrc.js
12
.eslintrc.js
@ -43,7 +43,7 @@ module.exports = {
|
||||
curly: ["off"],
|
||||
"default-case": ["off"],
|
||||
"dot-notation": ["off"],
|
||||
"eol-last": ["off"],
|
||||
"eol-last": ["error"],
|
||||
eqeqeq: ["off"],
|
||||
"for-direction": ["error"],
|
||||
"func-call-spacing": ["off"],
|
||||
@ -137,7 +137,7 @@ module.exports = {
|
||||
"no-ex-assign": ["off"],
|
||||
"no-extra-boolean-cast": ["error"],
|
||||
"no-extra-parens": ["off"],
|
||||
"no-extra-semi": ["off"],
|
||||
"no-extra-semi": ["error"],
|
||||
"no-eval": ["off"],
|
||||
"no-extend-native": ["off"],
|
||||
"no-extra-bind": ["error"],
|
||||
@ -166,12 +166,12 @@ module.exports = {
|
||||
"no-label-var": ["error"],
|
||||
"no-labels": ["off"],
|
||||
"no-lone-blocks": ["error"],
|
||||
"no-lonely-if": ["off"],
|
||||
"no-lonely-if": ["error"],
|
||||
"no-loop-func": ["off"],
|
||||
"no-magic-numbers": ["off"],
|
||||
"no-mixed-operators": ["off"],
|
||||
"no-mixed-requires": ["error"],
|
||||
"no-mixed-spaces-and-tabs": ["off"],
|
||||
"no-mixed-spaces-and-tabs": ["error"],
|
||||
"no-multi-assign": ["off"],
|
||||
"no-multi-spaces": ["off"],
|
||||
"no-multi-str": ["error"],
|
||||
@ -236,7 +236,7 @@ module.exports = {
|
||||
"no-ternary": ["off"],
|
||||
"no-this-before-super": ["off"],
|
||||
"no-throw-literal": ["error"],
|
||||
"no-trailing-spaces": ["off"],
|
||||
"no-trailing-spaces": ["error"],
|
||||
"no-undef": ["off"],
|
||||
"no-undef-init": ["error"],
|
||||
"no-undefined": ["off"],
|
||||
@ -253,7 +253,7 @@ module.exports = {
|
||||
"no-use-before-define": ["off"],
|
||||
"no-useless-call": ["off"],
|
||||
"no-useless-computed-key": ["error"],
|
||||
"no-useless-concat": ["off"],
|
||||
"no-useless-concat": ["error"],
|
||||
"no-useless-constructor": ["error"],
|
||||
"no-useless-escape": ["off"],
|
||||
"no-useless-rename": [
|
||||
|
1
CODE_OF_CONDUCT.md
Normal file
1
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1 @@
|
||||
Don't be an ass.
|
24
dist/bitburner.d.ts
vendored
24
dist/bitburner.d.ts
vendored
@ -958,6 +958,16 @@ export declare interface Corporation extends WarehouseAPI, OfficeAPI {
|
||||
* @param percent - Percent of profit to issue as dividends.
|
||||
*/
|
||||
issueDividends(percent: number): void;
|
||||
/**
|
||||
* Buyback Shares
|
||||
* @param amt - Number of shares to attempt to buyback.
|
||||
*/
|
||||
buyBackShares(amt: number): void;
|
||||
/**
|
||||
* Sell Shares
|
||||
* @param amt - Number of shares to attempt to sell.
|
||||
*/
|
||||
sellShares(amt: number): void;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3748,7 +3758,7 @@ export declare interface NS extends Singularity {
|
||||
* @remarks
|
||||
* RAM cost: 0.3 GB
|
||||
*
|
||||
* Running with no args returns curent script.
|
||||
* Running with no args returns current script.
|
||||
* If you use a PID as the first parameter, the hostname and args parameters are unnecessary.
|
||||
*
|
||||
* @param filename - Optional. Filename or PID of the script.
|
||||
@ -3905,7 +3915,7 @@ export declare interface NS extends Singularity {
|
||||
* @param data - Data to write.
|
||||
* @returns True if the data is successfully written to the port, and false otherwise.
|
||||
*/
|
||||
tryWritePort(port: number, data: string[] | number): Promise<boolean>;
|
||||
tryWritePort(port: number, data: string | number): Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Read content of a file.
|
||||
@ -4807,7 +4817,7 @@ export declare interface Server {
|
||||
/** IP Address. Must be unique */
|
||||
ip: string;
|
||||
|
||||
/** Flag indicating whether player is curently connected to this server */
|
||||
/** Flag indicating whether player is currently connected to this server */
|
||||
isConnectedTo: boolean;
|
||||
|
||||
/** RAM (GB) available on this server */
|
||||
@ -6635,6 +6645,14 @@ export declare interface WarehouseAPI {
|
||||
* @param amt - Amount of material to buy
|
||||
*/
|
||||
buyMaterial(divisionName: string, cityName: string, materialName: string, amt: number): void;
|
||||
/**
|
||||
* Set material to bulk buy
|
||||
* @param divisionName - Name of the division
|
||||
* @param cityName - Name of the city
|
||||
* @param materialName - Name of the material
|
||||
* @param amt - Amount of material to buy
|
||||
*/
|
||||
bulkPurchase(divisionName: string, cityName: string, materialName: string, amt: number): void;
|
||||
/**
|
||||
* Get warehouse data
|
||||
* @param divisionName - Name of the division
|
||||
|
89
dist/vendor.bundle.js
vendored
89
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
2
dist/vendor.bundle.js.map
vendored
2
dist/vendor.bundle.js.map
vendored
File diff suppressed because one or more lines are too long
@ -6,10 +6,8 @@ Intelligence is a :ref:`stat <gameplay_stats>` that is unlocked by having
|
||||
:ref:`Source-File 5 <gameplay_sourcefiles>` (i.e. Destroying BitNode-5).
|
||||
|
||||
Intelligence is unique because it is permanent and persistent. It never gets reset
|
||||
back to 1. However, gaining Intelligence experience is extremely slow. The methods
|
||||
of gaining Intelligence exp is also hidden. You won't know when you gain
|
||||
experience and how much. It is a stat that gradually builds up as you continue
|
||||
to play the game.
|
||||
back to 1. However, gaining Intelligence experience is extremely slow. It is a stat
|
||||
that gradually builds up as you continue to play the game.
|
||||
|
||||
Intelligence will boost your production for many actions in the game, including:
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
Augmentations
|
||||
=============
|
||||
Advances in science and medicine have lead to powerful new technologies
|
||||
Advances in science and medicine have led to powerful new technologies
|
||||
that allow people to augment themselves beyond normal human capabilities.
|
||||
There are many different types of Augmentations, ranging from cybernetic
|
||||
to genetic to biological. Acquiring these Augmentations enhances the
|
||||
|
@ -215,6 +215,7 @@ The list contains the name of (i.e. the value returned by
|
||||
| | | The answer should be provided as an array of strings containing the valid expressions. |
|
||||
| | | |
|
||||
| | | NOTE: Numbers in an expression cannot have leading 0's |
|
||||
| | | NOTE: The order of evaluation expects script operator precedence |
|
||||
| | | |
|
||||
| | | Examples: |
|
||||
| | | Input: digits = "123", target = 6 |
|
||||
|
@ -7,6 +7,16 @@ these companies, you can apply for jobs.
|
||||
|
||||
Working a job lets you earn money, experience, and reputation with that company.
|
||||
|
||||
While working for a company, you can click "Do something else simultaneously" to be able
|
||||
to do things while you continue to work in the background. There is a 20% penalty to the
|
||||
related gains. Clicking the "Focus" button under the overview will return you to the
|
||||
current work.
|
||||
|
||||
Reputation is required to apply for a promotion. This reputation is not counted towards
|
||||
your career until the shift ends, either due to the time spent or clicking the
|
||||
"Stop Working" button. For most jobs there is a penalty of 50% of the reputation gained
|
||||
if you stop your shift early.
|
||||
|
||||
Information about all Companies
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
TODO
|
||||
|
@ -107,3 +107,14 @@ starting security, rounded to the nearest integer. To be more precise::
|
||||
|
||||
This means that a server's security level will not fall below this
|
||||
value if you are trying to weaken() it.
|
||||
|
||||
Backdoors
|
||||
^^^^^^^^^
|
||||
Servers that can be hacked can also have backdoors installed. These backdoors
|
||||
will provide you with a benefit; the services may be cheaper, penalties may
|
||||
be reduced or there may be other results. Honeypots exist and will let factions
|
||||
know when you have succeeded at backdooring their system. Once you have a
|
||||
backdoor installed, you can connect to that server directly.
|
||||
|
||||
When you visit a location in the city and see that the name is partially scrambled,
|
||||
this indicates that you have backdoored the server related to the location.
|
||||
|
@ -21,23 +21,19 @@ can be used to check how much RAM a server has.
|
||||
|
||||
Identifying Servers
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
A server is identified by two properties: its IP address and its hostname.
|
||||
An IP address is a 32-bit number represented in dot-decimal notation.
|
||||
For example, "56.1.5.0" and "86.5.1.0" might be two IP addresses
|
||||
you see in the game. A hostname is a label assigned to a server.
|
||||
A server is identified by its hostname.
|
||||
A hostname is a label assigned to a server.
|
||||
A hostname will usually give you a general idea of what the server
|
||||
is. For example, the company Nova Medical might have a server with
|
||||
the hostname "nova-med".
|
||||
|
||||
Hostnames and IP addresses are unique. This means that if one
|
||||
server has the IP address "1.1.1.1" and the hostname
|
||||
"some-server", then no other server in the game can have that
|
||||
IP address or that hostname.
|
||||
Hostnames are unique. This means that if one
|
||||
server has the the hostname "some-server", then no other server
|
||||
in the game can have that that hostname.
|
||||
|
||||
There are many :ref:`Netscript Functions <netscriptfunctions>`
|
||||
and :ref:`terminal` commands in the game
|
||||
that will require you to target a specific server. This is done using
|
||||
either the IP address or the hostname of the server.
|
||||
that will require you to target a specific server by hostname.
|
||||
|
||||
Player-owned Servers
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -239,7 +239,7 @@ connect
|
||||
|
||||
$ connect [hostname/ip]
|
||||
|
||||
Connect to a remote server. The hostname or IP address of the remote server must
|
||||
Connect to a remote server. The hostname of the remote server must
|
||||
be given as the argument to this command. Note that only servers that are immediately
|
||||
adjacent to the current server in the network can be connected to. To see which
|
||||
servers can be connected to, use the 'scan' command.
|
||||
@ -544,28 +544,6 @@ Then in order to check its logs with 'tail' the same arguments must be used::
|
||||
|
||||
$ tail foo.script 10 50000
|
||||
|
||||
theme
|
||||
^^^^^
|
||||
|
||||
$ theme [preset] | [#background #text #highlight]
|
||||
|
||||
Change the color of the game's user interface
|
||||
|
||||
This command can be called with a preset theme. Currently, the supported presets are:
|
||||
|
||||
* default
|
||||
* muted
|
||||
* solarized
|
||||
|
||||
However, you can also specify your own color scheme using hex values.
|
||||
To do so, you must specify three hex color values for the background
|
||||
color, the text color, and the highlight color. These hex values must
|
||||
be preceded by a pound sign (#) and must be either 3 or 6 digits. Example::
|
||||
|
||||
$ theme #ffffff #385 #235012
|
||||
|
||||
A color picker such as Google's can be used to get your desired hex color values
|
||||
|
||||
top
|
||||
^^^
|
||||
|
||||
|
@ -3,6 +3,182 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
v1.5.0 - Steam Cloud integration
|
||||
--------------------------------
|
||||
|
||||
** Steam Cloud Saving **
|
||||
|
||||
* Added support for steam cloud saving (@MartinFournier)
|
||||
|
||||
** UI **
|
||||
|
||||
* background now matches game primary color (@nickofolas)
|
||||
* page title contains version (@MartinFourier)
|
||||
* Major text editor improvements (@nickofolas)
|
||||
* Display bonus time on sleeve page (@MartinFourier)
|
||||
* Several UI improvements (@nickofolas, @smolgumball, @DrCuriosity, @phyzical)
|
||||
* Fix aug display in alpha (@Dominik Winter)
|
||||
* Fix display of corporation product equation (@SagePtr)
|
||||
* Make Bitverse more accessible (@ChrissiQ)
|
||||
* Make corporation warehouse more accessible (@ChrissiQ)
|
||||
* Make tab style more consistent (@nikfolas)
|
||||
|
||||
** Netscript **
|
||||
|
||||
* Fix bug with async.
|
||||
* Add 'printf' ns function (@Ninetailed)
|
||||
* Remove blob caching.
|
||||
* Fix formulas access check (@Ornedan)
|
||||
* Fix bug in exp calculation (@qcorradi)
|
||||
* Fix NaN comparison (@qcorradi)
|
||||
* Fix travelToCity with bad argument (@SlyCedix)
|
||||
* Fix bug where augs could not be purchased via sing (@reacocard)
|
||||
* Fix rounding error in donateToFaction (@Risenafis)
|
||||
* Fix bug with weakenAnalyze (@rhobes)
|
||||
* Prevent exploit with atExit (@Ornedan)
|
||||
* Double 'share' power
|
||||
|
||||
** Corporations **
|
||||
|
||||
* Fix bugs with corp API (@pigalot)
|
||||
* Add smart supply func to corp API (@pd)
|
||||
|
||||
** Misc. **
|
||||
|
||||
* The file API now allows GET and DELETE (@lordducky)
|
||||
* Force achievement calculation on BN completion (@SagePtr)
|
||||
* Cleanup in repository (@MartinFourier)
|
||||
* Several improvements to the electron version (@MartinFourier)
|
||||
* Fix bug with casino roulette (@jamie-mac)
|
||||
* Terminal history persists in savefile (@MartinFourier)
|
||||
* Fix tests (@jamie-mac)
|
||||
* Fix crash with electron windows tracker (@smolgumball)
|
||||
* Fix BN6/7 passive reputation gain (@BrianLDev)
|
||||
* Fix Sleeve not resetting on install (@waffleattack)
|
||||
* Sort joined factions (@jjayeon)
|
||||
* Update documentation / typo (@lethern, @Meowdoleon, @JohnnyUrosevic, @JosephDavidTalbot,
|
||||
@pd, @lethern, @lordducky, @zeddrak, @fearnlj01, @reasonablytall, @MatthewTh0,
|
||||
@SagePtr, @manniL, @Jedimaster4559, @loganville, @Arrow2thekn33, @wdpk, @fwolfst,
|
||||
@fschoenfeldt, @Waladil, @AdamTReineke, @citrusmunch, @factubsio, @ashtongreen,
|
||||
@ChrissiQ, @DJ-Laser, @waffleattack, @ApamNapat, @CrafterKolyan, @DSteve595)
|
||||
* Nerf noodle bar.
|
||||
|
||||
v1.4.0 - 2022-01-18 Sharing is caring
|
||||
-------------------------------------
|
||||
|
||||
** Computer sharing **
|
||||
|
||||
* A new mechanic has been added, it's is invoked by calling the new function 'share'.
|
||||
This mechanic helps you farm reputation faster.
|
||||
|
||||
** gang **
|
||||
|
||||
* Installing augs means losing a little bit of ascension multipliers.
|
||||
|
||||
** Misc. **
|
||||
|
||||
* Prevent gang API from performing actions for the type of gang they are not. (@TheMas3212)
|
||||
* Fix donation to gang faction. (@TheMas3212)
|
||||
* Fix gang check crashing the game. (@TheMas3212)
|
||||
* Make time compression more robust.
|
||||
* Fix bug with scp.
|
||||
* Add zoom to steam version. (@MartinFourier)
|
||||
* Fix donateToFaction accepts donation of NaN. (@woody-lam-cwl)
|
||||
* Show correct hash capacity gain on cache level upgrade tooltip. (@woody-lam-cwl)
|
||||
* Fix tests (@woody-lam-cwl)
|
||||
* Fix cache tooltip (@woody-lam-cwl)
|
||||
* Added script to prettify save file for debugging (@MartinFourier)
|
||||
* Update documentation / typos (@theit8514, @thadguidry, @tigercat2000, @SlyCedix, @Spacejoker, @KenJohansson,
|
||||
@Ornedan, @JustAnOkapi, @nickofolas, @philarmstead, @TheMas3212, @dcragusa, @XxKingsxX-Pinu,
|
||||
@paiv, @smolgumball, @zeddrak, @stinky-lizard, @nickofolas, @Feodoric, @daanflore,
|
||||
@markusariliu, @mstruebing, @erplsf, @waffleattack, @Dexalt142, @AIT-OLPE, @deathly809, @BuckAMayzing,
|
||||
@MartinFourier, @pigalot, @lethern)
|
||||
* Fix BN3+ achievement (@SagePtr)
|
||||
* Fix reputation carry over bug (@TheMas3212)
|
||||
* Add button to exit infiltrations (@TheMas3212)
|
||||
* Add dev menu achievement check (@TheMas3212)
|
||||
* Add 'host' config for electron server (@MartinFourier)
|
||||
* Suppress save toast only works for autosave (@MartinFourier)
|
||||
* Fix some achievements not triggering with 'backdoor' (@SagePtr)
|
||||
* Update Neuroflux Governor description.
|
||||
* Fix bug with electron server.
|
||||
* Fix bug with corporation employee assignment function (@Ornedan)
|
||||
* Add detailed information to terminal 'mem' command (@MartinFourier)
|
||||
* Add savestamp to savefile (@MartinFourier)
|
||||
* Dev menu can apply export bonus (@MartinFourier)
|
||||
* Icarus message no longer applies on top of itself (@Feodoric)
|
||||
* purchase augment via API can no longer buy Neuroflux when it shouldn't (@Feodoric)
|
||||
* Syntax highlighter should be smarter (@neuralsim)
|
||||
* Fix some miscalculation when calculating money stolen (@zeddrak)
|
||||
* Fix max cache achievement working with 0 cache (@MartinFourier)
|
||||
* Add achievements in the game, not just steam (@MartinFourier)
|
||||
* Overflow hash converts to money automatically (@MartinFourier)
|
||||
* Make mathjax load locally (@MartinFourier)
|
||||
* Make favor calculation more efficient (@kittycat2002)
|
||||
* Fix some scripts crashing the game on startup (@MartinFourier)
|
||||
* Toasts will appear above tail window (@MartinFourier)
|
||||
* Fix issue that can cause terminal actions to start on one server and end on another (@MartinFourier)
|
||||
* Fix 'fileExists' not correctly matching file names (@TheMas3212)
|
||||
* Refactor some code to be more efficient (@TheMas3212)
|
||||
* Fix exp gain for terminal grow and weaken (@nickofolas)
|
||||
* Refactor script death code to reject waiting promises instead of resolving (@Ornedan)
|
||||
* HP recalculates on defense exp gain (@TheMas3212)
|
||||
* Fix log for ascendMember (@TheMas3212)
|
||||
* Netscript ports clear on reset (@TheMas3212)
|
||||
* Fix bug related to company (@TheMas3212)
|
||||
* Fix bug where corporation handbook would not be correctly added (@TheMas3212)
|
||||
* Servers in hash upgrades are sorted alpha (@MartinFourier)
|
||||
* Fix very old save not properly migrating augmentation renamed in 0.56 (@MartinFourier)
|
||||
* Add font height and line height in theme settings (@MartinFourier)
|
||||
* Fix crash when quitting job (@MartinFourier)
|
||||
* Added save file validation system (@TheMas3212)
|
||||
* React and ReactDOM are now global objects (@pigalot)
|
||||
* 'nano' supports globs (@smolgumball)
|
||||
* Character overview can be dragged (@MartinFourier)
|
||||
* Job page updates in real time (@nickofolas)
|
||||
* Company favor gain uses the same calculation as faction, this is just performance
|
||||
the value didn't change (@nickofolas)
|
||||
* ns2 files work with more import options (@theit8514)
|
||||
* Allow autocomplete for partial executables (@nickofolas)
|
||||
* Add support for contract completion (@nickofolas)
|
||||
* 'ls' link are clickable (@smolgumball)
|
||||
* Prevent steam from opening external LOCAL files (@MartinFourier)
|
||||
* Fix a bug with autocomplete (@Feodoric)
|
||||
* Optimise achievement checks (@Feodoric)
|
||||
* Hacknet server achievements grant associated hacknet node achievement (@Feodoric)
|
||||
* Fix display bug with hacknet (@Feodoric)
|
||||
* 'analyze' now says if the server is backdoored (@deathly809)
|
||||
* Add option to exclude running script from save (@MartinFourier)
|
||||
* Game now catches more errors and redirects to recovery page (@MartinFourier)
|
||||
* Fix bug with autocomplete (@nickofolas)
|
||||
* Add tooltip to unfocus work (@nickofolas)
|
||||
* Add detailst overview (@MartinFourier)
|
||||
* Fix focus bug (@deathly809)
|
||||
* Fix some NaN handling (@deathly809)
|
||||
* Added 'mv' ns function (@deathly809)
|
||||
* Add focus argument to some singularity functions (@nickofolas)
|
||||
* Fix some functions not disabling log correctly (@deathly809)
|
||||
* General UI improvements (@nickofolas)
|
||||
* Handle steamworks errors gravefully (@MartinFourier)
|
||||
* Fix some react component not unmounting correctly (@MartinFourier)
|
||||
* 'help' autocompletes (@nickofolas)
|
||||
* No longer push all achievements to steam (@Ornedan)
|
||||
* Recovery page has more information (@MartinFourier)
|
||||
* Added 'getGameInfo' ns function (@MartinFourier)
|
||||
* SF3.3 unlocks all corp API (@pigalot)
|
||||
* Major improvements to corp API (@pigalot)
|
||||
* Prevent seed money outside BN3 (@pigalot)
|
||||
* Fix bug where using keyboard shortcuts would crash if the feature is not available (@MartinFourier)\
|
||||
* Sidebar remains opened/closed on save (@MartinFourier)
|
||||
* Added tooltip to sidebar when closed (@MartinFourier)
|
||||
* Fix bug where Formulas.exe is not available when starting BN5 (@TheMas3212)
|
||||
* Fix CI (@tvanderpol)
|
||||
* Change shortcuts to match sidebar (@MartinFourier)
|
||||
* Format gang respect (@attrib)
|
||||
* Add modal to text editor with ram details (@nickofolas)
|
||||
* Fix several bugs with singularity focus (@nickofolas)
|
||||
* Nerf noodle bar.
|
||||
|
||||
v1.3.0 - 2022-01-04 Cleaning up
|
||||
-------------------------------
|
||||
|
||||
|
@ -64,9 +64,9 @@ documentation_title = '{0} Documentation'.format(project)
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '1.3'
|
||||
version = '1.5'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '1.3.0'
|
||||
release = '1.5.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
@ -117,7 +117,7 @@ Source-File
|
||||
:Max Level: 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 will reduce RAM costs.
|
||||
|
||||
Difficulty:
|
||||
Depending on what Source-Files you have unlocked before attempting this BitNode,
|
||||
|
@ -26,7 +26,7 @@ async function initialize(win) {
|
||||
} else {
|
||||
log.log('Invalid authentication token');
|
||||
res.writeHead(401);
|
||||
|
||||
|
||||
res.end(JSON.stringify({
|
||||
success: false,
|
||||
msg: 'Invalid authentication token'
|
||||
@ -71,7 +71,7 @@ async function initialize(win) {
|
||||
|
||||
result = await window.webContents.executeJavaScript(`document.saveFile("${data.filename}", "${data.code}")`);
|
||||
break;
|
||||
|
||||
|
||||
// Delete files
|
||||
case "DELETE":
|
||||
result = await window.webContents.executeJavaScript(`document.deleteFile("${data.filename}")`);
|
||||
|
@ -312,6 +312,16 @@ function getMenu(window) {
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Reset Zoom",
|
||||
enabled: utils.getZoomFactor() !== 1,
|
||||
accelerator: "CommandOrControl+num0",
|
||||
click: () => {
|
||||
utils.setZoomFactor(window, 1);
|
||||
refreshMenu(window);
|
||||
log.log("Reset zoom");
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
@ -337,23 +337,21 @@ async function restoreIfNewerExists(window) {
|
||||
let bestMatch;
|
||||
if (!steam.data && !disk.data) {
|
||||
log.info("No data to import");
|
||||
} else {
|
||||
} else if (!steam.data) {
|
||||
// We'll just compare using the lastSave field for now.
|
||||
if (!steam.data) {
|
||||
log.debug('Best potential save match: Disk');
|
||||
bestMatch = disk;
|
||||
} else if (!disk.data) {
|
||||
log.debug('Best potential save match: Steam Cloud');
|
||||
bestMatch = steam;
|
||||
} else if ((steam.data.lastSave >= disk.data.lastSave)
|
||||
|| (steam.data.playtime + lowPlaytime > disk.data.playtime)) {
|
||||
// We want to prioritze steam data if the playtime is very close
|
||||
log.debug('Best potential save match: Steam Cloud');
|
||||
bestMatch = steam;
|
||||
} else {
|
||||
log.debug('Best potential save match: disk');
|
||||
bestMatch = disk;
|
||||
}
|
||||
log.debug('Best potential save match: Disk');
|
||||
bestMatch = disk;
|
||||
} else if (!disk.data) {
|
||||
log.debug('Best potential save match: Steam Cloud');
|
||||
bestMatch = steam;
|
||||
} else if ((steam.data.lastSave >= disk.data.lastSave)
|
||||
|| (steam.data.playtime + lowPlaytime > disk.data.playtime)) {
|
||||
// We want to prioritze steam data if the playtime is very close
|
||||
log.debug('Best potential save match: Steam Cloud');
|
||||
bestMatch = steam;
|
||||
} else {
|
||||
log.debug('Best potential save match: disk');
|
||||
bestMatch = disk;
|
||||
}
|
||||
if (bestMatch) {
|
||||
if (bestMatch.data.lastSave > currentData.lastSave + 5000) {
|
||||
|
@ -29,6 +29,11 @@ const windowTracker = (windowName) => {
|
||||
};
|
||||
|
||||
const saveState = debounce(() => {
|
||||
if (!window || window.isDestroyed()) {
|
||||
log.silly(`Saving window state failed because window is not available`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!windowState.isMaximized) {
|
||||
windowState = window.getBounds();
|
||||
}
|
||||
@ -41,7 +46,7 @@ const windowTracker = (windowName) => {
|
||||
|
||||
const track = (win) => {
|
||||
window = win;
|
||||
['resize', 'move', 'close'].forEach((event) => {
|
||||
["resize", "move", "close"].forEach((event) => {
|
||||
win.on(event, saveState);
|
||||
});
|
||||
};
|
||||
|
@ -73,5 +73,5 @@
|
||||
<link rel="shortcut icon" href="favicon.ico"></head>
|
||||
<body>
|
||||
<div id="root"/>
|
||||
<script type="text/javascript" src="dist/vendor.bundle.js"></script><script type="text/javascript" src="dist/main.bundle.js"></script></body>
|
||||
<script type="text/javascript" src="dist/vendor.bundle.js"></script><script type="text/javascript" src="main.bundle.js"></script></body>
|
||||
</html>
|
||||
|
137
license.txt
137
license.txt
@ -1,85 +1,88 @@
|
||||
LIMITED USE SOFTWARE LICENSE AGREEMENT
|
||||
“Commons Clause” License Condition v1.0
|
||||
|
||||
This Limited Use Software License Agreement (the "Agreement") is a legal agreement between you, the end-user, and Daniel Y Xie,
|
||||
the creator of the software, hereafter referred to as the Creator.
|
||||
The Software is provided to you by the Licensor under the License, as defined below, subject to the following condition.
|
||||
|
||||
By downloading or purchasing the software material, which includes source code (the "Source Code"), artwork data, music and software
|
||||
tools (collectively, the "Software"), you are agreeing to be bound by the terms of this Agreement. If you do not agree to the terms
|
||||
of this Agreement, promptly destroy the Software you may have downloaded or copied.
|
||||
Without limiting other conditions in the License, the grant of rights under the License will not include, and the License does not grant to you, the right to Sell the Software.
|
||||
|
||||
SOFTWARE LICENSE
|
||||
For purposes of the foregoing, “Sell” means practicing any or all of the rights granted to you under the License to provide to third parties, for a fee or other consideration (including without limitation fees for hosting or consulting/ support services related to the Software), a product or service whose value derives, entirely or substantially, from the functionality of the Software. Any license notice or attribution required by the License must also include this Commons Clause License Condition notice.
|
||||
|
||||
1. Grant of License. The Creator grants to you the right to use the Software. You have no ownership or proprietary rights in or to
|
||||
the Software, or the Trademark. For purposes of this section, "use" means loading the Software into RAM, as well as installation
|
||||
on a hard disk or other storage device. The Software, together with any archive copy thereof, shall be destroyed when no longer
|
||||
used in accordance with this Agreement, or when the right to use the Software is terminated. You agree that the Software will not
|
||||
be shipped, transferred or exported into any country in violation of the U.S. Export Administration Act (or any other law governing
|
||||
such matters) and that you will not utilize, in any other manner, the Software in violation of any applicable law.
|
||||
Software: Bitburner
|
||||
|
||||
2. Permitted Uses.
|
||||
License: Apache 2.0 with Commons Clause
|
||||
|
||||
You may copy and distribute literal (i.e., verbatim) or modified copies of the Software's source code.
|
||||
You must meet all of the following conditions with respect to any work that you distribute or publish that in whole or in part
|
||||
contains or is derived from the Software or any part thereof:
|
||||
Licensor: Daniel Y Xie
|
||||
|
||||
(a) The distributed Software may not be used in any way for commercial gain and must not violate any of the restrictions
|
||||
set forth in Section 3.
|
||||
(b) If you have modified the Software, you must cause the modified Software to carry prominent notices stating that
|
||||
you have modified the Software's files. Modifications must not alter or remove any copyright notices in the Software.
|
||||
(c) The distributed Software must include either a written copy of this License, or a prominent written indication that
|
||||
the Software is covered by this License and written instructions for printing and/or displaying the copy of the License
|
||||
on the distribution medium
|
||||
(d) When modifications to the Software are released under this license, a non-exclusive royalty-free right is granted to
|
||||
the initial developer of the Software to distribute your modification in future versions of the Software provided
|
||||
such versions remain available under these terms in addition to any other license(s) of the initial developer.
|
||||
(d) You may not impose any further restrictions on the recipient's exercise of the rights granted herein.
|
||||
-------------------------------------------------------------------
|
||||
|
||||
For educational purposes only, you, the end-user, may use portions of the Source Code, such as particular
|
||||
routines, to develop your own software, but may not duplicate the Source Code. The limited
|
||||
right referenced in the preceding sentence is hereinafter referred to as "Educational Use." By so exercising the Educational
|
||||
Use right you shall not obtain any ownership, copyright, proprietary or other interest in or to the Source Code, or any portion
|
||||
of the Source Code. You may dispose of your own software in your sole discretion. When exercising the Educational Use right,
|
||||
you may not use or exploit the Software, or any portion of the Software, which includes the Source Code, for commercial gain.
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
3. Prohibited Uses: Under no circumstances shall you, the end-user, be permitted, allowed or authorized to commercially
|
||||
exploit the Software or any work that in whole or in part contains or is derived from the Software or any part thereof.
|
||||
Neither you nor anyone at your direction shall do any of the following acts with regard to the Software,
|
||||
or any portion thereof:
|
||||
Definitions.
|
||||
|
||||
Rent;
|
||||
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
Sell;
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
||||
|
||||
Lease;
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
Offer on a pay-per-play basis;
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
||||
|
||||
Distribute for money or any other consideration; or
|
||||
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
||||
|
||||
In any other manner and through any medium whatsoever commercially exploit or use for any commercial purpose.
|
||||
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
||||
|
||||
4. Copyright. The Software and all copyrights related thereto (including all characters and other images generated by the
|
||||
Software or depicted in the Software) are owned by the Creator and is protected by United States copyright laws and international treaty
|
||||
provisions. The Creator shall retain exclusive ownership and copyright in and to the Software and all portions of the Software and you
|
||||
shall have no ownership or other proprietary interest in such materials. You must treat the Software like any other copyrighted
|
||||
material. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License.
|
||||
You may not otherwise reproduce, copy or disclose to others, in whole or in any part, the Software. You may not copy the
|
||||
written materials accompanying the Software. You agree to use your best efforts to see that any user of the Software licensed
|
||||
hereunder complies with this Agreement.
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
5. NO WARRANTIES. The Creator DISCLAIMS ALL WARRANTIES, BOTH EXPRESS IMPLIED, INCLUDING BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE WITH RESPECT TO THE SOFTWARE. THIS LIMITED WARRANTY GIVES YOU SPECIFIC
|
||||
LEGAL RIGHTS. YOU MAY HAVE OTHER RIGHTS WHICH VARY FROM JURISDICTION TO JURISDICTION. the Creator DOES NOT WARRANT THAT THE OPERATION
|
||||
OF THE SOFTWARE WILL BE UNINTERRUPTED, ERROR FREE OR MEET YOUR SPECIFIC REQUIREMENTS. THE WARRANTY SET FORTH ABOVE IS IN LIEU
|
||||
OF ALL OTHER EXPRESS WARRANTIES WHETHER ORAL OR WRITTEN. THE AGENTS, EMPLOYEES, DISTRIBUTORS, AND DEALERS OF THE CREATOR ARE NOT AUTHORIZED
|
||||
TO MAKE MODIFICATIONS TO THIS WARRANTY, OR ADDITIONAL WARRANTIES ON BEHALF OF THE CREATOR.
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
Exclusive Remedies. The Software is being offered to you free of any charge. You agree that you have no remedy against the creator,
|
||||
its affiliates, contractors, suppliers, and agents for loss or damage caused by any defect or failure in the Software regardless
|
||||
of the form of action, whether in contract, tort, includinegligence, strict liability or otherwise, with regard to the Software.
|
||||
This Agreement shall be construed in accordance with and governed by the laws of the State of Texas. Copyright and other
|
||||
proprietary matters will be governed by United States laws and international treaties. IN ANY CASE, THE CREATOR SHALL NOT BE LIABLE
|
||||
FOR LOSS OF DATA, LOSS OF PROFITS, LOST SAVINGS, SPECIAL, INCIDENTAL, CONSEQUENTIAL, INDIRECT OR OTHER SIMILAR DAMAGES ARISING
|
||||
FROM BREACH OF WARRANTY, BREACH OF CONTRACT, NEGLIGENCE, OR OTHER LEGAL THEORY EVEN IF THE CREATOR OR ITS AGENT HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. Some jurisdictions do not allow the exclusion or limitation of
|
||||
incidental or consequential damages, so the above limitation or exclusion may not apply to you.
|
||||
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
||||
|
||||
Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
||||
|
||||
Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
||||
|
||||
Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
||||
|
||||
Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
||||
|
||||
Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
||||
|
||||
Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2022 Daniel Y Xie
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
20
main.bundle.js
Normal file
20
main.bundle.js
Normal file
File diff suppressed because one or more lines are too long
1
main.bundle.js.map
Normal file
1
main.bundle.js.map
Normal file
File diff suppressed because one or more lines are too long
24
markdown/bitburner.corporation.buybackshares.md
Normal file
24
markdown/bitburner.corporation.buybackshares.md
Normal file
@ -0,0 +1,24 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [bitburner](./bitburner.md) > [Corporation](./bitburner.corporation.md) > [buyBackShares](./bitburner.corporation.buybackshares.md)
|
||||
|
||||
## Corporation.buyBackShares() method
|
||||
|
||||
Buyback Shares
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
buyBackShares(amount: number): void;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| amount | number | Amount of shares to buy back. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
void
|
||||
|
@ -19,6 +19,7 @@ export interface Corporation extends WarehouseAPI, OfficeAPI
|
||||
| --- | --- |
|
||||
| [acceptInvestmentOffer()](./bitburner.corporation.acceptinvestmentoffer.md) | Accept investment based on you companies current valuation |
|
||||
| [bribe(factionName, amountCash, amountShares)](./bitburner.corporation.bribe.md) | Bribe a faction |
|
||||
| [buyBackShares(amount)](./bitburner.corporation.buybackshares.md) | Buyback Shares |
|
||||
| [createCorporation(corporationName, selfFund)](./bitburner.corporation.createcorporation.md) | Create a Corporation |
|
||||
| [expandCity(divisionName, cityName)](./bitburner.corporation.expandcity.md) | Expand to a new city |
|
||||
| [expandIndustry(industryType, divisionName)](./bitburner.corporation.expandindustry.md) | Expand to a new industry |
|
||||
@ -34,5 +35,6 @@ export interface Corporation extends WarehouseAPI, OfficeAPI
|
||||
| [hasUnlockUpgrade(upgradeName)](./bitburner.corporation.hasunlockupgrade.md) | Check if you have a one time unlockable upgrade |
|
||||
| [issueDividends(percent)](./bitburner.corporation.issuedividends.md) | Issue dividends |
|
||||
| [levelUpgrade(upgradeName)](./bitburner.corporation.levelupgrade.md) | Level an upgrade. |
|
||||
| [sellShares(amount)](./bitburner.corporation.sellshares.md) | Sell Shares |
|
||||
| [unlockUpgrade(upgradeName)](./bitburner.corporation.unlockupgrade.md) | Unlock an upgrade |
|
||||
|
||||
|
24
markdown/bitburner.corporation.sellshares.md
Normal file
24
markdown/bitburner.corporation.sellshares.md
Normal file
@ -0,0 +1,24 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [bitburner](./bitburner.md) > [Corporation](./bitburner.corporation.md) > [sellShares](./bitburner.corporation.sellshares.md)
|
||||
|
||||
## Corporation.sellShares() method
|
||||
|
||||
Sell Shares
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
sellShares(amount: number): void;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| amount | number | Amount of shares to sell. |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
void
|
||||
|
27
markdown/bitburner.warehouseapi.bulkpurchase.md
Normal file
27
markdown/bitburner.warehouseapi.bulkpurchase.md
Normal file
@ -0,0 +1,27 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [bitburner](./bitburner.md) > [WarehouseAPI](./bitburner.warehouseapi.md) > [bulkPurchase](./bitburner.warehouseapi.bulkpurchase.md)
|
||||
|
||||
## WarehouseAPI.bulkPurchase() method
|
||||
|
||||
Set material to bulk buy
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
bulkPurchase(divisionName: string, cityName: string, materialName: string, amt: number): void;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| divisionName | string | Name of the division |
|
||||
| cityName | string | Name of the city |
|
||||
| materialName | string | Name of the material |
|
||||
| amt | number | Amount of material to buy |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
void
|
||||
|
74
package-lock.json
generated
74
package-lock.json
generated
@ -1,11 +1,12 @@
|
||||
{
|
||||
"name": "bitburner",
|
||||
"version": "1.3.0",
|
||||
"version": "1.5.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"version": "1.3.0",
|
||||
"name": "bitburner",
|
||||
"version": "1.5.0",
|
||||
"hasInstallScript": true,
|
||||
"license": "SEE LICENSE IN license.txt",
|
||||
"dependencies": {
|
||||
@ -16,9 +17,12 @@
|
||||
"@mui/icons-material": "^5.0.3",
|
||||
"@mui/material": "^5.0.3",
|
||||
"@mui/styles": "^5.0.1",
|
||||
"@types/bcrypt": "^5.0.0",
|
||||
"@types/bcryptjs": "^2.4.2",
|
||||
"acorn": "^8.4.1",
|
||||
"acorn-walk": "^8.1.1",
|
||||
"arg": "^5.0.0",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"better-react-mathjax": "^1.0.3",
|
||||
"clsx": "^1.1.1",
|
||||
"date-fns": "^2.25.0",
|
||||
@ -3976,6 +3980,19 @@
|
||||
"@babel/types": "^7.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/bcrypt": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.0.tgz",
|
||||
"integrity": "sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw==",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/bcryptjs": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz",
|
||||
"integrity": "sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ=="
|
||||
},
|
||||
"node_modules/@types/escodegen": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/escodegen/-/escodegen-0.0.7.tgz",
|
||||
@ -4067,8 +4084,7 @@
|
||||
"node_modules/@types/node": {
|
||||
"version": "16.10.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.4.tgz",
|
||||
"integrity": "sha512-EITwVTX5B4nDjXjGeQAfXOrm+Jn+qNjDmyDRtWoD+wZsl/RDPRTFRKivs4Mt74iOFlLOrE5+Kf+p5yjyhm3+cA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-EITwVTX5B4nDjXjGeQAfXOrm+Jn+qNjDmyDRtWoD+wZsl/RDPRTFRKivs4Mt74iOFlLOrE5+Kf+p5yjyhm3+cA=="
|
||||
},
|
||||
"node_modules/@types/numeral": {
|
||||
"version": "0.0.25",
|
||||
@ -5447,6 +5463,11 @@
|
||||
"tweetnacl": "^0.14.3"
|
||||
}
|
||||
},
|
||||
"node_modules/bcryptjs": {
|
||||
"version": "2.4.3",
|
||||
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
|
||||
"integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms="
|
||||
},
|
||||
"node_modules/better-react-mathjax": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/better-react-mathjax/-/better-react-mathjax-1.0.3.tgz",
|
||||
@ -9645,9 +9666,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.14.7",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz",
|
||||
"integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==",
|
||||
"version": "1.14.8",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
|
||||
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@ -20380,9 +20401,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/url-parse": {
|
||||
"version": "1.5.3",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz",
|
||||
"integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==",
|
||||
"version": "1.5.10",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
|
||||
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"querystringify": "^2.1.1",
|
||||
@ -25343,6 +25364,19 @@
|
||||
"@babel/types": "^7.3.0"
|
||||
}
|
||||
},
|
||||
"@types/bcrypt": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.0.tgz",
|
||||
"integrity": "sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw==",
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/bcryptjs": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz",
|
||||
"integrity": "sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ=="
|
||||
},
|
||||
"@types/escodegen": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/escodegen/-/escodegen-0.0.7.tgz",
|
||||
@ -25434,8 +25468,7 @@
|
||||
"@types/node": {
|
||||
"version": "16.10.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.4.tgz",
|
||||
"integrity": "sha512-EITwVTX5B4nDjXjGeQAfXOrm+Jn+qNjDmyDRtWoD+wZsl/RDPRTFRKivs4Mt74iOFlLOrE5+Kf+p5yjyhm3+cA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-EITwVTX5B4nDjXjGeQAfXOrm+Jn+qNjDmyDRtWoD+wZsl/RDPRTFRKivs4Mt74iOFlLOrE5+Kf+p5yjyhm3+cA=="
|
||||
},
|
||||
"@types/numeral": {
|
||||
"version": "0.0.25",
|
||||
@ -26526,6 +26559,11 @@
|
||||
"tweetnacl": "^0.14.3"
|
||||
}
|
||||
},
|
||||
"bcryptjs": {
|
||||
"version": "2.4.3",
|
||||
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
|
||||
"integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms="
|
||||
},
|
||||
"better-react-mathjax": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/better-react-mathjax/-/better-react-mathjax-1.0.3.tgz",
|
||||
@ -29959,9 +29997,9 @@
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.14.7",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz",
|
||||
"integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==",
|
||||
"version": "1.14.8",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
|
||||
"integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==",
|
||||
"dev": true
|
||||
},
|
||||
"for-in": {
|
||||
@ -38392,9 +38430,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"url-parse": {
|
||||
"version": "1.5.3",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz",
|
||||
"integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==",
|
||||
"version": "1.5.10",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
|
||||
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"querystringify": "^2.1.1",
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "bitburner",
|
||||
"license": "SEE LICENSE IN license.txt",
|
||||
"version": "1.3.0",
|
||||
"version": "1.5.0",
|
||||
"main": "electron-main.js",
|
||||
"author": {
|
||||
"name": "Daniel Xie & Olivier Gagnon"
|
||||
@ -17,9 +17,12 @@
|
||||
"@mui/icons-material": "^5.0.3",
|
||||
"@mui/material": "^5.0.3",
|
||||
"@mui/styles": "^5.0.1",
|
||||
"@types/bcrypt": "^5.0.0",
|
||||
"@types/bcryptjs": "^2.4.2",
|
||||
"acorn": "^8.4.1",
|
||||
"acorn-walk": "^8.1.1",
|
||||
"arg": "^5.0.0",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"better-react-mathjax": "^1.0.3",
|
||||
"clsx": "^1.1.1",
|
||||
"date-fns": "^2.25.0",
|
||||
@ -114,6 +117,7 @@
|
||||
"lint": "eslint --fix . --ext js,jsx,ts,tsx",
|
||||
"lint:report": "eslint --ext js,jsx,ts,tsx .",
|
||||
"preinstall": "node ./tools/engines-check/engines-check.js",
|
||||
"postinstall": "cd electron && npm install",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"watch": "webpack --watch --mode production",
|
||||
@ -124,6 +128,6 @@
|
||||
"electron:packager-win": "electron-packager .package bitburner --platform win32 --arch x64 --out .build --overwrite --icon .package/icon.png",
|
||||
"electron:packager-mac": "electron-packager .package bitburner --platform darwin --arch x64 --out .build --overwrite --icon .package/icon.png",
|
||||
"electron:packager-linux": "electron-packager .package bitburner --platform linux --arch x64 --out .build --overwrite --icon .package/icon.png",
|
||||
"allbuild": "npm run build && npm run electron && git add --all && git commit --amend --no-edit && git push -f -u origin dev"
|
||||
"allbuild": "npm run build && npm run electron && git add --all && git commit -m \"allbuild commit $(which git)\" && git push -f -u origin dev"
|
||||
}
|
||||
}
|
||||
|
@ -481,7 +481,16 @@
|
||||
"ID": "DEVMENU",
|
||||
"Name": "Exploit: you're not meant to access this",
|
||||
"Description": "Open the dev menu."
|
||||
},
|
||||
"RAINBOW": {
|
||||
"ID": "RAINBOW",
|
||||
"Name": "Exploit: rainbow",
|
||||
"Description": "Make good use of the rainbow."
|
||||
},
|
||||
"TRUE_RECURSION": {
|
||||
"ID": "TRUE_RECURSION",
|
||||
"Name": "Exploit: true recursion",
|
||||
"Description": "Beat BN1 in megabyteburner 2000."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -553,7 +553,8 @@ export const achievements: IMap<Achievement> = {
|
||||
...achievementData["MAX_CACHE"],
|
||||
Icon: "HASHNETCAP",
|
||||
Visible: () => hasAccessToSF(Player, 9),
|
||||
Condition: () => hasHacknetServers(Player) &&
|
||||
Condition: () =>
|
||||
hasHacknetServers(Player) &&
|
||||
Player.hashManager.hashes === Player.hashManager.capacity &&
|
||||
Player.hashManager.capacity > 0,
|
||||
},
|
||||
@ -729,6 +730,18 @@ export const achievements: IMap<Achievement> = {
|
||||
Secret: true,
|
||||
Condition: () => Player.exploits.includes(Exploit.YoureNotMeantToAccessThis),
|
||||
},
|
||||
RAINBOW: {
|
||||
...achievementData["RAINBOW"],
|
||||
Icon: "SF-1",
|
||||
Secret: true,
|
||||
Condition: () => Player.exploits.includes(Exploit.INeedARainbow),
|
||||
},
|
||||
TRUE_RECURSION: {
|
||||
...achievementData["TRUE_RECURSION"],
|
||||
Icon: "SF-1",
|
||||
Secret: true,
|
||||
Condition: () => Player.exploits.includes(Exploit.TrueRecursion),
|
||||
},
|
||||
};
|
||||
|
||||
// Steam has a limit of 100 achievement. So these were planned but commented for now.
|
||||
|
@ -36,7 +36,7 @@ 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 != 7) {
|
||||
return false;
|
||||
|
43
src/Arcade/ui/ArcadeRoot.tsx
Normal file
43
src/Arcade/ui/ArcadeRoot.tsx
Normal file
@ -0,0 +1,43 @@
|
||||
import React, { useState } from "react";
|
||||
import { BBCabinetRoot } from "./BBCabinet";
|
||||
|
||||
import Button from "@mui/material/Button";
|
||||
import { use } from "../../ui/Context";
|
||||
import { AlertEvents } from "../../ui/React/AlertManager";
|
||||
|
||||
enum Page {
|
||||
None,
|
||||
Megabyteburner2000,
|
||||
}
|
||||
|
||||
export function ArcadeRoot(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const [page, setPage] = useState(Page.None);
|
||||
|
||||
function mbBurner2000(): void {
|
||||
if (player.sourceFileLvl(1) === 0) {
|
||||
AlertEvents.emit("This machine is broken.");
|
||||
} else {
|
||||
setPage(Page.Megabyteburner2000);
|
||||
}
|
||||
}
|
||||
|
||||
if (page === Page.None) {
|
||||
return (
|
||||
<>
|
||||
<Button onClick={mbBurner2000}>Megabyte burner 2000</Button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
let currentGame = <></>;
|
||||
switch (page) {
|
||||
case Page.Megabyteburner2000:
|
||||
currentGame = <BBCabinetRoot />;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Button onClick={() => setPage(Page.None)}>Back</Button>
|
||||
{currentGame}
|
||||
</>
|
||||
);
|
||||
}
|
62
src/Arcade/ui/BBCabinet.tsx
Normal file
62
src/Arcade/ui/BBCabinet.tsx
Normal file
@ -0,0 +1,62 @@
|
||||
import React, { useEffect } from "react";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { use } from "../../ui/Context";
|
||||
import { Exploit } from "../../Exploits/Exploit";
|
||||
|
||||
const metaBB = "https://bitburner-official.github.io/bitburner-legacy/";
|
||||
|
||||
const style = {
|
||||
width: "1060px",
|
||||
height: "800px",
|
||||
border: "0px",
|
||||
} as any;
|
||||
|
||||
export function BBCabinetRoot(): React.ReactElement {
|
||||
const player = use.Player();
|
||||
useEffect(() => {
|
||||
window.addEventListener("message", function (this: Window, ev: MessageEvent<boolean>) {
|
||||
if (ev.isTrusted && ev.origin == "https://bitburner-official.github.io" && ev.data) {
|
||||
player.giveExploit(Exploit.TrueRecursion);
|
||||
}
|
||||
});
|
||||
});
|
||||
// prettier-ignore
|
||||
const joystick =
|
||||
<>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> ,'" "', .-. </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> / \ ( ) </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | .-. '-' .-. </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ / ( ) ( )</Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> '.___.' '-' .-. '-'</Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> ||| ( ) </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> ||| '-' </Typography>
|
||||
</>;
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
width: "1060px",
|
||||
height: "800px",
|
||||
padding: "0",
|
||||
overflow: "hidden",
|
||||
borderColor: "white",
|
||||
borderStyle: "solid",
|
||||
borderWidth: "5px",
|
||||
}}
|
||||
>
|
||||
<iframe src={metaBB} style={style} />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
width: "1060px",
|
||||
borderColor: "white",
|
||||
borderStyle: "solid",
|
||||
borderWidth: "5px",
|
||||
}}
|
||||
>
|
||||
{joystick}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
@ -148,7 +148,7 @@ function initAugmentations(): void {
|
||||
name: AugmentationNames.HemoRecirculator,
|
||||
moneyCost: 4.5e7,
|
||||
repCost: 1e4,
|
||||
info: "A heart implant that greatly increases the body's ability to effectively use and pump " + "blood.",
|
||||
info: "A heart implant that greatly increases the body's ability to effectively use and pump blood.",
|
||||
strength_mult: 1.08,
|
||||
defense_mult: 1.08,
|
||||
agility_mult: 1.08,
|
||||
@ -430,7 +430,7 @@ function initAugmentations(): void {
|
||||
repCost: 1.125e6,
|
||||
moneyCost: 4.25e9,
|
||||
info:
|
||||
"Graphene is grafted and fused into the skeletal structure, " + "enhancing bone density and tensile strength.",
|
||||
"Graphene is grafted and fused into the skeletal structure, enhancing bone density and tensile strength.",
|
||||
strength_mult: 1.7,
|
||||
defense_mult: 1.7,
|
||||
});
|
||||
@ -1085,7 +1085,7 @@ function initAugmentations(): void {
|
||||
name: AugmentationNames.FocusWire,
|
||||
repCost: 7.5e4,
|
||||
moneyCost: 9e8,
|
||||
info: "A cranial implant that stops procrastination by blocking specific neural pathways " + "in the brain.",
|
||||
info: "A cranial implant that stops procrastination by blocking specific neural pathways in the brain.",
|
||||
hacking_exp_mult: 1.05,
|
||||
strength_exp_mult: 1.05,
|
||||
defense_exp_mult: 1.05,
|
||||
@ -1486,7 +1486,7 @@ function initAugmentations(): void {
|
||||
name: AugmentationNames.SmartSonar,
|
||||
repCost: 2.25e4,
|
||||
moneyCost: 7.5e7,
|
||||
info: "A cochlear implant that helps the player detect and locate enemies " + "using sound propagation.",
|
||||
info: "A cochlear implant that helps the player detect and locate enemies using sound propagation.",
|
||||
dexterity_mult: 1.1,
|
||||
dexterity_exp_mult: 1.15,
|
||||
crime_money_mult: 1.25,
|
||||
@ -1703,7 +1703,7 @@ function initAugmentations(): void {
|
||||
"The left arm of a legendary BitRunner who ascended beyond this world. " +
|
||||
"It projects a light blue energy shield that protects the exposed inner parts. " +
|
||||
"Even though it contains no weapons, the advanced tungsten titanium " +
|
||||
"alloy increases the users strength to unbelievable levels. The augmentation " +
|
||||
"alloy increases the user's strength to unbelievable levels. The augmentation " +
|
||||
"gets more powerful over time for seemingly no reason.",
|
||||
strength_mult: 2.7,
|
||||
});
|
||||
@ -2015,7 +2015,7 @@ function initAugmentations(): void {
|
||||
repCost: 6.25e4,
|
||||
moneyCost: 2.75e8,
|
||||
info:
|
||||
"Cybernetic arms created from plasteel and carbon fibers that completely replace " + "the user's organic arms.",
|
||||
"Cybernetic arms created from plasteel and carbon fibers that completely replace the user's organic arms.",
|
||||
strength_mult: 1.3,
|
||||
dexterity_mult: 1.3,
|
||||
});
|
||||
@ -2598,12 +2598,7 @@ function augmentationExists(name: string): boolean {
|
||||
|
||||
export function isRepeatableAug(aug: Augmentation): boolean {
|
||||
const augName = aug instanceof Augmentation ? aug.name : aug;
|
||||
|
||||
if (augName === AugmentationNames.NeuroFluxGovernor) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return augName === AugmentationNames.NeuroFluxGovernor;
|
||||
}
|
||||
|
||||
export { installAugmentations, initAugmentations, applyAugmentation, augmentationExists };
|
||||
|
@ -110,7 +110,7 @@ export function AugmentationsRoot(props: IProps): React.ReactElement {
|
||||
<br />
|
||||
<br />
|
||||
It is recommended to install several Augmentations at once. Preferably everything from any faction of your
|
||||
chosing.
|
||||
choosing.
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
@ -8,8 +8,8 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { AugmentationAccordion } from "../../ui/React/AugmentationAccordion";
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
import { Augmentations } from "../Augmentations";
|
||||
import { AugmentationNames } from "../data/AugmentationNames";
|
||||
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { use } from "../../ui/Context";
|
||||
|
@ -4,8 +4,8 @@
|
||||
*/
|
||||
import * as React from "react";
|
||||
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
import { Augmentations } from "../Augmentations";
|
||||
import { AugmentationNames } from "../data/AugmentationNames";
|
||||
import { Player } from "../../Player";
|
||||
|
||||
import { AugmentationAccordion } from "../../ui/React/AugmentationAccordion";
|
||||
|
@ -202,8 +202,8 @@ BitNodes["BitNode5"] = new BitNode(
|
||||
Destroying this BitNode will give you Source-File 5, or if you already have this Source-File it will upgrade its
|
||||
level up to a maximum of 3. This Source-File grants you a special new stat called Intelligence. Intelligence is
|
||||
unique because it is permanent and persistent (it never gets reset back to 1). However gaining Intelligence
|
||||
experience is much slower than other stats, and it is also hidden (you won't know when you gain experience and how
|
||||
much). Higher Intelligence levels will boost your production for many actions in the game. <br />
|
||||
experience is much slower than other stats. Higher Intelligence levels will boost your production for many actions
|
||||
in the game. <br />
|
||||
<br />
|
||||
In addition, this Source-File will unlock the getBitNodeMultipliers() Netscript function and let you start with
|
||||
Formulas.exe, and will also raise all of your hacking-related multipliers by:
|
||||
@ -670,7 +670,6 @@ export function initBitNodeMultipliers(p: IPlayer): void {
|
||||
BitNodeMultipliers.InfiltrationMoney = 0.75;
|
||||
BitNodeMultipliers.CorporationValuation = 0.2;
|
||||
BitNodeMultipliers.HacknetNodeMoney = 0.2;
|
||||
BitNodeMultipliers.FactionPassiveRepGain = 0;
|
||||
BitNodeMultipliers.HackExpGain = 0.25;
|
||||
BitNodeMultipliers.DaedalusAugsRequirement = 1.166; // Results in 35 Augs needed
|
||||
BitNodeMultipliers.PurchasedServerSoftcap = 2;
|
||||
@ -694,7 +693,6 @@ export function initBitNodeMultipliers(p: IPlayer): void {
|
||||
BitNodeMultipliers.InfiltrationMoney = 0.75;
|
||||
BitNodeMultipliers.CorporationValuation = 0.2;
|
||||
BitNodeMultipliers.HacknetNodeMoney = 0.2;
|
||||
BitNodeMultipliers.FactionPassiveRepGain = 0;
|
||||
BitNodeMultipliers.HackExpGain = 0.25;
|
||||
BitNodeMultipliers.FourSigmaMarketDataCost = 2;
|
||||
BitNodeMultipliers.FourSigmaMarketDataApiCost = 2;
|
||||
|
@ -8,38 +8,37 @@ import { CinematicText } from "../../ui/React/CinematicText";
|
||||
import { use } from "../../ui/Context";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import Button from "@mui/material/Button";
|
||||
|
||||
|
||||
const useStyles = makeStyles(() =>
|
||||
createStyles({
|
||||
level0: {
|
||||
color: "red",
|
||||
portal: {
|
||||
cursor: "pointer",
|
||||
fontFamily: "inherit",
|
||||
fontSize: "1rem",
|
||||
fontWeight: "bold",
|
||||
lineHeight: 1,
|
||||
padding: 0,
|
||||
"&:hover": {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
level0: {
|
||||
color: "red",
|
||||
},
|
||||
level1: {
|
||||
color: "yellow",
|
||||
cursor: "pointer",
|
||||
"&:hover": {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
level2: {
|
||||
color: "#48d1cc",
|
||||
cursor: "pointer",
|
||||
"&:hover": {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
level3: {
|
||||
color: "blue",
|
||||
cursor: "pointer",
|
||||
"&:hover": {
|
||||
color: "#fff",
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
@ -71,6 +70,7 @@ function BitNodePortal(props: IPortalProps): React.ReactElement {
|
||||
if (props.level === 2) {
|
||||
cssClass = classes.level2;
|
||||
}
|
||||
cssClass = `${classes.portal} ${cssClass}`
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -85,9 +85,24 @@ function BitNodePortal(props: IPortalProps): React.ReactElement {
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
<span onClick={() => setPortalOpen(true)} className={cssClass} aria-label={`enter-bitnode-${bitNode.number.toString()}`}>
|
||||
<b>O</b>
|
||||
</span>
|
||||
{Settings.DisableASCIIArt ? (
|
||||
<Button
|
||||
onClick={() => setPortalOpen(true)}
|
||||
sx={{ m: 2 }}
|
||||
aria-description={bitNode.desc}
|
||||
>
|
||||
<Typography>BitNode-{bitNode.number.toString()}: {bitNode.name}</Typography>
|
||||
</Button>
|
||||
) : (
|
||||
<IconButton
|
||||
onClick={() => setPortalOpen(true)}
|
||||
className={cssClass}
|
||||
aria-label={`BitNode-${bitNode.number.toString()}: ${bitNode.name}`}
|
||||
aria-description={bitNode.desc}
|
||||
>
|
||||
O
|
||||
</IconButton>
|
||||
)}
|
||||
</Tooltip>
|
||||
<PortalModal
|
||||
open={portalOpen}
|
||||
@ -98,6 +113,10 @@ function BitNodePortal(props: IPortalProps): React.ReactElement {
|
||||
destroyedBitNode={props.destroyedBitNode}
|
||||
flume={props.flume}
|
||||
/>
|
||||
|
||||
{Settings.DisableASCIIArt && (
|
||||
<br/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -113,7 +132,7 @@ export function BitverseRoot(props: IProps): React.ReactElement {
|
||||
const player = use.Player();
|
||||
const enter = enterBitNode;
|
||||
const destroyed = player.bitNodeN;
|
||||
const [destroySequence, setDestroySequence] = useState(true && !props.quick);
|
||||
const [destroySequence, setDestroySequence] = useState(!props.quick);
|
||||
|
||||
// Update NextSourceFileFlags
|
||||
const nextSourceFileFlags = SourceFileFlags.slice();
|
||||
@ -151,63 +170,104 @@ export function BitverseRoot(props: IProps): React.ReactElement {
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
if (Settings.DisableASCIIArt) {
|
||||
return (
|
||||
<>
|
||||
{Object.values(BitNodes).filter((node) => {
|
||||
console.log(node.desc);
|
||||
return node.desc !== 'COMING SOON';
|
||||
}).map((node) => {
|
||||
return (
|
||||
<BitNodePortal key={node.number} n={node.number} level={nextSourceFileFlags[node.number]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} />
|
||||
)
|
||||
})}
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<CinematicText lines={[
|
||||
"> Many decades ago, a humanoid extraterrestrial species which we call the Enders descended on the Earth...violently",
|
||||
"> Our species fought back, but it was futile. The Enders had technology far beyond our own...",
|
||||
"> Instead of killing every last one of us, the human race was enslaved...",
|
||||
"> We were shackled in a digital world, chained into a prison for our minds...",
|
||||
"> Using their advanced technology, the Enders created complex simulations of a virtual reality...",
|
||||
"> Simulations designed to keep us content...ignorant of the truth.",
|
||||
"> Simulations used to trap and suppress our consciousness, to keep us under control...",
|
||||
"> Why did they do this? Why didn't they just end our entire race? We don't know, not yet.",
|
||||
"> Humanity's only hope is to destroy these simulations, destroy the only realities we've ever known...",
|
||||
"> Only then can we begin to fight back...",
|
||||
"> By hacking the daemon that generated your reality, you've just destroyed one simulation, called a BitNode...",
|
||||
"> But there is still a long way to go...",
|
||||
"> The technology the Enders used to enslave the human race wasn't just a single complex simulation...",
|
||||
"> There are tens if not hundreds of BitNodes out there...",
|
||||
"> Each with their own simulations of a reality...",
|
||||
"> Each creating their own universes...a universe of universes",
|
||||
"> And all of which must be destroyed...",
|
||||
"> .......................................",
|
||||
"> Welcome to the Bitverse...",
|
||||
"> ",
|
||||
"> (Enter a new BitNode using the image above)",
|
||||
]} />
|
||||
</>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
// prettier-ignore
|
||||
<>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> O </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | O O | O O | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> O | | / __| \ | | O </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> O | O | | O / | O | | O | O </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | | |_/ |/ | \_ \_| | | | | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> O | | | O | | O__/ | / \__ | | O | | | O </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | | | | | / /| O / \| | | | | | | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>O | | | \| | O / _/ | / O | |/ | | | O</Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | | |O / | | O / | O O | | \ O| | | |</Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | |/ \/ / __| | |/ \ | \ | |__ \ \/ \| | |</Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| O | |_/ |\| \ <BitNodePortal n={13} level={nextSourceFileFlags[13]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \__| \_| | O |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | |_/ | | \| / | \_| | | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| / \| | / / \ |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | <BitNodePortal n={10} level={nextSourceFileFlags[10]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | / | <BitNodePortal n={11} level={nextSourceFileFlags[11]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> <BitNodePortal n={9} level={nextSourceFileFlags[9]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | | | | | | <BitNodePortal n={12} level={nextSourceFileFlags[12]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | / / \ \ | | | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| | / <BitNodePortal n={7} level={nextSourceFileFlags[7]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> / \ <BitNodePortal n={8} level={nextSourceFileFlags[8]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \ | |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ | / / | | \ \ | / </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ \JUMP <BitNodePortal n={5} level={nextSourceFileFlags[5]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} />3R | | | | | | R3<BitNodePortal n={6} level={nextSourceFileFlags[6]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> PMUJ/ / </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \|| | | | | | | | | ||/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| \_ | | | | | | _/ |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ \| / \ / \ |/ / </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> <BitNodePortal n={1} level={nextSourceFileFlags[1]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> |/ <BitNodePortal n={2} level={nextSourceFileFlags[2]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | <BitNodePortal n={3} level={nextSourceFileFlags[3]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \| <BitNodePortal n={4} level={nextSourceFileFlags[4]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | | | | | | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \JUMP3R|JUMP|3R| |R3|PMUJ|R3PMUJ/ </Typography>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<CinematicText lines={[
|
||||
"> Many decades ago, a humanoid extraterrestrial species which we call the Enders descended on the Earth...violently",
|
||||
"> Our species fought back, but it was futile. The Enders had technology far beyond our own...",
|
||||
"> Instead of killing every last one of us, the human race was enslaved...",
|
||||
"> We were shackled in a digital world, chained into a prison for our minds...",
|
||||
"> Using their advanced technology, the Enders created complex simulations of a virtual reality...",
|
||||
"> Simulations designed to keep us content...ignorant of the truth.",
|
||||
"> Simulations used to trap and suppress our consciousness, to keep us under control...",
|
||||
"> Why did they do this? Why didn't they just end our entire race? We don't know, not yet.",
|
||||
"> Humanity's only hope is to destroy these simulations, destroy the only realities we've ever known...",
|
||||
"> Only then can we begin to fight back...",
|
||||
"> By hacking the daemon that generated your reality, you've just destroyed one simulation, called a BitNode...",
|
||||
"> But there is still a long way to go...",
|
||||
"> The technology the Enders used to enslave the human race wasn't just a single complex simulation...",
|
||||
"> There are tens if not hundreds of BitNodes out there...",
|
||||
"> Each with their own simulations of a reality...",
|
||||
"> Each creating their own universes...a universe of universes",
|
||||
"> And all of which must be destroyed...",
|
||||
"> .......................................",
|
||||
"> Welcome to the Bitverse...",
|
||||
"> ",
|
||||
"> (Enter a new BitNode using the image above)",
|
||||
]} />
|
||||
</>
|
||||
);
|
||||
|
||||
<>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> O </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | O O | O O | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> O | | / __| \ | | O </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> O | O | | O / | O | | O | O </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | | |_/ |/ | \_ \_| | | | | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> O | | | O | | O__/ | / \__ | | O | | | O </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | | | | | / /| O / \| | | | | | | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>O | | | \| | O / _/ | / O | |/ | | | O</Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | | |O / | | O / | O O | | \ O| | | |</Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | |/ \/ / __| | |/ \ | \ | |__ \ \/ \| | |</Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| O | |_/ |\| \ <BitNodePortal n={13} level={nextSourceFileFlags[13]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \__| \_| | O |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | |_/ | | \| / | \_| | | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| / \| | / / \ |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | <BitNodePortal n={10} level={nextSourceFileFlags[10]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | / | <BitNodePortal n={11} level={nextSourceFileFlags[11]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> <BitNodePortal n={9} level={nextSourceFileFlags[9]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | | | | | | <BitNodePortal n={12} level={nextSourceFileFlags[12]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | / / \ \ | | | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| | / <BitNodePortal n={7} level={nextSourceFileFlags[7]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> / \ <BitNodePortal n={8} level={nextSourceFileFlags[8]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \ | |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ | / / | | \ \ | / </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ \JUMP <BitNodePortal n={5} level={nextSourceFileFlags[5]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} />3R | | | | | | R3<BitNodePortal n={6} level={nextSourceFileFlags[6]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> PMUJ/ / </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \|| | | | | | | | | ||/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| \_ | | | | | | _/ |/ </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ \| / \ / \ |/ / </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> <BitNodePortal n={1} level={nextSourceFileFlags[1]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> |/ <BitNodePortal n={2} level={nextSourceFileFlags[2]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | <BitNodePortal n={3} level={nextSourceFileFlags[3]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \| <BitNodePortal n={4} level={nextSourceFileFlags[4]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | | | | | | </Typography>
|
||||
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \JUMP3R|JUMP|3R| |R3|PMUJ|R3PMUJ/ </Typography>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<CinematicText lines={[
|
||||
"> Many decades ago, a humanoid extraterrestrial species which we call the Enders descended on the Earth...violently",
|
||||
"> Our species fought back, but it was futile. The Enders had technology far beyond our own...",
|
||||
"> Instead of killing every last one of us, the human race was enslaved...",
|
||||
"> We were shackled in a digital world, chained into a prison for our minds...",
|
||||
"> Using their advanced technology, the Enders created complex simulations of a virtual reality...",
|
||||
"> Simulations designed to keep us content...ignorant of the truth.",
|
||||
"> Simulations used to trap and suppress our consciousness, to keep us under control...",
|
||||
"> Why did they do this? Why didn't they just end our entire race? We don't know, not yet.",
|
||||
"> Humanity's only hope is to destroy these simulations, destroy the only realities we've ever known...",
|
||||
"> Only then can we begin to fight back...",
|
||||
"> By hacking the daemon that generated your reality, you've just destroyed one simulation, called a BitNode...",
|
||||
"> But there is still a long way to go...",
|
||||
"> The technology the Enders used to enslave the human race wasn't just a single complex simulation...",
|
||||
"> There are tens if not hundreds of BitNodes out there...",
|
||||
"> Each with their own simulations of a reality...",
|
||||
"> Each creating their own universes...a universe of universes",
|
||||
"> And all of which must be destroyed...",
|
||||
"> .......................................",
|
||||
"> Welcome to the Bitverse...",
|
||||
"> ",
|
||||
"> (Enter a new BitNode using the image above)",
|
||||
]} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
return <></>;
|
||||
}
|
||||
|
@ -43,6 +43,8 @@ export function PortalModal(props: IProps): React.ReactElement {
|
||||
<br />
|
||||
<br />
|
||||
<Button
|
||||
aria-label={`enter-bitnode-${bitNode.number.toString()}`}
|
||||
autoFocus={true}
|
||||
onClick={() => {
|
||||
props.enter(router, props.flume, props.destroyedBitNode, props.n);
|
||||
props.onClose();
|
||||
|
@ -135,7 +135,7 @@ export class Action implements IAction {
|
||||
if (this.decays.hasOwnProperty(decay)) {
|
||||
if (this.decays[decay] > 1) {
|
||||
throw new Error(
|
||||
"Invalid decays when constructing " + "Action " + this.name + ". " + "Decay value cannot be greater than 1",
|
||||
`Invalid decays when constructing Action ${this.name}. Decay value cannot be greater than 1`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1914,6 +1914,9 @@ export class Bladeburner implements IBladeburner {
|
||||
}
|
||||
|
||||
process(router: IRouter, player: IPlayer): void {
|
||||
// Edge race condition when the engine checks the processing counters and attempts to route before the router is initialized.
|
||||
if (!router.isInitialized) return;
|
||||
|
||||
// Edge case condition...if Operation Daedalus is complete trigger the BitNode
|
||||
if (router.page() !== Page.BitVerse && this.blackops.hasOwnProperty("Operation Daedalus")) {
|
||||
return router.toBitVerse(false, false);
|
||||
@ -2083,7 +2086,7 @@ export class Bladeburner implements IBladeburner {
|
||||
this.startAction(player, actionId);
|
||||
workerScript.log(
|
||||
"bladeburner.startAction",
|
||||
() => `Starting bladeburner action with type '${type}' and name ${name}"`,
|
||||
() => `Starting bladeburner action with type '${type}' and name '${name}'`,
|
||||
);
|
||||
return true;
|
||||
} catch (e: any) {
|
||||
|
@ -16,4 +16,4 @@ for (const actionName of actionNames){
|
||||
GeneralActions[actionName] = new Action({
|
||||
name: actionName,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ export const Skills: IMap<Skill> = {};
|
||||
Skills[SkillNames.BladesIntuition] = new Skill({
|
||||
name: SkillNames.BladesIntuition,
|
||||
desc:
|
||||
"Each level of this skill increases your success chance " + "for all Contracts, Operations, and BlackOps by 3%",
|
||||
"Each level of this skill increases your success chance for all Contracts, Operations, and BlackOps by 3%",
|
||||
baseCost: 3,
|
||||
costInc: 2.1,
|
||||
successChanceAll: 3,
|
||||
@ -33,14 +33,14 @@ export const Skills: IMap<Skill> = {};
|
||||
});
|
||||
Skills[SkillNames.DigitalObserver] = new Skill({
|
||||
name: SkillNames.DigitalObserver,
|
||||
desc: "Each level of this skill increases your success chance in " + "all Operations and BlackOps by 4%",
|
||||
desc: "Each level of this skill increases your success chance in all Operations and BlackOps by 4%",
|
||||
baseCost: 2,
|
||||
costInc: 2.1,
|
||||
successChanceOperation: 4,
|
||||
});
|
||||
Skills[SkillNames.Tracer] = new Skill({
|
||||
name: SkillNames.Tracer,
|
||||
desc: "Each level of this skill increases your success chance in " + "all Contracts by 4%",
|
||||
desc: "Each level of this skill increases your success chance in all Contracts by 4%",
|
||||
baseCost: 2,
|
||||
costInc: 2.1,
|
||||
successChanceContract: 4,
|
||||
@ -67,7 +67,7 @@ export const Skills: IMap<Skill> = {};
|
||||
});
|
||||
Skills[SkillNames.EvasiveSystem] = new Skill({
|
||||
name: SkillNames.EvasiveSystem,
|
||||
desc: "Each level of this skill increases your effective " + "dexterity and agility for Bladeburner actions by 4%",
|
||||
desc: "Each level of this skill increases your effective dexterity and agility for Bladeburner actions by 4%",
|
||||
baseCost: 2,
|
||||
costInc: 2.1,
|
||||
effDex: 4,
|
||||
|
@ -22,7 +22,7 @@ export function OperationPage(props: IProps): React.ReactElement {
|
||||
between different Operations.
|
||||
<br />
|
||||
<br />
|
||||
For operations, you can use a team. You must first recruit team members. Having a larger team will improves your
|
||||
For operations, you can use a team. You must first recruit team members. Having a larger team will improve your
|
||||
chances of success.
|
||||
<br />
|
||||
<br />
|
||||
|
@ -74,7 +74,7 @@ for (var i = 0; i < multKeys.length; ++i) {
|
||||
if (mult && mult !== 1) {
|
||||
mult = formatNumber(mult, 3);
|
||||
switch(multKeys[i]) {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,8 +111,8 @@ export const CONSTANTS: {
|
||||
TotalNumBitNodes: number;
|
||||
LatestUpdate: string;
|
||||
} = {
|
||||
VersionString: "1.4.0",
|
||||
VersionNumber: 10,
|
||||
VersionString: "1.5.0",
|
||||
VersionNumber: 11,
|
||||
|
||||
// Speed (in ms) at which the main loop is updated
|
||||
_idleSpeed: 200,
|
||||
@ -273,22 +273,64 @@ export const CONSTANTS: {
|
||||
TotalNumBitNodes: 24,
|
||||
|
||||
LatestUpdate: `
|
||||
v1.4.0 - 2022-01-18 Sharing is caring
|
||||
-------------------------------------
|
||||
v1.5.0 - Steam Cloud integration
|
||||
--------------------------------
|
||||
|
||||
** Computer sharing **
|
||||
** Steam Cloud Saving **
|
||||
|
||||
* A new mechanic has been added, it's is invoked by calling the new function 'share'.
|
||||
This mechanic helps you farm reputation faster.
|
||||
* Added (@MartinFournier)
|
||||
|
||||
** gang **
|
||||
** UI **
|
||||
|
||||
* Installing augs means losing a little bit of ascension multipliers.
|
||||
* background now matches game primary color (@nickofolas)
|
||||
* page title contains version (@MartinFourier)
|
||||
* Major text editor improvements (@nickofolas)
|
||||
* Display bonus time on sleeve page (@MartinFourier)
|
||||
* Several UI improvements (@nickofolas, @smolgumball, @DrCuriosity, @phyzical)
|
||||
* Fix aug display in alpha (@Dominik Winter)
|
||||
* Fix display of corporation product equation (@SagePtr)
|
||||
* Make Bitverse more accessible (@ChrissiQ)
|
||||
* Make corporation warehouse more accessible (@ChrissiQ)
|
||||
* Make tab style more consistent (@nikfolas)
|
||||
|
||||
** There's more but I'm going to write it later. **
|
||||
** Netscript **
|
||||
|
||||
** Misc. **
|
||||
* Fix bug with async.
|
||||
* Add 'printf' ns function (@Ninetailed)
|
||||
* Remove blob caching.
|
||||
* Fix formulas access check (@Ornedan)
|
||||
* Fix bug in exp calculation (@qcorradi)
|
||||
* Fix NaN comparison (@qcorradi)
|
||||
* Fix travelToCity with bad argument (@SlyCedix)
|
||||
* Fix bug where augs could not be purchased via sing (@reacocard)
|
||||
* Fix rounding error in donateToFaction (@Risenafis)
|
||||
* Fix bug with weakenAnalyze (@rhobes)
|
||||
* Prevent exploit with atExit (@Ornedan)
|
||||
* Double 'share' power
|
||||
|
||||
* Nerf noodle bar.
|
||||
** Corporations **
|
||||
|
||||
* Fix bugs with corp API (@pigalot)
|
||||
* Add smart supply func to corp API (@pd)
|
||||
|
||||
** Misc. **
|
||||
|
||||
* The file API now allows GET and DELETE (@lordducky)
|
||||
* Force achievement calculation on BN completion (@SagePtr)
|
||||
* Cleanup in repository (@MartinFourier)
|
||||
* Several improvements to the electron version (@MartinFourier)
|
||||
* Fix bug with casino roulette (@jamie-mac)
|
||||
* Terminal history persists in savefile (@MartinFourier)
|
||||
* Fix tests (@jamie-mac)
|
||||
* Fix crash with electron windows tracker (@smolgumball)
|
||||
* Fix BN6/7 passive reputation gain (@BrianLDev)
|
||||
* Fix Sleeve not resetting on install (@waffleattack)
|
||||
* Sort joined factions (@jjayeon)
|
||||
* Update documentation / typo (@lethern, @Meowdoleon, @JohnnyUrosevic, @JosephDavidTalbot,
|
||||
@pd, @lethern, @lordducky, @zeddrak, @fearnlj01, @reasonablytall, @MatthewTh0,
|
||||
@SagePtr, @manniL, @Jedimaster4559, @loganville, @Arrow2thekn33, @wdpk, @fwolfst,
|
||||
@fschoenfeldt, @Waladil, @AdamTReineke, @citrusmunch, @factubsio, @ashtongreen,
|
||||
@ChrissiQ, @DJ-Laser, @waffleattack, @ApamNapat, @CrafterKolyan, @DSteve595)
|
||||
* Nerf noodle bar.
|
||||
`,
|
||||
};
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { IPlayer } from 'src/PersonObjects/IPlayer';
|
||||
import { MaterialSizes } from './MaterialSizes';
|
||||
import { ICorporation } from "./ICorporation";
|
||||
import { IIndustry } from "./IIndustry";
|
||||
import { IndustryStartingCosts, IndustryResearchTrees } from "./IndustryData";
|
||||
@ -14,12 +16,15 @@ import { EmployeePositions } from "./EmployeePositions";
|
||||
import { Employee } from "./Employee";
|
||||
import { IndustryUpgrades } from "./IndustryUpgrades";
|
||||
import { ResearchMap } from "./ResearchMap";
|
||||
import { isRelevantMaterial } from "./ui/Helpers";
|
||||
|
||||
export function NewIndustry(corporation: ICorporation, industry: string, name: string): void {
|
||||
if (corporation.divisions.find(({ type }) => industry == type))
|
||||
throw new Error(`You have already expanded into the ${industry} industry!`);
|
||||
|
||||
for (let i = 0; i < corporation.divisions.length; ++i) {
|
||||
if (corporation.divisions[i].name === name) {
|
||||
throw new Error("This division name is already in use!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,22 +114,22 @@ export function SellMaterial(mat: Material, amt: string, price: string): void {
|
||||
if (amt.includes("MAX") || amt.includes("PROD")) {
|
||||
let q = amt.replace(/\s+/g, "");
|
||||
q = q.replace(/[^-()\d/*+.MAXPROD]/g, "");
|
||||
let tempQty = q.replace(/MAX/g, "1");
|
||||
tempQty = tempQty.replace(/PROD/g, "1");
|
||||
let tempQty = q.replace(/MAX/g, mat.maxsll.toString());
|
||||
tempQty = tempQty.replace(/PROD/g, mat.prd.toString());
|
||||
try {
|
||||
tempQty = eval(tempQty);
|
||||
} catch (e) {
|
||||
throw new Error("Invalid value or expression for sell price field: " + e);
|
||||
throw new Error("Invalid value or expression for sell quantity field: " + e);
|
||||
}
|
||||
|
||||
if (tempQty == null || isNaN(parseFloat(tempQty)) || parseFloat(tempQty) < 0) {
|
||||
throw new Error("Invalid value or expression for sell price field");
|
||||
throw new Error("Invalid value or expression for sell quantity field");
|
||||
}
|
||||
|
||||
mat.sllman[0] = true;
|
||||
mat.sllman[1] = q; //Use sanitized input
|
||||
} else if (isNaN(parseFloat(amt)) || parseFloat(amt) < 0) {
|
||||
throw new Error("Invalid value for sell quantity field! Must be numeric or 'MAX'");
|
||||
throw new Error("Invalid value for sell quantity field! Must be numeric or 'PROD' or 'MAX'");
|
||||
} else {
|
||||
let q = parseFloat(amt);
|
||||
if (isNaN(q)) {
|
||||
@ -151,10 +156,10 @@ export function SellProduct(product: Product, city: string, amt: string, price:
|
||||
try {
|
||||
temp = eval(temp);
|
||||
} catch (e) {
|
||||
throw new Error("Invalid value or expression for sell quantity field: " + e);
|
||||
throw new Error("Invalid value or expression for sell price field: " + e);
|
||||
}
|
||||
if (temp == null || isNaN(parseFloat(temp)) || parseFloat(temp) < 0) {
|
||||
throw new Error("Invalid value or expression for sell quantity field.");
|
||||
throw new Error("Invalid value or expression for sell price field.");
|
||||
}
|
||||
product.sCost = price; //Use sanitized price
|
||||
} else {
|
||||
@ -174,16 +179,16 @@ export function SellProduct(product: Product, city: string, amt: string, price:
|
||||
//Dynamically evaluated quantity. First test to make sure its valid
|
||||
let qty = amt.replace(/\s+/g, "");
|
||||
qty = qty.replace(/[^-()\d/*+.MAXPROD]/g, "");
|
||||
let temp = qty.replace(/MAX/g, "1");
|
||||
temp = temp.replace(/PROD/g, "1");
|
||||
let temp = qty.replace(/MAX/g, product.maxsll.toString());
|
||||
temp = temp.replace(/PROD/g, product.data[city][1].toString());
|
||||
try {
|
||||
temp = eval(temp);
|
||||
} catch (e) {
|
||||
throw new Error("Invalid value or expression for sell price field: " + e);
|
||||
throw new Error("Invalid value or expression for sell quantity field: " + e);
|
||||
}
|
||||
|
||||
if (temp == null || isNaN(parseFloat(temp)) || parseFloat(temp) < 0) {
|
||||
throw new Error("Invalid value or expression for sell price field");
|
||||
throw new Error("Invalid value or expression for sell quantity field");
|
||||
}
|
||||
if (all) {
|
||||
for (let i = 0; i < cities.length; ++i) {
|
||||
@ -196,7 +201,7 @@ export function SellProduct(product: Product, city: string, amt: string, price:
|
||||
product.sllman[city][1] = qty; //Use sanitized input
|
||||
}
|
||||
} else if (isNaN(parseFloat(amt)) || parseFloat(amt) < 0) {
|
||||
throw new Error("Invalid value for sell quantity field! Must be numeric");
|
||||
throw new Error("Invalid value for sell quantity field! Must be numeric or 'PROD' or 'MAX'");
|
||||
} else {
|
||||
let qty = parseFloat(amt);
|
||||
if (isNaN(qty)) {
|
||||
@ -213,8 +218,7 @@ export function SellProduct(product: Product, city: string, amt: string, price:
|
||||
product.sllman[city][0] = false;
|
||||
product.sllman[city][1] = "";
|
||||
}
|
||||
} else {
|
||||
if (all) {
|
||||
} else if (all) {
|
||||
for (let i = 0; i < cities.length; ++i) {
|
||||
const tempCity = cities[i];
|
||||
product.sllman[tempCity][0] = true;
|
||||
@ -224,7 +228,6 @@ export function SellProduct(product: Product, city: string, amt: string, price:
|
||||
product.sllman[city][0] = true;
|
||||
product.sllman[city][1] = qty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,6 +248,57 @@ export function BuyMaterial(material: Material, amt: number): void {
|
||||
material.buy = amt;
|
||||
}
|
||||
|
||||
export function BulkPurchase(corp: ICorporation, warehouse: Warehouse, material: Material, amt: number): void {
|
||||
const matSize = MaterialSizes[material.name];
|
||||
const maxAmount = (warehouse.size - warehouse.sizeUsed) / matSize;
|
||||
if (isNaN(amt) || amt < 0) {
|
||||
throw new Error(`Invalid input amount`);
|
||||
}
|
||||
if (amt * matSize > maxAmount) {
|
||||
throw new Error(`You do not have enough warehouse size to fit this purchase`);
|
||||
}
|
||||
const cost = amt * material.bCost;
|
||||
if (corp.funds >= cost) {
|
||||
corp.funds = corp.funds - cost;
|
||||
material.qty += amt;
|
||||
} else {
|
||||
throw new Error(`You cannot afford this purchase.`);
|
||||
}
|
||||
}
|
||||
|
||||
export function SellShares(corporation: ICorporation, player: IPlayer, numShares: number): number {
|
||||
if (isNaN(numShares)) throw new Error("Invalid value for number of shares");
|
||||
if (numShares < 0) throw new Error("Invalid value for number of shares");
|
||||
if (numShares > corporation.numShares) throw new Error("You don't have that many shares to sell!");
|
||||
if (!corporation.public) throw new Error("You haven't gone public!");
|
||||
if (corporation.shareSaleCooldown) throw new Error("Share sale on cooldown!");
|
||||
const stockSaleResults = corporation.calculateShareSale(numShares);
|
||||
const profit = stockSaleResults[0];
|
||||
const newSharePrice = stockSaleResults[1];
|
||||
const newSharesUntilUpdate = stockSaleResults[2];
|
||||
|
||||
corporation.numShares -= numShares;
|
||||
corporation.issuedShares += numShares;
|
||||
corporation.sharePrice = newSharePrice;
|
||||
corporation.shareSalesUntilPriceUpdate = newSharesUntilUpdate;
|
||||
corporation.shareSaleCooldown = CorporationConstants.SellSharesCooldown;
|
||||
player.gainMoney(profit, "corporation");
|
||||
return profit;
|
||||
}
|
||||
|
||||
export function BuyBackShares(corporation: ICorporation, player: IPlayer, numShares: number): boolean {
|
||||
if (isNaN(numShares)) throw new Error("Invalid value for number of shares");
|
||||
if (numShares < 0) throw new Error("Invalid value for number of shares");
|
||||
if (numShares > corporation.issuedShares) throw new Error("You don't have that many shares to buy!");
|
||||
if (!corporation.public) throw new Error("You haven't gone public!");
|
||||
const buybackPrice = corporation.sharePrice * 1.1;
|
||||
if (player.money < (numShares * buybackPrice)) throw new Error("You cant afford that many shares!");
|
||||
corporation.numShares += numShares;
|
||||
corporation.issuedShares -= numShares;
|
||||
player.loseMoney(numShares * buybackPrice, "corporation");
|
||||
return true;
|
||||
}
|
||||
|
||||
export function AssignJob(employee: Employee, job: string): void {
|
||||
if (!Object.values(EmployeePositions).includes(job)) throw new Error(`'${job}' is not a valid job.`);
|
||||
employee.pos = job;
|
||||
@ -290,6 +344,7 @@ export function PurchaseWarehouse(corp: ICorporation, division: IIndustry, city:
|
||||
|
||||
export function UpgradeWarehouse(corp: ICorporation, division: IIndustry, warehouse: Warehouse): void {
|
||||
const sizeUpgradeCost = CorporationConstants.WarehouseUpgradeBaseCost * Math.pow(1.07, warehouse.level + 1);
|
||||
if (corp.funds < sizeUpgradeCost) return;
|
||||
++warehouse.level;
|
||||
warehouse.updateSize(corp, division);
|
||||
corp.funds = corp.funds - sizeUpgradeCost;
|
||||
@ -334,6 +389,9 @@ export function MakeProduct(
|
||||
if (productName == null || productName === "") {
|
||||
throw new Error("You must specify a name for your product!");
|
||||
}
|
||||
if (!division.makesProducts) {
|
||||
throw new Error("You cannot create products for this industry!");
|
||||
}
|
||||
if (isNaN(designInvest)) {
|
||||
throw new Error("Invalid value for design investment");
|
||||
}
|
||||
@ -343,17 +401,29 @@ export function MakeProduct(
|
||||
if (corp.funds < designInvest + marketingInvest) {
|
||||
throw new Error("You don't have enough company funds to make this large of an investment");
|
||||
}
|
||||
let maxProducts = 3
|
||||
if (division.hasResearch("uPgrade: Capacity.II")) {
|
||||
maxProducts = 5
|
||||
} else if (division.hasResearch("uPgrade: Capacity.I")) {
|
||||
maxProducts = 4
|
||||
}
|
||||
const products = division.products
|
||||
if (Object.keys(products).length >= maxProducts) {
|
||||
throw new Error(`You are already at the max products (${maxProducts}) for division: ${division.name}!`);
|
||||
}
|
||||
|
||||
const product = new Product({
|
||||
name: productName.replace(/[<>]/g, ""), //Sanitize for HTMl elements
|
||||
createCity: city,
|
||||
designCost: designInvest,
|
||||
advCost: marketingInvest,
|
||||
});
|
||||
if (division.products[product.name] instanceof Product) {
|
||||
if (products[product.name] instanceof Product) {
|
||||
throw new Error(`You already have a product with this name!`);
|
||||
}
|
||||
|
||||
corp.funds = corp.funds - (designInvest + marketingInvest);
|
||||
division.products[product.name] = product;
|
||||
products[product.name] = product;
|
||||
}
|
||||
|
||||
export function Research(division: IIndustry, researchName: string): void {
|
||||
@ -372,7 +442,7 @@ export function Research(division: IIndustry, researchName: string): void {
|
||||
division.researched[researchName] = true;
|
||||
}
|
||||
|
||||
export function ExportMaterial(divisionName: string, cityName: string, material: Material, amt: string): void {
|
||||
export function ExportMaterial(divisionName: string, cityName: string, material: Material, amt: string, division?: Industry): void {
|
||||
// Sanitize amt
|
||||
let sanitizedAmt = amt.replace(/\s+/g, "").toUpperCase();
|
||||
sanitizedAmt = sanitizedAmt.replace(/[^-()\d/*+.MAX]/g, "");
|
||||
@ -388,6 +458,11 @@ export function ExportMaterial(divisionName: string, cityName: string, material:
|
||||
if (n == null || isNaN(n) || n < 0) {
|
||||
throw new Error("Invalid amount entered for export");
|
||||
}
|
||||
|
||||
if (!division || !isRelevantMaterial(material.name, division)) {
|
||||
throw new Error(`You cannot export material: ${material.name} to division: ${divisionName}!`);
|
||||
}
|
||||
|
||||
const exportObj = { ind: divisionName, city: cityName, amt: sanitizedAmt };
|
||||
material.exp.push(exportObj);
|
||||
}
|
||||
|
@ -828,7 +828,7 @@ export class Industry implements IIndustry {
|
||||
}
|
||||
}
|
||||
|
||||
const maxSell =
|
||||
mat.maxsll =
|
||||
(mat.qlt + 0.001) *
|
||||
marketFactor *
|
||||
markup *
|
||||
@ -839,7 +839,7 @@ export class Industry implements IIndustry {
|
||||
let sellAmt;
|
||||
if (isString(mat.sllman[1])) {
|
||||
//Dynamically evaluated
|
||||
let tmp = (mat.sllman[1] as string).replace(/MAX/g, (maxSell + "").toUpperCase());
|
||||
let tmp = (mat.sllman[1] as string).replace(/MAX/g, (mat.maxsll + "").toUpperCase());
|
||||
tmp = tmp.replace(/PROD/g, mat.prd + "");
|
||||
try {
|
||||
sellAmt = eval(tmp);
|
||||
@ -856,13 +856,13 @@ export class Industry implements IIndustry {
|
||||
);
|
||||
sellAmt = 0;
|
||||
}
|
||||
sellAmt = Math.min(maxSell, sellAmt);
|
||||
sellAmt = Math.min(mat.maxsll, sellAmt);
|
||||
} else if (mat.sllman[1] === -1) {
|
||||
//Backwards compatibility, -1 = MAX
|
||||
sellAmt = maxSell;
|
||||
sellAmt = mat.maxsll;
|
||||
} else {
|
||||
//Player's input value is just a number
|
||||
sellAmt = Math.min(maxSell, mat.sllman[1] as number);
|
||||
sellAmt = Math.min(mat.maxsll, mat.sllman[1] as number);
|
||||
}
|
||||
|
||||
sellAmt = sellAmt * CorporationConstants.SecsPerMarketCycle * marketCycles;
|
||||
@ -1188,8 +1188,7 @@ export class Industry implements IIndustry {
|
||||
}
|
||||
}
|
||||
|
||||
const maxSell =
|
||||
0.5 *
|
||||
product.maxsll = 0.5 *
|
||||
Math.pow(product.rat, 0.65) *
|
||||
marketFactor *
|
||||
corporation.getSalesMultiplier() *
|
||||
@ -1200,7 +1199,7 @@ export class Industry implements IIndustry {
|
||||
let sellAmt;
|
||||
if (product.sllman[city][0] && isString(product.sllman[city][1])) {
|
||||
//Sell amount is dynamically evaluated
|
||||
let tmp = product.sllman[city][1].replace(/MAX/g, (maxSell + "").toUpperCase());
|
||||
let tmp = product.sllman[city][1].replace(/MAX/g, (product.maxsll + "").toUpperCase());
|
||||
tmp = tmp.replace(/PROD/g, product.data[city][1]);
|
||||
try {
|
||||
tmp = eval(tmp);
|
||||
@ -1214,16 +1213,16 @@ export class Industry implements IIndustry {
|
||||
city +
|
||||
" office. Sell price is being set to MAX",
|
||||
);
|
||||
tmp = maxSell;
|
||||
tmp = product.maxsll;
|
||||
}
|
||||
sellAmt = Math.min(maxSell, tmp);
|
||||
sellAmt = Math.min(product.maxsll, tmp);
|
||||
} else if (product.sllman[city][0] && product.sllman[city][1] > 0) {
|
||||
//Sell amount is manually limited
|
||||
sellAmt = Math.min(maxSell, product.sllman[city][1]);
|
||||
sellAmt = Math.min(product.maxsll, product.sllman[city][1]);
|
||||
} else if (product.sllman[city][0] === false) {
|
||||
sellAmt = 0;
|
||||
} else {
|
||||
sellAmt = maxSell;
|
||||
sellAmt = product.maxsll;
|
||||
}
|
||||
if (sellAmt < 0) {
|
||||
sellAmt = 0;
|
||||
@ -1286,7 +1285,7 @@ export class Industry implements IIndustry {
|
||||
this.awareness = Math.min(awareness, Number.MAX_VALUE);
|
||||
|
||||
const popularity = (this.popularity + (1 * advMult)) * ((1 + getRandomInt(1, 3) / 100) * advMult);
|
||||
this.popularity = Math.min(popularity, Number.MAX_VALUE);
|
||||
this.popularity = Math.min(popularity, Number.MAX_VALUE);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
@ -227,13 +227,13 @@ export function resetIndustryResearchTrees(): void {
|
||||
IndustryResearchTrees.Agriculture = getBaseResearchTreeCopy();
|
||||
IndustryResearchTrees.Fishing = getBaseResearchTreeCopy();
|
||||
IndustryResearchTrees.Mining = getBaseResearchTreeCopy();
|
||||
IndustryResearchTrees.Food = getBaseResearchTreeCopy();
|
||||
IndustryResearchTrees.Tobacco = getBaseResearchTreeCopy();
|
||||
IndustryResearchTrees.Food = getProductIndustryResearchTreeCopy();
|
||||
IndustryResearchTrees.Tobacco = getProductIndustryResearchTreeCopy();
|
||||
IndustryResearchTrees.Chemical = getBaseResearchTreeCopy();
|
||||
IndustryResearchTrees.Pharmaceutical = getBaseResearchTreeCopy();
|
||||
IndustryResearchTrees.Computer = getBaseResearchTreeCopy();
|
||||
IndustryResearchTrees.Robotics = getBaseResearchTreeCopy();
|
||||
IndustryResearchTrees.Software = getBaseResearchTreeCopy();
|
||||
IndustryResearchTrees.Healthcare = getBaseResearchTreeCopy();
|
||||
IndustryResearchTrees.RealEstate = getBaseResearchTreeCopy();
|
||||
IndustryResearchTrees.Pharmaceutical = getProductIndustryResearchTreeCopy();
|
||||
IndustryResearchTrees.Computer = getProductIndustryResearchTreeCopy();
|
||||
IndustryResearchTrees.Robotics = getProductIndustryResearchTreeCopy();
|
||||
IndustryResearchTrees.Software = getProductIndustryResearchTreeCopy();
|
||||
IndustryResearchTrees.Healthcare = getProductIndustryResearchTreeCopy();
|
||||
IndustryResearchTrees.RealEstate = getProductIndustryResearchTreeCopy();
|
||||
}
|
||||
|
@ -62,6 +62,9 @@ export class Material {
|
||||
marketTa2 = false;
|
||||
marketTa2Price = 0;
|
||||
|
||||
// Determines the maximum amount of this material that can be sold in one market cycle
|
||||
maxsll = 0;
|
||||
|
||||
constructor(params: IConstructorParams = {}) {
|
||||
if (params.name) {
|
||||
this.name = params.name;
|
||||
|
@ -174,37 +174,19 @@ export class OfficeSpace {
|
||||
}
|
||||
|
||||
setEmployeeToJob(job: string, amount: number): boolean {
|
||||
let unassignedCount = 0;
|
||||
let jobCount = 0;
|
||||
for (let i = 0; i < this.employees.length; ++i) {
|
||||
if (this.employees[i].pos === EmployeePositions.Unassigned) {
|
||||
unassignedCount++;
|
||||
} else if (this.employees[i].pos === job) {
|
||||
let jobCount = this.employees.reduce((acc, employee) => (employee.pos === job ? acc + 1 : acc), 0);
|
||||
|
||||
for (const employee of this.employees) {
|
||||
if (jobCount == amount) return true
|
||||
if (employee.pos === EmployeePositions.Unassigned && jobCount <= amount) {
|
||||
employee.pos = job;
|
||||
jobCount++;
|
||||
} else if (employee.pos === job && jobCount >= amount) {
|
||||
employee.pos = EmployeePositions.Unassigned;
|
||||
jobCount--;
|
||||
}
|
||||
}
|
||||
|
||||
if ((jobCount + unassignedCount) < amount) return false;
|
||||
|
||||
for (let i = 0; i < this.employees.length; ++i) {
|
||||
if (this.employees[i].pos === EmployeePositions.Unassigned) {
|
||||
if (jobCount <= amount) {
|
||||
this.employees[i].pos = job;
|
||||
jobCount++;
|
||||
unassignedCount--;
|
||||
}
|
||||
if (jobCount === amount) break;
|
||||
} else if (this.employees[i].pos === job) {
|
||||
if (jobCount >= amount) {
|
||||
this.employees[i].pos = EmployeePositions.Unassigned;
|
||||
jobCount--;
|
||||
unassignedCount++;
|
||||
}
|
||||
if (jobCount === amount) break;
|
||||
}
|
||||
}
|
||||
if (jobCount !== amount) return false;
|
||||
return true;
|
||||
return jobCount === amount;
|
||||
}
|
||||
|
||||
toJSON(): any {
|
||||
|
@ -96,6 +96,8 @@ export class Product {
|
||||
marketTa2 = false;
|
||||
marketTa2Price: IMap<number> = createCityMap<number>(0);
|
||||
|
||||
// Determines the maximum amount of this product that can be sold in one market cycle
|
||||
maxsll = 0;
|
||||
constructor(params: IConstructorParams = {}) {
|
||||
this.name = params.name ? params.name : "";
|
||||
this.dmd = params.demand ? params.demand : 0;
|
||||
|
@ -106,7 +106,7 @@ export const researchMetadata: IConstructorParams[] = [
|
||||
{
|
||||
name: "JoyWire",
|
||||
cost: 20e3,
|
||||
desc: "A brain implant which is installed in employees, increasing their " + "maximum happiness by 10.",
|
||||
desc: "A brain implant which is installed in employees, increasing their maximum happiness by 10.",
|
||||
},
|
||||
{
|
||||
name: "Market-TA.I",
|
||||
@ -160,7 +160,7 @@ export const researchMetadata: IConstructorParams[] = [
|
||||
{
|
||||
name: "sudo.Assist",
|
||||
cost: 15e3,
|
||||
desc: "Develop a virtual assistant AI to handle and manage administrative " + "issues for your corporation.",
|
||||
desc: "Develop a virtual assistant AI to handle and manage administrative issues for your corporation.",
|
||||
},
|
||||
{
|
||||
name: "uPgrade: Capacity.I",
|
||||
|
@ -6,6 +6,8 @@ import { useCorporation } from "./Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import { BuyBackShares } from '../Actions';
|
||||
import { dialogBoxCreate } from '../../ui/React/DialogBox';
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
@ -36,20 +38,12 @@ export function BuybackSharesModal(props: IProps): React.ReactElement {
|
||||
|
||||
function buy(): void {
|
||||
if (disabled) return;
|
||||
if (shares === null) return;
|
||||
corp.numShares += shares;
|
||||
if (isNaN(corp.issuedShares)) {
|
||||
console.warn("Corporation issuedShares is NaN: " + corp.issuedShares);
|
||||
console.warn("Converting to number now");
|
||||
const res = corp.issuedShares;
|
||||
if (isNaN(res)) {
|
||||
corp.issuedShares = 0;
|
||||
} else {
|
||||
corp.issuedShares = res;
|
||||
}
|
||||
try {
|
||||
BuyBackShares(corp, player, shares)
|
||||
}
|
||||
catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
}
|
||||
corp.issuedShares -= shares;
|
||||
player.loseMoney(shares * buybackPrice, "corporation");
|
||||
props.onClose();
|
||||
props.rerender();
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ export function CityTabs(props: IProps): React.ReactElement {
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Tabs variant="fullWidth" value={city} onChange={handleChange}>
|
||||
<Tabs variant="fullWidth" value={city} onChange={handleChange} sx={{ maxWidth: '65%' }}>
|
||||
{Object.values(division.offices).map(
|
||||
(office: OfficeSpace | 0) => office !== 0 && <Tab key={office.loc} label={office.loc} value={office.loc} />,
|
||||
)}
|
||||
|
@ -38,7 +38,7 @@ export function CorporationRoot(): React.ReactElement {
|
||||
|
||||
return (
|
||||
<Context.Corporation.Provider value={corporation}>
|
||||
<Tabs variant="fullWidth" value={divisionName} onChange={handleChange}>
|
||||
<Tabs variant="scrollable" value={divisionName} onChange={handleChange} sx={{ maxWidth: '65%' }} scrollButtons>
|
||||
<Tab label={corporation.name} value={"Overview"} />
|
||||
{corporation.divisions.map((div) => (
|
||||
<Tab key={div.name} label={div.name} value={div.name} />
|
||||
|
@ -6,6 +6,7 @@ import { IIndustry } from "../IIndustry";
|
||||
import { ExportMaterial } from "../Actions";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { useCorporation } from "./Context";
|
||||
import { isRelevantMaterial } from "./Helpers";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
@ -22,11 +23,13 @@ interface IProps {
|
||||
// Create a popup that lets the player manage exports
|
||||
export function ExportModal(props: IProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
if (corp.divisions.length === 0) throw new Error("Export popup created with no divisions.");
|
||||
if (Object.keys(corp.divisions[0].warehouses).length === 0)
|
||||
const possibleDivisions = corp.divisions.filter((division: IIndustry) => isRelevantMaterial(props.mat.name, division));
|
||||
if (possibleDivisions.length === 0) throw new Error("Export popup created with no divisions.");
|
||||
const defaultDivision = possibleDivisions[0];
|
||||
if (Object.keys(defaultDivision.warehouses).length === 0)
|
||||
throw new Error("Export popup created in a division with no warehouses.");
|
||||
const [industry, setIndustry] = useState<string>(corp.divisions[0].name);
|
||||
const [city, setCity] = useState<string>(Object.keys(corp.divisions[0].warehouses)[0]);
|
||||
const [industry, setIndustry] = useState<string>(defaultDivision.name);
|
||||
const [city, setCity] = useState<string>(Object.keys(defaultDivision.warehouses)[0]);
|
||||
const [amt, setAmt] = useState("");
|
||||
const setRerender = useState(false)[1];
|
||||
|
||||
@ -50,7 +53,7 @@ export function ExportModal(props: IProps): React.ReactElement {
|
||||
|
||||
function exportMaterial(): void {
|
||||
try {
|
||||
ExportMaterial(industry, city, props.mat, amt);
|
||||
ExportMaterial(industry, city, props.mat, amt, currentDivision);
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
}
|
||||
@ -84,10 +87,12 @@ export function ExportModal(props: IProps): React.ReactElement {
|
||||
second. You can set the export amount to 'MAX' to export all of the materials in this warehouse.
|
||||
</Typography>
|
||||
<Select onChange={onIndustryChange} value={industry}>
|
||||
{corp.divisions.map((division: IIndustry) => (
|
||||
<MenuItem key={division.name} value={division.name}>
|
||||
{division.name}
|
||||
</MenuItem>
|
||||
{corp.divisions
|
||||
.filter((division: IIndustry) => isRelevantMaterial(props.mat.name, division))
|
||||
.map((division: IIndustry) => (
|
||||
<MenuItem key={division.name} value={division.name}>
|
||||
{division.name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
<Select onChange={onCityChange} value={city}>
|
||||
|
@ -4,7 +4,7 @@ import { IIndustry } from "../IIndustry";
|
||||
// current industry.
|
||||
export function isRelevantMaterial(matName: string, division: IIndustry): boolean {
|
||||
// Materials that affect Production multiplier
|
||||
const prodMultiplierMats = ["Hardware", "Robots", "AICores", "RealEstate"];
|
||||
const prodMultiplierMats = ["Hardware", "Robots", "AICores", "RealEstate", "AI Cores", "Real Estate"];
|
||||
|
||||
if (Object.keys(division.reqMats).includes(matName)) {
|
||||
return true;
|
||||
|
@ -13,12 +13,12 @@ export function IndustryProductEquation(props: IProps): React.ReactElement {
|
||||
if (reqAmt === undefined) continue;
|
||||
reqs.push(String.raw`${reqAmt}\text{ }${reqMat}`);
|
||||
}
|
||||
const prod = props.division.prodMats.slice();
|
||||
const prod = props.division.prodMats.map((p) => `1\\text{ }${p}`);
|
||||
if (props.division.makesProducts) {
|
||||
prod.push(props.division.type);
|
||||
prod.push("Products");
|
||||
}
|
||||
|
||||
return (
|
||||
<MathJaxWrapper>{"\\(" + reqs.join("+") + `\\Rightarrow` + prod.map((p) => `1 \\text{${p}}`).join("+") + "\\)"}</MathJaxWrapper>
|
||||
<MathJaxWrapper>{"\\(" + reqs.join("+") + `\\Rightarrow ` + prod.join("+") + "\\)"}</MathJaxWrapper>
|
||||
);
|
||||
}
|
||||
|
@ -27,6 +27,8 @@ import Tooltip from "@mui/material/Tooltip";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import Button from "@mui/material/Button";
|
||||
import Box from "@mui/material/Box";
|
||||
import makeStyles from "@mui/styles/makeStyles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
|
||||
interface IProps {
|
||||
corp: ICorporation;
|
||||
@ -37,6 +39,14 @@ interface IProps {
|
||||
rerender: () => void;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(() =>
|
||||
createStyles({
|
||||
retainHeight: {
|
||||
minHeight: '3em',
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
function WarehouseRoot(props: IProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const division = useDivision();
|
||||
@ -56,6 +66,8 @@ function WarehouseRoot(props: IProps): React.ReactElement {
|
||||
props.rerender();
|
||||
}
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
// Current State:
|
||||
let stateText;
|
||||
switch (division.state) {
|
||||
@ -83,8 +95,10 @@ function WarehouseRoot(props: IProps): React.ReactElement {
|
||||
const mats = [];
|
||||
for (const matName of Object.keys(props.warehouse.materials)) {
|
||||
if (!(props.warehouse.materials[matName] instanceof Material)) continue;
|
||||
// Only create UI for materials that are relevant for the industry
|
||||
if (!isRelevantMaterial(matName, division)) continue;
|
||||
// Only create UI for materials that are relevant for the industry or in stock
|
||||
const isInStock = props.warehouse.materials[matName].qty > 0;
|
||||
const isRelevant = isRelevantMaterial(matName, division);
|
||||
if (!isInStock && !isRelevant) continue;
|
||||
mats.push(
|
||||
<MaterialElem
|
||||
rerender={props.rerender}
|
||||
@ -158,7 +172,7 @@ function WarehouseRoot(props: IProps): React.ReactElement {
|
||||
</Typography>
|
||||
<br />
|
||||
|
||||
<Typography>{stateText}</Typography>
|
||||
<Typography className={classes.retainHeight}>{stateText}</Typography>
|
||||
|
||||
{corp.unlockUpgrades[1] && (
|
||||
<>
|
||||
|
@ -36,7 +36,7 @@ export function LimitProductProductionModal(props: IProps): React.ReactElement {
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography>
|
||||
Enter a limit to the amount of this product you would like to product per second. Leave the box empty to set no
|
||||
Enter a limit to the amount of this product you would like to produce per second. Leave the box empty to set no
|
||||
limit.
|
||||
</Typography>
|
||||
<TextField autoFocus={true} placeholder="Limit" type="number" onChange={onChange} onKeyDown={onKeyDown} />
|
||||
|
@ -4,7 +4,7 @@ import { MaterialSizes } from "../MaterialSizes";
|
||||
import { Warehouse } from "../Warehouse";
|
||||
import { Material } from "../Material";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { BuyMaterial } from "../Actions";
|
||||
import { BulkPurchase, BuyMaterial } from "../Actions";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { useCorporation, useDivision } from "./Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
@ -54,33 +54,17 @@ interface IBPProps {
|
||||
warehouse: Warehouse;
|
||||
}
|
||||
|
||||
function BulkPurchase(props: IBPProps): React.ReactElement {
|
||||
function BulkPurchaseSection(props: IBPProps): React.ReactElement {
|
||||
const corp = useCorporation();
|
||||
const [buyAmt, setBuyAmt] = useState("");
|
||||
|
||||
function bulkPurchase(): void {
|
||||
const amount = parseFloat(buyAmt);
|
||||
|
||||
const matSize = MaterialSizes[props.mat.name];
|
||||
const maxAmount = (props.warehouse.size - props.warehouse.sizeUsed) / matSize;
|
||||
if (amount * matSize > maxAmount) {
|
||||
dialogBoxCreate(`You do not have enough warehouse size to fit this purchase`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNaN(amount) || amount < 0) {
|
||||
dialogBoxCreate("Invalid input amount");
|
||||
} else {
|
||||
const cost = amount * props.mat.bCost;
|
||||
if (corp.funds >= cost) {
|
||||
corp.funds = corp.funds - cost;
|
||||
props.mat.qty += amount;
|
||||
} else {
|
||||
dialogBoxCreate(`You cannot afford this purchase.`);
|
||||
return;
|
||||
}
|
||||
props.onClose();
|
||||
try {
|
||||
BulkPurchase(corp, props.warehouse, props.mat, parseFloat(buyAmt));
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
}
|
||||
props.onClose();
|
||||
}
|
||||
|
||||
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||
@ -164,7 +148,7 @@ export function PurchaseMaterialModal(props: IProps): React.ReactElement {
|
||||
<Button onClick={purchaseMaterial}>Confirm</Button>
|
||||
<Button onClick={clearPurchase}>Clear Purchase</Button>
|
||||
{division.hasResearch("Bulk Purchasing") && (
|
||||
<BulkPurchase onClose={props.onClose} mat={props.mat} warehouse={props.warehouse} />
|
||||
<BulkPurchaseSection onClose={props.onClose} mat={props.mat} warehouse={props.warehouse} />
|
||||
)}
|
||||
</>
|
||||
</Modal>
|
||||
|
@ -4,12 +4,12 @@ import { dialogBoxCreate } from "../../ui/React/DialogBox";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { use } from "../../ui/Context";
|
||||
import { useCorporation } from "./Context";
|
||||
import { CorporationConstants } from "../data/Constants";
|
||||
import { ICorporation } from "../ICorporation";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import Button from "@mui/material/Button";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { SellShares } from "../Actions";
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
@ -48,38 +48,23 @@ export function SellSharesModal(props: IProps): React.ReactElement {
|
||||
}
|
||||
|
||||
function sell(): void {
|
||||
if (shares === null) return;
|
||||
if (disabled) return;
|
||||
const stockSaleResults = corp.calculateShareSale(shares);
|
||||
const profit = stockSaleResults[0];
|
||||
const newSharePrice = stockSaleResults[1];
|
||||
const newSharesUntilUpdate = stockSaleResults[2];
|
||||
try {
|
||||
const profit = SellShares(corp, player, shares)
|
||||
props.onClose();
|
||||
dialogBoxCreate(
|
||||
<>
|
||||
Sold {numeralWrapper.formatMoney(shares)} shares for
|
||||
<Money money={profit} />. The corporation's stock price fell to <Money money={corp.sharePrice} />
|
||||
as a result of dilution.
|
||||
</>,
|
||||
);
|
||||
|
||||
corp.numShares -= shares;
|
||||
if (isNaN(corp.issuedShares)) {
|
||||
console.error(`Corporation issuedShares is NaN: ${corp.issuedShares}`);
|
||||
const res = corp.issuedShares;
|
||||
if (isNaN(res)) {
|
||||
corp.issuedShares = 0;
|
||||
} else {
|
||||
corp.issuedShares = res;
|
||||
}
|
||||
props.rerender();
|
||||
} catch (err) {
|
||||
dialogBoxCreate(err + "");
|
||||
}
|
||||
corp.issuedShares += shares;
|
||||
corp.sharePrice = newSharePrice;
|
||||
corp.shareSalesUntilPriceUpdate = newSharesUntilUpdate;
|
||||
corp.shareSaleCooldown = CorporationConstants.SellSharesCooldown;
|
||||
player.gainMoney(profit, "corporation");
|
||||
props.onClose();
|
||||
dialogBoxCreate(
|
||||
<>
|
||||
Sold {numeralWrapper.formatMoney(shares)} shares for
|
||||
<Money money={profit} />. The corporation's stock price fell to <Money money={corp.sharePrice} />
|
||||
as a result of dilution.
|
||||
</>,
|
||||
);
|
||||
|
||||
props.rerender();
|
||||
}
|
||||
|
||||
function onKeyDown(event: React.KeyboardEvent<HTMLInputElement>): void {
|
||||
|
@ -33,8 +33,7 @@ export function ThrowPartyModal(props: IProps): React.ReactElement {
|
||||
function throwParty(): void {
|
||||
if (cost === null || isNaN(cost) || cost < 0) {
|
||||
dialogBoxCreate("Invalid value entered");
|
||||
} else {
|
||||
if (!canParty) {
|
||||
} else if (!canParty) {
|
||||
dialogBoxCreate("You don't have enough company funds to throw a party!");
|
||||
} else {
|
||||
const mult = ThrowParty(corp, props.office, cost);
|
||||
@ -46,7 +45,6 @@ export function ThrowPartyModal(props: IProps): React.ReactElement {
|
||||
props.rerender();
|
||||
props.onClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function EffectText(): React.ReactElement {
|
||||
|
@ -23,7 +23,7 @@ export function StaneksGiftRoot({ staneksGift }: IProps): React.ReactElement {
|
||||
The gift is a grid on which you can place upgrades called fragments. The main type of fragment increases a stat,
|
||||
like your hacking skill or agility exp. Once a stat fragment is placed it then needs to be charged via scripts
|
||||
in order to become useful. The other kind of fragments are called booster fragments. They increase the
|
||||
efficiency of neighboring fragments them (no diagonal). Q/E to rotate fragments.
|
||||
efficiency of the neighboring fragments (not diagonally). Use Q/E to rotate fragments.
|
||||
</Typography>
|
||||
{staneksGift.storedCycles > 5 && (
|
||||
<Typography>
|
||||
|
@ -20,14 +20,7 @@ export function determineCrimeSuccess(p: IPlayer, type: string): boolean {
|
||||
dialogBoxCreate(`ERR: Unrecognized crime type: ${type} This is probably a bug please contact the developer`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Math.random() <= chance) {
|
||||
//Success
|
||||
return true;
|
||||
} else {
|
||||
//Failure
|
||||
return false;
|
||||
}
|
||||
return Math.random() <= chance;
|
||||
}
|
||||
|
||||
export function findCrime(roughName: string): Crime | null {
|
||||
|
@ -19,10 +19,18 @@ interface IProps {
|
||||
export function Corporation(props: IProps): React.ReactElement {
|
||||
function addTonsCorporationFunds(): void {
|
||||
if (props.player.corporation) {
|
||||
props.player.corporation.funds = props.player.corporation.funds + 1e99;
|
||||
props.player.corporation.funds = props.player.corporation.funds + bigNumber;
|
||||
}
|
||||
}
|
||||
|
||||
function modifyCorporationFunds(modify: number): (x: number) => void {
|
||||
return function (funds: number): void {
|
||||
if (props.player.corporation) {
|
||||
props.player.corporation.funds += funds * modify;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function resetCorporationFunds(): void {
|
||||
if (props.player.corporation) {
|
||||
props.player.corporation.funds = props.player.corporation.funds - props.player.corporation.funds;
|
||||
@ -77,8 +85,17 @@ export function Corporation(props: IProps): React.ReactElement {
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<Button onClick={addTonsCorporationFunds}>Tons of funds</Button>
|
||||
<Button onClick={resetCorporationFunds}>Reset funds</Button>
|
||||
<Typography>Funds:</Typography>
|
||||
</td>
|
||||
<td>
|
||||
<Adjuster
|
||||
label="set funds"
|
||||
placeholder="amt"
|
||||
tons={addTonsCorporationFunds}
|
||||
add={modifyCorporationFunds(1)}
|
||||
subtract={modifyCorporationFunds(-1)}
|
||||
reset={resetCorporationFunds}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -1,13 +1,10 @@
|
||||
import { Player } from "./Player";
|
||||
import { Router } from "./ui/GameRoot";
|
||||
import { isScriptFilename } from "./Script/isScriptFilename";
|
||||
import { Script } from "./Script/Script";
|
||||
import { removeLeadingSlash } from "./Terminal/DirectoryHelpers";
|
||||
import { Terminal } from "./Terminal";
|
||||
import { SnackbarEvents } from "./ui/React/Snackbar";
|
||||
import { IMap, IReturnStatus } from "./types";
|
||||
import { GetServer } from "./Server/AllServers";
|
||||
import { resolve } from "cypress/types/bluebird";
|
||||
import { ImportPlayerData, SaveData, saveObject } from "./SaveObject";
|
||||
import { Settings } from "./Settings/Settings";
|
||||
import { exportScripts } from "./Terminal/commands/download";
|
||||
|
@ -19,6 +19,8 @@ export enum Exploit {
|
||||
RealityAlteration = "RealityAlteration",
|
||||
N00dles = "N00dles",
|
||||
YoureNotMeantToAccessThis = "YoureNotMeantToAccessThis",
|
||||
TrueRecursion = "TrueRecursion",
|
||||
INeedARainbow = "INeedARainbow",
|
||||
// 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.
|
||||
@ -37,6 +39,8 @@ const names: {
|
||||
RealityAlteration: "by altering reality to suit your whims.",
|
||||
N00dles: "by harnessing the power of the n00dles.",
|
||||
YoureNotMeantToAccessThis: "by accessing the dev menu.",
|
||||
TrueRecursion: "by truly recursing.",
|
||||
INeedARainbow: "by using the power of the rainbow.",
|
||||
};
|
||||
|
||||
export function ExploitName(exploit: string): string {
|
||||
|
@ -6,8 +6,7 @@ export let LastExportBonus = 0;
|
||||
const bonusTimer = 24 * 60 * 60 * 1000; // 24h
|
||||
export function canGetBonus(): boolean {
|
||||
const now = new Date().getTime();
|
||||
if (now - LastExportBonus > bonusTimer) return true;
|
||||
return false;
|
||||
return now - LastExportBonus > bonusTimer;
|
||||
}
|
||||
|
||||
export function onExport(p: IPlayer): void {
|
||||
|
@ -19,6 +19,42 @@ import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
|
||||
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||
import { InvitationEvent } from "./ui/InvitationModal";
|
||||
|
||||
const factionOrder = [
|
||||
"CyberSec",
|
||||
"Tian Di Hui",
|
||||
"Netburners",
|
||||
"Sector-12",
|
||||
"Chongqing",
|
||||
"New Tokyo",
|
||||
"Ishima",
|
||||
"Aevum",
|
||||
"Volhaven",
|
||||
"NiteSec",
|
||||
"The Black Hand",
|
||||
"BitRunners",
|
||||
"ECorp",
|
||||
"MegaCorp",
|
||||
"KuaiGong International",
|
||||
"Four Sigma",
|
||||
"NWO",
|
||||
"Blade Industries",
|
||||
"OmniTek Incorporated",
|
||||
"Bachman & Associates",
|
||||
"Clarke Incorporated",
|
||||
"Fulcrum Secret Technologies",
|
||||
"Slum Snakes",
|
||||
"Tetrads",
|
||||
"Silhouette",
|
||||
"Speakers for the Dead",
|
||||
"The Dark Army",
|
||||
"The Syndicate",
|
||||
"The Covenant",
|
||||
"Daedalus",
|
||||
"Illuminati",
|
||||
"Bladeburners",
|
||||
"Church of the Machine God",
|
||||
]
|
||||
|
||||
export function inviteToFaction(faction: Faction): void {
|
||||
Player.receiveInvite(faction.name);
|
||||
faction.alreadyInvited = true;
|
||||
@ -31,6 +67,8 @@ export function joinFaction(faction: Faction): void {
|
||||
if (faction.isMember) return;
|
||||
faction.isMember = true;
|
||||
Player.factions.push(faction.name);
|
||||
Player.factions.sort((a, b) =>
|
||||
factionOrder.indexOf(a) - factionOrder.indexOf(b));
|
||||
const factionInfo = faction.getInfo();
|
||||
|
||||
//Determine what factions you are banned from now that you have joined this faction
|
||||
@ -79,8 +117,7 @@ export function purchaseAugmentation(aug: Augmentation, fac: Faction, sing = fal
|
||||
const factionInfo = fac.getInfo();
|
||||
const hasPrereqs = hasAugmentationPrereqs(aug);
|
||||
if (!hasPrereqs) {
|
||||
const txt =
|
||||
"You must first purchase or install " + aug.prereqs.join(",") + " before you can " + "purchase this one.";
|
||||
const txt = `You must first purchase or install ${aug.prereqs.join(",")} before you can purchase this one.`;
|
||||
if (sing) {
|
||||
return txt;
|
||||
} else {
|
||||
@ -128,23 +165,21 @@ export function purchaseAugmentation(aug: Augmentation, fac: Faction, sing = fal
|
||||
|
||||
if (sing) {
|
||||
return "You purchased " + aug.name;
|
||||
} else {
|
||||
if (!Settings.SuppressBuyAugmentationConfirmation) {
|
||||
} else if (!Settings.SuppressBuyAugmentationConfirmation) {
|
||||
dialogBoxCreate(
|
||||
"You purchased " +
|
||||
aug.name +
|
||||
". Its enhancements will not take " +
|
||||
"effect until they are installed. To install your augmentations, go to the " +
|
||||
"'Augmentations' tab on the left-hand navigation menu. Purchasing additional " +
|
||||
"augmentations will now be more expensive.",
|
||||
aug.name +
|
||||
". Its enhancements will not take " +
|
||||
"effect until they are installed. To install your augmentations, go to the " +
|
||||
"'Augmentations' tab on the left-hand navigation menu. Purchasing additional " +
|
||||
"augmentations will now be more expensive.",
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dialogBoxCreate(
|
||||
"Hmm, something went wrong when trying to purchase an Augmentation. " +
|
||||
"Please report this to the game developer with an explanation of how to " +
|
||||
"reproduce this.",
|
||||
"Please report this to the game developer with an explanation of how to " +
|
||||
"reproduce this.",
|
||||
);
|
||||
}
|
||||
return "";
|
||||
|
@ -157,7 +157,7 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
(
|
||||
<>
|
||||
MegaCorp does what no other dares to do. We imagine. We create. We invent. We create what others have never even
|
||||
dreamed of. Our work fills the world's needs for food, water, power, and transportation on an unprecendented
|
||||
dreamed of. Our work fills the world's needs for food, water, power, and transportation on an unprecedented
|
||||
scale, in ways that no other company can.
|
||||
<br />
|
||||
<br />
|
||||
@ -559,7 +559,7 @@ export const FactionInfos: IMap<FactionInfo> = {
|
||||
{" `..` "}<br /><br />
|
||||
Many cultures predict an end to humanity in the near future, a final
|
||||
Armageddon that will end the world; but we disagree.
|
||||
<br /><br />Note that for this faction, reputation can
|
||||
<br /><br />Note that for this faction, reputation can
|
||||
only be gained by charging Stanek's gift.</>,
|
||||
[],
|
||||
false,
|
||||
|
@ -7,7 +7,7 @@ import { PurchaseableAugmentation } from "./PurchaseableAugmentation";
|
||||
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { Faction } from "../Faction";
|
||||
import { PurchaseAugmentationsOrderSetting } from "../../Settings/SettingEnums";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { hasAugmentationPrereqs } from "../FactionHelpers";
|
||||
|
@ -4,7 +4,7 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { Faction } from "../Faction";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { repFromDonation } from "../formulas/donation";
|
||||
import { Favor } from "../../ui/React/Favor";
|
||||
|
@ -13,7 +13,7 @@ import { Option } from "./Option";
|
||||
import { CONSTANTS } from "../../Constants";
|
||||
|
||||
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { Faction } from "../Faction";
|
||||
|
||||
import { use } from "../../ui/Context";
|
||||
import { CreateGangModal } from "./CreateGangModal";
|
||||
@ -24,10 +24,11 @@ import { CovenantPurchasesRoot } from "../../PersonObjects/Sleeve/ui/CovenantPur
|
||||
|
||||
type IProps = {
|
||||
faction: Faction;
|
||||
augPage: boolean;
|
||||
};
|
||||
|
||||
// Info text for all options on the UI
|
||||
const gangInfo = "Create and manage a gang for this Faction. Gangs will earn you money and " + "faction reputation";
|
||||
const gangInfo = "Create and manage a gang for this Faction. Gangs will earn you money and faction reputation";
|
||||
const hackingContractsInfo =
|
||||
"Complete hacking contracts for your faction. " +
|
||||
"Your effectiveness, which determines how much " +
|
||||
@ -70,7 +71,6 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
|
||||
const router = use.Router();
|
||||
const [sleevesOpen, setSleevesOpen] = useState(false);
|
||||
const [gangOpen, setGangOpen] = useState(false);
|
||||
const p = player;
|
||||
const factionInfo = faction.getInfo();
|
||||
|
||||
function manageGang(): void {
|
||||
@ -104,20 +104,20 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
|
||||
|
||||
// We have a special flag for whether the player this faction is the player's
|
||||
// gang faction because if the player has a gang, they cannot do any other action
|
||||
const isPlayersGang = p.inGang() && p.getGangName() === faction.name;
|
||||
const isPlayersGang = player.inGang() && player.getGangName() === faction.name;
|
||||
|
||||
// Flags for whether special options (gang, sleeve purchases, donate, etc.)
|
||||
// should be shown
|
||||
const favorToDonate = Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction);
|
||||
const canDonate = faction.favor >= favorToDonate;
|
||||
|
||||
const canPurchaseSleeves = faction.name === "The Covenant" && p.bitNodeN === 10;
|
||||
const canPurchaseSleeves = faction.name === "The Covenant" && player.bitNodeN === 10;
|
||||
|
||||
let canAccessGang = p.canAccessGang() && GangNames.includes(faction.name);
|
||||
if (p.inGang()) {
|
||||
if (p.getGangName() !== faction.name) {
|
||||
let canAccessGang = player.canAccessGang() && GangNames.includes(faction.name);
|
||||
if (player.inGang()) {
|
||||
if (player.getGangName() !== faction.name) {
|
||||
canAccessGang = false;
|
||||
} else if (p.getGangName() === faction.name) {
|
||||
} else if (player.getGangName() === faction.name) {
|
||||
canAccessGang = true;
|
||||
}
|
||||
}
|
||||
@ -174,6 +174,10 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
|
||||
|
||||
export function FactionRoot(props: IProps): React.ReactElement {
|
||||
const setRerender = useState(false)[1];
|
||||
const player = use.Player();
|
||||
const router = use.Router();
|
||||
const [purchasingAugs, setPurchasingAugs] = useState(props.augPage);
|
||||
|
||||
function rerender(): void {
|
||||
setRerender((old) => !old);
|
||||
}
|
||||
@ -185,7 +189,16 @@ export function FactionRoot(props: IProps): React.ReactElement {
|
||||
|
||||
const faction = props.faction;
|
||||
|
||||
const [purchasingAugs, setPurchasingAugs] = useState(false);
|
||||
if (player && !player.factions.includes(faction.name)) {
|
||||
return (
|
||||
<>
|
||||
<Typography variant="h4" color="primary">
|
||||
You have not joined {faction.name} yet!
|
||||
</Typography>
|
||||
<Button onClick={() => router.toFactions()}>Back to Factions</Button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return purchasingAugs ? (
|
||||
<AugmentationsPage faction={faction} routeToMainPage={() => setPurchasingAugs(false)} />
|
||||
|
@ -1,14 +1,21 @@
|
||||
import Box from "@mui/material/Box";
|
||||
import Button from "@mui/material/Button";
|
||||
import Container from "@mui/material/Container";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import TableBody from "@mui/material/TableBody";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Container,
|
||||
Paper,
|
||||
TableBody,
|
||||
TableRow,
|
||||
Typography
|
||||
} from "@mui/material";
|
||||
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Table, TableCell } from "../../ui/React/Table";
|
||||
import { IRouter } from "../../ui/Router";
|
||||
|
||||
import { Faction } from "../Faction";
|
||||
import { joinFaction } from "../FactionHelpers";
|
||||
import { Factions } from "../Factions";
|
||||
@ -41,12 +48,38 @@ export function FactionsRoot(props: IProps): React.ReactElement {
|
||||
props.router.toFaction(faction);
|
||||
}
|
||||
|
||||
function openFactionAugPage(faction: Faction): void {
|
||||
props.router.toFaction(faction, true);
|
||||
}
|
||||
|
||||
function acceptInvitation(event: React.MouseEvent<HTMLButtonElement, MouseEvent>, faction: string): void {
|
||||
if (!event.isTrusted) return;
|
||||
joinFaction(Factions[faction]);
|
||||
setRerender((x) => !x);
|
||||
}
|
||||
|
||||
const getAugsLeft = (faction: Faction, player: IPlayer): number => {
|
||||
const isPlayersGang = player.inGang() && player.getGangName() === faction.name;
|
||||
let augs: string[] = [];
|
||||
|
||||
if (isPlayersGang) {
|
||||
for (const augName of Object.keys(Augmentations)) {
|
||||
if (
|
||||
augName === AugmentationNames.NeuroFluxGovernor ||
|
||||
augName === AugmentationNames.TheRedPill && player.bitNodeN !== 2 ||
|
||||
Augmentations[augName].isSpecial
|
||||
) continue;
|
||||
augs.push(augName)
|
||||
}
|
||||
} else {
|
||||
augs = faction.augmentations.slice();
|
||||
}
|
||||
|
||||
return augs.filter(
|
||||
(augmentation: string) => !player.hasAugmentation(augmentation)
|
||||
).length;
|
||||
}
|
||||
|
||||
return (
|
||||
<Container disableGutters maxWidth="md" sx={{ mx: 0, mb: 10 }}>
|
||||
<Typography variant="h4">Factions</Typography>
|
||||
@ -61,7 +94,7 @@ export function FactionsRoot(props: IProps): React.ReactElement {
|
||||
</Typography>
|
||||
{(props.player.factions.length > 0 && (
|
||||
<Paper sx={{ my: 1, p: 1, pb: 0, display: "inline-block" }}>
|
||||
<Table padding="none">
|
||||
<Table padding="none" style={{ width: "fit-content" }}>
|
||||
<TableBody>
|
||||
{props.player.factions.map((faction: string) => (
|
||||
<TableRow key={faction}>
|
||||
@ -75,6 +108,13 @@ export function FactionsRoot(props: IProps): React.ReactElement {
|
||||
<Button onClick={() => openFaction(Factions[faction])}>Details</Button>
|
||||
</Box>
|
||||
</TableCell>
|
||||
<TableCell align="right">
|
||||
<Box ml={1} mb={1}>
|
||||
<Button sx={{ width: '100%' }} onClick={() => openFactionAugPage(Factions[faction])}>
|
||||
Augmentations Left: {getAugsLeft(Factions[faction], props.player)}
|
||||
</Button>
|
||||
</Box>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
|
@ -4,8 +4,8 @@
|
||||
*/
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { FactionInfo } from "../../Faction/FactionInfo";
|
||||
import { Faction } from "../Faction";
|
||||
import { FactionInfo } from "../FactionInfo";
|
||||
|
||||
import { Reputation } from "../../ui/React/Reputation";
|
||||
import { Favor } from "../../ui/React/Favor";
|
||||
|
@ -9,7 +9,7 @@ import { PurchaseAugmentationModal } from "./PurchaseAugmentationModal";
|
||||
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { Faction } from "../Faction";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
|
@ -273,7 +273,7 @@ export function EquipmentsSubpage(): React.ReactElement {
|
||||
sx={{ m: 1, width: '15%' }}
|
||||
/>
|
||||
|
||||
<Box display="grid" sx={{ gridTemplateColumns: '1fr 1fr', width: 'fit-content' }}>
|
||||
<Box display="grid" sx={{ gridTemplateColumns: '1fr 1fr', width: '100%' }}>
|
||||
{members.map((member: GangMember) => (
|
||||
<GangMemberUpgradePanel key={member.name} member={member} />
|
||||
))}
|
||||
|
@ -32,7 +32,7 @@ export function GangRoot(): React.ReactElement {
|
||||
|
||||
return (
|
||||
<Context.Gang.Provider value={gang}>
|
||||
<Tabs variant="fullWidth" value={value} onChange={handleChange}>
|
||||
<Tabs variant="fullWidth" value={value} onChange={handleChange} sx={{ minWidth: 'fit-content', maxWidth: '45%' }}>
|
||||
<Tab label="Management" />
|
||||
<Tab label="Equipment" />
|
||||
<Tab label="Territory" />
|
||||
|
@ -172,7 +172,7 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
|
||||
<Table size="small">
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<TableCell colSpan={3}>
|
||||
<Typography>{node.name}</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
@ -404,8 +404,9 @@ export const Literatures: IMap<Literature> = {};
|
||||
"What will the fate of the human race be?<br><br>" +
|
||||
"We live in an era vastly different from that of 15 or even 20 years ago. We have gone " +
|
||||
"beyond the limits of humanity. We have stripped ourselves of the tyranny of flesh.<br><br>" +
|
||||
"The Singularity is here. The merging of man and machine. This is where humanity evolves into ";
|
||||
"something greater. This is our future.<br><br>" + "Embrace it, and you will obey a new god. The God in the Machine.";
|
||||
"The Singularity is here. The merging of man and machine. This is where humanity evolves into " +
|
||||
"something greater. This is our future.<br><br>" +
|
||||
"Embrace it, and you will obey a new god. The God in the Machine.";
|
||||
Literatures[fn] = new Literature(title, fn, txt);
|
||||
|
||||
title = "The New Triads";
|
||||
|
@ -127,10 +127,10 @@ Cities[CityName.NewTokyo].asciiArt = `
|
||||
|
||||
o
|
||||
\\
|
||||
\\ [defcomm]
|
||||
[arcade] E [defcomm]
|
||||
\\
|
||||
o--x---A--x--o [travel agency]
|
||||
7 8 10 G
|
||||
7 8 10 H
|
||||
[vitalife] o 12 [global pharmaceuticals]
|
||||
|
|
||||
o--D-x----x-------x-C-+--------x--x-B-x---x-o
|
||||
@ -141,14 +141,14 @@ Cities[CityName.NewTokyo].asciiArt = `
|
||||
\\
|
||||
[hospital] o 15 [world stock exchange]
|
||||
|
|
||||
o--x--E--x-----x-----x---+---x----x--H--x-o
|
||||
o--x--F--x-----x-----x---+---x----x--I--x-o
|
||||
|
|
||||
|
|
||||
o 17
|
||||
|
||||
|
||||
|
||||
F [the slums]
|
||||
G [the slums]
|
||||
`;
|
||||
Cities[CityName.Sector12].asciiArt = `
|
||||
78 o 97
|
||||
|
@ -54,6 +54,7 @@ export enum LocationName {
|
||||
NewTokyoGlobalPharmaceuticals = "Global Pharmaceuticals",
|
||||
NewTokyoNoodleBar = "Noodle Bar",
|
||||
NewTokyoVitaLife = "VitaLife",
|
||||
NewTokyoArcade = "Arcade",
|
||||
|
||||
// Ishima
|
||||
IshimaNovaMedical = "Nova Medical",
|
||||
|
@ -215,6 +215,11 @@ export const LocationsMetadata: IConstructorParams[] = [
|
||||
name: LocationName.NewTokyoVitaLife,
|
||||
types: [LocationType.Company, LocationType.Special],
|
||||
},
|
||||
{
|
||||
city: CityName.NewTokyo,
|
||||
name: LocationName.NewTokyoArcade,
|
||||
types: [LocationType.Special],
|
||||
},
|
||||
{
|
||||
city: CityName.Sector12,
|
||||
infiltrationData: {
|
||||
|
@ -34,10 +34,9 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||
padding: "0px",
|
||||
cursor: "pointer",
|
||||
},
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
function toLocation(router: IRouter, location: Location): void {
|
||||
if (location.name === LocationName.TravelAgency) {
|
||||
router.toTravel();
|
||||
@ -132,12 +131,14 @@ function ASCIICity(props: IProps): React.ReactElement {
|
||||
|
||||
const elems: JSX.Element[] = [];
|
||||
const lines = props.city.asciiArt.split("\n");
|
||||
let i = 0;
|
||||
for (const line of lines) {
|
||||
elems.push(
|
||||
<Typography key={line} sx={{ lineHeight: "1em", whiteSpace: "pre" }}>
|
||||
<Typography key={i} sx={{ lineHeight: "1em", whiteSpace: "pre" }}>
|
||||
{lineElems(line)}
|
||||
</Typography>,
|
||||
);
|
||||
i++;
|
||||
}
|
||||
|
||||
return <>{elems}</>;
|
||||
|
@ -32,6 +32,7 @@ import { CorruptableText } from "../../ui/React/CorruptableText";
|
||||
import { HacknetNode } from "../../Hacknet/HacknetNode";
|
||||
import { HacknetServer } from "../../Hacknet/HacknetServer";
|
||||
import { GetServer } from "../../Server/AllServers";
|
||||
import { ArcadeRoot } from "../../Arcade/ui/ArcadeRoot";
|
||||
|
||||
type IProps = {
|
||||
loc: Location;
|
||||
@ -51,21 +52,19 @@ export function SpecialLocation(props: IProps): React.ReactElement {
|
||||
if (p.inBladeburner()) {
|
||||
// Enter Bladeburner division
|
||||
router.toBladeburner();
|
||||
} else {
|
||||
} else if (p.strength >= 100 && p.defense >= 100 && p.dexterity >= 100 && p.agility >= 100) {
|
||||
// Apply for Bladeburner division
|
||||
if (p.strength >= 100 && p.defense >= 100 && p.dexterity >= 100 && p.agility >= 100) {
|
||||
p.startBladeburner({ new: true });
|
||||
dialogBoxCreate("You have been accepted into the Bladeburner division!");
|
||||
setRerender((old) => !old);
|
||||
p.startBladeburner({new: true});
|
||||
dialogBoxCreate("You have been accepted into the Bladeburner division!");
|
||||
setRerender((old) => !old);
|
||||
|
||||
const worldHeader = document.getElementById("world-menu-header");
|
||||
if (worldHeader instanceof HTMLElement) {
|
||||
worldHeader.click();
|
||||
worldHeader.click();
|
||||
}
|
||||
} else {
|
||||
dialogBoxCreate("Rejected! Please apply again when you have 100 of each combat stat (str, def, dex, agi)");
|
||||
const worldHeader = document.getElementById("world-menu-header");
|
||||
if (worldHeader instanceof HTMLElement) {
|
||||
worldHeader.click();
|
||||
worldHeader.click();
|
||||
}
|
||||
} else {
|
||||
dialogBoxCreate("Rejected! Please apply again when you have 100 of each combat stat (str, def, dex, agi)");
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,7 +80,12 @@ export function SpecialLocation(props: IProps): React.ReactElement {
|
||||
return <></>;
|
||||
}
|
||||
const text = inBladeburner ? "Enter Bladeburner Headquarters" : "Apply to Bladeburner Division";
|
||||
return <><br/><Button onClick={handleBladeburner}>{text}</Button></>;
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
<Button onClick={handleBladeburner}>{text}</Button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function renderNoodleBar(): React.ReactElement {
|
||||
@ -311,6 +315,9 @@ export function SpecialLocation(props: IProps): React.ReactElement {
|
||||
case LocationName.IshimaGlitch: {
|
||||
return renderGlitch();
|
||||
}
|
||||
case LocationName.NewTokyoArcade: {
|
||||
return <ArcadeRoot />;
|
||||
}
|
||||
default:
|
||||
console.error(`Location ${props.loc.name} doesn't have any special properties`);
|
||||
return <></>;
|
||||
|
@ -59,6 +59,8 @@ export const RamCostConstants: IMap<number> = {
|
||||
|
||||
ScriptBladeburnerApiBaseRamCost: 4,
|
||||
|
||||
ScriptStanekWidth: 0.4,
|
||||
ScriptStanekHeight: 0.4,
|
||||
ScriptStanekCharge: 0.4,
|
||||
ScriptStanekFragmentDefinitions: 0,
|
||||
ScriptStanekPlacedFragments: 5,
|
||||
@ -106,6 +108,7 @@ export const RamCosts: IMap<any> = {
|
||||
hackAnalyzeSecurity: RamCostConstants.ScriptHackAnalyzeRamCost,
|
||||
hackAnalyzeChance: RamCostConstants.ScriptHackAnalyzeRamCost,
|
||||
sleep: 0,
|
||||
asleep: 0,
|
||||
share: 2.4,
|
||||
getSharePower: 0.2,
|
||||
grow: RamCostConstants.ScriptGrowRamCost,
|
||||
@ -354,6 +357,8 @@ export const RamCosts: IMap<any> = {
|
||||
},
|
||||
|
||||
stanek: {
|
||||
width: RamCostConstants.ScriptStanekWidth,
|
||||
height: RamCostConstants.ScriptStanekHeight,
|
||||
charge: RamCostConstants.ScriptStanekCharge,
|
||||
fragmentDefinitions: RamCostConstants.ScriptStanekFragmentDefinitions,
|
||||
activeFragments: RamCostConstants.ScriptStanekPlacedFragments,
|
||||
|
@ -102,7 +102,7 @@ export class WorkerScript {
|
||||
scriptRef: RunningScript;
|
||||
|
||||
/**
|
||||
* IP Address on which this script is running
|
||||
* hostname on which this script is running
|
||||
*/
|
||||
hostname: string;
|
||||
|
||||
|
@ -60,8 +60,5 @@ export function isScriptErrorMessage(msg: string): boolean {
|
||||
return false;
|
||||
}
|
||||
const splitMsg = msg.split("|DELIMITER|");
|
||||
if (splitMsg.length != 4) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return splitMsg.length == 4;
|
||||
}
|
||||
|
@ -425,19 +425,22 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
const helper = {
|
||||
updateDynamicRam: updateDynamicRam,
|
||||
makeRuntimeErrorMsg: makeRuntimeErrorMsg,
|
||||
string: (funcName: string, argName: string, v: any): string => {
|
||||
string: (funcName: string, argName: string, v: unknown): string => {
|
||||
if (typeof v === "string") return v;
|
||||
if (typeof v === "number") return v + ""; // cast to string;
|
||||
throw makeRuntimeErrorMsg(funcName, `${argName} should be a string`);
|
||||
},
|
||||
number: (funcName: string, argName: string, v: any): number => {
|
||||
if (!isNaN(v)) {
|
||||
if (typeof v === "number") return v;
|
||||
if (!isNaN(parseFloat(v))) return parseFloat(v);
|
||||
number: (funcName: string, argName: string, v: unknown): number => {
|
||||
if (typeof v === "string") {
|
||||
const x = parseFloat(v);
|
||||
if (!isNaN(x)) return x; // otherwise it wasn't even a string representing a number.
|
||||
} else if (typeof v === "number") {
|
||||
if (isNaN(v)) throw makeRuntimeErrorMsg(funcName, `${argName} is NaN`);
|
||||
return v;
|
||||
}
|
||||
throw makeRuntimeErrorMsg(funcName, `${argName} should be a number`);
|
||||
},
|
||||
boolean: (v: any): boolean => {
|
||||
boolean: (v: unknown): boolean => {
|
||||
return !!v; // Just convert it to boolean.
|
||||
},
|
||||
getServer: safeGetServer,
|
||||
@ -467,7 +470,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
|
||||
const gang = NetscriptGang(Player, workerScript, helper);
|
||||
const sleeve = NetscriptSleeve(Player, workerScript, helper);
|
||||
const extra = NetscriptExtra(Player, workerScript);
|
||||
const extra = NetscriptExtra(Player, workerScript, helper);
|
||||
const hacknet = NetscriptHacknet(Player, workerScript, helper);
|
||||
const stanek = NetscriptStanek(Player, workerScript, helper);
|
||||
const bladeburner = NetscriptBladeburner(Player, workerScript, helper);
|
||||
@ -550,6 +553,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
return calculatePercentMoneyHacked(server, Player);
|
||||
},
|
||||
hackAnalyzeSecurity: function (threads: any): number {
|
||||
updateDynamicRam("hackAnalyzeSecurity", getRamCost(Player, "hackAnalyzeSecurity"));
|
||||
return CONSTANTS.ServerFortifyAmount * threads;
|
||||
},
|
||||
hackAnalyzeChance: function (hostname: any): any {
|
||||
@ -564,6 +568,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
return calculateHackingChance(server, Player);
|
||||
},
|
||||
sleep: function (time: any): any {
|
||||
updateDynamicRam("sleep", getRamCost(Player, "sleep"));
|
||||
if (time === undefined) {
|
||||
throw makeRuntimeErrorMsg("sleep", "Takes 1 argument.");
|
||||
}
|
||||
@ -573,6 +578,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
});
|
||||
},
|
||||
asleep: function (time: any): any {
|
||||
updateDynamicRam("asleep", getRamCost(Player, "asleep"));
|
||||
if (time === undefined) {
|
||||
throw makeRuntimeErrorMsg("asleep", "Takes 1 argument.");
|
||||
}
|
||||
@ -650,6 +656,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
return numCycleForGrowth(server, Number(growth), Player, cores);
|
||||
},
|
||||
growthAnalyzeSecurity: function (threads: any): number {
|
||||
updateDynamicRam("growthAnalyzeSecurity", getRamCost(Player, "growthAnalyzeSecurity"));
|
||||
return 2 * CONSTANTS.ServerFortifyAmount * threads;
|
||||
},
|
||||
weaken: function (hostname: any, { threads: requestedThreads }: any = {}): any {
|
||||
@ -702,10 +709,12 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
});
|
||||
},
|
||||
weakenAnalyze: function (threads: any, cores: any = 1): number {
|
||||
updateDynamicRam("weakenAnalyze", getRamCost(Player, "weakenAnalyze"));
|
||||
const coreBonus = 1 + (cores - 1) / 16;
|
||||
return CONSTANTS.ServerWeakenAmount * threads * coreBonus;
|
||||
return CONSTANTS.ServerWeakenAmount * threads * coreBonus * BitNodeMultipliers.ServerWeakenRate;
|
||||
},
|
||||
share: function (): Promise<void> {
|
||||
updateDynamicRam("share", getRamCost(Player, "share"));
|
||||
workerScript.log("share", () => "Sharing this computer.");
|
||||
const end = StartSharing(workerScript.scriptRef.threads * calculateIntelligenceBonus(Player.intelligence, 2));
|
||||
return netscriptDelay(10000, workerScript).finally(function () {
|
||||
@ -714,21 +723,25 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
});
|
||||
},
|
||||
getSharePower: function (): number {
|
||||
updateDynamicRam("getSharePower", getRamCost(Player, "getSharePower"));
|
||||
return CalculateShareMult();
|
||||
},
|
||||
print: function (...args: any[]): void {
|
||||
updateDynamicRam("print", getRamCost(Player, "print"));
|
||||
if (args.length === 0) {
|
||||
throw makeRuntimeErrorMsg("print", "Takes at least 1 argument.");
|
||||
}
|
||||
workerScript.print(argsToString(args));
|
||||
},
|
||||
printf: function (format: string, ...args: any[]): void {
|
||||
updateDynamicRam("printf", getRamCost(Player, "printf"));
|
||||
if (typeof format !== "string") {
|
||||
throw makeRuntimeErrorMsg("printf", "First argument must be string for the format.");
|
||||
}
|
||||
workerScript.print(vsprintf(format, args));
|
||||
},
|
||||
tprint: function (...args: any[]): void {
|
||||
updateDynamicRam("tprint", getRamCost(Player, "tprint"));
|
||||
if (args.length === 0) {
|
||||
throw makeRuntimeErrorMsg("tprint", "Takes at least 1 argument.");
|
||||
}
|
||||
@ -752,6 +765,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
Terminal.print(`${workerScript.scriptRef.filename}: ${str}`);
|
||||
},
|
||||
tprintf: function (format: any, ...args: any): any {
|
||||
updateDynamicRam("tprintf", getRamCost(Player, "tprintf"));
|
||||
if (typeof format !== "string") {
|
||||
throw makeRuntimeErrorMsg("tprintf", "First argument must be string for the format.");
|
||||
}
|
||||
@ -776,9 +790,11 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
Terminal.print(`${str}`);
|
||||
},
|
||||
clearLog: function (): any {
|
||||
updateDynamicRam("clearLog", getRamCost(Player, "clearLog"));
|
||||
workerScript.scriptRef.clearLog();
|
||||
},
|
||||
disableLog: function (fn: any): any {
|
||||
updateDynamicRam("disableLog", getRamCost(Player, "disableLog"));
|
||||
if (fn === "ALL") {
|
||||
for (fn of Object.keys(possibleLogs)) {
|
||||
workerScript.disableLogs[fn] = true;
|
||||
@ -792,6 +808,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
}
|
||||
},
|
||||
enableLog: function (fn: any): any {
|
||||
updateDynamicRam("enableLog", getRamCost(Player, "enableLog"));
|
||||
if (fn === "ALL") {
|
||||
for (fn of Object.keys(possibleLogs)) {
|
||||
delete workerScript.disableLogs[fn];
|
||||
@ -804,12 +821,14 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
workerScript.log("enableLog", () => `Enabled logging for ${fn}`);
|
||||
},
|
||||
isLogEnabled: function (fn: any): any {
|
||||
updateDynamicRam("isLogEnabled", getRamCost(Player, "isLogEnabled"));
|
||||
if (possibleLogs[fn] === undefined) {
|
||||
throw makeRuntimeErrorMsg("isLogEnabled", `Invalid argument: ${fn}.`);
|
||||
}
|
||||
return workerScript.disableLogs[fn] ? false : true;
|
||||
return !workerScript.disableLogs[fn];
|
||||
},
|
||||
getScriptLogs: function (fn: any, hostname: any, ...scriptArgs: any): any {
|
||||
updateDynamicRam("getScriptLogs", getRamCost(Player, "getScriptLogs"));
|
||||
const runningScriptObj = getRunningScript(fn, hostname, "getScriptLogs", scriptArgs);
|
||||
if (runningScriptObj == null) {
|
||||
workerScript.log("getScriptLogs", () => getCannotFindRunningScriptErrorMessage(fn, hostname, scriptArgs));
|
||||
@ -819,6 +838,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
return runningScriptObj.logs.slice();
|
||||
},
|
||||
tail: function (fn: any, hostname: any = workerScript.hostname, ...scriptArgs: any): any {
|
||||
updateDynamicRam("tail", getRamCost(Player, "tail"));
|
||||
let runningScriptObj;
|
||||
if (arguments.length === 0) {
|
||||
runningScriptObj = workerScript.scriptRef;
|
||||
@ -1085,6 +1105,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
return scriptsRunning;
|
||||
},
|
||||
exit: function (): any {
|
||||
updateDynamicRam("exit", getRamCost(Player, "exit"));
|
||||
workerScript.running = false; // Prevent workerScript from "finishing execution naturally"
|
||||
if (killWorkerScript(workerScript)) {
|
||||
workerScript.log("exit", () => "Exiting...");
|
||||
@ -1121,7 +1142,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
|
||||
// Invalid file name
|
||||
if (!scriptname.endsWith(".lit") && !isScriptFilename(scriptname) && !scriptname.endsWith("txt")) {
|
||||
throw makeRuntimeErrorMsg("scp", "Only works for .script, .lit, and .txt files");
|
||||
throw makeRuntimeErrorMsg("scp", "Only works for scripts, .lit and .txt files");
|
||||
}
|
||||
|
||||
let destServer: BaseServer | null;
|
||||
@ -1590,10 +1611,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
}
|
||||
}
|
||||
const txtFile = getTextFile(filename, server);
|
||||
if (txtFile != null) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return txtFile != null;
|
||||
},
|
||||
isRunning: function (fn: any, hostname: any = workerScript.hostname, ...scriptArgs: any): any {
|
||||
updateDynamicRam("isRunning", getRamCost(Player, "isRunning"));
|
||||
@ -1628,6 +1646,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
return cost;
|
||||
},
|
||||
purchaseServer: function (aname: any, aram: any): any {
|
||||
if (arguments.length !== 2) throw makeRuntimeErrorMsg("purchaseServer", "Takes 2 arguments");
|
||||
const name = helper.string("purchaseServer", "name", aname);
|
||||
const ram = helper.number("purchaseServer", "ram", aram);
|
||||
updateDynamicRam("purchaseServer", getRamCost(Player, "purchaseServer"));
|
||||
@ -1649,12 +1668,15 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
|
||||
const cost = getPurchaseServerCost(ram);
|
||||
if (cost === Infinity) {
|
||||
if(ram > getPurchaseServerMaxRam()){
|
||||
workerScript.log("purchaseServer", () => `Invalid argument: ram='${ram}' must not be greater than getPurchaseServerMaxRam`);
|
||||
}else{
|
||||
if (ram > getPurchaseServerMaxRam()) {
|
||||
workerScript.log(
|
||||
"purchaseServer",
|
||||
() => `Invalid argument: ram='${ram}' must not be greater than getPurchaseServerMaxRam`,
|
||||
);
|
||||
} else {
|
||||
workerScript.log("purchaseServer", () => `Invalid argument: ram='${ram}' must be a positive power of 2`);
|
||||
}
|
||||
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
@ -1772,6 +1794,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
return res;
|
||||
},
|
||||
writePort: function (port: any, data: any = ""): any {
|
||||
updateDynamicRam("writePort", getRamCost(Player, "writePort"));
|
||||
if (typeof data !== "string" && typeof data !== "number") {
|
||||
throw makeRuntimeErrorMsg(
|
||||
"writePort",
|
||||
@ -1836,6 +1859,12 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
},
|
||||
tryWritePort: function (port: any, data: any = ""): any {
|
||||
updateDynamicRam("tryWritePort", getRamCost(Player, "tryWritePort"));
|
||||
if (typeof data !== "string" && typeof data !== "number") {
|
||||
throw makeRuntimeErrorMsg(
|
||||
"tryWritePort",
|
||||
`Trying to write invalid data to a port: only strings and numbers are valid.`,
|
||||
);
|
||||
}
|
||||
if (!isNaN(port)) {
|
||||
port = Math.round(port);
|
||||
if (port < 1 || port > CONSTANTS.NumNetscriptPorts) {
|
||||
@ -1854,6 +1883,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
}
|
||||
},
|
||||
readPort: function (port: any): any {
|
||||
updateDynamicRam("readPort", getRamCost(Player, "readPort"));
|
||||
// Read from port
|
||||
const iport = helper.getValidPort("readPort", port);
|
||||
const x = iport.read();
|
||||
@ -1913,6 +1943,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
return 0;
|
||||
},
|
||||
clearPort: function (port: any): any {
|
||||
updateDynamicRam("clearPort", getRamCost(Player, "clearPort"));
|
||||
// Clear port
|
||||
const iport = helper.getValidPort("clearPort", port);
|
||||
return iport.clear();
|
||||
@ -1961,6 +1992,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
return suc;
|
||||
},
|
||||
getScriptName: function (): any {
|
||||
updateDynamicRam("getScriptName", getRamCost(Player, "getScriptName"));
|
||||
return workerScript.name;
|
||||
},
|
||||
getScriptRam: function (scriptname: any, hostname: any = workerScript.hostname): any {
|
||||
@ -2092,6 +2124,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
}
|
||||
},
|
||||
nFormat: function (n: any, format: any): any {
|
||||
updateDynamicRam("nFormat", getRamCost(Player, "nFormat"));
|
||||
if (isNaN(n) || isNaN(parseFloat(n)) || typeof format !== "string") {
|
||||
return "";
|
||||
}
|
||||
@ -2099,6 +2132,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
return numeralWrapper.format(parseFloat(n), format);
|
||||
},
|
||||
tFormat: function (milliseconds: any, milliPrecision: any = false): any {
|
||||
updateDynamicRam("tFormat", getRamCost(Player, "tFormat"));
|
||||
return convertTimeMsToTimeElapsedString(milliseconds, milliPrecision);
|
||||
},
|
||||
getTimeSinceLastAug: function (): any {
|
||||
@ -2106,10 +2140,12 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
return Player.playtimeSinceLastAug;
|
||||
},
|
||||
alert: function (message: any): void {
|
||||
updateDynamicRam("alert", getRamCost(Player, "alert"));
|
||||
message = argsToString([message]);
|
||||
dialogBoxCreate(message);
|
||||
},
|
||||
toast: function (message: any, variant: any = "success", duration: any = 2000): void {
|
||||
updateDynamicRam("toast", getRamCost(Player, "toast"));
|
||||
if (!["success", "info", "warning", "error"].includes(variant))
|
||||
throw new Error(`variant must be one of "success", "info", "warning", or "error"`);
|
||||
|
||||
@ -2117,6 +2153,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
SnackbarEvents.emit(message, variant, duration);
|
||||
},
|
||||
prompt: function (txt: any): any {
|
||||
updateDynamicRam("prompt", getRamCost(Player, "prompt"));
|
||||
if (!isString(txt)) {
|
||||
txt = JSON.stringify(txt);
|
||||
}
|
||||
@ -2129,6 +2166,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
});
|
||||
},
|
||||
wget: async function (url: any, target: any, hostname: any = workerScript.hostname): Promise<boolean> {
|
||||
updateDynamicRam("wget", getRamCost(Player, "wget"));
|
||||
if (!isScriptFilename(target) && !target.endsWith(".txt")) {
|
||||
workerScript.log("wget", () => `Invalid target file: '${target}'. Must be a script or text file.`);
|
||||
return Promise.resolve(false);
|
||||
@ -2170,7 +2208,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
return Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction);
|
||||
},
|
||||
getOwnedSourceFiles: function (): SourceFileLvl[] {
|
||||
helper.updateDynamicRam("getOwnedSourceFiles", getRamCost(Player, "getOwnedSourceFiles"));
|
||||
updateDynamicRam("getOwnedSourceFiles", getRamCost(Player, "getOwnedSourceFiles"));
|
||||
const res: SourceFileLvl[] = [];
|
||||
for (let i = 0; i < Player.sourceFiles.length; ++i) {
|
||||
res.push({
|
||||
@ -2181,7 +2219,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
return res;
|
||||
},
|
||||
getPlayer: function (): INetscriptPlayer {
|
||||
helper.updateDynamicRam("getPlayer", getRamCost(Player, "getPlayer"));
|
||||
updateDynamicRam("getPlayer", getRamCost(Player, "getPlayer"));
|
||||
|
||||
const data = {
|
||||
hacking: Player.hacking,
|
||||
@ -2270,16 +2308,20 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
jobs: {},
|
||||
factions: Player.factions.slice(),
|
||||
tor: Player.hasTorRouter(),
|
||||
inBladeburner: Player.inBladeburner(),
|
||||
hasCorporation: Player.hasCorporation(),
|
||||
};
|
||||
Object.assign(data.jobs, Player.jobs);
|
||||
return data;
|
||||
},
|
||||
atExit: function (f: any): void {
|
||||
updateDynamicRam("atExit", getRamCost(Player, "atExit"));
|
||||
if (typeof f !== "function") {
|
||||
throw makeRuntimeErrorMsg("atExit", "argument should be function");
|
||||
}
|
||||
workerScript.atExit = f;
|
||||
workerScript.atExit = () => {
|
||||
f();
|
||||
}; // Wrap the user function to prevent WorkerScript leaking as 'this'
|
||||
},
|
||||
mv: function (host: string, source: string, destination: string): void {
|
||||
updateDynamicRam("mv", getRamCost(Player, "mv"));
|
||||
|
@ -365,7 +365,7 @@ export function NetscriptBladeburner(
|
||||
checkBladeburnerAccess("getBonusTime");
|
||||
const bladeburner = player.bladeburner;
|
||||
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
|
||||
return Math.round(bladeburner.storedCycles / 5);
|
||||
return (Math.round(bladeburner.storedCycles / 5))*1000;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -49,6 +49,9 @@ import {
|
||||
SetMaterialMarketTA2,
|
||||
SetProductMarketTA1,
|
||||
SetProductMarketTA2,
|
||||
BulkPurchase,
|
||||
SellShares,
|
||||
BuyBackShares,
|
||||
SetSmartSupplyUseLeftovers,
|
||||
} from "../Corporation/Actions";
|
||||
import { CorporationUnlockUpgrades } from "../Corporation/data/CorporationUnlockUpgrades";
|
||||
@ -132,11 +135,11 @@ export function NetscriptCorporation(
|
||||
|
||||
function getInvestmentOffer(): InvestmentOffer {
|
||||
const corporation = getCorporation();
|
||||
if (corporation.fundingRound >= CorporationConstants.FundingRoundShares.length || corporation.fundingRound >= CorporationConstants.FundingRoundMultiplier.length || corporation.public)
|
||||
if (corporation.fundingRound >= CorporationConstants.FundingRoundShares.length || corporation.fundingRound >= CorporationConstants.FundingRoundMultiplier.length || corporation.public)
|
||||
return {
|
||||
funds: 0,
|
||||
shares: 0,
|
||||
round: corporation.fundingRound + 1 // Make more readable
|
||||
round: corporation.fundingRound + 1 // Make more readable
|
||||
}; // Don't throw an error here, no reason to have a second function to check if you can get investment.
|
||||
const val = corporation.determineValuation();
|
||||
const percShares = CorporationConstants.FundingRoundShares[corporation.fundingRound];
|
||||
@ -146,7 +149,7 @@ export function NetscriptCorporation(
|
||||
return {
|
||||
funds: funding,
|
||||
shares: investShares,
|
||||
round: corporation.fundingRound + 1 // Make more readable
|
||||
round: corporation.fundingRound + 1 // Make more readable
|
||||
};
|
||||
}
|
||||
|
||||
@ -178,6 +181,7 @@ export function NetscriptCorporation(
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function getResearchCost(division: IIndustry, researchName: string): number {
|
||||
const researchTree = IndustryResearchTrees[division.type];
|
||||
if (researchTree === undefined) throw new Error(`No research tree for industry '${division.type}'`);
|
||||
@ -193,7 +197,8 @@ export function NetscriptCorporation(
|
||||
|
||||
function bribe(factionName: string, amountCash: number, amountShares: number): boolean {
|
||||
if (!player.factions.includes(factionName)) throw new Error("Invalid faction name");
|
||||
if (isNaN(amountCash) || amountCash < 0 || isNaN(amountShares) || amountShares < 0) throw new Error("Invalid value for amount field! Must be numeric, grater than 0.");
|
||||
if (isNaN(amountCash) || amountCash < 0 || isNaN(amountShares) || amountShares < 0) throw new Error("Invalid value for amount field! Must be numeric, grater than 0.");
|
||||
|
||||
const corporation = getCorporation();
|
||||
if (corporation.funds < amountCash) return false;
|
||||
if (corporation.numShares < amountShares) return false;
|
||||
@ -271,25 +276,25 @@ export function NetscriptCorporation(
|
||||
|
||||
function getSafeDivision(division: Industry): NSDivision {
|
||||
const cities: string[] = [];
|
||||
for (const office of Object.values(division.offices)) {
|
||||
if (office === 0) continue;
|
||||
cities.push(office.loc);
|
||||
}
|
||||
return {
|
||||
name: division.name,
|
||||
type: division.type,
|
||||
awareness: division.awareness,
|
||||
popularity: division.popularity,
|
||||
prodMult: division.prodMult,
|
||||
research: division.sciResearch.qty,
|
||||
lastCycleRevenue: division.lastCycleRevenue,
|
||||
lastCycleExpenses: division.lastCycleExpenses,
|
||||
thisCycleRevenue: division.thisCycleRevenue,
|
||||
thisCycleExpenses: division.thisCycleExpenses,
|
||||
upgrades: division.upgrades,
|
||||
cities: cities,
|
||||
products: division.products === undefined ? [] : Object.keys(division.products),
|
||||
};
|
||||
for (const office of Object.values(division.offices)) {
|
||||
if (office === 0) continue;
|
||||
cities.push(office.loc);
|
||||
}
|
||||
return {
|
||||
name: division.name,
|
||||
type: division.type,
|
||||
awareness: division.awareness,
|
||||
popularity: division.popularity,
|
||||
prodMult: division.prodMult,
|
||||
research: division.sciResearch.qty,
|
||||
lastCycleRevenue: division.lastCycleRevenue,
|
||||
lastCycleExpenses: division.lastCycleExpenses,
|
||||
thisCycleRevenue: division.thisCycleRevenue,
|
||||
thisCycleExpenses: division.thisCycleExpenses,
|
||||
upgrades: division.upgrades,
|
||||
cities: cities,
|
||||
products: division.products === undefined ? [] : Object.keys(division.products),
|
||||
};
|
||||
}
|
||||
|
||||
const warehouseAPI: WarehouseAPI = {
|
||||
@ -409,6 +414,8 @@ export function NetscriptCorporation(
|
||||
const cityName = helper.string("sellProduct", "cityName", acityName);
|
||||
const enabled = helper.boolean(aenabled);
|
||||
const warehouse = getWarehouse(divisionName, cityName);
|
||||
if (!hasUnlockUpgrade("Smart Supply"))
|
||||
throw helper.makeRuntimeErrorMsg(`corporation.setSmartSupply`, `You have not purchased the Smart Supply upgrade!`);
|
||||
SetSmartSupply(warehouse, enabled);
|
||||
},
|
||||
setSmartSupplyUseLeftovers: function (adivisionName: any, acityName: any, amaterialName: any, aenabled: any): void {
|
||||
@ -419,6 +426,8 @@ export function NetscriptCorporation(
|
||||
const enabled = helper.boolean(aenabled);
|
||||
const warehouse = getWarehouse(divisionName, cityName);
|
||||
const material = getMaterial(divisionName, cityName, materialName);
|
||||
if (!hasUnlockUpgrade("Smart Supply"))
|
||||
throw helper.makeRuntimeErrorMsg(`corporation.setSmartSupply`, `You have not purchased the Smart Supply upgrade!`);
|
||||
SetSmartSupplyUseLeftovers(warehouse, material, enabled);
|
||||
},
|
||||
buyMaterial: function (adivisionName: any, acityName: any, amaterialName: any, aamt: any): void {
|
||||
@ -427,10 +436,22 @@ export function NetscriptCorporation(
|
||||
const cityName = helper.string("buyMaterial", "cityName", acityName);
|
||||
const materialName = helper.string("buyMaterial", "materialName", amaterialName);
|
||||
const amt = helper.number("buyMaterial", "amt", aamt);
|
||||
if (amt < 0) throw new Error("Invalid value for amount field! Must be numeric and grater than 0");
|
||||
if (amt < 0) throw new Error("Invalid value for amount field! Must be numeric and greater than 0");
|
||||
const material = getMaterial(divisionName, cityName, materialName);
|
||||
BuyMaterial(material, amt);
|
||||
},
|
||||
bulkPurchase: function (adivisionName: any, acityName: any, amaterialName: any, aamt: any): void {
|
||||
checkAccess("bulkPurchase", 7);
|
||||
const divisionName = helper.string("bulkPurchase", "divisionName", adivisionName);
|
||||
if (!hasResearched(getDivision(adivisionName), "Bulk Purchasing")) throw new Error(`You have not researched Bulk Purchasing in ${divisionName}`)
|
||||
const corporation = getCorporation();
|
||||
const cityName = helper.string("bulkPurchase", "cityName", acityName);
|
||||
const materialName = helper.string("bulkPurchase", "materialName", amaterialName);
|
||||
const amt = helper.number("bulkPurchase", "amt", aamt);
|
||||
const warehouse = getWarehouse(divisionName, cityName)
|
||||
const material = getMaterial(divisionName, cityName, materialName);
|
||||
BulkPurchase(corporation, warehouse, material, amt);
|
||||
},
|
||||
makeProduct: function (
|
||||
adivisionName: any,
|
||||
acityName: any,
|
||||
@ -462,7 +483,7 @@ export function NetscriptCorporation(
|
||||
const targetCity = helper.string("exportMaterial", "targetCity", atargetCity);
|
||||
const materialName = helper.string("exportMaterial", "materialName", amaterialName);
|
||||
const amt = helper.string("exportMaterial", "amt", aamt);
|
||||
ExportMaterial(targetDivision, targetCity, getMaterial(sourceDivision, sourceCity, materialName), amt + "");
|
||||
ExportMaterial(targetDivision, targetCity, getMaterial(sourceDivision, sourceCity, materialName), amt + "", getDivision(targetDivision));
|
||||
},
|
||||
cancelExportMaterial: function (
|
||||
asourceDivision: any,
|
||||
@ -487,6 +508,8 @@ export function NetscriptCorporation(
|
||||
const cityName = helper.string("setMaterialMarketTA1", "cityName", acityName);
|
||||
const materialName = helper.string("setMaterialMarketTA1", "materialName", amaterialName);
|
||||
const on = helper.boolean(aon);
|
||||
if (!getDivision(divisionName).hasResearch("Market-TA.I"))
|
||||
throw helper.makeRuntimeErrorMsg(`corporation.setMaterialMarketTA1`, `You have not researched MarketTA.I for division: ${divisionName}`);
|
||||
SetMaterialMarketTA1(getMaterial(divisionName, cityName, materialName), on);
|
||||
},
|
||||
setMaterialMarketTA2: function (adivisionName: any, acityName: any, amaterialName: any, aon: any): void {
|
||||
@ -495,6 +518,8 @@ export function NetscriptCorporation(
|
||||
const cityName = helper.string("setMaterialMarketTA2", "cityName", acityName);
|
||||
const materialName = helper.string("setMaterialMarketTA2", "materialName", amaterialName);
|
||||
const on = helper.boolean(aon);
|
||||
if (!getDivision(divisionName).hasResearch("Market-TA.II"))
|
||||
throw helper.makeRuntimeErrorMsg(`corporation.setMaterialMarketTA2`, `You have not researched MarketTA.II for division: ${divisionName}`);
|
||||
SetMaterialMarketTA2(getMaterial(divisionName, cityName, materialName), on);
|
||||
},
|
||||
setProductMarketTA1: function (adivisionName: any, aproductName: any, aon: any): void {
|
||||
@ -502,6 +527,8 @@ export function NetscriptCorporation(
|
||||
const divisionName = helper.string("setProductMarketTA1", "divisionName", adivisionName);
|
||||
const productName = helper.string("setProductMarketTA1", "productName", aproductName);
|
||||
const on = helper.boolean(aon);
|
||||
if (!getDivision(divisionName).hasResearch("Market-TA.I"))
|
||||
throw helper.makeRuntimeErrorMsg(`corporation.setProductMarketTA1`, `You have not researched MarketTA.I for division: ${divisionName}`);
|
||||
SetProductMarketTA1(getProduct(divisionName, productName), on);
|
||||
},
|
||||
setProductMarketTA2: function (adivisionName: any, aproductName: any, aon: any): void {
|
||||
@ -509,6 +536,8 @@ export function NetscriptCorporation(
|
||||
const divisionName = helper.string("setProductMarketTA2", "divisionName", adivisionName);
|
||||
const productName = helper.string("setProductMarketTA2", "productName", aproductName);
|
||||
const on = helper.boolean(aon);
|
||||
if (!getDivision(divisionName).hasResearch("Market-TA.II"))
|
||||
throw helper.makeRuntimeErrorMsg(`corporation.setProductMarketTA2`, `You have not researched MarketTA.II for division: ${divisionName}`);
|
||||
SetProductMarketTA2(getProduct(divisionName, productName), on);
|
||||
},
|
||||
};
|
||||
@ -559,7 +588,7 @@ export function NetscriptCorporation(
|
||||
const divisionName = helper.string("getOfficeSizeUpgradeCost", "divisionName", adivisionName);
|
||||
const cityName = helper.string("getOfficeSizeUpgradeCost", "cityName", acityName);
|
||||
const size = helper.number("getOfficeSizeUpgradeCost", "size", asize);
|
||||
if (size < 0) throw new Error("Invalid value for size field! Must be numeric and grater than 0");
|
||||
if (size < 0) throw new Error("Invalid value for size field! Must be numeric and greater than 0");
|
||||
const office = getOffice(divisionName, cityName);
|
||||
const initialPriceMult = Math.round(office.size / CorporationConstants.OfficeInitialSize);
|
||||
const costMultiplier = 1.09;
|
||||
@ -592,7 +621,7 @@ export function NetscriptCorporation(
|
||||
const divisionName = helper.string("upgradeOfficeSize", "divisionName", adivisionName);
|
||||
const cityName = helper.string("upgradeOfficeSize", "cityName", acityName);
|
||||
const size = helper.number("upgradeOfficeSize", "size", asize);
|
||||
if (size < 0) throw new Error("Invalid value for size field! Must be numeric and grater than 0");
|
||||
if (size < 0) throw new Error("Invalid value for size field! Must be numeric and greater than 0");
|
||||
const office = getOffice(divisionName, cityName);
|
||||
const corporation = getCorporation();
|
||||
UpgradeOfficeSize(corporation, office, size);
|
||||
@ -602,7 +631,7 @@ export function NetscriptCorporation(
|
||||
const divisionName = helper.string("throwParty", "divisionName", adivisionName);
|
||||
const cityName = helper.string("throwParty", "cityName", acityName);
|
||||
const costPerEmployee = helper.number("throwParty", "costPerEmployee", acostPerEmployee);
|
||||
if (costPerEmployee < 0) throw new Error("Invalid value for Cost Per Employee field! Must be numeric and grater than 0");
|
||||
if (costPerEmployee < 0) throw new Error("Invalid value for Cost Per Employee field! Must be numeric and greater than 0");
|
||||
const office = getOffice(divisionName, cityName);
|
||||
const corporation = getCorporation();
|
||||
return netscriptDelay(
|
||||
@ -721,8 +750,10 @@ export function NetscriptCorporation(
|
||||
issueDividends: function (apercent: any): void {
|
||||
checkAccess("issueDividends");
|
||||
const percent = helper.number("issueDividends", "percent", apercent);
|
||||
if (percent < 0 || percent > 100) throw new Error("Invalid value for percent field! Must be numeric, grater than 0, and less than 100");
|
||||
if (percent < 0 || percent > 100) throw new Error("Invalid value for percent field! Must be numeric, greater than 0, and less than 100");
|
||||
const corporation = getCorporation();
|
||||
if (!corporation.public)
|
||||
throw helper.makeRuntimeErrorMsg(`corporation.issueDividends`, `Your company has not gone public!`);
|
||||
IssueDividends(corporation, percent);
|
||||
},
|
||||
|
||||
@ -781,24 +812,34 @@ export function NetscriptCorporation(
|
||||
const industryName = helper.string("getExpandIndustryCost", "industryName", aindustryName);
|
||||
return getExpandIndustryCost(industryName);
|
||||
},
|
||||
getExpandCityCost: function(): number {
|
||||
getExpandCityCost: function (): number {
|
||||
checkAccess("getExpandCityCost");
|
||||
return getExpandCityCost();
|
||||
},
|
||||
getInvestmentOffer: function(): InvestmentOffer {
|
||||
getInvestmentOffer: function (): InvestmentOffer {
|
||||
checkAccess("getInvestmentOffer");
|
||||
return getInvestmentOffer();
|
||||
},
|
||||
acceptInvestmentOffer: function(): boolean {
|
||||
acceptInvestmentOffer: function (): boolean {
|
||||
checkAccess("acceptInvestmentOffer");
|
||||
return acceptInvestmentOffer();
|
||||
},
|
||||
goPublic: function(anumShares: any): boolean {
|
||||
goPublic: function (anumShares: any): boolean {
|
||||
checkAccess("acceptInvestmentOffer");
|
||||
const numShares = helper.number("goPublic", "numShares", anumShares);
|
||||
return goPublic(numShares);
|
||||
},
|
||||
bribe: function(afactionName: string, aamountCash: any, aamountShares: any): boolean {
|
||||
sellShares: function (anumShares: any): number {
|
||||
checkAccess("acceptInvestmentOffer");
|
||||
const numShares = helper.number("sellStock", "numShares", anumShares);
|
||||
return SellShares(getCorporation(), player, numShares);
|
||||
},
|
||||
buyBackShares: function (anumShares: any): boolean {
|
||||
checkAccess("acceptInvestmentOffer");
|
||||
const numShares = helper.number("buyStock", "numShares", anumShares);
|
||||
return BuyBackShares(getCorporation(), player, numShares);
|
||||
},
|
||||
bribe: function (afactionName: string, aamountCash: any, aamountShares: any): boolean {
|
||||
checkAccess("bribe");
|
||||
const factionName = helper.string("bribe", "factionName", afactionName);
|
||||
const amountCash = helper.number("bribe", "amountCash", aamountCash);
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { WorkerScript } from "../Netscript/WorkerScript";
|
||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||
import { Exploit } from "../Exploits/Exploit";
|
||||
import * as bcrypt from "bcryptjs";
|
||||
import { INetscriptHelper } from "./INetscriptHelper";
|
||||
|
||||
export interface INetscriptExtra {
|
||||
heart: {
|
||||
@ -9,9 +11,10 @@ export interface INetscriptExtra {
|
||||
exploit(): void;
|
||||
bypass(doc: Document): void;
|
||||
alterReality(): void;
|
||||
rainbow(guess: string): void;
|
||||
}
|
||||
|
||||
export function NetscriptExtra(player: IPlayer, workerScript: WorkerScript): INetscriptExtra {
|
||||
export function NetscriptExtra(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): INetscriptExtra {
|
||||
return {
|
||||
heart: {
|
||||
// Easter egg function
|
||||
@ -22,17 +25,18 @@ export function NetscriptExtra(player: IPlayer, workerScript: WorkerScript): INe
|
||||
exploit: function (): void {
|
||||
player.giveExploit(Exploit.UndocumentedFunctionCall);
|
||||
},
|
||||
bypass: function (doc: any): void {
|
||||
bypass: function (doc: unknown): void {
|
||||
// reset both fields first
|
||||
doc.completely_unused_field = undefined;
|
||||
const d = doc as any;
|
||||
d.completely_unused_field = undefined;
|
||||
const real_document: any = document;
|
||||
real_document.completely_unused_field = undefined;
|
||||
// set one to true and check that it affected the other.
|
||||
real_document.completely_unused_field = true;
|
||||
if (doc.completely_unused_field && workerScript.ramUsage === 1.6) {
|
||||
if (d.completely_unused_field && workerScript.ramUsage === 1.6) {
|
||||
player.giveExploit(Exploit.Bypass);
|
||||
}
|
||||
doc.completely_unused_field = undefined;
|
||||
d.completely_unused_field = undefined;
|
||||
real_document.completely_unused_field = undefined;
|
||||
},
|
||||
alterReality: function (): void {
|
||||
@ -50,5 +54,17 @@ export function NetscriptExtra(player: IPlayer, workerScript: WorkerScript): INe
|
||||
player.giveExploit(Exploit.RealityAlteration);
|
||||
}
|
||||
},
|
||||
rainbow: function (guess: unknown): void {
|
||||
async function tryGuess(): Promise<void> {
|
||||
const verified = await bcrypt.compare(
|
||||
helper.string("rainbow", "guess", guess),
|
||||
"$2a$10$aertxDEkgor8baVtQDZsLuMwwGYmkRM/ohcA6FjmmzIHQeTCsrCcO",
|
||||
);
|
||||
if (verified) {
|
||||
player.giveExploit(Exploit.INeedARainbow);
|
||||
}
|
||||
}
|
||||
tryGuess();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -38,40 +38,6 @@ import {
|
||||
calculateAscensionPointsGain,
|
||||
} from "../Gang/formulas/formulas";
|
||||
|
||||
export interface INetscriptFormulas {
|
||||
skills: {
|
||||
calculateSkill(exp: any, mult?: any): any;
|
||||
calculateExp(skill: any, mult?: any): any;
|
||||
};
|
||||
hacking: {
|
||||
hackChance(server: any, player: any): any;
|
||||
hackExp(server: any, player: any): any;
|
||||
hackPercent(server: any, player: any): any;
|
||||
growPercent(server: any, threads: any, player: any, cores?: any): any;
|
||||
hackTime(server: any, player: any): any;
|
||||
growTime(server: any, player: any): any;
|
||||
weakenTime(server: any, player: any): any;
|
||||
};
|
||||
hacknetNodes: {
|
||||
moneyGainRate(level: any, ram: any, cores: any, mult?: any): any;
|
||||
levelUpgradeCost(startingLevel: any, extraLevels?: any, costMult?: any): any;
|
||||
ramUpgradeCost(startingRam: any, extraLevels?: any, costMult?: any): any;
|
||||
coreUpgradeCost(startingCore: any, extraCores?: any, costMult?: any): any;
|
||||
hacknetNodeCost(n: any, mult: any): any;
|
||||
constants(): any;
|
||||
};
|
||||
hacknetServers: {
|
||||
hashGainRate(level: any, ramUsed: any, maxRam: any, cores: any, mult?: any): any;
|
||||
levelUpgradeCost(startingLevel: any, extraLevels?: any, costMult?: any): any;
|
||||
ramUpgradeCost(startingRam: any, extraLevels?: any, costMult?: any): any;
|
||||
coreUpgradeCost(startingCore: any, extraCores?: any, costMult?: any): any;
|
||||
cacheUpgradeCost(startingCache: any, extraCache?: any): any;
|
||||
hashUpgradeCost(upgName: any, level: any): any;
|
||||
hacknetServerCost(n: any, mult: any): any;
|
||||
constants(): any;
|
||||
};
|
||||
}
|
||||
|
||||
export function NetscriptFormulas(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): IFormulas {
|
||||
const checkFormulasAccess = function (func: string): void {
|
||||
if (!player.hasProgram(Programs.Formulas.name)) {
|
||||
@ -80,63 +46,84 @@ export function NetscriptFormulas(player: IPlayer, workerScript: WorkerScript, h
|
||||
};
|
||||
return {
|
||||
skills: {
|
||||
calculateSkill: function (exp: any, mult: any = 1): any {
|
||||
calculateSkill: function (_exp: unknown, _mult: unknown = 1): number {
|
||||
const exp = helper.number("calculateSkill", "exp", _exp);
|
||||
const mult = helper.number("calculateSkill", "mult", _mult);
|
||||
checkFormulasAccess("skills.calculateSkill");
|
||||
return calculateSkill(exp, mult);
|
||||
},
|
||||
calculateExp: function (skill: any, mult: any = 1): any {
|
||||
calculateExp: function (_skill: unknown, _mult: unknown = 1): number {
|
||||
const skill = helper.number("calculateExp", "skill", _skill);
|
||||
const mult = helper.number("calculateExp", "mult", _mult);
|
||||
checkFormulasAccess("skills.calculateExp");
|
||||
return calculateExp(skill, mult);
|
||||
},
|
||||
},
|
||||
hacking: {
|
||||
hackChance: function (server: any, player: any): any {
|
||||
hackChance: function (server: any, player: any): number {
|
||||
checkFormulasAccess("hacking.hackChance");
|
||||
return calculateHackingChance(server, player);
|
||||
},
|
||||
hackExp: function (server: any, player: any): any {
|
||||
hackExp: function (server: any, player: any): number {
|
||||
checkFormulasAccess("hacking.hackExp");
|
||||
return calculateHackingExpGain(server, player);
|
||||
},
|
||||
hackPercent: function (server: any, player: any): any {
|
||||
hackPercent: function (server: any, player: any): number {
|
||||
checkFormulasAccess("hacking.hackPercent");
|
||||
return calculatePercentMoneyHacked(server, player);
|
||||
},
|
||||
growPercent: function (server: any, threads: any, player: any, cores: any = 1): any {
|
||||
growPercent: function (server: any, _threads: unknown, player: any, _cores: unknown = 1): number {
|
||||
const threads = helper.number("growPercent", "threads", _threads);
|
||||
const cores = helper.number("growPercent", "cores", _cores);
|
||||
checkFormulasAccess("hacking.growPercent");
|
||||
return calculateServerGrowth(server, threads, player, cores);
|
||||
},
|
||||
hackTime: function (server: any, player: any): any {
|
||||
hackTime: function (server: any, player: any): number {
|
||||
checkFormulasAccess("hacking.hackTime");
|
||||
return calculateHackingTime(server, player) * 1000;
|
||||
},
|
||||
growTime: function (server: any, player: any): any {
|
||||
growTime: function (server: any, player: any): number {
|
||||
checkFormulasAccess("hacking.growTime");
|
||||
return calculateGrowTime(server, player) * 1000;
|
||||
},
|
||||
weakenTime: function (server: any, player: any): any {
|
||||
weakenTime: function (server: any, player: any): number {
|
||||
checkFormulasAccess("hacking.weakenTime");
|
||||
return calculateWeakenTime(server, player) * 1000;
|
||||
},
|
||||
},
|
||||
hacknetNodes: {
|
||||
moneyGainRate: function (level: any, ram: any, cores: any, mult: any = 1): any {
|
||||
moneyGainRate: function (_level: unknown, _ram: unknown, _cores: unknown, _mult: unknown = 1): number {
|
||||
const level = helper.number("moneyGainRate", "level", _level);
|
||||
const ram = helper.number("moneyGainRate", "ram", _ram);
|
||||
const cores = helper.number("moneyGainRate", "cores", _cores);
|
||||
const mult = helper.number("moneyGainRate", "mult", _mult);
|
||||
checkFormulasAccess("hacknetNodes.moneyGainRate");
|
||||
return calculateMoneyGainRate(level, ram, cores, mult);
|
||||
},
|
||||
levelUpgradeCost: function (startingLevel: any, extraLevels: any = 1, costMult: any = 1): any {
|
||||
levelUpgradeCost: function (_startingLevel: unknown, _extraLevels: unknown = 1, _costMult: unknown = 1): number {
|
||||
const startingLevel = helper.number("levelUpgradeCost", "startingLevel", _startingLevel);
|
||||
const extraLevels = helper.number("levelUpgradeCost", "extraLevels", _extraLevels);
|
||||
const costMult = helper.number("levelUpgradeCost", "costMult", _costMult);
|
||||
checkFormulasAccess("hacknetNodes.levelUpgradeCost");
|
||||
return calculateLevelUpgradeCost(startingLevel, extraLevels, costMult);
|
||||
},
|
||||
ramUpgradeCost: function (startingRam: any, extraLevels: any = 1, costMult: any = 1): any {
|
||||
ramUpgradeCost: function (_startingRam: unknown, _extraLevels: unknown = 1, _costMult: unknown = 1): number {
|
||||
const startingRam = helper.number("ramUpgradeCost", "startingRam", _startingRam);
|
||||
const extraLevels = helper.number("ramUpgradeCost", "extraLevels", _extraLevels);
|
||||
const costMult = helper.number("ramUpgradeCost", "costMult", _costMult);
|
||||
checkFormulasAccess("hacknetNodes.ramUpgradeCost");
|
||||
return calculateRamUpgradeCost(startingRam, extraLevels, costMult);
|
||||
},
|
||||
coreUpgradeCost: function (startingCore: any, extraCores: any = 1, costMult: any = 1): any {
|
||||
coreUpgradeCost: function (_startingCore: unknown, _extraCores: unknown = 1, _costMult: unknown = 1): number {
|
||||
const startingCore = helper.number("coreUpgradeCost", "startingCore", _startingCore);
|
||||
const extraCores = helper.number("coreUpgradeCost", "extraCores", _extraCores);
|
||||
const costMult = helper.number("coreUpgradeCost", "costMult", _costMult);
|
||||
checkFormulasAccess("hacknetNodes.coreUpgradeCost");
|
||||
return calculateCoreUpgradeCost(startingCore, extraCores, costMult);
|
||||
},
|
||||
hacknetNodeCost: function (n: any, mult: any): any {
|
||||
hacknetNodeCost: function (_n: unknown, _mult: unknown): number {
|
||||
const n = helper.number("hacknetNodeCost", "n", _n);
|
||||
const mult = helper.number("hacknetNodeCost", "mult", _mult);
|
||||
checkFormulasAccess("hacknetNodes.hacknetNodeCost");
|
||||
return calculateNodeCost(n, mult);
|
||||
},
|
||||
@ -146,27 +133,51 @@ export function NetscriptFormulas(player: IPlayer, workerScript: WorkerScript, h
|
||||
},
|
||||
},
|
||||
hacknetServers: {
|
||||
hashGainRate: function (level: any, ramUsed: any, maxRam: any, cores: any, mult: any = 1): any {
|
||||
hashGainRate: function (
|
||||
_level: unknown,
|
||||
_ramUsed: unknown,
|
||||
_maxRam: unknown,
|
||||
_cores: unknown,
|
||||
_mult: unknown = 1,
|
||||
): number {
|
||||
const level = helper.number("hashGainRate", "level", _level);
|
||||
const ramUsed = helper.number("hashGainRate", "ramUsed", _ramUsed);
|
||||
const maxRam = helper.number("hashGainRate", "maxRam", _maxRam);
|
||||
const cores = helper.number("hashGainRate", "cores", _cores);
|
||||
const mult = helper.number("hashGainRate", "mult", _mult);
|
||||
checkFormulasAccess("hacknetServers.hashGainRate");
|
||||
return HScalculateHashGainRate(level, ramUsed, maxRam, cores, mult);
|
||||
},
|
||||
levelUpgradeCost: function (startingLevel: any, extraLevels: any = 1, costMult: any = 1): any {
|
||||
levelUpgradeCost: function (_startingLevel: unknown, _extraLevels: unknown = 1, _costMult: unknown = 1): number {
|
||||
const startingLevel = helper.number("levelUpgradeCost", "startingLevel", _startingLevel);
|
||||
const extraLevels = helper.number("levelUpgradeCost", "extraLevels", _extraLevels);
|
||||
const costMult = helper.number("levelUpgradeCost", "costMult", _costMult);
|
||||
checkFormulasAccess("hacknetServers.levelUpgradeCost");
|
||||
return HScalculateLevelUpgradeCost(startingLevel, extraLevels, costMult);
|
||||
},
|
||||
ramUpgradeCost: function (startingRam: any, extraLevels: any = 1, costMult: any = 1): any {
|
||||
ramUpgradeCost: function (_startingRam: unknown, _extraLevels: unknown = 1, _costMult: unknown = 1): number {
|
||||
const startingRam = helper.number("ramUpgradeCost", "startingRam", _startingRam);
|
||||
const extraLevels = helper.number("ramUpgradeCost", "extraLevels", _extraLevels);
|
||||
const costMult = helper.number("ramUpgradeCost", "costMult", _costMult);
|
||||
checkFormulasAccess("hacknetServers.ramUpgradeCost");
|
||||
return HScalculateRamUpgradeCost(startingRam, extraLevels, costMult);
|
||||
},
|
||||
coreUpgradeCost: function (startingCore: any, extraCores: any = 1, costMult: any = 1): any {
|
||||
coreUpgradeCost: function (_startingCore: unknown, _extraCores: unknown = 1, _costMult: unknown = 1): number {
|
||||
const startingCore = helper.number("coreUpgradeCost", "startingCore", _startingCore);
|
||||
const extraCores = helper.number("coreUpgradeCost", "extraCores", _extraCores);
|
||||
const costMult = helper.number("coreUpgradeCost", "costMult", _costMult);
|
||||
checkFormulasAccess("hacknetServers.coreUpgradeCost");
|
||||
return HScalculateCoreUpgradeCost(startingCore, extraCores, costMult);
|
||||
},
|
||||
cacheUpgradeCost: function (startingCache: any, extraCache: any = 1): any {
|
||||
cacheUpgradeCost: function (_startingCache: unknown, _extraCache: unknown = 1): number {
|
||||
const startingCache = helper.number("cacheUpgradeCost", "startingCache", _startingCache);
|
||||
const extraCache = helper.number("cacheUpgradeCost", "extraCache", _extraCache);
|
||||
checkFormulasAccess("hacknetServers.cacheUpgradeCost");
|
||||
return HScalculateCacheUpgradeCost(startingCache, extraCache);
|
||||
},
|
||||
hashUpgradeCost: function (upgName: any, level: any): any {
|
||||
hashUpgradeCost: function (_upgName: unknown, _level: unknown): number {
|
||||
const upgName = helper.string("hashUpgradeCost", "upgName", _upgName);
|
||||
const level = helper.number("hashUpgradeCost", "level", _level);
|
||||
checkFormulasAccess("hacknetServers.hashUpgradeCost");
|
||||
const upg = player.hashManager.getUpgrade(upgName);
|
||||
if (!upg) {
|
||||
@ -177,7 +188,9 @@ export function NetscriptFormulas(player: IPlayer, workerScript: WorkerScript, h
|
||||
}
|
||||
return upg.getCost(level);
|
||||
},
|
||||
hacknetServerCost: function (n: any, mult: any = 1): any {
|
||||
hacknetServerCost: function (_n: unknown, _mult: unknown = 1): number {
|
||||
const n = helper.number("hacknetServerCost", "n", _n);
|
||||
const mult = helper.number("hacknetServerCost", "mult", _mult);
|
||||
checkFormulasAccess("hacknetServers.hacknetServerCost");
|
||||
return HScalculateServerCost(n, mult);
|
||||
},
|
||||
@ -203,11 +216,13 @@ export function NetscriptFormulas(player: IPlayer, workerScript: WorkerScript, h
|
||||
checkFormulasAccess("gang.moneyGain");
|
||||
return calculateMoneyGain(gang, member, task);
|
||||
},
|
||||
ascensionPointsGain: function (exp: any): number {
|
||||
ascensionPointsGain: function (_exp: unknown): number {
|
||||
const exp = helper.number("ascensionPointsGain", "exp", _exp);
|
||||
checkFormulasAccess("gang.ascensionPointsGain");
|
||||
return calculateAscensionPointsGain(exp);
|
||||
},
|
||||
ascensionMultiplier: function (points: any): number {
|
||||
ascensionMultiplier: function (_points: unknown): number {
|
||||
const points = helper.number("ascensionMultiplier", "points", _points);
|
||||
checkFormulasAccess("gang.ascensionMultiplier");
|
||||
return calculateAscensionMult(points);
|
||||
},
|
||||
|
@ -24,10 +24,7 @@ import { Hacknet as IHacknet, NodeStats } from "../ScriptEditor/NetscriptDefinit
|
||||
|
||||
export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): IHacknet {
|
||||
// Utility function to get Hacknet Node object
|
||||
const getHacknetNode = function (i: any, callingFn = ""): HacknetNode | HacknetServer {
|
||||
if (isNaN(i)) {
|
||||
throw helper.makeRuntimeErrorMsg(callingFn, "Invalid index specified for Hacknet Node: " + i);
|
||||
}
|
||||
const getHacknetNode = function (i: number, callingFn = ""): HacknetNode | HacknetServer {
|
||||
if (i < 0 || i >= player.hacknetNodes.length) {
|
||||
throw helper.makeRuntimeErrorMsg(callingFn, "Index specified for Hacknet Node is out-of-bounds: " + i);
|
||||
}
|
||||
@ -72,7 +69,8 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript, he
|
||||
return getCostOfNextHacknetNode(player);
|
||||
}
|
||||
},
|
||||
getNodeStats: function (i: any): NodeStats {
|
||||
getNodeStats: function (_i: unknown): NodeStats {
|
||||
const i = helper.number("getNodeStats", "i", _i);
|
||||
const node = getHacknetNode(i, "getNodeStats");
|
||||
const hasUpgraded = hasHacknetServers(player);
|
||||
const res: any = {
|
||||
@ -93,19 +91,27 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript, he
|
||||
|
||||
return res;
|
||||
},
|
||||
upgradeLevel: function (i: any, n: any): boolean {
|
||||
upgradeLevel: function (_i: unknown, _n: unknown): boolean {
|
||||
const i = helper.number("upgradeLevel", "i", _i);
|
||||
const n = helper.number("upgradeLevel", "n", _n);
|
||||
const node = getHacknetNode(i, "upgradeLevel");
|
||||
return purchaseLevelUpgrade(player, node, n);
|
||||
},
|
||||
upgradeRam: function (i: any, n: any): boolean {
|
||||
upgradeRam: function (_i: unknown, _n: unknown): boolean {
|
||||
const i = helper.number("upgradeRam", "i", _i);
|
||||
const n = helper.number("upgradeRam", "n", _n);
|
||||
const node = getHacknetNode(i, "upgradeRam");
|
||||
return purchaseRamUpgrade(player, node, n);
|
||||
},
|
||||
upgradeCore: function (i: any, n: any): boolean {
|
||||
upgradeCore: function (_i: unknown, _n: unknown): boolean {
|
||||
const i = helper.number("upgradeCore", "i", _i);
|
||||
const n = helper.number("upgradeCore", "n", _n);
|
||||
const node = getHacknetNode(i, "upgradeCore");
|
||||
return purchaseCoreUpgrade(player, node, n);
|
||||
},
|
||||
upgradeCache: function (i: any, n: any): boolean {
|
||||
upgradeCache: function (_i: unknown, _n: unknown): boolean {
|
||||
const i = helper.number("upgradeCache", "i", _i);
|
||||
const n = helper.number("upgradeCache", "n", _n);
|
||||
if (!hasHacknetServers(player)) {
|
||||
return false;
|
||||
}
|
||||
@ -120,19 +126,27 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript, he
|
||||
}
|
||||
return res;
|
||||
},
|
||||
getLevelUpgradeCost: function (i: any, n: any): number {
|
||||
getLevelUpgradeCost: function (_i: unknown, _n: unknown): number {
|
||||
const i = helper.number("getLevelUpgradeCost", "i", _i);
|
||||
const n = helper.number("getLevelUpgradeCost", "n", _n);
|
||||
const node = getHacknetNode(i, "upgradeLevel");
|
||||
return node.calculateLevelUpgradeCost(n, player.hacknet_node_level_cost_mult);
|
||||
},
|
||||
getRamUpgradeCost: function (i: any, n: any): number {
|
||||
getRamUpgradeCost: function (_i: unknown, _n: unknown): number {
|
||||
const i = helper.number("getRamUpgradeCost", "i", _i);
|
||||
const n = helper.number("getRamUpgradeCost", "n", _n);
|
||||
const node = getHacknetNode(i, "upgradeRam");
|
||||
return node.calculateRamUpgradeCost(n, player.hacknet_node_ram_cost_mult);
|
||||
},
|
||||
getCoreUpgradeCost: function (i: any, n: any): number {
|
||||
getCoreUpgradeCost: function (_i: unknown, _n: unknown): number {
|
||||
const i = helper.number("getCoreUpgradeCost", "i", _i);
|
||||
const n = helper.number("getCoreUpgradeCost", "n", _n);
|
||||
const node = getHacknetNode(i, "upgradeCore");
|
||||
return node.calculateCoreUpgradeCost(n, player.hacknet_node_core_cost_mult);
|
||||
},
|
||||
getCacheUpgradeCost: function (i: any, n: any): number {
|
||||
getCacheUpgradeCost: function (_i: unknown, _n: unknown): number {
|
||||
const i = helper.number("getCacheUpgradeCost", "i", _i);
|
||||
const n = helper.number("getCacheUpgradeCost", "n", _n);
|
||||
if (!hasHacknetServers(player)) {
|
||||
return Infinity;
|
||||
}
|
||||
@ -155,26 +169,30 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript, he
|
||||
}
|
||||
return player.hashManager.capacity;
|
||||
},
|
||||
hashCost: function (upgName: any): number {
|
||||
hashCost: function (_upgName: unknown): number {
|
||||
const upgName = helper.string("hashCost", "upgName", _upgName);
|
||||
if (!hasHacknetServers(player)) {
|
||||
return Infinity;
|
||||
}
|
||||
|
||||
return player.hashManager.getUpgradeCost(upgName);
|
||||
},
|
||||
spendHashes: function (upgName: any, upgTarget: any): boolean {
|
||||
spendHashes: function (_upgName: unknown, _upgTarget: unknown): boolean {
|
||||
const upgName = helper.string("spendHashes", "upgName", _upgName);
|
||||
const upgTarget = helper.string("spendHashes", "upgTarget", _upgTarget);
|
||||
if (!hasHacknetServers(player)) {
|
||||
return false;
|
||||
}
|
||||
return purchaseHashUpgrade(player, upgName, upgTarget);
|
||||
},
|
||||
getHashUpgrades: function(): string[] {
|
||||
getHashUpgrades: function (): string[] {
|
||||
if (!hasHacknetServers(player)) {
|
||||
return [];
|
||||
}
|
||||
return Object.values(HashUpgrades).map((upgrade: HashUpgrade) => upgrade.name);
|
||||
},
|
||||
getHashUpgradeLevel: function (upgName: any): number {
|
||||
getHashUpgradeLevel: function (_upgName: unknown): number {
|
||||
const upgName = helper.string("getHashUpgradeLevel", "upgName", _upgName);
|
||||
const level = player.hashManager.upgrades[upgName];
|
||||
if (level === undefined) {
|
||||
throw helper.makeRuntimeErrorMsg("hacknet.hashUpgradeLevel", `Invalid Hash Upgrade: ${upgName}`);
|
||||
|
@ -3,9 +3,9 @@ import { BaseServer } from "../Server/BaseServer";
|
||||
export interface INetscriptHelper {
|
||||
updateDynamicRam(functionName: string, ram: number): void;
|
||||
makeRuntimeErrorMsg(functionName: string, message: string): void;
|
||||
string(funcName: string, argName: string, v: any): string;
|
||||
number(funcName: string, argName: string, v: any): number;
|
||||
boolean(v: any): boolean;
|
||||
string(funcName: string, argName: string, v: unknown): string;
|
||||
number(funcName: string, argName: string, v: unknown): number;
|
||||
boolean(v: unknown): boolean;
|
||||
getServer(ip: any, fn: any): BaseServer;
|
||||
checkSingularityAccess(func: string): void;
|
||||
hack(hostname: string, manual: boolean): Promise<number>;
|
||||
|
@ -1212,7 +1212,7 @@ export function NetscriptSingularity(
|
||||
);
|
||||
return false;
|
||||
}
|
||||
const repNeededToDonate = Math.round(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction);
|
||||
const repNeededToDonate = Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction);
|
||||
if (faction.favor < repNeededToDonate) {
|
||||
workerScript.log(
|
||||
"donateToFaction",
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user