Merge pull request #1879 from danielyxie/dev

bugfix
This commit is contained in:
hydroflame 2021-12-14 15:56:31 -05:00 committed by GitHub
commit a8f764bb8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 451942 additions and 101 deletions

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="256"
height="256"
viewBox="0 0 67.733332 67.733335"
version="1.1"
id="svg5"
inkscape:version="1.1.1 (c3084ef, 2021-09-22)"
sodipodi:docname="BN13+.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="true"
units="px"
inkscape:zoom="2.326908"
inkscape:cx="86.81048"
inkscape:cy="111.09163"
inkscape:window-width="2423"
inkscape:window-height="1341"
inkscape:window-x="146"
inkscape:window-y="29"
inkscape:window-maximized="0"
inkscape:current-layer="layer1">
<inkscape:grid
type="xygrid"
id="grid824" />
</sodipodi:namedview>
<defs
id="defs2" />
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="background">
<rect
style="fill:#000000;stroke:none;stroke-width:7.02745"
id="rect849"
width="67.73333"
height="67.73333"
x="0"
y="0" />
</g>
<g
inkscape:label="main"
inkscape:groupmode="layer"
id="layer1">
<text
xml:space="preserve"
style="font-weight:bold;font-size:16.0737px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';text-align:center;text-anchor:middle;fill:#00ff00;fill-opacity:1;stroke-width:0.215272"
x="34.276661"
y="40.084541"
id="text8876"><tspan
sodipodi:role="line"
style="text-align:center;text-anchor:middle;fill:#00ff00;fill-opacity:1;stroke-width:0.215272"
x="34.276661"
y="40.084541"
id="tspan20241">BN13+</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

File diff suppressed because one or more lines are too long

