From fe9ab58d966bc59d69863ce6471121308cbd5e66 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Wed, 26 Aug 2026 04:30:55 +0100 Subject: [PATCH 01/82] revamped tutorial and blast radius --- src/InteractiveTutorial.ts | 32 +- src/Programs/Programs.ts | 46 +- src/ScriptEditor/ui/ScriptEditorRoot.tsx | 3 +- src/Sidebar/ui/SidebarRoot.tsx | 7 +- src/Terminal/Terminal.ts | 32 +- src/Terminal/commands/grow.ts | 11 +- src/Terminal/commands/weaken.ts | 5 +- src/ui/CharacterStats.tsx | 11 + .../InteractiveTutorialRoot.tsx | 565 ++++++++++-------- 9 files changed, 430 insertions(+), 282 deletions(-) diff --git a/src/InteractiveTutorial.ts b/src/InteractiveTutorial.ts index b57b6045fd..8a6ae1e67e 100644 --- a/src/InteractiveTutorial.ts +++ b/src/InteractiveTutorial.ts @@ -1,3 +1,15 @@ +//// Tidy up: +// n00dles.js +// + +//////// +// Red to blue for stuff +/// Somewhere ??? the text that says 'can't kill during tutorial' ... when you clearly can +// Add the stuff about docs and the editor back in later on +// Don't auto-move from the Script editor to the Termainal. Make the player do that. +// add scp step +// add "all this stuff can be automated" scp > ns.scp; run > ns.run/ns.exec; weaken > ns.weaken + import { Player } from "@player"; import { LiteratureName } from "@enums"; import { ITutorialEvents } from "./ui/InteractiveTutorial/ITutorialEvents"; @@ -5,15 +17,13 @@ import { ITutorialEvents } from "./ui/InteractiveTutorial/ITutorialEvents"; // Ordered array of keys to Interactive Tutorial Steps enum iTutorialSteps { Start, - GoToCharacterPage, // Click on 'Stats' page - CharacterPage, // Introduction to 'Stats' page - CharacterGoToTerminalPage, // Go back to Terminal + + // Hacking TerminalIntro, // Introduction to Terminal - TerminalHelp, // Using 'help' Terminal command - TerminalLs, // Using 'ls' Terminal command TerminalScan, // Using 'scan' Terminal command TerminalScanAnalyze1, // Using 'scan-analyze' Terminal command TerminalScanAnalyze2, // Using 'scan-analyze 3' Terminal command + TerminalConnectInterval, TerminalConnect, // Connecting to n00dles TerminalAnalyze, // Analyzing n00dles TerminalNuke, // NUKE n00dles @@ -28,6 +38,15 @@ enum iTutorialSteps { ActiveScriptsPage, ActiveScriptsToTerminal, TerminalTailScript, + TerminalLs, // Using 'ls' Terminal command + TerminalScp, + TerminalHelp, // Using 'help' Terminal command + + // See the results of our hacking + GoToCharacterPage, // Click on 'Stats' page + CharacterPage, // Introduction to 'Stats' page + + // Finishing off GoToHacknetNodesPage, HacknetNodesIntroduction, HacknetNodesGoToWorldPage, @@ -45,7 +64,6 @@ const ITutorial = { [iTutorialSteps.Start]: false, [iTutorialSteps.GoToCharacterPage]: false, [iTutorialSteps.CharacterPage]: false, - [iTutorialSteps.CharacterGoToTerminalPage]: false, [iTutorialSteps.TerminalIntro]: false, [iTutorialSteps.TerminalHelp]: false, [iTutorialSteps.TerminalLs]: false, @@ -53,6 +71,7 @@ const ITutorial = { [iTutorialSteps.TerminalScanAnalyze1]: false, [iTutorialSteps.TerminalScanAnalyze2]: false, [iTutorialSteps.TerminalConnect]: false, + [iTutorialSteps.TerminalConnectInterval]: false, [iTutorialSteps.TerminalAnalyze]: false, [iTutorialSteps.TerminalNuke]: false, [iTutorialSteps.TerminalManualHack]: false, @@ -66,6 +85,7 @@ const ITutorial = { [iTutorialSteps.ActiveScriptsPage]: false, [iTutorialSteps.ActiveScriptsToTerminal]: false, [iTutorialSteps.TerminalTailScript]: false, + [iTutorialSteps.TerminalScp]: false, [iTutorialSteps.GoToHacknetNodesPage]: false, [iTutorialSteps.HacknetNodesIntroduction]: false, [iTutorialSteps.HacknetNodesGoToWorldPage]: false, diff --git a/src/Programs/Programs.ts b/src/Programs/Programs.ts index 495428a354..9dd4fb46d7 100644 --- a/src/Programs/Programs.ts +++ b/src/Programs/Programs.ts @@ -50,7 +50,7 @@ export const Programs: Record = { nsMethod: "nuke", create: { level: 1, - tooltip: "This virus is used to gain root access to a machine if enough ports are opened.", + tooltip: "This virus is used to gain root access to a machine if enough ports are opened", req: requireHackingLevel(1), time: CONSTANTS.MillisecondsPerFiveMinutes, }, @@ -62,13 +62,13 @@ export const Programs: Record = { } if (server.hasAdminRights) { Terminal.print("You already have root access to this computer. There is no reason to run NUKE.exe"); - Terminal.print("You can now run scripts on this server."); + Terminal.print("You can run scripts on this server"); return; } if (server.openPortCount >= server.numOpenPortsRequired) { server.hasAdminRights = true; Terminal.print("NUKE successful! Gained root access to " + server.hostname); - Terminal.print("You can now run scripts on this server."); + Terminal.print("You can now run scripts on this server"); return; } @@ -87,7 +87,7 @@ export const Programs: Record = { run: (args: string[], server: BaseServer): void => { warnIfNonArgProgramIsRunWithArgs(CompletedProgramName.bruteSsh, args); if (!(server instanceof Server)) { - Terminal.error("Cannot run BruteSSH.exe on this kind of server."); + Terminal.error("Cannot run BruteSSH.exe on this kind of server"); return; } if (server.sshPortOpen) { @@ -95,7 +95,7 @@ export const Programs: Record = { return; } if (server.purchasedByPlayer) { - Terminal.print("Opening ports on your own machines has no negative consequences in the game."); + Terminal.print("Opening ports on your own machines has no negative consequences in the game"); } server.sshPortOpen = true; @@ -115,7 +115,7 @@ export const Programs: Record = { run: (args: string[], server: BaseServer): void => { warnIfNonArgProgramIsRunWithArgs(CompletedProgramName.ftpCrack, args); if (!(server instanceof Server)) { - Terminal.error("Cannot run FTPCrack.exe on this kind of server."); + Terminal.error("Cannot run FTPCrack.exe on this kind of server"); return; } if (server.ftpPortOpen) { @@ -123,7 +123,7 @@ export const Programs: Record = { return; } if (server.purchasedByPlayer) { - Terminal.print("Opening ports on your own machines has no negative consequences in the game."); + Terminal.print("Opening ports on your own machines has no negative consequences in the game"); } server.ftpPortOpen = true; @@ -143,7 +143,7 @@ export const Programs: Record = { run: (args: string[], server: BaseServer): void => { warnIfNonArgProgramIsRunWithArgs(CompletedProgramName.relaySmtp, args); if (!(server instanceof Server)) { - Terminal.error("Cannot run relaySMTP.exe on this kind of server."); + Terminal.error("Cannot run relaySMTP.exe on this kind of server"); return; } if (server.smtpPortOpen) { @@ -151,7 +151,7 @@ export const Programs: Record = { return; } if (server.purchasedByPlayer) { - Terminal.print("Opening ports on your own machines has no negative consequences in the game."); + Terminal.print("Opening ports on your own machines has no negative consequences in the game"); } server.smtpPortOpen = true; @@ -171,7 +171,7 @@ export const Programs: Record = { run: (args: string[], server: BaseServer): void => { warnIfNonArgProgramIsRunWithArgs(CompletedProgramName.httpWorm, args); if (!(server instanceof Server)) { - Terminal.error("Cannot run HTTPWorm.exe on this kind of server."); + Terminal.error("Cannot run HTTPWorm.exe on this kind of server"); return; } if (server.httpPortOpen) { @@ -179,7 +179,7 @@ export const Programs: Record = { return; } if (server.purchasedByPlayer) { - Terminal.print("Opening ports on your own machines has no negative consequences in the game."); + Terminal.print("Opening ports on your own machines has no negative consequences in the game"); } server.httpPortOpen = true; @@ -199,7 +199,7 @@ export const Programs: Record = { run: (args: string[], server: BaseServer): void => { warnIfNonArgProgramIsRunWithArgs(CompletedProgramName.sqlInject, args); if (!(server instanceof Server)) { - Terminal.error("Cannot run SQLInject.exe on this kind of server."); + Terminal.error("Cannot run SQLInject.exe on this kind of server"); return; } if (server.sqlPortOpen) { @@ -207,7 +207,7 @@ export const Programs: Record = { return; } if (server.purchasedByPlayer) { - Terminal.print("Opening ports on your own machines has no negative consequences in the game."); + Terminal.print("Opening ports on your own machines has no negative consequences in the game"); } server.sqlPortOpen = true; @@ -224,8 +224,8 @@ export const Programs: Record = { time: CONSTANTS.MillisecondsPerQuarterHour, }, run: (): void => { - Terminal.print("This executable cannot be run."); - Terminal.print("DeepscanV1.exe lets you run 'scan-analyze' with a depth up to 5."); + Terminal.print("This executable cannot be run"); + Terminal.print("DeepscanV1.exe lets you run 'scan-analyze' with a depth up to 5"); }, }), [CompletedProgramName.deepScan2]: new Program({ @@ -237,8 +237,8 @@ export const Programs: Record = { time: CONSTANTS.MillisecondsPer2Hours, }, run: (): void => { - Terminal.print("This executable cannot be run."); - Terminal.print("DeepscanV2.exe lets you run 'scan-analyze' with a depth up to 10."); + Terminal.print("This executable cannot be run"); + Terminal.print("DeepscanV2.exe lets you run 'scan-analyze' with a depth up to 10"); }, }), [CompletedProgramName.serverProfiler]: new Program({ @@ -263,7 +263,7 @@ export const Programs: Record = { } if (!(targetServer instanceof Server)) { - Terminal.error(`ServerProfiler.exe can only be run on normal servers.`); + Terminal.error(`ServerProfiler.exe can only be run on normal servers`); return; } @@ -300,9 +300,9 @@ export const Programs: Record = { time: CONSTANTS.MillisecondsPerQuarterHour, }, run: (): void => { - Terminal.print("This executable cannot be run."); - Terminal.print("AutoLink.exe lets you automatically connect to other servers when using 'scan-analyze'."); - Terminal.print("When using scan-analyze, click on a server's hostname to connect to it."); + Terminal.print("This executable cannot be run"); + Terminal.print("AutoLink.exe lets you automatically connect to other servers when using 'scan-analyze'"); + Terminal.print("When using scan-analyze, click on a server's hostname to connect to it"); }, }), [CompletedProgramName.formulas]: new Program({ @@ -314,8 +314,8 @@ export const Programs: Record = { time: CONSTANTS.MillisecondsPer4Hours, }, run: (): void => { - Terminal.print("This executable cannot be run."); - Terminal.print("Formulas.exe lets you use the formulas API."); + Terminal.print("This executable cannot be run"); + Terminal.print("Formulas.exe lets you use the formulas API"); }, }), [CompletedProgramName.bitFlume]: new Program({ diff --git a/src/ScriptEditor/ui/ScriptEditorRoot.tsx b/src/ScriptEditor/ui/ScriptEditorRoot.tsx index 298b30c7db..4964ca904f 100644 --- a/src/ScriptEditor/ui/ScriptEditorRoot.tsx +++ b/src/ScriptEditor/ui/ScriptEditorRoot.tsx @@ -17,6 +17,7 @@ import { checkInfiniteLoop } from "../../Script/RamCalculations"; import { Settings } from "../../Settings/Settings"; import { iTutorialNextStep, ITutorial, iTutorialSteps } from "../../InteractiveTutorial"; +import { tutorialScriptName } from "../../ui/InteractiveTutorial/InteractiveTutorialRoot"; import { debounce } from "lodash"; import { GetServer } from "../../Server/AllServers"; @@ -196,7 +197,7 @@ function Root(props: IProps): React.ReactElement { // this is duplicate code with saving later. if (ITutorial.isRunning && ITutorial.currStep === iTutorialSteps.TerminalEditScript) { //Make sure filename + code properly follow tutorial - if (currentScript.path !== "n00dles.js") { + if (currentScript.path !== tutorialScriptName) { dialogBoxCreate("Don't change the script name for now."); return; } diff --git a/src/Sidebar/ui/SidebarRoot.tsx b/src/Sidebar/ui/SidebarRoot.tsx index 44e0f0c89b..8496baba74 100644 --- a/src/Sidebar/ui/SidebarRoot.tsx +++ b/src/Sidebar/ui/SidebarRoot.tsx @@ -128,16 +128,15 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement { let flash: Page | null = null; switch (ITutorial.currStep) { - case iTutorialSteps.CharacterGoToTerminalPage: case iTutorialSteps.ActiveScriptsPage: flash = Page.Terminal; break; - case iTutorialSteps.GoToCharacterPage: - flash = Page.Stats; - break; case iTutorialSteps.TerminalGoToActiveScriptsPage: flash = Page.ActiveScripts; break; + case iTutorialSteps.GoToCharacterPage: + flash = Page.Stats; + break; case iTutorialSteps.GoToHacknetNodesPage: flash = Page.Hacknet; break; diff --git a/src/Terminal/Terminal.ts b/src/Terminal/Terminal.ts index 43df8447be..fd5d1e00a1 100644 --- a/src/Terminal/Terminal.ts +++ b/src/Terminal/Terminal.ts @@ -12,6 +12,7 @@ import { GetServer } from "../Server/AllServers"; import { checkIfConnectedToDarkweb } from "../DarkWeb/DarkWeb"; import { iTutorialNextStep, iTutorialSteps, ITutorial } from "../InteractiveTutorial"; +import { tutorialScriptName } from "../ui/InteractiveTutorial/InteractiveTutorialRoot"; import { parseCommand, parseCommands } from "./Parser"; import { Settings } from "../Settings/Settings"; import { createProgressBarText } from "../utils/helpers/createProgressBarText"; @@ -347,7 +348,7 @@ export class Terminal { throw new Error("Could not get n00dles server"); } const errorMessageForBadCommand = - "Bad command. Please follow the tutorial or click 'Exit Tutorial' if you'd like to skip it."; + "Wrong command. Please follow the tutorial, or if you'd like to skip it click Exit Tutorial"; switch (ITutorial.currStep) { case iTutorialSteps.TerminalHelp: if (commandArray.length === 1 && commandArray[0] === "help") { @@ -417,7 +418,10 @@ export class Terminal { } break; case iTutorialSteps.TerminalNuke: - if (commandArray.length === 2 && commandArray[0] === "run" && commandArray[1] === "NUKE.exe") { + if ( + (commandArray.length === 2 && commandArray[0] === "run" && commandArray[1] === "NUKE.exe") || + commandArray[0] === "NUKE.exe" + ) { iTutorialNextStep(); } else { this.error(errorMessageForBadCommand); @@ -447,7 +451,7 @@ export class Terminal { } break; case iTutorialSteps.TerminalCreateScript: - if (commandArray.length === 2 && commandArray[0] === "nano" && commandArray[1] === "n00dles.js") { + if (commandArray.length === 2 && commandArray[0] === "nano" && commandArray[1] === tutorialScriptName) { iTutorialNextStep(); } else { this.error(errorMessageForBadCommand); @@ -463,7 +467,10 @@ export class Terminal { } break; case iTutorialSteps.TerminalRunScript: - if (commandArray.length === 2 && commandArray[0] === "run" && commandArray[1] === "n00dles.js") { + if ( + (commandArray.length === 2 && commandArray[0] === "run" && commandArray[1] === tutorialScriptName) || + commandArray[0] === tutorialScriptName + ) { iTutorialNextStep(); } else { this.error(errorMessageForBadCommand); @@ -471,7 +478,20 @@ export class Terminal { } break; case iTutorialSteps.ActiveScriptsToTerminal: - if (commandArray.length === 2 && commandArray[0] === "tail" && commandArray[1] === "n00dles.js") { + if (commandArray.length === 2 && commandArray[0] === "tail" && commandArray[1] === tutorialScriptName) { + iTutorialNextStep(); + } else { + this.error(errorMessageForBadCommand); + return; + } + break; + case iTutorialSteps.TerminalScp: + if ( + commandArray.length === 3 && + commandArray[0] === "scp" && + commandArray[1] === tutorialScriptName && + commandArray[2] === "n00dles" + ) { iTutorialNextStep(); } else { this.error(errorMessageForBadCommand); @@ -479,7 +499,7 @@ export class Terminal { } break; default: - this.error("Please follow the tutorial or click 'Exit Tutorial' if you'd like to skip it"); + this.error("Please follow the tutorial, or if you'd like to skip it click Exit Tutorial"); return; } } diff --git a/src/Terminal/commands/grow.ts b/src/Terminal/commands/grow.ts index e769d43054..3caf16d373 100644 --- a/src/Terminal/commands/grow.ts +++ b/src/Terminal/commands/grow.ts @@ -4,7 +4,7 @@ import { BaseServer } from "../../Server/BaseServer"; import { Server } from "../../Server/Server"; import { HacknetServer } from "../../Hacknet/HacknetServer"; import { Player } from "@player"; -import { formatExp, formatPercent, formatSecurity } from "../../ui/formatNumber"; +import { formatExp, formatPercent, formatSecurity, formatMoney } from "../../ui/formatNumber"; import { calculateHackingExpGain, calculateGrowTime } from "../../Hacking"; import { processSingleServerGrowth } from "../../Server/ServerHelpers"; @@ -17,7 +17,7 @@ export function grow(args: (string | number | boolean)[], server: BaseServer): u if (server.requiredHackingSkill === undefined) return Terminal.error("Cannot grow this server."); if (server instanceof HacknetServer) { - Terminal.error("Cannot grow this kind of server"); + Terminal.error("Cannot grow this kind of server."); return; } if (!(server instanceof Server)) throw new Error("server should be normal server"); @@ -26,12 +26,13 @@ export function grow(args: (string | number | boolean)[], server: BaseServer): u const oldSec = server.hackDifficulty; const growth = processSingleServerGrowth(server, 25, server.cpuCores); const newSec = server.hackDifficulty; + const newMoney = server.moneyAvailable; Player.gainHackingExp(expGain); Terminal.print( - `Available money on '${server.hostname}' grown by ${formatPercent(growth - 1, 6)}. Gained ${formatExp( - expGain, - )} hacking exp.`, + `Available money on '${server.hostname}' grown by ${formatPercent(growth - 1, 6)} to ${formatMoney( + newMoney, + )}. Gained ${formatExp(expGain)} hacking exp`, ); Terminal.print( `Security increased on '${server.hostname}' from ${formatSecurity(oldSec)} to ${formatSecurity(newSec)}`, diff --git a/src/Terminal/commands/weaken.ts b/src/Terminal/commands/weaken.ts index c212331d29..c8479b4729 100644 --- a/src/Terminal/commands/weaken.ts +++ b/src/Terminal/commands/weaken.ts @@ -32,8 +32,9 @@ export function weaken(args: (string | number | boolean)[], server: BaseServer): Terminal.print( `Security decreased on '${server.hostname}' by ${formatSecurity(weakenAmt)} from ${formatSecurity( oldSec, - )} to ${formatSecurity(newSec)} (min: ${formatSecurity(server.minDifficulty)})` + - ` and Gained ${formatExp(expGain)} hacking exp.`, + )} to ${formatSecurity(newSec)} (min: ${formatSecurity(server.minDifficulty)}). Gained ${formatExp( + expGain, + )} hacking exp`, ); }); } diff --git a/src/ui/CharacterStats.tsx b/src/ui/CharacterStats.tsx index 53d6e9bd0d..565dfc54a1 100644 --- a/src/ui/CharacterStats.tsx +++ b/src/ui/CharacterStats.tsx @@ -4,6 +4,7 @@ import React, { useState } from "react"; import { BitNodes } from "../BitNode/BitNode"; import { currentNodeMults } from "../BitNode/BitNodeMultipliers"; import { BitNodeMultipliersDisplay } from "../BitNode/ui/BitnodeMultipliersDescription"; +import { iTutorialSteps, iTutorialNextStep, ITutorial } from "../InteractiveTutorial"; import { HacknetServerConstants } from "../Hacknet/data/Constants"; import { getCloudServerLimit } from "../Server/ServerPurchases"; import { Settings } from "../Settings/Settings"; @@ -222,6 +223,16 @@ function MoneyModal({ open, onClose }: IMoneyModalProps): React.ReactElement { } export function CharacterStats(): React.ReactElement { + /* INTERACTIVE TUTORIAL */ + if (ITutorial.isRunning) { + if (ITutorial.currStep === iTutorialSteps.CharacterPage) { + iTutorialNextStep(); + } else { + //return -1; ?? not sure how to handle this + } + } + /* END INTERACTIVE TUTORIAL */ + const [moneyOpen, setMoneyOpen] = useState(false); const [employersOpen, setEmployersOpen] = useState(false); useCycleRerender(); diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 82e90e40f7..3d5c27e348 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -1,12 +1,9 @@ import React, { useEffect } from "react"; -import Paper from "@mui/material/Paper"; -import Typography from "@mui/material/Typography"; -import Button from "@mui/material/Button"; +import { Paper, Box, Typography, Button, Link } from "@mui/material"; import { ITutorialEvents } from "./ITutorialEvents"; import { CopyableText } from "../React/CopyableText"; -import ListItem from "@mui/material/ListItem"; import EqualizerIcon from "@mui/icons-material/Equalizer"; import LastPageIcon from "@mui/icons-material/LastPage"; import HelpIcon from "@mui/icons-material/Help"; @@ -43,12 +40,12 @@ const useStyles = makeStyles()((theme: Theme) => ({ }, })); +export const tutorialScriptName = `script.js`; + export function InteractiveTutorialRoot(): React.ReactElement { const { classes } = useStyles(); const rerender = useRerender(); - const tutorialScriptName = `n00dles.js`; - const contents: Record = { [iTutorialSteps.Start as number]: { content: ( @@ -58,170 +55,138 @@ export function InteractiveTutorialRoot(): React.ReactElement { future... The year is 2077...

- This tutorial will show you the basics of the game. You may skip the tutorial at any time. + This tutorial will show you the basics of the game.

- You can replay this tutorial by going to the Options tab and pressing "Reset tutorial". + If you need to hide this tutorial panel temporarily, there's a button to collapse it in the top-right.

