mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-20 05:05:47 +01:00
Merge pull request #3586 from danielyxie/better-ns-tutorial
MISC: Make tutorial explain ns1 vs ns2 better
This commit is contained in:
commit
9f18e114d6
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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: (
|
||||
<>
|
||||
<Typography>The tutorial will adjust to your programming ability.</Typography>
|
||||
<Typography>Bitburner has 2 types of scripts:</Typography>
|
||||
<List>
|
||||
<ListItem>
|
||||
<Typography>NS1: Javascript from 2009, very simple. Recommended for beginners to programming.</Typography>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<Typography>
|
||||
NS2: Native, modern Javascript. Recommended if you know any programming language or are serious about
|
||||
learning programming.
|
||||
</Typography>
|
||||
</ListItem>
|
||||
</List>
|
||||
<Typography>
|
||||
Both are available at all time and interchangeably. This choice is only for the tutorial.
|
||||
</Typography>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setLanguage(Language.NS1);
|
||||
iTutorialNextStep();
|
||||
}}
|
||||
>
|
||||
Use NS1
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setLanguage(Language.NS2);
|
||||
iTutorialNextStep();
|
||||
}}
|
||||
>
|
||||
Use NS2
|
||||
</Button>
|
||||
<Button onClick={() => setNSSelectionOpen(true)}>More info</Button>
|
||||
<br />
|
||||
</>
|
||||
),
|
||||
canNext: false,
|
||||
},
|
||||
[iTutorialSteps.GoToCharacterPage as number]: {
|
||||
content: (
|
||||
<>
|
||||
@ -321,7 +378,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {
|
||||
<Typography classes={{ root: classes.textfield }}>{"[home ~/]> nano"}</Typography>
|
||||
|
||||
<Typography>Scripts must end with the .script extension. Let's make a script now by entering </Typography>
|
||||
<Typography classes={{ root: classes.textfield }}>{"[home ~/]> nano n00dles.script"}</Typography>
|
||||
<Typography classes={{ root: classes.textfield }}>{`[home ~/]> nano ${tutorialScriptName}`}</Typography>
|
||||
|
||||
<Typography>
|
||||
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: (
|
||||
<>
|
||||
<Typography>
|
||||
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: <br />
|
||||
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: <br />
|
||||
</Typography>
|
||||
|
||||
<Typography classes={{ root: classes.code }}>
|
||||
<CopyableText
|
||||
value={`while(true) {
|
||||
{language !== Language.NS2 && (
|
||||
<CopyableText
|
||||
value={`while(true) {
|
||||
hack('n00dles');
|
||||
}`}
|
||||
/>
|
||||
/>
|
||||
)}
|
||||
{language === Language.NS2 && (
|
||||
<CopyableText
|
||||
value={`export async function main(ns) {
|
||||
while(true) {
|
||||
await ns.hack('n00dles');
|
||||
}
|
||||
}`}
|
||||
/>
|
||||
)}
|
||||
</Typography>
|
||||
<Typography>
|
||||
For anyone with basic programming experience, this code should be straightforward. This script will
|
||||
@ -378,7 +447,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {
|
||||
<Typography>
|
||||
We have 8GB of free RAM on this machine, which is enough to run our script. Let's run our script using
|
||||
</Typography>
|
||||
<Typography classes={{ root: classes.textfield }}>{"[home ~/]> run n00dles.script"}</Typography>
|
||||
<Typography classes={{ root: classes.textfield }}>{`[home ~/]> run ${tutorialScriptName}`}</Typography>
|
||||
</>
|
||||
),
|
||||
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{" "}
|
||||
</Typography>
|
||||
<Typography classes={{ root: classes.textfield }}>{"[home ~/]> tail n00dles.script"}</Typography>
|
||||
<Typography classes={{ root: classes.textfield }}>{`[home ~/]> tail ${tutorialScriptName}`}</Typography>
|
||||
</>
|
||||
),
|
||||
canNext: false,
|
||||
@ -447,14 +516,6 @@ export function InteractiveTutorialRoot(): React.ReactElement {
|
||||
in the main navigation menu to look at the documentation.
|
||||
<br />
|
||||
<br />
|
||||
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.
|
||||
<br />
|
||||
<br />
|
||||
You can learn more about the difference between them later in the documentation.
|
||||
<br />
|
||||
<br />
|
||||
For now, let's move on to something else!
|
||||
</Typography>
|
||||
</>
|
||||
@ -549,25 +610,30 @@ export function InteractiveTutorialRoot(): React.ReactElement {
|
||||
const content = contents[step];
|
||||
if (content === undefined) throw new Error("error in the tutorial");
|
||||
return (
|
||||
<Paper square sx={{ maxWidth: "70vw", p: 2 }}>
|
||||
{content.content}
|
||||
{step !== iTutorialSteps.TutorialPageInfo && (
|
||||
<>
|
||||
<IconButton onClick={iTutorialPrevStep} aria-label="previous">
|
||||
<ArrowBackIos />
|
||||
</IconButton>
|
||||
{content.canNext && (
|
||||
<IconButton onClick={iTutorialNextStep} aria-label="next">
|
||||
<ArrowForwardIos />
|
||||
</IconButton>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<br />
|
||||
<br />
|
||||
<Button onClick={iTutorialEnd}>
|
||||
{step !== iTutorialSteps.TutorialPageInfo ? "SKIP TUTORIAL" : "FINISH TUTORIAL"}
|
||||
</Button>
|
||||
</Paper>
|
||||
<>
|
||||
<NSSelection open={nsSelectionOpen} onClose={() => setNSSelectionOpen(false)} />
|
||||
<Paper square sx={{ maxWidth: "70vw", p: 2 }}>
|
||||
{content.content}
|
||||
{step !== iTutorialSteps.TutorialPageInfo && (
|
||||
<>
|
||||
{step !== iTutorialSteps.Start && (
|
||||
<IconButton onClick={iTutorialPrevStep} aria-label="previous">
|
||||
<ArrowBackIos />
|
||||
</IconButton>
|
||||
)}
|
||||
{content.canNext && (
|
||||
<IconButton onClick={iTutorialNextStep} aria-label="next">
|
||||
<ArrowForwardIos />
|
||||
</IconButton>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<br />
|
||||
<br />
|
||||
<Button onClick={iTutorialEnd}>
|
||||
{step !== iTutorialSteps.TutorialPageInfo ? "SKIP TUTORIAL" : "FINISH TUTORIAL"}
|
||||
</Button>
|
||||
</Paper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
82
src/ui/InteractiveTutorial/NSSelection.tsx
Normal file
82
src/ui/InteractiveTutorial/NSSelection.tsx
Normal file
@ -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 (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Tabs variant="fullWidth" value={value} onChange={handleChange}>
|
||||
<Tab label="NS1" />
|
||||
<Tab label="NS2" />
|
||||
</Tabs>
|
||||
|
||||
{value === 0 && (
|
||||
<>
|
||||
<Typography>
|
||||
These scripts end with '.script'. Using a very old interpreted version of javascript. It is perfect for
|
||||
beginner to programming.
|
||||
</Typography>
|
||||
<Typography>Example script using NS1:</Typography>
|
||||
<Editor
|
||||
loading={<></>}
|
||||
defaultLanguage="javascript"
|
||||
defaultValue={ns1Example}
|
||||
height={`${300}px`}
|
||||
theme={"vs-dark"}
|
||||
onMount={onMount}
|
||||
options={{ fontSize: 30 }}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{value === 1 && (
|
||||
<>
|
||||
<Typography>
|
||||
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.
|
||||
</Typography>
|
||||
<Typography>Example script using NS2:</Typography>
|
||||
<Editor
|
||||
loading={<></>}
|
||||
defaultLanguage="javascript"
|
||||
defaultValue={ns2Example}
|
||||
height={`${300}px`}
|
||||
theme={"vs-dark"}
|
||||
options={{ fontSize: 30 }}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
}
|
@ -12,6 +12,7 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
zIndex: 999999,
|
||||
},
|
||||
paper: {
|
||||
backgroundColor: theme.palette.background.default,
|
||||
|
Loading…
Reference in New Issue
Block a user