From 339d9a8d96e70e27dee73ee40d827cfc8061d4a4 Mon Sep 17 00:00:00 2001
From: Olivier Gagnon <oli.gagnon4418@gmail.com>
Date: Fri, 10 Sep 2021 16:08:58 -0400
Subject: [PATCH] more cleanup in engine

---
 src/Augmentation/AugmentationHelpers.jsx      |  16 -
 src/Milestones/MilestoneHelpers.tsx           |  26 --
 .../ui/{Root.tsx => MilestonesRoot.tsx}       |   2 +-
 src/PersonObjects/IPlayer.ts                  |   1 +
 src/Prestige.js                               |   2 +-
 src/Programs/ProgramHelpers.js                |  40 +--
 src/Programs/ui/ProgramsRoot.tsx              |  49 ++++
 src/Terminal.jsx                              |   4 +-
 src/Tutorial/ui/TutorialRoot.tsx              |  99 +++++++
 src/engine.jsx                                | 243 ++++++---------
 src/index.html                                | 277 ++----------------
 11 files changed, 269 insertions(+), 490 deletions(-)
 delete mode 100644 src/Milestones/MilestoneHelpers.tsx
 rename src/Milestones/ui/{Root.tsx => MilestonesRoot.tsx} (94%)
 create mode 100644 src/Programs/ui/ProgramsRoot.tsx
 create mode 100644 src/Tutorial/ui/TutorialRoot.tsx

diff --git a/src/Augmentation/AugmentationHelpers.jsx b/src/Augmentation/AugmentationHelpers.jsx
index e9da71d17..d71909c97 100644
--- a/src/Augmentation/AugmentationHelpers.jsx
+++ b/src/Augmentation/AugmentationHelpers.jsx
@@ -2455,22 +2455,6 @@ function augmentationExists(name) {
   return Augmentations.hasOwnProperty(name);
 }
 