@ -0,0 +1,415 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
define('vs/basic-languages/typescript/typescript',["require", "exports", "../fillers/monaco-editor-core"], function (require, exports, monaco_editor_core_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.language = exports.conf = void 0;
exports.conf = {
wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,
comments: {
lineComment: '//',
blockComment: ['/*', '*/']
},
brackets: [
['{', '}'],
['[', ']'],
['(', ')']
],
onEnterRules: [
{
// e.g. /** | */
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
afterText: /^\s*\*\/$/,
action: {
indentAction: monaco_editor_core_1.languages.IndentAction.IndentOutdent,
appendText: ' * '
}
},
{
// e.g. /** ...|
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
action: {
indentAction: monaco_editor_core_1.languages.IndentAction.None,
appendText: ' * '
}
},
{
// e.g. * ...|
beforeText: /^(\t|(\ \ ))*\ \*(\ ([^\*]|\*(?!\/))*)?$/,
action: {
indentAction: monaco_editor_core_1.languages.IndentAction.None,
appendText: '* '
}
},
{
// e.g. */|
beforeText: /^(\t|(\ \ ))*\ \*\/\s*$/,
action: {
indentAction: monaco_editor_core_1.languages.IndentAction.None,
removeText: 1
}
}
],
autoClosingPairs: [
{ open: '{', close: '}' },
{ open: '[', close: ']' },
{ open: '(', close: ')' },
{ open: '"', close: '"', notIn: ['string'] },
{ open: "'", close: "'", notIn: ['string', 'comment'] },
{ open: '`', close: '`', notIn: ['string', 'comment'] },
{ open: '/**', close: ' */', notIn: ['string'] }
],
folding: {
markers: {
start: new RegExp('^\\s*//\\s*#?region\\b'),
end: new RegExp('^\\s*//\\s*#?endregion\\b')
}
}
};
exports.language = {
// Set defaultToken to invalid to see what you do not tokenize yet
defaultToken: 'invalid',
tokenPostfix: '.ts',
keywords: [
// Should match the keys of textToKeywordObj in
// https://github.com/microsoft/TypeScript/blob/master/src/compiler/scanner.ts
'abstract',
'any',
'as',
'asserts',
'bigint',
'boolean',
'break',
'case',
'catch',
'class',
'continue',
'const',
'constructor',
'debugger',
'declare',
'default',
'delete',
'do',
'else',
'enum',
'export',
'extends',
'false',
'finally',
'for',
'from',
'function',
'get',
'if',
'implements',
'import',
'in',
'infer',
'instanceof',
'interface',
'is',
'keyof',
'let',
'module',
'namespace',
'never',
'new',
'null',
'number',
'object',
'package',
'private',
'protected',
'public',
'override',
'readonly',
'require',
'global',
'return',
'set',
'static',
'string',
'super',
'switch',
'symbol',
'this',
'throw',
'true',
'try',
'type',
'typeof',
'undefined',
'unique',
'unknown',
'var',
'void',
'while',
'with',
'yield',
'async',
'await',
'of'
],
operators: [
'<=',
'>=',
'==',
'!=',
'===',
'!==',
'=>',
'+',
'-',
'**',
'*',
'/',
'%',
'++',
'--',
'<<',
'</',
'>>',
'>>>',
'&',
'|',
'^',
'!',
'~',
'&&',
'||',
'??',
'?',
':',
'=',
'+=',
'-=',
'*=',
'**=',
'/=',
'%=',
'<<=',
'>>=',
'>>>=',
'&=',
'|=',
'^=',
'@'
],
// we include these common regular expressions
symbols: /[=><!~?:&|+\-*\/\^%]+/,
escapes: /\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,
digits: /\d+(_+\d+)*/,
octaldigits: /[0-7]+(_+[0-7]+)*/,
binarydigits: /[0-1]+(_+[0-1]+)*/,
hexdigits: /[[0-9a-fA-F]+(_+[0-9a-fA-F]+)*/,
regexpctl: /[(){}\[\]\$\^|\-*+?\.]/,
regexpesc: /\\(?:[bBdDfnrstvwWn0\\\/]|@regexpctl|c[A-Z]|x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4})/,
// The main tokenizer for our languages
tokenizer: {
root: [[/[{}]/, 'delimiter.bracket'], { include: 'common' }],
common: [
// identifiers and keywords
[
/[a-z_$][\w$]*/,
{
cases: {
'@keywords': 'keyword',
'@default': 'identifier'
}
}
],
[/[A-Z][\w\$]*/, 'type.identifier'],
// [/[A-Z][\w\$]*/, 'identifier'],
// whitespace
{ include: '@whitespace' },
// regular expression: ensure it is terminated before beginning (otherwise it is an opeator)
[
/\/(?=([^\\\/]|\\.)+\/([dgimsuy]*)(\s*)(\.|;|,|\)|\]|\}|$))/,
{ token: 'regexp', bracket: '@open', next: '@regexp' }
],
// delimiters and operators
[/[()\[\]]/, '@brackets'],
[/[<>](?!@symbols)/, '@brackets'],
[/!(?=([^=]|$))/, 'delimiter'],
[
/@symbols/,
{
cases: {
'@operators': 'delimiter',
'@default': ''
}
}
],
// numbers
[/(@digits)[eE]([\-+]?(@digits))?/, 'number.float'],
[/(@digits)\.(@digits)([eE][\-+]?(@digits))?/, 'number.float'],
[/0[xX](@hexdigits)n?/, 'number.hex'],
[/0[oO]?(@octaldigits)n?/, 'number.octal'],
[/0[bB](@binarydigits)n?/, 'number.binary'],
[/(@digits)n?/, 'number'],
// delimiter: after number because of .\d floats
[/[;,.]/, 'delimiter'],
// strings
[/"([^"\\]|\\.)*$/, 'string.invalid'],
[/'([^'\\]|\\.)*$/, 'string.invalid'],
[/"/, 'string', '@string_double'],
[/'/, 'string', '@string_single'],
[/`/, 'string', '@string_backtick']
],
whitespace: [
[/[ \t\r\n]+/, ''],
[/\/\*\*(?!\/)/, 'comment.doc', '@jsdoc'],
[/\/\*/, 'comment', '@comment'],
[/\/\/.*$/, 'comment']
],
comment: [
[/[^\/*]+/, 'comment'],
[/\*\//, 'comment', '@pop'],
[/[\/*]/, 'comment']
],
jsdoc: [
[/[^\/*]+/, 'comment.doc'],
[/\*\//, 'comment.doc', '@pop'],
[/[\/*]/, 'comment.doc']
],
// We match regular expression quite precisely
regexp: [
[
/(\{)(\d+(?:,\d*)?)(\})/,
['regexp.escape.control', 'regexp.escape.control', 'regexp.escape.control']
],
[
/(\[)(\^?)(?=(?:[^\]\\\/]|\\.)+)/,
['regexp.escape.control', { token: 'regexp.escape.control', next: '@regexrange' }]
],
[/(\()(\?:|\?=|\?!)/, ['regexp.escape.control', 'regexp.escape.control']],
[/[()]/, 'regexp.escape.control'],
[/@regexpctl/, 'regexp.escape.control'],
[/[^\\\/]/, 'regexp'],
[/@regexpesc/, 'regexp.escape'],
[/\\\./, 'regexp.invalid'],
[
/(\/)([dgimsuy]*)/,
[{ token: 'regexp', bracket: '@close', next: '@pop' }, 'keyword.other']
]
],
regexrange: [
[/-/, 'regexp.escape.control'],
[/\^/, 'regexp.invalid'],
[/@regexpesc/, 'regexp.escape'],
[/[^\]]/, 'regexp'],
[
/\]/,
{
token: 'regexp.escape.control',
next: '@pop',
bracket: '@close'
}
]
],
string_double: [
[/[^\\"]+/, 'string'],
[/@escapes/, 'string.escape'],
[/\\./, 'string.escape.invalid'],
[/"/, 'string', '@pop']
],
string_single: [
[/[^\\']+/, 'string'],
[/@escapes/, 'string.escape'],
[/\\./, 'string.escape.invalid'],
[/'/, 'string', '@pop']
],
string_backtick: [
[/\$\{/, { token: 'delimiter.bracket', next: '@bracketCounting' }],
[/[^\\`$]+/, 'string'],
[/@escapes/, 'string.escape'],
[/\\./, 'string.escape.invalid'],
[/`/, 'string', '@pop']
],
bracketCounting: [
[/\{/, 'delimiter.bracket', '@bracketCounting'],
[/\}/, 'delimiter.bracket', '@pop'],
{ include: 'common' }
]
}
};
});
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
define('vs/basic-languages/javascript/javascript',["require", "exports", "../typescript/typescript"], function (require, exports, typescript_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.language = exports.conf = void 0;
exports.conf = typescript_1.conf;
exports.language = {
// Set defaultToken to invalid to see what you do not tokenize yet
defaultToken: 'invalid',
tokenPostfix: '.js',
keywords: [
'break',
'case',
'catch',
'class',
'continue',
'const',
'constructor',
'debugger',
'default',
'delete',
'do',
'else',
'export',
'extends',
'false',
'finally',
'for',
'from',
'function',
'get',
'if',
'import',
'in',
'instanceof',
'let',
'new',
'null',
'return',
'set',
'super',
'switch',
'symbol',
'this',
'throw',
'true',
'try',
'typeof',
'undefined',
'var',
'void',
'while',
'with',
'yield',
'async',
'await',
'of'
],
typeKeywords: [],
operators: typescript_1.language.operators,
symbols: typescript_1.language.symbols,
escapes: typescript_1.language.escapes,
digits: typescript_1.language.digits,
octaldigits: typescript_1.language.octaldigits,
binarydigits: typescript_1.language.binarydigits,
hexdigits: typescript_1.language.hexdigits,
regexpctl: typescript_1.language.regexpctl,
regexpesc: typescript_1.language.regexpesc,
tokenizer: typescript_1.language.tokenizer
};
});

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

1911
dist/ext/monaco-editor/min/vs/loader.js vendored Normal file

File diff suppressed because it is too large Load Diff

28
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

@ -28,16 +28,16 @@ entire "quest-line".
First Steps First Steps
----------- -----------
I'm going to assume you followed the introductory tutorial when you first began the game. I'm going to assume you followed the introductory tutorial when you first began the game.
In this introductory tutorial you created a script called :code:`foodnstuff.script` and ran it In this introductory tutorial you created a script called :code:`n00dles.script` and ran it
on the :code:`foodnstuff` server. Right now, we'll kill this script. There are two ways on the :code:`n00dles` server. Right now, we'll kill this script. There are two ways
to do this: to do this:
1. You can go to the Terminal and enter:: 1. You can go to the Terminal and enter::
$ kill foodnstuff.script $ kill n00dles.script
2. You can go to the :code:`Active Scripts` page (|Keyboard shortcut| Alt + s) and 2. You can go to the :code:`Active Scripts` page (|Keyboard shortcut| Alt + s) and
press the "Kill Script" button for :code:`foodnstuff.script`. press the "Kill Script" button for :code:`n00dles.script`.
If you skipped the introductory tutorial, then ignore the part above. Instead, go to the If you skipped the introductory tutorial, then ignore the part above. Instead, go to the
:code:`Hacknet Nodes` page (|Keyboard shortcut| Alt + h) and purchase a :code:`Hacknet Nodes` page (|Keyboard shortcut| Alt + h) and purchase a
@ -82,8 +82,8 @@ Enter the following code in the script editor:
.. code:: javascript .. code:: javascript
// Defines the "target server", which is the server // Defines the "target server", which is the server
// that we're going to hack. In this case, it's "foodnstuff" // that we're going to hack. In this case, it's "n00dles"
var target = "foodnstuff"; var target = "n00dles";
// Defines how much money a server should have before we hack it // Defines how much money a server should have before we hack it
// In this case, it is set to 75% of the server's max money // In this case, it is set to 75% of the server's max money
@ -122,10 +122,10 @@ step-by-step anyways.
.. code:: javascript .. code:: javascript
var target = "foodnstuff"; var target = "n00dles";
This first command defines a string which contains our target server. That's the server This first command defines a string which contains our target server. That's the server
that we're going to hack. For now, it's set to `foodnstuff` because that's the only that we're going to hack. For now, it's set to `n00dles` because that's the only
server with a required hacking level of 1. If you want to hack a different server, server with a required hacking level of 1. If you want to hack a different server,
simply change this simply change this
variable to be the hostname of another server. variable to be the hostname of another server.
@ -196,7 +196,7 @@ Here's what mine showed at the time I made this::
[home ~]> scan-analyze 2 [home ~]> scan-analyze 2
~~~~~~~~~~ Beginning scan-analyze ~~~~~~~~~~ ~~~~~~~~~~ Beginning scan-analyze ~~~~~~~~~~
>foodnstuff >n00dles
--Root Access: NO, Required hacking skill: 1 --Root Access: NO, Required hacking skill: 1
--Number of open ports required to NUKE: 0 --Number of open ports required to NUKE: 0
--RAM: 16 --RAM: 16
@ -248,7 +248,7 @@ Here's what mine showed at the time I made this::
Take note of the following servers: Take note of the following servers:
* |foodnstuff| * |n00dles|
* |sigma-cosmetics| * |sigma-cosmetics|
* |joesguns| * |joesguns|
* |nectar-net| * |nectar-net|
@ -279,13 +279,13 @@ servers, we have to do the following:
Here's the sequence of |Terminal| commands I used in order to achieve this:: Here's the sequence of |Terminal| commands I used in order to achieve this::
$ home $ home
$ scp early-hack-template.script foodnstuff $ scp early-hack-template.script n00dles
$ scp early-hack-template.script sigma-cosmetics $ scp early-hack-template.script sigma-cosmetics
$ scp early-hack-template.script joesguns $ scp early-hack-template.script joesguns
$ scp early-hack-template.script nectar-net $ scp early-hack-template.script nectar-net
$ scp early-hack-template.script hong-fang-tea $ scp early-hack-template.script hong-fang-tea
$ scp early-hack-template.script harakiri-sushi $ scp early-hack-template.script harakiri-sushi
$ connect foodnstuff $ connect n00dles
$ run NUKE.exe $ run NUKE.exe
$ run early-hack-template.script -t 6 $ run early-hack-template.script -t 6
$ home $ home
@ -334,10 +334,10 @@ we start running more scripts.
Increasing Hacking Level Increasing Hacking Level
------------------------ ------------------------
There are many servers besides |foodnstuff| that can be hacked, but they have There are many servers besides |n00dles| that can be hacked, but they have
higher required hacking levels. Therefore, we should raise our hacking level. Not only higher required hacking levels. Therefore, we should raise our hacking level. Not only
will this let us hack more servers, but it will also increase the effectiveness of our hacking will this let us hack more servers, but it will also increase the effectiveness of our hacking
against |foodnstuff|. against |n00dles|.
The easiest way to train your hacking level is to visit Rothman University. You can do this by The easiest way to train your hacking level is to visit Rothman University. You can do this by
clicking the `City` tab on the left-hand navigation menu, or you can use the clicking the `City` tab on the left-hand navigation menu, or you can use the
@ -361,8 +361,8 @@ Since studying at Rothman University earns you 1 experience per second, this wil
Editing our Hacking Script Editing our Hacking Script
-------------------------- --------------------------
Now that we have a hacking level of 10, we can hack the :code:`joesguns` server. This server Now that we have a hacking level of 10, we can hack the :code:`joesguns` server. This server
will be slightly more profitable than :code:`foodnstuff`. Therefore, we want to change our hacking will be slightly more profitable than :code:`n00dles`. Therefore, we want to change our hacking
script to target :code:`joesguns` instead of :code:`foodnstuff`. script to target :code:`joesguns` instead of :code:`n00dles`.
Go to |Terminal| and edit the hacking script by entering:: Go to |Terminal| and edit the hacking script by entering::
@ -799,7 +799,7 @@ startup script. Feel free to adjust it to your liking.
// Array of all servers that don't need any ports opened // Array of all servers that don't need any ports opened
// to gain root access. These have 16 GB of RAM // to gain root access. These have 16 GB of RAM
var servers0Port = ["foodnstuff", var servers0Port = ["n00dles",
"sigma-cosmetics", "sigma-cosmetics",
"joesguns", "joesguns",
"nectar-net", "nectar-net",
@ -869,7 +869,7 @@ Random Tips
.. |Keyboard shortcut| replace:: :ref:`Keyboard shortcut <shortcuts>` .. |Keyboard shortcut| replace:: :ref:`Keyboard shortcut <shortcuts>`
.. |NUKE| replace:: :code:`NUKE.exe` .. |NUKE| replace:: :code:`NUKE.exe`
.. |Terminal| replace:: :code:`Terminal` .. |Terminal| replace:: :code:`Terminal`
.. |foodnstuff| replace:: :code:`foodnstuff` .. |n00dles| replace:: :code:`n00dles`
.. |harakiri-sushi| replace:: :code:`harakiri-sushi` .. |harakiri-sushi| replace:: :code:`harakiri-sushi`
.. |hong-fang-tea| replace:: :code:`hong-fang-tea` .. |hong-fang-tea| replace:: :code:`hong-fang-tea`
.. |joesguns| replace:: :code:`joesguns` .. |joesguns| replace:: :code:`joesguns`

136614
editor.main.js Normal file

File diff suppressed because one or more lines are too long

@ -30,6 +30,19 @@ function createWindow() {
e.preventDefault(); e.preventDefault();
shell.openExternal(url); shell.openExternal(url);
}); });
win.webContents.backgroundThrottling = false;
// This is backward but the game fills in an array called `document.achievements` and we retrieve it from
// here. Hey if it works it works.
const achievements = greenworks.getAchievementNames();
const intervalID = setInterval(async () => {
const achs = await win.webContents.executeJavaScript("document.achievements");
console.log(achs);
for (const ach of achs) {
if (!achievements.includes(ach)) continue;
greenworks.activateAchievement(ach, () => undefined);
}
}, 1000);
// Create the Application's main menu // Create the Application's main menu
Menu.setApplicationMenu( Menu.setApplicationMenu(
@ -59,8 +72,10 @@ function createWindow() {
{ {
label: "reload & kill all scripts", label: "reload & kill all scripts",
click: () => { click: () => {
if (intervalID) clearInterval(intervalID);
win.webContents.forcefullyCrashRenderer(); win.webContents.forcefullyCrashRenderer();
setTimeout(() => win.loadFile("index.html", { query: { noScripts: "true" } }), 5000); win.close();
createWindow();
}, },
}, },
], ],
@ -92,20 +107,6 @@ function createWindow() {
}, },
]), ]),
); );
// This is backward but the game fills in an array called `document.achievements` and we retrieve it from
// here. Hey if it works it works.
const achievements = greenworks.getAchievementNames();
// for (const ach of achievements) {
// greenworks.clearAchievement(ach, () => undefined);
// }
setInterval(async () => {
const achs = await win.webContents.executeJavaScript("document.achievements");
for (const ach of achs) {
if (!achievements.includes(ach)) continue;
greenworks.activateAchievement(ach, () => undefined);
}
}, 1000);
} }
app.whenReady().then(() => { app.whenReady().then(() => {

@ -13,6 +13,17 @@
<meta name="msapplication-TileColor" content="#000000"/> <meta name="msapplication-TileColor" content="#000000"/>
<meta name="msapplication-config" content="dist/browserconfig.xml"/> <meta name="msapplication-config" content="dist/browserconfig.xml"/>
<meta name="theme-color" content="#ffffff"/> <meta name="theme-color" content="#ffffff"/>
<!-- MONACO JS -->
<link rel="stylesheet" data-name="vs/editor/editor.main" href="dist/ext/monaco-editor/min/vs/editor/editor.main.css"/>
<script>
var require = { paths: { vs: "dist/ext/monaco-editor/min/vs" } };
</script>
<script src="dist/ext/monaco-editor/min/vs/loader.js"></script>
<script src="dist/ext/monaco-editor/min/vs/editor/editor.main.nls.js"></script>
<script src="dist/ext/monaco-editor/min/vs/editor/editor.main.js"></script>
<!-- Google Analytics --> <!-- Google Analytics -->
<script> <script>
(function (i, s, o, g, r, a, m) { (function (i, s, o, g, r, a, m) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -109,6 +109,6 @@
"test:watch": "jest --watch", "test:watch": "jest --watch",
"watch": "webpack --watch --mode production", "watch": "webpack --watch --mode production",
"watch:dev": "webpack --watch --mode development", "watch:dev": "webpack --watch --mode development",
"electron": "cp -r electron/* .package && cp index.html .package && cp main.bundle.js .package && cp dist/vendor.bundle.js .package/dist && electron-packager .package bitburner --all --out .build --overwrite --icon .package/icon.png" "electron": "cp -r electron/* .package && cp index.html .package && cp main.bundle.js .package && cp dist/vendor.bundle.js .package/dist && cp -r dist/ext .package/dist/ext && electron-packager .package bitburner --all --out .build --overwrite --icon .package/icon.png"
} }
} }

@ -11,6 +11,7 @@ import TableBody from "@mui/material/TableBody";
import TableRow from "@mui/material/TableRow"; import TableRow from "@mui/material/TableRow";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Box from "@mui/material/Box"; import Box from "@mui/material/Box";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
function calculateAugmentedStats(): any { function calculateAugmentedStats(): any {
const augP: any = {}; const augP: any = {};
@ -24,7 +25,7 @@ function calculateAugmentedStats(): any {
return augP; return augP;
} }
function Improvements({ r }: { r: number }): React.ReactElement { function Improvements({ r, m }: { r: number; m: number }): React.ReactElement {
if (r) { if (r) {
return ( return (
<> <>
@ -32,7 +33,9 @@ function Improvements({ r }: { r: number }): React.ReactElement {
<Typography>&nbsp;{"=>"}&nbsp;</Typography> <Typography>&nbsp;{"=>"}&nbsp;</Typography>
</TableCell> </TableCell>
<TableCell key="3"> <TableCell key="3">
<Typography>{numeralWrapper.formatPercentage(r)}</Typography> <Typography>
{numeralWrapper.formatPercentage(r)} <BN5Stat base={r} mult={m} />
</Typography>
</TableCell> </TableCell>
</> </>
); );
@ -40,7 +43,17 @@ function Improvements({ r }: { r: number }): React.ReactElement {
return <></>; return <></>;
} }
function MultiplierTable({ rows }: { rows: [string, number, number][] }): React.ReactElement { interface IBN5StatsProps {
base: number;
mult: number;
}
function BN5Stat(props: IBN5StatsProps): React.ReactElement {
if (props.mult === 1) return <></>;
return <>({numeralWrapper.formatPercentage(props.base * props.mult)})</>;
}
function MultiplierTable({ rows }: { rows: [string, number, number, number][] }): React.ReactElement {
return ( return (
<Table size="small" padding="none"> <Table size="small" padding="none">
<TableBody> <TableBody>
@ -50,9 +63,11 @@ function MultiplierTable({ rows }: { rows: [string, number, number][] }): React.
<Typography noWrap>{r[0]} multiplier:&nbsp;</Typography> <Typography noWrap>{r[0]} multiplier:&nbsp;</Typography>
</TableCell> </TableCell>
<TableCell key="1" style={{ textAlign: "right" }}> <TableCell key="1" style={{ textAlign: "right" }}>
<Typography noWrap>{numeralWrapper.formatPercentage(r[1])}</Typography> <Typography noWrap>
{numeralWrapper.formatPercentage(r[1])} <BN5Stat base={r[1]} mult={r[3]} />
</Typography>
</TableCell> </TableCell>
<Improvements r={r[2]} /> <Improvements r={r[2]} m={r[3]} />
</TableRow> </TableRow>
))} ))}
</TableBody> </TableBody>
@ -73,21 +88,25 @@ export function PlayerMultipliers(): React.ReactElement {
"Bladeburner Success Chance", "Bladeburner Success Chance",
Player.bladeburner_success_chance_mult, Player.bladeburner_success_chance_mult,
Player.bladeburner_success_chance_mult * mults.bladeburner_success_chance_mult, Player.bladeburner_success_chance_mult * mults.bladeburner_success_chance_mult,
1,
], ],
[ [
"Bladeburner Max Stamina", "Bladeburner Max Stamina",
Player.bladeburner_max_stamina_mult, Player.bladeburner_max_stamina_mult,
Player.bladeburner_max_stamina_mult * mults.bladeburner_max_stamina_mult, Player.bladeburner_max_stamina_mult * mults.bladeburner_max_stamina_mult,
1,
], ],
[ [
"Bladeburner Stamina Gain", "Bladeburner Stamina Gain",
Player.bladeburner_stamina_gain_mult, Player.bladeburner_stamina_gain_mult,
Player.bladeburner_stamina_gain_mult * mults.bladeburner_stamina_gain_mult, Player.bladeburner_stamina_gain_mult * mults.bladeburner_stamina_gain_mult,
1,
], ],
[ [
"Bladeburner Field Analysis", "Bladeburner Field Analysis",
Player.bladeburner_analysis_mult, Player.bladeburner_analysis_mult,
Player.bladeburner_analysis_mult * mults.bladeburner_analysis_mult, Player.bladeburner_analysis_mult * mults.bladeburner_analysis_mult,
1,
], ],
]} ]}
/> />
@ -102,58 +121,98 @@ export function PlayerMultipliers(): React.ReactElement {
<Box mx={2}> <Box mx={2}>
<MultiplierTable <MultiplierTable
rows={[ rows={[
["Hacking Chance ", Player.hacking_chance_mult, Player.hacking_chance_mult * mults.hacking_chance_mult], ["Hacking Chance ", Player.hacking_chance_mult, Player.hacking_chance_mult * mults.hacking_chance_mult, 1],
["Hacking Speed ", Player.hacking_speed_mult, Player.hacking_speed_mult * mults.hacking_speed_mult], ["Hacking Speed ", Player.hacking_speed_mult, Player.hacking_speed_mult * mults.hacking_speed_mult, 1],
["Hacking Money ", Player.hacking_money_mult, Player.hacking_money_mult * mults.hacking_money_mult], ["Hacking Money ", Player.hacking_money_mult, Player.hacking_money_mult * mults.hacking_money_mult, 1],
["Hacking Growth ", Player.hacking_grow_mult, Player.hacking_grow_mult * mults.hacking_grow_mult], ["Hacking Growth ", Player.hacking_grow_mult, Player.hacking_grow_mult * mults.hacking_grow_mult, 1],
]} ]}
/> />
<br /> <br />
<MultiplierTable <MultiplierTable
rows={[ rows={[
["Hacking Level ", Player.hacking_mult, Player.hacking_mult * mults.hacking_mult], [
["Hacking Experience ", Player.hacking_exp_mult, Player.hacking_exp_mult * mults.hacking_exp_mult], "Hacking Level ",
Player.hacking_mult,
Player.hacking_mult * mults.hacking_mult,
BitNodeMultipliers.HackingLevelMultiplier,
],
[
"Hacking Experience ",
Player.hacking_exp_mult,
Player.hacking_exp_mult * mults.hacking_exp_mult,
BitNodeMultipliers.HackExpGain,
],
]} ]}
/> />
<br /> <br />
<MultiplierTable <MultiplierTable
rows={[ rows={[
["Strength Level ", Player.strength_mult, Player.strength_mult * mults.strength_mult], [
["Strength Experience ", Player.strength_exp_mult, Player.strength_exp_mult * mults.strength_exp_mult], "Strength Level ",
Player.strength_mult,
Player.strength_mult * mults.strength_mult,
BitNodeMultipliers.StrengthLevelMultiplier,
],
["Strength Experience ", Player.strength_exp_mult, Player.strength_exp_mult * mults.strength_exp_mult, 1],
]} ]}
/> />
<br /> <br />
<MultiplierTable <MultiplierTable
rows={[ rows={[
["Defense Level ", Player.defense_mult, Player.defense_mult * mults.defense_mult], [
["Defense Experience ", Player.defense_exp_mult, Player.defense_exp_mult * mults.defense_exp_mult], "Defense Level ",
Player.defense_mult,
Player.defense_mult * mults.defense_mult,
BitNodeMultipliers.DefenseLevelMultiplier,
],
["Defense Experience ", Player.defense_exp_mult, Player.defense_exp_mult * mults.defense_exp_mult, 1],
]} ]}
/> />
<br /> <br />
<MultiplierTable <MultiplierTable
rows={[ rows={[
["Dexterity Level ", Player.dexterity_mult, Player.dexterity_mult * mults.dexterity_mult], [
["Dexterity Experience ", Player.dexterity_exp_mult, Player.dexterity_exp_mult * mults.dexterity_exp_mult], "Dexterity Level ",
Player.dexterity_mult,
Player.dexterity_mult * mults.dexterity_mult,
BitNodeMultipliers.DexterityLevelMultiplier,
],
[
"Dexterity Experience ",
Player.dexterity_exp_mult,
Player.dexterity_exp_mult * mults.dexterity_exp_mult,
1,
],
]} ]}
/> />
<br /> <br />
<MultiplierTable <MultiplierTable
rows={[ rows={[
["Agility Level ", Player.agility_mult, Player.agility_mult * mults.agility_mult], [
["Agility Experience ", Player.agility_exp_mult, Player.agility_exp_mult * mults.agility_exp_mult], "Agility Level ",
Player.agility_mult,
Player.agility_mult * mults.agility_mult,
BitNodeMultipliers.AgilityLevelMultiplier,
],
["Agility Experience ", Player.agility_exp_mult, Player.agility_exp_mult * mults.agility_exp_mult, 1],
]} ]}
/> />
<br /> <br />
<MultiplierTable <MultiplierTable
rows={[ rows={[
["Charisma Level ", Player.charisma_mult, Player.charisma_mult * mults.charisma_mult], [
["Charisma Experience ", Player.charisma_exp_mult, Player.charisma_exp_mult * mults.charisma_exp_mult], "Charisma Level ",
Player.charisma_mult,
Player.charisma_mult * mults.charisma_mult,
BitNodeMultipliers.CharismaLevelMultiplier,
],
["Charisma Experience ", Player.charisma_exp_mult, Player.charisma_exp_mult * mults.charisma_exp_mult, 1],
]} ]}
/> />
<br /> <br />
@ -164,26 +223,31 @@ export function PlayerMultipliers(): React.ReactElement {
"Hacknet Node production ", "Hacknet Node production ",
Player.hacknet_node_money_mult, Player.hacknet_node_money_mult,
Player.hacknet_node_money_mult * mults.hacknet_node_money_mult, Player.hacknet_node_money_mult * mults.hacknet_node_money_mult,
BitNodeMultipliers.HacknetNodeMoney,
], ],
[ [
"Hacknet Node purchase cost ", "Hacknet Node purchase cost ",
Player.hacknet_node_purchase_cost_mult, Player.hacknet_node_purchase_cost_mult,
Player.hacknet_node_purchase_cost_mult * mults.hacknet_node_purchase_cost_mult, Player.hacknet_node_purchase_cost_mult * mults.hacknet_node_purchase_cost_mult,
1,
], ],
[ [
"Hacknet Node RAM upgrade cost ", "Hacknet Node RAM upgrade cost ",
Player.hacknet_node_ram_cost_mult, Player.hacknet_node_ram_cost_mult,
Player.hacknet_node_ram_cost_mult * mults.hacknet_node_ram_cost_mult, Player.hacknet_node_ram_cost_mult * mults.hacknet_node_ram_cost_mult,
1,
], ],
[ [
"Hacknet Node Core purchase cost ", "Hacknet Node Core purchase cost ",
Player.hacknet_node_core_cost_mult, Player.hacknet_node_core_cost_mult,
Player.hacknet_node_core_cost_mult * mults.hacknet_node_core_cost_mult, Player.hacknet_node_core_cost_mult * mults.hacknet_node_core_cost_mult,
1,
], ],
[ [
"Hacknet Node level upgrade cost ", "Hacknet Node level upgrade cost ",
Player.hacknet_node_level_cost_mult, Player.hacknet_node_level_cost_mult,
Player.hacknet_node_level_cost_mult * mults.hacknet_node_level_cost_mult, Player.hacknet_node_level_cost_mult * mults.hacknet_node_level_cost_mult,
1,
], ],
]} ]}
/> />
@ -191,17 +255,32 @@ export function PlayerMultipliers(): React.ReactElement {
<MultiplierTable <MultiplierTable
rows={[ rows={[
["Company reputation gain ", Player.company_rep_mult, Player.company_rep_mult * mults.company_rep_mult], ["Company reputation gain ", Player.company_rep_mult, Player.company_rep_mult * mults.company_rep_mult, 1],
["Faction reputation gain ", Player.faction_rep_mult, Player.faction_rep_mult * mults.faction_rep_mult], [
["Salary ", Player.work_money_mult, Player.work_money_mult * mults.work_money_mult], "Faction reputation gain ",
Player.faction_rep_mult,
Player.faction_rep_mult * mults.faction_rep_mult,
BitNodeMultipliers.FactionWorkRepGain,
],
[
"Salary ",
Player.work_money_mult,
Player.work_money_mult * mults.work_money_mult,
BitNodeMultipliers.CompanyWorkMoney,
],
]} ]}
/> />
<br /> <br />
<MultiplierTable <MultiplierTable
rows={[ rows={[
["Crime success ", Player.crime_success_mult, Player.crime_success_mult * mults.crime_success_mult], ["Crime success ", Player.crime_success_mult, Player.crime_success_mult * mults.crime_success_mult, 1],
["Crime money ", Player.crime_money_mult, Player.crime_money_mult * mults.crime_money_mult], [
"Crime money ",
Player.crime_money_mult,
Player.crime_money_mult * mults.crime_money_mult,
BitNodeMultipliers.CrimeMoney,
],
]} ]}
/> />
<br /> <br />

@ -341,6 +341,13 @@ const achievements: Achievement[] = [
), ),
}, },
{ ID: "CHALLENGE_BN12", Condition: () => Player.sourceFileLvl(12) >= 50 }, { ID: "CHALLENGE_BN12", Condition: () => Player.sourceFileLvl(12) >= 50 },
{
ID: "CHALLENGE_BN13",
Condition: () =>
Player.bitNodeN === 13 &&
bitNodeFinishedState() &&
!Player.augmentations.some((a) => a.name === AugmentationNames.StaneksGift1),
},
{ ID: "BYPASS", Condition: () => Player.exploits.includes(Exploit.Bypass) }, { ID: "BYPASS", Condition: () => Player.exploits.includes(Exploit.Bypass) },
{ ID: "PROTOTYPETAMPERING", Condition: () => Player.exploits.includes(Exploit.PrototypeTampering) }, { ID: "PROTOTYPETAMPERING", Condition: () => Player.exploits.includes(Exploit.PrototypeTampering) },
{ ID: "UNCLICKABLE", Condition: () => Player.exploits.includes(Exploit.Unclickable) }, { ID: "UNCLICKABLE", Condition: () => Player.exploits.includes(Exploit.Unclickable) },

@ -24,10 +24,15 @@ interface IProps {
rerender: () => void; rerender: () => void;
} }
const serversMap: { [key: string]: string } = {};
export function HacknetUpgradeElem(props: IProps): React.ReactElement { export function HacknetUpgradeElem(props: IProps): React.ReactElement {
const [selectedServer, setSelectedServer] = useState("ecorp"); const [selectedServer, setSelectedServer] = useState(
serversMap[props.upg.name] ? serversMap[props.upg.name] : "ecorp",
);
function changeTargetServer(event: SelectChangeEvent<string>): void { function changeTargetServer(event: SelectChangeEvent<string>): void {
setSelectedServer(event.target.value); setSelectedServer(event.target.value);
serversMap[props.upg.name] = event.target.value;
} }
function purchase(): void { function purchase(): void {

@ -114,6 +114,7 @@ const ITutorial: {
function iTutorialStart(): void { function iTutorialStart(): void {
ITutorial.isRunning = true; ITutorial.isRunning = true;
ITutorial.currStep = iTutorialSteps.Start;
} }
// Go to the next step and evaluate it // Go to the next step and evaluate it

@ -28,6 +28,7 @@ import { GetServer } from "../../Server/AllServers";
import { CorruptableText } from "../../ui/React/CorruptableText"; import { CorruptableText } from "../../ui/React/CorruptableText";
import { use } from "../../ui/Context"; import { use } from "../../ui/Context";
import { serverMetadata } from "../../Server/data/servers";
type IProps = { type IProps = {
loc: Location; loc: Location;
@ -83,7 +84,9 @@ export function GenericLocation({ loc }: IProps): React.ReactElement {
} }
const locContent: React.ReactNode[] = getLocationSpecificContent(); const locContent: React.ReactNode[] = getLocationSpecificContent();
const server = GetServer(loc.name); const serverMeta = serverMetadata.find((s) => s.specialName === loc.name);
const server = GetServer(serverMeta ? serverMeta.hostname : "");
const backdoorInstalled = server !== null && isBackdoorInstalled(server); const backdoorInstalled = server !== null && isBackdoorInstalled(server);
return ( return (

@ -15,6 +15,7 @@ import { Server } from "../../Server/Server";
import { Money } from "../../ui/React/Money"; import { Money } from "../../ui/React/Money";
import { IRouter } from "../../ui/Router"; import { IRouter } from "../../ui/Router";
import { serverMetadata } from "../../Server/data/servers";
type IProps = { type IProps = {
loc: Location; loc: Location;
@ -24,7 +25,8 @@ type IProps = {
export function GymLocation(props: IProps): React.ReactElement { export function GymLocation(props: IProps): React.ReactElement {
function calculateCost(): number { function calculateCost(): number {
const server = GetServer(props.loc.name); const serverMeta = serverMetadata.find((s) => s.specialName === props.loc.name);
const server = GetServer(serverMeta ? serverMeta.hostname : "");
if (server == null || !server.hasOwnProperty("backdoorInstalled")) return props.loc.costMult; if (server == null || !server.hasOwnProperty("backdoorInstalled")) return props.loc.costMult;
const discount = (server as Server).backdoorInstalled ? 0.9 : 1; const discount = (server as Server).backdoorInstalled ? 0.9 : 1;
return props.loc.costMult * discount; return props.loc.costMult * discount;

@ -29,6 +29,9 @@ import { N00dles } from "../../utils/helpers/N00dles";
import { Exploit } from "../../Exploits/Exploit"; import { Exploit } from "../../Exploits/Exploit";
import { applyAugmentation } from "../../Augmentation/AugmentationHelpers"; import { applyAugmentation } from "../../Augmentation/AugmentationHelpers";
import { CorruptableText } from "../../ui/React/CorruptableText"; import { CorruptableText } from "../../ui/React/CorruptableText";
import { HacknetNode } from "../../Hacknet/HacknetNode";
import { HacknetServer } from "../../Hacknet/HacknetServer";
import { GetServer } from "../../Server/AllServers";
type IProps = { type IProps = {
loc: Location; loc: Location;
@ -84,11 +87,34 @@ export function SpecialLocation(props: IProps): React.ReactElement {
function renderNoodleBar(): React.ReactElement { function renderNoodleBar(): React.ReactElement {
function EatNoodles(): void { function EatNoodles(): void {
SnackbarEvents.emit("You ate some delicious noodles and feel refreshed", "success"); SnackbarEvents.emit("You ate some delicious noodles and feel refreshed", "success");
N00dles(); N00dles(); // This is the true power of the noodles.
if (player.sourceFiles.length > 0) player.giveExploit(Exploit.N00dles); if (player.sourceFiles.length > 0) player.giveExploit(Exploit.N00dles);
if (player.sourceFileLvl(5) > 0 || player.bitNodeN === 5) { if (player.sourceFileLvl(5) > 0 || player.bitNodeN === 5) {
player.intelligence_exp *= 1.0000000000000002; player.intelligence_exp *= 1.0000000000000002;
} }
player.hacking_exp *= 1.0000000000000002;
player.strength_exp *= 1.0000000000000002;
player.defense_exp *= 1.0000000000000002;
player.agility_exp *= 1.0000000000000002;
player.dexterity_exp *= 1.0000000000000002;
player.charisma_exp *= 1.0000000000000002;
for (const node of player.hacknetNodes) {
if (node instanceof HacknetNode) {
player.gainMoney(node.moneyGainRatePerSecond * 0.001, "other");
} else {
const server = GetServer(node);
if (!(server instanceof HacknetServer)) throw new Error(`Server ${node} is not a hacknet server.`);
player.hashManager.storeHashes(server.hashRate * 0.001);
}
}
if (player.bladeburner) {
player.bladeburner.rank += 0.00001;
}
if (player.corporation) {
player.corporation.funds += player.corporation.revenue * 0.01;
}
} }
return ( return (

@ -14,6 +14,9 @@ export function netscriptDelay(time: number, workerScript: WorkerScript): Promis
} }
export function makeRuntimeRejectMsg(workerScript: WorkerScript, msg: string): string { export function makeRuntimeRejectMsg(workerScript: WorkerScript, msg: string): string {
if ((msg as any) instanceof WorkerScript) {
console.error("HERE");
}
const server = GetServer(workerScript.hostname); const server = GetServer(workerScript.hostname);
if (server == null) { if (server == null) {
throw new Error(`WorkerScript constructed with invalid server ip: ${workerScript.hostname}`); throw new Error(`WorkerScript constructed with invalid server ip: ${workerScript.hostname}`);

@ -139,7 +139,10 @@ function startNetscript2Script(workerScript: WorkerScript): Promise<WorkerScript
} else if (isScriptErrorMessage(e)) { } else if (isScriptErrorMessage(e)) {
workerScript.errorMessage = e; workerScript.errorMessage = e;
throw workerScript; throw workerScript;
} else if (e instanceof WorkerScript) {
throw e;
} }
workerScript.errorMessage = makeRuntimeRejectMsg(workerScript, e); workerScript.errorMessage = makeRuntimeRejectMsg(workerScript, e);
throw workerScript; // Don't know what to do with it, let's rethrow. throw workerScript; // Don't know what to do with it, let's rethrow.
}); });
@ -528,6 +531,8 @@ function createAndAddWorkerScript(runningScriptObj: RunningScript, server: BaseS
// Once the code finishes (either resolved or rejected, doesnt matter), set its // Once the code finishes (either resolved or rejected, doesnt matter), set its
// running status to false // running status to false
p.then(function (w: WorkerScript) { p.then(function (w: WorkerScript) {
w.running = false;
w.env.stopFlag = true;
// On natural death, the earnings are transfered to the parent if it still exists. // On natural death, the earnings are transfered to the parent if it still exists.
if (parent !== undefined) { if (parent !== undefined) {
if (parent.running) { if (parent.running) {
@ -568,8 +573,6 @@ function createAndAddWorkerScript(runningScriptObj: RunningScript, server: BaseS
w.log("", () => "Script killed"); w.log("", () => "Script killed");
return; // Already killed, so stop here return; // Already killed, so stop here
} }
w.running = false;
w.env.stopFlag = true;
} else if (isScriptErrorMessage(w)) { } else if (isScriptErrorMessage(w)) {
dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer"); dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer");
console.error( console.error(

@ -1853,7 +1853,7 @@ export function applyForEmployeeJob(this: IPlayer, sing = false): boolean {
this.companyName = company.name; this.companyName = company.name;
this.jobs[company.name] = posNames.MiscCompanyPositions[1]; this.jobs[company.name] = posNames.MiscCompanyPositions[1];
if (!sing) { if (!sing) {
dialogBoxCreate("Congratulations, you are now employed at " + this.companyName); dialogBoxCreate("Congratulations, you are now employed at " + this.location);
} }
return true; return true;
@ -1871,7 +1871,7 @@ export function applyForPartTimeEmployeeJob(this: IPlayer, sing = false): boolea
if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[1]])) { if (this.isQualified(company, CompanyPositions[posNames.PartTimeCompanyPositions[1]])) {
this.jobs[company.name] = posNames.PartTimeCompanyPositions[1]; this.jobs[company.name] = posNames.PartTimeCompanyPositions[1];
if (!sing) { if (!sing) {
dialogBoxCreate("Congratulations, you are now employed part-time at " + this.companyName); dialogBoxCreate("Congratulations, you are now employed part-time at " + this.location);
} }
return true; return true;
@ -1890,7 +1890,7 @@ export function applyForWaiterJob(this: IPlayer, sing = false): boolean {
this.companyName = company.name; this.companyName = company.name;
this.jobs[company.name] = posNames.MiscCompanyPositions[0]; this.jobs[company.name] = posNames.MiscCompanyPositions[0];
if (!sing) { if (!sing) {
dialogBoxCreate("Congratulations, you are now employed as a waiter at " + this.companyName); dialogBoxCreate("Congratulations, you are now employed as a waiter at " + this.location);
} }
return true; return true;
} else { } else {
@ -1907,7 +1907,7 @@ export function applyForPartTimeWaiterJob(this: IPlayer, sing = false): boolean
this.companyName = company.name; this.companyName = company.name;
this.jobs[company.name] = posNames.PartTimeCompanyPositions[0]; this.jobs[company.name] = posNames.PartTimeCompanyPositions[0];
if (!sing) { if (!sing) {
dialogBoxCreate("Congratulations, you are now employed as a part-time waiter at " + this.companyName); dialogBoxCreate("Congratulations, you are now employed as a part-time waiter at " + this.location);
} }
return true; return true;
} else { } else {

@ -3904,9 +3904,9 @@ export interface NS extends Singularity {
* *
* @example * @example
* ```ts * ```ts
* //For example, assume the following returns 1: * //For example, assume the following returns 0.01:
* hackAnalyze("foodnstuff"); * hackAnalyze("foodnstuff");
* //This means that if hack the foodnstuff server, then you will steal 1% of its total money. If you hack using N threads, then you will steal N% of its total money. * //This means that if hack the foodnstuff server, then you will steal 1% of its total money. If you hack using N threads, then you will steal N*0.01% of its total money.
* ``` * ```
* @param host - Hostname of the target server. * @param host - Hostname of the target server.
* @returns The percentage of money you will steal from the target server with a single hack. * @returns The percentage of money you will steal from the target server with a single hack.

@ -23,6 +23,7 @@ import { iTutorialNextStep, ITutorial, iTutorialSteps } from "../../InteractiveT
import { debounce } from "lodash"; import { debounce } from "lodash";
import { saveObject } from "../../SaveObject"; import { saveObject } from "../../SaveObject";
import { loadThemes } from "./themes"; import { loadThemes } from "./themes";
import { GetServer } from "../../Server/AllServers";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
@ -146,7 +147,7 @@ export function Root(props: IProps): React.ReactElement {
} }
//Save the script //Save the script
const server = props.player.getCurrentServer(); const server = GetServer(hostname);
if (server === null) throw new Error("Server should not be null but it is."); if (server === null) throw new Error("Server should not be null but it is.");
let found = false; let found = false;
for (let i = 0; i < server.scripts.length; i++) { for (let i = 0; i < server.scripts.length; i++) {
@ -180,7 +181,7 @@ export function Root(props: IProps): React.ReactElement {
return; return;
} }
const server = props.player.getCurrentServer(); const server = GetServer(hostname);
if (server === null) throw new Error("Server should not be null but it is."); if (server === null) throw new Error("Server should not be null but it is.");
if (isScriptFilename(filename)) { if (isScriptFilename(filename)) {
//If the current script already exists on the server, overwrite it //If the current script already exists on the server, overwrite it

@ -507,16 +507,15 @@ export class Terminal implements ITerminal {
if (s.hasAdminRights) { if (s.hasAdminRights) {
c = "YES"; c = "YES";
} }
let out = `${dashes}Root Access: ${c}${ this.print(
!isHacknet ? ", Required hacking skill: " + (s as any).requiredHackingSkill : "" `${dashes}Root Access: ${c}${!isHacknet ? ", Required hacking skill: " + (s as any).requiredHackingSkill : ""}`,
}`; );
if (s.hasOwnProperty("numOpenPortsRequired")) { if (s.hasOwnProperty("numOpenPortsRequired")) {
out += "\n" + dashes + "Number of open ports required to NUKE: " + (s as any).numOpenPortsRequired; this.print(dashes + "Number of open ports required to NUKE: " + (s as any).numOpenPortsRequired);
} }
out += "\n" + dashes + "RAM: " + numeralWrapper.formatRAM(s.maxRam); this.print(dashes + "RAM: " + numeralWrapper.formatRAM(s.maxRam));
out += "\n" + " "; this.print(" ");
this.print(out);
} }
} }

@ -52,6 +52,7 @@ export function runScript(
} }
// Check for admin rights and that there is enough RAM availble to run // Check for admin rights and that there is enough RAM availble to run
const script = server.scripts[i]; const script = server.scripts[i];
script.server = player.getCurrentServer().hostname;
const ramUsage = script.ramUsage * numThreads; const ramUsage = script.ramUsage * numThreads;
const ramAvailable = server.maxRam - server.ramUsed; const ramAvailable = server.maxRam - server.ramUsed;

@ -3,11 +3,18 @@ import React from "react";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Link from "@mui/material/Link"; import Link from "@mui/material/Link";
import Box from "@mui/material/Box"; import Box from "@mui/material/Box";
export function TutorialRoot(): React.ReactElement { import Button from "@mui/material/Button";
interface IProps {
reactivateTutorial: () => void;
}
export function TutorialRoot(props: IProps): React.ReactElement {
return ( return (
<> <>
<Typography variant="h4">Tutorial / Documentation</Typography> <Typography variant="h4">Tutorial / Documentation</Typography>
<Box m={2}> <Box m={2}>
<Button onClick={props.reactivateTutorial}>Soft reset and Restart tutorial</Button>
<Link <Link
color="primary" color="primary"
target="_blank" target="_blank"

@ -13,6 +13,21 @@
<meta name="msapplication-TileColor" content="#000000" /> <meta name="msapplication-TileColor" content="#000000" />
<meta name="msapplication-config" content="dist/browserconfig.xml" /> <meta name="msapplication-config" content="dist/browserconfig.xml" />
<meta name="theme-color" content="#ffffff" /> <meta name="theme-color" content="#ffffff" />
<!-- MONACO JS -->
<link
rel="stylesheet"
data-name="vs/editor/editor.main"
href="dist/ext/monaco-editor/min/vs/editor/editor.main.css"
/>
<script>
var require = { paths: { vs: "dist/ext/monaco-editor/min/vs" } };
</script>
<script src="dist/ext/monaco-editor/min/vs/loader.js"></script>
<script src="dist/ext/monaco-editor/min/vs/editor/editor.main.nls.js"></script>
<script src="dist/ext/monaco-editor/min/vs/editor/editor.main.js"></script>
<!-- Google Analytics --> <!-- Google Analytics -->
<script> <script>
(function (i, s, o, g, r, a, m) { (function (i, s, o, g, r, a, m) {

@ -9,7 +9,7 @@ import { onExport } from "../ExportBonus";
import { LocationName } from "../Locations/data/LocationNames"; import { LocationName } from "../Locations/data/LocationNames";
import { Location } from "../Locations/Location"; import { Location } from "../Locations/Location";
import { Locations } from "../Locations/Locations"; import { Locations } from "../Locations/Locations";
import { ITutorial } from "../InteractiveTutorial"; import { ITutorial, iTutorialStart } from "../InteractiveTutorial";
import { InteractiveTutorialRoot } from "./InteractiveTutorial/InteractiveTutorialRoot"; import { InteractiveTutorialRoot } from "./InteractiveTutorial/InteractiveTutorialRoot";
import { ITutorialEvents } from "./InteractiveTutorial/ITutorialEvents"; import { ITutorialEvents } from "./InteractiveTutorial/ITutorialEvents";
@ -349,7 +349,13 @@ export function GameRoot({ player, engine, terminal }: IProps): React.ReactEleme
) : page === Page.Milestones ? ( ) : page === Page.Milestones ? (
<MilestonesRoot player={player} /> <MilestonesRoot player={player} />
) : page === Page.Tutorial ? ( ) : page === Page.Tutorial ? (
<TutorialRoot /> <TutorialRoot
reactivateTutorial={() => {
prestigeAugmentation();
Router.toTerminal();
iTutorialStart();
}}
/>
) : page === Page.DevMenu ? ( ) : page === Page.DevMenu ? (
<DevMenuRoot player={player} engine={engine} router={Router} /> <DevMenuRoot player={player} engine={engine} router={Router} />
) : page === Page.Gang ? ( ) : page === Page.Gang ? (