- You can also collapse this panel to temporarily hide this tutorial. - - - ), - canNext: true, - }, - [iTutorialSteps.GoToCharacterPage as number]: { - content: ( - <> - Let's start by heading to the Stats page. Click - - - Stats - - - on the main navigation menu (left-hand side of the screen) - - ), - canNext: false, - }, - [iTutorialSteps.CharacterPage as number]: { - content: ( - <> - - - Stats - - - shows a lot of important information about your progress, such as your skills, money, and bonuses. + You can also exit the tutorial at any time. If you ever want to review it, go to the Options tab and select + Repeat Tutorial. ), canNext: true, }, - [iTutorialSteps.CharacterGoToTerminalPage as number]: { - content: ( - <> - Let's head to your computer's terminal by clicking - - - Terminal - - on the main navigation menu. - - ), - canNext: false, - }, [iTutorialSteps.TerminalIntro as number]: { content: ( <> - - - Terminal - - is used to interface with your home computer as well as all of the other machines around the world. + We're currently on the{" "} + + + Terminal + {" "} + tab. +
+
+ You can use the{" "} + + + Terminal + {" "} + to interface with your home computer, as well as with other machines around the world.
), canNext: true, }, - [iTutorialSteps.TerminalHelp as number]: { - content: ( - <> - Let's try it out. Start by entering - {"[home /]> help"} - (Don't forget to press Enter after typing the command) - - ), - canNext: false, - }, - [iTutorialSteps.TerminalLs as number]: { + [iTutorialSteps.TerminalScan as number]: { content: ( <> - {"[home /]> help"} - displays a list of all available Terminal commands, how to use them, and a description of what they do.{" "} + Let's try that out. Start by entering

- Let's try another command. Enter
- - {"[home /]> ls"} + {"[home /]> scan"} -
( "ls" is short for "list" ) +
+ (Don't forget to press Enter after typing the command.)
), canNext: false, }, - [iTutorialSteps.TerminalScan as number]: { + [iTutorialSteps.TerminalScanAnalyze1 as number]: { content: ( <> - {"[home /]> ls"} - {" "} - is a basic command that lists the files on the computer. Right now, it shows that you have a program called{" "} - NUKE.exe on your computer. We'll get to what this does later.
+ Running +

- Using your home computer's terminal, you can connect to other machines throughout the world. Let's do that - now by first entering
{"[home /]> scan"} + +
+ shows all servers that you can connect to from your current machine. Servers are identified by their + hostname. +
+
+ The network's much bigger than these nearby servers though. To start exploring it, let's enter +
+
+
+ {"[home /]> scan-analyze"} ), canNext: false, }, - [iTutorialSteps.TerminalScanAnalyze1 as number]: { + [iTutorialSteps.TerminalScanAnalyze2 as number]: { content: ( <> - {"[home /]> scan"} - shows all available network connections. In other words, it displays a list of all servers that can be - connected to from your current machine. A server is identified by its hostname.
+ That's given more detailed information about the servers you can connect to. +
+
+ To look depeer into the network, we can change our scanning depth to 2. +

- That's great and all, but there's so many servers. Which one should you go to?{" "}
- - {"[home /]> scan-analyze"} - gives some more detailed information about servers on the network. Try it now! + {"[home /]> scan-analyze 2"} ), canNext: false, }, - [iTutorialSteps.TerminalScanAnalyze2 as number]: { + [iTutorialSteps.TerminalConnectInterval as number]: { content: ( <> - {"[home /]> scan-analyze"} - shows more detailed information about each server that you can connect to (servers that are a distance of - one node away).
-
It is also possible to run scan-analyze with a higher depth. Let's try a depth of two with the - following command:{" "} + Now you can see information about all servers that are up to 2 nodes away. You can also see how to navigate + to those servers through the network. +
+
+ That's great and all, but there are so many servers. Which one should we go to? Well, let's pick a target we + can hack!
- - {"[home /]> scan-analyze 2"} ), - canNext: false, + canNext: true, }, [iTutorialSteps.TerminalConnect as number]: { content: ( <> - Now you can see information about all servers that are up to two nodes away, as well as figure out how to - navigate to those servers through the network. You can only connect to a server that is one node away. To - connect to a machine, use + In the year 2077, currency is digital and decentralized. People and corporations store their money on + servers and computers. Using hacking skills and malware, you can hack servers to steal money and gain + experience. +
+
+ If you check the read-out of scan-analyze you can see that n00dles has a required hacking skill of only 1. + That means you can hack it right now. +
+
+ To do that, we need to connect to it. You can connect to a machine that is one node away using +
+
{"[home /]> connect hostname"} - - From the results of - {"[home /]> scan-analyze 2"} - - {" "} - we can see that the n00dles server is only one node away. Let's connect to it now using: +
+ So let's connect to n00dles. +
+
- {"[home /]> connect n00dles"} ), @@ -231,13 +196,9 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - You are now connected to another machine! What can you do now? You can hack it! + Before we try hacking, let's start by running some diagnostics using
-
In the year 2077, currency has become digital and decentralized. People and corporations store their - money on servers and computers. Using your hacking abilities, you can hack servers to steal money and gain - experience.

- Before you try to hack a server, you should run diagnostics using{" "}
{"[n00dles /]> analyze"} @@ -247,26 +208,28 @@ export function InteractiveTutorialRoot(): React.ReactElement { [iTutorialSteps.TerminalNuke as number]: { content: ( <> - When - {"[n00dles /]> analyze"} - - finishes running it will show useful information about hacking the server.
-
For this server, the required hacking skill is only 1, which means you can hack it right now. - However, in order to hack a server you must first gain root access. The NUKE.exe program that we saw earlier - on your home computer is a virus that will grant you root access to a machine if there are enough open - ports. + When +
+
{"[n00dles /]> analyze"} - - {" "} - shows that there do not need to be any open ports on this machine for the NUKE virus to work, so go ahead - and run the virus using{" "} +
+ finishes running, it'll display some useful diagnostic data. +
+
+ In the data, you can see the server's Root Access status. To hack a server you must gain root access first. + Handily, you've come prepared with a virus called NUKE.exe. NUKE.exe will grant you root access to a machine + as long as there are enough open ports. +
+
+ If you look at the diagnostics again, you'll also see that the required number of open ports for NUKE is 0. + So you're good to go ahead and run the virus! Just enter +
+
- {"[n00dles /]> run NUKE.exe"} - - + {"[n00dles /]> NUKE.exe"} ), canNext: false, @@ -274,61 +237,88 @@ export function InteractiveTutorialRoot(): React.ReactElement { [iTutorialSteps.TerminalManualHack as number]: { content: ( <> - You now have root access! You can hack the server using + + You now have root access! You can hack the server using +
+
+
{"[n00dles /]> hack"} - - Try doing that now. + +
+ Try doing that now. +
), canNext: true, }, [iTutorialSteps.TerminalHackingMechanics as number]: { content: ( - - You are now attempting to hack the server. Performing a hack takes time and only has a certain percentage - chance of success. This time and success chance is determined by a variety of factors, including your hacking - skill and the server's security level. -
-
- If your attempt to hack the server is successful, you will steal a certain percentage of the server's total - money. This percentage is affected by your hacking skill and the server's security level. -
-
- The amount of money on a server is not limitless. So, if you constantly hack a server and deplete its money, - then you will encounter diminishing returns in your hacking. You will need to use{" "} + <> + + You're now attempting to hack the server. Performing a hack takes time, and has a certain success chance. + Both the hack time and success chance are affected by your hacking skill, and by the server's security + level. +
+
+ If your attempt to hack the server is successful, you'll steal a percentage of the server's available money. + (Again, this percentage is affected by your hacking skill and the server's security level). +
+
+ As you hack a server, you'll deplete the money it has available and cause its security level to rise. To + restore things, you need to use +
+
+
{"[n00dles /]> grow"} - which tricks the company into adding money to their server and{" "} + +
+ which tricks the company into adding money to their server, and +
+
+
{"[n00dles /]> weaken"} - which increases the speed of hack and grow. -
+ +
+ which lowers the server's security level. +
+ ), canNext: true, }, [iTutorialSteps.TerminalGoHome as number]: { content: ( <> - From any server you can get back home using + + Hacking from the terminal is OK, but it's manual. It sure would be handy if there was a way to automate it! +
+
+ So let's head home and create our first script. +
+
+ You can get back home from any server using +
+
+
{"[n00dles /]> home"} - - Let's head home before creating our first script! ), canNext: false, }, + [iTutorialSteps.TerminalCreateScript as number]: { content: ( <> - Hacking is the core mechanic of the game and is necessary for progressing. However, you don't want to be - hacking manually the entire time. You can automate your hacking by writing scripts! + To create a new script or edit an existing one, you can use

- To create a new script or edit an existing one, you can use{" "}
- {"[home /]> nano"} - + {"[home /]> nano file"} - Scripts must end with a script extension (.js, .jsx, .ts, .tsx). Let's make a script now by entering +
+ Script names must end with a script extension (.js, .ts, .jsx, .tsx). Let's make a script now by entering +
+
{`[home /]> nano ${tutorialScriptName}`} @@ -339,8 +329,10 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - This is the script editor. You can use it to program your scripts. Click this text to copy it and paste it - into the text editor: + This is the script editor. +
+
+ Below is a basic script that hacks n00dles. Click it to copy it, then paste it into the editor.

@@ -357,18 +349,29 @@ export async function main(ns) {
- For anyone with basic programming experience, this code should be straightforward. This script will - continuously hack the n00dles server. + If you have a look at the code of the script, you might be able to see that it hacks n00dles while 'true' is + true – which it always is! So this script hacks n00dles on a loop forever.

- Use the search tool at the bottom to find and have a quick glance at documentation of any NS APIs. + Unlike manual hacking where you need to be connected to your target, scripts can target any server on the + network + from any server on the network.

- To access NS API documentation, press the - link at the bottom. + While we're in the editor, it's worth saying that everything we do in this tutorial can be scripted. You can + map the network with ns.scan(), run scripts with ns.run() or ns.exec(), and get server diagnostics with + ns.getServer().

- To save and close the script editor, press the button at the bottom. + If you ever want to check which functions are available to you, you can do that in the editor. Either search + using the search bar tool at the bottom of the editor, or click the{" "} + + NS API documentation + {" "} + link beside it. +
+
+ OK, back to hacking. Click Save at the bottom to save your script and close the editor.
), @@ -378,12 +381,13 @@ export async function main(ns) { content: ( <> - Now we'll run the script. Scripts require a certain amount of RAM to run, and can be run on any machine - which you have root access to. Different servers have different amounts of RAM. You can also purchase more - RAM for your home server. + Now we'll run the script. Scripts need RAM to run, and can be run on any machine which you have root access + to. Different servers have different amounts of RAM. You can also purchase more RAM for your home server.

To check how much RAM is available on this machine, enter +
+
{"[home /]> free"} @@ -394,9 +398,11 @@ export async function main(ns) { content: ( <> - We have 8GB of free RAM on this machine, which is enough to run our script. Let's run our script using + We have 8GB of free RAM, which is enough to run our script. Let's run our script using +
+
- {`[home /]> run ${tutorialScriptName}`} + {`[home /]> ${tutorialScriptName}`} ), canNext: false, @@ -405,18 +411,20 @@ export async function main(ns) { content: ( <> - Your script is now running! It will continuously run in the background and will automatically stop if the - code ever completes (the {tutorialScriptName} will never complete because it runs an infinite loop).
+ Your script is now running! Scripts run in the background until their code completes (although + {tutorialScriptName} will never complete because it has an infinite loop). +
+
+ Scripts can passively earn you income and hacking experience. They'll keep earning even while you're + offline, although at a slower rate.
- These scripts can passively earn you income and hacking experience. Your scripts will also earn money and - experience while you are offline, although at a slightly slower rate.

Let's check out some statistics for our running scripts by clicking{" "} + + + Active Scripts +
- - - Active Scripts - ), canNext: false, @@ -429,18 +437,18 @@ export async function main(ns) { this to gauge how well your scripts are doing.

- Click on Home to see the scripts running on it. + Click home to see the scripts running on it.

- Then click on n00dles.js to see the scripts information. + Then click ${tutorialScriptName} to see the script's information.

- Let's go back to + Let's go back to the{" "} + + + Terminal + - - - Terminal - ), canNext: false, @@ -449,8 +457,10 @@ export async function main(ns) { content: ( <> - One last thing about scripts, each active script contains logs that detail what it's doing. We can check - these logs using the tail command. Do that now for the script we just ran by typing{" "} + Each active script has logs that detail what it's doing. You can check these logs using the tail command. To + do that for the script you just ran, you can enter +
+
{`[home /]> tail ${tutorialScriptName}`} @@ -461,20 +471,99 @@ export async function main(ns) { content: ( <> - The log for this script won't show much right now (it might show nothing at all) because it just started - running...but check back again in a few minutes!
+ The log for this script may not show much right now because it just started running... but check back again + in a few minutes! +
+ + ), + canNext: true, + }, + [iTutorialSteps.TerminalLs as number]: { + content: ( + <> + + We're not going to get very far running scripts on our home computer alone. We need to copy them to other + servers too. +
+
+ Before we do that, let's see what's currently on our home computer using +
+
+
+ {"[home /]> ls"} + +
+ ("ls" is short for "list".) +
+ + ), + canNext: false, + }, + [iTutorialSteps.TerminalScp as number]: { + content: ( + <> + + That's shown all the files on your home computer. Right now, you can see the NUKE.exe program that you used + earlier, and {tutorialScriptName}. +
+
+ NUKE.exe can only ever be on your home computer. But if you want other servers to run {tutorialScriptName}, + you need to copy it to them. +
+
+ To do that, we use +

- This covers the basics of hacking. To learn more about writing scripts, select
- - - Documentation - + {"[home /]> scp file destination"} - in the main navigation menu to look at the documentation. +
+ To copy {tutorialScriptName} to n00dles, enter

- For now, let's move on to something else! +
+ {`[home /]> scp ${tutorialScriptName} n00dles`} + + ), + canNext: false, + }, + [iTutorialSteps.TerminalHelp as number]: { + content: ( + <> + + Lastly, if you can't remember the right terminal command, you can always use +
+
+
+ {"[home /]> help"} + + ), + canNext: false, + }, + [iTutorialSteps.GoToCharacterPage as number]: { + content: ( + <> + + Now we've made some money and exp, let's head to the Stats tab and see our gains. Click{" "} + + + Stats + {" "} + at the left-hand side of the screen. + + + ), + canNext: false, + }, + [iTutorialSteps.CharacterPage as number]: { + content: ( + <> + + + + Stats + {" "} + shows information about your skills, money, and bonuses. ), @@ -484,14 +573,14 @@ export async function main(ns) { content: ( <> - Hacking is not the only way to earn money. One other way to passively earn money is by purchasing and - upgrading Hacknet Nodes. Let's go to + Hacking isn't the only way to earn money. One other way to passively earn money is to purchase and upgrade + Hacknet Nodes. Let's go to{" "} + + + Hacknet + {" "} + . - - - Hacknet - - through the main navigation menu now. ), canNext: false, @@ -499,7 +588,7 @@ export async function main(ns) { [iTutorialSteps.HacknetNodesIntroduction as number]: { content: ( - Here you can purchase new Hacknet Nodes and upgrade your existing ones. Let's purchase a new one now. + Here you can purchase new Hacknet Nodes and upgrade your existing ones. Let's purchase a new one. ), canNext: true, @@ -508,16 +597,17 @@ export async function main(ns) { content: ( <> - You just purchased a Hacknet Node! This Hacknet Node will passively earn you money over time, both online - and offline. When you get enough money, you can upgrade your newly-purchased Hacknet Node below. + Hacknet Nodes earn you money over time, both online and offline. When you get enough money, you can upgrade + your newly-purchased Hacknet Node below.

- Let's go to + Let's go to{" "} + + + City + {" "} + .
- - - City - ), canNext: false, @@ -526,16 +616,17 @@ export async function main(ns) { content: ( <> - This page lists all of the different locations you can currently travel to. Each location has something that - you can do. There's a lot of content out in the world, make sure you explore and discover! + This page lists all of the locations in your current city. Each location has something that you can do. + There's a lot of content out in the world, so make sure you explore and discover!

- Lastly, click on + Lastly, click on{" "} + + + Documentation + {" "} + .
- - - Documentation - ), canNext: false, @@ -543,40 +634,44 @@ export async function main(ns) { [iTutorialSteps.DocumentationPageInfo as number]: { content: ( - This page contains a lot of different documentation about the game's contents and mechanics. I know it's a - lot, but I highly suggest you read (or at least skim) through this before you start playing. Some pages are - inaccessible at the start and will be unlocked later. -
+ The pages in the Documentation tab explain the game's content and mechanics. I know it looks a lot, but I + highly suggest you read (or at least skim) through this before you start playing.
- If you click a link in these pages while holding Ctrl key (Control key on Mac keyboard), it will be opened in - a new tab. If you play the Steam version, that link will be opened in your default browser.
-
- You should at least check these pages: + If you look at nothing else, the three pages I'd recommend are:
  • - The Beginner's guide contains the - guide for new players, navigating you through most of the early game. + the Beginner's guide, which will + help you navigate through most of the early game
  • - The NS API documentation contains reference - materials for all NS APIs. + the NS API documentation, which contains + reference materials for all NS APIs
  • - The FAQ contains questions often asked by - beginners of the game. + the FAQ, which answers questions often asked by + beginners
- - This documentation page is the best place to get up-to-date information, especially when you get stuck. If - you have a question and cannot find the answer here, please ask us on Discord. - + You'll notice that some of the pages are inaccessible right now. Don't worry – you'll unlock them later on. +
+
+ If you want to open one of the Documentaion page links in a new tab, click it while holding Ctrl (Control on a + Mac keyboard). If you're playing the Steam version, doing that will open the link in your default browser. +
+
+ While the documentation page is the best place to get information, especially when you get stuck, if you + can't find the answer here then please{" "} + + ask us on Discord + + .
- The documentation at readthedocs is outdated and unmaintained. Do not use them! + The documentation at readthedocs is outdated and unmaintained. Do not use it!
- That's the end of the tutorial. Hope you enjoy the game! + And that's the end of the tutorial. We hope you enjoy the game!
), canNext: true, @@ -597,7 +692,7 @@ export async function main(ns) { throw new Error(`Invalid step in the tutorial: ${step}`); } return ( - + {content.content}
{step !== iTutorialSteps.DocumentationPageInfo && ( From 3b733464a43065ac18c00cf4327bbf8274c9edb6 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Wed, 26 Aug 2026 04:39:26 +0100 Subject: [PATCH 02/82] spacing --- .../InteractiveTutorialRoot.tsx | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 3d5c27e348..a19b61833d 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -83,7 +83,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { You can use the{" "} - Terminal + Terminal {" "} to interface with your home computer, as well as with other machines around the world. @@ -422,7 +422,7 @@ export async function main(ns) { Let's check out some statistics for our running scripts by clicking{" "} - Active Scripts + Active Scripts @@ -446,7 +446,7 @@ export async function main(ns) { Let's go back to the{" "} - Terminal + Terminal @@ -547,7 +547,7 @@ export async function main(ns) { Now we've made some money and exp, let's head to the Stats tab and see our gains. Click{" "} - Stats + Stats {" "} at the left-hand side of the screen. @@ -561,7 +561,7 @@ export async function main(ns) { - Stats + Stats {" "} shows information about your skills, money, and bonuses. @@ -577,7 +577,7 @@ export async function main(ns) { Hacknet Nodes. Let's go to{" "} - Hacknet + Hacknet {" "} . @@ -604,7 +604,7 @@ export async function main(ns) { Let's go to{" "} - City + City {" "} . @@ -623,7 +623,7 @@ export async function main(ns) { Lastly, click on{" "} - Documentation + Documentation {" "} . @@ -660,8 +660,8 @@ export async function main(ns) { Mac keyboard). If you're playing the Steam version, doing that will open the link in your default browser.

- While the documentation page is the best place to get information, especially when you get stuck, if you - can't find the answer here then please{" "} + While the documentation page is the best place to get information, especially when you get stuck, if you can't + find the answer here then please{" "} ask us on Discord From c6350ab1098a2ae57999d26f53dcd542b9b6f2f3 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Wed, 26 Aug 2026 04:51:42 +0100 Subject: [PATCH 03/82] blah --- src/InteractiveTutorial.ts | 14 ++++---------- .../InteractiveTutorialRoot.tsx | 4 ++-- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/InteractiveTutorial.ts b/src/InteractiveTutorial.ts index 8a6ae1e67e..7c071e7971 100644 --- a/src/InteractiveTutorial.ts +++ b/src/InteractiveTutorial.ts @@ -1,14 +1,8 @@ -//// Tidy up: -// n00dles.js -// - -//////// +//// Still to do: +// n00dles.js references in docs // Red to blue for stuff -/// Somewhere ??? the text that says 'can't kill during tutorial' ... when you clearly can -// Add the stuff about docs and the editor back in later on -// Don't auto-move from the Script editor to the Termainal. Make the player do that. -// add scp step -// add "all this stuff can be automated" scp > ns.scp; run > ns.run/ns.exec; weaken > ns.weaken +// Somewhere ??? the text that says 'Processes cannot be killed during the tutorial' ... when you clearly can! +// Rebase to get rid of the irrelevant commits! import { Player } from "@player"; import { LiteratureName } from "@enums"; diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index a19b61833d..70b4dd8a7a 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -641,8 +641,8 @@ export async function main(ns) { If you look at nothing else, the three pages I'd recommend are:
  • - the Beginner's guide, which will - help you navigate through most of the early game + the Beginner's guide, which contains + an invaluable basic hacking script, and which helps you navigate through most of the early game
  • the NS API documentation, which contains From 42dd5940ac8ccb13aace1cfe867cc914c3eefa6c Mon Sep 17 00:00:00 2001 From: branchtheory Date: Wed, 26 Aug 2026 14:29:39 +0100 Subject: [PATCH 04/82] attempt --- src/Sidebar/ui/SidebarAccordion.tsx | 6 +- src/Sidebar/ui/SidebarItem.tsx | 10 +- src/Sidebar/ui/SidebarRoot.tsx | 8 +- .../InteractiveTutorialRoot.tsx | 185 +++++++++--------- src/ui/MD/code.tsx | 12 +- 5 files changed, 119 insertions(+), 102 deletions(-) diff --git a/src/Sidebar/ui/SidebarAccordion.tsx b/src/Sidebar/ui/SidebarAccordion.tsx index 10f4bbcb19..5e72deba4d 100644 --- a/src/Sidebar/ui/SidebarAccordion.tsx +++ b/src/Sidebar/ui/SidebarAccordion.tsx @@ -20,7 +20,7 @@ type SidebarAccordionProps = { items: (IItemProps | boolean)[]; icon: React.ReactElement["type"]; sidebarOpen: boolean; - classes: Record<"listitem" | "active", string>; + classes: Record<"listitem" | "active" | "themeColorPrimary" | "themeColorSecondary" | "themeColorInfo" | "themeColorError", string>; }; type ClickFnCacheKeyType = (page: Page) => void; @@ -69,11 +69,11 @@ export function SidebarAccordion({ setOpen((open) => !open)}> - + {key_}} /> - {open ? : } + {open ? : } ), [li_classes, sidebarOpen, key_, open, Icon], diff --git a/src/Sidebar/ui/SidebarItem.tsx b/src/Sidebar/ui/SidebarItem.tsx index 6ffb90494e..1e90115dba 100644 --- a/src/Sidebar/ui/SidebarItem.tsx +++ b/src/Sidebar/ui/SidebarItem.tsx @@ -19,12 +19,12 @@ export interface ICreateProps { export interface SidebarItemProps extends ICreateProps { clickFn: () => void; flash: boolean; - classes: Record<"listitem" | "active", string>; + classes: Record<"listitem" | "active" | "themeColorPrimary" | "themeColorSecondary" | "themeColorInfo" | "themeColorError", string>; sidebarOpen: boolean; } export const SidebarItem = memo(function SidebarItem(props: SidebarItemProps): React.ReactElement { - const color = props.flash ? "error" : props.active ? "primary" : "secondary"; + const color = props.flash ? props.classes.themeColorInfo : props.active ? props.classes.themeColorPrimary : props.classes.themeColorSecondary; return ( - 0 ? props.count : undefined} color="error"> + 0 ? props.count : undefined} sx={{ color: props.classes.themeColorError }}> - + - {props.key_} + {props.key_} ); diff --git a/src/Sidebar/ui/SidebarRoot.tsx b/src/Sidebar/ui/SidebarRoot.tsx index 8496baba74..ba2127828f 100644 --- a/src/Sidebar/ui/SidebarRoot.tsx +++ b/src/Sidebar/ui/SidebarRoot.tsx @@ -119,7 +119,11 @@ const useStyles = makeStyles()((theme: Theme) => ({ active: { borderLeft: "3px solid " + theme.palette.primary.main, }, - listitem: {}, + listitem: {}, + themeColorPrimary: { color: theme.palette.primary.main }, + themeColorSecondary: { color: theme.palette.secondary.main }, + themeColorInfo: { color: theme.palette.info.main }, + themeColorError: { color: theme.palette.error.main }, })); export function SidebarRoot(props: { page: Page }): React.ReactElement { @@ -327,7 +331,7 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement { () => ( - + ({ - textfield: { - borderBottom: "1px solid " + theme.palette.primary.main, - }, - code: { - whiteSpace: "pre", - backgroundColor: theme.palette.background.paper, - }, -})); - export const tutorialScriptName = `script.js`; export function InteractiveTutorialRoot(): React.ReactElement { - const { classes } = useStyles(); + const theme = useTheme(); + const { classes } = codeBlockStyles(); + const TerminalText = styled(Typography)(({ theme }) => ({ + borderBottom: `1px solid ${theme.palette.primary.main}`, + })); const rerender = useRerender(); const contents: Record = { @@ -58,7 +52,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { This tutorial will show you the basics of the game.

    - If you need to hide this tutorial panel temporarily, there's a button to collapse it in the top-right. + If you need to hide this tutorial panel temporarily, you can collapse it.

    You can also exit the tutorial at any time. If you ever want to review it, go to the Options tab and select @@ -74,16 +68,16 @@ export function InteractiveTutorialRoot(): React.ReactElement { We're currently on the{" "} - - Terminal + {" "} + Terminal {" "} tab.

    You can use the{" "} - - Terminal + {" "} + Terminal {" "} to interface with your home computer, as well as with other machines around the world.
    @@ -99,7 +93,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {

    - {"[home /]> scan"} + {"[home /]> scan"}
    (Don't forget to press Enter after typing the command.) @@ -116,7 +110,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {

    - {"[home /]> scan"} + {"[home /]> scan"}
    shows all servers that you can connect to from your current machine. Servers are identified by their @@ -127,7 +121,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {

    - {"[home /]> scan-analyze"} + {"[home /]> scan-analyze"} ), canNext: false, @@ -136,14 +130,14 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - That's given more detailed information about the servers you can connect to. + That's given us more detailed information about the servers we can connect to.

    To look depeer into the network, we can change our scanning depth to 2.

    - {"[home /]> scan-analyze 2"} + {"[home /]> scan-analyze 2"} ), canNext: false, @@ -180,14 +174,14 @@ export function InteractiveTutorialRoot(): React.ReactElement {

    - {"[home /]> connect hostname"} + {"[home /]> connect hostname"}
    So let's connect to n00dles.

    - {"[home /]> connect n00dles"} + {"[home /]> connect n00dles"} ), canNext: false, @@ -196,11 +190,11 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - Before we try hacking, let's start by running some diagnostics using + Before we try hacking, let's run some diagnostics using

    - {"[n00dles /]> analyze"} + {"[n00dles /]> analyze"} ), canNext: false, @@ -213,23 +207,23 @@ export function InteractiveTutorialRoot(): React.ReactElement {

    - {"[n00dles /]> analyze"} + {"[n00dles /]> analyze"}
    finishes running, it'll display some useful diagnostic data.

    - In the data, you can see the server's Root Access status. To hack a server you must gain root access first. + In the data, you can see the server's root access status. To hack a server you must gain root access first. Handily, you've come prepared with a virus called NUKE.exe. NUKE.exe will grant you root access to a machine as long as there are enough open ports.

    - If you look at the diagnostics again, you'll also see that the required number of open ports for NUKE is 0. - So you're good to go ahead and run the virus! Just enter + If you look at the diagnostics again, you'll also see that n00dles' required number of open ports for NUKE + is 0. So you're good to go ahead and run the virus! Just enter

    - {"[n00dles /]> NUKE.exe"} + {"[n00dles /]> NUKE.exe"} ), canNext: false, @@ -242,7 +236,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {

    - {"[n00dles /]> hack"} + {"[n00dles /]> hack"}
    Try doing that now. @@ -264,22 +258,25 @@ export function InteractiveTutorialRoot(): React.ReactElement { (Again, this percentage is affected by your hacking skill and the server's security level).

    - As you hack a server, you'll deplete the money it has available and cause its security level to rise. To - restore things, you need to use + When you hack a server, you deplete the money it has available, so your following hacks take less money. You + also cause its security level to rise, so your hacks take longer. +
    +
    + To restore things, you can use

    - {"[n00dles /]> grow"} + {"[n00dles /]> grow"}
    which tricks the company into adding money to their server, and

    - {"[n00dles /]> weaken"} + {"[n00dles /]> weaken"}
    - which lowers the server's security level. + which lowers the server's security level, speeding up hack, grow and weaken.
    ), @@ -289,7 +286,8 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - Hacking from the terminal is OK, but it's manual. It sure would be handy if there was a way to automate it! + Hacking is the core mechanic of the game and is necessary for progression. So you don't want to + be hacking manually the entire time. What we need is a way to automate it.

    So let's head home and create our first script. @@ -299,7 +297,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {

    - {"[n00dles /]> home"} + {"[n00dles /]> home"} ), canNext: false, @@ -313,14 +311,14 @@ export function InteractiveTutorialRoot(): React.ReactElement {

    - {"[home /]> nano file"} + {"[home /]> nano file"}
    - Script names must end with a script extension (.js, .ts, .jsx, .tsx). Let's make a script now by entering + Script names must end with a script extension (.js, .ts, .jsx, .tsx). Let's create a script now by entering

    - {`[home /]> nano ${tutorialScriptName}`} + {`[home /]> nano ${tutorialScriptName}`} ), canNext: false, @@ -332,7 +330,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { This is the script editor.

    - Below is a basic script that hacks n00dles. Click it to copy it, then paste it into the editor. + Below is a basic script that hacks n00dles. Copy and paste it into the editor.
    @@ -349,29 +347,26 @@ export async function main(ns) {
    - If you have a look at the code of the script, you might be able to see that it hacks n00dles while 'true' is + If you have a look at the code of the script, you might be able to see that it hacks n00dles while true is true – which it always is! So this script hacks n00dles on a loop forever.

    - Unlike manual hacking where you need to be connected to your target, scripts can target any server on the - network - from any server on the network. + When we were hacking manually, we needed to be connected to our target. With scripts, however, we can target + any server on the network{" "} + from{" "}any target on the network.

    While we're in the editor, it's worth saying that everything we do in this tutorial can be scripted. You can - map the network with ns.scan(), run scripts with ns.run() or ns.exec(), and get server diagnostics with + map the network with ns.scan(), run scripts with ns.run() or ns.exec(), and get server information with ns.getServer().

    If you ever want to check which functions are available to you, you can do that in the editor. Either search using the search bar tool at the bottom of the editor, or click the{" "} - - NS API documentation - {" "} - link beside it. + NS API documentation link beside it.

    - OK, back to hacking. Click Save at the bottom to save your script and close the editor. + OK, back to hacking. Click Save at the bottom to save your script and close the editor.
    ), @@ -381,15 +376,17 @@ export async function main(ns) { content: ( <> - Now we'll run the script. Scripts need RAM to run, and can be run on any machine which you have root access - to. Different servers have different amounts of RAM. You can also purchase more RAM for your home server. + Now we'll run the script. You can run scripts on any server that you have root access to. +
    +
    + Scripts need RAM to run, and different servers have different amounts.

    To check how much RAM is available on this machine, enter

    - {"[home /]> free"} + {"[home /]> free"} ), canNext: false, @@ -398,11 +395,15 @@ export async function main(ns) { content: ( <> - We have 8GB of free RAM, which is enough to run our script. Let's run our script using + We have 8GB of free RAM. If that doesn't sound like much, don't worry: you can purchase more RAM + for your home server. +
    +
    + For now though, let's run our script using

    - {`[home /]> ${tutorialScriptName}`} + {`[home /]> ${tutorialScriptName}`} ), canNext: false, @@ -421,8 +422,8 @@ export async function main(ns) {
    Let's check out some statistics for our running scripts by clicking{" "} - - Active Scripts + {" "} + Active Scripts @@ -437,16 +438,16 @@ export async function main(ns) { this to gauge how well your scripts are doing.

    - Click home to see the scripts running on it. + Click home to see the scripts running on it.

    - Then click ${tutorialScriptName} to see the script's information. + Then click {tutorialScriptName} to see the script's information.

    Let's go back to the{" "} - - Terminal + + Terminal @@ -462,7 +463,7 @@ export async function main(ns) {

    - {`[home /]> tail ${tutorialScriptName}`} + {`[home /]> tail ${tutorialScriptName}`} ), canNext: false, @@ -486,11 +487,11 @@ export async function main(ns) { servers too.

    - Before we do that, let's see what's currently on our home computer using + Before we do that, let's see what files are stored on our home computer using

    - {"[home /]> ls"} + {"[home /]> ls"}
    ("ls" is short for "list".) @@ -503,26 +504,32 @@ export async function main(ns) { content: ( <> - That's shown all the files on your home computer. Right now, you can see the NUKE.exe program that you used - earlier, and {tutorialScriptName}. + That's shown you all the files on your home computer. Right now, you can see NUKE.exe, the program that you + used earlier, and {tutorialScriptName}.

    - NUKE.exe can only ever be on your home computer. But if you want other servers to run {tutorialScriptName}, - you need to copy it to them. + If you want other servers to run {tutorialScriptName}, you need to copy it to them. (NUKE.exe can't be copied + elsewhere. It's only stored on home.)

    To do that, we use

    - {"[home /]> scp file destination"} + {"[home /]> scp file destination"}
    To copy {tutorialScriptName} to n00dles, enter

    - {`[home /]> scp ${tutorialScriptName} n00dles`} + {`[home /]> scp ${tutorialScriptName} n00dles`} + +
    + You can then connect to n00dles and run your script on it later. +
    +
    +
    ), canNext: false, @@ -535,7 +542,7 @@ export async function main(ns) {

    - {"[home /]> help"} + {"[home /]> help"} ), canNext: false, @@ -544,10 +551,10 @@ export async function main(ns) { content: ( <> - Now we've made some money and exp, let's head to the Stats tab and see our gains. Click{" "} + Now we've made some money and exp, let's head to the Stats tab and see what we've gained. Click{" "} - - Stats + {" "} + Stats {" "} at the left-hand side of the screen. @@ -560,8 +567,8 @@ export async function main(ns) { <> - - Stats + {" "} + Stats {" "} shows information about your skills, money, and bonuses. @@ -576,8 +583,8 @@ export async function main(ns) { Hacking isn't the only way to earn money. One other way to passively earn money is to purchase and upgrade Hacknet Nodes. Let's go to{" "} - - Hacknet + {" "} + Hacknet {" "} . @@ -603,8 +610,8 @@ export async function main(ns) {
    Let's go to{" "} - - City + {" "} + City {" "} . @@ -622,8 +629,8 @@ export async function main(ns) {
    Lastly, click on{" "} - - Documentation + {" "} + Documentation {" "} . @@ -641,8 +648,9 @@ export async function main(ns) { If you look at nothing else, the three pages I'd recommend are:
    • - the Beginner's guide, which contains - an invaluable basic hacking script, and which helps you navigate through most of the early game + the Beginner's guide, which gives + you an invaluable basic hacking script, and which helps you navigate through most of the + early game
    • the NS API documentation, which contains @@ -667,6 +675,7 @@ export async function main(ns) { .
      +
      The documentation at readthedocs is outdated and unmaintained. Do not use it! diff --git a/src/ui/MD/code.tsx b/src/ui/MD/code.tsx index 93aa640c0d..04abad5aff 100644 --- a/src/ui/MD/code.tsx +++ b/src/ui/MD/code.tsx @@ -6,7 +6,7 @@ import { CodeProps } from "react-markdown/lib/ast-to-react"; import { Typography } from "@mui/material"; import { makeStyles } from "tss-react/mui"; -const useStyles = makeStyles()((theme: Theme) => ({ +export const useStyles = makeStyles()((theme: Theme) => ({ pre: { borderRadius: "6px", }, @@ -36,7 +36,11 @@ const InlineCode = (props: React.PropsWithChildren): React.ReactEleme ); -const BigCode = (props: React.PropsWithChildren): React.ReactElement => ( +type CodeBlockProps = { + children: string; +}; + +export const CodeBlock = ( {children}: CodeBlockProps): React.ReactElement => ( ): React.ReactElement borderRadius: "6px", }} > - {String(props.children)} + {children} ); export const code = (props: React.PropsWithChildren): React.ReactElement => - props.inline ? : ; + props.inline ? : {String(props.children)}; \ No newline at end of file From 374150e6f4782b43ffe4ac516ebea6fcc57f76f6 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Wed, 26 Aug 2026 16:04:19 +0100 Subject: [PATCH 05/82] better --- .../doc/en/help/getting_started.md | 6 +- src/InteractiveTutorial.ts | 6 +- src/Sidebar/ui/SidebarAccordion.tsx | 6 +- src/Sidebar/ui/SidebarItem.tsx | 14 +- src/Sidebar/ui/SidebarRoot.tsx | 10 +- src/Terminal/Terminal.ts | 31 +++-- .../InteractiveTutorialRoot.tsx | 122 ++++++++++-------- src/ui/MD/code.tsx | 4 +- 8 files changed, 114 insertions(+), 85 deletions(-) diff --git a/src/Documentation/doc/en/help/getting_started.md b/src/Documentation/doc/en/help/getting_started.md index 503c7df065..2a2a94894f 100644 --- a/src/Documentation/doc/en/help/getting_started.md +++ b/src/Documentation/doc/en/help/getting_started.md @@ -19,11 +19,11 @@ Since this guide is written as a basic introduction to Bitburner, it will not ex ## First Steps I'm going to assume you followed the introductory tutorial when you first began the game. -In this introductory tutorial, you created a [Script](../basic/scripts.md) called `n00dles.js` and ran it on the `n00dles` server. +In this introductory tutorial, you created a [Script](../basic/scripts.md) called `hacking.js` and ran it on the `home` server. Now, we'll kill this [Script](../basic/scripts.md). There are two ways to do this: -- You can go to the Terminal and enter: `kill n00dles.js` -- You can go to the `Active Scripts` page (Alt + s) and press the `Kill Script` button for `n00dles.js`. +- You can go to the Terminal and enter: `kill hacking.js` +- You can go to the `Active Scripts` page (Alt + s) and press the `Kill Script` button for `hacking.js`. If you skipped the introductory tutorial, then ignore the part above. Instead, go to the `Hacknet Nodes` page (Alt + h) and purchase a [Hacknet Node](../basic/hacknet_nodes.md) to start generating some passive income. diff --git a/src/InteractiveTutorial.ts b/src/InteractiveTutorial.ts index 7c071e7971..881ef73968 100644 --- a/src/InteractiveTutorial.ts +++ b/src/InteractiveTutorial.ts @@ -1,6 +1,4 @@ //// Still to do: -// n00dles.js references in docs -// Red to blue for stuff // Somewhere ??? the text that says 'Processes cannot be killed during the tutorial' ... when you clearly can! // Rebase to get rid of the irrelevant commits! @@ -23,6 +21,7 @@ enum iTutorialSteps { TerminalNuke, // NUKE n00dles TerminalManualHack, // Hack n00dles TerminalHackingMechanics, // Explanation of hacking mechanics + TerminalWeakenGrowMechanics, // Explanation of grow/weaken mechanics TerminalGoHome, // Go home before creating a script. TerminalCreateScript, // Create a script using 'nano' TerminalEditScript, // Script Editor page - Edit script and then save & close @@ -33,7 +32,7 @@ enum iTutorialSteps { ActiveScriptsToTerminal, TerminalTailScript, TerminalLs, // Using 'ls' Terminal command - TerminalScp, + TerminalScp, // using the 'scp' Terminal command TerminalHelp, // Using 'help' Terminal command // See the results of our hacking @@ -70,6 +69,7 @@ const ITutorial = { [iTutorialSteps.TerminalNuke]: false, [iTutorialSteps.TerminalManualHack]: false, [iTutorialSteps.TerminalHackingMechanics]: false, + [iTutorialSteps.TerminalWeakenGrowMechanics]: false, [iTutorialSteps.TerminalGoHome]: false, [iTutorialSteps.TerminalCreateScript]: false, [iTutorialSteps.TerminalEditScript]: false, diff --git a/src/Sidebar/ui/SidebarAccordion.tsx b/src/Sidebar/ui/SidebarAccordion.tsx index 5e72deba4d..3ec9db7ada 100644 --- a/src/Sidebar/ui/SidebarAccordion.tsx +++ b/src/Sidebar/ui/SidebarAccordion.tsx @@ -20,7 +20,7 @@ type SidebarAccordionProps = { items: (IItemProps | boolean)[]; icon: React.ReactElement["type"]; sidebarOpen: boolean; - classes: Record<"listitem" | "active" | "themeColorPrimary" | "themeColorSecondary" | "themeColorInfo" | "themeColorError", string>; + classes: Record<"listitem" | "active" | "themeColorPrimary" | "themeColorSecondary" | "themeColorInfo", string>; }; type ClickFnCacheKeyType = (page: Page) => void; @@ -69,11 +69,11 @@ export function SidebarAccordion({ setOpen((open) => !open)}> - + {key_}} /> - {open ? : } + {open ? : } ), [li_classes, sidebarOpen, key_, open, Icon], diff --git a/src/Sidebar/ui/SidebarItem.tsx b/src/Sidebar/ui/SidebarItem.tsx index 1e90115dba..496c1c5936 100644 --- a/src/Sidebar/ui/SidebarItem.tsx +++ b/src/Sidebar/ui/SidebarItem.tsx @@ -19,12 +19,16 @@ export interface ICreateProps { export interface SidebarItemProps extends ICreateProps { clickFn: () => void; flash: boolean; - classes: Record<"listitem" | "active" | "themeColorPrimary" | "themeColorSecondary" | "themeColorInfo" | "themeColorError", string>; + classes: Record<"listitem" | "active" | "themeColorPrimary" | "themeColorSecondary" | "themeColorInfo", string>; sidebarOpen: boolean; } export const SidebarItem = memo(function SidebarItem(props: SidebarItemProps): React.ReactElement { - const color = props.flash ? props.classes.themeColorInfo : props.active ? props.classes.themeColorPrimary : props.classes.themeColorSecondary; + const colorClass = props.flash + ? props.classes.themeColorInfo + : props.active + ? props.classes.themeColorPrimary + : props.classes.themeColorSecondary; return ( - 0 ? props.count : undefined} sx={{ color: props.classes.themeColorError }}> + 0 ? props.count : undefined} color="error"> - + - {props.key_} + {props.key_} ); diff --git a/src/Sidebar/ui/SidebarRoot.tsx b/src/Sidebar/ui/SidebarRoot.tsx index ba2127828f..db0d8a36bf 100644 --- a/src/Sidebar/ui/SidebarRoot.tsx +++ b/src/Sidebar/ui/SidebarRoot.tsx @@ -119,11 +119,15 @@ const useStyles = makeStyles()((theme: Theme) => ({ active: { borderLeft: "3px solid " + theme.palette.primary.main, }, - listitem: {}, + listitem: {}, + // To explain why I did this daft shit: Lots of elements here are setting their colour using color="error" or similar. + // The problem is that Typography doesn't have the same list of possible colours as other items. In particular, it's missing + // "info". Do We're currently on the{" "} - {" "} - Terminal + + Terminal {" "} tab.

      You can use the{" "} - {" "} - Terminal + + Terminal {" "} to interface with your home computer, as well as with other machines around the world.
      @@ -162,12 +162,12 @@ export function InteractiveTutorialRoot(): React.ReactElement { <> In the year 2077, currency is digital and decentralized. People and corporations store their money on - servers and computers. Using hacking skills and malware, you can hack servers to steal money and gain + servers and computers. Using specialised your skills, you can hack servers to steal money and gain experience.

      - If you check the read-out of scan-analyze you can see that n00dles has a required hacking skill of only 1. - That means you can hack it right now. + If you check the read-out of scan-analyze in the Terminal you can see that n00dles has a required hacking + skill of only 1. That means you can hack it right now.

      To do that, we need to connect to it. You can connect to a machine that is one node away using @@ -210,16 +210,16 @@ export function InteractiveTutorialRoot(): React.ReactElement { {"[n00dles /]> analyze"}
      - finishes running, it'll display some useful diagnostic data. + finishes running, it displays some useful diagnostic data.

      - In the data, you can see the server's root access status. To hack a server you must gain root access first. - Handily, you've come prepared with a virus called NUKE.exe. NUKE.exe will grant you root access to a machine - as long as there are enough open ports. + If you have a look, you can see the server's root access status. To hack a server, you must gain root access + first. Handily, you've come prepared with a virus called NUKE.exe. NUKE.exe will grant you root access to a + machine as long as there are enough open ports.

      - If you look at the diagnostics again, you'll also see that n00dles' required number of open ports for NUKE - is 0. So you're good to go ahead and run the virus! Just enter + If you look at the diagnostics again, you'll see that n00dles' "Required number of open ports for NUKE" is + 0. So you're good to go ahead and run the virus! Just enter

      @@ -249,17 +249,26 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - You're now attempting to hack the server. Performing a hack takes time, and has a certain success chance. - Both the hack time and success chance are affected by your hacking skill, and by the server's security - level. + You're now attempting to hack the server. Hacking takes time, and has a success chance. If your hack is + successful, you'll steal a percentage of the server's available money.

      - If your attempt to hack the server is successful, you'll steal a percentage of the server's available money. - (Again, this percentage is affected by your hacking skill and the server's security level). -
      -
      - When you hack a server, you deplete the money it has available, so your following hacks take less money. You - also cause its security level to rise, so your hacks take longer. + All of those variables (hacking time, success chance, and the percentage stolen) are affected by: +
        +
      • your hacking skill
      • +
      • the server's security level
      • +
      +
      + + ), + canNext: true, + }, + [iTutorialSteps.TerminalWeakenGrowMechanics as number]: { + content: ( + <> + + When you hack a server, you deplete the money it has available, so any following hacks take less money. You + also cause its security level to rise, so your hacks take longer.

      To restore things, you can use @@ -286,8 +295,8 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - Hacking is the core mechanic of the game and is necessary for progression. So you don't want to - be hacking manually the entire time. What we need is a way to automate it. + Hacking is the core mechanic of the game and is necessary for progression. So you don't want to be hacking + manually the entire time. What we need is a way to automate it.

      So let's head home and create our first script. @@ -314,7 +323,10 @@ export function InteractiveTutorialRoot(): React.ReactElement { {"[home /]> nano file"}
      - Script names must end with a script extension (.js, .ts, .jsx, .tsx). Let's create a script now by entering + Script names must end with a script extension (.js, .jsx, .ts, .tsx). +
      +
      + Let's create a script now by entering

      @@ -347,13 +359,12 @@ export async function main(ns) {

      - If you have a look at the code of the script, you might be able to see that it hacks n00dles while true is - true – which it always is! So this script hacks n00dles on a loop forever. + Have a look at the code of the script. It says to hack n00dles while true is true – which it always is! So + this script hacks n00dles on a loop forever.

      - When we were hacking manually, we needed to be connected to our target. With scripts, however, we can target - any server on the network{" "} - from{" "}any target on the network. + One benefit of using scripts to hack is that you don't need to be connected to the server you're hacking. + You can target any server on the network from any server on the network.

      While we're in the editor, it's worth saying that everything we do in this tutorial can be scripted. You can @@ -361,8 +372,8 @@ export async function main(ns) { ns.getServer().

      - If you ever want to check which functions are available to you, you can do that in the editor. Either search - using the search bar tool at the bottom of the editor, or click the{" "} + If you ever want to check which functions are available to you in the edior, you can search using the search + bar at the bottom, or click the{" "} NS API documentation link beside it.

      @@ -395,11 +406,11 @@ export async function main(ns) { content: ( <> - We have 8GB of free RAM. If that doesn't sound like much, don't worry: you can purchase more RAM - for your home server. + We have 8GB of free RAM. If that doesn't sound like much, don't worry: you can purchase more RAM for your + home server later.

      - For now though, let's run our script using + For now, let's run our script using

      @@ -422,8 +433,8 @@ export async function main(ns) {
      Let's check out some statistics for our running scripts by clicking{" "} - {" "} - Active Scripts + + Active Scripts
      @@ -447,7 +458,7 @@ export async function main(ns) { Let's go back to the{" "} - Terminal + Terminal
      @@ -508,8 +519,8 @@ export async function main(ns) { used earlier, and {tutorialScriptName}.

      - If you want other servers to run {tutorialScriptName}, you need to copy it to them. (NUKE.exe can't be copied - elsewhere. It's only stored on home.) + If you want other servers to run {tutorialScriptName}, you need to copy it to them. (NUKE.exe can't be + copied elsewhere. It's only stored on home.)

      To do that, we use @@ -553,8 +564,8 @@ export async function main(ns) { Now we've made some money and exp, let's head to the Stats tab and see what we've gained. Click{" "} - {" "} - Stats + + Stats {" "} at the left-hand side of the screen. @@ -567,8 +578,8 @@ export async function main(ns) { <> - {" "} - Stats + + Stats {" "} shows information about your skills, money, and bonuses. @@ -583,8 +594,8 @@ export async function main(ns) { Hacking isn't the only way to earn money. One other way to passively earn money is to purchase and upgrade Hacknet Nodes. Let's go to{" "} - {" "} - Hacknet + + Hacknet {" "} .
      @@ -610,10 +621,9 @@ export async function main(ns) {
      Let's go to{" "} - {" "} - City + + City {" "} - . ), @@ -629,8 +639,8 @@ export async function main(ns) {
      Lastly, click on{" "} - {" "} - Documentation + + Documentation {" "} . @@ -648,7 +658,7 @@ export async function main(ns) { If you look at nothing else, the three pages I'd recommend are:
      • - the Beginner's guide, which gives + the Beginner's guide, which gives you an invaluable basic hacking script, and which helps you navigate through most of the early game
      • @@ -661,14 +671,14 @@ export async function main(ns) { beginners
      - You'll notice that some of the pages are inaccessible right now. Don't worry – you'll unlock them later on. + You'll notice that some of the pages are inaccessible right now. You'll unlock those later on.

      If you want to open one of the Documentaion page links in a new tab, click it while holding Ctrl (Control on a Mac keyboard). If you're playing the Steam version, doing that will open the link in your default browser.

      - While the documentation page is the best place to get information, especially when you get stuck, if you can't + While the documentation page is the best place to get information, especially when you're stuck, if you can't find the answer here then please{" "} ask us on Discord diff --git a/src/ui/MD/code.tsx b/src/ui/MD/code.tsx index 04abad5aff..f78cc7bf60 100644 --- a/src/ui/MD/code.tsx +++ b/src/ui/MD/code.tsx @@ -40,7 +40,7 @@ type CodeBlockProps = { children: string; }; -export const CodeBlock = ( {children}: CodeBlockProps): React.ReactElement => ( +const BigCode = ({ children }: CodeBlockProps): React.ReactElement => ( ( ); export const code = (props: React.PropsWithChildren): React.ReactElement => - props.inline ? : {String(props.children)}; \ No newline at end of file + props.inline ? : {String(props.children)}; From dc74aa7e71a343a7280b1d22ea3e99b804647deb Mon Sep 17 00:00:00 2001 From: branchtheory Date: Wed, 26 Aug 2026 16:25:49 +0100 Subject: [PATCH 06/82] ok first draft ish --- .../InteractiveTutorialRoot.tsx | 16 +++++++--------- src/ui/React/CopyableText.tsx | 3 ++- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 6bff9296d8..c5c2a17a50 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -3,6 +3,7 @@ import React, { useEffect } from "react"; import { Paper, Box, Typography, Button, Link } from "@mui/material"; import { ITutorialEvents } from "./ITutorialEvents"; import { CopyableText } from "../React/CopyableText"; +import { useStyles as codeBlockStyles } from "../MD/code"; import EqualizerIcon from "@mui/icons-material/Equalizer"; import LastPageIcon from "@mui/icons-material/LastPage"; @@ -11,7 +12,6 @@ import AccountTreeIcon from "@mui/icons-material/AccountTree"; import StorageIcon from "@mui/icons-material/Storage"; import LocationCityIcon from "@mui/icons-material/LocationCity"; import { useTheme, styled } from "@mui/material/styles"; -import { useStyles as codeBlockStyles } from "../MD/code"; import { iTutorialPrevStep, @@ -34,7 +34,7 @@ export const tutorialScriptName = `hacking.js`; export function InteractiveTutorialRoot(): React.ReactElement { const theme = useTheme(); - const { classes } = codeBlockStyles(); + const { classes: codeClasses } = codeBlockStyles(); const TerminalText = styled(Typography)(({ theme }) => ({ borderBottom: `1px solid ${theme.palette.primary.main}`, })); @@ -345,18 +345,16 @@ export function InteractiveTutorialRoot(): React.ReactElement { Below is a basic script that hacks n00dles. Copy and paste it into the editor.
      - - { - - } - + /> +

      Have a look at the code of the script. It says to hack n00dles while true is true – which it always is! So diff --git a/src/ui/React/CopyableText.tsx b/src/ui/React/CopyableText.tsx index ee583d46fa..eec89391fa 100644 --- a/src/ui/React/CopyableText.tsx +++ b/src/ui/React/CopyableText.tsx @@ -5,6 +5,7 @@ import Tooltip from "@mui/material/Tooltip"; interface IProps { value: string; color?: string; + className?: string; variant?: | "button" | "caption" @@ -40,7 +41,7 @@ export function CopyableText(props: IProps): React.ReactElement { return ( Copied!}> - + {props.value} From f05499635fb8dc055a29e08d41787f0ac68c13eb Mon Sep 17 00:00:00 2001 From: branchtheory Date: Wed, 26 Aug 2026 17:36:29 +0100 Subject: [PATCH 07/82] more --- src/Sidebar/ui/SidebarRoot.tsx | 2 +- src/Terminal/Terminal.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Sidebar/ui/SidebarRoot.tsx b/src/Sidebar/ui/SidebarRoot.tsx index db0d8a36bf..f281dc109c 100644 --- a/src/Sidebar/ui/SidebarRoot.tsx +++ b/src/Sidebar/ui/SidebarRoot.tsx @@ -335,7 +335,7 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement { () => ( - + Date: Wed, 26 Aug 2026 23:53:51 +0100 Subject: [PATCH 08/82] less bad --- src/InteractiveTutorial.ts | 7 +- src/ui/CharacterStats.tsx | 11 -- .../InteractiveTutorialRoot.tsx | 116 ++++++++---------- 3 files changed, 54 insertions(+), 80 deletions(-) diff --git a/src/InteractiveTutorial.ts b/src/InteractiveTutorial.ts index 881ef73968..864700a3fe 100644 --- a/src/InteractiveTutorial.ts +++ b/src/InteractiveTutorial.ts @@ -1,6 +1,11 @@ //// Still to do: // Somewhere ??? the text that says 'Processes cannot be killed during the tutorial' ... when you clearly can! -// Rebase to get rid of the irrelevant commits! +// You can't "Previous" if you're on the Stats page. It keeps pushing you forward. +// Note down changes that are part of something different, and reverse them +// Full stops +// Theming +// Code block component +// CL's other points import { Player } from "@player"; import { LiteratureName } from "@enums"; diff --git a/src/ui/CharacterStats.tsx b/src/ui/CharacterStats.tsx index 565dfc54a1..53d6e9bd0d 100644 --- a/src/ui/CharacterStats.tsx +++ b/src/ui/CharacterStats.tsx @@ -4,7 +4,6 @@ import React, { useState } from "react"; import { BitNodes } from "../BitNode/BitNode"; import { currentNodeMults } from "../BitNode/BitNodeMultipliers"; import { BitNodeMultipliersDisplay } from "../BitNode/ui/BitnodeMultipliersDescription"; -import { iTutorialSteps, iTutorialNextStep, ITutorial } from "../InteractiveTutorial"; import { HacknetServerConstants } from "../Hacknet/data/Constants"; import { getCloudServerLimit } from "../Server/ServerPurchases"; import { Settings } from "../Settings/Settings"; @@ -223,16 +222,6 @@ function MoneyModal({ open, onClose }: IMoneyModalProps): React.ReactElement { } export function CharacterStats(): React.ReactElement { - /* INTERACTIVE TUTORIAL */ - if (ITutorial.isRunning) { - if (ITutorial.currStep === iTutorialSteps.CharacterPage) { - iTutorialNextStep(); - } else { - //return -1; ?? not sure how to handle this - } - } - /* END INTERACTIVE TUTORIAL */ - const [moneyOpen, setMoneyOpen] = useState(false); const [employersOpen, setEmployersOpen] = useState(false); useCycleRerender(); diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index c5c2a17a50..415df1ad20 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -6,6 +6,7 @@ import { CopyableText } from "../React/CopyableText"; import { useStyles as codeBlockStyles } from "../MD/code"; import EqualizerIcon from "@mui/icons-material/Equalizer"; +import SettingsIcon from "@mui/icons-material/Settings"; import LastPageIcon from "@mui/icons-material/LastPage"; import HelpIcon from "@mui/icons-material/Help"; import AccountTreeIcon from "@mui/icons-material/AccountTree"; @@ -52,11 +53,15 @@ export function InteractiveTutorialRoot(): React.ReactElement { This tutorial will show you the basics of the game.

      - If you need to hide this tutorial panel temporarily, you can collapse it. + If you need to hide the tutorial panel temporarily, you can collapse it.

      - You can also exit the tutorial at any time. If you ever want to review it, go to the Options tab and select - Repeat Tutorial. + You can also exit the tutorial at any time. If you ever want to review it, go to the{" "} + + + Options + {" "} + tab and select Repeat Tutorial.
      ), @@ -68,7 +73,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { We're currently on the{" "} - + Terminal {" "} tab. @@ -76,10 +81,10 @@ export function InteractiveTutorialRoot(): React.ReactElement {
      You can use the{" "} - + Terminal {" "} - to interface with your home computer, as well as with other machines around the world. + to interface with your home computer, and with other machines around the world.
      ), @@ -113,8 +118,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { {"[home /]> scan"}
      - shows all servers that you can connect to from your current machine. Servers are identified by their - hostname. + shows all servers that you can connect to from your current machine.

      The network's much bigger than these nearby servers though. To start exploring it, let's enter @@ -214,8 +218,11 @@ export function InteractiveTutorialRoot(): React.ReactElement {

      If you have a look, you can see the server's root access status. To hack a server, you must gain root access - first. Handily, you've come prepared with a virus called NUKE.exe. NUKE.exe will grant you root access to a - machine as long as there are enough open ports. + first. +
      +
      + Handily, you've come prepared with a virus called NUKE.exe. NUKE.exe will grant you root access to a machine + as long as there are enough open ports.

      If you look at the diagnostics again, you'll see that n00dles' "Required number of open ports for NUKE" is @@ -339,10 +346,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - This is the script editor. -
      -
      - Below is a basic script that hacks n00dles. Copy and paste it into the editor. + Below is a basic script that hacks n00dles on a continuous loop. Copy and paste it into the editor.


      - Have a look at the code of the script. It says to hack n00dles while true is true – which it always is! So - this script hacks n00dles on a loop forever. -
      -
      One benefit of using scripts to hack is that you don't need to be connected to the server you're hacking. - You can target any server on the network from any server on the network. + You can target any server on the network from any server on the network.

      While we're in the editor, it's worth saying that everything we do in this tutorial can be scripted. You can @@ -370,9 +370,9 @@ export async function main(ns) { ns.getServer().

      - If you ever want to check which functions are available to you in the edior, you can search using the search - bar at the bottom, or click the{" "} - NS API documentation link beside it. + If you want to check which functions are available to you in the editor, use the search bar at the bottom, + or click the NS API documentation link beside + it.

      OK, back to hacking. Click Save at the bottom to save your script and close the editor. @@ -388,10 +388,7 @@ export async function main(ns) { Now we'll run the script. You can run scripts on any server that you have root access to.

      - Scripts need RAM to run, and different servers have different amounts. -
      -
      - To check how much RAM is available on this machine, enter + Scripts need RAM to run. To check how much RAM is available on this machine, enter

      @@ -421,17 +418,17 @@ export async function main(ns) { content: ( <> - Your script is now running! Scripts run in the background until their code completes (although - {tutorialScriptName} will never complete because it has an infinite loop). + Your script is now running! Scripts run in the background until their code completes ({tutorialScriptName}{" "} + will never complete because it has an infinite loop).

      - Scripts can passively earn you income and hacking experience. They'll keep earning even while you're - offline, although at a slower rate. + Scripts will passively earn you income and hacking experience. They even keep earning while you're offline, + although at a slower rate.

      - Let's check out some statistics for our running scripts by clicking{" "} + Let's check out some statistics of our running scripts by clicking{" "} - + Active Scripts
      @@ -443,8 +440,8 @@ export async function main(ns) { content: ( <> - This page displays information about all of your scripts that are running across every server. You can use - this to gauge how well your scripts are doing. + This page shows every script you're running across every server. You can use it to gauge how well your + scripts are doing.

      Click home to see the scripts running on it. @@ -468,7 +465,7 @@ export async function main(ns) { <> Each active script has logs that detail what it's doing. You can check these logs using the tail command. To - do that for the script you just ran, you can enter + do that for the script you just ran, enter

      @@ -481,8 +478,7 @@ export async function main(ns) { content: ( <> - The log for this script may not show much right now because it just started running... but check back again - in a few minutes! + This log might not show much because the script just started... but check back again in a few minutes! ), @@ -492,8 +488,8 @@ export async function main(ns) { content: ( <> - We're not going to get very far running scripts on our home computer alone. We need to copy them to other - servers too. + We won't get far running scripts on just our home computer. We want to run them on other servers too, and + that means we need to copy them over.

      Before we do that, let's see what files are stored on our home computer using @@ -513,32 +509,18 @@ export async function main(ns) { content: ( <> - That's shown you all the files on your home computer. Right now, you can see NUKE.exe, the program that you - used earlier, and {tutorialScriptName}. -
      -
      - If you want other servers to run {tutorialScriptName}, you need to copy it to them. (NUKE.exe can't be - copied elsewhere. It's only stored on home.) -
      -
      - To do that, we use + To copy {tutorialScriptName} to another server, you can use

      {"[home /]> scp file destination"}
      - To copy {tutorialScriptName} to n00dles, enter + To copy it to n00dles, enter

      {`[home /]> scp ${tutorialScriptName} n00dles`} - -
      - You can then connect to n00dles and run your script on it later. -
      -
      -
      ), canNext: false, @@ -547,7 +529,7 @@ export async function main(ns) { content: ( <> - Lastly, if you can't remember the right terminal command, you can always use + Lastly, if you can't remember the right terminal command, you can always enter

      @@ -562,7 +544,7 @@ export async function main(ns) { Now we've made some money and exp, let's head to the Stats tab and see what we've gained. Click{" "} - + Stats {" "} at the left-hand side of the screen. @@ -576,7 +558,7 @@ export async function main(ns) { <> - + Stats {" "} shows information about your skills, money, and bonuses. @@ -589,13 +571,12 @@ export async function main(ns) { content: ( <> - Hacking isn't the only way to earn money. One other way to passively earn money is to purchase and upgrade - Hacknet Nodes. Let's go to{" "} + Hacking isn't the only way to earn money. One other way to passively earn money is to purchase Hacknet + Nodes. Let's go to{" "} - + Hacknet {" "} - . ), @@ -604,7 +585,7 @@ export async function main(ns) { [iTutorialSteps.HacknetNodesIntroduction as number]: { content: ( - Here you can purchase new Hacknet Nodes and upgrade your existing ones. Let's purchase a new one. + Here you can purchase new Hacknet Nodes and upgrade your existing ones. Let's purchase one. ), canNext: true, @@ -614,12 +595,12 @@ export async function main(ns) { <> Hacknet Nodes earn you money over time, both online and offline. When you get enough money, you can upgrade - your newly-purchased Hacknet Node below. + your Hacknet Node below.

      Let's go to{" "} - + City {" "}
      @@ -635,12 +616,11 @@ export async function main(ns) { There's a lot of content out in the world, so make sure you explore and discover!

      - Lastly, click on{" "} + Lastly, go to{" "} - + Documentation {" "} - .
      ), From fbe9b41c7a6c6f800bcdcdfcbf23037bcc1bfa66 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 00:00:34 +0100 Subject: [PATCH 09/82] less bad 2 --- .../InteractiveTutorialRoot.tsx | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 415df1ad20..40adedb61a 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -637,8 +637,7 @@ export async function main(ns) {
      • the Beginner's guide, which gives - you an invaluable basic hacking script, and which helps you navigate through most of the - early game + you an invaluable basic hacking script, and helps you with most of the early game
      • the NS API documentation, which contains @@ -656,12 +655,14 @@ export async function main(ns) { Mac keyboard). If you're playing the Steam version, doing that will open the link in your default browser.

        - While the documentation page is the best place to get information, especially when you're stuck, if you can't - find the answer here then please{" "} - - ask us on Discord - - . + + While the documentation is the best place to get help, if you can't + find the answer then please{" "} + + ask us on Discord + + . +

        From 4314c5d79300512df9bb9a4dfe73137f115aa97b Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 00:20:04 +0100 Subject: [PATCH 10/82] briefer --- .../InteractiveTutorialRoot.tsx | 35 +++++++------------ 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 40adedb61a..3c9cd4c51c 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -121,7 +121,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { shows all servers that you can connect to from your current machine.

        - The network's much bigger than these nearby servers though. To start exploring it, let's enter + The network's much bigger than that though. To start exploring it, let's enter

        @@ -137,7 +137,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { That's given us more detailed information about the servers we can connect to.

        - To look depeer into the network, we can change our scanning depth to 2. + To look depeer into the network, change your scanning depth to 2.

        @@ -150,11 +150,10 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - Now you can see information about all servers that are up to 2 nodes away. You can also see how to navigate - to those servers through the network. + Now you can see all servers that are up to 2 nodes away, and how to navigate to them.

        - That's great and all, but there are so many servers. Which one should we go to? Well, let's pick a target we + That's great and all, but there are so many servers. Which ones do we focus on? Well, let's pick a target we can hack!
        @@ -207,18 +206,8 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - When -
        -
        -
        - {"[n00dles /]> analyze"} - -
        - finishes running, it displays some useful diagnostic data. -
        -
        - If you have a look, you can see the server's root access status. To hack a server, you must gain root access - first. + If you have a look at the diagnostic data, you can see the server's root access status. To hack a server, + you must gain root access first.

        Handily, you've come prepared with a virus called NUKE.exe. NUKE.exe will grant you root access to a machine @@ -274,7 +263,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - When you hack a server, you deplete the money it has available, so any following hacks take less money. You + When you hack a server, you deplete the money it has available, so the following hacks take less money. You also cause its security level to rise, so your hacks take longer.

        @@ -464,7 +453,7 @@ export async function main(ns) { content: ( <> - Each active script has logs that detail what it's doing. You can check these logs using the tail command. To + Each active script has logs that detail what it's doing. You can check these using the tail command. To do that for the script you just ran, enter

        @@ -478,7 +467,7 @@ export async function main(ns) { content: ( <> - This log might not show much because the script just started... but check back again in a few minutes! + This log might not show much because the script has just started... but check back again in a few minutes! ), @@ -488,11 +477,11 @@ export async function main(ns) { content: ( <> - We won't get far running scripts on just our home computer. We want to run them on other servers too, and - that means we need to copy them over. + We won't get far running scripts on just our home computer. We can run them on other servers too, and + to do that, we need to copy them over.

        - Before we do that, let's see what files are stored on our home computer using + First though, let's see what files are stored on our home computer using

        From 82c8f5bf733506c88fe8cfc343675fd0ef27da3c Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 00:33:42 +0100 Subject: [PATCH 11/82] brie --- src/Sidebar/ui/SidebarRoot.tsx | 2 +- .../InteractiveTutorialRoot.tsx | 32 +++++++++---------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/Sidebar/ui/SidebarRoot.tsx b/src/Sidebar/ui/SidebarRoot.tsx index f281dc109c..e695572c38 100644 --- a/src/Sidebar/ui/SidebarRoot.tsx +++ b/src/Sidebar/ui/SidebarRoot.tsx @@ -335,7 +335,7 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement { () => ( - +
        - To look depeer into the network, change your scanning depth to 2. + To look depeer into the network, increase your scanning depth to 2.

        @@ -165,7 +165,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { <> In the year 2077, currency is digital and decentralized. People and corporations store their money on - servers and computers. Using specialised your skills, you can hack servers to steal money and gain + servers and computers. Using your specialised skills, you can hack servers to steal money and gain experience.

        @@ -173,7 +173,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { skill of only 1. That means you can hack it right now.

        - To do that, we need to connect to it. You can connect to a machine that is one node away using + To do that, you need to connect to it. You can connect to any machine that is one node away using

        @@ -206,12 +206,12 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - If you have a look at the diagnostic data, you can see the server's root access status. To hack a server, + If you have a look at the diagnostic data, you can see the server's root access status. To hack a server, you must gain root access first.

        - Handily, you've come prepared with a virus called NUKE.exe. NUKE.exe will grant you root access to a machine - as long as there are enough open ports. + Handily, you've come prepared with a virus called NUKE.exe. NUKE.exe will grant you root access to any + machine as long as it has enough open ports.

        If you look at the diagnostics again, you'll see that n00dles' "Required number of open ports for NUKE" is @@ -350,13 +350,12 @@ export async function main(ns) {

        - One benefit of using scripts to hack is that you don't need to be connected to the server you're hacking. - You can target any server on the network from any server on the network. + One benefit of using scripts to hack is that they don't need to be connected to the server they're hacking. + Scripts can target any server on the network.

        While we're in the editor, it's worth saying that everything we do in this tutorial can be scripted. You can - map the network with ns.scan(), run scripts with ns.run() or ns.exec(), and get server information with - ns.getServer(). + map the network with ns.scan(), run scripts with ns.run(), or get server information with ns.getServer().

        If you want to check which functions are available to you in the editor, use the search bar at the bottom, @@ -453,8 +452,8 @@ export async function main(ns) { content: ( <> - Each active script has logs that detail what it's doing. You can check these using the tail command. To - do that for the script you just ran, enter + Each active script has logs that detail what it's doing. You can check these using the tail command. To do + that for the script you just ran, enter

        @@ -467,7 +466,7 @@ export async function main(ns) { content: ( <> - This log might not show much because the script has just started... but check back again in a few minutes! + This log might not show much because the script just started... but check back again in a few minutes! ), @@ -477,8 +476,8 @@ export async function main(ns) { content: ( <> - We won't get far running scripts on just our home computer. We can run them on other servers too, and - to do that, we need to copy them over. + We won't get far running scripts on just our home computer. We can run them on other servers too, and to do + that, we need to copy them over.

        First though, let's see what files are stored on our home computer using @@ -645,8 +644,7 @@ export async function main(ns) {

        - While the documentation is the best place to get help, if you can't - find the answer then please{" "} + While the documentation is the best place to get help, if you can't find the answer then please{" "} ask us on Discord From 639b325143d1b01036b1d9707f34113c43ed97ee Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 01:41:57 +0100 Subject: [PATCH 12/82] bre --- src/InteractiveTutorial.ts | 3 +- src/Sidebar/ui/SidebarRoot.tsx | 2 +- .../InteractiveTutorialRoot.tsx | 38 +++++++++---------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/InteractiveTutorial.ts b/src/InteractiveTutorial.ts index 864700a3fe..5dcf333312 100644 --- a/src/InteractiveTutorial.ts +++ b/src/InteractiveTutorial.ts @@ -1,7 +1,6 @@ //// Still to do: // Somewhere ??? the text that says 'Processes cannot be killed during the tutorial' ... when you clearly can! -// You can't "Previous" if you're on the Stats page. It keeps pushing you forward. -// Note down changes that are part of something different, and reverse them +// Note down changes that are part of something different, and reverse them: // Full stops // Theming // Code block component diff --git a/src/Sidebar/ui/SidebarRoot.tsx b/src/Sidebar/ui/SidebarRoot.tsx index e695572c38..90ba90d205 100644 --- a/src/Sidebar/ui/SidebarRoot.tsx +++ b/src/Sidebar/ui/SidebarRoot.tsx @@ -121,7 +121,7 @@ const useStyles = makeStyles()((theme: Theme) => ({ }, listitem: {}, // To explain why I did this daft shit: Lots of elements here are setting their colour using color="error" or similar. - // The problem is that Typography doesn't have the same list of possible colours as other items. In particular, it's missing + // The problem is that Typography's default colour options are not the same as with other elements. In particular, it's missing // "info". Do scan"}
        - shows all servers that you can connect to from your current machine. + shows you every server you can connect to from your current machine.

        The network's much bigger than that though. To start exploring it, let's enter @@ -154,7 +154,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {

        That's great and all, but there are so many servers. Which ones do we focus on? Well, let's pick a target we - can hack! + can hack.
        ), @@ -169,11 +169,11 @@ export function InteractiveTutorialRoot(): React.ReactElement { experience.

        - If you check the read-out of scan-analyze in the Terminal you can see that n00dles has a required hacking - skill of only 1. That means you can hack it right now. + If you check the read-out of scan-analyze in the Terminal, you can see that n00dles has a required hacking + skill of 1. It's a great first target.

        - To do that, you need to connect to it. You can connect to any machine that is one node away using + To hack n00dles, you need to connect to it. You can connect to any machine that is one node away using

        @@ -193,7 +193,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - Before we try hacking, let's run some diagnostics using + To make sure we can hack n00dles, let's run some diagnostics using

        @@ -211,7 +211,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {

        Handily, you've come prepared with a virus called NUKE.exe. NUKE.exe will grant you root access to any - machine as long as it has enough open ports. + machine as long as enough ports are open.

        If you look at the diagnostics again, you'll see that n00dles' "Required number of open ports for NUKE" is @@ -249,7 +249,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { successful, you'll steal a percentage of the server's available money.

        - All of those variables (hacking time, success chance, and the percentage stolen) are affected by: + All of those variables (time, success chance, and percentage stolen) are affected by:
        • your hacking skill
        • the server's security level
        • @@ -292,7 +292,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { <> Hacking is the core mechanic of the game and is necessary for progression. So you don't want to be hacking - manually the entire time. What we need is a way to automate it. + manually the entire time. We need a way to automate it.

          So let's head home and create our first script. @@ -335,7 +335,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - Below is a basic script that hacks n00dles on a continuous loop. Copy and paste it into the editor. + Below is a script that hacks n00dles on a continuous loop. Copy and paste it into the editor.

          - Scripts will passively earn you income and hacking experience. They even keep earning while you're offline, + Scripts will passively earn you income and hacking experience. They also keep earning while you're offline, although at a slower rate.

          @@ -476,7 +476,7 @@ export async function main(ns) { content: ( <> - We won't get far running scripts on just our home computer. We can run them on other servers too, and to do + We won't get far running scripts on our home computer alone. We can run them on other servers too, but to do that, we need to copy them over.

          @@ -497,14 +497,14 @@ export async function main(ns) { content: ( <> - To copy {tutorialScriptName} to another server, you can use + To copy a script to another server, you can use

          {"[home /]> scp file destination"}
          - To copy it to n00dles, enter + To copy {tutorialScriptName} to n00dles, enter

          @@ -583,7 +583,7 @@ export async function main(ns) { <> Hacknet Nodes earn you money over time, both online and offline. When you get enough money, you can upgrade - your Hacknet Node below. + your Hacknet Nodes below.

          Let's go to{" "} @@ -600,8 +600,8 @@ export async function main(ns) { content: ( <> - This page lists all of the locations in your current city. Each location has something that you can do. - There's a lot of content out in the world, so make sure you explore and discover! + This maps all of the locations in your current city. Each location has something that you can do. There's a + lot of content out in the world, so make sure you explore and discover!

          Lastly, go to{" "} @@ -625,11 +625,11 @@ export async function main(ns) {
          • the Beginner's guide, which gives - you an invaluable basic hacking script, and helps you with most of the early game + you an invaluable basic hacking script, and helps with most of the early game
          • the NS API documentation, which contains - reference materials for all NS APIs + reference materials on functions you can use in scripts
          • the FAQ, which answers questions often asked by From 77acc69bad0d8b997e25129222366dcfea70410c Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 02:21:45 +0100 Subject: [PATCH 13/82] reverted nansense --- .../InteractiveTutorialRoot.tsx | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 8e6b6b8317..6008d664b1 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -3,7 +3,6 @@ import React, { useEffect } from "react"; import { Paper, Box, Typography, Button, Link } from "@mui/material"; import { ITutorialEvents } from "./ITutorialEvents"; import { CopyableText } from "../React/CopyableText"; -import { useStyles as codeBlockStyles } from "../MD/code"; import EqualizerIcon from "@mui/icons-material/Equalizer"; import SettingsIcon from "@mui/icons-material/Settings"; @@ -35,7 +34,6 @@ export const tutorialScriptName = `hacking.js`; export function InteractiveTutorialRoot(): React.ReactElement { const theme = useTheme(); - const { classes: codeClasses } = codeBlockStyles(); const TerminalText = styled(Typography)(({ theme }) => ({ borderBottom: `1px solid ${theme.palette.primary.main}`, })); @@ -170,10 +168,10 @@ export function InteractiveTutorialRoot(): React.ReactElement {

            If you check the read-out of scan-analyze in the Terminal, you can see that n00dles has a required hacking - skill of 1. It's a great first target. + skill of 1, which makes it a great first target.

            - To hack n00dles, you need to connect to it. You can connect to any machine that is one node away using + To hack n00dles, you need to connect to it. You can connect to any machine that is 1 node away using

            @@ -263,7 +261,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - When you hack a server, you deplete the money it has available, so the following hacks take less money. You + When you hack a server, you deplete the money it has available, so any subsequent hacks take less money. You'll also cause its security level to rise, so your hacks take longer.

            @@ -338,16 +336,18 @@ export function InteractiveTutorialRoot(): React.ReactElement { Below is a script that hacks n00dles on a continuous loop. Copy and paste it into the editor.

            - + { + -
            + /> + } +
            One benefit of using scripts to hack is that they don't need to be connected to the server they're hacking. @@ -358,8 +358,8 @@ export async function main(ns) { map the network with ns.scan(), run scripts with ns.run(), or get server information with ns.getServer().

            - If you want to check which functions are available to you in the editor, use the search bar at the bottom, - or click the NS API documentation link beside + If you want to check which functions are available, use the search bar at the bottom, or click the{" "} + NS API documentation{" "}link beside it.

            From 61fb619823da6b13bec9c7a423a392215fe271f2 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 02:36:28 +0100 Subject: [PATCH 14/82] zz --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 6008d664b1..33880e5bab 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -168,7 +168,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {

            If you check the read-out of scan-analyze in the Terminal, you can see that n00dles has a required hacking - skill of 1, which makes it a great first target. + skill of 1, making it a great first target.

            To hack n00dles, you need to connect to it. You can connect to any machine that is 1 node away using @@ -289,7 +289,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - Hacking is the core mechanic of the game and is necessary for progression. So you don't want to be hacking + Hacking is the core mechanic of the game and is necessary for progression. So you don't want to hack manually the entire time. We need a way to automate it.

            @@ -314,7 +314,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {

            - {"[home /]> nano file"} + {"[home /]> nano"}
            Script names must end with a script extension (.js, .jsx, .ts, .tsx). @@ -530,7 +530,7 @@ export async function main(ns) { content: ( <> - Now we've made some money and exp, let's head to the Stats tab and see what we've gained. Click{" "} + Now we've gained some money and exp, let look at it the Stats tab. Click{" "} Stats From 29cdb3c6099427ce0b28ff4332d70393b16a76a4 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 12:26:56 +0100 Subject: [PATCH 15/82] betterer --- src/InteractiveTutorial.ts | 8 +- src/Terminal/Terminal.ts | 14 +- .../InteractiveTutorialRoot.tsx | 170 +++++++----------- 3 files changed, 75 insertions(+), 117 deletions(-) diff --git a/src/InteractiveTutorial.ts b/src/InteractiveTutorial.ts index 5dcf333312..a9b1461759 100644 --- a/src/InteractiveTutorial.ts +++ b/src/InteractiveTutorial.ts @@ -5,6 +5,10 @@ // Theming // Code block component // CL's other points +/* This should be a tip in the documentation UI -- not in the tutorial + If you want to open one of the Documentaion page links in a new tab, click it while holding Ctrl (Control on a + Mac keyboard). If you're playing the Steam version, doing that will open the link in your default browser. + */ import { Player } from "@player"; import { LiteratureName } from "@enums"; @@ -19,13 +23,11 @@ enum iTutorialSteps { TerminalScan, // Using 'scan' Terminal command TerminalScanAnalyze1, // Using 'scan-analyze' Terminal command TerminalScanAnalyze2, // Using 'scan-analyze 3' Terminal command - TerminalConnectInterval, TerminalConnect, // Connecting to n00dles TerminalAnalyze, // Analyzing n00dles TerminalNuke, // NUKE n00dles TerminalManualHack, // Hack n00dles TerminalHackingMechanics, // Explanation of hacking mechanics - TerminalWeakenGrowMechanics, // Explanation of grow/weaken mechanics TerminalGoHome, // Go home before creating a script. TerminalCreateScript, // Create a script using 'nano' TerminalEditScript, // Script Editor page - Edit script and then save & close @@ -68,12 +70,10 @@ const ITutorial = { [iTutorialSteps.TerminalScanAnalyze1]: false, [iTutorialSteps.TerminalScanAnalyze2]: false, [iTutorialSteps.TerminalConnect]: false, - [iTutorialSteps.TerminalConnectInterval]: false, [iTutorialSteps.TerminalAnalyze]: false, [iTutorialSteps.TerminalNuke]: false, [iTutorialSteps.TerminalManualHack]: false, [iTutorialSteps.TerminalHackingMechanics]: false, - [iTutorialSteps.TerminalWeakenGrowMechanics]: false, [iTutorialSteps.TerminalGoHome]: false, [iTutorialSteps.TerminalCreateScript]: false, [iTutorialSteps.TerminalEditScript]: false, diff --git a/src/Terminal/Terminal.ts b/src/Terminal/Terminal.ts index 257565831d..3259591468 100644 --- a/src/Terminal/Terminal.ts +++ b/src/Terminal/Terminal.ts @@ -348,7 +348,7 @@ export class Terminal { throw new Error("Could not get n00dles server"); } const errorMessageForBadCommand = - "Wrong command! Try again, or if you'd like to skip the tutorial click Exit Tutorial"; + "Wrong command. Try again, or if you'd like to skip the tutorial click Exit Tutorial"; switch (ITutorial.currStep) { case iTutorialSteps.TerminalHelp: if (commandArray.length === 1 && commandArray[0] === "help") { @@ -401,7 +401,7 @@ export class Terminal { ) { iTutorialNextStep(); } else { - this.error("Wrong command! Try again!"); + this.error("Wrong command. Try again!"); return; } } else { @@ -442,12 +442,6 @@ export class Terminal { return; } break; - case iTutorialSteps.TerminalWeakenGrowMechanics: - if (commandArray.length !== 1 || !["grow", "weaken", "hack"].includes(commandArray[0] + "")) { - this.error(errorMessageForBadCommand); - return; - } - break; case iTutorialSteps.TerminalGoHome: if (commandArray.length === 1 && commandArray[0] === "home") { iTutorialNextStep(); @@ -461,7 +455,7 @@ export class Terminal { if (commandArray[0] === "nano" && commandArray[1] === tutorialScriptName) { iTutorialNextStep(); } else { - this.error("Wrong command! Try again!"); + this.error("Wrong command. Try again!"); return; } } else { @@ -501,7 +495,7 @@ export class Terminal { if (commandArray[0] === "scp" && commandArray[1] === tutorialScriptName && commandArray[2] === "n00dles") { iTutorialNextStep(); } else { - this.error("Wrong command! Try again!"); + this.error("Wrong command. Try again!"); return; } } else { diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 33880e5bab..0164c0c7e4 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -44,7 +44,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - Welcome to Bitburner, a cyberpunk-themed incremental RPG! The game takes place in a dark, dystopian + Welcome to Bitburner, a cyberpunk-themed incremental RPG. The game takes place in a dark, dystopian future... The year is 2077...

            @@ -54,7 +54,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { If you need to hide the tutorial panel temporarily, you can collapse it.

            - You can also exit the tutorial at any time. If you ever want to review it, go to the{" "} + You can exit the tutorial at any time. If you ever want to review it, go to the{" "} Options @@ -119,7 +119,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { shows you every server you can connect to from your current machine.

            - The network's much bigger than that though. To start exploring it, let's enter + The network's much bigger than that though! To start exploring it, enter

            @@ -135,7 +135,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { That's given us more detailed information about the servers we can connect to.

            - To look depeer into the network, increase your scanning depth to 2. + To look depeer into the network, let's increase the scanning depth to 2.

            @@ -144,41 +144,21 @@ export function InteractiveTutorialRoot(): React.ReactElement { ), canNext: false, }, - [iTutorialSteps.TerminalConnectInterval as number]: { - content: ( - <> - - Now you can see all servers that are up to 2 nodes away, and how to navigate to them. -
            -
            - That's great and all, but there are so many servers. Which ones do we focus on? Well, let's pick a target we - can hack. -
            - - ), - canNext: true, - }, [iTutorialSteps.TerminalConnect as number]: { content: ( <> - In the year 2077, currency is digital and decentralized. People and corporations store their money on - servers and computers. Using your specialised skills, you can hack servers to steal money and gain - experience. -
            -
            - If you check the read-out of scan-analyze in the Terminal, you can see that n00dles has a required hacking - skill of 1, making it a great first target. + Now you can see all the servers that are up to 2 nodes away, and the route to get to them.

            - To hack n00dles, you need to connect to it. You can connect to any machine that is 1 node away using + You can connect to any machine that is 1 node away using

            {"[home /]> connect hostname"}
            - So let's connect to n00dles. + Let's connect to n00dles.

            @@ -191,7 +171,15 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - To make sure we can hack n00dles, let's run some diagnostics using + In the year 2077, currency is digital and decentralized. People and corporations store their money on + servers and computers. Using specialised skills, you can hack servers to steal money and gain experience. +
            +
            + You've got the skills to hack n00dles – scan-analyze showed us that n00dles has a required hacking skill of + 1. +
            +
            + But there's something else we need to check. Let's run some diagnostics using

            @@ -204,16 +192,16 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - If you have a look at the diagnostic data, you can see the server's root access status. To hack a server, - you must gain root access first. + If you have a look, you can see the server's "Root Access" status. You must gain root access before you can + hack a server.

            - Handily, you've come prepared with a virus called NUKE.exe. NUKE.exe will grant you root access to any - machine as long as enough ports are open. + Handily, you've built a virus called NUKE.exe. NUKE.exe will grant you root access to any machine as long as + enough ports are open.

            - If you look at the diagnostics again, you'll see that n00dles' "Required number of open ports for NUKE" is - 0. So you're good to go ahead and run the virus! Just enter + If you check the diagnostics, you'll see that n00dles' "Required number of open ports for NUKE" is 0. So + you're good to run the virus! Just enter

            @@ -226,18 +214,14 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - You now have root access! You can hack the server using + Now you've got root access, you can hack the server! Try entering

            {"[n00dles /]> hack"} - -
            - Try doing that now. -
            ), - canNext: true, + canNext: false, }, [iTutorialSteps.TerminalHackingMechanics as number]: { content: ( @@ -247,22 +231,12 @@ export function InteractiveTutorialRoot(): React.ReactElement { successful, you'll steal a percentage of the server's available money.

            - All of those variables (time, success chance, and percentage stolen) are affected by: -
              -
            • your hacking skill
            • -
            • the server's security level
            • -
            -
            - - ), - canNext: true, - }, - [iTutorialSteps.TerminalWeakenGrowMechanics as number]: { - content: ( - <> - - When you hack a server, you deplete the money it has available, so any subsequent hacks take less money. You'll - also cause its security level to rise, so your hacks take longer. + All of those variables (time, success chance, and percentage stolen) are affected by your hacking skill, and + by the server's security level. +
            +
            + When you hack a server, you deplete the money it has available, so any subsequent hacks take less money. + You'll also cause its security level to rise, so your hacks take longer.

            To restore things, you can use @@ -289,11 +263,11 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - Hacking is the core mechanic of the game and is necessary for progression. So you don't want to hack - manually the entire time. We need a way to automate it. + Hacking is the core mechanic of the game and is necessary to progress. So you don't want to hack manually + the entire time. We need a way to automate it!

            - So let's head home and create our first script. + Let's head home and create our first script.

            You can get back home from any server using @@ -336,7 +310,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { Below is a script that hacks n00dles on a continuous loop. Copy and paste it into the editor.

            - + {
            - While we're in the editor, it's worth saying that everything we do in this tutorial can be scripted. You can - map the network with ns.scan(), run scripts with ns.run(), or get server information with ns.getServer(). -
            -
            - If you want to check which functions are available, use the search bar at the bottom, or click the{" "} - NS API documentation{" "}link beside + If you want to check what other functions you can use in the editor, use the search bar at the bottom, or + click the NS API documentation link beside it.

            - OK, back to hacking. Click Save at the bottom to save your script and close the editor. + Click Save at the bottom to save your script and close the editor.
            ), @@ -376,7 +346,7 @@ export async function main(ns) { Now we'll run the script. You can run scripts on any server that you have root access to.

            - Scripts need RAM to run. To check how much RAM is available on this machine, enter + Scripts need RAM to run. To check how much RAM is available on a machine, enter

            @@ -406,15 +376,15 @@ export async function main(ns) { content: ( <> - Your script is now running! Scripts run in the background until their code completes ({tutorialScriptName}{" "} - will never complete because it has an infinite loop). + Your script is now running! Scripts run in the background until their code completes (though if they have an + infinite loop, like {tutorialScriptName}, it never will).

            - Scripts will passively earn you income and hacking experience. They also keep earning while you're offline, - although at a slower rate. + Scripts will passively earn you income and hacking experience. They even earn money and exp while you're + offline, although at a slower rate.

            - Let's check out some statistics of our running scripts by clicking{" "} + Let's check how our running scripts are doing by clicking{" "} Active Scripts @@ -435,7 +405,7 @@ export async function main(ns) { Click home to see the scripts running on it.

            - Then click {tutorialScriptName} to see the script's information. + Then click {tutorialScriptName} to see some data about it.

            Let's go back to the{" "} @@ -452,8 +422,8 @@ export async function main(ns) { content: ( <> - Each active script has logs that detail what it's doing. You can check these using the tail command. To do - that for the script you just ran, enter + Each active script has logs that detail what it's doing. You can check these using the tail{" "} + command. To do that for the script you just ran, enter

            @@ -476,11 +446,11 @@ export async function main(ns) { content: ( <> - We won't get far running scripts on our home computer alone. We can run them on other servers too, but to do + We won't get far running scripts on our home computer alone. We can run them on other servers too. To do that, we need to copy them over.

            - First though, let's see what files are stored on our home computer using + First, let's see what files are stored on our home computer using

            @@ -497,14 +467,10 @@ export async function main(ns) { content: ( <> - To copy a script to another server, you can use + To copy a script to another server, we can use the scp command.

            -
            - {"[home /]> scp file destination"} - -
            - To copy {tutorialScriptName} to n00dles, enter + Let's copy {tutorialScriptName} to n00dles.

            @@ -559,8 +525,7 @@ export async function main(ns) { content: ( <> - Hacking isn't the only way to earn money. One other way to passively earn money is to purchase Hacknet - Nodes. Let's go to{" "} + Hacking isn't the only way to earn money. One other way to is to purchase Hacknet Nodes. Let's go to{" "} Hacknet @@ -582,8 +547,8 @@ export async function main(ns) { content: ( <> - Hacknet Nodes earn you money over time, both online and offline. When you get enough money, you can upgrade - your Hacknet Nodes below. + Hacknet Nodes passively earn you money over time, even when you're offline. When you get enough money, you + can upgrade your Hacknet Nodes below.

            Let's go to{" "} @@ -600,7 +565,7 @@ export async function main(ns) { content: ( <> - This maps all of the locations in your current city. Each location has something that you can do. There's a + This shows all the locations in your current city. Each location has something that you can do. There's a lot of content out in the world, so make sure you explore and discover!

            @@ -617,26 +582,26 @@ export async function main(ns) { [iTutorialSteps.DocumentationPageInfo as number]: { content: ( - The pages in the Documentation tab explain the game's content and mechanics. I know it looks a lot, but I - highly suggest you read (or at least skim) through this before you start playing. + These pages explain the game's content and mechanics. I know it's a lot, but I highly suggest you read (or at + least skim) through this before you start playing.

            - If you look at nothing else, the three pages I'd recommend are: + These pages are especially helpful:
            • - the Beginner's guide, which gives - you an invaluable basic hacking script, and helps with most of the early game + The Beginner's guide gives you an{" "} + invaluable basic hacking script, and helps with most of the early game.
            • - the NS API documentation, which contains - reference materials on functions you can use in scripts + The NS API documentation contains reference + materials on functions you can use in scripts.
            • - the FAQ, which answers questions often asked by - beginners + The FAQ answers questions often asked by + beginners.
            - You'll notice that some of the pages are inaccessible right now. You'll unlock those later on. + You'll notice that some Documentation pages are inaccessible right now. You'll unlock those later on.

            If you want to open one of the Documentaion page links in a new tab, click it while holding Ctrl (Control on a @@ -644,16 +609,15 @@ export async function main(ns) {

            - While the documentation is the best place to get help, if you can't find the answer then please{" "} - + While the documentation is the first place to get help, if you can't find an answer then please{" "} + ask us on Discord .
            -
            - The documentation at readthedocs is outdated and unmaintained. Do not use it! + Note: The documentation at readthedocs is outdated and unmaintained. Do not use it!
            And that's the end of the tutorial. We hope you enjoy the game! From 583dc8b0459b940b73202329cf6a8240b2e149ea Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 12:38:02 +0100 Subject: [PATCH 16/82] . --- src/InteractiveTutorial.ts | 2 -- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 8 ++++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/InteractiveTutorial.ts b/src/InteractiveTutorial.ts index a9b1461759..9e8082127c 100644 --- a/src/InteractiveTutorial.ts +++ b/src/InteractiveTutorial.ts @@ -1,9 +1,7 @@ //// Still to do: // Somewhere ??? the text that says 'Processes cannot be killed during the tutorial' ... when you clearly can! -// Note down changes that are part of something different, and reverse them: // Full stops // Theming -// Code block component // CL's other points /* This should be a tip in the documentation UI -- not in the tutorial If you want to open one of the Documentaion page links in a new tab, click it while holding Ctrl (Control on a diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 0164c0c7e4..e82c47764c 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -54,7 +54,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { If you need to hide the tutorial panel temporarily, you can collapse it.

            - You can exit the tutorial at any time. If you ever want to review it, go to the{" "} + You can also exit the tutorial at any time. If you ever want to review it, go to the{" "} Options @@ -377,7 +377,7 @@ export async function main(ns) { <> Your script is now running! Scripts run in the background until their code completes (though if they have an - infinite loop, like {tutorialScriptName}, it never will). + infinite loop, like {tutorialScriptName} does, it never will).

            Scripts will passively earn you income and hacking experience. They even earn money and exp while you're @@ -512,8 +512,8 @@ export async function main(ns) { <> - - Stats + + Stats {" "} shows information about your skills, money, and bonuses. From be31a78cb32ae76f45def2906d0c955845d34004 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 12:40:52 +0100 Subject: [PATCH 17/82] ok second draft ish --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index e82c47764c..9dc9b5cb7f 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -610,7 +610,11 @@ export async function main(ns) {
            While the documentation is the first place to get help, if you can't find an answer then please{" "} - + ask us on Discord . From 90a6cd79f68a642962dbd23e968c2421e97d5d1f Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 12:59:48 +0100 Subject: [PATCH 18/82] run! --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 9dc9b5cb7f..b873b40749 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -205,7 +205,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {

            - {"[n00dles /]> NUKE.exe"} + {"[n00dles /]> run NUKE.exe"} ), canNext: false, @@ -367,7 +367,7 @@ export async function main(ns) {

            - {`[home /]> ${tutorialScriptName}`} + {`[home /]> run ${tutorialScriptName}`} ), canNext: false, @@ -593,8 +593,8 @@ export async function main(ns) { invaluable basic hacking script, and helps with most of the early game.
          • - The NS API documentation contains reference - materials on functions you can use in scripts. + The NS API documentation details the + functions you can use in scripts.
          • The FAQ answers questions often asked by From 3942c823685af1f81156906e91cc0e008a1eec8a Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 14:23:59 +0100 Subject: [PATCH 19/82] being more permissive --- src/Terminal/Terminal.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Terminal/Terminal.ts b/src/Terminal/Terminal.ts index 3259591468..88f10f18a9 100644 --- a/src/Terminal/Terminal.ts +++ b/src/Terminal/Terminal.ts @@ -451,7 +451,7 @@ export class Terminal { } break; case iTutorialSteps.TerminalCreateScript: - if (commandArray.length === 2) { + if (commandArray.length === 2 || commandArray[0] === "nano") { if (commandArray[0] === "nano" && commandArray[1] === tutorialScriptName) { iTutorialNextStep(); } else { @@ -474,7 +474,7 @@ export class Terminal { case iTutorialSteps.TerminalRunScript: if ( (commandArray.length === 2 && commandArray[0] === "run" && commandArray[1] === tutorialScriptName) || - commandArray[0] === tutorialScriptName + (commandArray.length === 1 && commandArray[0] === tutorialScriptName) ) { iTutorialNextStep(); } else { @@ -482,6 +482,18 @@ export class Terminal { return; } break; + case iTutorialSteps.TerminalGoToActiveScriptsPage: + if ( + !( + (commandArray.length === 1 && commandArray[0] === "free") || + (commandArray.length === 2 && commandArray[0] === "run" && commandArray[1] === tutorialScriptName) || + (commandArray.length === 1 && commandArray[0] === tutorialScriptName) + ) + ) { + this.error(errorMessageForBadCommand); + return; + } + break; case iTutorialSteps.ActiveScriptsToTerminal: if (commandArray.length === 2 && commandArray[0] === "tail" && commandArray[1] === tutorialScriptName) { iTutorialNextStep(); From 550f86f25d13d53ba4f8db1440485de521ddc61c Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 14:36:16 +0100 Subject: [PATCH 20/82] + --- src/Terminal/Terminal.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Terminal/Terminal.ts b/src/Terminal/Terminal.ts index 88f10f18a9..0d29f2152f 100644 --- a/src/Terminal/Terminal.ts +++ b/src/Terminal/Terminal.ts @@ -394,9 +394,9 @@ export class Terminal { } break; case iTutorialSteps.TerminalConnect: - if (commandArray.length === 2) { + if (commandArray[0] === "connect") { if ( - commandArray[0] === "connect" && + commandArray.length === 2 && (commandArray[1] === "n00dles" || commandArray[1] === n00dlesServ.hostname) ) { iTutorialNextStep(); @@ -419,8 +419,8 @@ export class Terminal { break; case iTutorialSteps.TerminalNuke: if ( - (commandArray.length === 2 && commandArray[0] === "run" && commandArray[1] === "NUKE.exe") || - commandArray[0] === "NUKE.exe" + (commandArray.length === 1 && commandArray[0] === "NUKE.exe") || + (commandArray.length === 2 && commandArray[0] === "run" && commandArray[1] === "NUKE.exe") ) { iTutorialNextStep(); } else { @@ -451,8 +451,8 @@ export class Terminal { } break; case iTutorialSteps.TerminalCreateScript: - if (commandArray.length === 2 || commandArray[0] === "nano") { - if (commandArray[0] === "nano" && commandArray[1] === tutorialScriptName) { + if (commandArray[0] === "nano") { + if (commandArray.length === 2 && commandArray[1] === tutorialScriptName) { iTutorialNextStep(); } else { this.error("Wrong command. Try again!"); @@ -473,8 +473,8 @@ export class Terminal { break; case iTutorialSteps.TerminalRunScript: if ( - (commandArray.length === 2 && commandArray[0] === "run" && commandArray[1] === tutorialScriptName) || - (commandArray.length === 1 && commandArray[0] === tutorialScriptName) + (commandArray.length === 1 && commandArray[0] === tutorialScriptName) || + (commandArray.length === 2 && commandArray[0] === "run" && commandArray[1] === tutorialScriptName) ) { iTutorialNextStep(); } else { @@ -482,12 +482,12 @@ export class Terminal { return; } break; - case iTutorialSteps.TerminalGoToActiveScriptsPage: + case iTutorialSteps.TerminalGoToActiveScriptsPage: // giving the player room to play around a bit if ( !( (commandArray.length === 1 && commandArray[0] === "free") || - (commandArray.length === 2 && commandArray[0] === "run" && commandArray[1] === tutorialScriptName) || - (commandArray.length === 1 && commandArray[0] === tutorialScriptName) + (commandArray.length === 1 && commandArray[0] === tutorialScriptName) || + (commandArray.length === 2 && commandArray[0] === "run" && commandArray[1] === tutorialScriptName) ) ) { this.error(errorMessageForBadCommand); @@ -503,8 +503,8 @@ export class Terminal { } break; case iTutorialSteps.TerminalScp: - if (commandArray.length === 3) { - if (commandArray[0] === "scp" && commandArray[1] === tutorialScriptName && commandArray[2] === "n00dles") { + if (commandArray[0] === "scp") { + if (commandArray.length === 3 && commandArray[1] === tutorialScriptName && commandArray[2] === "n00dles") { iTutorialNextStep(); } else { this.error("Wrong command. Try again!"); From 62e404fc73df1e9114478ffdf3752a12a671bb42 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 14:52:36 +0100 Subject: [PATCH 21/82] better second draft! --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index b873b40749..3bb8845e8c 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -227,12 +227,12 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - You're now attempting to hack the server. Hacking takes time, and has a success chance. If your hack is - successful, you'll steal a percentage of the server's available money. + You're now attempting to hack the server. If your hack is successful, you'll steal a percentage of the server's + available money.

            - All of those variables (time, success chance, and percentage stolen) are affected by your hacking skill, and - by the server's security level. + Nearly all aspects of hacking (including time taken, success chance and percentage stolen) are affected by your + hacking skill, and by the server's security level.

            When you hack a server, you deplete the money it has available, so any subsequent hacks take less money. From eb568a65de37a948ee3a01fd6555f26aae306d64 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 15:01:31 +0100 Subject: [PATCH 22/82] a --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 3bb8845e8c..5413b9ada8 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -175,8 +175,8 @@ export function InteractiveTutorialRoot(): React.ReactElement { servers and computers. Using specialised skills, you can hack servers to steal money and gain experience.

            - You've got the skills to hack n00dles – scan-analyze showed us that n00dles has a required hacking skill of - 1. + You've got the hacking skill needed to hack n00dles – scan-analyze showed us that n00dles has a required + hacking skill of 1.

            But there's something else we need to check. Let's run some diagnostics using From cf4eb52916e4a41b72ebc03d9c9bcbdfd10da792 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 15:07:25 +0100 Subject: [PATCH 23/82] ... --- .../InteractiveTutorialRoot.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 5413b9ada8..9692b2787c 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -175,7 +175,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { servers and computers. Using specialised skills, you can hack servers to steal money and gain experience.

            - You've got the hacking skill needed to hack n00dles – scan-analyze showed us that n00dles has a required + You've got the hacking skill needed to hack n00dles – scan-analyze showed us that n00dles has a required hacking skill of 1.

            @@ -227,12 +227,12 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - You're now attempting to hack the server. If your hack is successful, you'll steal a percentage of the server's - available money. + You're now attempting to hack the server. If your hack is successful, you'll steal a percentage of the + server's available money.

            - Nearly all aspects of hacking (including time taken, success chance and percentage stolen) are affected by your - hacking skill, and by the server's security level. + Nearly all aspects of hacking (including time taken, success chance and percentage stolen) are affected by + your hacking skill, and by the server's security level.

            When you hack a server, you deplete the money it has available, so any subsequent hacks take less money. @@ -263,8 +263,8 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - Hacking is the core mechanic of the game and is necessary to progress. So you don't want to hack manually - the entire time. We need a way to automate it! + Hacking is the core mechanic of the game and is necessary to progress. So you don't want to be hacking + manually the entire time. We need a way to automate it!

            Let's head home and create our first script. @@ -496,7 +496,7 @@ export async function main(ns) { content: ( <> - Now we've gained some money and exp, let look at it the Stats tab. Click{" "} + Now we've gained some money and exp, let look at the Stats tab. Click{" "} Stats From c437b1fa4cd109ea0ace788e56c7cced1caafb60 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 15:40:03 +0100 Subject: [PATCH 24/82] final second draft --- .../InteractiveTutorialRoot.tsx | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 9692b2787c..be3d797f35 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -446,8 +446,8 @@ export async function main(ns) { content: ( <> - We won't get far running scripts on our home computer alone. We can run them on other servers too. To do - that, we need to copy them over. + You can boost your earnings by running your scripts on other servers too. To do that, we need to copy them + over.

            First, let's see what files are stored on our home computer using @@ -496,7 +496,7 @@ export async function main(ns) { content: ( <> - Now we've gained some money and exp, let look at the Stats tab. Click{" "} + Now we've gained some money and exp, let's look at the Stats tab. Click{" "} Stats @@ -547,8 +547,7 @@ export async function main(ns) { content: ( <> - Hacknet Nodes passively earn you money over time, even when you're offline. When you get enough money, you - can upgrade your Hacknet Nodes below. + Hacknet Nodes passively earn you money over time, even when you're offline.

            Let's go to{" "} @@ -565,8 +564,8 @@ export async function main(ns) { content: ( <> - This shows all the locations in your current city. Each location has something that you can do. There's a - lot of content out in the world, so make sure you explore and discover! + Each location in a city has something that you can do. There's a lot of content out in the world, + so make sure you explore and discover!

            Lastly, go to{" "} @@ -607,6 +606,10 @@ export async function main(ns) { If you want to open one of the Documentaion page links in a new tab, click it while holding Ctrl (Control on a Mac keyboard). If you're playing the Steam version, doing that will open the link in your default browser.
            +
            + + Note: The documentation at readthedocs is outdated and unmaintained. Do not use it! +
            While the documentation is the first place to get help, if you can't find an answer then please{" "} @@ -614,17 +617,14 @@ export async function main(ns) { href="https://discord.com/channels/415207508303544321/415207508303544323" underline="always" target="_blank" + color={Settings.theme.info} > ask us on Discord .
            - - Note: The documentation at readthedocs is outdated and unmaintained. Do not use it! - -
            - And that's the end of the tutorial. We hope you enjoy the game! + That's the end of the tutorial. We hope you enjoy the game!
            ), canNext: true, From 00df9e61488bbb42e84b6554a535ddbc399b631d Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 16:13:32 +0100 Subject: [PATCH 25/82] yeah I said that was final but ... --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index be3d797f35..ffb2819504 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -408,7 +408,7 @@ export async function main(ns) { Then click {tutorialScriptName} to see some data about it.

            - Let's go back to the{" "} + When you're ready, let's go back to the{" "} Terminal @@ -621,9 +621,12 @@ export async function main(ns) { > ask us on Discord - . + .

            +
            +
            +
            That's the end of the tutorial. We hope you enjoy the game!
            ), From 422767cf8185851796595e6dc45d5abab857f47b Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 16:26:53 +0100 Subject: [PATCH 26/82] ! --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index ffb2819504..84eda3260c 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -148,7 +148,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - Now you can see all the servers that are up to 2 nodes away, and the route to get to them. + Now you can see all the servers that are up to 2 nodes away, and the routes to get to them.

            You can connect to any machine that is 1 node away using @@ -623,7 +623,6 @@ export async function main(ns) { .
            -



            From ed3bc649865cbd47b4111647f7293047174e98e6 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 16:30:19 +0100 Subject: [PATCH 27/82] . --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 84eda3260c..d3de8eb28a 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -611,7 +611,7 @@ export async function main(ns) { Note: The documentation at readthedocs is outdated and unmaintained. Do not use it!

            - +
            While the documentation is the first place to get help, if you can't find an answer then please{" "} . -
            +



            From 1b3d2ad458da2de3ef0ff5ef650f1908973ac7d2 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 16:39:55 +0100 Subject: [PATCH 28/82] boing --- .../InteractiveTutorialRoot.tsx | 32 ++++++++++--------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index d3de8eb28a..314bce93a9 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -148,7 +148,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - Now you can see all the servers that are up to 2 nodes away, and the routes to get to them. + Now you can see all the servers that are up to 2 nodes away, and the routes to get to them.

            You can connect to any machine that is 1 node away using @@ -564,8 +564,8 @@ export async function main(ns) { content: ( <> - Each location in a city has something that you can do. There's a lot of content out in the world, - so make sure you explore and discover! + Each location in a city has something that you can do. There's a lot of content out in the world, so make + sure you explore and discover!

            Lastly, go to{" "} @@ -606,24 +606,26 @@ export async function main(ns) { If you want to open one of the Documentaion page links in a new tab, click it while holding Ctrl (Control on a Mac keyboard). If you're playing the Steam version, doing that will open the link in your default browser.
            -
            +
            Note: The documentation at readthedocs is outdated and unmaintained. Do not use it!
            + While the documentation is the first place to get help, if you can't find an answer then please{" "} + + ask us on Discord + + .
            - While the documentation is the first place to get help, if you can't find an answer then please{" "} - - ask us on Discord - - .
            -
            + +
            +


            That's the end of the tutorial. We hope you enjoy the game! From 49f4f34e3a2c1ca6f723f116bb86c29829d592ed Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 16:50:20 +0100 Subject: [PATCH 29/82] . --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 314bce93a9..55dd6462ed 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -623,12 +623,7 @@ export async function main(ns) { .

            - -
            -
            -
            -
            - That's the end of the tutorial. We hope you enjoy the game! + And that's the end of the tutorial. I hope you enjoy the game!
            ), canNext: true, From 76d7c91f1ee0f6102bdfc70166a90341dc792f09 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 17:31:56 +0100 Subject: [PATCH 30/82] reverting nonsense --- src/Programs/Programs.ts | 46 +++++++++++++++++----------------- src/Sidebar/ui/SidebarRoot.tsx | 6 +---- src/Terminal/commands/grow.ts | 4 +-- src/ui/MD/code.tsx | 12 +++------ src/ui/React/CopyableText.tsx | 3 +-- 5 files changed, 31 insertions(+), 40 deletions(-) diff --git a/src/Programs/Programs.ts b/src/Programs/Programs.ts index 9dd4fb46d7..495428a354 100644 --- a/src/Programs/Programs.ts +++ b/src/Programs/Programs.ts @@ -50,7 +50,7 @@ export const Programs: Record = { nsMethod: "nuke", create: { level: 1, - tooltip: "This virus is used to gain root access to a machine if enough ports are opened", + tooltip: "This virus is used to gain root access to a machine if enough ports are opened.", req: requireHackingLevel(1), time: CONSTANTS.MillisecondsPerFiveMinutes, }, @@ -62,13 +62,13 @@ export const Programs: Record = { } if (server.hasAdminRights) { Terminal.print("You already have root access to this computer. There is no reason to run NUKE.exe"); - Terminal.print("You can run scripts on this server"); + Terminal.print("You can now run scripts on this server."); return; } if (server.openPortCount >= server.numOpenPortsRequired) { server.hasAdminRights = true; Terminal.print("NUKE successful! Gained root access to " + server.hostname); - Terminal.print("You can now run scripts on this server"); + Terminal.print("You can now run scripts on this server."); return; } @@ -87,7 +87,7 @@ export const Programs: Record = { run: (args: string[], server: BaseServer): void => { warnIfNonArgProgramIsRunWithArgs(CompletedProgramName.bruteSsh, args); if (!(server instanceof Server)) { - Terminal.error("Cannot run BruteSSH.exe on this kind of server"); + Terminal.error("Cannot run BruteSSH.exe on this kind of server."); return; } if (server.sshPortOpen) { @@ -95,7 +95,7 @@ export const Programs: Record = { return; } if (server.purchasedByPlayer) { - Terminal.print("Opening ports on your own machines has no negative consequences in the game"); + Terminal.print("Opening ports on your own machines has no negative consequences in the game."); } server.sshPortOpen = true; @@ -115,7 +115,7 @@ export const Programs: Record = { run: (args: string[], server: BaseServer): void => { warnIfNonArgProgramIsRunWithArgs(CompletedProgramName.ftpCrack, args); if (!(server instanceof Server)) { - Terminal.error("Cannot run FTPCrack.exe on this kind of server"); + Terminal.error("Cannot run FTPCrack.exe on this kind of server."); return; } if (server.ftpPortOpen) { @@ -123,7 +123,7 @@ export const Programs: Record = { return; } if (server.purchasedByPlayer) { - Terminal.print("Opening ports on your own machines has no negative consequences in the game"); + Terminal.print("Opening ports on your own machines has no negative consequences in the game."); } server.ftpPortOpen = true; @@ -143,7 +143,7 @@ export const Programs: Record = { run: (args: string[], server: BaseServer): void => { warnIfNonArgProgramIsRunWithArgs(CompletedProgramName.relaySmtp, args); if (!(server instanceof Server)) { - Terminal.error("Cannot run relaySMTP.exe on this kind of server"); + Terminal.error("Cannot run relaySMTP.exe on this kind of server."); return; } if (server.smtpPortOpen) { @@ -151,7 +151,7 @@ export const Programs: Record = { return; } if (server.purchasedByPlayer) { - Terminal.print("Opening ports on your own machines has no negative consequences in the game"); + Terminal.print("Opening ports on your own machines has no negative consequences in the game."); } server.smtpPortOpen = true; @@ -171,7 +171,7 @@ export const Programs: Record = { run: (args: string[], server: BaseServer): void => { warnIfNonArgProgramIsRunWithArgs(CompletedProgramName.httpWorm, args); if (!(server instanceof Server)) { - Terminal.error("Cannot run HTTPWorm.exe on this kind of server"); + Terminal.error("Cannot run HTTPWorm.exe on this kind of server."); return; } if (server.httpPortOpen) { @@ -179,7 +179,7 @@ export const Programs: Record = { return; } if (server.purchasedByPlayer) { - Terminal.print("Opening ports on your own machines has no negative consequences in the game"); + Terminal.print("Opening ports on your own machines has no negative consequences in the game."); } server.httpPortOpen = true; @@ -199,7 +199,7 @@ export const Programs: Record = { run: (args: string[], server: BaseServer): void => { warnIfNonArgProgramIsRunWithArgs(CompletedProgramName.sqlInject, args); if (!(server instanceof Server)) { - Terminal.error("Cannot run SQLInject.exe on this kind of server"); + Terminal.error("Cannot run SQLInject.exe on this kind of server."); return; } if (server.sqlPortOpen) { @@ -207,7 +207,7 @@ export const Programs: Record = { return; } if (server.purchasedByPlayer) { - Terminal.print("Opening ports on your own machines has no negative consequences in the game"); + Terminal.print("Opening ports on your own machines has no negative consequences in the game."); } server.sqlPortOpen = true; @@ -224,8 +224,8 @@ export const Programs: Record = { time: CONSTANTS.MillisecondsPerQuarterHour, }, run: (): void => { - Terminal.print("This executable cannot be run"); - Terminal.print("DeepscanV1.exe lets you run 'scan-analyze' with a depth up to 5"); + Terminal.print("This executable cannot be run."); + Terminal.print("DeepscanV1.exe lets you run 'scan-analyze' with a depth up to 5."); }, }), [CompletedProgramName.deepScan2]: new Program({ @@ -237,8 +237,8 @@ export const Programs: Record = { time: CONSTANTS.MillisecondsPer2Hours, }, run: (): void => { - Terminal.print("This executable cannot be run"); - Terminal.print("DeepscanV2.exe lets you run 'scan-analyze' with a depth up to 10"); + Terminal.print("This executable cannot be run."); + Terminal.print("DeepscanV2.exe lets you run 'scan-analyze' with a depth up to 10."); }, }), [CompletedProgramName.serverProfiler]: new Program({ @@ -263,7 +263,7 @@ export const Programs: Record = { } if (!(targetServer instanceof Server)) { - Terminal.error(`ServerProfiler.exe can only be run on normal servers`); + Terminal.error(`ServerProfiler.exe can only be run on normal servers.`); return; } @@ -300,9 +300,9 @@ export const Programs: Record = { time: CONSTANTS.MillisecondsPerQuarterHour, }, run: (): void => { - Terminal.print("This executable cannot be run"); - Terminal.print("AutoLink.exe lets you automatically connect to other servers when using 'scan-analyze'"); - Terminal.print("When using scan-analyze, click on a server's hostname to connect to it"); + Terminal.print("This executable cannot be run."); + Terminal.print("AutoLink.exe lets you automatically connect to other servers when using 'scan-analyze'."); + Terminal.print("When using scan-analyze, click on a server's hostname to connect to it."); }, }), [CompletedProgramName.formulas]: new Program({ @@ -314,8 +314,8 @@ export const Programs: Record = { time: CONSTANTS.MillisecondsPer4Hours, }, run: (): void => { - Terminal.print("This executable cannot be run"); - Terminal.print("Formulas.exe lets you use the formulas API"); + Terminal.print("This executable cannot be run."); + Terminal.print("Formulas.exe lets you use the formulas API."); }, }), [CompletedProgramName.bitFlume]: new Program({ diff --git a/src/Sidebar/ui/SidebarRoot.tsx b/src/Sidebar/ui/SidebarRoot.tsx index 90ba90d205..ac9b2462f4 100644 --- a/src/Sidebar/ui/SidebarRoot.tsx +++ b/src/Sidebar/ui/SidebarRoot.tsx @@ -120,11 +120,7 @@ const useStyles = makeStyles()((theme: Theme) => ({ borderLeft: "3px solid " + theme.palette.primary.main, }, listitem: {}, - // To explain why I did this daft shit: Lots of elements here are setting their colour using color="error" or similar. - // The problem is that Typography's default colour options are not the same as with other elements. In particular, it's missing - // "info". Do ({ +const useStyles = makeStyles()((theme: Theme) => ({ pre: { borderRadius: "6px", }, @@ -36,11 +36,7 @@ const InlineCode = (props: React.PropsWithChildren): React.ReactEleme ); -type CodeBlockProps = { - children: string; -}; - -const BigCode = ({ children }: CodeBlockProps): React.ReactElement => ( +const BigCode = (props: React.PropsWithChildren): React.ReactElement => ( ( borderRadius: "6px", }} > - {children} + {String(props.children)} ); export const code = (props: React.PropsWithChildren): React.ReactElement => - props.inline ? : {String(props.children)}; + props.inline ? : ; diff --git a/src/ui/React/CopyableText.tsx b/src/ui/React/CopyableText.tsx index eec89391fa..ee583d46fa 100644 --- a/src/ui/React/CopyableText.tsx +++ b/src/ui/React/CopyableText.tsx @@ -5,7 +5,6 @@ import Tooltip from "@mui/material/Tooltip"; interface IProps { value: string; color?: string; - className?: string; variant?: | "button" | "caption" @@ -41,7 +40,7 @@ export function CopyableText(props: IProps): React.ReactElement { return ( Copied!
            }> - + {props.value} From d4224c567eb30a3e51017835f15d991db1aced99 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 17:44:08 +0100 Subject: [PATCH 31/82] deleted comments --- src/InteractiveTutorial.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/InteractiveTutorial.ts b/src/InteractiveTutorial.ts index 9e8082127c..e8f2a102b5 100644 --- a/src/InteractiveTutorial.ts +++ b/src/InteractiveTutorial.ts @@ -1,13 +1,3 @@ -//// Still to do: -// Somewhere ??? the text that says 'Processes cannot be killed during the tutorial' ... when you clearly can! -// Full stops -// Theming -// CL's other points -/* This should be a tip in the documentation UI -- not in the tutorial - If you want to open one of the Documentaion page links in a new tab, click it while holding Ctrl (Control on a - Mac keyboard). If you're playing the Steam version, doing that will open the link in your default browser. - */ - import { Player } from "@player"; import { LiteratureName } from "@enums"; import { ITutorialEvents } from "./ui/InteractiveTutorial/ITutorialEvents"; From a26b4499d0cf735180d68f985fe85ea95e41f738 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 18:41:28 +0100 Subject: [PATCH 32/82] cleaner --- .../InteractiveTutorialRoot.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 55dd6462ed..bc806574ba 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -155,7 +155,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {

            - {"[home /]> connect hostname"} + {"[home /]> connect"}
            Let's connect to n00dles. @@ -201,7 +201,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {

            If you check the diagnostics, you'll see that n00dles' "Required number of open ports for NUKE" is 0. So - you're good to run the virus! Just enter + you're good to run the virus. Just enter

            @@ -217,7 +217,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { Now you've got root access, you can hack the server! Try entering

            -
            +
            d {"[n00dles /]> hack"} ), @@ -324,7 +324,7 @@ export async function main(ns) {

            - One benefit of using scripts to hack is that they don't need to be connected to the server they're hacking. + One benefit of using scripts to hack is that you don't need to be connected to the server they're hacking. Scripts can target any server on the network.

            @@ -377,7 +377,7 @@ export async function main(ns) { <> Your script is now running! Scripts run in the background until their code completes (though if they have an - infinite loop, like {tutorialScriptName} does, it never will). + continuous loop, like {tutorialScriptName} does, they'll run indefinitely).

            Scripts will passively earn you income and hacking experience. They even earn money and exp while you're @@ -496,12 +496,12 @@ export async function main(ns) { content: ( <> - Now we've gained some money and exp, let's look at the Stats tab. Click{" "} + Now we've gained some money and exp, let's look at the{" "} Stats {" "} - at the left-hand side of the screen. + tab ), @@ -623,7 +623,7 @@ export async function main(ns) { .

            - And that's the end of the tutorial. I hope you enjoy the game! + And that concludes the tutorial. I hope you enjoy the game!
            ), canNext: true, From fc0e4353811be297b2e1cf72e20228f0db77f087 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 21:17:09 +0100 Subject: [PATCH 33/82] tiny --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index bc806574ba..e5d5df20dd 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -200,8 +200,8 @@ export function InteractiveTutorialRoot(): React.ReactElement { enough ports are open.

            - If you check the diagnostics, you'll see that n00dles' "Required number of open ports for NUKE" is 0. So - you're good to run the virus. Just enter + If you check the diagnostics again, you'll see that n00dles' "Required number of open ports for NUKE" is 0. + So you're good to run the virus. Just enter

            @@ -217,7 +217,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { Now you've got root access, you can hack the server! Try entering

            -
            d + {"[n00dles /]> hack"} ), @@ -376,7 +376,7 @@ export async function main(ns) { content: ( <> - Your script is now running! Scripts run in the background until their code completes (though if they have an + Your script is now running! Scripts run in the background until their code completes (if they have an continuous loop, like {tutorialScriptName} does, they'll run indefinitely).

            From 65a6bd21bd28d50d5963e760cbcd9968223b78c1 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Thu, 27 Aug 2026 21:46:56 +0100 Subject: [PATCH 34/82] uiop --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index e5d5df20dd..8e1a4455b9 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -179,7 +179,8 @@ export function InteractiveTutorialRoot(): React.ReactElement { hacking skill of 1.

            - But there's something else we need to check. Let's run some diagnostics using + But there's something else we need to do before we start hacking. To see what, let's run some diagnostics + using

            From 54e1d46040dd9fa5c348a4ceefa6a652c131d8fc Mon Sep 17 00:00:00 2001 From: branchtheory Date: Fri, 28 Aug 2026 01:17:22 +0100 Subject: [PATCH 35/82] just learned how themes work --- .../InteractiveTutorialRoot.tsx | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 8e1a4455b9..67ea024172 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -33,7 +33,6 @@ interface IContent { export const tutorialScriptName = `hacking.js`; export function InteractiveTutorialRoot(): React.ReactElement { - const theme = useTheme(); const TerminalText = styled(Typography)(({ theme }) => ({ borderBottom: `1px solid ${theme.palette.primary.main}`, })); @@ -56,8 +55,8 @@ export function InteractiveTutorialRoot(): React.ReactElement {
            You can also exit the tutorial at any time. If you ever want to review it, go to the{" "} - - Options + + Options {" "} tab and select Repeat Tutorial. @@ -71,16 +70,16 @@ export function InteractiveTutorialRoot(): React.ReactElement { We're currently on the{" "} - - Terminal + + Terminal {" "} tab.

            You can use the{" "} - - Terminal + + Terminal {" "} to interface with your home computer, and with other machines around the world.
            @@ -179,7 +178,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { hacking skill of 1.

            - But there's something else we need to do before we start hacking. To see what, let's run some diagnostics + But there's something else we need before we can start hacking. To see what, let's run some diagnostics using

            @@ -308,7 +307,8 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - Below is a script that hacks n00dles on a continuous loop. Copy and paste it into the editor. + Below is a script that hacks n00dles on a continuous loop. Click it to copy it, then paste it into the + editor.
            @@ -387,8 +387,8 @@ export async function main(ns) {
            Let's check how our running scripts are doing by clicking{" "} - - Active Scripts + + Active Scripts
            @@ -411,8 +411,8 @@ export async function main(ns) {
            When you're ready, let's go back to the{" "} - - Terminal + + Terminal @@ -499,8 +499,8 @@ export async function main(ns) { Now we've gained some money and exp, let's look at the{" "} - - Stats + + Stats {" "} tab @@ -513,8 +513,8 @@ export async function main(ns) { <> - - Stats + + Stats {" "} shows information about your skills, money, and bonuses. @@ -528,8 +528,8 @@ export async function main(ns) { Hacking isn't the only way to earn money. One other way to is to purchase Hacknet Nodes. Let's go to{" "} - - Hacknet + + Hacknet {" "} @@ -553,8 +553,8 @@ export async function main(ns) {
            Let's go to{" "} - - City + + City {" "} @@ -571,8 +571,8 @@ export async function main(ns) {
            Lastly, go to{" "} - - Documentation + + Documentation {" "} From 03e63db422b8ca8217983e5726dbe9e56b9053e4 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Fri, 28 Aug 2026 10:21:47 +0100 Subject: [PATCH 36/82] REMOVED HACKNET --- src/Hacknet/HacknetHelpers.tsx | 11 ---- src/Hacknet/ui/GeneralInfo.tsx | 32 +++++----- src/InteractiveTutorial.ts | 10 +-- src/Sidebar/ui/SidebarRoot.tsx | 10 +-- .../InteractiveTutorialRoot.tsx | 61 +++---------------- 5 files changed, 32 insertions(+), 92 deletions(-) diff --git a/src/Hacknet/HacknetHelpers.tsx b/src/Hacknet/HacknetHelpers.tsx index 439d03ce8b..e599fe2b18 100644 --- a/src/Hacknet/HacknetHelpers.tsx +++ b/src/Hacknet/HacknetHelpers.tsx @@ -17,7 +17,6 @@ import { HashManager } from "./HashManager"; import { HashUpgrades } from "./HashUpgrades"; import { generateRandomContract } from "../CodingContract/ContractGenerator"; -import { iTutorialSteps, iTutorialNextStep, ITutorial } from "../InteractiveTutorial"; import { Player } from "@player"; import { GetServer } from "../Server/AllServers"; import { Server } from "../Server/Server"; @@ -36,16 +35,6 @@ export function hasHacknetServers(): boolean { } export function purchaseHacknet(): number { - /* INTERACTIVE TUTORIAL */ - if (ITutorial.isRunning) { - if (ITutorial.currStep === iTutorialSteps.HacknetNodesIntroduction) { - iTutorialNextStep(); - } else { - return -1; - } - } - /* END INTERACTIVE TUTORIAL */ - const numOwned = Player.hacknetNodes.length; if (hasHacknetServers()) { const cost = getCostOfNextHacknetServer(); diff --git a/src/Hacknet/ui/GeneralInfo.tsx b/src/Hacknet/ui/GeneralInfo.tsx index 5e2fe73b3e..86a7a03b77 100644 --- a/src/Hacknet/ui/GeneralInfo.tsx +++ b/src/Hacknet/ui/GeneralInfo.tsx @@ -14,36 +14,32 @@ export function GeneralInfo(props: IProps): React.ReactElement { return ( <> - The Hacknet is a global, decentralized network of machines. It is used by hackers all around the world to - anonymously share computing power and perform distributed cyberattacks without the fear of being traced. + The Hacknet is a global, decentralized network of machines. It is used by hackers around the world to perform + cyber attacks without the fear of being traced. Hackers who use the network distribute a small percentage of + their profits to it. The machines that the Hacknet runs on are called Hacknet Nodes, specialised rigs that can + share computing power anonymously.
            {!props.hasHacknetServers ? ( <> + You can purchase Hacknet Nodes to passively earn money. +
            - {`Here, you can purchase a Hacknet Node, a specialized machine that can connect ` + - `and contribute its resources to the Hacknet network. This allows you to take ` + - `a small percentage of profits from hacks performed on the network. Essentially, ` + - `you are renting out your Node's computing power.`} - - - {`Each Hacknet Node you purchase will passively earn you money. Each Hacknet Node ` + - `can be upgraded in order to increase its computing power and thereby increase ` + - `the profit you earn from it.`} + Each Node can be upgraded to increase its computing power and the profit you make from it. ) : ( <> - {`Here, you can purchase a Hacknet Server, an upgraded version of the Hacknet Node. ` + - `Hacknet Servers will perform computations and operations on the network, earning ` + - `you hashes. Hashes can be spent on a variety of different upgrades.`} + Here you can purchase a Hacknet Server, an upgraded version of the Hacknet Node. Hacknet Servers will + perform computations and operations on the network, earning you hashes. Hashes can be spent on a variety of + different upgrades. +
            - {`Hacknet Servers can also be used as servers to run scripts. However, running scripts ` + - `on a server will reduce its hash rate (hashes generated per second). A Hacknet Server's hash ` + - `rate will be reduced by the percentage of RAM that is being used by that Server to run ` + - `scripts.`} + Hacknet Servers can also be used as servers to run scripts. However, running scripts on a server will reduce + its hash rate (hashes generated per second). A Hacknet Server's hash rate will be reduced by the percentage + of RAM that is being used by that Server to run scripts. )} diff --git a/src/InteractiveTutorial.ts b/src/InteractiveTutorial.ts index e8f2a102b5..f69f7a6f3f 100644 --- a/src/InteractiveTutorial.ts +++ b/src/InteractiveTutorial.ts @@ -7,7 +7,6 @@ enum iTutorialSteps { Start, // Hacking - TerminalIntro, // Introduction to Terminal TerminalScan, // Using 'scan' Terminal command TerminalScanAnalyze1, // Using 'scan-analyze' Terminal command TerminalScanAnalyze2, // Using 'scan-analyze 3' Terminal command @@ -34,9 +33,7 @@ enum iTutorialSteps { CharacterPage, // Introduction to 'Stats' page // Finishing off - GoToHacknetNodesPage, - HacknetNodesIntroduction, - HacknetNodesGoToWorldPage, + CharacterGoToWorldPage, WorldDescription, DocumentationPageInfo, End, @@ -51,7 +48,6 @@ const ITutorial = { [iTutorialSteps.Start]: false, [iTutorialSteps.GoToCharacterPage]: false, [iTutorialSteps.CharacterPage]: false, - [iTutorialSteps.TerminalIntro]: false, [iTutorialSteps.TerminalHelp]: false, [iTutorialSteps.TerminalLs]: false, [iTutorialSteps.TerminalScan]: false, @@ -72,9 +68,7 @@ const ITutorial = { [iTutorialSteps.ActiveScriptsToTerminal]: false, [iTutorialSteps.TerminalTailScript]: false, [iTutorialSteps.TerminalScp]: false, - [iTutorialSteps.GoToHacknetNodesPage]: false, - [iTutorialSteps.HacknetNodesIntroduction]: false, - [iTutorialSteps.HacknetNodesGoToWorldPage]: false, + [iTutorialSteps.CharacterGoToWorldPage]: false, [iTutorialSteps.WorldDescription]: false, [iTutorialSteps.DocumentationPageInfo]: false, [iTutorialSteps.End]: false, diff --git a/src/Sidebar/ui/SidebarRoot.tsx b/src/Sidebar/ui/SidebarRoot.tsx index ac9b2462f4..5331b43af9 100644 --- a/src/Sidebar/ui/SidebarRoot.tsx +++ b/src/Sidebar/ui/SidebarRoot.tsx @@ -138,13 +138,15 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement { case iTutorialSteps.TerminalGoToActiveScriptsPage: flash = Page.ActiveScripts; break; + case iTutorialSteps.TerminalEditScript: + if (props.page !== Page.ScriptEditor) { + flash = Page.ScriptEditor; + } + break; case iTutorialSteps.GoToCharacterPage: flash = Page.Stats; break; - case iTutorialSteps.GoToHacknetNodesPage: - flash = Page.Hacknet; - break; - case iTutorialSteps.HacknetNodesGoToWorldPage: + case iTutorialSteps.CharacterGoToWorldPage: flash = Page.City; break; case iTutorialSteps.WorldDescription: diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 67ea024172..ff7fef1ed2 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -8,10 +8,9 @@ import EqualizerIcon from "@mui/icons-material/Equalizer"; import SettingsIcon from "@mui/icons-material/Settings"; import LastPageIcon from "@mui/icons-material/LastPage"; import HelpIcon from "@mui/icons-material/Help"; -import AccountTreeIcon from "@mui/icons-material/AccountTree"; import StorageIcon from "@mui/icons-material/Storage"; import LocationCityIcon from "@mui/icons-material/LocationCity"; -import { useTheme, styled } from "@mui/material/styles"; +import { styled } from "@mui/material/styles"; import { iTutorialPrevStep, @@ -64,7 +63,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { ), canNext: true, }, - [iTutorialSteps.TerminalIntro as number]: { + [iTutorialSteps.TerminalScan as number]: { content: ( <> @@ -82,15 +81,8 @@ export function InteractiveTutorialRoot(): React.ReactElement { Terminal {" "} to interface with your home computer, and with other machines around the world. - - - ), - canNext: true, - }, - [iTutorialSteps.TerminalScan as number]: { - content: ( - <> - +
            +
            Let's try that out. Start by entering

            @@ -108,14 +100,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - Running -
            -
            -
            - {"[home /]> scan"} - -
            - shows you every server you can connect to from your current machine. + That's shown you every server you can connect to from your current machine.

            The network's much bigger than that though! To start exploring it, enter @@ -178,8 +163,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { hacking skill of 1.

            - But there's something else we need before we can start hacking. To see what, let's run some diagnostics - using + But there's something else we need too. To see what, let's run some diagnostics using

            @@ -227,8 +211,8 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - You're now attempting to hack the server. If your hack is successful, you'll steal a percentage of the - server's available money. + You're now attempting to hack n00dles. If your hack is successful, you'll steal a percentage of the server's + available money.

            Nearly all aspects of hacking (including time taken, success chance and percentage stolen) are affected by @@ -522,36 +506,11 @@ export async function main(ns) { ), canNext: true, }, - [iTutorialSteps.GoToHacknetNodesPage as number]: { + [iTutorialSteps.CharacterGoToWorldPage as number]: { content: ( <> - Hacking isn't the only way to earn money. One other way to is to purchase Hacknet Nodes. Let's go to{" "} - - - Hacknet - {" "} - - - ), - canNext: false, - }, - [iTutorialSteps.HacknetNodesIntroduction as number]: { - content: ( - - Here you can purchase new Hacknet Nodes and upgrade your existing ones. Let's purchase one. - - ), - canNext: true, - }, - [iTutorialSteps.HacknetNodesGoToWorldPage as number]: { - content: ( - <> - - Hacknet Nodes passively earn you money over time, even when you're offline. -
            -
            - Let's go to{" "} + Next, let's go to{" "} City From 1907a8962ceb3d5bddea0025bd26b0fde8cfa98b Mon Sep 17 00:00:00 2001 From: branchtheory Date: Fri, 28 Aug 2026 14:01:02 +0100 Subject: [PATCH 37/82] moved hacknet info rewrite to a separate branch --- src/Hacknet/ui/GeneralInfo.tsx | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/Hacknet/ui/GeneralInfo.tsx b/src/Hacknet/ui/GeneralInfo.tsx index 86a7a03b77..5e2fe73b3e 100644 --- a/src/Hacknet/ui/GeneralInfo.tsx +++ b/src/Hacknet/ui/GeneralInfo.tsx @@ -14,32 +14,36 @@ export function GeneralInfo(props: IProps): React.ReactElement { return ( <> - The Hacknet is a global, decentralized network of machines. It is used by hackers around the world to perform - cyber attacks without the fear of being traced. Hackers who use the network distribute a small percentage of - their profits to it. The machines that the Hacknet runs on are called Hacknet Nodes, specialised rigs that can - share computing power anonymously. + The Hacknet is a global, decentralized network of machines. It is used by hackers all around the world to + anonymously share computing power and perform distributed cyberattacks without the fear of being traced.
            {!props.hasHacknetServers ? ( <> - You can purchase Hacknet Nodes to passively earn money. -
            - Each Node can be upgraded to increase its computing power and the profit you make from it. + {`Here, you can purchase a Hacknet Node, a specialized machine that can connect ` + + `and contribute its resources to the Hacknet network. This allows you to take ` + + `a small percentage of profits from hacks performed on the network. Essentially, ` + + `you are renting out your Node's computing power.`} + + + {`Each Hacknet Node you purchase will passively earn you money. Each Hacknet Node ` + + `can be upgraded in order to increase its computing power and thereby increase ` + + `the profit you earn from it.`} ) : ( <> - Here you can purchase a Hacknet Server, an upgraded version of the Hacknet Node. Hacknet Servers will - perform computations and operations on the network, earning you hashes. Hashes can be spent on a variety of - different upgrades. + {`Here, you can purchase a Hacknet Server, an upgraded version of the Hacknet Node. ` + + `Hacknet Servers will perform computations and operations on the network, earning ` + + `you hashes. Hashes can be spent on a variety of different upgrades.`} -
            - Hacknet Servers can also be used as servers to run scripts. However, running scripts on a server will reduce - its hash rate (hashes generated per second). A Hacknet Server's hash rate will be reduced by the percentage - of RAM that is being used by that Server to run scripts. + {`Hacknet Servers can also be used as servers to run scripts. However, running scripts ` + + `on a server will reduce its hash rate (hashes generated per second). A Hacknet Server's hash ` + + `rate will be reduced by the percentage of RAM that is being used by that Server to run ` + + `scripts.`} )} From 7b2750e38955380ddb64c48869e802b33a7ecd58 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Tue, 1 Sep 2026 22:34:19 +0100 Subject: [PATCH 38/82] 3rd draft --- src/InteractiveTutorial.ts | 4 +- src/Sidebar/ui/SidebarRoot.tsx | 12 +++- .../InteractiveTutorialRoot.tsx | 56 ++++++++++++------- 3 files changed, 47 insertions(+), 25 deletions(-) diff --git a/src/InteractiveTutorial.ts b/src/InteractiveTutorial.ts index f69f7a6f3f..7014b2081f 100644 --- a/src/InteractiveTutorial.ts +++ b/src/InteractiveTutorial.ts @@ -33,7 +33,7 @@ enum iTutorialSteps { CharacterPage, // Introduction to 'Stats' page // Finishing off - CharacterGoToWorldPage, + GoToWorldPage, WorldDescription, DocumentationPageInfo, End, @@ -68,7 +68,7 @@ const ITutorial = { [iTutorialSteps.ActiveScriptsToTerminal]: false, [iTutorialSteps.TerminalTailScript]: false, [iTutorialSteps.TerminalScp]: false, - [iTutorialSteps.CharacterGoToWorldPage]: false, + [iTutorialSteps.GoToWorldPage]: false, [iTutorialSteps.WorldDescription]: false, [iTutorialSteps.DocumentationPageInfo]: false, [iTutorialSteps.End]: false, diff --git a/src/Sidebar/ui/SidebarRoot.tsx b/src/Sidebar/ui/SidebarRoot.tsx index 5331b43af9..c6fb14f1af 100644 --- a/src/Sidebar/ui/SidebarRoot.tsx +++ b/src/Sidebar/ui/SidebarRoot.tsx @@ -131,12 +131,15 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement { useCycleRerender(); let flash: Page | null = null; + let shouldIncrementTutorial = false; switch (ITutorial.currStep) { case iTutorialSteps.ActiveScriptsPage: flash = Page.Terminal; + shouldIncrementTutorial = true; break; case iTutorialSteps.TerminalGoToActiveScriptsPage: flash = Page.ActiveScripts; + shouldIncrementTutorial = true; break; case iTutorialSteps.TerminalEditScript: if (props.page !== Page.ScriptEditor) { @@ -145,12 +148,15 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement { break; case iTutorialSteps.GoToCharacterPage: flash = Page.Stats; + shouldIncrementTutorial = true; break; - case iTutorialSteps.CharacterGoToWorldPage: + case iTutorialSteps.GoToWorldPage: flash = Page.City; + shouldIncrementTutorial = true; break; case iTutorialSteps.WorldDescription: flash = Page.Documentation; + shouldIncrementTutorial = true; break; } @@ -199,11 +205,11 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement { } else { throw new Error("Can't handle click on Page " + page); } - if (flash === page) { + if (flash === page && shouldIncrementTutorial) { iTutorialNextStep(); } }, - [flash], + [flash, shouldIncrementTutorial], ); /** diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index ff7fef1ed2..259f3a4bec 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -46,9 +46,12 @@ export function InteractiveTutorialRoot(): React.ReactElement { future... The year is 2077...

            - This tutorial will show you the basics of the game. -
            -
            + This tutorial will show you the basics of the game. We'll look at: +
              +
            • the network
            • +
            • hacking
            • +
            • scripts
            • +
            If you need to hide the tutorial panel temporarily, you can collapse it.

            @@ -176,8 +179,8 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - If you have a look, you can see the server's "Root Access" status. You must gain root access before you can - hack a server. + If you have a look, you can see the server's "Root Access" status is NO. You must gain root access before + you can hack a server.

            Handily, you've built a virus called NUKE.exe. NUKE.exe will grant you root access to any machine as long as @@ -219,8 +222,8 @@ export function InteractiveTutorialRoot(): React.ReactElement { your hacking skill, and by the server's security level.

            - When you hack a server, you deplete the money it has available, so any subsequent hacks take less money. - You'll also cause its security level to rise, so your hacks take longer. + When you hack a server, you deplete the money it has available, so subsequent hacks take less money. You'll + also cause its security level to rise, so your hacks take longer.

            To restore things, you can use @@ -315,7 +318,8 @@ export async function main(ns) {
            If you want to check what other functions you can use in the editor, use the search bar at the bottom, or click the NS API documentation link beside - it. + it. Almost everything you do in this tutorial can scripted using functions available to you from the very + start.

            Click Save at the bottom to save your script and close the editor. @@ -344,11 +348,7 @@ export async function main(ns) { content: ( <> - We have 8GB of free RAM. If that doesn't sound like much, don't worry: you can purchase more RAM for your - home server later. -
            -
            - For now, let's run our script using + We have 8GB of free RAM, enough to run our script. We can do that using

            @@ -452,7 +452,7 @@ export async function main(ns) { content: ( <> - To copy a script to another server, we can use the scp command. + To copy a script to another server, you can use the scp command.

            Let's copy {tutorialScriptName} to n00dles. @@ -506,7 +506,7 @@ export async function main(ns) { ), canNext: true, }, - [iTutorialSteps.CharacterGoToWorldPage as number]: { + [iTutorialSteps.GoToWorldPage as number]: { content: ( <> @@ -524,8 +524,15 @@ export async function main(ns) { content: ( <> - Each location in a city has something that you can do. There's a lot of content out in the world, so make - sure you explore and discover! + Each location in a city has something that you can do. +
            +
            + Look out for Tech centres like alpha ent. They'll let you purchase servers and upgrade your + home computer. +
            +
            + There's a lot of other content out in the world, so make sure you explore and discover! Hacking may be the + core mechanic, but it's far from the only one.

            Lastly, go to{" "} @@ -623,9 +630,18 @@ export async function main(ns) { )}

            - + + + + + + + {step + 1} / {Object.keys(iTutorialSteps).length / 2 - 1} + + + ); } From 2157207692f28274b1e47fafffd314f4057b19b1 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Wed, 2 Sep 2026 00:10:25 +0100 Subject: [PATCH 39/82] wording tweaks --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 259f3a4bec..eda5f3f78a 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -50,7 +50,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {
            • the network
            • hacking
            • -
            • scripts
            • +
            • creating scripts
            If you need to hide the tutorial panel temporarily, you can collapse it.
            @@ -179,7 +179,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - If you have a look, you can see the server's "Root Access" status is NO. You must gain root access before + If you have a look, you can see the server's "Root Access" status is "NO". You must gain root access before you can hack a server.

            @@ -318,7 +318,7 @@ export async function main(ns) {
            If you want to check what other functions you can use in the editor, use the search bar at the bottom, or click the NS API documentation link beside - it. Almost everything you do in this tutorial can scripted using functions available to you from the very + it. Almost everything we do in this tutorial can scripted using functions available to you from the very start.

            From a15aa5edd0cf16c79b86d77c2b9a62b6ba39596d Mon Sep 17 00:00:00 2001 From: branchtheory Date: Wed, 2 Sep 2026 01:30:55 +0100 Subject: [PATCH 40/82] briefer --- .../InteractiveTutorialRoot.tsx | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index eda5f3f78a..12087fd53f 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -179,16 +179,15 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - If you have a look, you can see the server's "Root Access" status is "NO". You must gain root access before - you can hack a server. + If you look, you can see that n00dles' "Root Access" status is "NO". You must gain root access before you + can hack a server. Handily, you've built a virus called NUKE.exe.

            - Handily, you've built a virus called NUKE.exe. NUKE.exe will grant you root access to any machine as long as - enough ports are open. + NUKE.exe will grant you root access to any machine as long as enough ports are open.

            - If you check the diagnostics again, you'll see that n00dles' "Required number of open ports for NUKE" is 0. - So you're good to run the virus. Just enter + In the diagnostics, you'll also see that n00dles' "Required number of open ports for NUKE" is 0. So you're + good to run the virus. Just enter

            @@ -214,16 +213,15 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - You're now attempting to hack n00dles. If your hack is successful, you'll steal a percentage of the server's + You're now attempting to hack n00dles. If your hack is successful, you'll steal a percentage of its available money.

            - Nearly all aspects of hacking (including time taken, success chance and percentage stolen) are affected by - your hacking skill, and by the server's security level. + As your hacking skill increases, hacking takes less time, steals more money, and has a higher success + chance. Higher server security has the opposite effect though.

            - When you hack a server, you deplete the money it has available, so subsequent hacks take less money. You'll - also cause its security level to rise, so your hacks take longer. + When you hack a server, you deplete its money and cause its security level to rise.

            To restore things, you can use @@ -312,14 +310,18 @@ export async function main(ns) {

            - One benefit of using scripts to hack is that you don't need to be connected to the server they're hacking. - Scripts can target any server on the network. + When using scripts to hack, you don't need to be connected to the server they're hacking. Scripts can target + any server on the network.

            - If you want to check what other functions you can use in the editor, use the search bar at the bottom, or - click the NS API documentation link beside - it. Almost everything we do in this tutorial can scripted using functions available to you from the very - start. + To check what other functions you can use in the editor, you can: +
              +
            • use the search bar at the bottom
            • +
            • + click the NS API documentation link +
            • +
            + Almost everything we do in this tutorial can scripted using functions available to you from the very start.

            Click Save at the bottom to save your script and close the editor. From ed4cf9dc652f62d5a678267781e42952bf766618 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Wed, 2 Sep 2026 02:13:52 +0100 Subject: [PATCH 41/82] not going to get much better ... --- .../InteractiveTutorialRoot.tsx | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 12087fd53f..047294d8c1 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -83,7 +83,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { Terminal
            {" "} - to interface with your home computer, and with other machines around the world. + to interface with your home computer, and with other computers around the world.

            Let's try that out. Start by entering @@ -119,7 +119,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - That's given us more detailed information about the servers we can connect to. + That's given us more detailed information.

            To look depeer into the network, let's increase the scanning depth to 2. @@ -217,14 +217,17 @@ export function InteractiveTutorialRoot(): React.ReactElement { available money.

            - As your hacking skill increases, hacking takes less time, steals more money, and has a higher success - chance. Higher server security has the opposite effect though. -
            -
            - When you hack a server, you deplete its money and cause its security level to rise. + As your hacking skill increases, hacking will: +
              +
            • take less time
            • +
            • steal more money
            • +
            • have a higher success chance
            • +
            + Higher server security has the opposite effects though.

            - To restore things, you can use + When you hack a server, you deplete its available money and make its security level go up. To restore + things, you can use

            @@ -249,7 +252,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { <> Hacking is the core mechanic of the game and is necessary to progress. So you don't want to be hacking - manually the entire time. We need a way to automate it! + manually the entire time. You need a way to automate it!

            Let's head home and create our first script. @@ -310,8 +313,8 @@ export async function main(ns) {

            - When using scripts to hack, you don't need to be connected to the server they're hacking. Scripts can target - any server on the network. + When using scripts to hack a server, you don't need to be connected to it. Scripts can target any server, + from any server.

            To check what other functions you can use in the editor, you can: @@ -321,7 +324,7 @@ export async function main(ns) { click the NS API documentation link
          - Almost everything we do in this tutorial can scripted using functions available to you from the very start. + Almost everything we do in this tutorial can scripted using functions available from the very start.

          Click Save at the bottom to save your script and close the editor. @@ -334,7 +337,10 @@ export async function main(ns) { content: ( <> - Now we'll run the script. You can run scripts on any server that you have root access to. + Now we'll run the script. +
          +
          + You can run scripts on any server that you have root access to.

          Scripts need RAM to run. To check how much RAM is available on a machine, enter @@ -350,7 +356,10 @@ export async function main(ns) { content: ( <> - We have 8GB of free RAM, enough to run our script. We can do that using + We have 8GB of free RAM, enough to run our script. +
          +
          + We can do that using

          @@ -367,8 +376,8 @@ export async function main(ns) { continuous loop, like {tutorialScriptName} does, they'll run indefinitely).

          - Scripts will passively earn you income and hacking experience. They even earn money and exp while you're - offline, although at a slower rate. + Scripts will passively earn you money and hacking exp. They even earn money and exp while you're offline, + although at a slower rate.

          Let's check how our running scripts are doing by clicking{" "} From ec5b9d69255545be3c6a88ce40e97a88e8534bb1 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Wed, 2 Sep 2026 02:18:05 +0100 Subject: [PATCH 42/82] nit = picked --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 047294d8c1..b14fb11c98 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -324,7 +324,7 @@ export async function main(ns) { click the NS API documentation link
        - Almost everything we do in this tutorial can scripted using functions available from the very start. + Almost everything we do in this tutorial can be scripted using functions available from the very start.

        Click Save at the bottom to save your script and close the editor. From 3124bb495f71cbd3626c588735cb0634f4ca3cb6 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Wed, 2 Sep 2026 08:52:46 +0100 Subject: [PATCH 43/82] shorter clearer --- .../InteractiveTutorialRoot.tsx | 158 ++++++++++++++++-- 1 file changed, 147 insertions(+), 11 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index b14fb11c98..bd26632a16 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -1,3 +1,139 @@ +/* + + +Return docs to the home screen when moving to the docs tab. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +*/ + import React, { useEffect } from "react"; import { Paper, Box, Typography, Button, Link } from "@mui/material"; @@ -187,7 +323,10 @@ export function InteractiveTutorialRoot(): React.ReactElement {

        In the diagnostics, you'll also see that n00dles' "Required number of open ports for NUKE" is 0. So you're - good to run the virus. Just enter + good to run the virus. +
        +
        + Just enter

        @@ -223,11 +362,10 @@ export function InteractiveTutorialRoot(): React.ReactElement {
      • steal more money
      • have a higher success chance
      - Higher server security has the opposite effects though. + When you hack a server, you deplete its available money and increase its security level. Higher security levels make hacking slower and less effective.

      - When you hack a server, you deplete its available money and make its security level go up. To restore - things, you can use + To restore things, you can use

      @@ -313,21 +451,19 @@ export async function main(ns) {

      - When using scripts to hack a server, you don't need to be connected to it. Scripts can target any server, - from any server. + When using scripts to hack a server, you don't need to be connected to the server. Scripts can target any + server, from any server.

      - To check what other functions you can use in the editor, you can: + Almost everything we do in this tutorial can be scripted using functions available to you right away. To + check what functions there are, you can:
      • use the search bar at the bottom
      • click the NS API documentation link
      - Almost everything we do in this tutorial can be scripted using functions available from the very start. -
      -
      - Click Save at the bottom to save your script and close the editor. + For now though, click Save at the bottom to save your script and close the editor.
      ), From 948ad3758ac142c2b77e7080fe75de895f010d44 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Wed, 2 Sep 2026 17:23:56 +0100 Subject: [PATCH 44/82] RAM! --- src/InteractiveTutorial.ts | 8 +- src/ScriptEditor/ui/ScriptEditorRoot.tsx | 4 +- src/ScriptEditor/ui/Toolbar.tsx | 18 ++++- src/Sidebar/ui/SidebarAccordion.tsx | 2 +- src/Sidebar/ui/SidebarItem.tsx | 12 +-- src/Sidebar/ui/SidebarRoot.tsx | 10 +-- .../InteractiveTutorialRoot.tsx | 78 +++++++++++++++---- 7 files changed, 93 insertions(+), 39 deletions(-) diff --git a/src/InteractiveTutorial.ts b/src/InteractiveTutorial.ts index 7014b2081f..ef298ca613 100644 --- a/src/InteractiveTutorial.ts +++ b/src/InteractiveTutorial.ts @@ -17,7 +17,9 @@ enum iTutorialSteps { TerminalHackingMechanics, // Explanation of hacking mechanics TerminalGoHome, // Go home before creating a script. TerminalCreateScript, // Create a script using 'nano' - TerminalEditScript, // Script Editor page - Edit script and then save & close + ScriptEditorEdit, // Script Editor page - Edit script and then save & close + ScriptEditorRam, + ScriptEditorGoToTerminal, TerminalFree, // Using 'Free' Terminal command TerminalRunScript, // Running script using 'run' Terminal command TerminalGoToActiveScriptsPage, @@ -60,7 +62,9 @@ const ITutorial = { [iTutorialSteps.TerminalHackingMechanics]: false, [iTutorialSteps.TerminalGoHome]: false, [iTutorialSteps.TerminalCreateScript]: false, - [iTutorialSteps.TerminalEditScript]: false, + [iTutorialSteps.ScriptEditorEdit]: false, + [iTutorialSteps.ScriptEditorRam]: false, + [iTutorialSteps.ScriptEditorGoToTerminal]: false, [iTutorialSteps.TerminalFree]: false, [iTutorialSteps.TerminalRunScript]: false, [iTutorialSteps.TerminalGoToActiveScriptsPage]: false, diff --git a/src/ScriptEditor/ui/ScriptEditorRoot.tsx b/src/ScriptEditor/ui/ScriptEditorRoot.tsx index 4964ca904f..44124ae465 100644 --- a/src/ScriptEditor/ui/ScriptEditorRoot.tsx +++ b/src/ScriptEditor/ui/ScriptEditorRoot.tsx @@ -195,7 +195,7 @@ function Root(props: IProps): React.ReactElement { const preSave = options.beautifyOnSave ? beautify : () => Promise.resolve(); // this is duplicate code with saving later. - if (ITutorial.isRunning && ITutorial.currStep === iTutorialSteps.TerminalEditScript) { + if (ITutorial.isRunning && ITutorial.currStep === iTutorialSteps.ScriptEditorEdit) { //Make sure filename + code properly follow tutorial if (currentScript.path !== tutorialScriptName) { dialogBoxCreate("Don't change the script name for now."); @@ -211,8 +211,6 @@ function Root(props: IProps): React.ReactElement { //Save the script await preSave(); saveScript(currentScript); - Router.toPage(Page.Terminal); - iTutorialNextStep(); return; diff --git a/src/ScriptEditor/ui/Toolbar.tsx b/src/ScriptEditor/ui/Toolbar.tsx index c7cd09a93f..575e94376c 100644 --- a/src/ScriptEditor/ui/Toolbar.tsx +++ b/src/ScriptEditor/ui/Toolbar.tsx @@ -26,6 +26,7 @@ import { DocumentationAutocomplete } from "../../Documentation/ui/DocumentationA import { openDocumentationPopUp } from "../../Documentation/root"; import { defaultNsApiPage, openDocExternally } from "../../ui/React/Documentation"; import { DocumentationLink } from "../../ui/React/DocumentationLink"; +import { iTutorialSteps, iTutorialNextStep, ITutorial } from "../../InteractiveTutorial"; type IStandaloneCodeEditor = monaco.editor.IStandaloneCodeEditor; @@ -70,14 +71,25 @@ export function Toolbar({ editor, onSave, onRun, onBeautify }: IProps) { Beautify
    - When you hack a server, you deplete its available money and increase its security level. Higher security levels make hacking slower and less effective. + When you hack a server, you deplete its available money and increase its security level. Higher security + levels make hacking slower and less effective.

    To restore things, you can use @@ -429,7 +430,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { ), canNext: false, }, - [iTutorialSteps.TerminalEditScript as number]: { + [iTutorialSteps.ScriptEditorEdit as number]: { content: ( <> @@ -451,35 +452,75 @@ export async function main(ns) {
    - When using scripts to hack a server, you don't need to be connected to the server. Scripts can target any - server, from any server. + When using scripts to hack, you don't need to be connected to the target server. Scripts can target any + server, no matter where you are.

    Almost everything we do in this tutorial can be scripted using functions available to you right away. To - check what functions there are, you can: + check what functions are available, you can:
    • use the search bar at the bottom
    • click the NS API documentation link
    - For now though, click Save at the bottom to save your script and close the editor. + For now though, click{" "} + + Save + {" "} + at the bottom.
    ), canNext: false, }, - [iTutorialSteps.TerminalFree as number]: { + [iTutorialSteps.ScriptEditorRam as number]: { content: ( <> - Now we'll run the script. + Scripts cost RAM to run.

    - You can run scripts on any server that you have root access to. + To see how much RAM this script costs, check the{" "} + + RAM + {" "} + button at the bottom.

    - Scripts need RAM to run. To check how much RAM is available on a machine, enter + You can also click the{" "} + + RAM + {" "} + button to see a breakdown of what's contributing to the RAM cost. +
    +
    + Try doing that now. +
    + + ), + canNext: false, + }, + [iTutorialSteps.ScriptEditorGoToTerminal as number]: { + content: ( + <> + + Now we know how much RAM we need, let's head back to the{" "} + + + Terminal + {" "} + to run our script. + + + ), + canNext: false, + }, + [iTutorialSteps.TerminalFree as number]: { + content: ( + <> + + To check how much RAM is available, enter

    @@ -492,10 +533,10 @@ export async function main(ns) { content: ( <> - We have 8GB of free RAM, enough to run our script. + You have 8GB of free RAM, enough to run your script.

    - We can do that using + You can run it using

    @@ -508,8 +549,11 @@ export async function main(ns) { content: ( <> - Your script is now running! Scripts run in the background until their code completes (if they have an - continuous loop, like {tutorialScriptName} does, they'll run indefinitely). + Your script is now running! +
    +
    + Scripts run in the background until their code completes (if they have an continuous loop, like{" "} + {tutorialScriptName} does, they'll run indefinitely).

    Scripts will passively earn you money and hacking exp. They even earn money and exp while you're offline, @@ -578,7 +622,7 @@ export async function main(ns) { content: ( <> - You can boost your earnings by running your scripts on other servers too. To do that, we need to copy them + You can run scripts on any server that you have root access to. To do that, you need to copy your scripts over.

    From 3e25daacce539a0ff5ae9347b554d3240b0c3625 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Wed, 2 Sep 2026 17:44:45 +0100 Subject: [PATCH 45/82] ELDRITCH THINGS --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index efcdeac43d..27a3665c94 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -380,7 +380,8 @@ export function InteractiveTutorialRoot(): React.ReactElement { {"[n00dles /]> weaken"}
    - which lowers the server's security level, speeding up hack, grow and weaken. + which lowers the server's security level. That actually speeds up grow and weaken too, and makes grow more + effective.
    ), From 81965b6c7cf7104e3be50bba4183f72a6052d467 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Wed, 2 Sep 2026 17:56:20 +0100 Subject: [PATCH 46/82] glarp --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 27a3665c94..600b7782fa 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -380,8 +380,8 @@ export function InteractiveTutorialRoot(): React.ReactElement { {"[n00dles /]> weaken"}
    - which lowers the server's security level. That actually speeds up grow and weaken too, and makes grow more - effective. + which lowers the server's security level. Lowering security speeds up not just hack but grow and weaken too, + and makes grow more effective.
    ), From 6f9d26221330f6a23cf5148c3199d3e57e46376a Mon Sep 17 00:00:00 2001 From: branchtheory Date: Wed, 2 Sep 2026 18:08:24 +0100 Subject: [PATCH 47/82] sheesh --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 600b7782fa..13b7b2207a 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -352,7 +352,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - You're now attempting to hack n00dles. If your hack is successful, you'll steal a percentage of n00dles' + You're now attempting to hack n00dles. If your hack is successful, you'll steal a percentage of its available money.

    @@ -380,8 +380,8 @@ export function InteractiveTutorialRoot(): React.ReactElement { {"[n00dles /]> weaken"}
    - which lowers the server's security level. Lowering security speeds up not just hack but grow and weaken too, - and makes grow more effective. + which lowers the server's security level. Lowering security helps grow and weaken too. It speeds them both + up, and makes grow more effective.
    ), From 33221d28269952de841dfd01741043fbb931678a Mon Sep 17 00:00:00 2001 From: branchtheory Date: Wed, 2 Sep 2026 18:19:51 +0100 Subject: [PATCH 48/82] ????? --- .../InteractiveTutorial/InteractiveTutorialRoot.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 13b7b2207a..1b0fd5d3ba 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -380,8 +380,10 @@ export function InteractiveTutorialRoot(): React.ReactElement { {"[n00dles /]> weaken"}
    - which lowers the server's security level. Lowering security helps grow and weaken too. It speeds them both - up, and makes grow more effective. + which lowers the server's security level. +
    +
    + Lowering security helps grow and weaken too. It speeds them both up, and makes grow more effective.
    ), @@ -624,10 +626,10 @@ export async function main(ns) { <> You can run scripts on any server that you have root access to. To do that, you need to copy your scripts - over. + over to it first.

    - First, let's see what files are stored on our home computer using + Before we do that, let's see what files are stored on our home computer using

    @@ -678,7 +680,7 @@ export async function main(ns) { Stats {" "} - tab + tab.
    ), From 203c9eb9daa57650141610279bcc6f0741466cdd Mon Sep 17 00:00:00 2001 From: branchtheory Date: Fri, 4 Sep 2026 02:12:09 +0100 Subject: [PATCH 49/82] basically done --- .../InteractiveTutorialRoot.tsx | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 1b0fd5d3ba..0eb562945f 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -302,7 +302,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { hacking skill of 1.

    - But there's something else we need too. To see what, let's run some diagnostics using + But there's something else we need as well. To see what, let's run some diagnostics using

    @@ -322,8 +322,8 @@ export function InteractiveTutorialRoot(): React.ReactElement { NUKE.exe will grant you root access to any machine as long as enough ports are open.

    - In the diagnostics, you'll also see that n00dles' "Required number of open ports for NUKE" is 0. So you're - good to run the virus. + In the diagnostics, you'll see that n00dles' "Required number of open ports for NUKE" is 0. So you're good + to run the virus.

    Just enter @@ -356,12 +356,10 @@ export function InteractiveTutorialRoot(): React.ReactElement { available money.

    - As your hacking skill increases, hacking will: -
      -
    • take less time
    • -
    • steal more money
    • -
    • have a higher success chance
    • -
    + As your hacking skill increases, hacking will take less time, steal more money, and have a higher success + chance. +
    +
    When you hack a server, you deplete its available money and increase its security level. Higher security levels make hacking slower and less effective.
    @@ -383,7 +381,8 @@ export function InteractiveTutorialRoot(): React.ReactElement { which lowers the server's security level.

    - Lowering security helps grow and weaken too. It speeds them both up, and makes grow more effective. + Lowering the security level helps grow and weaken too. It speeds them both up, and makes grow more + effective.
    ), @@ -495,7 +494,7 @@ export async function main(ns) { RAM {" "} - button to see a breakdown of what's contributing to the RAM cost. + button to see what's contributing to the RAM cost.

    Try doing that now. @@ -536,7 +535,7 @@ export async function main(ns) { content: ( <> - You have 8GB of free RAM, enough to run your script. + You have 8GB of free RAM, enough to run your script!

    You can run it using @@ -552,7 +551,7 @@ export async function main(ns) { content: ( <> - Your script is now running! + Your script is now running.

    Scripts run in the background until their code completes (if they have an continuous loop, like{" "} @@ -601,7 +600,7 @@ export async function main(ns) { content: ( <> - Each active script has logs that detail what it's doing. You can check these using the tail{" "} + Each active script has a log that details what it's doing. You can check these using the tail{" "} command. To do that for the script you just ran, enter

    @@ -625,11 +624,11 @@ export async function main(ns) { content: ( <> - You can run scripts on any server that you have root access to. To do that, you need to copy your scripts - over to it first. + You can run scripts on any servers that you have root access to. To do that, you first need to copy your + scripts over to them.

    - Before we do that, let's see what files are stored on our home computer using + Before that, let's check what files are stored on our home computer using

    @@ -725,8 +724,7 @@ export async function main(ns) { home computer.

    - There's a lot of other content out in the world, so make sure you explore and discover! Hacking may be the - core mechanic, but it's far from the only one. + There's a lot of other content out in the world, so make sure you explore and discover!

    Lastly, go to{" "} From c5a4832fa1690729e496018e000961cd71f6d800 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Fri, 4 Sep 2026 04:25:26 +0100 Subject: [PATCH 50/82] ready --- src/Documentation/ui/DocumentationRoot.tsx | 8 + src/InteractiveTutorial.ts | 17 +-- .../InteractiveTutorialRoot.tsx | 140 +----------------- 3 files changed, 18 insertions(+), 147 deletions(-) diff --git a/src/Documentation/ui/DocumentationRoot.tsx b/src/Documentation/ui/DocumentationRoot.tsx index 94767553ce..a5017c7450 100644 --- a/src/Documentation/ui/DocumentationRoot.tsx +++ b/src/Documentation/ui/DocumentationRoot.tsx @@ -16,6 +16,7 @@ import { Settings } from "../../Settings/Settings"; import { Router } from "../../ui/GameRoot"; import { Page } from "../../ui/Router"; import { DocumentationAutocomplete } from "./DocumentationAutocomplete"; +import { iTutorialSteps, ITutorial } from "../../InteractiveTutorial"; export function DocumentationRoot({ docPage }: { docPage?: string }): React.ReactElement { const history = useHistory(); @@ -48,6 +49,13 @@ export function DocumentationRoot({ docPage }: { docPage?: string }): React.Reac }; }, [history]); + useEffect(() => { + if (ITutorial.currStep === iTutorialSteps.DocumentationPageInfo) { + history.home(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); // only needs to run once per mount + useEffect(() => { if (!deepLink) { return; diff --git a/src/InteractiveTutorial.ts b/src/InteractiveTutorial.ts index ef298ca613..c4df3203ec 100644 --- a/src/InteractiveTutorial.ts +++ b/src/InteractiveTutorial.ts @@ -17,8 +17,8 @@ enum iTutorialSteps { TerminalHackingMechanics, // Explanation of hacking mechanics TerminalGoHome, // Go home before creating a script. TerminalCreateScript, // Create a script using 'nano' - ScriptEditorEdit, // Script Editor page - Edit script and then save & close - ScriptEditorRam, + ScriptEditorEdit, // Script Editor page - Edit script + ScriptEditorRam, // Script Editor page - Check RAM usage ScriptEditorGoToTerminal, TerminalFree, // Using 'Free' Terminal command TerminalRunScript, // Running script using 'run' Terminal command @@ -30,11 +30,9 @@ enum iTutorialSteps { TerminalScp, // using the 'scp' Terminal command TerminalHelp, // Using 'help' Terminal command - // See the results of our hacking + // Finishing off GoToCharacterPage, // Click on 'Stats' page CharacterPage, // Introduction to 'Stats' page - - // Finishing off GoToWorldPage, WorldDescription, DocumentationPageInfo, @@ -48,10 +46,7 @@ const ITutorial = { // Keeps track of whether each step has been done stepIsDone: { [iTutorialSteps.Start]: false, - [iTutorialSteps.GoToCharacterPage]: false, - [iTutorialSteps.CharacterPage]: false, - [iTutorialSteps.TerminalHelp]: false, - [iTutorialSteps.TerminalLs]: false, + [iTutorialSteps.TerminalScan]: false, [iTutorialSteps.TerminalScanAnalyze1]: false, [iTutorialSteps.TerminalScanAnalyze2]: false, @@ -71,7 +66,11 @@ const ITutorial = { [iTutorialSteps.ActiveScriptsPage]: false, [iTutorialSteps.ActiveScriptsToTerminal]: false, [iTutorialSteps.TerminalTailScript]: false, + [iTutorialSteps.TerminalLs]: false, [iTutorialSteps.TerminalScp]: false, + [iTutorialSteps.TerminalHelp]: false, + [iTutorialSteps.GoToCharacterPage]: false, + [iTutorialSteps.CharacterPage]: false, [iTutorialSteps.GoToWorldPage]: false, [iTutorialSteps.WorldDescription]: false, [iTutorialSteps.DocumentationPageInfo]: false, diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 0eb562945f..4011fc6585 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -1,139 +1,3 @@ -/* - - -Return docs to the home screen when moving to the docs tab. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ - import React, { useEffect } from "react"; import { Paper, Box, Typography, Button, Link } from "@mui/material"; @@ -600,8 +464,8 @@ export async function main(ns) { content: ( <> - Each active script has a log that details what it's doing. You can check these using the tail{" "} - command. To do that for the script you just ran, enter + Each active script has a log that details what it's doing. You can check these using the tail command. To do + that for the script you just ran, enter

    From cc66147462f6522a475ec0239dc98b295627ca39 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Fri, 4 Sep 2026 05:19:25 +0100 Subject: [PATCH 51/82] infelicities ejected --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 4011fc6585..aad1195289 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -179,8 +179,8 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - If you look, you can see that n00dles' "Root Access" status is "NO". You must gain root access before you - can hack a server. Handily, you've built a virus called NUKE.exe. + If you look, you can see that n00dles' "Root Access" status is NO . You must gain root access before you can + hack a server. Handily, you've built a virus called NUKE.exe.

    NUKE.exe will grant you root access to any machine as long as enough ports are open. @@ -216,7 +216,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - You're now attempting to hack n00dles. If your hack is successful, you'll steal a percentage of its + You're now attempting to hack n00dles. If your hack is successful, you'll steal a percentage of the server's available money.

    @@ -492,7 +492,7 @@ export async function main(ns) { scripts over to them.

    - Before that, let's check what files are stored on our home computer using + Let's check what files are stored on our home computer using

    From 5375ddeafe3384a92eb4b9b9a32e383b14a94315 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Fri, 4 Sep 2026 05:27:46 +0100 Subject: [PATCH 52/82] readier --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index aad1195289..8ff60483e1 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -179,8 +179,8 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - If you look, you can see that n00dles' "Root Access" status is NO . You must gain root access before you can - hack a server. Handily, you've built a virus called NUKE.exe. + If you look, you can see that n00dles' "Root Access" status is "NO". You must gain root access before you + can hack a server. Handily, you've built a virus called NUKE.exe.

    NUKE.exe will grant you root access to any machine as long as enough ports are open. From a63660a7f526a25a19926642414f3ff05a2ac55d Mon Sep 17 00:00:00 2001 From: branchtheory Date: Fri, 4 Sep 2026 05:31:29 +0100 Subject: [PATCH 53/82] . --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 8ff60483e1..36f27c5fa7 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -186,11 +186,10 @@ export function InteractiveTutorialRoot(): React.ReactElement { NUKE.exe will grant you root access to any machine as long as enough ports are open.

    - In the diagnostics, you'll see that n00dles' "Required number of open ports for NUKE" is 0. So you're good - to run the virus. + In the diagnostics, you'll see that n00dles' "Required number of open ports for NUKE" is 0.

    - Just enter + So you're good to run the virus. Just enter

    From 0f4fdf8e3b7a58d1c3ea384aeaf727c113450891 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Fri, 4 Sep 2026 09:17:02 +0100 Subject: [PATCH 54/82] prettier --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 36f27c5fa7..2e73b33992 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -186,7 +186,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { NUKE.exe will grant you root access to any machine as long as enough ports are open.

    - In the diagnostics, you'll see that n00dles' "Required number of open ports for NUKE" is 0. + In the diagnostics, you'll see that n00dles' "Required number of open ports for NUKE" is 0.

    So you're good to run the virus. Just enter From a0ab610986dba4b76af878d9ff4dcaa57a1dadbc Mon Sep 17 00:00:00 2001 From: branchtheory Date: Fri, 4 Sep 2026 10:04:28 +0100 Subject: [PATCH 55/82] moved grow.ts and weaken.ts changes into a separate PR --- src/Terminal/commands/grow.ts | 9 ++++----- src/Terminal/commands/weaken.ts | 5 ++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Terminal/commands/grow.ts b/src/Terminal/commands/grow.ts index c1fe14cb47..e769d43054 100644 --- a/src/Terminal/commands/grow.ts +++ b/src/Terminal/commands/grow.ts @@ -4,7 +4,7 @@ import { BaseServer } from "../../Server/BaseServer"; import { Server } from "../../Server/Server"; import { HacknetServer } from "../../Hacknet/HacknetServer"; import { Player } from "@player"; -import { formatExp, formatPercent, formatSecurity, formatMoney } from "../../ui/formatNumber"; +import { formatExp, formatPercent, formatSecurity } from "../../ui/formatNumber"; import { calculateHackingExpGain, calculateGrowTime } from "../../Hacking"; import { processSingleServerGrowth } from "../../Server/ServerHelpers"; @@ -26,13 +26,12 @@ export function grow(args: (string | number | boolean)[], server: BaseServer): u const oldSec = server.hackDifficulty; const growth = processSingleServerGrowth(server, 25, server.cpuCores); const newSec = server.hackDifficulty; - const newMoney = server.moneyAvailable; Player.gainHackingExp(expGain); Terminal.print( - `Available money on '${server.hostname}' grown by ${formatPercent(growth - 1, 6)} to ${formatMoney( - newMoney, - )}. Gained ${formatExp(expGain)} hacking exp.`, + `Available money on '${server.hostname}' grown by ${formatPercent(growth - 1, 6)}. Gained ${formatExp( + expGain, + )} hacking exp.`, ); Terminal.print( `Security increased on '${server.hostname}' from ${formatSecurity(oldSec)} to ${formatSecurity(newSec)}`, diff --git a/src/Terminal/commands/weaken.ts b/src/Terminal/commands/weaken.ts index c8479b4729..c212331d29 100644 --- a/src/Terminal/commands/weaken.ts +++ b/src/Terminal/commands/weaken.ts @@ -32,9 +32,8 @@ export function weaken(args: (string | number | boolean)[], server: BaseServer): Terminal.print( `Security decreased on '${server.hostname}' by ${formatSecurity(weakenAmt)} from ${formatSecurity( oldSec, - )} to ${formatSecurity(newSec)} (min: ${formatSecurity(server.minDifficulty)}). Gained ${formatExp( - expGain, - )} hacking exp`, + )} to ${formatSecurity(newSec)} (min: ${formatSecurity(server.minDifficulty)})` + + ` and Gained ${formatExp(expGain)} hacking exp.`, ); }); } From 8e2aae6d2a46eb6b3b60f0783f66c5e992d65bcc Mon Sep 17 00:00:00 2001 From: branchtheory Date: Fri, 4 Sep 2026 10:46:51 +0100 Subject: [PATCH 56/82] keeping up with the refactor --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 2e73b33992..91ec2a32d1 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -20,7 +20,6 @@ import { iTutorialEnd, } from "../../InteractiveTutorial"; import { useRerender } from "../React/hooks"; -import { Settings } from "../../Settings/Settings"; import { DocumentationLink } from "../React/DocumentationLink"; import { defaultNsApiPage } from "../React/Documentation"; @@ -629,7 +628,7 @@ export async function main(ns) { Mac keyboard). If you're playing the Steam version, doing that will open the link in your default browser.

    - + Note: The documentation at readthedocs is outdated and unmaintained. Do not use it!
    @@ -638,7 +637,7 @@ export async function main(ns) { href="https://discord.com/channels/415207508303544321/415207508303544323" underline="always" target="_blank" - color={Settings.theme.info} + sx={{ color: "info.main" }} > ask us on Discord From 8bd6f9f569c6e53c77ac6a9460afb7e3e5f5a0b7 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Fri, 4 Sep 2026 16:43:41 +0100 Subject: [PATCH 57/82] Explained the purpose of the DocumentationRoot useEffect --- src/Documentation/ui/DocumentationRoot.tsx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/Documentation/ui/DocumentationRoot.tsx b/src/Documentation/ui/DocumentationRoot.tsx index a5017c7450..8fce2455bc 100644 --- a/src/Documentation/ui/DocumentationRoot.tsx +++ b/src/Documentation/ui/DocumentationRoot.tsx @@ -49,13 +49,6 @@ export function DocumentationRoot({ docPage }: { docPage?: string }): React.Reac }; }, [history]); - useEffect(() => { - if (ITutorial.currStep === iTutorialSteps.DocumentationPageInfo) { - history.home(); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); // only needs to run once per mount - useEffect(() => { if (!deepLink) { return; @@ -78,6 +71,18 @@ export function DocumentationRoot({ docPage }: { docPage?: string }): React.Reac }, 0); }); + /** + * During the tutorial, the player is given the link to the NS API page a few times. If they click one of the links, + * then when they come to the documentation step they'll still see the NS API docs. This ensures that when the player + * visits the documentation page for the Docs step, they see index.md / home. + */ + useEffect(() => { + if (ITutorial.currStep === iTutorialSteps.DocumentationPageInfo) { + history.home(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); // Lint doesn't like empty dependencies. But this really should only run on the first render. + return ( <> Date: Fri, 4 Sep 2026 17:30:55 +0100 Subject: [PATCH 58/82] prettier griefing me again --- src/Documentation/ui/DocumentationRoot.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Documentation/ui/DocumentationRoot.tsx b/src/Documentation/ui/DocumentationRoot.tsx index 8fce2455bc..ca983411aa 100644 --- a/src/Documentation/ui/DocumentationRoot.tsx +++ b/src/Documentation/ui/DocumentationRoot.tsx @@ -72,16 +72,18 @@ export function DocumentationRoot({ docPage }: { docPage?: string }): React.Reac }); /** - * During the tutorial, the player is given the link to the NS API page a few times. If they click one of the links, - * then when they come to the documentation step they'll still see the NS API docs. This ensures that when the player + * During the tutorial, the player is given the link to the NS API page a few times. If they click one of the links, + * then when they come to the documentation step they'll still see the NS API docs. This ensures that when the player * visits the documentation page for the Docs step, they see index.md / home. - */ + */ useEffect(() => { if (ITutorial.currStep === iTutorialSteps.DocumentationPageInfo) { history.home(); } + + // Lint doesn't like empty dependencies. But this really should only run on the first render. So: // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); // Lint doesn't like empty dependencies. But this really should only run on the first render. + }, []); return ( <> From 7533f0fddd88b8b1b1271ee7a4b1d3159231ef43 Mon Sep 17 00:00:00 2001 From: branchtheory <97463314+branchtheory@users.noreply.github.com> Date: Sat, 5 Sep 2026 10:48:18 +0100 Subject: [PATCH 59/82] Reworded variable for precision --- src/Sidebar/ui/SidebarRoot.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Sidebar/ui/SidebarRoot.tsx b/src/Sidebar/ui/SidebarRoot.tsx index 601891af70..9eff5ae89a 100644 --- a/src/Sidebar/ui/SidebarRoot.tsx +++ b/src/Sidebar/ui/SidebarRoot.tsx @@ -127,15 +127,15 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement { useCycleRerender(); let flash: Page | null = null; - let shouldIncrementTutorial = false; + let incrementTutorialStep = false; switch (ITutorial.currStep) { case iTutorialSteps.ActiveScriptsPage: flash = Page.Terminal; - shouldIncrementTutorial = true; + incrementTutorialStep = true; break; case iTutorialSteps.TerminalGoToActiveScriptsPage: flash = Page.ActiveScripts; - shouldIncrementTutorial = true; + incrementTutorialStep = true; break; case iTutorialSteps.ScriptEditorEdit: if (props.page !== Page.ScriptEditor) { @@ -144,19 +144,19 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement { break; case iTutorialSteps.ScriptEditorGoToTerminal: flash = Page.Terminal; - shouldIncrementTutorial = true; + incrementTutorialStep = true; break; case iTutorialSteps.GoToCharacterPage: flash = Page.Stats; - shouldIncrementTutorial = true; + incrementTutorialStep = true; break; case iTutorialSteps.GoToWorldPage: flash = Page.City; - shouldIncrementTutorial = true; + incrementTutorialStep = true; break; case iTutorialSteps.WorldDescription: flash = Page.Documentation; - shouldIncrementTutorial = true; + incrementTutorialStep = true; break; } @@ -205,7 +205,7 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement { } else { throw new Error("Can't handle click on Page " + page); } - if (flash === page && shouldIncrementTutorial) { + if (flash === page && incrementTutorialStep) { iTutorialNextStep(); } }, From bb308a9a4ebe033e6b6e1b92c4d96e888a50731b Mon Sep 17 00:00:00 2001 From: branchtheory <97463314+branchtheory@users.noreply.github.com> Date: Sat, 5 Sep 2026 10:59:47 +0100 Subject: [PATCH 60/82] Missed a reference --- src/Sidebar/ui/SidebarRoot.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Sidebar/ui/SidebarRoot.tsx b/src/Sidebar/ui/SidebarRoot.tsx index 9eff5ae89a..1e0955450e 100644 --- a/src/Sidebar/ui/SidebarRoot.tsx +++ b/src/Sidebar/ui/SidebarRoot.tsx @@ -209,7 +209,7 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement { iTutorialNextStep(); } }, - [flash, shouldIncrementTutorial], + [flash, incrementTutorialStep], ); /** From 7af815c2befc65c559ecdaa100ea05363d530dae Mon Sep 17 00:00:00 2001 From: branchtheory Date: Mon, 7 Sep 2026 19:27:17 +0100 Subject: [PATCH 61/82] My vision is augmented. --- src/Documentation/ui/DocumentationRoot.tsx | 2 +- src/InteractiveTutorial.ts | 82 +++++++++---------- src/ScriptEditor/ui/ScriptEditorRoot.tsx | 2 +- src/ScriptEditor/ui/Toolbar.tsx | 2 +- src/Sidebar/ui/SidebarRoot.tsx | 8 +- src/Terminal/Terminal.ts | 20 ++--- src/ui/ActiveScripts/ServerAccordion.tsx | 15 +++- .../ActiveScripts/WorkerScriptAccordion.tsx | 9 +- .../InteractiveTutorialRoot.tsx | 46 ++++++----- 9 files changed, 107 insertions(+), 79 deletions(-) diff --git a/src/Documentation/ui/DocumentationRoot.tsx b/src/Documentation/ui/DocumentationRoot.tsx index ca983411aa..4a990dd2fe 100644 --- a/src/Documentation/ui/DocumentationRoot.tsx +++ b/src/Documentation/ui/DocumentationRoot.tsx @@ -77,7 +77,7 @@ export function DocumentationRoot({ docPage }: { docPage?: string }): React.Reac * visits the documentation page for the Docs step, they see index.md / home. */ useEffect(() => { - if (ITutorial.currStep === iTutorialSteps.DocumentationPageInfo) { + if (ITutorial.currStep === iTutorialSteps.DocumenationExplanation) { history.home(); } diff --git a/src/InteractiveTutorial.ts b/src/InteractiveTutorial.ts index c4df3203ec..1177fa35bd 100644 --- a/src/InteractiveTutorial.ts +++ b/src/InteractiveTutorial.ts @@ -4,39 +4,40 @@ import { ITutorialEvents } from "./ui/InteractiveTutorial/ITutorialEvents"; // Ordered array of keys to Interactive Tutorial Steps enum iTutorialSteps { - Start, + Start, // Intro, overview, and housekeeping // Hacking - TerminalScan, // Using 'scan' Terminal command - TerminalScanAnalyze1, // Using 'scan-analyze' Terminal command - TerminalScanAnalyze2, // Using 'scan-analyze 3' Terminal command - TerminalConnect, // Connecting to n00dles - TerminalAnalyze, // Analyzing n00dles - TerminalNuke, // NUKE n00dles - TerminalManualHack, // Hack n00dles - TerminalHackingMechanics, // Explanation of hacking mechanics - TerminalGoHome, // Go home before creating a script. - TerminalCreateScript, // Create a script using 'nano' - ScriptEditorEdit, // Script Editor page - Edit script - ScriptEditorRam, // Script Editor page - Check RAM usage + TerminalScan, + TerminalScanAnalyze, + TerminalScanAnalyze2, + TerminalConnectN00dles, + TerminalAnalyze, + TerminalNuke, + TerminalManualHack, + TerminalHackWeakenGrowMechanics, + TerminalHome, + TerminalNano, + ScriptEditorEditAndSave, + ScriptEditorRam, ScriptEditorGoToTerminal, - TerminalFree, // Using 'Free' Terminal command - TerminalRunScript, // Running script using 'run' Terminal command - TerminalGoToActiveScriptsPage, - ActiveScriptsPage, - ActiveScriptsToTerminal, - TerminalTailScript, - TerminalLs, // Using 'ls' Terminal command - TerminalScp, // using the 'scp' Terminal command - TerminalHelp, // Using 'help' Terminal command + TerminalFree, + TerminalRunScript, + TerminalGoToActiveScriptsPage, // Also explains a bit about running scripts + ActiveScriptsExplanation, + TerminalTail, + TerminalTailOutcome, + TerminalLs, + TerminalScp, + TerminalHelp, // Finishing off - GoToCharacterPage, // Click on 'Stats' page - CharacterPage, // Introduction to 'Stats' page - GoToWorldPage, + TerminalGoToCharacterStats, + CharacterStatsExplanation, + CharacterStatsGoToWorld, WorldDescription, - DocumentationPageInfo, - End, + DocumenationExplanation, + + End, // Empty step not seen by players. Powers the logic in iTutorialNextStep. } const ITutorial = { @@ -46,34 +47,33 @@ const ITutorial = { // Keeps track of whether each step has been done stepIsDone: { [iTutorialSteps.Start]: false, - [iTutorialSteps.TerminalScan]: false, - [iTutorialSteps.TerminalScanAnalyze1]: false, + [iTutorialSteps.TerminalScanAnalyze]: false, [iTutorialSteps.TerminalScanAnalyze2]: false, - [iTutorialSteps.TerminalConnect]: false, + [iTutorialSteps.TerminalConnectN00dles]: false, [iTutorialSteps.TerminalAnalyze]: false, [iTutorialSteps.TerminalNuke]: false, [iTutorialSteps.TerminalManualHack]: false, - [iTutorialSteps.TerminalHackingMechanics]: false, - [iTutorialSteps.TerminalGoHome]: false, - [iTutorialSteps.TerminalCreateScript]: false, - [iTutorialSteps.ScriptEditorEdit]: false, + [iTutorialSteps.TerminalHackWeakenGrowMechanics]: false, + [iTutorialSteps.TerminalHome]: false, + [iTutorialSteps.TerminalNano]: false, + [iTutorialSteps.ScriptEditorEditAndSave]: false, [iTutorialSteps.ScriptEditorRam]: false, [iTutorialSteps.ScriptEditorGoToTerminal]: false, [iTutorialSteps.TerminalFree]: false, [iTutorialSteps.TerminalRunScript]: false, [iTutorialSteps.TerminalGoToActiveScriptsPage]: false, - [iTutorialSteps.ActiveScriptsPage]: false, - [iTutorialSteps.ActiveScriptsToTerminal]: false, - [iTutorialSteps.TerminalTailScript]: false, + [iTutorialSteps.ActiveScriptsExplanation]: false, + [iTutorialSteps.TerminalTail]: false, + [iTutorialSteps.TerminalTailOutcome]: false, [iTutorialSteps.TerminalLs]: false, [iTutorialSteps.TerminalScp]: false, [iTutorialSteps.TerminalHelp]: false, - [iTutorialSteps.GoToCharacterPage]: false, - [iTutorialSteps.CharacterPage]: false, - [iTutorialSteps.GoToWorldPage]: false, + [iTutorialSteps.TerminalGoToCharacterStats]: false, + [iTutorialSteps.CharacterStatsExplanation]: false, + [iTutorialSteps.CharacterStatsGoToWorld]: false, [iTutorialSteps.WorldDescription]: false, - [iTutorialSteps.DocumentationPageInfo]: false, + [iTutorialSteps.DocumenationExplanation]: false, [iTutorialSteps.End]: false, }, }; diff --git a/src/ScriptEditor/ui/ScriptEditorRoot.tsx b/src/ScriptEditor/ui/ScriptEditorRoot.tsx index 44124ae465..b395bdb26a 100644 --- a/src/ScriptEditor/ui/ScriptEditorRoot.tsx +++ b/src/ScriptEditor/ui/ScriptEditorRoot.tsx @@ -195,7 +195,7 @@ function Root(props: IProps): React.ReactElement { const preSave = options.beautifyOnSave ? beautify : () => Promise.resolve(); // this is duplicate code with saving later. - if (ITutorial.isRunning && ITutorial.currStep === iTutorialSteps.ScriptEditorEdit) { + if (ITutorial.isRunning && ITutorial.currStep === iTutorialSteps.ScriptEditorEditAndSave) { //Make sure filename + code properly follow tutorial if (currentScript.path !== tutorialScriptName) { dialogBoxCreate("Don't change the script name for now."); diff --git a/src/ScriptEditor/ui/Toolbar.tsx b/src/ScriptEditor/ui/Toolbar.tsx index 575e94376c..cfb007b3ba 100644 --- a/src/ScriptEditor/ui/Toolbar.tsx +++ b/src/ScriptEditor/ui/Toolbar.tsx @@ -89,7 +89,7 @@ export function Toolbar({ editor, onSave, onRun, onBeautify }: IProps) { From d94a062dcf15e6f54dc94bb46e5844540abe0519 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Mon, 7 Sep 2026 20:04:40 +0100 Subject: [PATCH 62/82] Finito --- src/Documentation/ui/DocumentationRoot.tsx | 2 +- src/InteractiveTutorial.ts | 28 +++++++++---------- src/Sidebar/ui/SidebarRoot.tsx | 8 +++--- src/Terminal/Terminal.ts | 2 +- src/ui/ActiveScripts/ServerAccordion.tsx | 2 +- .../ActiveScripts/WorkerScriptAccordion.tsx | 2 +- .../InteractiveTutorialRoot.tsx | 18 ++++++------ 7 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/Documentation/ui/DocumentationRoot.tsx b/src/Documentation/ui/DocumentationRoot.tsx index 4a990dd2fe..7bcf3aed50 100644 --- a/src/Documentation/ui/DocumentationRoot.tsx +++ b/src/Documentation/ui/DocumentationRoot.tsx @@ -77,7 +77,7 @@ export function DocumentationRoot({ docPage }: { docPage?: string }): React.Reac * visits the documentation page for the Docs step, they see index.md / home. */ useEffect(() => { - if (ITutorial.currStep === iTutorialSteps.DocumenationExplanation) { + if (ITutorial.currStep === iTutorialSteps.DocumentationInfo) { history.home(); } diff --git a/src/InteractiveTutorial.ts b/src/InteractiveTutorial.ts index 1177fa35bd..e45168e1f4 100644 --- a/src/InteractiveTutorial.ts +++ b/src/InteractiveTutorial.ts @@ -10,7 +10,7 @@ enum iTutorialSteps { TerminalScan, TerminalScanAnalyze, TerminalScanAnalyze2, - TerminalConnectN00dles, + TerminalConnect, TerminalAnalyze, TerminalNuke, TerminalManualHack, @@ -19,11 +19,11 @@ enum iTutorialSteps { TerminalNano, ScriptEditorEditAndSave, ScriptEditorRam, - ScriptEditorGoToTerminal, + ScriptEditorGoToTerminalPage, TerminalFree, TerminalRunScript, TerminalGoToActiveScriptsPage, // Also explains a bit about running scripts - ActiveScriptsExplanation, + ActiveScriptsDescription, TerminalTail, TerminalTailOutcome, TerminalLs, @@ -31,11 +31,11 @@ enum iTutorialSteps { TerminalHelp, // Finishing off - TerminalGoToCharacterStats, - CharacterStatsExplanation, - CharacterStatsGoToWorld, + TerminalGoToCharacterStatsPage, + CharacterStatsDescription, + CharacterStatsGoToWorldPage, WorldDescription, - DocumenationExplanation, + DocumentationInfo, End, // Empty step not seen by players. Powers the logic in iTutorialNextStep. } @@ -50,7 +50,7 @@ const ITutorial = { [iTutorialSteps.TerminalScan]: false, [iTutorialSteps.TerminalScanAnalyze]: false, [iTutorialSteps.TerminalScanAnalyze2]: false, - [iTutorialSteps.TerminalConnectN00dles]: false, + [iTutorialSteps.TerminalConnect]: false, [iTutorialSteps.TerminalAnalyze]: false, [iTutorialSteps.TerminalNuke]: false, [iTutorialSteps.TerminalManualHack]: false, @@ -59,21 +59,21 @@ const ITutorial = { [iTutorialSteps.TerminalNano]: false, [iTutorialSteps.ScriptEditorEditAndSave]: false, [iTutorialSteps.ScriptEditorRam]: false, - [iTutorialSteps.ScriptEditorGoToTerminal]: false, + [iTutorialSteps.ScriptEditorGoToTerminalPage]: false, [iTutorialSteps.TerminalFree]: false, [iTutorialSteps.TerminalRunScript]: false, [iTutorialSteps.TerminalGoToActiveScriptsPage]: false, - [iTutorialSteps.ActiveScriptsExplanation]: false, + [iTutorialSteps.ActiveScriptsDescription]: false, [iTutorialSteps.TerminalTail]: false, [iTutorialSteps.TerminalTailOutcome]: false, [iTutorialSteps.TerminalLs]: false, [iTutorialSteps.TerminalScp]: false, [iTutorialSteps.TerminalHelp]: false, - [iTutorialSteps.TerminalGoToCharacterStats]: false, - [iTutorialSteps.CharacterStatsExplanation]: false, - [iTutorialSteps.CharacterStatsGoToWorld]: false, + [iTutorialSteps.TerminalGoToCharacterStatsPage]: false, + [iTutorialSteps.CharacterStatsDescription]: false, + [iTutorialSteps.CharacterStatsGoToWorldPage]: false, [iTutorialSteps.WorldDescription]: false, - [iTutorialSteps.DocumenationExplanation]: false, + [iTutorialSteps.DocumentationInfo]: false, [iTutorialSteps.End]: false, }, }; diff --git a/src/Sidebar/ui/SidebarRoot.tsx b/src/Sidebar/ui/SidebarRoot.tsx index 33c477085b..05045c4703 100644 --- a/src/Sidebar/ui/SidebarRoot.tsx +++ b/src/Sidebar/ui/SidebarRoot.tsx @@ -129,7 +129,7 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement { let flash: Page | null = null; let incrementTutorialStep = false; switch (ITutorial.currStep) { - case iTutorialSteps.ActiveScriptsExplanation: + case iTutorialSteps.ActiveScriptsDescription: flash = Page.Terminal; incrementTutorialStep = true; break; @@ -142,15 +142,15 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement { flash = Page.ScriptEditor; } break; - case iTutorialSteps.ScriptEditorGoToTerminal: + case iTutorialSteps.ScriptEditorGoToTerminalPage: flash = Page.Terminal; incrementTutorialStep = true; break; - case iTutorialSteps.TerminalGoToCharacterStats: + case iTutorialSteps.TerminalGoToCharacterStatsPage: flash = Page.Stats; incrementTutorialStep = true; break; - case iTutorialSteps.CharacterStatsGoToWorld: + case iTutorialSteps.CharacterStatsGoToWorldPage: flash = Page.City; incrementTutorialStep = true; break; diff --git a/src/Terminal/Terminal.ts b/src/Terminal/Terminal.ts index 1c1292c610..d8630bf713 100644 --- a/src/Terminal/Terminal.ts +++ b/src/Terminal/Terminal.ts @@ -393,7 +393,7 @@ export class Terminal { return; } break; - case iTutorialSteps.TerminalConnectN00dles: + case iTutorialSteps.TerminalConnect: if (commandArray[0] === "connect") { if ( commandArray.length === 2 && diff --git a/src/ui/ActiveScripts/ServerAccordion.tsx b/src/ui/ActiveScripts/ServerAccordion.tsx index 69a6c907b4..3e6d77f9cb 100644 --- a/src/ui/ActiveScripts/ServerAccordion.tsx +++ b/src/ui/ActiveScripts/ServerAccordion.tsx @@ -43,7 +43,7 @@ export function ServerAccordion({ server, scripts, startOpen }: ServerAccordionP {headerTxt} diff --git a/src/ui/ActiveScripts/WorkerScriptAccordion.tsx b/src/ui/ActiveScripts/WorkerScriptAccordion.tsx index 300cb683cf..ed97bace51 100644 --- a/src/ui/ActiveScripts/WorkerScriptAccordion.tsx +++ b/src/ui/ActiveScripts/WorkerScriptAccordion.tsx @@ -73,7 +73,7 @@ export function WorkerScriptAccordion(props: IProps): React.ReactElement { └ {props.workerScript.name} ({formatRam(scriptRef.ramUsage * scriptRef.threads)}){" "} diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 489b3ecf54..f90a37de71 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -130,7 +130,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { ), canNext: false, }, - [iTutorialSteps.TerminalConnectN00dles as number]: { + [iTutorialSteps.TerminalConnect as number]: { content: ( <> @@ -365,7 +365,7 @@ export async function main(ns) { ), canNext: false, }, - [iTutorialSteps.ScriptEditorGoToTerminal as number]: { + [iTutorialSteps.ScriptEditorGoToTerminalPage as number]: { content: ( <> @@ -434,7 +434,7 @@ export async function main(ns) { ), canNext: false, }, - [iTutorialSteps.ActiveScriptsExplanation as number]: { + [iTutorialSteps.ActiveScriptsDescription as number]: { content: ( <> @@ -540,7 +540,7 @@ export async function main(ns) { ), canNext: false, }, - [iTutorialSteps.TerminalGoToCharacterStats as number]: { + [iTutorialSteps.TerminalGoToCharacterStatsPage as number]: { content: ( <> @@ -555,7 +555,7 @@ export async function main(ns) { ), canNext: false, }, - [iTutorialSteps.CharacterStatsExplanation as number]: { + [iTutorialSteps.CharacterStatsDescription as number]: { content: ( <> @@ -569,7 +569,7 @@ export async function main(ns) { ), canNext: true, }, - [iTutorialSteps.CharacterStatsGoToWorld as number]: { + [iTutorialSteps.CharacterStatsGoToWorldPage as number]: { content: ( <> @@ -607,7 +607,7 @@ export async function main(ns) { ), canNext: false, }, - [iTutorialSteps.DocumenationExplanation as number]: { + [iTutorialSteps.DocumentationInfo as number]: { content: ( These pages explain the game's content and mechanics. I know it's a lot, but I highly suggest you read (or at @@ -676,7 +676,7 @@ export async function main(ns) { {content.content}
    - {step !== iTutorialSteps.DocumenationExplanation && ( + {step !== iTutorialSteps.DocumentationInfo && ( <> {step !== iTutorialSteps.Start && (
    From 82f06e47fafb03b1cffc0d19835b9955578a74c7 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Mon, 7 Sep 2026 23:42:07 +0100 Subject: [PATCH 63/82] last minute fix of a last minute fix --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index f90a37de71..f1709fb8c7 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -161,8 +161,8 @@ export function InteractiveTutorialRoot(): React.ReactElement { servers and computers. Using specialised skills, you can hack servers to steal money and gain experience.

    - You've got the hacking skill needed to hack n00dles – if you check scan-analyze, you'll see n00dles has a - required hacking skill of 1. + You've got the hacking skill needed to hack n00dles – scan-analyze shows us that n00dles has a "Required + hacking skill" of 1.

    But there's something else we need as well. To see what, let's run some diagnostics using From d7f77862ec1afabad54f6596eacf77d0e16ae61e Mon Sep 17 00:00:00 2001 From: branchtheory Date: Tue, 8 Sep 2026 08:18:02 +0100 Subject: [PATCH 64/82] Refactored out 'styled' --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index f1709fb8c7..c330de1412 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -10,7 +10,6 @@ import LastPageIcon from "@mui/icons-material/LastPage"; import HelpIcon from "@mui/icons-material/Help"; import StorageIcon from "@mui/icons-material/Storage"; import LocationCityIcon from "@mui/icons-material/LocationCity"; -import { styled } from "@mui/material/styles"; import { iTutorialPrevStep, @@ -23,6 +22,12 @@ import { useRerender } from "../React/hooks"; import { DocumentationLink } from "../React/DocumentationLink"; import { defaultNsApiPage } from "../React/Documentation"; +function TerminalText({ children }: { children: React.ReactNode }): React.ReactElement { + return ( + `1px solid ${theme.palette.primary.main}` }}>{children} + ); +} + interface IContent { content: React.ReactElement; canNext: boolean; @@ -31,9 +36,6 @@ interface IContent { export const tutorialScriptName = `hacking.js`; export function InteractiveTutorialRoot(): React.ReactElement { - const TerminalText = styled(Typography)(({ theme }) => ({ - borderBottom: `1px solid ${theme.palette.primary.main}`, - })); const rerender = useRerender(); const contents: Record = { From 03349f8b525d427b2d9c968cfcf35b9d0177dc80 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Tue, 8 Sep 2026 08:35:27 +0100 Subject: [PATCH 65/82] easier reviewing order --- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index c330de1412..b2ab7a3bdd 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -22,17 +22,17 @@ import { useRerender } from "../React/hooks"; import { DocumentationLink } from "../React/DocumentationLink"; import { defaultNsApiPage } from "../React/Documentation"; +interface IContent { + content: React.ReactElement; + canNext: boolean; +} + function TerminalText({ children }: { children: React.ReactNode }): React.ReactElement { return ( `1px solid ${theme.palette.primary.main}` }}>{children} ); } -interface IContent { - content: React.ReactElement; - canNext: boolean; -} - export const tutorialScriptName = `hacking.js`; export function InteractiveTutorialRoot(): React.ReactElement { From e64a7dfc1abe506d2c9255ff3872c400bdf6910e Mon Sep 17 00:00:00 2001 From: branchtheory Date: Tue, 8 Sep 2026 14:29:07 +0100 Subject: [PATCH 66/82] Much cleaner handling of bad terminal commands --- src/Terminal/Terminal.ts | 210 ++++++++++++++------------------------- 1 file changed, 73 insertions(+), 137 deletions(-) diff --git a/src/Terminal/Terminal.ts b/src/Terminal/Terminal.ts index d8630bf713..2163d169a7 100644 --- a/src/Terminal/Terminal.ts +++ b/src/Terminal/Terminal.ts @@ -347,178 +347,114 @@ export class Terminal { if (n00dlesServ == null) { throw new Error("Could not get n00dles server"); } - const errorMessageForBadCommand = - "Bad command. Try again, or if you'd like to skip the tutorial click Exit Tutorial"; + + const commandArrayMatches = (...rightCommand: string[]): boolean => + commandArray.length === rightCommand.length && commandArray.every((e, idx) => e === rightCommand[idx]); + + const errorMessageForBadCommand = "Wrong command. Try again."; + + let isCorrect: boolean; + let incrementStep = true; + switch (ITutorial.currStep) { - case iTutorialSteps.TerminalHelp: - if (commandArray.length === 1 && commandArray[0] === "help") { - iTutorialNextStep(); - } else { - this.error(errorMessageForBadCommand); - return; - } - break; - case iTutorialSteps.TerminalLs: - if (commandArray.length === 1 && commandArray[0] === "ls") { - iTutorialNextStep(); - } else if (commandArray[0] === "1s") { - this.error("Command '1s' not found. Did you mean 'ls' with a lowercase L?"); - return; - } else { - this.error(errorMessageForBadCommand); - return; - } - break; case iTutorialSteps.TerminalScan: - if (commandArray.length === 1 && commandArray[0] === "scan") { - iTutorialNextStep(); - } else { - this.error(errorMessageForBadCommand); - return; - } - break; - case iTutorialSteps.TerminalScanAnalyze: - if (commandArray.length === 1 && commandArray[0] === "scan-analyze") { - iTutorialNextStep(); - } else { - this.error(errorMessageForBadCommand); - return; - } + isCorrect = commandArrayMatches("scan"); break; + case iTutorialSteps.TerminalScanAnalyze2: - if (commandArray.length === 2 && commandArray[0] === "scan-analyze" && commandArray[1] === 2) { - iTutorialNextStep(); - } else { - this.error(errorMessageForBadCommand); - return; - } + isCorrect = commandArrayMatches("scan-analyze", "2"); break; + case iTutorialSteps.TerminalConnect: - if (commandArray[0] === "connect") { - if ( - commandArray.length === 2 && - (commandArray[1] === "n00dles" || commandArray[1] === n00dlesServ.hostname) - ) { - iTutorialNextStep(); - } else { - this.error("Bad command. Try again!"); - return; - } + if (commandArrayMatches("connect", "n00dles") || commandArrayMatches("connect", n00dlesServ.hostname)) { + isCorrect = true; + } else if ( + // gives the player some freedom + commandArrayMatches("scan-analyze", "3") + ) { + isCorrect = true; + incrementStep = false; } else { - this.error(errorMessageForBadCommand); - return; + isCorrect = false; } break; + case iTutorialSteps.TerminalAnalyze: - if (commandArray.length === 1 && commandArray[0] === "analyze") { - iTutorialNextStep(); - } else { - this.error(errorMessageForBadCommand); - return; - } + isCorrect = commandArrayMatches("analyze"); break; + case iTutorialSteps.TerminalNuke: - if ( - (commandArray.length === 1 && commandArray[0] === "NUKE.exe") || - (commandArray.length === 2 && commandArray[0] === "run" && commandArray[1] === "NUKE.exe") - ) { - iTutorialNextStep(); - } else { - this.error(errorMessageForBadCommand); - return; - } + isCorrect = commandArrayMatches("NUKE.exe") || commandArrayMatches("run", "NUKE.exe"); break; + case iTutorialSteps.TerminalManualHack: - if (commandArray.length === 1 && commandArray[0] === "hack") { - iTutorialNextStep(); - } else { - this.error(errorMessageForBadCommand); - return; - } + isCorrect = commandArrayMatches("hack"); break; + case iTutorialSteps.TerminalHackWeakenGrowMechanics: - if (commandArray.length !== 1 || !["grow", "weaken", "hack"].includes(commandArray[0] + "")) { - this.error(errorMessageForBadCommand); - return; - } + isCorrect = ["hack", "weaken", "grow"].some((c) => commandArrayMatches(c)); break; + case iTutorialSteps.TerminalHome: - if (commandArray.length === 1 && commandArray[0] === "home") { - iTutorialNextStep(); - } else { - this.error(errorMessageForBadCommand); - return; - } + isCorrect = commandArrayMatches("home"); break; + case iTutorialSteps.TerminalNano: - if (commandArray[0] === "nano") { - if (commandArray.length === 2 && commandArray[1] === tutorialScriptName) { - iTutorialNextStep(); - } else { - this.error("Bad command. Try again!"); - return; - } - } else { - this.error(errorMessageForBadCommand); - return; - } + isCorrect = commandArrayMatches("nano", tutorialScriptName); break; + case iTutorialSteps.TerminalFree: - if (commandArray.length === 1 && commandArray[0] === "free") { - iTutorialNextStep(); - } else { - this.error(errorMessageForBadCommand); - return; - } + isCorrect = commandArrayMatches("free"); break; + case iTutorialSteps.TerminalRunScript: - if ( - (commandArray.length === 1 && commandArray[0] === tutorialScriptName) || - (commandArray.length === 2 && commandArray[0] === "run" && commandArray[1] === tutorialScriptName) - ) { - iTutorialNextStep(); - } else { - this.error(errorMessageForBadCommand); - return; - } + isCorrect = commandArrayMatches("run", tutorialScriptName) || commandArrayMatches(tutorialScriptName); break; - case iTutorialSteps.TerminalGoToActiveScriptsPage: // giving the player room to play around a bit - if ( - !( - (commandArray.length === 1 && commandArray[0] === "free") || - (commandArray.length === 1 && commandArray[0] === tutorialScriptName) || - (commandArray.length === 2 && commandArray[0] === "run" && commandArray[1] === tutorialScriptName) - ) - ) { - this.error(errorMessageForBadCommand); - return; - } + + case iTutorialSteps.TerminalGoToActiveScriptsPage: // gives the player some freedom + isCorrect = + commandArrayMatches("free") || + commandArrayMatches(tutorialScriptName) || + commandArrayMatches("run", tutorialScriptName); + incrementStep = false; break; + case iTutorialSteps.TerminalTail: - if (commandArray.length === 2 && commandArray[0] === "tail" && commandArray[1] === tutorialScriptName) { - iTutorialNextStep(); - } else { - this.error(errorMessageForBadCommand); + isCorrect = commandArrayMatches("tail", tutorialScriptName); + break; + + case iTutorialSteps.TerminalLs: + if (commandArrayMatches("ls")) { + isCorrect = true; + } else if (commandArray[0] === "1s") { + this.error("Command '1s' not found. Did you mean 'ls' with a lowercase L?"); return; + } else { + isCorrect = false; } break; + case iTutorialSteps.TerminalScp: - if (commandArray[0] === "scp") { - if (commandArray.length === 3 && commandArray[1] === tutorialScriptName && commandArray[2] === "n00dles") { - iTutorialNextStep(); - } else { - this.error("Bad command. Try again!"); - return; - } - } else { - this.error(errorMessageForBadCommand); - return; - } + isCorrect = commandArrayMatches("scp", tutorialScriptName, "n00dles"); + break; + + case iTutorialSteps.TerminalHelp: + isCorrect = commandArrayMatches("help"); break; + default: - this.error("Make sure you're following the tutorial. If you'd like to skip it click Exit Tutorial"); + this.error("This step doesn't involve the terminal."); return; } + + if (!isCorrect) { + this.error(errorMessageForBadCommand); + return; + } + + if (incrementStep) { + iTutorialNextStep(); + } } /****************** END INTERACTIVE TUTORIAL ******************/ /* Command parser */ From f2e96d730c96d3c78d6f095a552fb55449634825 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Tue, 8 Sep 2026 14:44:32 +0100 Subject: [PATCH 67/82] fix --- src/Terminal/Terminal.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Terminal/Terminal.ts b/src/Terminal/Terminal.ts index 2163d169a7..baf0b2014e 100644 --- a/src/Terminal/Terminal.ts +++ b/src/Terminal/Terminal.ts @@ -361,6 +361,10 @@ export class Terminal { isCorrect = commandArrayMatches("scan"); break; + case iTutorialSteps.TerminalScanAnalyze: + isCorrect = commandArrayMatches("scan-analyze"); + break; + case iTutorialSteps.TerminalScanAnalyze2: isCorrect = commandArrayMatches("scan-analyze", "2"); break; From a778f5d5b15fecf0a59380ffc3d4fcf72a9ebf72 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Tue, 8 Sep 2026 15:08:15 +0100 Subject: [PATCH 68/82] Type issue --- src/Terminal/Terminal.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Terminal/Terminal.ts b/src/Terminal/Terminal.ts index baf0b2014e..a04a9ac658 100644 --- a/src/Terminal/Terminal.ts +++ b/src/Terminal/Terminal.ts @@ -348,7 +348,7 @@ export class Terminal { throw new Error("Could not get n00dles server"); } - const commandArrayMatches = (...rightCommand: string[]): boolean => + const commandArrayMatches = (...rightCommand: (string | number)[]): boolean => commandArray.length === rightCommand.length && commandArray.every((e, idx) => e === rightCommand[idx]); const errorMessageForBadCommand = "Wrong command. Try again."; @@ -366,7 +366,7 @@ export class Terminal { break; case iTutorialSteps.TerminalScanAnalyze2: - isCorrect = commandArrayMatches("scan-analyze", "2"); + isCorrect = commandArrayMatches("scan-analyze", 2); break; case iTutorialSteps.TerminalConnect: @@ -374,7 +374,7 @@ export class Terminal { isCorrect = true; } else if ( // gives the player some freedom - commandArrayMatches("scan-analyze", "3") + commandArrayMatches("scan-analyze", 3) ) { isCorrect = true; incrementStep = false; @@ -397,6 +397,7 @@ export class Terminal { case iTutorialSteps.TerminalHackWeakenGrowMechanics: isCorrect = ["hack", "weaken", "grow"].some((c) => commandArrayMatches(c)); + incrementStep = false; break; case iTutorialSteps.TerminalHome: @@ -447,7 +448,7 @@ export class Terminal { break; default: - this.error("This step doesn't involve the terminal."); + this.error("This step doesn't involve the terminal"); return; } From ddbb3e47b8f367792c314fd0aad15cbbefe20d1f Mon Sep 17 00:00:00 2001 From: branchtheory Date: Tue, 8 Sep 2026 15:17:36 +0100 Subject: [PATCH 69/82] Removed bad ideas --- src/Terminal/Terminal.ts | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/src/Terminal/Terminal.ts b/src/Terminal/Terminal.ts index a04a9ac658..bb596c9feb 100644 --- a/src/Terminal/Terminal.ts +++ b/src/Terminal/Terminal.ts @@ -370,17 +370,7 @@ export class Terminal { break; case iTutorialSteps.TerminalConnect: - if (commandArrayMatches("connect", "n00dles") || commandArrayMatches("connect", n00dlesServ.hostname)) { - isCorrect = true; - } else if ( - // gives the player some freedom - commandArrayMatches("scan-analyze", 3) - ) { - isCorrect = true; - incrementStep = false; - } else { - isCorrect = false; - } + isCorrect = commandArrayMatches("connect", "n00dles") || commandArrayMatches("connect", n00dlesServ.hostname); break; case iTutorialSteps.TerminalAnalyze: @@ -416,14 +406,6 @@ export class Terminal { isCorrect = commandArrayMatches("run", tutorialScriptName) || commandArrayMatches(tutorialScriptName); break; - case iTutorialSteps.TerminalGoToActiveScriptsPage: // gives the player some freedom - isCorrect = - commandArrayMatches("free") || - commandArrayMatches(tutorialScriptName) || - commandArrayMatches("run", tutorialScriptName); - incrementStep = false; - break; - case iTutorialSteps.TerminalTail: isCorrect = commandArrayMatches("tail", tutorialScriptName); break; From eb5dd3c858c00f1ccf85033313a0df6eb2a09b80 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Tue, 8 Sep 2026 16:48:11 +0100 Subject: [PATCH 70/82] Tiny refactor --- src/Sidebar/ui/SidebarRoot.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Sidebar/ui/SidebarRoot.tsx b/src/Sidebar/ui/SidebarRoot.tsx index 05045c4703..87c2e8a483 100644 --- a/src/Sidebar/ui/SidebarRoot.tsx +++ b/src/Sidebar/ui/SidebarRoot.tsx @@ -129,7 +129,12 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement { let flash: Page | null = null; let incrementTutorialStep = false; switch (ITutorial.currStep) { - case iTutorialSteps.ActiveScriptsDescription: + case iTutorialSteps.ScriptEditorEditAndSave: + if (props.page !== Page.ScriptEditor) { + flash = Page.ScriptEditor; + } + break; + case iTutorialSteps.ScriptEditorGoToTerminalPage: flash = Page.Terminal; incrementTutorialStep = true; break; @@ -137,12 +142,7 @@ export function SidebarRoot(props: { page: Page }): React.ReactElement { flash = Page.ActiveScripts; incrementTutorialStep = true; break; - case iTutorialSteps.ScriptEditorEditAndSave: - if (props.page !== Page.ScriptEditor) { - flash = Page.ScriptEditor; - } - break; - case iTutorialSteps.ScriptEditorGoToTerminalPage: + case iTutorialSteps.ActiveScriptsDescription: flash = Page.Terminal; incrementTutorialStep = true; break; From b94873c5f2ff0e261de30c5dd1e15addb1710fc9 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Tue, 8 Sep 2026 17:11:25 +0100 Subject: [PATCH 71/82] Correction --- src/InteractiveTutorial.ts | 4 ++-- src/Terminal/Terminal.ts | 2 +- src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/InteractiveTutorial.ts b/src/InteractiveTutorial.ts index e45168e1f4..24487d2c08 100644 --- a/src/InteractiveTutorial.ts +++ b/src/InteractiveTutorial.ts @@ -21,7 +21,7 @@ enum iTutorialSteps { ScriptEditorRam, ScriptEditorGoToTerminalPage, TerminalFree, - TerminalRunScript, + TerminalRun, TerminalGoToActiveScriptsPage, // Also explains a bit about running scripts ActiveScriptsDescription, TerminalTail, @@ -61,7 +61,7 @@ const ITutorial = { [iTutorialSteps.ScriptEditorRam]: false, [iTutorialSteps.ScriptEditorGoToTerminalPage]: false, [iTutorialSteps.TerminalFree]: false, - [iTutorialSteps.TerminalRunScript]: false, + [iTutorialSteps.TerminalRun]: false, [iTutorialSteps.TerminalGoToActiveScriptsPage]: false, [iTutorialSteps.ActiveScriptsDescription]: false, [iTutorialSteps.TerminalTail]: false, diff --git a/src/Terminal/Terminal.ts b/src/Terminal/Terminal.ts index bb596c9feb..b33071e85a 100644 --- a/src/Terminal/Terminal.ts +++ b/src/Terminal/Terminal.ts @@ -402,7 +402,7 @@ export class Terminal { isCorrect = commandArrayMatches("free"); break; - case iTutorialSteps.TerminalRunScript: + case iTutorialSteps.TerminalRun: isCorrect = commandArrayMatches("run", tutorialScriptName) || commandArrayMatches(tutorialScriptName); break; diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index b2ab7a3bdd..5a79518cf8 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -395,7 +395,7 @@ export async function main(ns) { ), canNext: false, }, - [iTutorialSteps.TerminalRunScript as number]: { + [iTutorialSteps.TerminalRun as number]: { content: ( <> From c83cee7a4ce007f4523faec46a0546c873619fab Mon Sep 17 00:00:00 2001 From: branchtheory Date: Tue, 8 Sep 2026 17:33:14 +0100 Subject: [PATCH 72/82] adding isRunning --- src/Documentation/ui/DocumentationRoot.tsx | 2 +- src/ScriptEditor/ui/Toolbar.tsx | 4 ++-- src/ui/ActiveScripts/ServerAccordion.tsx | 5 ++++- src/ui/ActiveScripts/WorkerScriptAccordion.tsx | 5 ++++- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Documentation/ui/DocumentationRoot.tsx b/src/Documentation/ui/DocumentationRoot.tsx index 7bcf3aed50..65c418e815 100644 --- a/src/Documentation/ui/DocumentationRoot.tsx +++ b/src/Documentation/ui/DocumentationRoot.tsx @@ -77,7 +77,7 @@ export function DocumentationRoot({ docPage }: { docPage?: string }): React.Reac * visits the documentation page for the Docs step, they see index.md / home. */ useEffect(() => { - if (ITutorial.currStep === iTutorialSteps.DocumentationInfo) { + if (ITutorial.isRunning && ITutorial.currStep === iTutorialSteps.DocumentationInfo) { history.home(); } diff --git a/src/ScriptEditor/ui/Toolbar.tsx b/src/ScriptEditor/ui/Toolbar.tsx index cfb007b3ba..2a9b761fa6 100644 --- a/src/ScriptEditor/ui/Toolbar.tsx +++ b/src/ScriptEditor/ui/Toolbar.tsx @@ -76,12 +76,12 @@ export function Toolbar({ editor, onSave, onRun, onBeautify }: IProps) { whiteSpace: "nowrap", color: isUpdatingRAM ? "secondary.main" - : ITutorial.currStep === iTutorialSteps.ScriptEditorRam + : ITutorial.isRunning && ITutorial.currStep === iTutorialSteps.ScriptEditorRam ? "info.main" : "primary.main", }} onClick={() => { - if (ITutorial.currStep === iTutorialSteps.ScriptEditorRam) iTutorialNextStep(); + if (ITutorial.isRunning && ITutorial.currStep === iTutorialSteps.ScriptEditorRam) iTutorialNextStep(); openRAMInfo(); }} > diff --git a/src/ui/ActiveScripts/ServerAccordion.tsx b/src/ui/ActiveScripts/ServerAccordion.tsx index 3e6d77f9cb..0665d93a2f 100644 --- a/src/ui/ActiveScripts/ServerAccordion.tsx +++ b/src/ui/ActiveScripts/ServerAccordion.tsx @@ -43,7 +43,10 @@ export function ServerAccordion({ server, scripts, startOpen }: ServerAccordionP {headerTxt} diff --git a/src/ui/ActiveScripts/WorkerScriptAccordion.tsx b/src/ui/ActiveScripts/WorkerScriptAccordion.tsx index ed97bace51..e8a7217d59 100644 --- a/src/ui/ActiveScripts/WorkerScriptAccordion.tsx +++ b/src/ui/ActiveScripts/WorkerScriptAccordion.tsx @@ -73,7 +73,10 @@ export function WorkerScriptAccordion(props: IProps): React.ReactElement { └ {props.workerScript.name} ({formatRam(scriptRef.ramUsage * scriptRef.threads)}){" "} From 42f5b66b7dca75d4f0cf5895555a0bd924f5b3a1 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Tue, 8 Sep 2026 20:02:49 +0100 Subject: [PATCH 73/82] Removed pointless stuff --- src/Terminal/Terminal.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Terminal/Terminal.ts b/src/Terminal/Terminal.ts index b33071e85a..ece061afb0 100644 --- a/src/Terminal/Terminal.ts +++ b/src/Terminal/Terminal.ts @@ -378,7 +378,7 @@ export class Terminal { break; case iTutorialSteps.TerminalNuke: - isCorrect = commandArrayMatches("NUKE.exe") || commandArrayMatches("run", "NUKE.exe"); + isCorrect = commandArrayMatches("run", "NUKE.exe"); break; case iTutorialSteps.TerminalManualHack: @@ -403,7 +403,7 @@ export class Terminal { break; case iTutorialSteps.TerminalRun: - isCorrect = commandArrayMatches("run", tutorialScriptName) || commandArrayMatches(tutorialScriptName); + isCorrect = commandArrayMatches("run", tutorialScriptName); break; case iTutorialSteps.TerminalTail: From 8c7b1cc005b7360102c1de9a27017c661a4e5be6 Mon Sep 17 00:00:00 2001 From: branchtheory Date: Tue, 8 Sep 2026 21:59:41 +0100 Subject: [PATCH 74/82] isRunning additions --- src/ScriptEditor/ui/Toolbar.tsx | 4 ++- src/Sidebar/ui/SidebarRoot.tsx | 62 +++++++++++++++++---------------- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/src/ScriptEditor/ui/Toolbar.tsx b/src/ScriptEditor/ui/Toolbar.tsx index 2a9b761fa6..8897223dff 100644 --- a/src/ScriptEditor/ui/Toolbar.tsx +++ b/src/ScriptEditor/ui/Toolbar.tsx @@ -89,7 +89,9 @@ export function Toolbar({ editor, onSave, onRun, onBeautify }: IProps) {