2019-05-16 08:05:36 +02:00
|
|
|
/**
|
|
|
|
* Game engine. Handles the main game loop as well as the main UI pages
|
|
|
|
*
|
|
|
|
* TODO: Separate UI functionality into its own component
|
|
|
|
*/
|
2021-09-09 05:47:34 +02:00
|
|
|
import { convertTimeMsToTimeElapsedString, replaceAt } from "../utils/StringHelperFunctions";
|
2019-04-11 10:37:40 +02:00
|
|
|
import { Augmentations } from "./Augmentation/Augmentations";
|
2021-09-13 00:03:07 +02:00
|
|
|
import { initAugmentations, installAugmentations } from "./Augmentation/AugmentationHelpers";
|
2021-09-10 22:08:58 +02:00
|
|
|
import { onExport } from "./ExportBonus";
|
|
|
|
import { AugmentationsRoot } from "./Augmentation/ui/Root";
|
2019-04-11 10:37:40 +02:00
|
|
|
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
2021-09-05 01:09:30 +02:00
|
|
|
import { initBitNodeMultipliers } from "./BitNode/BitNode";
|
2021-08-17 00:43:55 +02:00
|
|
|
import { Bladeburner } from "./Bladeburner/Bladeburner";
|
2021-09-13 00:03:07 +02:00
|
|
|
import { CharacterOverview } from "./ui/React/CharacterOverview";
|
2019-04-11 10:37:40 +02:00
|
|
|
import { generateRandomContract } from "./CodingContractGenerator";
|
|
|
|
import { initCompanies } from "./Company/Companies";
|
|
|
|
import { Corporation } from "./Corporation/Corporation";
|
|
|
|
import { CONSTANTS } from "./Constants";
|
2021-09-10 22:57:05 +02:00
|
|
|
import { DevMenuRoot } from "./DevMenu";
|
2019-04-11 10:37:40 +02:00
|
|
|
import { Factions, initFactions } from "./Faction/Factions";
|
2021-09-09 05:47:34 +02:00
|
|
|
import { processPassiveFactionRepGain, inviteToFaction } from "./Faction/FactionHelpers";
|
2021-09-05 01:09:30 +02:00
|
|
|
import { FactionList } from "./Faction/ui/FactionList";
|
2021-08-16 04:35:43 +02:00
|
|
|
import { Root as BladeburnerRoot } from "./Bladeburner/ui/Root";
|
2021-09-09 19:48:21 +02:00
|
|
|
import { Root as GangRoot } from "./Gang/ui/Root";
|
2021-09-14 21:23:16 +02:00
|
|
|
import { SidebarRoot } from "./Sidebar/ui/SidebarRoot";
|
2021-09-09 20:21:21 +02:00
|
|
|
import { CorporationRoot } from "./Corporation/ui/CorporationRoot";
|
2021-09-09 21:19:11 +02:00
|
|
|
import { ResleeveRoot } from "./PersonObjects/Resleeving/ui/ResleeveRoot";
|
2021-09-14 21:23:16 +02:00
|
|
|
import { GameOptionsRoot } from "./ui/React/GameOptionsRoot";
|
2021-09-15 03:05:49 +02:00
|
|
|
import { Theme } from "./ui/React/Theme";
|
2021-09-10 03:38:05 +02:00
|
|
|
import { SleeveRoot } from "./PersonObjects/Sleeve/ui/SleeveRoot";
|
2021-06-13 17:05:40 +02:00
|
|
|
import { displayInfiltrationContent } from "./Infiltration/Helper";
|
2021-09-05 01:09:30 +02:00
|
|
|
import {
|
|
|
|
getHackingWorkRepGain,
|
|
|
|
getFactionSecurityWorkRepGain,
|
|
|
|
getFactionFieldWorkRepGain,
|
2021-05-11 02:11:03 +02:00
|
|
|
} from "./PersonObjects/formulas/reputation";
|
2021-09-09 09:17:01 +02:00
|
|
|
import { hasHacknetServers, processHacknetEarnings } from "./Hacknet/HacknetHelpers";
|
|
|
|
import { HacknetRoot } from "./Hacknet/ui/HacknetRoot";
|
2019-04-11 10:37:40 +02:00
|
|
|
import { iTutorialStart } from "./InteractiveTutorial";
|
|
|
|
import { LocationName } from "./Locations/data/LocationNames";
|
|
|
|
import { LocationRoot } from "./Locations/ui/Root";
|
|
|
|
import { checkForMessagesToSend, initMessages } from "./Message/MessageHelpers";
|
|
|
|
import { inMission, currMission } from "./Missions";
|
2019-05-17 22:41:16 +02:00
|
|
|
import { workerScripts } from "./Netscript/WorkerScripts";
|
2021-09-09 05:47:34 +02:00
|
|
|
import { loadAllRunningScripts, updateOnlineScriptTimes } from "./NetscriptWorker";
|
2019-04-11 10:37:40 +02:00
|
|
|
import { Player } from "./Player";
|
2019-05-15 05:56:59 +02:00
|
|
|
import { prestigeAugmentation } from "./Prestige";
|
2021-09-10 22:08:58 +02:00
|
|
|
import { ProgramsRoot } from "./Programs/ui/ProgramsRoot";
|
2019-04-11 10:37:40 +02:00
|
|
|
import { saveObject, loadGame } from "./SaveObject";
|
2021-08-20 08:03:16 +02:00
|
|
|
import { Root as ScriptEditorRoot } from "./ScriptEditor/ui/Root";
|
2021-05-06 00:58:53 +02:00
|
|
|
import { initForeignServers, AllServers } from "./Server/AllServers";
|
2019-04-11 10:37:40 +02:00
|
|
|
import { Settings } from "./Settings/Settings";
|
|
|
|
import { updateSourceFileFlags } from "./SourceFile/SourceFileFlags";
|
2019-05-15 09:37:11 +02:00
|
|
|
import { initSpecialServerIps } from "./Server/SpecialServerIps";
|
2021-09-09 05:47:34 +02:00
|
|
|
import { initSymbolToStockMap, processStockPrices, displayStockMarketContent } from "./StockMarket/StockMarket";
|
2021-09-10 22:08:58 +02:00
|
|
|
import { MilestonesRoot } from "./Milestones/ui/MilestonesRoot";
|
2021-09-16 08:52:45 +02:00
|
|
|
import { TerminalRoot } from "./Terminal/ui/TerminalRoot";
|
|
|
|
import { Terminal } from "./Terminal";
|
2021-09-10 22:08:58 +02:00
|
|
|
import { TutorialRoot } from "./Tutorial/ui/TutorialRoot";
|
2019-04-11 10:37:40 +02:00
|
|
|
import { Sleeve } from "./PersonObjects/Sleeve/Sleeve";
|
2019-01-18 18:57:21 +01:00
|
|
|
|
2021-03-07 21:58:52 +01:00
|
|
|
import { CharacterInfo } from "./ui/CharacterInfo";
|
2019-04-11 10:37:40 +02:00
|
|
|
import { Page, routing } from "./ui/navigationTracking";
|
2021-03-31 06:45:21 +02:00
|
|
|
import { Money } from "./ui/React/Money";
|
|
|
|
import { Hashes } from "./ui/React/Hashes";
|
2021-05-11 02:11:03 +02:00
|
|
|
import { Reputation } from "./ui/React/Reputation";
|
2019-05-17 22:41:16 +02:00
|
|
|
|
|
|
|
import { ActiveScriptsRoot } from "./ui/ActiveScripts/Root";
|
2021-09-13 00:03:07 +02:00
|
|
|
import { MainMenuLinks } from "./ui/MainMenu/Links";
|
2019-01-18 18:57:21 +01:00
|
|
|
|
2019-04-11 10:37:40 +02:00
|
|
|
import { dialogBoxCreate } from "../utils/DialogBox";
|
|
|
|
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
|
|
|
import { removeLoadingScreen } from "../utils/uiHelpers/removeLoadingScreen";
|
2021-03-09 02:31:34 +01:00
|
|
|
import "./Exploits/tampering";
|
2021-03-22 19:48:48 +01:00
|
|
|
import "./Exploits/unclickable";
|
2019-01-18 18:57:21 +01:00
|
|
|
|
2019-04-11 10:37:40 +02:00
|
|
|
import React from "react";
|
|
|
|
import ReactDOM from "react-dom";
|
2019-01-18 18:57:21 +01:00
|
|
|
|
2018-09-06 18:07:59 +02:00
|
|
|
const Engine = {
|
2021-09-05 01:09:30 +02:00
|
|
|
// Clickable objects
|
|
|
|
Clickables: {
|
|
|
|
// Main menu buttons
|
|
|
|
saveMainMenuButton: null,
|
|
|
|
deleteMainMenuButton: null,
|
|
|
|
},
|
|
|
|
|
|
|
|
// Display objects
|
|
|
|
// TODO-Refactor this into its own component
|
|
|
|
Display: {
|
2021-09-10 23:29:07 +02:00
|
|
|
// Generic page that most react loads into.
|
|
|
|
content: null,
|
2021-09-05 01:09:30 +02:00
|
|
|
// Main menu content
|
|
|
|
infiltrationContent: null,
|
|
|
|
workInProgressContent: null,
|
|
|
|
redPillContent: null,
|
|
|
|
cinematicTextContent: null,
|
|
|
|
missionContent: null,
|
2021-09-16 23:30:47 +02:00
|
|
|
overview: null,
|
2021-09-05 01:09:30 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
indexedDb: undefined,
|
|
|
|
|
|
|
|
// Time variables (milliseconds unix epoch time)
|
|
|
|
_lastUpdate: new Date().getTime(),
|
|
|
|
_idleSpeed: 200, // Speed (in ms) at which the main loop is updated
|
|
|
|
|
|
|
|
loadTerminalContent: function () {
|
|
|
|
Engine.hideAllContent();
|
2021-09-16 08:52:45 +02:00
|
|
|
Engine.Display.content.style.display = "block";
|
|
|
|
routing.navigateTo(Page.CharacterInfo);
|
|
|
|
ReactDOM.render(
|
|
|
|
<Theme>
|
|
|
|
<TerminalRoot terminal={Terminal} engine={this} player={Player} />
|
|
|
|
</Theme>,
|
|
|
|
Engine.Display.content,
|
|
|
|
);
|
|
|
|
MainMenuLinks.Stats.classList.add("active");
|
2021-09-05 01:09:30 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
loadCharacterContent: function () {
|
|
|
|
Engine.hideAllContent();
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content.style.display = "block";
|
2021-09-05 01:09:30 +02:00
|
|
|
routing.navigateTo(Page.CharacterInfo);
|
2021-09-10 23:29:07 +02:00
|
|
|
ReactDOM.render(<CharacterInfo player={Player} />, Engine.Display.content);
|
2021-09-05 01:09:30 +02:00
|
|
|
MainMenuLinks.Stats.classList.add("active");
|
|
|
|
},
|
|
|
|
|
|
|
|
loadScriptEditorContent: function (filename = "", code = "") {
|
|
|
|
Engine.hideAllContent();
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content.style.display = "block";
|
2021-09-05 01:09:30 +02:00
|
|
|
routing.navigateTo(Page.ScriptEditor);
|
2021-09-10 22:08:58 +02:00
|
|
|
MainMenuLinks.ScriptEditor.classList.add("active");
|
2021-09-05 01:09:30 +02:00
|
|
|
ReactDOM.render(
|
2021-09-09 05:47:34 +02:00
|
|
|
<ScriptEditorRoot filename={filename} code={code} player={Player} engine={this} />,
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content,
|
2021-09-05 01:09:30 +02:00
|
|
|
);
|
|
|
|
},
|
|
|
|
|
|
|
|
loadActiveScriptsContent: function () {
|
|
|
|
Engine.hideAllContent();
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content.style.display = "block";
|
2021-09-05 01:09:30 +02:00
|
|
|
routing.navigateTo(Page.ActiveScripts);
|
2021-09-10 22:08:58 +02:00
|
|
|
MainMenuLinks.ActiveScripts.classList.add("active");
|
2021-09-10 23:29:07 +02:00
|
|
|
ReactDOM.render(<ActiveScriptsRoot p={Player} workerScripts={workerScripts} />, Engine.Display.content);
|
2021-09-05 01:09:30 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
loadHacknetNodesContent: function () {
|
|
|
|
Engine.hideAllContent();
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content.style.display = "block";
|
2021-09-05 01:09:30 +02:00
|
|
|
routing.navigateTo(Page.HacknetNodes);
|
|
|
|
MainMenuLinks.HacknetNodes.classList.add("active");
|
2021-09-10 23:29:07 +02:00
|
|
|
ReactDOM.render(<HacknetRoot player={Player} />, Engine.Display.content);
|
2021-09-05 01:09:30 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
loadCreateProgramContent: function () {
|
|
|
|
Engine.hideAllContent();
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content.style.display = "block";
|
2021-09-05 01:09:30 +02:00
|
|
|
routing.navigateTo(Page.CreateProgram);
|
|
|
|
MainMenuLinks.CreateProgram.classList.add("active");
|
2021-09-16 03:54:30 +02:00
|
|
|
ReactDOM.render(<Theme><ProgramsRoot player={Player} /></Theme>, Engine.Display.content);
|
2021-09-05 01:09:30 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
loadFactionsContent: function () {
|
|
|
|
Engine.hideAllContent();
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content.style.display = "block";
|
2021-09-05 01:09:30 +02:00
|
|
|
routing.navigateTo(Page.Factions);
|
|
|
|
MainMenuLinks.Factions.classList.add("active");
|
2021-09-10 23:29:07 +02:00
|
|
|
ReactDOM.render(<FactionList player={Player} engine={this} />, Engine.Display.content);
|
2021-09-05 01:09:30 +02:00
|
|
|
},
|
|
|
|
|
2021-09-10 22:08:58 +02:00
|
|
|
// TODO reactify
|
2021-09-05 01:09:30 +02:00
|
|
|
loadFactionContent: function () {
|
|
|
|
Engine.hideAllContent();
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content.style.display = "block";
|
2021-09-05 01:09:30 +02:00
|
|
|
routing.navigateTo(Page.Faction);
|
|
|
|
},
|
|
|
|
|
|
|
|
loadAugmentationsContent: function () {
|
|
|
|
Engine.hideAllContent();
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content.style.display = "block";
|
2021-09-05 01:09:30 +02:00
|
|
|
routing.navigateTo(Page.Augmentations);
|
|
|
|
MainMenuLinks.Augmentations.classList.add("active");
|
2021-09-10 22:08:58 +02:00
|
|
|
|
|
|
|
function backup() {
|
|
|
|
saveObject.exportGame();
|
|
|
|
onExport(Player);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReactDOM.render(
|
|
|
|
<AugmentationsRoot exportGameFn={backup} installAugmentationsFn={installAugmentations} />,
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content,
|
2021-09-10 22:08:58 +02:00
|
|
|
);
|
2021-09-05 01:09:30 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
loadMilestonesContent: function () {
|
|
|
|
Engine.hideAllContent();
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content.style.display = "block";
|
2021-09-05 01:09:30 +02:00
|
|
|
routing.navigateTo(Page.Milestones);
|
|
|
|
MainMenuLinks.Milestones.classList.add("active");
|
2021-09-10 23:29:07 +02:00
|
|
|
ReactDOM.render(<MilestonesRoot player={Player} />, Engine.Display.content);
|
2021-09-05 01:09:30 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
loadTutorialContent: function () {
|
|
|
|
Engine.hideAllContent();
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content.style.display = "block";
|
2021-09-05 01:09:30 +02:00
|
|
|
routing.navigateTo(Page.Tutorial);
|
|
|
|
MainMenuLinks.Tutorial.classList.add("active");
|
2021-09-10 23:29:07 +02:00
|
|
|
ReactDOM.render(<TutorialRoot />, Engine.Display.content);
|
2021-09-05 01:09:30 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
loadDevMenuContent: function () {
|
|
|
|
Engine.hideAllContent();
|
2021-09-10 22:57:05 +02:00
|
|
|
if (process.env.NODE_ENV !== "development") {
|
|
|
|
throw new Error("Cannot create Dev Menu because you are not in a dev build");
|
|
|
|
}
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content.style.display = "block";
|
|
|
|
ReactDOM.render(<DevMenuRoot player={Player} engine={this} />, Engine.Display.content);
|
2021-09-05 01:09:30 +02:00
|
|
|
routing.navigateTo(Page.DevMenu);
|
|
|
|
MainMenuLinks.DevMenu.classList.add("active");
|
|
|
|
},
|
|
|
|
|
|
|
|
loadLocationContent: function (initiallyInCity = true) {
|
|
|
|
Engine.hideAllContent();
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content.style.display = "block";
|
2021-09-05 01:09:30 +02:00
|
|
|
routing.navigateTo(Page.Location);
|
2021-09-10 22:08:58 +02:00
|
|
|
MainMenuLinks.City.classList.add("active");
|
|
|
|
ReactDOM.render(
|
|
|
|
<LocationRoot initiallyInCity={initiallyInCity} engine={Engine} p={Player} />,
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content,
|
2021-09-10 22:08:58 +02:00
|
|
|
);
|
2021-09-05 01:09:30 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
loadTravelContent: function () {
|
|
|
|
// Same as loadLocationContent() except first set the location to the travel agency,
|
|
|
|
// and make sure that the 'City' main menu link doesnt become 'active'
|
|
|
|
Engine.hideAllContent();
|
|
|
|
Player.gotoLocation(LocationName.TravelAgency);
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content.style.display = "block";
|
2021-09-05 01:09:30 +02:00
|
|
|
routing.navigateTo(Page.Location);
|
2021-09-10 22:08:58 +02:00
|
|
|
MainMenuLinks.Travel.classList.add("active");
|
2021-09-10 23:29:07 +02:00
|
|
|
ReactDOM.render(<LocationRoot initiallyInCity={false} engine={Engine} p={Player} />, Engine.Display.content);
|
2021-09-05 01:09:30 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
loadJobContent: function () {
|
|
|
|
// Same as loadLocationContent(), except first set the location to the job.
|
|
|
|
// Make sure that the 'City' main menu link doesnt become 'active'
|
|
|
|
if (Player.companyName == "") {
|
|
|
|
dialogBoxCreate(
|
2021-09-09 05:47:34 +02:00
|
|
|
"You do not currently have a job! You can visit various companies " + "in the city and try to find a job.",
|
2021-09-05 01:09:30 +02:00
|
|
|
);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Engine.hideAllContent();
|
|
|
|
Player.gotoLocation(Player.companyName);
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content.style.display = "block";
|
2021-09-05 01:09:30 +02:00
|
|
|
routing.navigateTo(Page.Location);
|
2021-09-10 22:08:58 +02:00
|
|
|
MainMenuLinks.Job.classList.add("active");
|
2021-09-10 23:29:07 +02:00
|
|
|
ReactDOM.render(<LocationRoot initiallyInCity={false} engine={Engine} p={Player} />, Engine.Display.content);
|
2021-09-05 01:09:30 +02:00
|
|
|
},
|
|
|
|
|
2021-09-10 22:08:58 +02:00
|
|
|
// TODO reactify
|
2021-09-05 01:09:30 +02:00
|
|
|
loadWorkInProgressContent: function () {
|
|
|
|
Engine.hideAllContent();
|
2021-09-10 22:08:58 +02:00
|
|
|
const mainMenu = document.getElementById("mainmenu-container");
|
2021-09-05 01:09:30 +02:00
|
|
|
mainMenu.style.visibility = "hidden";
|
|
|
|
Engine.Display.workInProgressContent.style.display = "block";
|
|
|
|
routing.navigateTo(Page.WorkInProgress);
|
|
|
|
},
|
|
|
|
|
|
|
|
loadRedPillContent: function () {
|
|
|
|
Engine.hideAllContent();
|
2021-09-10 22:08:58 +02:00
|
|
|
const mainMenu = document.getElementById("mainmenu-container");
|
2021-09-05 01:09:30 +02:00
|
|
|
mainMenu.style.visibility = "hidden";
|
|
|
|
Engine.Display.redPillContent.style.display = "block";
|
|
|
|
routing.navigateTo(Page.RedPill);
|
|
|
|
},
|
|
|
|
|
2021-09-10 22:08:58 +02:00
|
|
|
// TODO reactify
|
2021-09-05 01:09:30 +02:00
|
|
|
loadCinematicTextContent: function () {
|
|
|
|
Engine.hideAllContent();
|
|
|
|
var mainMenu = document.getElementById("mainmenu-container");
|
|
|
|
mainMenu.style.visibility = "hidden";
|
|
|
|
Engine.Display.cinematicTextContent.style.display = "block";
|
|
|
|
routing.navigateTo(Page.CinematicText);
|
|
|
|
},
|
|
|
|
|
2021-09-10 22:08:58 +02:00
|
|
|
// TODO reactify
|
2021-09-05 01:09:30 +02:00
|
|
|
loadInfiltrationContent: function (name, difficulty, maxLevel) {
|
|
|
|
Engine.hideAllContent();
|
|
|
|
const mainMenu = document.getElementById("mainmenu-container");
|
|
|
|
mainMenu.style.visibility = "hidden";
|
|
|
|
Engine.Display.infiltrationContent.style.display = "block";
|
|
|
|
routing.navigateTo(Page.Infiltration);
|
|
|
|
displayInfiltrationContent(this, Player, name, difficulty, maxLevel);
|
|
|
|
},
|
|
|
|
|
|
|
|
loadStockMarketContent: function () {
|
|
|
|
Engine.hideAllContent();
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content.style.display = "block";
|
2021-09-05 01:09:30 +02:00
|
|
|
routing.navigateTo(Page.StockMarket);
|
2021-09-10 22:08:58 +02:00
|
|
|
MainMenuLinks.StockMarket.classList.add("active");
|
2021-09-05 01:09:30 +02:00
|
|
|
displayStockMarketContent();
|
|
|
|
},
|
|
|
|
|
|
|
|
loadGangContent: function () {
|
2021-09-10 22:08:58 +02:00
|
|
|
if (!Player.inGang()) return;
|
2021-09-05 01:09:30 +02:00
|
|
|
Engine.hideAllContent();
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content.style.display = "block";
|
2021-09-10 22:08:58 +02:00
|
|
|
routing.navigateTo(Page.Gang);
|
|
|
|
MainMenuLinks.Gang.classList.add("active");
|
2021-09-10 23:29:07 +02:00
|
|
|
ReactDOM.render(<GangRoot engine={this} gang={Player.gang} player={Player} />, Engine.Display.content);
|
2021-09-05 01:09:30 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
loadMissionContent: function () {
|
|
|
|
Engine.hideAllContent();
|
|
|
|
document.getElementById("mainmenu-container").style.visibility = "hidden";
|
2021-09-16 23:30:47 +02:00
|
|
|
document.getElementById("character-overview").style.visibility = "hidden";
|
2021-09-05 01:09:30 +02:00
|
|
|
Engine.Display.missionContent.style.display = "block";
|
|
|
|
routing.navigateTo(Page.Mission);
|
|
|
|
},
|
|
|
|
|
|
|
|
loadCorporationContent: function () {
|
2021-09-09 19:48:21 +02:00
|
|
|
if (!(Player.corporation instanceof Corporation)) return;
|
|
|
|
Engine.hideAllContent();
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content.style.display = "block";
|
2021-09-10 22:08:58 +02:00
|
|
|
routing.navigateTo(Page.Corporation);
|
|
|
|
MainMenuLinks.Corporation.classList.add("active");
|
2021-09-10 23:29:07 +02:00
|
|
|
ReactDOM.render(<CorporationRoot corp={Player.corporation} player={Player} />, Engine.Display.content);
|
2021-09-05 01:09:30 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
loadBladeburnerContent: function () {
|
|
|
|
if (!(Player.bladeburner instanceof Bladeburner)) return;
|
|
|
|
Engine.hideAllContent();
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content.style.display = "block";
|
2021-09-10 22:08:58 +02:00
|
|
|
routing.navigateTo(Page.Bladeburner);
|
|
|
|
MainMenuLinks.Bladeburner.classList.add("active");
|
2021-09-05 01:09:30 +02:00
|
|
|
ReactDOM.render(
|
2021-09-09 05:47:34 +02:00
|
|
|
<BladeburnerRoot bladeburner={Player.bladeburner} player={Player} engine={this} />,
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content,
|
2021-09-05 01:09:30 +02:00
|
|
|
);
|
|
|
|
},
|
|
|
|
|
|
|
|
loadSleevesContent: function () {
|
2021-09-10 03:38:05 +02:00
|
|
|
Engine.hideAllContent();
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content.style.display = "block";
|
2021-09-10 22:08:58 +02:00
|
|
|
routing.navigateTo(Page.Sleeves);
|
2021-09-10 23:29:07 +02:00
|
|
|
ReactDOM.render(<SleeveRoot player={Player} />, Engine.Display.content);
|
2021-09-05 01:09:30 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
loadResleevingContent: function () {
|
2021-09-09 21:19:11 +02:00
|
|
|
Engine.hideAllContent();
|
|
|
|
routing.navigateTo(Page.Resleeves);
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content.style.display = "block";
|
2021-09-10 22:08:58 +02:00
|
|
|
MainMenuLinks.City.classList.add("active");
|
2021-09-10 23:29:07 +02:00
|
|
|
ReactDOM.render(<ResleeveRoot player={Player} />, Engine.Display.content);
|
2021-09-05 01:09:30 +02:00
|
|
|
},
|
2017-07-25 03:06:40 +02:00
|
|
|
|
2021-09-14 21:23:16 +02:00
|
|
|
loadGameOptionsContent: function () {
|
|
|
|
Engine.hideAllContent();
|
|
|
|
routing.navigateTo(Page.GameOptions);
|
|
|
|
Engine.Display.content.style.display = "block";
|
|
|
|
MainMenuLinks.City.classList.add("active");
|
2021-09-15 03:05:49 +02:00
|
|
|
ReactDOM.render(
|
|
|
|
<Theme>
|
|
|
|
<GameOptionsRoot
|
|
|
|
player={Player}
|
|
|
|
save={() => saveObject.saveGame(Engine.indexedDb)}
|
|
|
|
delete={() => saveObject.deleteGame(Engine.indexedDb)}
|
|
|
|
export={() => saveObject.exportGame()}
|
|
|
|
import={() => saveObject.importGame()}
|
|
|
|
forceKill={() => {
|
|
|
|
for (const hostname of Object.keys(AllServers)) {
|
|
|
|
AllServers[hostname].runningScripts = [];
|
|
|
|
}
|
|
|
|
dialogBoxCreate("Forcefully deleted all running scripts. Please save and refresh page.");
|
|
|
|
}}
|
|
|
|
softReset={() => {
|
|
|
|
dialogBoxCreate("Soft Reset!");
|
|
|
|
prestigeAugmentation();
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</Theme>,
|
|
|
|
Engine.Display.content,
|
|
|
|
);
|
2021-09-14 21:23:16 +02:00
|
|
|
},
|
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
// Helper function that hides all content
|
|
|
|
hideAllContent: function () {
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content.style.display = "none";
|
2021-09-14 20:54:45 +02:00
|
|
|
Engine.Display.content.scrollTop = 0;
|
2021-09-10 23:29:07 +02:00
|
|
|
ReactDOM.unmountComponentAtNode(Engine.Display.content);
|
2021-09-10 22:57:05 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
Engine.Display.infiltrationContent.style.display = "none";
|
|
|
|
ReactDOM.unmountComponentAtNode(Engine.Display.infiltrationContent);
|
2017-07-25 03:06:40 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
Engine.Display.workInProgressContent.style.display = "none";
|
|
|
|
Engine.Display.redPillContent.style.display = "none";
|
|
|
|
Engine.Display.cinematicTextContent.style.display = "none";
|
|
|
|
Engine.Display.missionContent.style.display = "none";
|
|
|
|
},
|
|
|
|
|
|
|
|
displayCharacterOverviewInfo: function () {
|
2021-09-16 23:30:47 +02:00
|
|
|
ReactDOM.render(
|
|
|
|
<Theme>
|
|
|
|
<CharacterOverview player={Player} save={() => saveObject.saveGame(Engine.indexedDb)} />
|
|
|
|
</Theme>,
|
|
|
|
document.getElementById("character-overview"),
|
|
|
|
);
|
2021-09-05 01:09:30 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
// Main Game Loop
|
|
|
|
idleTimer: function () {
|
|
|
|
// Get time difference
|
|
|
|
const _thisUpdate = new Date().getTime();
|
|
|
|
let diff = _thisUpdate - Engine._lastUpdate;
|
|
|
|
const offset = diff % Engine._idleSpeed;
|
|
|
|
|
|
|
|
// Divide this by cycle time to determine how many cycles have elapsed since last update
|
|
|
|
diff = Math.floor(diff / Engine._idleSpeed);
|
|
|
|
|
|
|
|
if (diff > 0) {
|
|
|
|
// Update the game engine by the calculated number of cycles
|
|
|
|
Engine._lastUpdate = _thisUpdate - offset;
|
|
|
|
Player.lastUpdate = _thisUpdate - offset;
|
|
|
|
Engine.updateGame(diff);
|
|
|
|
}
|
2019-01-20 23:57:38 +01:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
window.requestAnimationFrame(Engine.idleTimer);
|
|
|
|
},
|
2017-07-25 03:06:40 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
updateGame: function (numCycles = 1) {
|
|
|
|
const time = numCycles * Engine._idleSpeed;
|
|
|
|
if (Player.totalPlaytime == null) {
|
|
|
|
Player.totalPlaytime = 0;
|
|
|
|
}
|
|
|
|
if (Player.playtimeSinceLastAug == null) {
|
|
|
|
Player.playtimeSinceLastAug = 0;
|
|
|
|
}
|
|
|
|
if (Player.playtimeSinceLastBitnode == null) {
|
|
|
|
Player.playtimeSinceLastBitnode = 0;
|
|
|
|
}
|
|
|
|
Player.totalPlaytime += time;
|
|
|
|
Player.playtimeSinceLastAug += time;
|
|
|
|
Player.playtimeSinceLastBitnode += time;
|
|
|
|
|
2021-09-16 20:43:39 +02:00
|
|
|
Terminal.process(Player, numCycles);
|
2017-07-25 03:06:40 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
// Working
|
|
|
|
if (Player.isWorking) {
|
|
|
|
if (Player.workType == CONSTANTS.WorkTypeFaction) {
|
|
|
|
Player.workForFaction(numCycles);
|
|
|
|
} else if (Player.workType == CONSTANTS.WorkTypeCreateProgram) {
|
|
|
|
Player.createProgramWork(numCycles);
|
|
|
|
} else if (Player.workType == CONSTANTS.WorkTypeStudyClass) {
|
|
|
|
Player.takeClass(numCycles);
|
|
|
|
} else if (Player.workType == CONSTANTS.WorkTypeCrime) {
|
|
|
|
Player.commitCrime(numCycles);
|
|
|
|
} else if (Player.workType == CONSTANTS.WorkTypeCompanyPartTime) {
|
|
|
|
Player.workPartTime(numCycles);
|
|
|
|
} else {
|
|
|
|
Player.work(numCycles);
|
|
|
|
}
|
|
|
|
}
|
2017-07-25 03:06:40 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
// Update stock prices
|
|
|
|
if (Player.hasWseAccount) {
|
|
|
|
processStockPrices(numCycles);
|
|
|
|
}
|
2017-07-25 03:06:40 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
// Gang, if applicable
|
|
|
|
if (Player.inGang()) {
|
|
|
|
Player.gang.process(numCycles, Player);
|
|
|
|
}
|
2019-05-17 22:41:16 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
// Mission
|
|
|
|
if (inMission && currMission) {
|
|
|
|
currMission.process(numCycles);
|
|
|
|
}
|
2018-05-10 19:14:45 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
// Corporation
|
|
|
|
if (Player.corporation instanceof Corporation) {
|
|
|
|
// Stores cycles in a "buffer". Processed separately using Engine Counters
|
|
|
|
Player.corporation.storeCycles(numCycles);
|
|
|
|
}
|
2017-07-25 03:06:40 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
if (Player.bladeburner instanceof Bladeburner) {
|
|
|
|
Player.bladeburner.storeCycles(numCycles);
|
|
|
|
}
|
2017-07-25 03:06:40 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
// Sleeves
|
|
|
|
for (let i = 0; i < Player.sleeves.length; ++i) {
|
|
|
|
if (Player.sleeves[i] instanceof Sleeve) {
|
|
|
|
const expForOtherSleeves = Player.sleeves[i].process(Player, numCycles);
|
2017-08-18 19:20:51 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
// This sleeve earns experience for other sleeves
|
|
|
|
if (expForOtherSleeves == null) {
|
|
|
|
continue;
|
2017-05-05 18:52:48 +02:00
|
|
|
}
|
2021-09-05 01:09:30 +02:00
|
|
|
for (let j = 0; j < Player.sleeves.length; ++j) {
|
|
|
|
if (j === i) {
|
|
|
|
continue;
|
|
|
|
}
|
2021-09-09 05:47:34 +02:00
|
|
|
Player.sleeves[j].gainExperience(Player, expForOtherSleeves, numCycles, true);
|
2021-03-08 00:41:04 +01:00
|
|
|
}
|
2021-09-05 01:09:30 +02:00
|
|
|
}
|
|
|
|
}
|
2021-03-08 00:41:04 +01:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
// Counters
|
|
|
|
Engine.decrementAllCounters(numCycles);
|
|
|
|
Engine.checkCounters();
|
2021-03-08 00:41:04 +01:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
// Update the running time of all active scripts
|
|
|
|
updateOnlineScriptTimes(numCycles);
|
|
|
|
|
|
|
|
// Hacknet Nodes
|
2021-09-09 09:17:01 +02:00
|
|
|
processHacknetEarnings(Player, numCycles);
|
2021-09-05 01:09:30 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Counters for the main event loop. Represent the number of game cycles that
|
|
|
|
* are required for something to happen. These counters are in game cycles,
|
|
|
|
* which is once every 200ms
|
|
|
|
*/
|
|
|
|
Counters: {
|
|
|
|
autoSaveCounter: 300,
|
|
|
|
updateSkillLevelsCounter: 10,
|
|
|
|
updateDisplays: 3,
|
|
|
|
updateDisplaysLong: 15,
|
|
|
|
updateActiveScriptsDisplay: 5,
|
|
|
|
createProgramNotifications: 10,
|
|
|
|
augmentationsNotifications: 10,
|
|
|
|
checkFactionInvitations: 100,
|
|
|
|
passiveFactionGrowth: 5,
|
|
|
|
messages: 150,
|
|
|
|
mechanicProcess: 5, // Processes certain mechanics (Corporation, Bladeburner)
|
|
|
|
contractGeneration: 3000, // Generate Coding Contracts
|
|
|
|
},
|
|
|
|
|
|
|
|
decrementAllCounters: function (numCycles = 1) {
|
|
|
|
for (var counter in Engine.Counters) {
|
|
|
|
if (Engine.Counters.hasOwnProperty(counter)) {
|
|
|
|
Engine.Counters[counter] = Engine.Counters[counter] - numCycles;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if any counters are 0. If they are, executes whatever
|
|
|
|
* is necessary and then resets the counter
|
|
|
|
*/
|
|
|
|
checkCounters: function () {
|
|
|
|
if (Engine.Counters.autoSaveCounter <= 0) {
|
|
|
|
if (Settings.AutosaveInterval == null) {
|
|
|
|
Settings.AutosaveInterval = 60;
|
|
|
|
}
|
|
|
|
if (Settings.AutosaveInterval === 0) {
|
|
|
|
Engine.Counters.autoSaveCounter = Infinity;
|
|
|
|
} else {
|
|
|
|
Engine.Counters.autoSaveCounter = Settings.AutosaveInterval * 5;
|
|
|
|
saveObject.saveGame(Engine.indexedDb);
|
|
|
|
}
|
|
|
|
}
|
2017-07-25 03:06:40 +02:00
|
|
|
|
2021-09-11 23:23:56 +02:00
|
|
|
if (Engine.Counters.checkFactionInvitations <= 0) {
|
|
|
|
const invitedFactions = Player.checkForFactionInvitations();
|
|
|
|
if (invitedFactions.length > 0) {
|
|
|
|
const randFaction = invitedFactions[Math.floor(Math.random() * invitedFactions.length)];
|
|
|
|
inviteToFaction(randFaction);
|
|
|
|
}
|
|
|
|
Engine.Counters.checkFactionInvitations = 100;
|
|
|
|
}
|
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
if (Engine.Counters.passiveFactionGrowth <= 0) {
|
|
|
|
var adjustedCycles = Math.floor(5 - Engine.Counters.passiveFactionGrowth);
|
|
|
|
processPassiveFactionRepGain(adjustedCycles);
|
|
|
|
Engine.Counters.passiveFactionGrowth = 5;
|
|
|
|
}
|
2019-01-20 23:57:38 +01:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
if (Engine.Counters.messages <= 0) {
|
|
|
|
checkForMessagesToSend();
|
|
|
|
if (Augmentations[AugmentationNames.TheRedPill].owned) {
|
|
|
|
Engine.Counters.messages = 4500; // 15 minutes for Red pill message
|
|
|
|
} else {
|
|
|
|
Engine.Counters.messages = 150;
|
|
|
|
}
|
|
|
|
}
|
2017-07-25 03:06:40 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
if (Engine.Counters.mechanicProcess <= 0) {
|
|
|
|
if (Player.corporation instanceof Corporation) {
|
|
|
|
Player.corporation.process(Player);
|
|
|
|
}
|
|
|
|
if (Player.bladeburner instanceof Bladeburner) {
|
|
|
|
try {
|
|
|
|
Player.bladeburner.process(Player);
|
|
|
|
} catch (e) {
|
|
|
|
exceptionAlert("Exception caught in Bladeburner.process(): " + e);
|
2017-05-05 23:27:35 +02:00
|
|
|
}
|
2021-09-05 01:09:30 +02:00
|
|
|
}
|
|
|
|
Engine.Counters.mechanicProcess = 5;
|
|
|
|
}
|
2017-07-25 03:06:40 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
if (Engine.Counters.contractGeneration <= 0) {
|
|
|
|
// X% chance of a contract being generated
|
|
|
|
if (Math.random() <= 0.25) {
|
|
|
|
generateRandomContract();
|
|
|
|
}
|
|
|
|
Engine.Counters.contractGeneration = 3000;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Used in game when clicking on a main menu header (NOT used for initialization)
|
|
|
|
* @param open {boolean} Whether header is being opened or closed
|
|
|
|
* @param elems {HTMLElement[]} li Elements under header
|
|
|
|
* @param links {HTMLElement[]} a elements under header
|
|
|
|
*/
|
|
|
|
toggleMainMenuHeader: function (open, elems, links) {
|
|
|
|
for (var i = 0; i < elems.length; ++i) {
|
|
|
|
if (open) {
|
|
|
|
elems[i].style.opacity = 1;
|
|
|
|
elems[i].style.maxHeight = elems[i].scrollHeight + "px";
|
|
|
|
} else {
|
|
|
|
elems[i].style.opacity = 0;
|
|
|
|
elems[i].style.maxHeight = null;
|
|
|
|
}
|
|
|
|
}
|
2018-05-02 19:38:11 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
for (var i = 0; i < links.length; ++i) {
|
|
|
|
if (open) {
|
|
|
|
links[i].style.opacity = 1;
|
|
|
|
links[i].style.maxHeight = links[i].scrollHeight + "px";
|
|
|
|
links[i].style.pointerEvents = "auto";
|
|
|
|
} else {
|
|
|
|
links[i].style.opacity = 0;
|
|
|
|
links[i].style.maxHeight = null;
|
|
|
|
links[i].style.pointerEvents = "none";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
load: function (saveString) {
|
|
|
|
// Load game from save or create new game
|
|
|
|
if (loadGame(saveString)) {
|
|
|
|
initBitNodeMultipliers(Player);
|
|
|
|
Engine.setDisplayElements(); // Sets variables for important DOM elements
|
|
|
|
Engine.init(); // Initialize buttons, work, etc.
|
|
|
|
updateSourceFileFlags(Player);
|
|
|
|
initAugmentations(); // Also calls Player.reapplyAllAugmentations()
|
|
|
|
Player.reapplyAllSourceFiles();
|
|
|
|
if (Player.hasWseAccount) {
|
|
|
|
initSymbolToStockMap();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calculate the number of cycles have elapsed while offline
|
|
|
|
Engine._lastUpdate = new Date().getTime();
|
|
|
|
const lastUpdate = Player.lastUpdate;
|
|
|
|
const timeOffline = Engine._lastUpdate - lastUpdate;
|
|
|
|
const numCyclesOffline = Math.floor(timeOffline / Engine._idleSpeed);
|
|
|
|
|
|
|
|
let offlineReputation = 0;
|
2021-09-09 05:47:34 +02:00
|
|
|
const offlineHackingIncome = (Player.moneySourceA.hacking / Player.playtimeSinceLastAug) * timeOffline * 0.75;
|
2021-09-05 01:09:30 +02:00
|
|
|
Player.gainMoney(offlineHackingIncome);
|
|
|
|
// Process offline progress
|
|
|
|
loadAllRunningScripts(); // This also takes care of offline production for those scripts
|
|
|
|
if (Player.isWorking) {
|
|
|
|
Player.focus = true;
|
|
|
|
if (Player.workType == CONSTANTS.WorkTypeFaction) {
|
|
|
|
Player.workForFaction(numCyclesOffline);
|
|
|
|
} else if (Player.workType == CONSTANTS.WorkTypeCreateProgram) {
|
|
|
|
Player.createProgramWork(numCyclesOffline);
|
|
|
|
} else if (Player.workType == CONSTANTS.WorkTypeStudyClass) {
|
|
|
|
Player.takeClass(numCyclesOffline);
|
|
|
|
} else if (Player.workType == CONSTANTS.WorkTypeCrime) {
|
|
|
|
Player.commitCrime(numCyclesOffline);
|
|
|
|
} else if (Player.workType == CONSTANTS.WorkTypeCompanyPartTime) {
|
|
|
|
Player.workPartTime(numCyclesOffline);
|
|
|
|
} else {
|
|
|
|
Player.work(numCyclesOffline);
|
2019-01-18 18:57:21 +01:00
|
|
|
}
|
2021-09-05 01:09:30 +02:00
|
|
|
} else {
|
|
|
|
for (let i = 0; i < Player.factions.length; i++) {
|
|
|
|
const facName = Player.factions[i];
|
|
|
|
if (!Factions.hasOwnProperty(facName)) continue;
|
|
|
|
const faction = Factions[facName];
|
|
|
|
if (!faction.isMember) continue;
|
|
|
|
// No rep for special factions.
|
|
|
|
const info = faction.getInfo();
|
|
|
|
if (!info.offersWork()) continue;
|
|
|
|
// No rep for gangs.
|
|
|
|
if (Player.getGangName() === facName) continue;
|
|
|
|
|
|
|
|
const hRep = getHackingWorkRepGain(Player, faction);
|
|
|
|
const sRep = getFactionSecurityWorkRepGain(Player, faction);
|
|
|
|
const fRep = getFactionFieldWorkRepGain(Player, faction);
|
|
|
|
// can be infinite, doesn't matter.
|
2021-09-09 05:47:34 +02:00
|
|
|
const reputationRate = Math.max(hRep, sRep, fRep) / Player.factions.length;
|
2021-09-05 01:09:30 +02:00
|
|
|
|
|
|
|
const rep = reputationRate * numCyclesOffline;
|
|
|
|
faction.playerReputation += rep;
|
|
|
|
offlineReputation += rep;
|
2017-07-22 00:54:55 +02:00
|
|
|
}
|
2021-09-05 01:09:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Hacknet Nodes offline progress
|
2021-09-09 09:17:01 +02:00
|
|
|
var offlineProductionFromHacknetNodes = processHacknetEarnings(Player, numCyclesOffline);
|
|
|
|
const hacknetProdInfo = hasHacknetServers(Player) ? (
|
2021-09-05 01:09:30 +02:00
|
|
|
<>{Hashes(offlineProductionFromHacknetNodes)} hashes</>
|
|
|
|
) : (
|
|
|
|
<Money money={offlineProductionFromHacknetNodes} />
|
|
|
|
);
|
|
|
|
|
|
|
|
// Passive faction rep gain offline
|
|
|
|
processPassiveFactionRepGain(numCyclesOffline);
|
|
|
|
|
|
|
|
// Stock Market offline progress
|
|
|
|
if (Player.hasWseAccount) {
|
|
|
|
processStockPrices(numCyclesOffline);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Gang progress for BitNode 2
|
|
|
|
if (Player.inGang()) {
|
|
|
|
Player.gang.process(numCyclesOffline, Player);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Corporation offline progress
|
|
|
|
if (Player.corporation instanceof Corporation) {
|
|
|
|
Player.corporation.storeCycles(numCyclesOffline);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bladeburner offline progress
|
|
|
|
if (Player.bladeburner instanceof Bladeburner) {
|
|
|
|
Player.bladeburner.storeCycles(numCyclesOffline);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sleeves offline progress
|
|
|
|
for (let i = 0; i < Player.sleeves.length; ++i) {
|
|
|
|
if (Player.sleeves[i] instanceof Sleeve) {
|
2021-09-09 05:47:34 +02:00
|
|
|
const expForOtherSleeves = Player.sleeves[i].process(Player, numCyclesOffline);
|
2021-09-05 01:09:30 +02:00
|
|
|
|
|
|
|
// This sleeve earns experience for other sleeves
|
|
|
|
if (expForOtherSleeves == null) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for (let j = 0; j < Player.sleeves.length; ++j) {
|
|
|
|
if (j === i) {
|
|
|
|
continue;
|
2018-08-07 03:15:31 +02:00
|
|
|
}
|
2021-09-09 05:47:34 +02:00
|
|
|
Player.sleeves[j].gainExperience(Player, expForOtherSleeves, numCyclesOffline, true);
|
2021-09-05 01:09:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update total playtime
|
|
|
|
var time = numCyclesOffline * Engine._idleSpeed;
|
|
|
|
if (Player.totalPlaytime == null) {
|
|
|
|
Player.totalPlaytime = 0;
|
|
|
|
}
|
|
|
|
if (Player.playtimeSinceLastAug == null) {
|
|
|
|
Player.playtimeSinceLastAug = 0;
|
|
|
|
}
|
|
|
|
if (Player.playtimeSinceLastBitnode == null) {
|
|
|
|
Player.playtimeSinceLastBitnode = 0;
|
|
|
|
}
|
|
|
|
Player.totalPlaytime += time;
|
|
|
|
Player.playtimeSinceLastAug += time;
|
|
|
|
Player.playtimeSinceLastBitnode += time;
|
|
|
|
|
|
|
|
Player.lastUpdate = Engine._lastUpdate;
|
|
|
|
Engine.start(); // Run main game loop and Scripts loop
|
|
|
|
removeLoadingScreen();
|
|
|
|
const timeOfflineString = convertTimeMsToTimeElapsedString(time);
|
|
|
|
dialogBoxCreate(
|
|
|
|
<>
|
2021-09-09 05:47:34 +02:00
|
|
|
Offline for {timeOfflineString}. While you were offline, your scripts generated{" "}
|
|
|
|
<Money money={offlineHackingIncome} />, your Hacknet Nodes generated {hacknetProdInfo} and you gained{" "}
|
2021-09-05 01:09:30 +02:00
|
|
|
{Reputation(offlineReputation)} divided amongst your factions.
|
|
|
|
</>,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
// No save found, start new game
|
|
|
|
initBitNodeMultipliers(Player);
|
|
|
|
initSpecialServerIps();
|
|
|
|
Engine.setDisplayElements(); // Sets variables for important DOM elements
|
|
|
|
Engine.start(); // Run main game loop and Scripts loop
|
|
|
|
Player.init();
|
|
|
|
initForeignServers(Player.getHomeComputer());
|
|
|
|
initCompanies();
|
|
|
|
initFactions();
|
|
|
|
initAugmentations();
|
|
|
|
initMessages();
|
|
|
|
updateSourceFileFlags(Player);
|
|
|
|
|
|
|
|
// Start interactive tutorial
|
|
|
|
iTutorialStart();
|
|
|
|
removeLoadingScreen();
|
|
|
|
}
|
2021-09-11 07:54:19 +02:00
|
|
|
|
|
|
|
ReactDOM.render(<SidebarRoot engine={this} player={Player} />, document.getElementById("sidebar"));
|
2021-09-16 08:52:45 +02:00
|
|
|
Engine.loadTerminalContent();
|
2021-09-05 01:09:30 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
setDisplayElements: function () {
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.content = document.getElementById("generic-react-container");
|
|
|
|
Engine.Display.content.style.display = "none";
|
2021-09-05 01:09:30 +02:00
|
|
|
|
2021-09-09 05:47:34 +02:00
|
|
|
Engine.Display.missionContent = document.getElementById("mission-container");
|
2021-09-05 01:09:30 +02:00
|
|
|
Engine.Display.missionContent.style.display = "none";
|
|
|
|
|
|
|
|
// Work In Progress
|
2021-09-09 05:47:34 +02:00
|
|
|
Engine.Display.workInProgressContent = document.getElementById("work-in-progress-container");
|
2021-09-05 01:09:30 +02:00
|
|
|
Engine.Display.workInProgressContent.style.display = "none";
|
|
|
|
|
|
|
|
// Red Pill / Hack World Daemon
|
2021-09-09 05:47:34 +02:00
|
|
|
Engine.Display.redPillContent = document.getElementById("red-pill-container");
|
2021-09-05 01:09:30 +02:00
|
|
|
Engine.Display.redPillContent.style.display = "none";
|
|
|
|
|
2021-09-10 23:29:07 +02:00
|
|
|
Engine.Display.infiltrationContent = document.getElementById("infiltration-container");
|
|
|
|
Engine.Display.infiltrationContent.style.display = "none";
|
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
// Cinematic Text
|
2021-09-09 05:47:34 +02:00
|
|
|
Engine.Display.cinematicTextContent = document.getElementById("cinematic-text-container");
|
2021-09-05 01:09:30 +02:00
|
|
|
Engine.Display.cinematicTextContent.style.display = "none";
|
2021-09-16 23:30:47 +02:00
|
|
|
|
|
|
|
Engine.Display.overview = document.getElementById("character-overview");
|
2021-09-05 01:09:30 +02:00
|
|
|
},
|
2017-07-25 03:06:40 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
// Initialization
|
|
|
|
init: function () {
|
|
|
|
// Player was working cancel button
|
|
|
|
if (Player.isWorking) {
|
2021-09-09 05:47:34 +02:00
|
|
|
var cancelButton = document.getElementById("work-in-progress-cancel-button");
|
2021-09-05 01:09:30 +02:00
|
|
|
cancelButton.addEventListener("click", function () {
|
|
|
|
if (Player.workType == CONSTANTS.WorkTypeFaction) {
|
|
|
|
Player.finishFactionWork(true);
|
|
|
|
} else if (Player.workType == CONSTANTS.WorkTypeCreateProgram) {
|
|
|
|
Player.finishCreateProgramWork(true);
|
|
|
|
} else if (Player.workType == CONSTANTS.WorkTypeStudyClass) {
|
|
|
|
Player.finishClass();
|
|
|
|
} else if (Player.workType == CONSTANTS.WorkTypeCrime) {
|
|
|
|
Player.finishCrime(true);
|
|
|
|
} else if (Player.workType == CONSTANTS.WorkTypeCompanyPartTime) {
|
|
|
|
Player.finishWorkPartTime();
|
|
|
|
} else {
|
|
|
|
Player.finishWork(true);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-09-09 05:47:34 +02:00
|
|
|
const focusButton = document.getElementById("work-in-progress-something-else-button");
|
2021-09-05 01:09:30 +02:00
|
|
|
focusButton.style.visibility = "hidden";
|
2021-09-09 05:47:34 +02:00
|
|
|
const focusable = [CONSTANTS.WorkTypeFaction, CONSTANTS.WorkTypeCompanyPartTime, CONSTANTS.WorkTypeCompany];
|
2021-09-05 01:09:30 +02:00
|
|
|
if (focusable.includes(Player.workType)) {
|
|
|
|
focusButton.style.visibility = "visible";
|
|
|
|
focusButton.addEventListener("click", function () {
|
|
|
|
Player.stopFocusing();
|
2017-06-13 17:58:31 +02:00
|
|
|
});
|
2021-09-05 01:09:30 +02:00
|
|
|
}
|
2017-07-25 03:06:40 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
Engine.loadWorkInProgressContent();
|
2017-07-25 03:06:40 +02:00
|
|
|
|
2021-09-16 23:30:47 +02:00
|
|
|
Engine.displayCharacterOverviewInfo();
|
|
|
|
}
|
2021-09-05 01:09:30 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
start: function () {
|
|
|
|
// Run main loop
|
|
|
|
Engine.idleTimer();
|
|
|
|
},
|
2016-10-17 10:24:39 +02:00
|
|
|
};
|
|
|
|
|
2021-05-11 19:27:02 +02:00
|
|
|
var indexedDbRequest;
|
2021-09-05 01:09:30 +02:00
|
|
|
window.onload = function () {
|
|
|
|
if (!window.indexedDB) {
|
|
|
|
return Engine.load(null); // Will try to load from localstorage
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* DB is called bitburnerSave
|
|
|
|
* Object store is called savestring
|
|
|
|
* key for the Object store is called save
|
|
|
|
*/
|
|
|
|
indexedDbRequest = window.indexedDB.open("bitburnerSave", 1);
|
|
|
|
|
|
|
|
indexedDbRequest.onerror = function (e) {
|
|
|
|
console.error("Error opening indexedDB: ");
|
|
|
|
console.error(e);
|
|
|
|
return Engine.load(null); // Try to load from localstorage
|
|
|
|
};
|
|
|
|
|
|
|
|
indexedDbRequest.onsuccess = function (e) {
|
|
|
|
Engine.indexedDb = e.target.result;
|
|
|
|
var transaction = Engine.indexedDb.transaction(["savestring"]);
|
|
|
|
var objectStore = transaction.objectStore("savestring");
|
|
|
|
var request = objectStore.get("save");
|
|
|
|
request.onerror = function (e) {
|
|
|
|
console.error("Error in Database request to get savestring: " + e);
|
|
|
|
return Engine.load(null); // Try to load from localstorage
|
2017-10-12 04:00:22 +02:00
|
|
|
};
|
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
request.onsuccess = function () {
|
|
|
|
Engine.load(request.result);
|
2017-10-12 04:00:22 +02:00
|
|
|
};
|
2021-09-05 01:09:30 +02:00
|
|
|
};
|
2017-10-12 04:00:22 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
indexedDbRequest.onupgradeneeded = function (e) {
|
|
|
|
const db = e.target.result;
|
|
|
|
db.createObjectStore("savestring");
|
|
|
|
};
|
2016-10-17 10:24:39 +02:00
|
|
|
};
|
2017-08-30 19:44:29 +02:00
|
|
|
|
2021-09-05 01:09:30 +02:00
|
|
|
export { Engine };
|