-export function displayAugmentationsContent(contentEl) {
-  if (!routing.isOn(Page.Augmentations)) {
-    return;
-  }
-  if (!(contentEl instanceof HTMLElement)) {
-    return;
-  }
-
-  function backup() {
-    saveObject.exportGame();
-    onExport(Player);
-  }
-
-  ReactDOM.render(<AugmentationsRoot exportGameFn={backup} installAugmentationsFn={installAugmentations} />, contentEl);
-}
-
 export function isRepeatableAug(aug) {
   const augName = aug instanceof Augmentation ? aug.name : aug;
 
diff --git a/src/Milestones/MilestoneHelpers.tsx b/src/Milestones/MilestoneHelpers.tsx
deleted file mode 100644
index 7ea791d77..000000000
--- a/src/Milestones/MilestoneHelpers.tsx
+++ /dev/null
@@ -1,26 +0,0 @@
-import { Page, routing } from ".././ui/navigationTracking";
-import { Root } from "./ui/Root";
-import { Player } from "../Player";
-import * as React from "react";
-import * as ReactDOM from "react-dom";
-
-let milestonesContainer: HTMLElement | null = null;
-
-(function () {
-  function setContainer(): void {
-    milestonesContainer = document.getElementById("milestones-container");
-    document.removeEventListener("DOMContentLoaded", setContainer);
-  }
-
-  document.addEventListener("DOMContentLoaded", setContainer);
-})();
-
-export function displayMilestonesContent(): void {
-  if (!routing.isOn(Page.Milestones)) {
-    return;
-  }
-
-  if (milestonesContainer instanceof HTMLElement) {
-    ReactDOM.render(<Root player={Player} />, milestonesContainer);
-  }
-}
diff --git a/src/Milestones/ui/Root.tsx b/src/Milestones/ui/MilestonesRoot.tsx
similarity index 94%
rename from src/Milestones/ui/Root.tsx
rename to src/Milestones/ui/MilestonesRoot.tsx
index 5f108a708..46d682dd9 100644
--- a/src/Milestones/ui/Root.tsx
+++ b/src/Milestones/ui/MilestonesRoot.tsx
@@ -16,7 +16,7 @@ function highestMilestone(p: IPlayer, milestones: Milestone[]): number {
   return n;
 }
 
-export function Root(props: IProps): JSX.Element {
+export function MilestonesRoot(props: IProps): JSX.Element {
   const n = highestMilestone(props.player, Milestones);
   const milestones = Milestones.map((milestone: Milestone, i: number) => {
     if (i <= n + 1) {
diff --git a/src/PersonObjects/IPlayer.ts b/src/PersonObjects/IPlayer.ts
index ef772bef7..383e492bf 100644
--- a/src/PersonObjects/IPlayer.ts
+++ b/src/PersonObjects/IPlayer.ts
@@ -192,4 +192,5 @@ export interface IPlayer {
   getCasinoWinnings(): number;
   quitJob(company: string): void;
   createHacknetServer(): void;
+  startCreateProgramWork(programName: string, time: number, reqLevel: number): void;
 }
diff --git a/src/Prestige.js b/src/Prestige.js
index 31813d446..835bb7a1b 100755
--- a/src/Prestige.js
+++ b/src/Prestige.js
@@ -23,7 +23,7 @@ import { prestigeHomeComputer } from "./Server/ServerHelpers";
 import { SourceFileFlags, updateSourceFileFlags } from "./SourceFile/SourceFileFlags";
 import { SpecialServerIps, prestigeSpecialServerIps, SpecialServerNames } from "./Server/SpecialServerIps";
 import { deleteStockMarket, initStockMarket, initSymbolToStockMap } from "./StockMarket/StockMarket";
-import { Terminal, postNetburnerText } from "./Terminal";
+import { Terminal, postVersion } from "./Terminal";
 
 import { Page, routing } from "./ui/navigationTracking";
 
diff --git a/src/Programs/ProgramHelpers.js b/src/Programs/ProgramHelpers.js
index acc880c25..ee807392a 100644
--- a/src/Programs/ProgramHelpers.js
+++ b/src/Programs/ProgramHelpers.js
@@ -3,19 +3,6 @@ import { Programs } from "./Programs";
 import { Player } from "../Player";
 import { createElement } from "../../utils/uiHelpers/createElement";
 
-// this has the same key as 'Programs', not program names
-const aLinks = {};
-
-function displayCreateProgramContent() {
-  for (const key in aLinks) {
-    const p = Programs[key];
-    aLinks[key].style.display = "none";
-    if (!Player.hasProgram(p.name) && p.create.req(Player)) {
-      aLinks[key].style.display = "inline-block";
-    }
-  }
-}
-
 //Returns the number of programs that are currently available to be created
 function getNumAvailableCreateProgram() {
   var count = 0;
@@ -46,29 +33,4 @@ function getNumAvailableCreateProgram() {
   return count;
 }
 
-function initCreateProgramButtons() {
-  const createProgramList = document.getElementById("create-program-list");
-  for (const key in Programs) {
-    if (Programs[key].create === null) {
-      continue;
-    }
-    const elem = createElement("a", {
-      class: "a-link-button",
-      id: Programs[key].htmlID(),
-      innerText: Programs[key].name,
-      tooltip: Programs[key].create.tooltip,
-    });
-    aLinks[key] = elem;
-    createProgramList.appendChild(elem);
-  }
-
-  for (const key in aLinks) {
-    const p = Programs[key];
-    aLinks[key].addEventListener("click", function () {
-      Player.startCreateProgramWork(p.name, p.create.time, p.create.level);
-      return false;
-    });
-  }
-}
-
-export { displayCreateProgramContent, getNumAvailableCreateProgram, initCreateProgramButtons };
+export { getNumAvailableCreateProgram };
diff --git a/src/Programs/ui/ProgramsRoot.tsx b/src/Programs/ui/ProgramsRoot.tsx
new file mode 100644
index 000000000..a163e47c2
--- /dev/null
+++ b/src/Programs/ui/ProgramsRoot.tsx
@@ -0,0 +1,49 @@
+import React, { useState, useEffect } from "react";
+import { IPlayer } from "../../PersonObjects/IPlayer";
+import { Programs } from "../Programs";
+
+interface IProps {
+  player: IPlayer;
+}
+
+export function ProgramsRoot(props: IProps): React.ReactElement {
+  const setRerender = useState(false)[1];
+  function rerender(): void {
+    setRerender((old) => !old);
+  }
+  const [divisionName, setDivisionName] = useState("Overview");
+
+  useEffect(() => {
+    const id = setInterval(rerender, 20);
+    return () => clearInterval(id);
+  }, []);
+
+  return (
+    <>
+      <p id="create-program-page-text">
+        This page displays any programs that you are able to create. Writing the code for a program takes time, which
+        can vary based on how complex the program is. If you are working on creating a program you can cancel at any
+        time. Your progress will be saved and you can continue later.
+      </p>
+
+      <ul id="create-program-list">
+        {Object.keys(Programs).map((programName) => {
+          const program = Programs[programName];
+          if (program == null) return <></>;
+          const create = program.create;
+          if (create === null) return <></>;
+          return (
+            <a
+              key={programName}
+              className="a-link-button tooltip"
+              onClick={() => props.player.startCreateProgramWork(program.name, create.time, create.level)}
+            >
+              {program.name}
+              <span className="tooltiptext">{create.tooltip}</span>
+            </a>
+          );
+        })}
+      </ul>
+    </>
+  );
+}
diff --git a/src/Terminal.jsx b/src/Terminal.jsx
index 4672504ea..0bd9a08ea 100644
--- a/src/Terminal.jsx
+++ b/src/Terminal.jsx
@@ -64,7 +64,7 @@ import * as FileSaver from "file-saver";
 import * as libarg from "arg";
 import React from "react";
 
-function postNetburnerText() {
+function postVersion() {
   post("Bitburner v" + CONSTANTS.Version);
 }
 
@@ -2616,4 +2616,4 @@ let Terminal = {
   },
 };
 
-export { postNetburnerText, Terminal };
+export { postVersion, Terminal };
diff --git a/src/Tutorial/ui/TutorialRoot.tsx b/src/Tutorial/ui/TutorialRoot.tsx
new file mode 100644
index 000000000..3c21168b4
--- /dev/null
+++ b/src/Tutorial/ui/TutorialRoot.tsx
@@ -0,0 +1,99 @@
+import React from "react";
+
+export function TutorialRoot(): React.ReactElement {
+  return (
+    <>
+      <h1>Tutorial (AKA Links to Documentation)</h1>
+      <a
+        id="tutorial-getting-started-link"
+        className="a-link-button"
+        target="_blank"
+        href="https://bitburner.readthedocs.io/en/latest/guidesandtips/gettingstartedguideforbeginnerprogrammers.html"
+      >
+        Getting Started
+      </a>
+      <br />
+      <br />
+      <a
+        className="a-link-button"
+        target="_blank"
+        href="https://bitburner.readthedocs.io/en/latest/basicgameplay/servers.html"
+      >
+        Servers & Networking
+      </a>
+      <br />
+      <br />
+      <a
+        className="a-link-button"
+        target="_blank"
+        href="https://bitburner.readthedocs.io/en/latest/basicgameplay/hacking.html"
+      >
+        Hacking
+      </a>
+      <br />
+      <br />
+      <a
+        className="a-link-button"
+        target="_blank"
+        href="https://bitburner.readthedocs.io/en/latest/basicgameplay/scripts.html"
+      >
+        Scripts
+      </a>
+      <br />
+      <br />
+      <a className="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/netscript.html">
+        Netscript Programming Language
+      </a>
+      <br />
+      <br />
+      <a
+        className="a-link-button"
+        target="_blank"
+        href="https://bitburner.readthedocs.io/en/latest/basicgameplay/world.html"
+      >
+        Traveling
+      </a>
+      <br />
+      <br />
+      <a
+        className="a-link-button"
+        target="_blank"
+        href="https://bitburner.readthedocs.io/en/latest/basicgameplay/companies.html"
+      >
+        Companies
+      </a>
+      <br />
+      <br />
+      <a
+        className="a-link-button"
+        target="_blank"
+        href="https://bitburner.readthedocs.io/en/latest/basicgameplay/infiltration.html"
+      >
+        Infiltration
+      </a>
+      <br />
+      <br />
+      <a
+        className="a-link-button"
+        target="_blank"
+        href="https://bitburner.readthedocs.io/en/latest/basicgameplay/factions.html"
+      >
+        Factions
+      </a>
+      <br />
+      <br />
+      <a
+        className="a-link-button"
+        target="_blank"
+        href="https://bitburner.readthedocs.io/en/latest/basicgameplay/augmentations.html"
+      >
+        Augmentations
+      </a>
+      <br />
+      <br />
+      <a className="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/shortcuts.html">
+        Keyboard Shortcuts
+      </a>
+    </>
+  );
+}
diff --git a/src/engine.jsx b/src/engine.jsx
index 7807a157b..7f40aa2bd 100644
--- a/src/engine.jsx
+++ b/src/engine.jsx
@@ -5,7 +5,13 @@
  */
 import { convertTimeMsToTimeElapsedString, replaceAt } from "../utils/StringHelperFunctions";
 import { Augmentations } from "./Augmentation/Augmentations";
-import { initAugmentations, displayAugmentationsContent } from "./Augmentation/AugmentationHelpers";
+import {
+  initAugmentations,
+  displayAugmentationsContent,
+  installAugmentations,
+} from "./Augmentation/AugmentationHelpers";
+import { onExport } from "./ExportBonus";
+import { AugmentationsRoot } from "./Augmentation/ui/Root";
 import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
 import { initBitNodeMultipliers } from "./BitNode/BitNode";
 import { Bladeburner } from "./Bladeburner/Bladeburner";
@@ -42,11 +48,8 @@ import { workerScripts } from "./Netscript/WorkerScripts";
 import { loadAllRunningScripts, updateOnlineScriptTimes } from "./NetscriptWorker";
 import { Player } from "./Player";
 import { prestigeAugmentation } from "./Prestige";
-import {
-  displayCreateProgramContent,
-  getNumAvailableCreateProgram,
-  initCreateProgramButtons,
-} from "./Programs/ProgramHelpers";
+import { getNumAvailableCreateProgram } from "./Programs/ProgramHelpers";
+import { ProgramsRoot } from "./Programs/ui/ProgramsRoot";
 import { redPillFlag } from "./RedPill";
 import { saveObject, loadGame } from "./SaveObject";
 import { Root as ScriptEditorRoot } from "./ScriptEditor/ui/Root";
@@ -55,8 +58,9 @@ import { Settings } from "./Settings/Settings";
 import { updateSourceFileFlags } from "./SourceFile/SourceFileFlags";
 import { initSpecialServerIps } from "./Server/SpecialServerIps";
 import { initSymbolToStockMap, processStockPrices, displayStockMarketContent } from "./StockMarket/StockMarket";
-import { displayMilestonesContent } from "./Milestones/MilestoneHelpers";
-import { Terminal, postNetburnerText } from "./Terminal";
+import { MilestonesRoot } from "./Milestones/ui/MilestonesRoot";
+import { Terminal, postVersion } from "./Terminal";
+import { TutorialRoot } from "./Tutorial/ui/TutorialRoot";
 import { Sleeve } from "./PersonObjects/Sleeve/Sleeve";
 
 import { createStatusText } from "./ui/createStatusText";
@@ -197,9 +201,6 @@ const Engine = {
     redPillContent: null,
     cinematicTextContent: null,
     missionContent: null,
-
-    // Character info
-    characterInfo: null,
   },
 
   indexedDb: undefined,
@@ -218,8 +219,8 @@ const Engine = {
   loadCharacterContent: function () {
     Engine.hideAllContent();
     Engine.Display.characterContent.style.display = "block";
-    ReactDOM.render(<CharacterInfo player={Player} />, Engine.Display.characterInfo);
     routing.navigateTo(Page.CharacterInfo);
+    ReactDOM.render(<CharacterInfo player={Player} />, Engine.Display.characterContent);
     MainMenuLinks.Stats.classList.add("active");
   },
 
@@ -227,50 +228,49 @@ const Engine = {
     Engine.hideAllContent();
     Engine.Display.scriptEditorContent.style.display = "block";
     routing.navigateTo(Page.ScriptEditor);
-
+    MainMenuLinks.ScriptEditor.classList.add("active");
     ReactDOM.render(
       <ScriptEditorRoot filename={filename} code={code} player={Player} engine={this} />,
       Engine.Display.scriptEditorContent,
     );
-
-    MainMenuLinks.ScriptEditor.classList.add("active");
   },
 
   loadActiveScriptsContent: function () {
     Engine.hideAllContent();
     Engine.Display.activeScriptsContent.style.display = "block";
     routing.navigateTo(Page.ActiveScripts);
+    MainMenuLinks.ActiveScripts.classList.add("active");
     ReactDOM.render(
       <ActiveScriptsRoot p={Player} workerScripts={workerScripts} />,
       Engine.Display.activeScriptsContent,
     );
-    MainMenuLinks.ActiveScripts.classList.add("active");
   },
 
   loadHacknetNodesContent: function () {
     Engine.hideAllContent();
     Engine.Display.hacknetNodesContent.style.display = "block";
     routing.navigateTo(Page.HacknetNodes);
-    ReactDOM.render(<HacknetRoot player={Player} />, Engine.Display.hacknetNodesContent);
     MainMenuLinks.HacknetNodes.classList.add("active");
+    ReactDOM.render(<HacknetRoot player={Player} />, Engine.Display.hacknetNodesContent);
   },
 
   loadCreateProgramContent: function () {
     Engine.hideAllContent();
     Engine.Display.createProgramContent.style.display = "block";
-    displayCreateProgramContent();
     routing.navigateTo(Page.CreateProgram);
     MainMenuLinks.CreateProgram.classList.add("active");
+    ReactDOM.render(<ProgramsRoot player={Player} />, Engine.Display.createProgramContent);
   },
 
   loadFactionsContent: function () {
     Engine.hideAllContent();
     Engine.Display.factionsContent.style.display = "block";
     routing.navigateTo(Page.Factions);
-    ReactDOM.render(<FactionList player={Player} engine={this} />, Engine.Display.factionsContent);
     MainMenuLinks.Factions.classList.add("active");
+    ReactDOM.render(<FactionList player={Player} engine={this} />, Engine.Display.factionsContent);
   },
 
+  // TODO reactify
   loadFactionContent: function () {
     Engine.hideAllContent();
     Engine.Display.factionContent.style.display = "block";
@@ -281,16 +281,25 @@ const Engine = {
     Engine.hideAllContent();
     Engine.Display.augmentationsContent.style.display = "block";
     routing.navigateTo(Page.Augmentations);
-    displayAugmentationsContent(Engine.Display.augmentationsContent);
     MainMenuLinks.Augmentations.classList.add("active");
+
+    function backup() {
+      saveObject.exportGame();
+      onExport(Player);
+    }
+
+    ReactDOM.render(
+      <AugmentationsRoot exportGameFn={backup} installAugmentationsFn={installAugmentations} />,
+      Engine.Display.augmentationsContent,
+    );
   },
 
   loadMilestonesContent: function () {
     Engine.hideAllContent();
     Engine.Display.milestonesContent.style.display = "block";
     routing.navigateTo(Page.Milestones);
-    displayMilestonesContent();
     MainMenuLinks.Milestones.classList.add("active");
+    ReactDOM.render(<MilestonesRoot player={Player} />, Engine.Display.milestonesContent);
   },
 
   loadTutorialContent: function () {
@@ -298,8 +307,10 @@ const Engine = {
     Engine.Display.tutorialContent.style.display = "block";
     routing.navigateTo(Page.Tutorial);
     MainMenuLinks.Tutorial.classList.add("active");
+    ReactDOM.render(<TutorialRoot />, Engine.Display.tutorialContent);
   },
 
+  // TODO reactify
   loadDevMenuContent: function () {
     Engine.hideAllContent();
     createDevMenu();
@@ -310,11 +321,12 @@ const Engine = {
   loadLocationContent: function (initiallyInCity = true) {
     Engine.hideAllContent();
     Engine.Display.locationContent.style.display = "block";
-    MainMenuLinks.City.classList.add("active");
-
     routing.navigateTo(Page.Location);
-    const rootComponent = <LocationRoot initiallyInCity={initiallyInCity} engine={Engine} p={Player} />;
-    ReactDOM.render(rootComponent, Engine.Display.locationContent);
+    MainMenuLinks.City.classList.add("active");
+    ReactDOM.render(
+      <LocationRoot initiallyInCity={initiallyInCity} engine={Engine} p={Player} />,
+      Engine.Display.locationContent,
+    );
   },
 
   loadTravelContent: function () {
@@ -323,11 +335,12 @@ const Engine = {
     Engine.hideAllContent();
     Player.gotoLocation(LocationName.TravelAgency);
     Engine.Display.locationContent.style.display = "block";
-    MainMenuLinks.Travel.classList.add("active");
-
     routing.navigateTo(Page.Location);
-    const rootComponent = <LocationRoot initiallyInCity={false} engine={Engine} p={Player} />;
-    ReactDOM.render(rootComponent, Engine.Display.locationContent);
+    MainMenuLinks.Travel.classList.add("active");
+    ReactDOM.render(
+      <LocationRoot initiallyInCity={false} engine={Engine} p={Player} />,
+      Engine.Display.locationContent,
+    );
   },
 
   loadJobContent: function () {
@@ -342,29 +355,33 @@ const Engine = {
     Engine.hideAllContent();
     Player.gotoLocation(Player.companyName);
     Engine.Display.locationContent.style.display = "block";
-    MainMenuLinks.Job.classList.add("active");
-
     routing.navigateTo(Page.Location);
-    const rootComponent = <LocationRoot initiallyInCity={false} engine={Engine} p={Player} />;
-    ReactDOM.render(rootComponent, Engine.Display.locationContent);
+    MainMenuLinks.Job.classList.add("active");
+    ReactDOM.render(
+      <LocationRoot initiallyInCity={false} engine={Engine} p={Player} />,
+      Engine.Display.locationContent,
+    );
   },
 
+  // TODO reactify
   loadWorkInProgressContent: function () {
     Engine.hideAllContent();
-    var mainMenu = document.getElementById("mainmenu-container");
+    const mainMenu = document.getElementById("mainmenu-container");
     mainMenu.style.visibility = "hidden";
     Engine.Display.workInProgressContent.style.display = "block";
     routing.navigateTo(Page.WorkInProgress);
   },
 
+  // TODO reactify
   loadRedPillContent: function () {
     Engine.hideAllContent();
-    var mainMenu = document.getElementById("mainmenu-container");
+    const mainMenu = document.getElementById("mainmenu-container");
     mainMenu.style.visibility = "hidden";
     Engine.Display.redPillContent.style.display = "block";
     routing.navigateTo(Page.RedPill);
   },
 
+  // TODO reactify
   loadCinematicTextContent: function () {
     Engine.hideAllContent();
     var mainMenu = document.getElementById("mainmenu-container");
@@ -373,6 +390,7 @@ const Engine = {
     routing.navigateTo(Page.CinematicText);
   },
 
+  // TODO reactify
   loadInfiltrationContent: function (name, difficulty, maxLevel) {
     Engine.hideAllContent();
     const mainMenu = document.getElementById("mainmenu-container");
@@ -386,19 +404,17 @@ const Engine = {
     Engine.hideAllContent();
     Engine.Display.stockMarketContent.style.display = "block";
     routing.navigateTo(Page.StockMarket);
+    MainMenuLinks.StockMarket.classList.add("active");
     displayStockMarketContent();
   },
 
   loadGangContent: function () {
+    if (!Player.inGang()) return;
     Engine.hideAllContent();
-    if (Player.inGang()) {
-      Engine.Display.gangContent.style.display = "block";
-      routing.navigateTo(Page.Gang);
-      ReactDOM.render(<GangRoot engine={this} gang={Player.gang} player={Player} />, Engine.Display.gangContent);
-    } else {
-      Engine.loadTerminalContent();
-      routing.navigateTo(Page.Terminal);
-    }
+    Engine.Display.gangContent.style.display = "block";
+    routing.navigateTo(Page.Gang);
+    MainMenuLinks.Gang.classList.add("active");
+    ReactDOM.render(<GangRoot engine={this} gang={Player.gang} player={Player} />, Engine.Display.gangContent);
   },
 
   loadMissionContent: function () {
@@ -412,27 +428,28 @@ const Engine = {
   loadCorporationContent: function () {
     if (!(Player.corporation instanceof Corporation)) return;
     Engine.hideAllContent();
-    routing.navigateTo(Page.Corporation);
     Engine.Display.corporationContent.style.display = "block";
+    routing.navigateTo(Page.Corporation);
+    MainMenuLinks.Corporation.classList.add("active");
     ReactDOM.render(<CorporationRoot corp={Player.corporation} player={Player} />, Engine.Display.corporationContent);
   },
 
   loadBladeburnerContent: function () {
     if (!(Player.bladeburner instanceof Bladeburner)) return;
     Engine.hideAllContent();
-    routing.navigateTo(Page.Bladeburner);
     Engine.Display.bladeburnerContent.style.display = "block";
+    routing.navigateTo(Page.Bladeburner);
+    MainMenuLinks.Bladeburner.classList.add("active");
     ReactDOM.render(
       <BladeburnerRoot bladeburner={Player.bladeburner} player={Player} engine={this} />,
       Engine.Display.bladeburnerContent,
     );
-    MainMenuLinks.Bladeburner.classList.add("active");
   },
 
   loadSleevesContent: function () {
     Engine.hideAllContent();
-    routing.navigateTo(Page.Sleeves);
     Engine.Display.sleevesContent.style.display = "block";
+    routing.navigateTo(Page.Sleeves);
     ReactDOM.render(<SleeveRoot player={Player} />, Engine.Display.sleevesContent);
   },
 
@@ -440,6 +457,7 @@ const Engine = {
     Engine.hideAllContent();
     routing.navigateTo(Page.Resleeves);
     Engine.Display.resleeveContent.style.display = "block";
+    MainMenuLinks.City.classList.add("active");
     ReactDOM.render(<ResleeveRoot player={Player} />, Engine.Display.resleeveContent);
   },
 
@@ -716,10 +734,6 @@ const Engine = {
 
     if (Engine.Counters.updateDisplays <= 0) {
       Engine.displayCharacterOverviewInfo();
-      if (routing.isOn(Page.CreateProgram)) {
-        displayCreateProgramContent();
-      }
-
       Engine.Counters.updateDisplays = 3;
     }
 
@@ -1238,9 +1252,6 @@ const Engine = {
     Engine.Display.missionContent = document.getElementById("mission-container");
     Engine.Display.missionContent.style.display = "none";
 
-    // Character info
-    Engine.Display.characterInfo = document.getElementById("character-content");
-
     // Location page (page that shows up when you visit a specific location in World)
     Engine.Display.locationContent = document.getElementById("location-container");
     Engine.Display.locationContent.style.display = "none";
@@ -1285,110 +1296,30 @@ const Engine = {
       return;
     }
 
-    MainMenuLinks.Terminal.addEventListener("click", function () {
-      Engine.loadTerminalContent();
-      return false;
-    });
-
-    MainMenuLinks.ScriptEditor.addEventListener("click", function () {
-      Engine.loadScriptEditorContent();
-      return false;
-    });
-
-    MainMenuLinks.ActiveScripts.addEventListener("click", function () {
-      Engine.loadActiveScriptsContent();
-      return false;
-    });
-
-    MainMenuLinks.CreateProgram.addEventListener("click", function () {
-      Engine.loadCreateProgramContent();
-      return false;
-    });
-
-    MainMenuLinks.Stats.addEventListener("click", function () {
-      Engine.loadCharacterContent();
-      return false;
-    });
-
-    MainMenuLinks.Factions.addEventListener("click", function () {
-      Engine.loadFactionsContent();
-      return false;
-    });
-
-    MainMenuLinks.Augmentations.addEventListener("click", function () {
-      Engine.loadAugmentationsContent();
-      return false;
-    });
-
-    MainMenuLinks.HacknetNodes.addEventListener("click", function () {
-      Engine.loadHacknetNodesContent();
-      return false;
-    });
-
-    MainMenuLinks.Sleeves.addEventListener("click", function () {
-      Engine.loadSleevesContent();
-      MainMenuLinks.Sleeves.classList.add("active");
-      return false;
-    });
-
-    MainMenuLinks.City.addEventListener("click", function () {
-      Engine.loadLocationContent();
-      return false;
-    });
-
-    MainMenuLinks.Travel.addEventListener("click", function () {
-      Engine.loadTravelContent();
-      return false;
-    });
-
-    MainMenuLinks.Job.addEventListener("click", function () {
-      Engine.loadJobContent();
-      return false;
-    });
-
-    MainMenuLinks.StockMarket.addEventListener("click", function () {
-      Engine.loadStockMarketContent();
-      MainMenuLinks.StockMarket.classList.add("active");
-      return false;
-    });
-
-    MainMenuLinks.Bladeburner.addEventListener("click", function () {
-      Engine.loadBladeburnerContent();
-      return false;
-    });
-
-    MainMenuLinks.Corporation.addEventListener("click", function () {
-      Engine.loadCorporationContent();
-      MainMenuLinks.Corporation.classList.add("active");
-      return false;
-    });
-
-    MainMenuLinks.Gang.addEventListener("click", function () {
-      Engine.loadGangContent();
-      MainMenuLinks.Gang.classList.add("active");
-      return false;
-    });
-
-    MainMenuLinks.Milestones.addEventListener("click", function () {
-      Engine.loadMilestonesContent();
-      return false;
-    });
-
-    MainMenuLinks.Tutorial.addEventListener("click", function () {
-      Engine.loadTutorialContent();
-      return false;
-    });
-
+    MainMenuLinks.Terminal.addEventListener("click", () => Engine.loadTerminalContent());
+    MainMenuLinks.ScriptEditor.addEventListener("click", () => Engine.loadScriptEditorContent());
+    MainMenuLinks.ActiveScripts.addEventListener("click", () => Engine.loadActiveScriptsContent());
+    MainMenuLinks.CreateProgram.addEventListener("click", () => Engine.loadCreateProgramContent());
+    MainMenuLinks.Stats.addEventListener("click", () => Engine.loadCharacterContent());
+    MainMenuLinks.Factions.addEventListener("click", () => Engine.loadFactionsContent());
+    MainMenuLinks.Augmentations.addEventListener("click", () => Engine.loadAugmentationsContent());
+    MainMenuLinks.HacknetNodes.addEventListener("click", () => Engine.loadHacknetNodesContent());
+    MainMenuLinks.Sleeves.addEventListener("click", () => Engine.loadSleevesContent());
+    MainMenuLinks.City.addEventListener("click", () => Engine.loadLocationContent());
+    MainMenuLinks.Travel.addEventListener("click", () => Engine.loadTravelContent());
+    MainMenuLinks.Job.addEventListener("click", () => Engine.loadJobContent());
+    MainMenuLinks.StockMarket.addEventListener("click", () => Engine.loadStockMarketContent());
+    MainMenuLinks.Bladeburner.addEventListener("click", () => Engine.loadBladeburnerContent());
+    MainMenuLinks.Corporation.addEventListener("click", () => Engine.loadCorporationContent());
+    MainMenuLinks.Gang.addEventListener("click", () => Engine.loadGangContent());
+    MainMenuLinks.Milestones.addEventListener("click", () => Engine.loadMilestonesContent());
+    MainMenuLinks.Tutorial.addEventListener("click", () => Engine.loadTutorialContent());
     MainMenuLinks.DevMenu.addEventListener("click", function () {
       if (process.env.NODE_ENV === "development") {
         Engine.loadDevMenuContent();
       }
-      return false;
     });
 
-    // Active scripts list
-    Engine.ActiveScriptsList = document.getElementById("active-scripts-list");
-
     // Save, Delete, Import/Export buttons
     Engine.Clickables.saveMainMenuButton = document.getElementById("save-game-link");
     Engine.Clickables.saveMainMenuButton.addEventListener("click", function () {
@@ -1418,11 +1349,8 @@ const Engine = {
       return false;
     });
 
-    // Create Program buttons
-    initCreateProgramButtons();
-
     // Message at the top of terminal
-    postNetburnerText();
+    postVersion();
 
     // Player was working cancel button
     if (Player.isWorking) {
@@ -1517,7 +1445,6 @@ const Engine = {
       }
       dialogBoxCreate("Forcefully deleted all running scripts. Please save and refresh page.");
       gameOptionsBoxClose();
-      return false;
     });
 
     // DEBUG Soft Reset
@@ -1525,13 +1452,11 @@ const Engine = {
       dialogBoxCreate("Soft Reset!");
       prestigeAugmentation();
       gameOptionsBoxClose();
-      return false;
     });
 
     // DEBUG File diagnostic
     document.getElementById("debug-files").addEventListener("click", function () {
       createPopup("debug-files-diagnostic-popup", FileDiagnosticPopup, {});
-      return false;
     });
   },
 
diff --git a/src/index.html b/src/index.html
index c1c0528f3..943739abd 100644
--- a/src/index.html
+++ b/src/index.html
@@ -41,178 +41,93 @@
     <div id="entire-game-container" style="visibility: hidden">
       <div id="mainmenu-container">
         <!-- Main menu -->
-        <ul id="mainmenu" class="mainmenu noscrollbar">
+        <ul id="mainmenu" class="mainmenu noscrollbar noselect">
           <!-- Hacking dropdown -->
           <li id="hacking-menu-header-li">
-            <button id="hacking-menu-header" class="mainmenu-accordion-header noselect">Hacking</button>
+            <button id="hacking-menu-header" class="mainmenu-accordion-header">Hacking</button>
           </li>
-          <li id="terminal-tab" class="mainmenu-accordion-panel noselect">
+          <li id="terminal-tab" class="mainmenu-accordion-panel">
             <button id="terminal-menu-link">Terminal</button>
           </li>
-          <li id="create-script-tab" class="mainmenu-accordion-panel noselect">
+          <li id="create-script-tab" class="mainmenu-accordion-panel">
             <button id="create-script-menu-link">Create Script</button>
           </li>
-          <li id="active-scripts-tab" class="mainmenu-accordion-panel noselect">
+          <li id="active-scripts-tab" class="mainmenu-accordion-panel">
             <button id="active-scripts-menu-link">Active Scripts</button>
           </li>
-          <li id="create-program-tab" class="mainmenu-accordion-panel noselect">
+          <li id="create-program-tab" class="mainmenu-accordion-panel">
             <button id="create-program-menu-link">Create Program</button>
             <span id="create-program-notification" class="notification-off"> </span>
           </li>
 
           <!-- Character dropdown -->
           <li id="character-menu-header-li">
-            <button id="character-menu-header" class="mainmenu-accordion-header noselect">Character</button>
+            <button id="character-menu-header" class="mainmenu-accordion-header">Character</button>
           </li>
-          <li id="stats-tab" class="mainmenu-accordion-panel noselect">
+          <li id="stats-tab" class="mainmenu-accordion-panel">
             <button id="stats-menu-link">Stats</button>
           </li>
-          <li id="factions-tab" class="mainmenu-accordion-panel noselect">
+          <li id="factions-tab" class="mainmenu-accordion-panel">
             <button id="factions-menu-link">Factions</button>
             <span id="factions-notification" class="notification-off"> </span>
           </li>
-          <li id="augmentations-tab" class="mainmenu-accordion-panel noselect">
+          <li id="augmentations-tab" class="mainmenu-accordion-panel">
             <button id="augmentations-menu-link" style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap">
               Augmentations
             </button>
             <span id="augmentations-notification" class="notification-off"> </span>
           </li>
-          <li id="hacknet-nodes-tab" class="mainmenu-accordion-panel noselect">
+          <li id="hacknet-nodes-tab" class="mainmenu-accordion-panel">
             <button id="hacknet-nodes-menu-link">Hacknet</button>
           </li>
-          <li id="sleeves-tab" class="mainmenu-accordion-panel noselect">
+          <li id="sleeves-tab" class="mainmenu-accordion-panel">
             <button id="sleeves-menu-link">Sleeves</button>
           </li>
 
           <!-- World dropdown -->
           <li id="world-menu-header-li">
-            <button id="world-menu-header" class="mainmenu-accordion-header noselect">World</button>
+            <button id="world-menu-header" class="mainmenu-accordion-header">World</button>
           </li>
-          <li id="city-tab" class="mainmenu-accordion-panel noselect">
+          <li id="city-tab" class="mainmenu-accordion-panel">
             <button id="city-menu-link">City</button>
           </li>
-          <li id="travel-tab" class="mainmenu-accordion-panel noselect">
+          <li id="travel-tab" class="mainmenu-accordion-panel">
             <button id="travel-menu-link">Travel</button>
           </li>
-          <li id="job-tab" class="mainmenu-accordion-panel noselect">
+          <li id="job-tab" class="mainmenu-accordion-panel">
             <button id="job-menu-link">Job</button>
           </li>
-          <li id="stock-market-tab" class="mainmenu-accordion-panel noselect">
+          <li id="stock-market-tab" class="mainmenu-accordion-panel">
             <button id="stock-market-menu-link">Stock Market</button>
           </li>
-          <li id="bladeburner-tab" class="mainmenu-accordion-panel noselect">
+          <li id="bladeburner-tab" class="mainmenu-accordion-panel">
             <button id="bladeburner-menu-link">Bladeburner</button>
           </li>
-          <li id="corporation-tab" class="mainmenu-accordion-panel noselect">
+          <li id="corporation-tab" class="mainmenu-accordion-panel">
             <button id="corporation-menu-link">Corp</button>
           </li>
-          <li id="gang-tab" class="mainmenu-accordion-panel noselect">
+          <li id="gang-tab" class="mainmenu-accordion-panel">
             <button id="gang-menu-link">Gang</button>
           </li>
 
           <li id="help-menu-header-li">
-            <button id="help-menu-header" class="mainmenu-accordion-header noselect">Help</button>
+            <button id="help-menu-header" class="mainmenu-accordion-header">Help</button>
           </li>
-          <li id="milestones-tab" class="mainmenu-accordion-panel noselect">
+          <li id="milestones-tab" class="mainmenu-accordion-panel">
             <button id="milestones-menu-link">Milestones</button>
           </li>
-          <li id="tutorial-tab" class="mainmenu-accordion-panel noselect">
+          <li id="tutorial-tab" class="mainmenu-accordion-panel">
             <button id="tutorial-menu-link">Tutorial</button>
           </li>
-          <li id="options-tab" class="mainmenu-accordion-panel noselect">
+          <li id="options-tab" class="mainmenu-accordion-panel">
             <button id="options-menu-link">Options</button>
           </li>
-          <li id="dev-tab" class="mainmenu-accordion-panel noselect">
+          <li id="dev-tab" class="mainmenu-accordion-panel">
             <button id="dev-menu-link">Dev</button>
           </li>
         </ul>
       </div>
 
-      <div id="script-editor-container" class="generic-menupage-container">
-        <div id="script-editor-wrapper">
-          <div id="script-editor-filename-wrapper">
-            <p id="script-editor-filename-tag">
-              <strong style="background-color: #555">Script name: </strong>
-            </p>
-            <input id="script-editor-filename" type="text" maxlength="100" tabindex="1" />
-          </div>
-
-          <div id="monaco-editor"></div>
-
-          <div id="script-editor-buttons-wrapper"></div>
-          <!-- Buttons below script editor -->
-        </div>
-        <!-- End wrapper -->
-
-        <div id="script-editor-options-panel">
-          <h1 style="color: white">Script Editor Options</h1>
-          <fieldset>
-            <label for="script-editor-option-editor">Editor</label>
-            <select id="script-editor-option-editor" class="dropdown">
-              <option value="Ace">Ace</option>
-              <option value="CodeMirror">CodeMirror</option>
-            </select>
-          </fieldset>
-
-          <fieldset>
-            <label for="script-editor-option-theme">Theme</label>
-            <select id="script-editor-option-theme" class="dropdown"></select>
-          </fieldset>
-
-          <fieldset>
-            <label for="script-editor-option-keybinding">Key Binding</label>
-            <select id="script-editor-option-keybinding" class="dropdown"></select>
-          </fieldset>
-
-          <fieldset>
-            <label for="script-editor-option-highlightactiveline">Highlight Active Line</label>
-            <input
-              type="checkbox"
-              class="optionCheckbox"
-              name="script-editor-option-highlightactiveline"
-              id="script-editor-option-highlightactiveline"
-              checked
-            />
-          </fieldset>
-
-          <fieldset>
-            <label for="script-editor-option-showinvisibles">Show Invisibles</label>
-            <input
-              type="checkbox"
-              class="optionCheckbox"
-              name="script-editor-option-showinvisibles"
-              id="script-editor-option-showinvisibles"
-            />
-          </fieldset>
-
-          <fieldset>
-            <label for="script-editor-option-usesofttab">Use Soft Tab</label>
-            <input
-              type="checkbox"
-              class="optionCheckbox"
-              name="script-editor-option-usesofttab"
-              id="script-editor-option-usesofttab"
-              checked
-            />
-          </fieldset>
-
-          <fieldset id="script-editor-option-flex1-fieldset"></fieldset>
-          <fieldset id="script-editor-option-flex2-fieldset"></fieldset>
-          <fieldset id="script-editor-option-flex3-fieldset"></fieldset>
-          <fieldset id="script-editor-option-flex4-fieldset"></fieldset>
-        </div>
-        <!-- End script editor options panel -->
-
-        <!-- TODO(hydroflame): remove this once Monaco is implemented -->
-        <div id="ace-editor" style="display: none"></div>
-        <form id="codemirror-form-wrapper" style="display: none">
-          <textarea id="codemirror-editor"></textarea>
-        </form>
-        <div id="codemirror-vim-command-display-wrapper" style="display: none">
-          Key Buffer: <span id="codemirror-vim-command-display"></span>
-        </div>
-      </div>
-
       <!-- Terminal page -->
       <div id="terminal-container">
         <table id="terminal">
@@ -233,133 +148,16 @@
       </div>
 
       <!-- Character Info page -->
-      <div id="character-container" class="generic-menupage-container">
-        <div id="character-content"></div>
-      </div>
-
-      <!-- Active scripts info page -->
-      <div id="active-scripts-container" class="generic-menupage-container">
-        <p id="active-scripts-text">
-          This page displays a list of all of your scripts that are currently running across every machine. It also
-          provides information about each script's production. The scripts are categorized by the hostname of the
-          servers on which they are running.
-        </p>
-        <p id="active-scripts-total-prod">
-          Total online production of Active scripts:
-          <span class="money-gold"><span id="active-scripts-total-production-active">$0.000</span> / sec</span><br />
-          Total online production since last Aug installation:
-          <span id="active-scripts-total-prod-aug-total" class="money-gold">$0.000</span>
-          (<span class="money-gold"
-            ><span id="active-scripts-total-prod-aug-avg" class="money-gold">$0.000</span> / sec</span
-          >)
-        </p>
-        <ul class="active-scripts-list" id="active-scripts-list" style="list-style: none"></ul>
-      </div>
-
-      <!-- Hacknet Nodes -->
-      <div id="hacknet-nodes-container" class="generic-menupage-container">
-        <!-- React Component -->
-      </div>
-
-      <!-- Create a program(executable) -->
-      <div id="create-program-container" class="generic-menupage-container">
-        <p id="create-program-page-text">
-          This page displays any programs that you are able to create. Writing the code for a program takes time, which
-          can vary based on how complex the program is. If you are working on creating a program you can cancel at any
-          time. Your progress will be saved and you can continue later.
-        </p>
-
-        <ul id="create-program-list"></ul>
-      </div>
-
-      <!-- Factions -->
+      <div id="character-container" class="generic-menupage-container"></div>
+      <div id="active-scripts-container" class="generic-menupage-container"></div>
+      <div id="script-editor-container" class="generic-menupage-container"></div>
+      <div id="hacknet-nodes-container" class="generic-menupage-container"></div>
+      <div id="create-program-container" class="generic-menupage-container"></div>
       <div id="factions-container" class="generic-menupage-container"></div>
-
-      <!-- Single Faction info (when you select a faction from the Factions menu) -->
       <div id="faction-container" class="generic-menupage-container"></div>
-
-      <!-- Augmentations -->
       <div id="augmentations-container" class="generic-menupage-container"></div>
-
-      <!-- Milestones content -->
       <div id="milestones-container" class="generic-menupage-container"></div>
-
-      <!-- Tutorial content -->
-      <div id="tutorial-container" class="generic-menupage-container">
-        <h1>Tutorial (AKA Links to Documentation)</h1>
-        <a
-          id="tutorial-getting-started-link"
-          class="a-link-button"
-          target="_blank"
-          href="https://bitburner.readthedocs.io/en/latest/guidesandtips/gettingstartedguideforbeginnerprogrammers.html"
-        >
-          Getting Started</a
-        ><br /><br />
-        <a
-          class="a-link-button"
-          target="_blank"
-          href="https://bitburner.readthedocs.io/en/latest/basicgameplay/servers.html"
-        >
-          Servers & Networking</a
-        ><br /><br />
-        <a
-          class="a-link-button"
-          target="_blank"
-          href="https://bitburner.readthedocs.io/en/latest/basicgameplay/hacking.html"
-        >
-          Hacking</a
-        ><br /><br />
-        <a
-          class="a-link-button"
-          target="_blank"
-          href="https://bitburner.readthedocs.io/en/latest/basicgameplay/scripts.html"
-        >
-          Scripts</a
-        ><br /><br />
-        <a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/netscript.html">
-          Netscript Programming Language</a
-        ><br /><br />
-        <a
-          class="a-link-button"
-          target="_blank"
-          href="https://bitburner.readthedocs.io/en/latest/basicgameplay/world.html"
-        >
-          Traveling</a
-        ><br /><br />
-        <a
-          class="a-link-button"
-          target="_blank"
-          href="https://bitburner.readthedocs.io/en/latest/basicgameplay/companies.html"
-        >
-          Companies</a
-        ><br /><br />
-        <a
-          class="a-link-button"
-          target="_blank"
-          href="https://bitburner.readthedocs.io/en/latest/basicgameplay/infiltration.html"
-        >
-          Infiltration</a
-        ><br /><br />
-        <a
-          class="a-link-button"
-          target="_blank"
-          href="https://bitburner.readthedocs.io/en/latest/basicgameplay/factions.html"
-        >
-          Factions</a
-        ><br /><br />
-        <a
-          class="a-link-button"
-          target="_blank"
-          href="https://bitburner.readthedocs.io/en/latest/basicgameplay/augmentations.html"
-        >
-          Augmentations</a
-        ><br /><br />
-        <a class="a-link-button" target="_blank" href="https://bitburner.readthedocs.io/en/latest/shortcuts.html">
-          Keyboard Shortcuts</a
-        >
-      </div>
-
-      <!-- Location (visiting a location in World) -->
+      <div id="tutorial-container" class="generic-menupage-container"></div>
       <div id="location-container" class="generic-menupage-container"></div>
       <div id="infiltration-container" class="generic-fullscreen-container"></div>
       <div id="stock-market-container" class="generic-menupage-container"></div>
@@ -403,19 +201,6 @@
         </div>
       </div>
 
-      <!-- End of Infiltration pop up box -->
-      <div id="infiltration-box-container" class="popup-box-container">
-        <div id="infiltration-box-content" class="popup-box-content">
-          <p id="infiltration-box-text"></p>
-
-          <button id="infiltration-box-sell" class="a-link-button">Sell on Black Market</button>
-          <br /><br />
-          <select id="infiltration-faction-select" class="dropdown"></select>
-          <br />
-          <button id="infiltration-box-faction" class="a-link-button">Give to Faction for Reputation</button>
-        </div>
-      </div>
-
       <!-- Mission container -->
       <div id="mission-container" class="generic-fullscreen-container"></div>