gave some love to the tutorial.

This commit is contained in:
Olivier Gagnon 2021-06-12 04:23:15 -04:00
parent 00a5085cdf
commit cdd376f2ae
5 changed files with 121 additions and 101 deletions

@ -69,3 +69,22 @@
float: right; float: right;
padding: 4px; padding: 4px;
} }
.interactive-tutorial-command {
background-color: #000;
color: $hacker-green;
white-space: nowrap;
}
.interactive-tutorial-code {
background-color: #272822;
color: white;
padding: 3px;
}
.interactive-tutorial-tab {
background-color: #555;
color: #e6e6e6;
padding: 3px;
box-shadow: 0 0 3px #000;
}

@ -11,7 +11,6 @@ import { createElement } from "../utils/uiHelpers/createElement";
import { createPopup } from "../utils/uiHelpers/createPopup"; import { createPopup } from "../utils/uiHelpers/createPopup";
import { removeElementById } from "../utils/uiHelpers/removeElementById"; import { removeElementById } from "../utils/uiHelpers/removeElementById";
// Ordered array of keys to Interactive Tutorial Steps // Ordered array of keys to Interactive Tutorial Steps
const orderedITutorialSteps = [ const orderedITutorialSteps = [
"Start", "Start",
@ -24,10 +23,10 @@ const orderedITutorialSteps = [
"TerminalScan", // Using 'scan' Terminal command "TerminalScan", // Using 'scan' Terminal command
"TerminalScanAnalyze1", // Using 'scan-analyze' Terminal command "TerminalScanAnalyze1", // Using 'scan-analyze' Terminal command
"TerminalScanAnalyze2", // Using 'scan-analyze 3' Terminal command "TerminalScanAnalyze2", // Using 'scan-analyze 3' Terminal command
"TerminalConnect", // Connecting to foodnstuff "TerminalConnect", // Connecting to n00dles
"TerminalAnalyze", // Analyzing foodnstuff "TerminalAnalyze", // Analyzing n00dles
"TerminalNuke", // NUKE foodnstuff "TerminalNuke", // NUKE n00dles
"TerminalManualHack", // Hack foodnstuff "TerminalManualHack", // Hack n00dles
"TerminalHackingMechanics", // Explanation of hacking mechanics "TerminalHackingMechanics", // Explanation of hacking mechanics
"TerminalCreateScript", // Create a script using 'nano' "TerminalCreateScript", // Create a script using 'nano'
"TerminalTypeScript", // Script Editor page - Type script and then save & close "TerminalTypeScript", // Script Editor page - Type script and then save & close
@ -51,7 +50,7 @@ for (let i = 0; i < orderedITutorialSteps.length; ++i) {
iTutorialSteps[orderedITutorialSteps[i]] = i; iTutorialSteps[orderedITutorialSteps[i]] = i;
} }
var ITutorial = { const ITutorial = {
currStep: 0, // iTutorialSteps.Start currStep: 0, // iTutorialSteps.Start
isRunning: false, isRunning: false,
@ -76,21 +75,21 @@ function iTutorialStart() {
document.getElementById("interactive-tutorial-container").style.display = "block"; document.getElementById("interactive-tutorial-container").style.display = "block";
// Exit tutorial button // Exit tutorial button
var exitButton = clearEventListeners("interactive-tutorial-exit"); const exitButton = clearEventListeners("interactive-tutorial-exit");
exitButton.addEventListener("click", function() { exitButton.addEventListener("click", function() {
iTutorialEnd(); iTutorialEnd();
return false; return false;
}); });
// Back button // Back button
var backButton = clearEventListeners("interactive-tutorial-back"); const backButton = clearEventListeners("interactive-tutorial-back");
backButton.addEventListener("click", function() { backButton.addEventListener("click", function() {
iTutorialPrevStep(); iTutorialPrevStep();
return false; return false;
}); });
// Next button // Next button
var nextButton = clearEventListeners("interactive-tutorial-next"); const nextButton = clearEventListeners("interactive-tutorial-next");
nextButton.addEventListener("click", function() { nextButton.addEventListener("click", function() {
iTutorialNextStep(); iTutorialNextStep();
return false; return false;
@ -103,12 +102,12 @@ function iTutorialEvaluateStep() {
if (!ITutorial.isRunning) {return;} if (!ITutorial.isRunning) {return;}
// Disable and clear main menu // Disable and clear main menu
var terminalMainMenu = clearEventListeners("terminal-menu-link"); const terminalMainMenu = clearEventListeners("terminal-menu-link");
var statsMainMenu = clearEventListeners("stats-menu-link"); const statsMainMenu = clearEventListeners("stats-menu-link");
var activeScriptsMainMenu = clearEventListeners("active-scripts-menu-link"); const activeScriptsMainMenu = clearEventListeners("active-scripts-menu-link");
var hacknetMainMenu = clearEventListeners("hacknet-nodes-menu-link"); const hacknetMainMenu = clearEventListeners("hacknet-nodes-menu-link");
var cityMainMenu = clearEventListeners("city-menu-link"); const cityMainMenu = clearEventListeners("city-menu-link");
var tutorialMainMenu = clearEventListeners("tutorial-menu-link"); const tutorialMainMenu = clearEventListeners("tutorial-menu-link");
terminalMainMenu.removeAttribute("class"); terminalMainMenu.removeAttribute("class");
statsMainMenu.removeAttribute("class"); statsMainMenu.removeAttribute("class");
activeScriptsMainMenu.removeAttribute("class"); activeScriptsMainMenu.removeAttribute("class");
@ -117,20 +116,20 @@ function iTutorialEvaluateStep() {
tutorialMainMenu.removeAttribute("class"); tutorialMainMenu.removeAttribute("class");
// Interactive Tutorial Next button // Interactive Tutorial Next button
var nextBtn = document.getElementById("interactive-tutorial-next"); const nextBtn = document.getElementById("interactive-tutorial-next");
switch(ITutorial.currStep) { switch(ITutorial.currStep) {
case iTutorialSteps.Start: case iTutorialSteps.Start:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("Welcome to Bitburner, a cyberpunk-themed incremental RPG! " + iTutorialSetText("Welcome to Bitburner, a cyberpunk-themed incremental RPG! " +
"The game takes place in a dark, dystopian future...The year is 2077...<br><br>" + "The game takes place in a dark, dystopian future... The year is 2077...<br><br>" +
"This tutorial will show you the basics of the game. " + "This tutorial will show you the basics of the game. " +
"You may skip the tutorial at any time."); "You may skip the tutorial at any time.");
nextBtn.style.display = "inline-block"; nextBtn.style.display = "inline-block";
break; break;
case iTutorialSteps.GoToCharacterPage: case iTutorialSteps.GoToCharacterPage:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("Let's start by heading to the Stats page. Click the 'Stats' tab on " + iTutorialSetText("Let's start by heading to the Stats page. Click the <code class='interactive-tutorial-tab flashing-button'>Stats</code> tab on " +
"the main navigation menu (left-hand side of the screen)"); "the main navigation menu (left-hand side of the screen)");
nextBtn.style.display = "none"; nextBtn.style.display = "none";
@ -144,13 +143,13 @@ function iTutorialEvaluateStep() {
break; break;
case iTutorialSteps.CharacterPage: case iTutorialSteps.CharacterPage:
Engine.loadCharacterContent(); Engine.loadCharacterContent();
iTutorialSetText("The Stats page shows a lot of important information about your progress, " + iTutorialSetText("The <code class='interactive-tutorial-tab'>Stats</code> page shows a lot of important information about your progress, " +
"such as your skills, money, and bonuses/multipliers. ") "such as your skills, money, and bonuses. ")
nextBtn.style.display = "inline-block"; nextBtn.style.display = "inline-block";
break; break;
case iTutorialSteps.CharacterGoToTerminalPage: case iTutorialSteps.CharacterGoToTerminalPage:
Engine.loadCharacterContent(); Engine.loadCharacterContent();
iTutorialSetText("Let's head to your computer's terminal by clicking the 'Terminal' tab on the " + iTutorialSetText("Let's head to your computer's terminal by clicking the <code class='interactive-tutorial-tab flashing-button'>Terminal</code> tab on the " +
"main navigation menu."); "main navigation menu.");
nextBtn.style.display = "none"; nextBtn.style.display = "none";
@ -164,57 +163,56 @@ function iTutorialEvaluateStep() {
break; break;
case iTutorialSteps.TerminalIntro: case iTutorialSteps.TerminalIntro:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("The Terminal is used to interface with your home computer as well as " + iTutorialSetText("The <code class='interactive-tutorial-tab'>Terminal</code> is used to interface with your home computer as well as " +
"all of the other machines around the world."); "all of the other machines around the world.");
nextBtn.style.display = "inline-block"; nextBtn.style.display = "inline-block";
break; break;
case iTutorialSteps.TerminalHelp: case iTutorialSteps.TerminalHelp:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("Let's try it out. Start by entering the 'help' command into the Terminal " + iTutorialSetText("Let's try it out. Start by entering the <code class='interactive-tutorial-command'>help</code> command into the <code class='interactive-tutorial-tab'>Terminal</code> " +
"(Don't forget to press Enter after typing the command)"); "(Don't forget to press Enter after typing the command)");
nextBtn.style.display = "none"; // next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalLs: case iTutorialSteps.TerminalLs:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("The 'help' command displays a list of all available Terminal commands, how to use them, " + iTutorialSetText("The <code class='interactive-tutorial-command'>help</code> command displays a list of all available <code class='interactive-tutorial-tab'>Terminal</code> commands, how to use them, " +
"and a description of what they do. <br><br>Let's try another command. Enter the 'ls' command"); "and a description of what they do. <br><br>Let's try another command. Enter the <code class='interactive-tutorial-command'>ls</code> command.");
nextBtn.style.display = "none"; // next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalScan: case iTutorialSteps.TerminalScan:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("'ls' is a basic command that shows all of the contents (programs/scripts) " + iTutorialSetText(" <code class='interactive-tutorial-command'>ls</code> is a basic command that shows files " +
"on the computer. Right now, it shows that you have a program called 'NUKE.exe' on your computer. " + "on the computer. Right now, it shows that you have a program called <code class='interactive-tutorial-command'>NUKE.exe</code> on your computer. " +
"We'll get to what this does later. <br><br>Using your home computer's terminal, you can connect " + "We'll get to what this does later. <br><br>Using your home computer's terminal, you can connect " +
"to other machines throughout the world. Let's do that now by first entering " + "to other machines throughout the world. Let's do that now by first entering " +
"the 'scan' command."); "the <code class='interactive-tutorial-command'>scan</code> command.");
nextBtn.style.display = "none"; // next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalScanAnalyze1: case iTutorialSteps.TerminalScanAnalyze1:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("The 'scan' command shows all available network connections. In other words, " + iTutorialSetText("The <code class='interactive-tutorial-command'>scan</code> command shows all available network connections. In other words, " +
"it displays a list of all servers that can be connected to from your " + "it displays a list of all servers that can be connected to from your " +
"current machine. A server is identified by either its IP or its hostname. <br><br> " + "current machine. A server is identified by its hostname. <br><br> " +
"That's great and all, but there's so many servers. Which one should you go to? " + "That's great and all, but there's so many servers. Which one should you go to? " +
"The 'scan-analyze' command gives some more detailed information about servers on the " + "The <code class='interactive-tutorial-command'>scan-analyze</code> command gives some more detailed information about servers on the " +
"network. Try it now"); "network. Try it now!");
nextBtn.style.display = "none"; // next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalScanAnalyze2: case iTutorialSteps.TerminalScanAnalyze2:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("You just ran 'scan-analyze' with a depth of one. This command shows more detailed " + iTutorialSetText("You just ran <code class='interactive-tutorial-command'>scan-analyze</code> with a depth of one. This command shows more detailed " +
"information about each server that you can connect to (servers that are a distance of " + "information about each server that you can connect to (servers that are a distance of " +
"one node away). <br><br> It is also possible to run 'scan-analyze' with " + "one node away). <br><br> It is also possible to run <code class='interactive-tutorial-command'>scan-analyze</code> with " +
"a higher depth. Let's try a depth of two with the following command: 'scan-analyze 2'.") "a higher depth. Let's try a depth of two with the following command: <code class='interactive-tutorial-command'>scan-analyze 2</code>.")
nextBtn.style.display = "none"; // next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalConnect: case iTutorialSteps.TerminalConnect:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("Now you can see information about all servers that are up to two nodes away, as well " + iTutorialSetText("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 " + "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 the 'connect [ip/hostname]' command. You can type in " + "a server that is one node away. To connect to a machine, use the <code class='interactive-tutorial-command'>connect [hostname]</code> command.<br><br>" +
"the ip or the hostname, but dont use both.<br><br>" + "From the results of the <code class='interactive-tutorial-command'>scan-analyze</code> command, we can see that the <code class='interactive-tutorial-command'>n00dles</code> server is " +
"From the results of the 'scan-analyze' command, we can see that the 'foodnstuff' server is " + "only one node away. Let's connect so it now using: <code class='interactive-tutorial-command'>connect n00dles</code>");
"only one node away. Let's connect so it now using: 'connect foodnstuff'");
nextBtn.style.display = "none"; // next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalAnalyze: case iTutorialSteps.TerminalAnalyze:
@ -223,30 +221,30 @@ function iTutorialEvaluateStep() {
"become digital and decentralized. People and corporations store their money " + "become digital and decentralized. People and corporations store their money " +
"on servers and computers. Using your hacking abilities, you can hack servers " + "on servers and computers. Using your hacking abilities, you can hack servers " +
"to steal money and gain experience. <br><br> " + "to steal money and gain experience. <br><br> " +
"Before you try to hack a server, you should run diagnostics using the 'analyze' command"); "Before you try to hack a server, you should run diagnostics using the <code class='interactive-tutorial-command'>analyze</code> command.");
nextBtn.style.display = "none"; // next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalNuke: case iTutorialSteps.TerminalNuke:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("When the 'analyze' command finishes running it will show useful information " + iTutorialSetText("When the <code class='interactive-tutorial-command'>analyze</code> command finishes running it will show useful information " +
"about hacking the server. <br><br> For this server, the required hacking skill is only 1, " + "about hacking the server. <br><br> For this server, the required hacking skill is only <span class='character-hack-cell'>1</span>, " +
"which means you can hack it right now. However, in order to hack a server " + "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 " + "you must first gain root access. The <code class='interactive-tutorial-command'>NUKE.exe</code> 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 " + "home computer is a virus that will grant you root access to a machine if there are enough " +
"open ports.<br><br> The 'analyze' results shows that there do not need to be any open ports " + "open ports.<br><br> The <code class='interactive-tutorial-command'>analyze</code> results 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 the " + "on this machine for the NUKE virus to work, so go ahead and run the virus using the " +
"'run NUKE.exe' command."); "<code class='interactive-tutorial-command'>run NUKE.exe</code> command.");
nextBtn.style.display = "none"; // next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalManualHack: case iTutorialSteps.TerminalManualHack:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("You now have root access! You can hack the server using the 'hack' command. " + iTutorialSetText("You now have root access! You can hack the server using the <code class='interactive-tutorial-command'>hack</code> command. " +
"Try doing that now."); "Try doing that now.");
nextBtn.style.display = "none"; // next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalHackingMechanics: case iTutorialSteps.TerminalHackingMechanics:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("You are now attempting to hack the server. Note that performing a hack takes time and " + iTutorialSetText("You are now attempting to hack the server. Performing a hack takes time and " +
"only has a certain percentage chance " + "only has a certain percentage chance " +
"of success. This time and success chance is determined by a variety of factors, including " + "of success. This time and success chance is determined by a variety of factors, including " +
"your hacking skill and the server's security level.<br><br>" + "your hacking skill and the server's security level.<br><br>" +
@ -261,25 +259,22 @@ function iTutorialEvaluateStep() {
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("Hacking is the core mechanic of the game and is necessary for progressing. However, " + iTutorialSetText("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 " + "you don't want to be hacking manually the entire time. You can automate your hacking " +
"by writing scripts!<br><br>To create a new script or edit an existing one, you can use the 'nano' " + "by writing scripts!<br><br>To create a new script or edit an existing one, you can use the <code class='interactive-tutorial-command'>nano</code> " +
"command. Scripts must end with the '.script' extension. Let's make a script now by " + "command. Scripts must end with the <code class='interactive-tutorial-command'>.script</code> extension. Let's make a script now by " +
"entering 'nano foodnstuff.script' after the hack command finishes running (Sidenote: Pressing ctrl + c" + "entering <code class='interactive-tutorial-command'>nano n00dles.script</code> after the hack command finishes running (Sidenote: Pressing ctrl + c" +
" will end a command like hack early)"); " will end a command like hack early)");
nextBtn.style.display = "none"; // next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalTypeScript: case iTutorialSteps.TerminalTypeScript:
Engine.loadScriptEditorContent("foodnstuff.script", ""); Engine.loadScriptEditorContent("n00dles.script", "");
iTutorialSetText("This is the script editor. You can use it to program your scripts. Scripts are " + iTutorialSetText("This is the script editor. You can use it to program your scripts. Scripts are " +
"written in the Netscript language, a programming language created for " + "written in a simplified version of javascript. Copy and paste the following code into the script editor: <br><br>" +
"this game. <strong style='background-color:#444;'>There are details about the Netscript language in the documentation, which " + "<pre class='interactive-tutorial-code'>" +
"can be accessed in the 'Tutorial' tab on the main navigation menu. I highly suggest you check " + "while(true) {\n" +
"it out after this tutorial.</strong> For now, just copy " + " hack('n00dles');\n" +
"and paste the following code into the script editor: <br><br>" + "}</pre>" +
"while(true) { <br>" +
"&nbsp;&nbsp;hack('foodnstuff'); <br>" +
"}<br><br> " +
"For anyone with basic programming experience, this code should be straightforward. " + "For anyone with basic programming experience, this code should be straightforward. " +
"This script will continuously hack the 'foodnstuff' server.<br><br>" + "This script will continuously hack the <code class='interactive-tutorial-command'>n00dles</code> server.<br><br>" +
"To save and close the script editor, press the button in the bottom left, or press ctrl + b."); "To save and close the script editor, press the button in the bottom left, or press ctrl + b.");
nextBtn.style.display = "none"; // next step triggered in saveAndCloseScriptEditor() (Script.js) nextBtn.style.display = "none"; // next step triggered in saveAndCloseScriptEditor() (Script.js)
break; break;
@ -288,25 +283,25 @@ function iTutorialEvaluateStep() {
iTutorialSetText("Now we'll run the script. Scripts require a certain amount of RAM to run, and can be " + iTutorialSetText("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 " + "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.<br><br>To check how much " + "amounts of RAM. You can also purchase more RAM for your home server.<br><br>To check how much " +
"RAM is available on this machine, enter the 'free' command."); "RAM is available on this machine, enter the <code class='interactive-tutorial-command'>free</code> command.");
nextBtn.style.display = "none"; // next step triggered by terminal commmand nextBtn.style.display = "none"; // next step triggered by terminal commmand
break; break;
case iTutorialSteps.TerminalRunScript: case iTutorialSteps.TerminalRunScript:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("We have 16GB of free RAM on this machine, which is enough to run our " + iTutorialSetText("We have 16GB of free RAM on this machine, which is enough to run our " +
"script. Let's run our script using 'run foodnstuff.script'."); "script. Let's run our script using <code class='interactive-tutorial-command'>run n00dles.script</code>.");
nextBtn.style.display = "none"; // next step triggered by terminal commmand nextBtn.style.display = "none"; // next step triggered by terminal commmand
break; break;
case iTutorialSteps.TerminalGoToActiveScriptsPage: case iTutorialSteps.TerminalGoToActiveScriptsPage:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("Your script is now running! The script might take a few seconds to 'fully start up'. " + iTutorialSetText("Your script is now running! " +
"Your scripts will continuously run in the background and will automatically stop if " + "It will continuously run in the background and will automatically stop if " +
"the code ever completes (the 'foodnstuff.script' will never complete because it " + "the code ever completes (the <code class='interactive-tutorial-command'>n00dles.script</code> will never complete because it " +
"runs an infinite loop). <br><br>These scripts can passively earn you income and hacking experience. " + "runs an infinite loop). <br><br>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 " + "Your scripts will also earn money and experience while you are offline, although at a " +
"much slower rate. <br><br> " + "slightly slower rate. <br><br> " +
"Let's check out some statistics for our running scripts by clicking the " + "Let's check out some statistics for our running scripts by clicking the " +
"'Active Scripts' link in the main navigation menu."); "<code class='interactive-tutorial-tab flashing-button'>Active Scripts</code> link in the main navigation menu.");
nextBtn.style.display = "none"; nextBtn.style.display = "none";
// Flash 'Active Scripts' menu and set its tutorial click handler // Flash 'Active Scripts' menu and set its tutorial click handler
@ -319,10 +314,9 @@ function iTutorialEvaluateStep() {
break; break;
case iTutorialSteps.ActiveScriptsPage: case iTutorialSteps.ActiveScriptsPage:
Engine.loadActiveScriptsContent(); Engine.loadActiveScriptsContent();
iTutorialSetText("This page displays stats/information about all of your scripts that are " + iTutorialSetText("This page displays information about all of your scripts that are " +
"running across every existing server. You can use this to gauge how well " + "running across every server. You can use this to gauge how well " +
"your scripts are doing. Let's go back to the Terminal now using the 'Terminal' " + "your scripts are doing. Let's go back to the <code class='interactive-tutorial-tab flashing-button'>Terminal</code>");
"link.");
nextBtn.style.display = "none"; nextBtn.style.display = "none";
// Flash 'Terminal' button and set its tutorial click handler // Flash 'Terminal' button and set its tutorial click handler
@ -336,27 +330,27 @@ function iTutorialEvaluateStep() {
case iTutorialSteps.ActiveScriptsToTerminal: case iTutorialSteps.ActiveScriptsToTerminal:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("One last thing about scripts, each active script contains logs that detail " + iTutorialSetText("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 " + "what it's doing. We can check these logs using the <code class='interactive-tutorial-command'>tail</code> command. Do that " +
"now for the script we just ran by typing 'tail foodnstuff.script'"); "now for the script we just ran by typing <code class='interactive-tutorial-command'>tail n00dles.script</code>");
nextBtn.style.display = "none"; // next step triggered by terminal command nextBtn.style.display = "none"; // next step triggered by terminal command
break; break;
case iTutorialSteps.TerminalTailScript: case iTutorialSteps.TerminalTailScript:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("The log for this script won't show much right now (it might show nothing at all) because it " + iTutorialSetText("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! <br><br>" + "just started running...but check back again in a few minutes! <br><br>" +
"This pretty much covers the basics of hacking. To learn more about writing " + "This covers the basics of hacking. To learn more about writing " +
"scripts using the Netscript language, select the 'Tutorial' link in the " + "scripts, select the <code class='interactive-tutorial-tab'>Tutorial</code> link in the " +
"main navigation menu to look at the documentation. " + "main navigation menu to look at the documentation. " +
"<strong style='background-color:#444;'>If you are an experienced JavaScript " + "<strong style='background-color:#444;'>If you are an experienced JavaScript " +
"developer, I would highly suggest you check out the section on " + "developer, I would highly suggest you check out the section on " +
"NetscriptJS/Netscript 2.0.</strong><br><br>For now, let's move on to something else!"); "NetscriptJS/Netscript 2.0, it's faster and more powerful.</strong><br><br>For now, let's move on to something else!");
nextBtn.style.display = "inline-block"; nextBtn.style.display = "inline-block";
break; break;
case iTutorialSteps.GoToHacknetNodesPage: case iTutorialSteps.GoToHacknetNodesPage:
Engine.loadTerminalContent(); Engine.loadTerminalContent();
iTutorialSetText("Hacking is not the only way to earn money. One other way to passively " + iTutorialSetText("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 " + "earn money is by purchasing and upgrading Hacknet Nodes. Let's go to " +
"the 'Hacknet Nodes' page through the main navigation menu now."); "the <code class='interactive-tutorial-tab flashing-button'>Hacknet</code> page through the main navigation menu now.");
nextBtn.style.display = "none"; nextBtn.style.display = "none";
// Flash 'Hacknet' menu and set its tutorial click handler // Flash 'Hacknet' menu and set its tutorial click handler
@ -369,7 +363,7 @@ function iTutorialEvaluateStep() {
break; break;
case iTutorialSteps.HacknetNodesIntroduction: case iTutorialSteps.HacknetNodesIntroduction:
Engine.loadHacknetNodesContent(); Engine.loadHacknetNodesContent();
iTutorialSetText("From this page you can purchase new Hacknet Nodes and upgrade your " + iTutorialSetText("here you can purchase new Hacknet Nodes and upgrade your " +
"existing ones. Let's purchase a new one now."); "existing ones. Let's purchase a new one now.");
nextBtn.style.display = "none"; // Next step triggered by purchaseHacknet() (HacknetNode.js) nextBtn.style.display = "none"; // Next step triggered by purchaseHacknet() (HacknetNode.js)
break; break;
@ -379,7 +373,7 @@ function iTutorialEvaluateStep() {
"earn you money over time, both online and offline. When you get enough " + "earn you money over time, both online and offline. When you get enough " +
" money, you can upgrade " + " money, you can upgrade " +
"your newly-purchased Hacknet Node below.<br><br>" + "your newly-purchased Hacknet Node below.<br><br>" +
"Let's go to the 'City' page through the main navigation menu."); "Let's go to the <code class='interactive-tutorial-tab flashing-button'>City</code> page through the main navigation menu.");
nextBtn.style.display = "none"; nextBtn.style.display = "none";
// Flash 'City' menu and set its tutorial click handler // Flash 'City' menu and set its tutorial click handler
@ -396,7 +390,7 @@ function iTutorialEvaluateStep() {
"travel to. Each location has something that you can do. " + "travel to. Each location has something that you can do. " +
"There's a lot of content out in the world, make sure " + "There's a lot of content out in the world, make sure " +
"you explore and discover!<br><br>" + "you explore and discover!<br><br>" +
"Lastly, click on the 'Tutorial' link in the main navigation menu."); "Lastly, click on the <code class='interactive-tutorial-tab flashing-button'>Tutorial</code> link in the main navigation menu.");
nextBtn.style.display = "none"; nextBtn.style.display = "none";
// Flash 'Tutorial' menu and set its tutorial click handler // Flash 'Tutorial' menu and set its tutorial click handler
@ -493,8 +487,8 @@ function iTutorialEnd() {
document.getElementById("interactive-tutorial-container").style.display = "none"; document.getElementById("interactive-tutorial-container").style.display = "none";
// Create a popup with final introductory stuff // Create a popup with final introductory stuff
var popupId = "interactive-tutorial-ending-popup"; const popupId = "interactive-tutorial-ending-popup";
var txt = createElement("p", { const txt = createElement("p", {
innerHTML: innerHTML:
"If you are new to the game, the following links may be useful for you!<br><br>" + "If you are new to the game, the following links may be useful for you!<br><br>" +
"<a class='a-link-button' href='https://bitburner.readthedocs.io/en/latest/guidesandtips/gettingstartedguideforbeginnerprogrammers.html' target='_blank'>Getting Started Guide</a>" + "<a class='a-link-button' href='https://bitburner.readthedocs.io/en/latest/guidesandtips/gettingstartedguideforbeginnerprogrammers.html' target='_blank'>Getting Started Guide</a>" +
@ -502,7 +496,7 @@ function iTutorialEnd() {
"The Beginner's Guide to Hacking was added to your home computer! It contains some tips/pointers for starting out with the game. " + "The Beginner's Guide to Hacking was added to your home computer! It contains some tips/pointers for starting out with the game. " +
"To read it, go to Terminal and enter<br><br>cat " + LiteratureNames.HackersStartingHandbook, "To read it, go to Terminal and enter<br><br>cat " + LiteratureNames.HackersStartingHandbook,
}); });
var gotitBtn = createElement("a", { const gotitBtn = createElement("a", {
class:"a-link-button", float:"right", padding:"6px", innerText:"Got it!", class:"a-link-button", float:"right", padding:"6px", innerText:"Got it!",
clickListener:()=>{ clickListener:()=>{
removeElementById(popupId); removeElementById(popupId);
@ -513,9 +507,16 @@ function iTutorialEnd() {
Player.getHomeComputer().messages.push(LiteratureNames.HackersStartingHandbook); Player.getHomeComputer().messages.push(LiteratureNames.HackersStartingHandbook);
} }
let textBox = null;
(function() {
function set() {
textBox = document.getElementById("interactive-tutorial-text");
document.removeEventListener("DOMContentLoaded", set);
}
document.addEventListener("DOMContentLoaded", set);
})();
function iTutorialSetText(txt) { function iTutorialSetText(txt) {
var textBox = document.getElementById("interactive-tutorial-text");
if (textBox == null) {throw new Error("Could not find text box"); return;}
textBox.innerHTML = txt; textBox.innerHTML = txt;
textBox.parentElement.scrollTop = 0; // this resets scroll position textBox.parentElement.scrollTop = 0; // this resets scroll position
} }

@ -231,12 +231,12 @@ function saveAndCloseScriptEditor() {
if (ITutorial.isRunning && ITutorial.currStep === iTutorialSteps.TerminalTypeScript) { if (ITutorial.isRunning && ITutorial.currStep === iTutorialSteps.TerminalTypeScript) {
//Make sure filename + code properly follow tutorial //Make sure filename + code properly follow tutorial
if (filename !== "foodnstuff.script") { if (filename !== "n00dles.script") {
dialogBoxCreate("Leave the script name as 'foodnstuff'!"); dialogBoxCreate("Leave the script name as 'n00dles'!");
return; return;
} }
code = code.replace(/\s/g, ""); code = code.replace(/\s/g, "");
if (code.indexOf("while(true){hack('foodnstuff');}") == -1) { if (code.indexOf("while(true){hack('n00dles');}") == -1) {
dialogBoxCreate("Please copy and paste the code from the tutorial!"); dialogBoxCreate("Please copy and paste the code from the tutorial!");
return; return;
} }

@ -742,8 +742,8 @@ let Terminal = {
/****************** Interactive Tutorial Terminal Commands ******************/ /****************** Interactive Tutorial Terminal Commands ******************/
if (ITutorial.isRunning) { if (ITutorial.isRunning) {
var foodnstuffServ = GetServerByHostname("foodnstuff"); var n00dlesServ = GetServerByHostname("n00dles");
if (foodnstuffServ == null) {throw new Error("Could not get foodnstuff server"); return;} if (n00dlesServ == null) {throw new Error("Could not get n00dles server"); return;}
switch(ITutorial.currStep) { switch(ITutorial.currStep) {
case iTutorialSteps.TerminalHelp: case iTutorialSteps.TerminalHelp:
@ -780,11 +780,11 @@ let Terminal = {
case iTutorialSteps.TerminalConnect: case iTutorialSteps.TerminalConnect:
if (commandArray.length == 2) { if (commandArray.length == 2) {
if ((commandArray[0] == "connect") && if ((commandArray[0] == "connect") &&
(commandArray[1] == "foodnstuff" || commandArray[1] == foodnstuffServ.ip)) { (commandArray[1] == "n00dles" || commandArray[1] == n00dlesServ.ip)) {
Player.getCurrentServer().isConnectedTo = false; Player.getCurrentServer().isConnectedTo = false;
Player.currentServer = foodnstuffServ.ip; Player.currentServer = n00dlesServ.ip;
Player.getCurrentServer().isConnectedTo = true; Player.getCurrentServer().isConnectedTo = true;
post("Connected to foodnstuff"); post("Connected to n00dles");
iTutorialNextStep(); iTutorialNextStep();
} else {post("Wrong command! Try again!"); return;} } else {post("Wrong command! Try again!"); return;}
} else {post("Bad command. Please follow the tutorial");} } else {post("Bad command. Please follow the tutorial");}
@ -804,8 +804,8 @@ let Terminal = {
case iTutorialSteps.TerminalNuke: case iTutorialSteps.TerminalNuke:
if (commandArray.length == 2 && if (commandArray.length == 2 &&
commandArray[0] == "run" && commandArray[1] == "NUKE.exe") { commandArray[0] == "run" && commandArray[1] == "NUKE.exe") {
foodnstuffServ.hasAdminRights = true; n00dlesServ.hasAdminRights = true;
post("NUKE successful! Gained root access to foodnstuff"); post("NUKE successful! Gained root access to n00dles");
iTutorialNextStep(); iTutorialNextStep();
} else {post("Bad command. Please follow the tutorial");} } else {post("Bad command. Please follow the tutorial");}
break; break;
@ -817,8 +817,8 @@ let Terminal = {
break; break;
case iTutorialSteps.TerminalCreateScript: case iTutorialSteps.TerminalCreateScript:
if (commandArray.length == 2 && if (commandArray.length == 2 &&
commandArray[0] == "nano" && commandArray[1] == "foodnstuff.script") { commandArray[0] == "nano" && commandArray[1] == "n00dles.script") {
Engine.loadScriptEditorContent("foodnstuff.script", ""); Engine.loadScriptEditorContent("n00dles.script", "");
iTutorialNextStep(); iTutorialNextStep();
} else {post("Bad command. Please follow the tutorial");} } else {post("Bad command. Please follow the tutorial");}
break; break;
@ -830,16 +830,16 @@ let Terminal = {
break; break;
case iTutorialSteps.TerminalRunScript: case iTutorialSteps.TerminalRunScript:
if (commandArray.length == 2 && if (commandArray.length == 2 &&
commandArray[0] == "run" && commandArray[1] == "foodnstuff.script") { commandArray[0] == "run" && commandArray[1] == "n00dles.script") {
Terminal.runScript(commandArray); Terminal.runScript(commandArray);
iTutorialNextStep(); iTutorialNextStep();
} else {post("Bad command. Please follow the tutorial");} } else {post("Bad command. Please follow the tutorial");}
break; break;
case iTutorialSteps.ActiveScriptsToTerminal: case iTutorialSteps.ActiveScriptsToTerminal:
if (commandArray.length == 2 && if (commandArray.length == 2 &&
commandArray[0] == "tail" && commandArray[1] == "foodnstuff.script") { commandArray[0] == "tail" && commandArray[1] == "n00dles.script") {
// Check that the script exists on this machine // Check that the script exists on this machine
var runningScript = findRunningScript("foodnstuff.script", [], Player.getCurrentServer()); var runningScript = findRunningScript("n00dles.script", [], Player.getCurrentServer());
if (runningScript == null) { if (runningScript == null) {
post("Error: No such script exists"); post("Error: No such script exists");
return; return;

@ -67,7 +67,7 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
<span id="augmentations-notification" class="notification-off"> </span> <span id="augmentations-notification" class="notification-off"> </span>
</li> </li>
<li id="hacknet-nodes-tab" class="mainmenu-accordion-panel"> <li id="hacknet-nodes-tab" class="mainmenu-accordion-panel">
<button id="hacknet-nodes-menu-link"> Hacknet Manager </button> <button id="hacknet-nodes-menu-link"> Hacknet </button>
</li> </li>
<li id="sleeves-tab" class="mainmenu-accordion-panel"> <li id="sleeves-tab" class="mainmenu-accordion-panel">
<button id="sleeves-menu-link"> Sleeves </button> <button id="sleeves-menu-link"> Sleeves </button>