mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-18 13:43:49 +01:00
commit
7afc7d5c78
@ -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"],
|
||||
@ -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": [
|
||||
|
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:
|
||||
|
||||
|
@ -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
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -230,7 +230,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.
|
||||
@ -326,7 +326,7 @@ Then to kill this script the same arguments would have to be used::
|
||||
|
||||
$ kill foo.script 50e3 sigma-cosmetics
|
||||
|
||||
If you are killing the script using its PID, then the PID argument must be numeric.
|
||||
If you are killing the script using its PID, then the PID argument must be numeric.
|
||||
|
||||
killall
|
||||
^^^^^^^
|
||||
@ -533,28 +533,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
|
||||
^^^
|
||||
|
||||
|
@ -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) {
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
49
package-lock.json
generated
49
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "bitburner",
|
||||
"version": "1.4.0",
|
||||
"version": "1.5.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "bitburner",
|
||||
"version": "1.4.0",
|
||||
"version": "1.5.0",
|
||||
"hasInstallScript": true,
|
||||
"license": "SEE LICENSE IN license.txt",
|
||||
"dependencies": {
|
||||
@ -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",
|
||||
@ -3977,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",
|
||||
@ -4068,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",
|
||||
@ -5448,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",
|
||||
@ -25344,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",
|
||||
@ -25435,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",
|
||||
@ -26527,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",
|
||||
|
@ -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",
|
||||
|
@ -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.
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React from "react";
|
||||
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/";
|
||||
|
||||
@ -10,6 +12,14 @@ const style = {
|
||||
} 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 =
|
||||
<>
|
||||
|
@ -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,
|
||||
});
|
||||
|
@ -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:
|
||||
|
@ -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`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -119,17 +119,17 @@ export function SellMaterial(mat: Material, amt: string, price: string): void {
|
||||
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)) {
|
||||
@ -156,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 {
|
||||
@ -184,11 +184,11 @@ 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 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) {
|
||||
@ -201,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)) {
|
||||
@ -218,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;
|
||||
@ -229,7 +228,6 @@ export function SellProduct(product: Product, city: string, amt: string, price:
|
||||
product.sllman[city][0] = true;
|
||||
product.sllman[city][1] = qty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -117,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 {
|
||||
@ -166,8 +165,7 @@ 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 +
|
||||
@ -177,7 +175,6 @@ export function purchaseAugmentation(aug: Augmentation, fac: Faction, sing = fal
|
||||
"augmentations will now be more expensive.",
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dialogBoxCreate(
|
||||
"Hmm, something went wrong when trying to purchase an Augmentation. " +
|
||||
|
@ -28,7 +28,7 @@ type IProps = {
|
||||
};
|
||||
|
||||
// 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 " +
|
||||
|
@ -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";
|
||||
@ -51,6 +58,28 @@ export function FactionsRoot(props: IProps): React.ReactElement {
|
||||
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>
|
||||
@ -82,11 +111,7 @@ export function FactionsRoot(props: IProps): React.ReactElement {
|
||||
<TableCell align="right">
|
||||
<Box ml={1} mb={1}>
|
||||
<Button sx={{ width: '100%' }} onClick={() => openFactionAugPage(Factions[faction])}>
|
||||
Augmentations Left: {Factions[faction]
|
||||
.augmentations
|
||||
.filter((augmentation: string) =>
|
||||
!props.player.hasAugmentation(augmentation))
|
||||
.length}
|
||||
Augmentations Left: {getAugsLeft(Factions[faction], props.player)}
|
||||
</Button>
|
||||
</Box>
|
||||
</TableCell>
|
||||
|
@ -52,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)");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -174,7 +174,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
throw makeRuntimeRejectMsg(
|
||||
workerScript,
|
||||
`Invalid scriptArgs argument passed into getRunningScript() from ${callingFnName}(). ` +
|
||||
`This is probably a bug. Please report to game developer`,
|
||||
`This is probably a bug. Please report to game developer`,
|
||||
);
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
@ -692,7 +699,8 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
workerScript.log(
|
||||
"weaken",
|
||||
() =>
|
||||
`'${server.hostname}' security level weakened to ${server.hackDifficulty
|
||||
`'${server.hostname}' security level weakened to ${
|
||||
server.hackDifficulty
|
||||
}. Gained ${numeralWrapper.formatExp(expGain)} hacking exp (t=${numeralWrapper.formatThreads(threads)})`,
|
||||
);
|
||||
workerScript.scriptRef.onlineExpGained += expGain;
|
||||
@ -701,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 * 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 () {
|
||||
@ -713,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.");
|
||||
}
|
||||
@ -751,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.");
|
||||
}
|
||||
@ -775,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;
|
||||
@ -791,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];
|
||||
@ -803,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];
|
||||
},
|
||||
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));
|
||||
@ -818,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;
|
||||
@ -1084,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...");
|
||||
@ -1647,7 +1669,10 @@ 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`);
|
||||
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`);
|
||||
}
|
||||
@ -1769,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",
|
||||
@ -1857,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();
|
||||
@ -1916,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();
|
||||
@ -1964,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 {
|
||||
@ -2095,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 "";
|
||||
}
|
||||
@ -2102,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 {
|
||||
@ -2109,17 +2140,20 @@ 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"`);
|
||||
|
||||
message = argsToString([message]);
|
||||
SnackbarEvents.emit(message, variant, duration);
|
||||
},
|
||||
prompt: function (txt: any): any {
|
||||
prompt: function (txt: any, options?: { type?: string; options?: string[] }): any {
|
||||
updateDynamicRam("prompt", getRamCost(Player, "prompt"));
|
||||
if (!isString(txt)) {
|
||||
txt = JSON.stringify(txt);
|
||||
}
|
||||
@ -2127,11 +2161,13 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
|
||||
return new Promise(function (resolve) {
|
||||
PromptEvent.emit({
|
||||
txt: txt,
|
||||
options,
|
||||
resolve: resolve,
|
||||
});
|
||||
});
|
||||
},
|
||||
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);
|
||||
@ -2173,7 +2209,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({
|
||||
@ -2184,7 +2220,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,
|
||||
@ -2273,16 +2309,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(); }; // Wrap the user function to prevent WorkerScript leaking as 'this'
|
||||
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"));
|
||||
|
@ -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>;
|
||||
|
@ -32,9 +32,9 @@ export function NetscriptStanek(player: IPlayer, workerScript: WorkerScript, hel
|
||||
checkStanekAPIAccess("height");
|
||||
return staneksGift.height();
|
||||
},
|
||||
charge: function (arootX: unknown, arootY: unknown): Promise<void> {
|
||||
const rootX = helper.number("stanek.charge", "rootX", arootX);
|
||||
const rootY = helper.number("stanek.charge", "rootY", arootY);
|
||||
charge: function (_rootX: unknown, _rootY: unknown): Promise<void> {
|
||||
const rootX = helper.number("stanek.charge", "rootX", _rootX);
|
||||
const rootY = helper.number("stanek.charge", "rootY", _rootY);
|
||||
|
||||
helper.updateDynamicRam("charge", getRamCost(player, "stanek", "charge"));
|
||||
checkStanekAPIAccess("charge");
|
||||
@ -67,11 +67,11 @@ export function NetscriptStanek(player: IPlayer, workerScript: WorkerScript, hel
|
||||
workerScript.log("stanek.clear", () => `Cleared Stanek's Gift.`);
|
||||
staneksGift.clear();
|
||||
},
|
||||
canPlace: function (arootX: unknown, arootY: unknown, arotation: unknown, afragmentId: unknown): boolean {
|
||||
const rootX = helper.number("stanek.canPlace", "rootX", arootX);
|
||||
const rootY = helper.number("stanek.canPlace", "rootY", arootY);
|
||||
const rotation = helper.number("stanek.canPlace", "rotation", arotation);
|
||||
const fragmentId = helper.number("stanek.canPlace", "fragmentId", afragmentId);
|
||||
canPlace: function (_rootX: unknown, _rootY: unknown, _rotation: unknown, _fragmentId: unknown): boolean {
|
||||
const rootX = helper.number("stanek.canPlace", "rootX", _rootX);
|
||||
const rootY = helper.number("stanek.canPlace", "rootY", _rootY);
|
||||
const rotation = helper.number("stanek.canPlace", "rotation", _rotation);
|
||||
const fragmentId = helper.number("stanek.canPlace", "fragmentId", _fragmentId);
|
||||
helper.updateDynamicRam("canPlace", getRamCost(player, "stanek", "canPlace"));
|
||||
checkStanekAPIAccess("canPlace");
|
||||
const fragment = FragmentById(fragmentId);
|
||||
@ -79,29 +79,29 @@ export function NetscriptStanek(player: IPlayer, workerScript: WorkerScript, hel
|
||||
const can = staneksGift.canPlace(rootX, rootY, rotation, fragment);
|
||||
return can;
|
||||
},
|
||||
place: function (arootX: unknown, arootY: unknown, arotation: unknown, afragmentId: unknown): boolean {
|
||||
const rootX = helper.number("stanek.place", "rootX", arootX);
|
||||
const rootY = helper.number("stanek.place", "rootY", arootY);
|
||||
const rotation = helper.number("stanek.place", "rotation", arotation);
|
||||
const fragmentId = helper.number("stanek.place", "fragmentId", afragmentId);
|
||||
place: function (_rootX: unknown, _rootY: unknown, _rotation: unknown, _fragmentId: unknown): boolean {
|
||||
const rootX = helper.number("stanek.place", "rootX", _rootX);
|
||||
const rootY = helper.number("stanek.place", "rootY", _rootY);
|
||||
const rotation = helper.number("stanek.place", "rotation", _rotation);
|
||||
const fragmentId = helper.number("stanek.place", "fragmentId", _fragmentId);
|
||||
helper.updateDynamicRam("place", getRamCost(player, "stanek", "place"));
|
||||
checkStanekAPIAccess("place");
|
||||
const fragment = FragmentById(fragmentId);
|
||||
if (!fragment) throw helper.makeRuntimeErrorMsg("stanek.place", `Invalid fragment id: ${fragmentId}`);
|
||||
return staneksGift.place(rootX, rootY, rotation, fragment);
|
||||
},
|
||||
get: function (arootX: unknown, arootY: unknown): IActiveFragment | undefined {
|
||||
const rootX = helper.number("stanek.get", "rootX", arootX);
|
||||
const rootY = helper.number("stanek.get", "rootY", arootY);
|
||||
get: function (_rootX: unknown, _rootY: unknown): IActiveFragment | undefined {
|
||||
const rootX = helper.number("stanek.get", "rootX", _rootX);
|
||||
const rootY = helper.number("stanek.get", "rootY", _rootY);
|
||||
helper.updateDynamicRam("get", getRamCost(player, "stanek", "get"));
|
||||
checkStanekAPIAccess("get");
|
||||
const fragment = staneksGift.findFragment(rootX, rootY);
|
||||
if (fragment !== undefined) return fragment.copy();
|
||||
return undefined;
|
||||
},
|
||||
remove: function (arootX: unknown, arootY: unknown): boolean {
|
||||
const rootX = helper.number("stanek.remove", "rootX", arootX);
|
||||
const rootY = helper.number("stanek.remove", "rootY", arootY);
|
||||
remove: function (_rootX: unknown, _rootY: unknown): boolean {
|
||||
const rootX = helper.number("stanek.remove", "rootX", _rootX);
|
||||
const rootY = helper.number("stanek.remove", "rootY", _rootY);
|
||||
helper.updateDynamicRam("remove", getRamCost(player, "stanek", "remove"));
|
||||
checkStanekAPIAccess("remove");
|
||||
return staneksGift.delete(rootX, rootY);
|
||||
|
@ -34,33 +34,37 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
|
||||
return stock;
|
||||
};
|
||||
return {
|
||||
getSymbols: function (): any {
|
||||
getSymbols: function (): string[] {
|
||||
helper.updateDynamicRam("getSymbols", getRamCost(player, "stock", "getSymbols"));
|
||||
checkTixApiAccess("getSymbols");
|
||||
return Object.values(StockSymbols);
|
||||
},
|
||||
getPrice: function (symbol: any): any {
|
||||
getPrice: function (_symbol: unknown): number {
|
||||
const symbol = helper.string("getPrice", "symbol", _symbol);
|
||||
helper.updateDynamicRam("getPrice", getRamCost(player, "stock", "getPrice"));
|
||||
checkTixApiAccess("getPrice");
|
||||
const stock = getStockFromSymbol(symbol, "getPrice");
|
||||
|
||||
return stock.price;
|
||||
},
|
||||
getAskPrice: function (symbol: any): any {
|
||||
getAskPrice: function (_symbol: unknown): number {
|
||||
const symbol = helper.string("getAskPrice", "symbol", _symbol);
|
||||
helper.updateDynamicRam("getAskPrice", getRamCost(player, "stock", "getAskPrice"));
|
||||
checkTixApiAccess("getAskPrice");
|
||||
const stock = getStockFromSymbol(symbol, "getAskPrice");
|
||||
|
||||
return stock.getAskPrice();
|
||||
},
|
||||
getBidPrice: function (symbol: any): any {
|
||||
getBidPrice: function (_symbol: unknown): number {
|
||||
const symbol = helper.string("getBidPrice", "symbol", _symbol);
|
||||
helper.updateDynamicRam("getBidPrice", getRamCost(player, "stock", "getBidPrice"));
|
||||
checkTixApiAccess("getBidPrice");
|
||||
const stock = getStockFromSymbol(symbol, "getBidPrice");
|
||||
|
||||
return stock.getBidPrice();
|
||||
},
|
||||
getPosition: function (symbol: any): any {
|
||||
getPosition: function (_symbol: unknown): [number, number, number, number] {
|
||||
const symbol = helper.string("getPosition", "symbol", _symbol);
|
||||
helper.updateDynamicRam("getPosition", getRamCost(player, "stock", "getPosition"));
|
||||
checkTixApiAccess("getPosition");
|
||||
const stock = SymbolToStockMap[symbol];
|
||||
@ -69,14 +73,18 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
|
||||
}
|
||||
return [stock.playerShares, stock.playerAvgPx, stock.playerShortShares, stock.playerAvgShortPx];
|
||||
},
|
||||
getMaxShares: function (symbol: any): any {
|
||||
getMaxShares: function (_symbol: unknown): number {
|
||||
const symbol = helper.string("getMaxShares", "symbol", _symbol);
|
||||
helper.updateDynamicRam("getMaxShares", getRamCost(player, "stock", "getMaxShares"));
|
||||
checkTixApiAccess("getMaxShares");
|
||||
const stock = getStockFromSymbol(symbol, "getMaxShares");
|
||||
|
||||
return stock.maxShares;
|
||||
},
|
||||
getPurchaseCost: function (symbol: any, shares: any, posType: any): any {
|
||||
getPurchaseCost: function (_symbol: unknown, _shares: unknown, _posType: unknown): number {
|
||||
const symbol = helper.string("getPurchaseCost", "symbol", _symbol);
|
||||
let shares = helper.number("getPurchaseCost", "shares", _shares);
|
||||
const posType = helper.string("getPurchaseCost", "posType", _posType);
|
||||
helper.updateDynamicRam("getPurchaseCost", getRamCost(player, "stock", "getPurchaseCost"));
|
||||
checkTixApiAccess("getPurchaseCost");
|
||||
const stock = getStockFromSymbol(symbol, "getPurchaseCost");
|
||||
@ -99,7 +107,10 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
|
||||
|
||||
return res;
|
||||
},
|
||||
getSaleGain: function (symbol: any, shares: any, posType: any): any {
|
||||
getSaleGain: function (_symbol: unknown, _shares: unknown, _posType: unknown): number {
|
||||
const symbol = helper.string("getSaleGain", "symbol", _symbol);
|
||||
let shares = helper.number("getSaleGain", "shares", _shares);
|
||||
const posType = helper.string("getSaleGain", "posType", _posType);
|
||||
helper.updateDynamicRam("getSaleGain", getRamCost(player, "stock", "getSaleGain"));
|
||||
checkTixApiAccess("getSaleGain");
|
||||
const stock = getStockFromSymbol(symbol, "getSaleGain");
|
||||
@ -122,14 +133,18 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
|
||||
|
||||
return res;
|
||||
},
|
||||
buy: function (symbol: any, shares: any): any {
|
||||
buy: function (_symbol: unknown, _shares: unknown): number {
|
||||
const symbol = helper.string("buy", "symbol", _symbol);
|
||||
const shares = helper.number("buy", "shares", _shares);
|
||||
helper.updateDynamicRam("buy", getRamCost(player, "stock", "buy"));
|
||||
checkTixApiAccess("buy");
|
||||
const stock = getStockFromSymbol(symbol, "buy");
|
||||
const res = buyStock(stock, shares, workerScript, {});
|
||||
return res ? stock.getAskPrice() : 0;
|
||||
},
|
||||
sell: function (symbol: any, shares: any): any {
|
||||
sell: function (_symbol: unknown, _shares: unknown): number {
|
||||
const symbol = helper.string("sell", "symbol", _symbol);
|
||||
const shares = helper.number("sell", "shares", _shares);
|
||||
helper.updateDynamicRam("sell", getRamCost(player, "stock", "sell"));
|
||||
checkTixApiAccess("sell");
|
||||
const stock = getStockFromSymbol(symbol, "sell");
|
||||
@ -137,7 +152,9 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
|
||||
|
||||
return res ? stock.getBidPrice() : 0;
|
||||
},
|
||||
short: function (symbol: any, shares: any): any {
|
||||
short: function (_symbol: unknown, _shares: unknown): number {
|
||||
const symbol = helper.string("short", "symbol", _symbol);
|
||||
const shares = helper.number("short", "shares", _shares);
|
||||
helper.updateDynamicRam("short", getRamCost(player, "stock", "short"));
|
||||
checkTixApiAccess("short");
|
||||
if (player.bitNodeN !== 8) {
|
||||
@ -153,7 +170,9 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
|
||||
|
||||
return res ? stock.getBidPrice() : 0;
|
||||
},
|
||||
sellShort: function (symbol: any, shares: any): any {
|
||||
sellShort: function (_symbol: unknown, _shares: unknown): number {
|
||||
const symbol = helper.string("sellShort", "symbol", _symbol);
|
||||
const shares = helper.number("sellShort", "shares", _shares);
|
||||
helper.updateDynamicRam("sellShort", getRamCost(player, "stock", "sellShort"));
|
||||
checkTixApiAccess("sellShort");
|
||||
if (player.bitNodeN !== 8) {
|
||||
@ -169,7 +188,12 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
|
||||
|
||||
return res ? stock.getAskPrice() : 0;
|
||||
},
|
||||
placeOrder: function (symbol: any, shares: any, price: any, type: any, pos: any): any {
|
||||
placeOrder: function (_symbol: unknown, _shares: unknown, _price: unknown, _type: unknown, _pos: unknown): boolean {
|
||||
const symbol = helper.string("placeOrder", "symbol", _symbol);
|
||||
const shares = helper.number("placeOrder", "shares", _shares);
|
||||
const price = helper.number("placeOrder", "price", _price);
|
||||
const type = helper.string("placeOrder", "type", _type);
|
||||
const pos = helper.string("placeOrder", "pos", _pos);
|
||||
helper.updateDynamicRam("placeOrder", getRamCost(player, "stock", "placeOrder"));
|
||||
checkTixApiAccess("placeOrder");
|
||||
if (player.bitNodeN !== 8) {
|
||||
@ -208,7 +232,18 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
|
||||
|
||||
return placeOrder(stock, shares, price, orderType, orderPos, workerScript);
|
||||
},
|
||||
cancelOrder: function (symbol: any, shares: any, price: any, type: any, pos: any): any {
|
||||
cancelOrder: function (
|
||||
_symbol: unknown,
|
||||
_shares: unknown,
|
||||
_price: unknown,
|
||||
_type: unknown,
|
||||
_pos: unknown,
|
||||
): boolean {
|
||||
const symbol = helper.string("cancelOrder", "symbol", _symbol);
|
||||
const shares = helper.number("cancelOrder", "shares", _shares);
|
||||
const price = helper.number("cancelOrder", "price", _price);
|
||||
const type = helper.string("cancelOrder", "type", _type);
|
||||
const pos = helper.string("cancelOrder", "pos", _pos);
|
||||
helper.updateDynamicRam("cancelOrder", getRamCost(player, "stock", "cancelOrder"));
|
||||
checkTixApiAccess("cancelOrder");
|
||||
if (player.bitNodeN !== 8) {
|
||||
@ -290,7 +325,8 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
|
||||
|
||||
return orders;
|
||||
},
|
||||
getVolatility: function (symbol: any): any {
|
||||
getVolatility: function (_symbol: unknown): number {
|
||||
const symbol = helper.string("getVolatility", "symbol", _symbol);
|
||||
helper.updateDynamicRam("getVolatility", getRamCost(player, "stock", "getVolatility"));
|
||||
if (!player.has4SDataTixApi) {
|
||||
throw helper.makeRuntimeErrorMsg("getVolatility", "You don't have 4S Market Data TIX API Access!");
|
||||
@ -299,7 +335,8 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
|
||||
|
||||
return stock.mv / 100; // Convert from percentage to decimal
|
||||
},
|
||||
getForecast: function (symbol: any): any {
|
||||
getForecast: function (_symbol: unknown): number {
|
||||
const symbol = helper.string("getForecast", "symbol", _symbol);
|
||||
helper.updateDynamicRam("getForecast", getRamCost(player, "stock", "getForecast"));
|
||||
if (!player.has4SDataTixApi) {
|
||||
throw helper.makeRuntimeErrorMsg("getForecast", "You don't have 4S Market Data TIX API Access!");
|
||||
@ -310,7 +347,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
|
||||
stock.b ? (forecast += stock.otlkMag) : (forecast -= stock.otlkMag);
|
||||
return forecast / 100; // Convert from percentage to decimal
|
||||
},
|
||||
purchase4SMarketData: function () {
|
||||
purchase4SMarketData: function (): boolean {
|
||||
helper.updateDynamicRam("purchase4SMarketData", getRamCost(player, "stock", "purchase4SMarketData"));
|
||||
checkTixApiAccess("purchase4SMarketData");
|
||||
|
||||
@ -329,7 +366,7 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
|
||||
workerScript.log("stock.purchase4SMarketData", () => "Purchased 4S Market Data");
|
||||
return true;
|
||||
},
|
||||
purchase4SMarketDataTixApi: function () {
|
||||
purchase4SMarketDataTixApi: function (): boolean {
|
||||
helper.updateDynamicRam("purchase4SMarketDataTixApi", getRamCost(player, "stock", "purchase4SMarketDataTixApi"));
|
||||
checkTixApiAccess("purchase4SMarketDataTixApi");
|
||||
|
||||
|
@ -375,7 +375,7 @@ function processNetscript1Imports(code: string, workerScript: WorkerScript): any
|
||||
});
|
||||
|
||||
//Now we have to generate the code that would create the namespace
|
||||
generatedCode += "var " + namespace + ";\n" + "(function (namespace) {\n";
|
||||
generatedCode += `var ${namespace};\n(function (namespace) {\n`;
|
||||
|
||||
//Add the function declarations
|
||||
fnDeclarations.forEach((fn: any) => {
|
||||
@ -390,7 +390,7 @@ function processNetscript1Imports(code: string, workerScript: WorkerScript): any
|
||||
});
|
||||
|
||||
//Finish
|
||||
generatedCode += "})(" + namespace + " || " + "(" + namespace + " = {}));\n";
|
||||
generatedCode += `})(${namespace} || (" + namespace + " = {}));\n`;
|
||||
} else {
|
||||
//import {...} from script
|
||||
|
||||
|
@ -363,11 +363,11 @@ export class PlayerObject implements IPlayer {
|
||||
this.companyName = ""; // Name of Company. Must match a key value in Companies ma;
|
||||
|
||||
// Servers
|
||||
this.currentServer = ""; //IP address of Server currently being accessed through termina;
|
||||
this.purchasedServers = []; //IP Addresses of purchased server;
|
||||
this.currentServer = ""; //hostname of Server currently being accessed through termina;
|
||||
this.purchasedServers = []; //hostnames of purchased server;
|
||||
|
||||
// Hacknet Nodes/Servers
|
||||
this.hacknetNodes = []; // Note= For Hacknet Servers, this array holds the IP addresses of the server;
|
||||
this.hacknetNodes = []; // Note= For Hacknet Servers, this array holds the hostnames of the server;
|
||||
this.hashManager = new HashManager();
|
||||
|
||||
//Factions
|
||||
@ -483,11 +483,11 @@ export class PlayerObject implements IPlayer {
|
||||
// Let's get a hash of some semi-random stuff so we have something unique.
|
||||
this.identifier = cyrb53(
|
||||
"I-" +
|
||||
new Date().getTime() +
|
||||
navigator.userAgent +
|
||||
window.innerWidth +
|
||||
window.innerHeight +
|
||||
getRandomInt(100, 999),
|
||||
new Date().getTime() +
|
||||
navigator.userAgent +
|
||||
window.innerWidth +
|
||||
window.innerHeight +
|
||||
getRandomInt(100, 999),
|
||||
);
|
||||
|
||||
this.init = generalMethods.init;
|
||||
|
@ -608,11 +608,9 @@ export function process(this: IPlayer, router: IRouter, numCycles = 1): void {
|
||||
if (this.workPartTime(numCycles)) {
|
||||
router.toCity();
|
||||
}
|
||||
} else {
|
||||
if (this.work(numCycles)) {
|
||||
} else if (this.work(numCycles)) {
|
||||
router.toCity();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1315,9 +1313,7 @@ export function createProgramWork(this: IPlayer, numCycles: number): boolean {
|
||||
export function finishCreateProgramWork(this: IPlayer, cancelled: boolean): string {
|
||||
const programName = this.createProgramName;
|
||||
if (cancelled === false) {
|
||||
dialogBoxCreate(
|
||||
"You've finished creating " + programName + "!<br>" + "The new program can be found on your home computer.",
|
||||
);
|
||||
dialogBoxCreate(`You've finished creating ${programName}!<br>The new program can be found on your home computer.`);
|
||||
|
||||
this.getHomeComputer().programs.push(programName);
|
||||
} else {
|
||||
@ -2244,8 +2240,7 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
|
||||
if (!(fulcrumSecretServer instanceof Server)) throw new Error("Fulcrum Secret Technologies should be normal server");
|
||||
if (fulcrumSecretServer == null) {
|
||||
console.error("Could not find Fulcrum Secret Technologies Server");
|
||||
} else {
|
||||
if (
|
||||
} else if (
|
||||
!fulcrumsecrettechonologiesFac.isBanned &&
|
||||
!fulcrumsecrettechonologiesFac.isMember &&
|
||||
!fulcrumsecrettechonologiesFac.alreadyInvited &&
|
||||
@ -2254,7 +2249,6 @@ export function checkForFactionInvitations(this: IPlayer): Faction[] {
|
||||
) {
|
||||
invitedFactions.push(fulcrumsecrettechonologiesFac);
|
||||
}
|
||||
}
|
||||
|
||||
//BitRunners
|
||||
const bitrunnersFac = Factions["BitRunners"];
|
||||
|
@ -34,7 +34,32 @@ export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentat
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
const validMults = [
|
||||
"hacking_mult",
|
||||
"strength_mult",
|
||||
"defense_mult",
|
||||
"dexterity_mult",
|
||||
"agility_mult",
|
||||
"charisma_mult",
|
||||
"hacking_exp_mult",
|
||||
"strength_exp_mult",
|
||||
"defense_exp_mult",
|
||||
"dexterity_exp_mult",
|
||||
"agility_exp_mult",
|
||||
"charisma_exp_mult",
|
||||
"company_rep_mult",
|
||||
"faction_rep_mult",
|
||||
"crime_money_mult",
|
||||
"crime_success_mult",
|
||||
"work_money_mult",
|
||||
];
|
||||
for (const mult of Object.keys(aug.mults)) {
|
||||
if (validMults.includes(mult)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// If player is in a gang, then we return all augs that the player
|
||||
|
@ -1,9 +1,19 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { use } from "../../ui/Context";
|
||||
import { getAvailableCreatePrograms } from "../ProgramHelpers";
|
||||
import { find } from "lodash";
|
||||
|
||||
import { Box, Tooltip, Typography } from "@mui/material";
|
||||
import Button from "@mui/material/Button";
|
||||
import {
|
||||
Box,
|
||||
Typography,
|
||||
Button,
|
||||
Container,
|
||||
Paper
|
||||
} from "@mui/material";
|
||||
import { Check, Lock, Create } from "@mui/icons-material";
|
||||
|
||||
import { use } from "../../ui/Context";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
|
||||
import { Programs } from "../Programs";
|
||||
|
||||
export const ProgramsSeen: string[] = [];
|
||||
|
||||
@ -15,7 +25,20 @@ export function ProgramsRoot(): React.ReactElement {
|
||||
setRerender((old) => !old);
|
||||
}
|
||||
|
||||
const programs = getAvailableCreatePrograms(player);
|
||||
const programs = [...Object.values(Programs)]
|
||||
.filter(prog => {
|
||||
const create = prog.create;
|
||||
if (create === null) return false;
|
||||
if (prog.name === "b1t_flum3.exe") {
|
||||
return create.req(player);
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.sort((a, b) => {
|
||||
if (player.hasProgram(a.name)) return 1;
|
||||
if (player.hasProgram(b.name)) return -1;
|
||||
return (a.create?.level ?? 0) - (b.create?.level ?? 0);
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
programs.forEach((p) => {
|
||||
@ -29,8 +52,27 @@ export function ProgramsRoot(): React.ReactElement {
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
|
||||
const getHackingLevelRemaining = (lvl: number): number => {
|
||||
return Math.ceil(Math.max(lvl - (player.hacking + player.intelligence / 2), 0));
|
||||
}
|
||||
|
||||
const getProgCompletion = (name: string): number => {
|
||||
const programFile = find(player.getHomeComputer().programs, p => {
|
||||
return (p.startsWith(name) && p.endsWith("%-INC"));
|
||||
});
|
||||
if (!programFile) return -1;
|
||||
|
||||
const res = programFile.split("-");
|
||||
if (res.length != 3) return -1;
|
||||
const percComplete = Number(res[1].slice(0, -1));
|
||||
if (isNaN(percComplete) || percComplete < 0 || percComplete >= 100) {
|
||||
return -1;
|
||||
}
|
||||
return percComplete;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Container disableGutters maxWidth="lg" sx={{ mx: 0, mb: 10 }}>
|
||||
<Typography variant="h4">Create program</Typography>
|
||||
<Typography>
|
||||
This page displays any programs that you are able to create. Writing the code for a program takes time, which
|
||||
@ -38,30 +80,45 @@ export function ProgramsRoot(): React.ReactElement {
|
||||
time. Your progress will be saved and you can continue later.
|
||||
</Typography>
|
||||
|
||||
<Box sx={{ display: 'grid', width: 'fit-content' }}>
|
||||
<Box sx={{ display: 'grid', gridTemplateColumns: "repeat(3, 1fr)", my: 1 }}>
|
||||
{programs.map((program) => {
|
||||
const create = program.create;
|
||||
if (create === null) return <></>;
|
||||
const curCompletion = getProgCompletion(program.name);
|
||||
|
||||
return (
|
||||
<React.Fragment key={program.name}>
|
||||
<Tooltip title={create.tooltip}>
|
||||
<Button
|
||||
sx={{ my: 1 }}
|
||||
onClick={(event) => {
|
||||
if (!event.isTrusted) return;
|
||||
player.startCreateProgramWork(program.name, create.time, create.level);
|
||||
player.startFocusing();
|
||||
router.toWork();
|
||||
}}
|
||||
>
|
||||
{program.name}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</React.Fragment>
|
||||
<Box component={Paper} sx={{ p: 1, opacity: player.hasProgram(program.name) ? 0.75 : 1 }} key={program.name}>
|
||||
<Typography variant="h6" sx={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap' }}>
|
||||
{player.hasProgram(program.name) && <Check sx={{ mr: 1 }} /> ||
|
||||
(create.req(player) && <Create sx={{ mr: 1 }} /> || <Lock sx={{ mr: 1 }} />)}
|
||||
{program.name}
|
||||
</Typography>
|
||||
{(!player.hasProgram(program.name) && create.req(player)) && <Button
|
||||
sx={{ my: 1, width: '100%' }}
|
||||
onClick={(event) => {
|
||||
if (!event.isTrusted) return;
|
||||
player.startCreateProgramWork(program.name, create.time, create.level);
|
||||
player.startFocusing();
|
||||
router.toWork();
|
||||
}}
|
||||
>
|
||||
Create program
|
||||
</Button>}
|
||||
{(player.hasProgram(program.name) || getHackingLevelRemaining(create.level) === 0) ||
|
||||
<Typography color={Settings.theme.hack}>
|
||||
<b>Unlocks in:</b> {getHackingLevelRemaining(create.level)} hacking levels
|
||||
</Typography>}
|
||||
{(curCompletion !== -1) &&
|
||||
<Typography color={Settings.theme.infolight}>
|
||||
<b>Current completion:</b> {curCompletion}%
|
||||
</Typography>}
|
||||
<Typography>
|
||||
{create.tooltip}
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
</>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ function giveSourceFile(bitNodeNumber: number): void {
|
||||
if (alreadyOwned && ownedSourceFile) {
|
||||
if (ownedSourceFile.lvl >= 3 && ownedSourceFile.n !== 12) {
|
||||
dialogBoxCreate(
|
||||
"The Source-File for the BitNode you just destroyed, " + sourceFile.name + ", " + "is already at max level!",
|
||||
`The Source-File for the BitNode you just destroyed, ${sourceFile.name}, is already at max level!`,
|
||||
);
|
||||
} else {
|
||||
++ownedSourceFile.lvl;
|
||||
@ -75,12 +75,10 @@ function giveSourceFile(bitNodeNumber: number): void {
|
||||
export function enterBitNode(router: IRouter, flume: boolean, destroyedBitNode: number, newBitNode: number): void {
|
||||
if (!flume) {
|
||||
giveSourceFile(destroyedBitNode);
|
||||
} else {
|
||||
if (SourceFileFlags[5] === 0 && newBitNode !== 5) {
|
||||
} else if (SourceFileFlags[5] === 0 && newBitNode !== 5) {
|
||||
Player.intelligence = 0;
|
||||
Player.intelligence_exp = 0;
|
||||
}
|
||||
}
|
||||
if (newBitNode === 5 && Player.intelligence === 0) {
|
||||
Player.intelligence = 1;
|
||||
}
|
||||
|
37
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
37
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
@ -94,6 +94,7 @@ interface Player {
|
||||
factions: string[];
|
||||
tor: boolean;
|
||||
hasCorporation: boolean;
|
||||
inBladeburner: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2784,7 +2785,7 @@ export interface Bladeburner {
|
||||
*
|
||||
* Note that this is meant to be used for Contracts and Operations.
|
||||
* This function will return ‘Infinity’ for actions such as Training and Field Analysis.
|
||||
* This function will return 1 for BlackOps not yet completed regardless of wether
|
||||
* This function will return 1 for BlackOps not yet completed regardless of whether
|
||||
* the player has the required rank to attempt the mission or not.
|
||||
*
|
||||
* @param type - Type of action.
|
||||
@ -2824,7 +2825,7 @@ export interface Bladeburner {
|
||||
getActionCurrentLevel(type: string, name: string): number;
|
||||
|
||||
/**
|
||||
* Get wether an action is set to autolevel.
|
||||
* Get whether an action is set to autolevel.
|
||||
* @remarks
|
||||
* RAM cost: 4 GB
|
||||
*
|
||||
@ -5983,19 +5984,25 @@ export interface NS extends Singularity {
|
||||
tFormat(milliseconds: number, milliPrecision?: boolean): string;
|
||||
|
||||
/**
|
||||
* Prompt the player with a Yes/No modal.
|
||||
* Prompt the player with an input modal.
|
||||
* @remarks
|
||||
* RAM cost: 0 GB
|
||||
*
|
||||
* Prompts the player with a dialog box with two options: “Yes” and “No”.
|
||||
* This function will return true if the player click “Yes” and false if
|
||||
* the player clicks “No”. The script’s execution is halted until the player
|
||||
* selects one of the options.
|
||||
* Prompts the player with a dialog box. If `options.type` is undefined or "boolean",
|
||||
* the player is shown "Yes" and "No" prompts, which return true and false respectively.
|
||||
* Passing a type of "text" will give the player a text field and a value of "select"
|
||||
* will show a drop-down field. Choosing type "select" will require an array or object
|
||||
* to be passed via the `options.choices` property.
|
||||
* The script’s execution is halted until the player selects one of the options.
|
||||
*
|
||||
* @param txt - Text to appear in the prompt dialog box.
|
||||
* @returns True if the player click “Yes” and false if the player clicks “No”.
|
||||
* @param options - Options to modify the prompt the player is shown.
|
||||
* @returns True if the player click “Yes”; false if the player clicks “No”; or the value entered by the player.
|
||||
*/
|
||||
prompt(txt: string): Promise<boolean>;
|
||||
prompt(
|
||||
txt: string,
|
||||
options?: { type?: "boolean" | "text" | "select" | undefined; choices?: string[] },
|
||||
): Promise<boolean | string>;
|
||||
|
||||
/**
|
||||
* Open up a message box.
|
||||
@ -6385,12 +6392,12 @@ export interface WarehouseAPI {
|
||||
*/
|
||||
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
|
||||
*/
|
||||
* 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
|
||||
|
@ -17,6 +17,7 @@ import { calculateRamUsage, checkInfiniteLoop } from "../../Script/RamCalculatio
|
||||
import { RamCalculationErrorCode } from "../../Script/RamCalculationErrorCodes";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
|
||||
import SearchIcon from "@mui/icons-material/Search";
|
||||
|
||||
import { NetscriptFunctions } from "../../NetscriptFunctions";
|
||||
import { WorkerScript } from "../../Netscript/WorkerScript";
|
||||
@ -42,7 +43,7 @@ import { PromptEvent } from "../../ui/React/PromptManager";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
|
||||
import libSource from "!!raw-loader!../NetscriptDefinitions.d.ts";
|
||||
import { Tooltip } from "@mui/material";
|
||||
import { TextField, Tooltip } from "@mui/material";
|
||||
|
||||
interface IProps {
|
||||
// Map of filename -> code
|
||||
@ -53,7 +54,7 @@ interface IProps {
|
||||
vim: boolean;
|
||||
}
|
||||
|
||||
// TODO: try to removve global symbols
|
||||
// TODO: try to remove global symbols
|
||||
let symbolsLoaded = false;
|
||||
let symbols: string[] = [];
|
||||
export function SetupTextEditor(): void {
|
||||
@ -113,6 +114,8 @@ export function Root(props: IProps): React.ReactElement {
|
||||
const vimStatusRef = useRef<HTMLElement>(null);
|
||||
const [vimEditor, setVimEditor] = useState<any>(null);
|
||||
const [editor, setEditor] = useState<IStandaloneCodeEditor | null>(null);
|
||||
const [filter, setFilter] = useState("");
|
||||
const [searchExpanded, setSearchExpanded] = useState(false);
|
||||
|
||||
const [ram, setRAM] = useState("RAM: ???");
|
||||
const [ramEntries, setRamEntries] = useState<string[][]>([["???", ""]]);
|
||||
@ -232,7 +235,7 @@ export function Root(props: IProps): React.ReactElement {
|
||||
MonacoVim.VimMode.Vim.mapCommand("gT", "action", "prevTabs", {}, { context: "normal" });
|
||||
editor.focus();
|
||||
});
|
||||
} catch {}
|
||||
} catch { }
|
||||
} else if (!options.vim) {
|
||||
// Whem vim mode is disabled
|
||||
vimEditor?.dispose();
|
||||
@ -478,7 +481,7 @@ export function Root(props: IProps): React.ReactElement {
|
||||
}
|
||||
try {
|
||||
infLoop(newCode);
|
||||
} catch (err) {}
|
||||
} catch (err) { }
|
||||
}
|
||||
|
||||
function saveScript(scriptToSave: OpenScript): void {
|
||||
@ -523,7 +526,7 @@ export function Root(props: IProps): React.ReactElement {
|
||||
const textFile = new TextFile(scriptToSave.fileName, scriptToSave.code);
|
||||
server.textFiles.push(textFile);
|
||||
} else {
|
||||
dialogBoxCreate("Invalid filename. Must be either a script (.script, .js, or .ns) or " + " or text file (.txt)");
|
||||
dialogBoxCreate("Invalid filename. Must be either a script (.script, .js, or .ns) or a text file (.txt)");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -607,7 +610,7 @@ export function Root(props: IProps): React.ReactElement {
|
||||
const textFile = new TextFile(currentScript.fileName, currentScript.code);
|
||||
server.textFiles.push(textFile);
|
||||
} else {
|
||||
dialogBoxCreate("Invalid filename. Must be either a script (.script, .js, or .ns) or " + " or text file (.txt)");
|
||||
dialogBoxCreate("Invalid filename. Must be either a script (.script, .js, or .ns) or a text file (.txt)");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -688,7 +691,7 @@ export function Root(props: IProps): React.ReactElement {
|
||||
if (serverScriptIndex === -1 || savedScriptCode !== server.scripts[serverScriptIndex as number].code) {
|
||||
PromptEvent.emit({
|
||||
txt: "Do you want to save changes to " + closingScript.fileName + "?",
|
||||
resolve: (result: boolean) => {
|
||||
resolve: (result: boolean | string) => {
|
||||
if (result) {
|
||||
// Save changes
|
||||
closingScript.code = savedScriptCode;
|
||||
@ -745,7 +748,7 @@ export function Root(props: IProps): React.ReactElement {
|
||||
"Do you want to overwrite the current editor content with the contents of " +
|
||||
openScript.fileName +
|
||||
" on the server? This cannot be undone.",
|
||||
resolve: (result: boolean) => {
|
||||
resolve: (result: boolean | string) => {
|
||||
if (result) {
|
||||
// Save changes
|
||||
openScript.code = serverScriptCode;
|
||||
@ -787,6 +790,16 @@ export function Root(props: IProps): React.ReactElement {
|
||||
const serverScript = server.scripts.find((s) => s.filename === openScript.fileName);
|
||||
return serverScript?.code ?? null;
|
||||
}
|
||||
function handleFilterChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
setFilter(event.target.value);
|
||||
}
|
||||
function handleExpandSearch(): void {
|
||||
setFilter("")
|
||||
setSearchExpanded(!searchExpanded)
|
||||
}
|
||||
const filteredOpenScripts = Object.values(openScripts).filter(
|
||||
(script) => (script.hostname.includes(filter) || script.fileName.includes(filter))
|
||||
);
|
||||
|
||||
// Toolbars are roughly 112px:
|
||||
// 8px body margin top
|
||||
@ -797,7 +810,7 @@ export function Root(props: IProps): React.ReactElement {
|
||||
const editorHeight = dimensions.height - (130 + (options.vim ? 34 : 0));
|
||||
const tabsMaxWidth = 1640;
|
||||
const tabMargin = 5;
|
||||
const tabMaxWidth = openScripts.length ? tabsMaxWidth / openScripts.length - tabMargin : 0;
|
||||
const tabMaxWidth = filteredOpenScripts.length ? tabsMaxWidth / filteredOpenScripts.length - tabMargin : 0;
|
||||
const tabIconWidth = 25;
|
||||
const tabTextWidth = tabMaxWidth - tabIconWidth * 2;
|
||||
return (
|
||||
@ -821,23 +834,36 @@ export function Root(props: IProps): React.ReactElement {
|
||||
overflowX: "scroll",
|
||||
}}
|
||||
>
|
||||
{openScripts.map(({ fileName, hostname }, index) => {
|
||||
<Tooltip title={"Search Open Scripts"}>
|
||||
{searchExpanded ?
|
||||
<TextField
|
||||
value={filter}
|
||||
onChange={handleFilterChange}
|
||||
autoFocus
|
||||
InputProps={{
|
||||
startAdornment: <SearchIcon />,
|
||||
spellCheck: false,
|
||||
endAdornment: <CloseIcon onClick={handleExpandSearch} />
|
||||
}}
|
||||
/> : <Button onClick={handleExpandSearch} ><SearchIcon /></Button>}
|
||||
</Tooltip>
|
||||
{filteredOpenScripts.map(({ fileName, hostname }, index) => {
|
||||
const iconButtonStyle = {
|
||||
maxWidth: `${tabIconWidth}px`,
|
||||
minWidth: `${tabIconWidth}px`,
|
||||
minHeight: "38.5px",
|
||||
maxHeight: "38.5px",
|
||||
...(currentScript?.fileName === openScripts[index].fileName
|
||||
...(currentScript?.fileName === filteredOpenScripts[index].fileName
|
||||
? {
|
||||
background: Settings.theme.button,
|
||||
borderColor: Settings.theme.button,
|
||||
color: Settings.theme.primary,
|
||||
}
|
||||
background: Settings.theme.button,
|
||||
borderColor: Settings.theme.button,
|
||||
color: Settings.theme.primary,
|
||||
}
|
||||
: {
|
||||
background: Settings.theme.backgroundsecondary,
|
||||
borderColor: Settings.theme.backgroundsecondary,
|
||||
color: Settings.theme.secondary,
|
||||
}),
|
||||
background: Settings.theme.backgroundsecondary,
|
||||
borderColor: Settings.theme.backgroundsecondary,
|
||||
color: Settings.theme.secondary,
|
||||
}),
|
||||
};
|
||||
|
||||
const scriptTabText = `${hostname}:~/${fileName} ${dirty(index)}`;
|
||||
@ -870,18 +896,19 @@ export function Root(props: IProps): React.ReactElement {
|
||||
}}
|
||||
style={{
|
||||
maxWidth: `${tabTextWidth}px`,
|
||||
minHeight: '38.5px',
|
||||
overflow: "hidden",
|
||||
...(currentScript?.fileName === openScripts[index].fileName
|
||||
...(currentScript?.fileName === filteredOpenScripts[index].fileName
|
||||
? {
|
||||
background: Settings.theme.button,
|
||||
borderColor: Settings.theme.button,
|
||||
color: Settings.theme.primary,
|
||||
}
|
||||
background: Settings.theme.button,
|
||||
borderColor: Settings.theme.button,
|
||||
color: Settings.theme.primary,
|
||||
}
|
||||
: {
|
||||
background: Settings.theme.backgroundsecondary,
|
||||
borderColor: Settings.theme.backgroundsecondary,
|
||||
color: Settings.theme.secondary,
|
||||
}),
|
||||
background: Settings.theme.backgroundsecondary,
|
||||
borderColor: Settings.theme.backgroundsecondary,
|
||||
color: Settings.theme.secondary,
|
||||
}),
|
||||
}}
|
||||
>
|
||||
<span style={{ overflow: "hidden", direction: "rtl", textOverflow: "ellipsis" }}>
|
||||
|
@ -78,12 +78,11 @@ export function ipExists(ip: string): boolean {
|
||||
}
|
||||
|
||||
export function createUniqueRandomIp(): string {
|
||||
const ip = createRandomIp();
|
||||
|
||||
// If the Ip already exists, recurse to create a new one
|
||||
if (ipExists(ip)) {
|
||||
return createRandomIp();
|
||||
}
|
||||
let ip: string;
|
||||
// Repeat generating ip, until unique one is found
|
||||
do {
|
||||
ip = createRandomIp();
|
||||
} while (ipExists(ip));
|
||||
|
||||
return ip;
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ export class BaseServer {
|
||||
// Script files on this Server
|
||||
scripts: Script[] = [];
|
||||
|
||||
// Contains the IP Addresses of all servers that are immediately
|
||||
// Contains the hostnames of all servers that are immediately
|
||||
// reachable from this one
|
||||
serversOnNetwork: string[] = [];
|
||||
|
||||
|
@ -143,11 +143,6 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
||||
const augmentationCount = props.player.queuedAugmentations.length;
|
||||
const invitationsCount = props.player.factionInvitations.filter((f) => !InvitationsSeen.includes(f)).length;
|
||||
const programCount = getAvailableCreatePrograms(props.player).length - ProgramsSeen.length;
|
||||
const canCreateProgram =
|
||||
getAvailableCreatePrograms(props.player).length > 0 ||
|
||||
props.player.augmentations.length > 0 ||
|
||||
props.player.queuedAugmentations.length > 0 ||
|
||||
props.player.sourceFiles.length > 0;
|
||||
|
||||
const canOpenFactions =
|
||||
props.player.factionInvitations.length > 0 ||
|
||||
@ -439,29 +434,27 @@ export function SidebarRoot(props: IProps): React.ReactElement {
|
||||
</Typography>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
{canCreateProgram && (
|
||||
<ListItem
|
||||
button
|
||||
key={"Create Program"}
|
||||
className={clsx({
|
||||
[classes.active]: props.page === Page.CreateProgram,
|
||||
})}
|
||||
onClick={clickCreateProgram}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<Badge badgeContent={programCount > 0 ? programCount : undefined} color="error">
|
||||
<Tooltip title={!open ? "Create Program" : ""}>
|
||||
<BugReportIcon color={props.page !== Page.CreateProgram ? "secondary" : "primary"} />
|
||||
</Tooltip>
|
||||
</Badge>
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
<Typography color={props.page !== Page.CreateProgram ? "secondary" : "primary"}>
|
||||
Create Program
|
||||
</Typography>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
)}
|
||||
<ListItem
|
||||
button
|
||||
key={"Create Program"}
|
||||
className={clsx({
|
||||
[classes.active]: props.page === Page.CreateProgram,
|
||||
})}
|
||||
onClick={clickCreateProgram}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<Badge badgeContent={programCount > 0 ? programCount : undefined} color="error">
|
||||
<Tooltip title={!open ? "Create Program" : ""}>
|
||||
<BugReportIcon color={props.page !== Page.CreateProgram ? "secondary" : "primary"} />
|
||||
</Tooltip>
|
||||
</Badge>
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
<Typography color={props.page !== Page.CreateProgram ? "secondary" : "primary"}>
|
||||
Create Program
|
||||
</Typography>
|
||||
</ListItemText>
|
||||
</ListItem>
|
||||
{canStaneksGift && (
|
||||
<ListItem
|
||||
button
|
||||
|
@ -66,10 +66,9 @@ SourceFiles["SourceFile5"] = new SourceFile(
|
||||
<>
|
||||
This Source-File grants 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. In addition, this Source-File will unlock the
|
||||
getBitNodeMultipliers() Netscript function and let you start with Formulas.exe, and will raise all of your
|
||||
hacking-related multipliers by:
|
||||
stats. Higher Intelligence levels will boost your production for many actions in the game. In addition, this
|
||||
Source-File will unlock the getBitNodeMultipliers() Netscript function and let you start with Formulas.exe, and
|
||||
will raise all of your hacking-related multipliers by:
|
||||
<br />
|
||||
<br />
|
||||
Level 1: 8%
|
||||
|
@ -117,7 +117,7 @@ export function buyStock(
|
||||
const resultTxt =
|
||||
`Bought ${numeralWrapper.formatShares(shares)} shares of ${stock.symbol} for ${numeralWrapper.formatMoney(
|
||||
totalPrice,
|
||||
)}. ` + `Paid ${numeralWrapper.formatMoney(CONSTANTS.StockMarketCommission)} in commission fees.`;
|
||||
)}. Paid ${numeralWrapper.formatMoney(CONSTANTS.StockMarketCommission)} in commission fees.`;
|
||||
workerScript.log("stock.buy", () => resultTxt);
|
||||
} else if (opts.suppressDialog !== true) {
|
||||
dialogBoxCreate(
|
||||
|
@ -165,8 +165,7 @@ function executeOrder(order: Order, refs: IProcessOrderRefs): void {
|
||||
|
||||
console.error("Could not find the following Order in Order Book: ");
|
||||
console.error(order);
|
||||
} else {
|
||||
if (isBuy) {
|
||||
} else if (isBuy) {
|
||||
dialogBoxCreate(
|
||||
<>
|
||||
Failed to execute {order.type} for {stock.symbol} @ <Money money={order.price} /> ({pos}). This is most likely
|
||||
@ -174,5 +173,4 @@ function executeOrder(order: Order, refs: IProcessOrderRefs): void {
|
||||
</>,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -213,13 +213,11 @@ export class Stock {
|
||||
} else {
|
||||
this.otlkMag -= changeAmt;
|
||||
}
|
||||
} else {
|
||||
} else if (this.b) {
|
||||
// Forecast decreases
|
||||
if (this.b) {
|
||||
this.otlkMag -= changeAmt;
|
||||
} else {
|
||||
this.otlkMag += changeAmt;
|
||||
}
|
||||
this.otlkMag -= changeAmt;
|
||||
} else {
|
||||
this.otlkMag += changeAmt;
|
||||
}
|
||||
|
||||
this.otlkMag = Math.min(this.otlkMag, 50);
|
||||
|
@ -113,11 +113,9 @@ export function StockTicker(props: IProps): React.ReactElement {
|
||||
if (qty > stock.playerShares) {
|
||||
return <>You do not have this many shares in the Long position</>;
|
||||
}
|
||||
} else {
|
||||
if (qty > stock.playerShortShares) {
|
||||
} else if (qty > stock.playerShortShares) {
|
||||
return <>You do not have this many shares in the Short position</>;
|
||||
}
|
||||
}
|
||||
|
||||
const cost = getSellTransactionGain(stock, qty, position);
|
||||
if (cost == null) {
|
||||
|
@ -190,7 +190,7 @@ export const HelpTexts: IMap<string[]> = {
|
||||
connect: [
|
||||
"Usage: connect [hostname]",
|
||||
" ",
|
||||
"Connect to a remote server. The hostname or IP address of the remote server must be given as the argument ",
|
||||
"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.",
|
||||
" ",
|
||||
|
@ -68,13 +68,11 @@ export function ParseCommand(command: string): (string | number | boolean)[] {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (inQuote === ``) {
|
||||
} else if (inQuote === ``) {
|
||||
inQuote = `"`;
|
||||
} else if (inQuote === `"`) {
|
||||
inQuote = ``;
|
||||
}
|
||||
}
|
||||
} else if (c === "'") {
|
||||
// Single quotes, same thing as above
|
||||
if (!escaped && prevChar === " ") {
|
||||
@ -88,13 +86,11 @@ export function ParseCommand(command: string): (string | number | boolean)[] {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (inQuote === ``) {
|
||||
} else if (inQuote === ``) {
|
||||
inQuote = `'`;
|
||||
} else if (inQuote === `'`) {
|
||||
inQuote = ``;
|
||||
}
|
||||
}
|
||||
} else if (c === " " && inQuote === ``) {
|
||||
const arg = command.substr(start, i - start);
|
||||
|
||||
|
@ -167,7 +167,7 @@ export function ls(
|
||||
|
||||
function postSegments(segments: string[], style?: any, linked?: boolean): void {
|
||||
const maxLength = Math.max(...segments.map((s) => s.length)) + 1;
|
||||
const filesPerRow = Math.floor(80 / maxLength);
|
||||
const filesPerRow = Math.ceil(80 / maxLength);
|
||||
for (let i = 0; i < segments.length; i++) {
|
||||
let row = "";
|
||||
for (let col = 0; col < filesPerRow; col++) {
|
||||
@ -179,13 +179,11 @@ export function ls(
|
||||
i--;
|
||||
if (!style) {
|
||||
terminal.print(row);
|
||||
} else {
|
||||
if (linked) {
|
||||
} else if (linked) {
|
||||
terminal.printRaw(<ClickableScriptRow row={row} prefix={prefix} hostname={server.hostname} />);
|
||||
} else {
|
||||
terminal.printRaw(<span style={style}>{row}</span>);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,11 +14,9 @@ export function unalias(
|
||||
if (args.length !== 1) {
|
||||
terminal.error("Incorrect usage of unalias name. Usage: unalias [alias]");
|
||||
return;
|
||||
} else {
|
||||
if (removeAlias(args[0] + "")) {
|
||||
} else if (removeAlias(args[0] + "")) {
|
||||
terminal.print(`Removed alias ${args[0]}`);
|
||||
} else {
|
||||
terminal.error(`No such alias exists: ${args[0]}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,28 +66,22 @@ export function tabCompletion(
|
||||
if (arg === "") {
|
||||
if (longestStartSubstr === command) {
|
||||
return allPossibilities;
|
||||
} else {
|
||||
if (semiColonIndex === -1) {
|
||||
} else if (semiColonIndex === -1) {
|
||||
// No semicolon, so replace the whole command
|
||||
return longestStartSubstr;
|
||||
} else {
|
||||
// Replace only after the last semicolon
|
||||
return `${oldValue.slice(0, semiColonIndex + 1)} ${longestStartSubstr}`;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (longestStartSubstr === arg) {
|
||||
} else if (longestStartSubstr === arg) {
|
||||
// List all possible options
|
||||
return allPossibilities;
|
||||
} else {
|
||||
if (semiColonIndex == -1) {
|
||||
} else if (semiColonIndex == -1) {
|
||||
// No semicolon, so replace the whole command
|
||||
return `${command} ${longestStartSubstr}`;
|
||||
} else {
|
||||
// Replace only after the last semicolon
|
||||
return `${oldValue.slice(0, semiColonIndex + 1)} ${command} ${longestStartSubstr}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -640,7 +640,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
||||
"of the path, you may only move to adjacent numbers in the row below.",
|
||||
"The triangle is represented as a 2D array of numbers:\n\n",
|
||||
`${triangle}\n\n`,
|
||||
"Example: If you are given the following triangle:\n\n" + "[\n",
|
||||
"Example: If you are given the following triangle:\n\n[\n",
|
||||
" [2],\n",
|
||||
" [3,4],\n",
|
||||
" [6,5,7],\n",
|
||||
|
@ -56,7 +56,7 @@ export function ServerAccordions(props: IProps): React.ReactElement {
|
||||
for (const ws of props.workerScripts.values()) {
|
||||
const server = GetServer(ws.hostname);
|
||||
if (server == null) {
|
||||
console.warn(`WorkerScript has invalid IP address: ${ws.hostname}`);
|
||||
console.warn(`WorkerScript has invalid hostname: ${ws.hostname}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -86,6 +86,9 @@ function Intelligence(): React.ReactElement {
|
||||
<TableCell align="right">
|
||||
<Typography>{numeralWrapper.formatSkill(player.intelligence)} </Typography>
|
||||
</TableCell>
|
||||
<TableCell align="right">
|
||||
<Typography noWrap>({numeralWrapper.formatExp(player.intelligence_exp)} exp)</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
|
@ -33,23 +33,34 @@ interface IProps {
|
||||
}
|
||||
|
||||
function Intelligence(): React.ReactElement {
|
||||
const theme = useTheme();
|
||||
const player = use.Player();
|
||||
const classes = useStyles();
|
||||
if (player.intelligence === 0) return <></>;
|
||||
const progress = player.calculateSkillProgress(player.intelligence_exp);
|
||||
|
||||
return (
|
||||
<TableRow>
|
||||
<TableCell component="th" scope="row" classes={{ root: classes.cell }}>
|
||||
<Typography classes={{ root: classes.int }}>Int </Typography>
|
||||
</TableCell>
|
||||
<TableCell align="right" classes={{ root: classes.cell }}>
|
||||
<Typography classes={{ root: classes.int }}>{numeralWrapper.formatSkill(player.intelligence)}</Typography>
|
||||
</TableCell>
|
||||
<TableCell align="right" classes={{ root: classes.cell }}>
|
||||
<Typography id="overview-int-hook" classes={{ root: classes.int }}>
|
||||
{/*Hook for player scripts*/}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<>
|
||||
<TableRow>
|
||||
<TableCell component="th" scope="row" classes={{ root: classes.cell }}>
|
||||
<Typography classes={{ root: classes.int }}>Int </Typography>
|
||||
</TableCell>
|
||||
<TableCell align="right" classes={{ root: classes.cell }}>
|
||||
<Typography classes={{ root: classes.int }}>{numeralWrapper.formatSkill(player.intelligence)}</Typography>
|
||||
</TableCell>
|
||||
<TableCell align="right" classes={{ root: classes.cell }}>
|
||||
<Typography id="overview-int-hook" classes={{ root: classes.int }}>
|
||||
{/*Hook for player scripts*/}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
||||
<TableRow>
|
||||
{!Settings.DisableOverviewProgressBars && (
|
||||
<StatsProgressOverviewCell progress={progress} color={theme.colors.int} />
|
||||
)}
|
||||
</TableRow>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -3,54 +3,150 @@ import { EventEmitter } from "../../utils/EventEmitter";
|
||||
import { Modal } from "./Modal";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Button from "@mui/material/Button";
|
||||
import Select, { SelectChangeEvent } from "@mui/material/Select";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
|
||||
export const PromptEvent = new EventEmitter<[Prompt]>();
|
||||
|
||||
interface Prompt {
|
||||
txt: string;
|
||||
resolve: (result: boolean) => void;
|
||||
options?: { type?: string; choices?: string[] };
|
||||
resolve: (result: boolean | string) => void;
|
||||
}
|
||||
|
||||
export function PromptManager(): React.ReactElement {
|
||||
const [prompt, setPrompt] = useState<Prompt | null>(null);
|
||||
useEffect(
|
||||
() =>
|
||||
PromptEvent.subscribe((p: Prompt) => {
|
||||
setPrompt(p);
|
||||
}),
|
||||
[],
|
||||
);
|
||||
useEffect(() => {
|
||||
return PromptEvent.subscribe((p: Prompt) => {
|
||||
setPrompt(p);
|
||||
});
|
||||
}, []);
|
||||
|
||||
if (prompt === null) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
function close(): void {
|
||||
if (prompt === null) return;
|
||||
prompt.resolve(false);
|
||||
if (["text", "select"].includes(prompt?.options?.type ?? "")) {
|
||||
prompt.resolve("");
|
||||
} else {
|
||||
prompt.resolve(false);
|
||||
}
|
||||
setPrompt(null);
|
||||
}
|
||||
|
||||
function yes(): void {
|
||||
if (prompt === null) return;
|
||||
prompt.resolve(true);
|
||||
const types: { [key: string]: any } = {
|
||||
text: PromptMenuText,
|
||||
select: PromptMenuSelect,
|
||||
};
|
||||
|
||||
let PromptContent = PromptMenuBoolean;
|
||||
if (prompt?.options?.type) PromptContent = types[prompt?.options?.type];
|
||||
|
||||
const resolve = (value: boolean | string): void => {
|
||||
prompt.resolve(value);
|
||||
setPrompt(null);
|
||||
}
|
||||
function no(): void {
|
||||
if (prompt === null) return;
|
||||
prompt.resolve(false);
|
||||
setPrompt(null);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal open={true} onClose={close}>
|
||||
<Typography>{prompt.txt}</Typography>
|
||||
<PromptContent prompt={prompt} resolve={resolve} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
interface IContentProps {
|
||||
prompt: Prompt;
|
||||
resolve: (value: boolean | string) => void;
|
||||
}
|
||||
|
||||
function PromptMenuBoolean({ resolve }: IContentProps): React.ReactElement {
|
||||
const yes = (): void => resolve(true);
|
||||
const no = (): void => resolve(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
{prompt != null && (
|
||||
<Modal open={true} onClose={close}>
|
||||
<pre>
|
||||
<Typography>{prompt.txt}</Typography>
|
||||
</pre>
|
||||
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', paddingTop: '10px' }}>
|
||||
<Button style={{ marginRight: 'auto' }} onClick={yes}>Yes</Button>
|
||||
<Button onClick={no}>No</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
)}
|
||||
<div style={{ display: "flex", justifyContent: "center", alignItems: "center", paddingTop: "10px" }}>
|
||||
<Button style={{ marginRight: "auto" }} onClick={yes}>
|
||||
Yes
|
||||
</Button>
|
||||
<Button onClick={no}>No</Button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function PromptMenuText({ resolve }: IContentProps): React.ReactElement {
|
||||
const [value, setValue] = useState("");
|
||||
|
||||
const submit = (): void => resolve(value);
|
||||
|
||||
const onInput = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
setValue(event.target.value);
|
||||
};
|
||||
|
||||
const onKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {
|
||||
event.stopPropagation();
|
||||
|
||||
if (event.key === "Enter") {
|
||||
event.preventDefault();
|
||||
submit();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ display: "flex", alignItems: "center", paddingTop: "10px" }}>
|
||||
<TextField
|
||||
autoFocus
|
||||
value={value}
|
||||
onInput={onInput}
|
||||
onKeyDown={onKeyDown}
|
||||
style={{ flex: "1 0 auto" }}
|
||||
InputProps={{
|
||||
endAdornment: <Button onClick={submit}>Confirm</Button>,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function PromptMenuSelect({ prompt, resolve }: IContentProps): React.ReactElement {
|
||||
const [value, setValue] = useState("");
|
||||
|
||||
const submit = (): void => resolve(value);
|
||||
|
||||
const onChange = (event: SelectChangeEvent<string>): void => {
|
||||
setValue(event.target.value);
|
||||
};
|
||||
|
||||
const getItems = (choices: string[]): React.ReactElement[] => {
|
||||
const content = [];
|
||||
for (const i of choices) {
|
||||
// @ts-ignore
|
||||
content.push(
|
||||
<MenuItem key={i} value={i}>
|
||||
{i}
|
||||
</MenuItem>,
|
||||
);
|
||||
}
|
||||
return content;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ display: "flex", alignItems: "center", paddingTop: "10px" }}>
|
||||
<Select onChange={onChange} value={value} style={{ flex: "1 0 auto" }}>
|
||||
{getItems(prompt?.options?.choices || [])}
|
||||
</Select>
|
||||
<Button onClick={submit} disabled={value === ""}>
|
||||
Confirm
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -17,8 +17,7 @@ export function validateObject<Type extends Record<string, unknown>, Key extends
|
||||
if (paramValidator !== undefined) {
|
||||
if (typeof paramValidator === 'function') {
|
||||
paramValidator(obj, key);
|
||||
} else {
|
||||
if (paramValidator.func !== undefined) {
|
||||
} else if (paramValidator.func !== undefined) {
|
||||
paramValidator.func(obj, validator, key);
|
||||
} else {
|
||||
if ((typeof obj[key]) !== (typeof paramValidator.default)) {
|
||||
@ -31,7 +30,6 @@ export function validateObject<Type extends Record<string, unknown>, Key extends
|
||||
if (obj[key] > paramValidator.max) obj[key] = paramValidator.max as Type[Key];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -94,9 +94,9 @@ export function v1APIBreak(): void {
|
||||
|
||||
if (s.length === 0) continue;
|
||||
|
||||
txt += `// Detected change ${change[0]}, reason: ${change[1]}` + "\n";
|
||||
txt += `// Detected change ${change[0]}, reason: ${change[1]}\n`;
|
||||
for (const fl of s) {
|
||||
txt += `${fl.file}:${fl.line}` + "\n";
|
||||
txt += `${fl.file}:${fl.line}\n`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ async function main(version, versionNumber, changelog) {
|
||||
join('\n').replaceAll('`', '\\`');
|
||||
|
||||
modifiedConstants = modifiedConstants.
|
||||
replace(/(^\s*?LatestUpdate:\s`\n)(.*)`,$/ms, `$1${paddedChangelog}\n` + "`,");
|
||||
replace(/(^\s*?LatestUpdate:\s`\n)(.*)`,$/ms, `$1${paddedChangelog}\n\`,`);
|
||||
}
|
||||
await fs.writeFile(appPaths.constants, modifiedConstants);
|
||||
console.log(`Modified ${appPaths.constants}`);
|
||||
|
Loading…
Reference in New Issue
Block a user