diff --git a/src/InteractiveTutorial.ts b/src/InteractiveTutorial.ts index 94967be29..2d7b16848 100644 --- a/src/InteractiveTutorial.ts +++ b/src/InteractiveTutorial.ts @@ -7,6 +7,7 @@ import { ITutorialEvents } from "./ui/InteractiveTutorial/ITutorialEvents"; // Ordered array of keys to Interactive Tutorial Steps enum iTutorialSteps { Start, + NSSelection, GoToCharacterPage, // Click on 'Stats' page CharacterPage, // Introduction to 'Stats' page CharacterGoToTerminalPage, // Go back to Terminal @@ -43,6 +44,7 @@ const ITutorial: { isRunning: boolean; stepIsDone: { [iTutorialSteps.Start]: boolean; + [iTutorialSteps.NSSelection]: boolean; [iTutorialSteps.GoToCharacterPage]: boolean; [iTutorialSteps.CharacterPage]: boolean; [iTutorialSteps.CharacterGoToTerminalPage]: boolean; @@ -80,6 +82,7 @@ const ITutorial: { // Keeps track of whether each step has been done stepIsDone: { [iTutorialSteps.Start]: false, + [iTutorialSteps.NSSelection]: false, [iTutorialSteps.GoToCharacterPage]: false, [iTutorialSteps.CharacterPage]: false, [iTutorialSteps.CharacterGoToTerminalPage]: false, diff --git a/src/ScriptEditor/ui/ScriptEditorRoot.tsx b/src/ScriptEditor/ui/ScriptEditorRoot.tsx index 2dc20212b..645085198 100644 --- a/src/ScriptEditor/ui/ScriptEditorRoot.tsx +++ b/src/ScriptEditor/ui/ScriptEditorRoot.tsx @@ -544,11 +544,14 @@ export function Root(props: IProps): React.ReactElement { // this is duplicate code with saving later. if (ITutorial.isRunning && ITutorial.currStep === iTutorialSteps.TerminalTypeScript) { //Make sure filename + code properly follow tutorial - if (currentScript.fileName !== "n00dles.script") { - dialogBoxCreate("Leave the script name as 'n00dles.script'!"); + if (currentScript.fileName !== "n00dles.script" && currentScript.fileName !== "n00dles.js") { + dialogBoxCreate("Don't change the script name for now."); return; } - if (currentScript.code.replace(/\s/g, "").indexOf("while(true){hack('n00dles');}") == -1) { + const cleanCode = currentScript.code.replace(/\s/g, ""); + const ns1 = "while(true){hack('n00dles');}"; + const ns2 = `exportasyncfunctionmain(ns){while(true){awaitns.hack('n00dles');}}`; + if (cleanCode.indexOf(ns1) == -1 && cleanCode.indexOf(ns2) == -1) { dialogBoxCreate("Please copy and paste the code from the tutorial!"); return; } diff --git a/src/Terminal/Terminal.ts b/src/Terminal/Terminal.ts index d9b0a0ebe..5369a5907 100644 --- a/src/Terminal/Terminal.ts +++ b/src/Terminal/Terminal.ts @@ -718,7 +718,11 @@ export class Terminal implements ITerminal { } break; case iTutorialSteps.TerminalCreateScript: - if (commandArray.length == 2 && commandArray[0] == "nano" && commandArray[1] == "n00dles.script") { + if ( + commandArray.length == 2 && + commandArray[0] == "nano" && + (commandArray[1] == "n00dles.script" || commandArray[1] == "n00dles.js") + ) { iTutorialNextStep(); } else { this.error("Bad command. Please follow the tutorial"); @@ -734,7 +738,11 @@ export class Terminal implements ITerminal { } break; case iTutorialSteps.TerminalRunScript: - if (commandArray.length == 2 && commandArray[0] == "run" && commandArray[1] == "n00dles.script") { + if ( + commandArray.length == 2 && + commandArray[0] == "run" && + (commandArray[1] == "n00dles.script" || commandArray[1] == "n00dles.js") + ) { iTutorialNextStep(); } else { this.error("Bad command. Please follow the tutorial"); @@ -742,7 +750,11 @@ export class Terminal implements ITerminal { } break; case iTutorialSteps.ActiveScriptsToTerminal: - if (commandArray.length == 2 && commandArray[0] == "tail" && commandArray[1] == "n00dles.script") { + if ( + commandArray.length == 2 && + commandArray[0] == "tail" && + (commandArray[1] == "n00dles.script" || commandArray[1] == "n00dles.js") + ) { iTutorialNextStep(); } else { this.error("Bad command. Please follow the tutorial"); diff --git a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx index 12eda15ab..befd01e6e 100644 --- a/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx +++ b/src/ui/InteractiveTutorial/InteractiveTutorialRoot.tsx @@ -9,6 +9,7 @@ import ArrowBackIos from "@mui/icons-material/ArrowBackIos"; import { ITutorialEvents } from "./ITutorialEvents"; import { CopyableText } from "../React/CopyableText"; +import List from "@mui/material/List"; import ListItem from "@mui/material/ListItem"; import EqualizerIcon from "@mui/icons-material/Equalizer"; import LastPageIcon from "@mui/icons-material/LastPage"; @@ -27,6 +28,7 @@ import { iTutorialSteps, iTutorialEnd, } from "../../InteractiveTutorial"; +import { NSSelection } from "./NSSelection"; interface IContent { content: React.ReactElement; @@ -45,9 +47,23 @@ const useStyles = makeStyles((theme: Theme) => }), ); +enum Language { + None, + NS1, + NS2, +} + export function InteractiveTutorialRoot(): React.ReactElement { + const [nsSelectionOpen, setNSSelectionOpen] = useState(false); + const [language, setLanguage] = useState(Language.None); const classes = useStyles(); + const tutorialScriptName = { + [Language.None]: "n00dles.script", + [Language.NS1]: "n00dles.script", + [Language.NS2]: "n00dles.js", + }[language]; + const contents: { [number: string]: IContent | undefined } = { [iTutorialSteps.Start as number]: { content: ( @@ -66,6 +82,47 @@ export function InteractiveTutorialRoot(): React.ReactElement { ), canNext: true, }, + [iTutorialSteps.NSSelection as number]: { + content: ( + <> + The tutorial will adjust to your programming ability. + Bitburner has 2 types of scripts: + + + NS1: Javascript from 2009, very simple. Recommended for beginner to programming. + + + + NS2: Native, modern Javascript. Recommended if you know any programming language or are serious about + learning programming. + + + + + Both are available at all time and interchangeably. This choice is only for the tutorial. + + + + +
+ + ), + canNext: false, + }, [iTutorialSteps.GoToCharacterPage as number]: { content: ( <> @@ -321,7 +378,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { {"[home ~/]> nano"} Scripts must end with the .script extension. Let's make a script now by entering - {"[home ~/]> nano n00dles.script"} + {`[home ~/]> nano ${tutorialScriptName}`} after the hack command finishes running (Sidenote: Pressing ctrl + c will end a command like hack early) @@ -334,16 +391,28 @@ export function InteractiveTutorialRoot(): React.ReactElement { content: ( <> - This is the script editor. You can use it to program your scripts. Scripts are written in a simplified - version of javascript. Copy and paste the following code into the script editor:
+ This is the script editor. You can use it to program your scripts.{" "} + {language !== Language.NS2 && <>Scripts are written in a simplified version of javascript.} Copy and + paste the following code into the script editor:
- + /> + )} + {language === Language.NS2 && ( + + )} For anyone with basic programming experience, this code should be straightforward. This script will @@ -378,7 +447,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { We have 8GB of free RAM on this machine, which is enough to run our script. Let's run our script using - {"[home ~/]> run n00dles.script"} + {`[home ~/]> run ${tutorialScriptName}`} ), canNext: false, @@ -425,7 +494,7 @@ export function InteractiveTutorialRoot(): React.ReactElement { 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{" "} - {"[home ~/]> tail n00dles.script"} + {`[home ~/]> tail ${tutorialScriptName}`} ), canNext: false, @@ -447,14 +516,6 @@ export function InteractiveTutorialRoot(): React.ReactElement { in the main navigation menu to look at the documentation.

- If you know even a little bit of programming it is highly recommended you use NS2 instead. You will enjoy - the game much more. NS1 files end with .script and are a subset of javascript. NS2 files end with .js and - are full speed native javascript. -
-
- You can learn more about the difference between them later in the documentation. -
-
For now, let's move on to something else!
@@ -549,25 +610,30 @@ export function InteractiveTutorialRoot(): React.ReactElement { const content = contents[step]; if (content === undefined) throw new Error("error in the tutorial"); return ( - - {content.content} - {step !== iTutorialSteps.TutorialPageInfo && ( - <> - - - - {content.canNext && ( - - - - )} - - )} -
-
- -
+ <> + setNSSelectionOpen(false)} /> + + {content.content} + {step !== iTutorialSteps.TutorialPageInfo && ( + <> + {step !== iTutorialSteps.Start && ( + + + + )} + {content.canNext && ( + + + + )} + + )} +
+
+ +
+ ); } diff --git a/src/ui/InteractiveTutorial/NSSelection.tsx b/src/ui/InteractiveTutorial/NSSelection.tsx new file mode 100644 index 000000000..848598d6a --- /dev/null +++ b/src/ui/InteractiveTutorial/NSSelection.tsx @@ -0,0 +1,82 @@ +import Editor from "@monaco-editor/react"; +import { Tab, Tabs, Typography } from "@mui/material"; +import React from "react"; + +import { Modal } from "../React/Modal"; + +import * as monaco from "monaco-editor"; + +type IStandaloneCodeEditor = monaco.editor.IStandaloneCodeEditor; + +interface IProps { + open: boolean; + onClose: () => void; +} + +const ns1Example = `while(true) { + hack('n00dles'); +}`; +const ns2Example = `/** @param {NS} ns */ +export async function main(ns) { + while(true) { + await ns.hack('n00dles'); + } +}`; + +export function NSSelection(props: IProps): React.ReactElement { + const [value, setValue] = React.useState(0); + + function handleChange(event: React.SyntheticEvent, tab: number): void { + setValue(tab); + } + + function onMount(editor: IStandaloneCodeEditor): void { + editor.updateOptions({ readOnly: true }); + } + + return ( + + + + + + + {value === 0 && ( + <> + + These scripts end with '.script'. Using a very old interpreted version of javascript. It is perfect for + beginner to programming. + + Example script using NS1: + } + defaultLanguage="javascript" + defaultValue={ns1Example} + height={`${300}px`} + theme={"vs-dark"} + onMount={onMount} + options={{ fontSize: 30 }} + /> + + )} + {value === 1 && ( + <> + + These scripts end with '.js'. Scripts using ns2 are running natively along the game. If you know any + programming language you should be using this. However if you're unfamiliar with javascript Promises you + might want to read up on them a little bit before diving in. + + Example script using NS2: + } + defaultLanguage="javascript" + defaultValue={ns2Example} + height={`${300}px`} + theme={"vs-dark"} + options={{ fontSize: 30 }} + /> + + )} + + ); +} diff --git a/src/ui/React/Modal.tsx b/src/ui/React/Modal.tsx index ce6c634c6..ca71d8be1 100644 --- a/src/ui/React/Modal.tsx +++ b/src/ui/React/Modal.tsx @@ -12,6 +12,7 @@ const useStyles = makeStyles((theme: Theme) => display: "flex", alignItems: "center", justifyContent: "center", + zIndex: 999999, }, paper: { backgroundColor: theme.palette.background.default,