2019-04-11 10:37:40 +02:00
|
|
|
import {
|
|
|
|
loadAliases,
|
|
|
|
loadGlobalAliases,
|
|
|
|
Aliases,
|
|
|
|
GlobalAliases
|
|
|
|
} from "./Alias";
|
|
|
|
import { Companies, loadCompanies } from "./Company/Companies";
|
|
|
|
import { CompanyPosition } from "./Company/CompanyPosition";
|
|
|
|
import { CONSTANTS } from "./Constants";
|
|
|
|
import { Engine } from "./engine";
|
|
|
|
import { Factions, loadFactions } from "./Faction/Factions";
|
|
|
|
import { processPassiveFactionRepGain } from "./Faction/FactionHelpers";
|
|
|
|
import { loadFconf } from "./Fconf/Fconf";
|
|
|
|
import { FconfSettings } from "./Fconf/FconfSettings";
|
|
|
|
import { loadAllGangs, AllGangs } from "./Gang";
|
|
|
|
import {
|
|
|
|
hasHacknetServers,
|
|
|
|
processHacknetEarnings
|
|
|
|
} from "./Hacknet/HacknetHelpers";
|
2019-03-05 02:40:28 +01:00
|
|
|
import { loadMessages, initMessages, Messages } from "./Message/MessageHelpers";
|
2019-05-07 03:01:06 +02:00
|
|
|
import { loadAllRunningScripts } from "./NetscriptWorker";
|
2019-04-11 10:37:40 +02:00
|
|
|
import { Player, loadPlayer } from "./Player";
|
|
|
|
import { AllServers, loadAllServers } from "./Server/AllServers";
|
|
|
|
import { Settings } from "./Settings/Settings";
|
|
|
|
import {
|
|
|
|
loadSpecialServerIps,
|
|
|
|
SpecialServerIps
|
|
|
|
} from "./Server/SpecialServerIps";
|
2019-05-14 10:35:37 +02:00
|
|
|
import { SourceFileFlags } from "./SourceFile/SourceFileFlags";
|
2019-04-11 10:37:40 +02:00
|
|
|
import { loadStockMarket, StockMarket } from "./StockMarket/StockMarket";
|
2019-02-20 09:42:27 +01:00
|
|
|
|
2019-04-11 10:37:40 +02:00
|
|
|
import { createStatusText } from "./ui/createStatusText";
|
|
|
|
import { numeralWrapper } from "./ui/numeralFormat";
|
2017-08-30 19:44:29 +02:00
|
|
|
|
2019-04-11 10:37:40 +02:00
|
|
|
import { setTimeoutRef } from "./utils/SetTimeoutRef";
|
|
|
|
|
|
|
|
import { dialogBoxCreate } from "../utils/DialogBox";
|
|
|
|
import { gameOptionsBoxClose } from "../utils/GameOptions";
|
|
|
|
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
|
|
|
|
import { clearEventListeners } from "../utils/uiHelpers/clearEventListeners";
|
|
|
|
import {
|
|
|
|
Reviver,
|
|
|
|
Generic_toJSON,
|
|
|
|
Generic_fromJSON
|
|
|
|
} from "../utils/JSONReviver";
|
|
|
|
import { createElement } from "../utils/uiHelpers/createElement";
|
|
|
|
import { createPopup } from "../utils/uiHelpers/createPopup";
|
|
|
|
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
|
|
|
|
|
|
|
import Decimal from "decimal.js";
|
2017-08-30 19:44:29 +02:00
|
|
|
|
2017-07-25 16:39:56 +02:00
|
|
|
/* SaveObject.js
|
|
|
|
* Defines the object used to save/load games
|
2017-05-05 03:08:44 +02:00
|
|
|
*/
|
2017-08-30 19:44:29 +02:00
|
|
|
let saveObject = new BitburnerSaveObject();
|
2017-05-05 03:08:44 +02:00
|
|
|
|
|
|
|
function BitburnerSaveObject() {
|
2018-12-27 03:38:07 +01:00
|
|
|
this.PlayerSave = "";
|
|
|
|
this.AllServersSave = "";
|
|
|
|
this.CompaniesSave = "";
|
|
|
|
this.FactionsSave = "";
|
|
|
|
this.SpecialServerIpsSave = "";
|
|
|
|
this.AliasesSave = "";
|
|
|
|
this.GlobalAliasesSave = "";
|
|
|
|
this.MessagesSave = "";
|
|
|
|
this.StockMarketSave = "";
|
|
|
|
this.SettingsSave = "";
|
|
|
|
this.FconfSettingsSave = "";
|
|
|
|
this.VersionSave = "";
|
|
|
|
this.AllGangsSave = "";
|
2017-05-05 03:08:44 +02:00
|
|
|
}
|
|
|
|
|
2018-12-31 01:11:48 +01:00
|
|
|
BitburnerSaveObject.prototype.getSaveString = function() {
|
2017-05-05 03:08:44 +02:00
|
|
|
this.PlayerSave = JSON.stringify(Player);
|
2017-07-25 16:39:56 +02:00
|
|
|
|
2019-04-13 03:22:46 +02:00
|
|
|
// Delete all logs from all running scripts
|
2017-06-19 16:54:11 +02:00
|
|
|
var TempAllServers = JSON.parse(JSON.stringify(AllServers), Reviver);
|
2017-06-18 11:31:14 +02:00
|
|
|
for (var ip in TempAllServers) {
|
|
|
|
var server = TempAllServers[ip];
|
|
|
|
if (server == null) {continue;}
|
|
|
|
for (var i = 0; i < server.runningScripts.length; ++i) {
|
|
|
|
var runningScriptObj = server.runningScripts[i];
|
|
|
|
runningScriptObj.logs.length = 0;
|
|
|
|
runningScriptObj.logs = [];
|
|
|
|
}
|
|
|
|
}
|
2017-07-25 16:39:56 +02:00
|
|
|
|
2017-06-18 11:31:14 +02:00
|
|
|
this.AllServersSave = JSON.stringify(TempAllServers);
|
2017-05-05 03:08:44 +02:00
|
|
|
this.CompaniesSave = JSON.stringify(Companies);
|
|
|
|
this.FactionsSave = JSON.stringify(Factions);
|
|
|
|
this.SpecialServerIpsSave = JSON.stringify(SpecialServerIps);
|
2017-05-23 17:12:09 +02:00
|
|
|
this.AliasesSave = JSON.stringify(Aliases);
|
2017-06-30 18:44:03 +02:00
|
|
|
this.GlobalAliasesSave = JSON.stringify(GlobalAliases);
|
2017-06-02 06:15:45 +02:00
|
|
|
this.MessagesSave = JSON.stringify(Messages);
|
2017-07-03 21:42:11 +02:00
|
|
|
this.StockMarketSave = JSON.stringify(StockMarket);
|
2017-07-25 16:39:56 +02:00
|
|
|
this.SettingsSave = JSON.stringify(Settings);
|
2018-03-12 20:39:04 +01:00
|
|
|
this.FconfSettingsSave = JSON.stringify(FconfSettings);
|
2017-06-07 02:04:18 +02:00
|
|
|
this.VersionSave = JSON.stringify(CONSTANTS.Version);
|
2019-04-14 11:08:10 +02:00
|
|
|
if (Player.inGang()) {
|
2017-08-13 07:01:33 +02:00
|
|
|
this.AllGangsSave = JSON.stringify(AllGangs);
|
|
|
|
}
|
2017-05-05 06:54:40 +02:00
|
|
|
var saveString = btoa(unescape(encodeURIComponent(JSON.stringify(this))));
|
2017-10-12 04:00:22 +02:00
|
|
|
|
2018-12-31 01:11:48 +01:00
|
|
|
return saveString;
|
|
|
|
}
|
|
|
|
|
|
|
|
BitburnerSaveObject.prototype.saveGame = function(db) {
|
|
|
|
var saveString = this.getSaveString();
|
|
|
|
|
2019-04-13 03:22:46 +02:00
|
|
|
// We'll save to both localstorage and indexedDb
|
2017-10-12 04:00:22 +02:00
|
|
|
var objectStore = db.transaction(["savestring"], "readwrite").objectStore("savestring");
|
|
|
|
var request = objectStore.put(saveString, "save");
|
|
|
|
|
|
|
|
request.onerror = function(e) {
|
|
|
|
console.log("Error saving game to IndexedDB: " + e);
|
|
|
|
}
|
|
|
|
|
|
|
|
request.onsuccess = function(e) {
|
2019-04-13 03:22:46 +02:00
|
|
|
// TODO anything here?
|
2017-10-12 04:00:22 +02:00
|
|
|
}
|
|
|
|
|
2017-09-19 20:38:03 +02:00
|
|
|
try {
|
|
|
|
window.localStorage.setItem("bitburnerSave", saveString);
|
|
|
|
} catch(e) {
|
|
|
|
if (e.code == 22) {
|
2018-07-19 18:17:43 +02:00
|
|
|
createStatusText("Save failed for localStorage! Check console(F12)");
|
2017-10-12 04:00:22 +02:00
|
|
|
console.log("Failed to save game to localStorage because the size of the save file " +
|
|
|
|
"is too large. However, the game will still be saved to IndexedDb if your browser " +
|
|
|
|
"supports it. If you would like to save to localStorage as well, then " +
|
|
|
|
"consider killing several of your scripts to " +
|
|
|
|
"fix this, or increasing the size of your browsers localStorage");
|
2017-09-19 20:38:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-19 18:17:43 +02:00
|
|
|
createStatusText("Game saved!");
|
2017-05-05 03:08:44 +02:00
|
|
|
}
|
|
|
|
|
2018-11-16 04:45:03 +01:00
|
|
|
// Makes necessary changes to the loaded/imported data to ensure
|
|
|
|
// the game stills works with new versions
|
|
|
|
function evaluateVersionCompatibility(ver) {
|
|
|
|
// This version refactored the Company/job-related code
|
|
|
|
if (ver <= "0.41.2") {
|
|
|
|
// Player's company position is now a string
|
|
|
|
if (Player.companyPosition != null && typeof Player.companyPosition !== "string") {
|
|
|
|
console.log("Changed Player.companyPosition value to be compatible with v0.41.2");
|
2018-11-18 01:23:48 +01:00
|
|
|
Player.companyPosition = Player.companyPosition.data.positionName;
|
2018-11-16 04:45:03 +01:00
|
|
|
if (Player.companyPosition == null) {
|
|
|
|
Player.companyPosition = "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// The "companyName" property of all Companies is renamed to "name"
|
|
|
|
for (var companyName in Companies) {
|
|
|
|
const company = Companies[companyName];
|
2018-11-19 11:21:21 +01:00
|
|
|
if ((company.name == null || company.name === 0 || company.name === "") && company.companyName != null) {
|
2018-11-16 04:45:03 +01:00
|
|
|
console.log("Changed company name property to be compatible with v0.41.2");
|
|
|
|
company.name = company.companyName;
|
|
|
|
}
|
2018-11-18 01:23:48 +01:00
|
|
|
|
|
|
|
if (company.companyPositions instanceof Array) {
|
|
|
|
console.log("Changed company companyPositions property to be compatible with v0.41.2");
|
|
|
|
const pos = {};
|
|
|
|
|
|
|
|
for (let i = 0; i < company.companyPositions.length; ++i) {
|
|
|
|
pos[company.companyPositions[i]] = true;
|
|
|
|
}
|
|
|
|
company.companyPositions = pos;
|
|
|
|
}
|
2018-11-16 04:45:03 +01:00
|
|
|
}
|
|
|
|
}
|
2019-01-15 04:34:04 +01:00
|
|
|
|
|
|
|
// This version allowed players to hold multiple jobs
|
2019-01-18 18:57:21 +01:00
|
|
|
if (ver < "0.43.0") {
|
|
|
|
if (Player.companyName !== "" && Player.companyPosition != null && Player.companyPosition !== "") {
|
2019-01-15 04:34:04 +01:00
|
|
|
console.log("Copied player's companyName and companyPosition properties to the Player.jobs map for v0.43.0");
|
|
|
|
Player.jobs[Player.companyName] = Player.companyPosition;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete Player.companyPosition;
|
|
|
|
}
|
2018-11-16 04:45:03 +01:00
|
|
|
}
|
|
|
|
|
2017-10-12 04:00:22 +02:00
|
|
|
function loadGame(saveString) {
|
2017-10-26 00:05:12 +02:00
|
|
|
if (saveString === "" || saveString == null || saveString === undefined) {
|
2017-10-12 04:00:22 +02:00
|
|
|
if (!window.localStorage.getItem("bitburnerSave")) {
|
|
|
|
console.log("No save file to load");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
saveString = decodeURIComponent(escape(atob(window.localStorage.getItem("bitburnerSave"))));
|
|
|
|
console.log("Loading game from localStorage");
|
|
|
|
} else {
|
|
|
|
saveString = decodeURIComponent(escape(atob(saveString)));
|
|
|
|
console.log("Loading game from IndexedDB");
|
2017-05-05 03:08:44 +02:00
|
|
|
}
|
2017-10-12 04:00:22 +02:00
|
|
|
|
|
|
|
var saveObj = JSON.parse(saveString, Reviver);
|
2017-07-25 16:39:56 +02:00
|
|
|
|
2017-08-30 19:44:29 +02:00
|
|
|
loadPlayer(saveObj.PlayerSave);
|
|
|
|
loadAllServers(saveObj.AllServersSave);
|
|
|
|
loadCompanies(saveObj.CompaniesSave);
|
|
|
|
loadFactions(saveObj.FactionsSave);
|
|
|
|
loadSpecialServerIps(saveObj.SpecialServerIpsSave);
|
2017-07-25 16:39:56 +02:00
|
|
|
|
2017-05-23 19:36:35 +02:00
|
|
|
if (saveObj.hasOwnProperty("AliasesSave")) {
|
2017-05-23 18:15:17 +02:00
|
|
|
try {
|
2017-08-30 19:44:29 +02:00
|
|
|
loadAliases(saveObj.AliasesSave);
|
2017-05-23 18:15:17 +02:00
|
|
|
} catch(e) {
|
2019-04-30 05:54:20 +02:00
|
|
|
console.warn(`Could not load Aliases from save`);
|
2017-08-30 19:44:29 +02:00
|
|
|
loadAliases("");
|
2017-05-23 18:15:17 +02:00
|
|
|
}
|
|
|
|
} else {
|
2019-04-30 05:54:20 +02:00
|
|
|
console.warn(`Save file did not contain an Aliases property`);
|
2017-08-30 19:44:29 +02:00
|
|
|
loadAliases("");
|
2017-05-23 18:15:17 +02:00
|
|
|
}
|
2017-06-30 18:44:03 +02:00
|
|
|
if (saveObj.hasOwnProperty("GlobalAliasesSave")) {
|
|
|
|
try {
|
2017-08-30 19:44:29 +02:00
|
|
|
loadGlobalAliases(saveObj.GlobalAliasesSave);
|
2017-06-30 18:44:03 +02:00
|
|
|
} catch(e) {
|
2019-04-30 05:54:20 +02:00
|
|
|
console.warn(`Could not load GlobalAliases from save`);
|
2017-08-30 19:44:29 +02:00
|
|
|
loadGlobalAliases("");
|
2017-06-30 18:44:03 +02:00
|
|
|
}
|
|
|
|
} else {
|
2019-04-30 05:54:20 +02:00
|
|
|
console.warn(`Save file did not contain a GlobalAliases property`);
|
2017-08-30 19:44:29 +02:00
|
|
|
loadGlobalAliases("");
|
2017-06-30 18:44:03 +02:00
|
|
|
}
|
2017-06-02 06:15:45 +02:00
|
|
|
if (saveObj.hasOwnProperty("MessagesSave")) {
|
|
|
|
try {
|
2017-08-30 19:44:29 +02:00
|
|
|
loadMessages(saveObj.MessagesSave);
|
2017-06-02 06:15:45 +02:00
|
|
|
} catch(e) {
|
2019-04-30 05:54:20 +02:00
|
|
|
console.warn(`Could not load Messages from save`);
|
2017-06-02 06:15:45 +02:00
|
|
|
initMessages();
|
|
|
|
}
|
|
|
|
} else {
|
2019-04-30 05:54:20 +02:00
|
|
|
console.warn(`Save file did not contain a Messages property`);
|
2017-06-02 06:15:45 +02:00
|
|
|
initMessages();
|
|
|
|
}
|
2017-07-03 21:42:11 +02:00
|
|
|
if (saveObj.hasOwnProperty("StockMarketSave")) {
|
|
|
|
try {
|
2017-08-30 19:44:29 +02:00
|
|
|
loadStockMarket(saveObj.StockMarketSave);
|
2017-07-03 21:42:11 +02:00
|
|
|
} catch(e) {
|
2017-08-30 19:44:29 +02:00
|
|
|
loadStockMarket("");
|
2017-07-03 21:42:11 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-08-30 19:44:29 +02:00
|
|
|
loadStockMarket("");
|
2017-07-03 21:42:11 +02:00
|
|
|
}
|
2017-07-25 16:39:56 +02:00
|
|
|
if (saveObj.hasOwnProperty("SettingsSave")) {
|
|
|
|
try {
|
2018-07-31 05:02:12 +02:00
|
|
|
Settings.load(saveObj.SettingsSave);
|
2017-07-25 16:39:56 +02:00
|
|
|
} catch(e) {
|
2017-08-30 19:44:29 +02:00
|
|
|
console.log("ERROR: Failed to parse Settings. Re-initing default values");
|
2018-07-31 05:02:12 +02:00
|
|
|
Settings.init();
|
2017-07-25 16:39:56 +02:00
|
|
|
}
|
|
|
|
} else {
|
2018-07-31 05:02:12 +02:00
|
|
|
Settings.init();
|
2017-07-25 16:39:56 +02:00
|
|
|
}
|
2018-03-12 20:39:04 +01:00
|
|
|
if (saveObj.hasOwnProperty("FconfSettingsSave")) {
|
|
|
|
try {
|
|
|
|
loadFconf(saveObj.FconfSettingsSave);
|
|
|
|
} catch(e) {
|
|
|
|
console.log("ERROR: Failed to parse .fconf Settings.");
|
|
|
|
}
|
|
|
|
}
|
2017-06-07 02:04:18 +02:00
|
|
|
if (saveObj.hasOwnProperty("VersionSave")) {
|
|
|
|
try {
|
|
|
|
var ver = JSON.parse(saveObj.VersionSave, Reviver);
|
2018-11-16 04:45:03 +01:00
|
|
|
evaluateVersionCompatibility(ver);
|
2018-11-16 02:28:23 +01:00
|
|
|
|
2018-07-19 04:23:49 +02:00
|
|
|
if (window.location.href.toLowerCase().includes("bitburner-beta")) {
|
2019-04-13 03:22:46 +02:00
|
|
|
// Beta branch, always show changes
|
2018-07-19 04:23:49 +02:00
|
|
|
createBetaUpdateText();
|
|
|
|
} else if (ver != CONSTANTS.Version) {
|
2017-06-07 02:28:20 +02:00
|
|
|
createNewUpdateText();
|
2017-06-07 02:04:18 +02:00
|
|
|
}
|
|
|
|
} catch(e) {
|
2017-06-07 02:28:20 +02:00
|
|
|
createNewUpdateText();
|
2017-06-07 02:04:18 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-06-07 02:28:20 +02:00
|
|
|
createNewUpdateText();
|
2017-06-07 02:04:18 +02:00
|
|
|
}
|
2019-04-14 11:08:10 +02:00
|
|
|
if (Player.inGang() && saveObj.hasOwnProperty("AllGangsSave")) {
|
2017-08-13 07:01:33 +02:00
|
|
|
try {
|
2017-08-30 19:44:29 +02:00
|
|
|
loadAllGangs(saveObj.AllGangsSave);
|
2017-08-13 07:01:33 +02:00
|
|
|
} catch(e) {
|
|
|
|
console.log("ERROR: Failed to parse AllGangsSave: " + e);
|
|
|
|
}
|
|
|
|
}
|
2017-07-25 16:39:56 +02:00
|
|
|
|
2017-05-05 03:08:44 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-08-30 19:44:29 +02:00
|
|
|
function loadImportedGame(saveObj, saveString) {
|
2017-06-08 06:57:40 +02:00
|
|
|
var tempSaveObj = null;
|
|
|
|
var tempPlayer = null;
|
|
|
|
var tempAllServers = null;
|
|
|
|
var tempCompanies = null;
|
|
|
|
var tempFactions = null;
|
|
|
|
var tempSpecialServerIps = null;
|
|
|
|
var tempAliases = null;
|
2017-06-30 18:44:03 +02:00
|
|
|
var tempGlobalAliases = null;
|
2017-06-08 06:57:40 +02:00
|
|
|
var tempMessages = null;
|
2017-07-03 21:42:11 +02:00
|
|
|
var tempStockMarket = null;
|
2018-02-18 04:08:54 +01:00
|
|
|
var tempAllGangs = null;
|
2018-12-27 03:38:07 +01:00
|
|
|
let tempCorporationResearchTrees = null;
|
2017-08-30 19:44:29 +02:00
|
|
|
|
2019-04-13 03:22:46 +02:00
|
|
|
// Check to see if the imported save file can be parsed. If any
|
|
|
|
// errors are caught it will fail
|
2017-06-08 06:57:40 +02:00
|
|
|
try {
|
2017-08-30 19:44:29 +02:00
|
|
|
var decodedSaveString = decodeURIComponent(escape(atob(saveString)));
|
2017-06-08 06:57:40 +02:00
|
|
|
tempSaveObj = new BitburnerSaveObject();
|
2017-08-30 19:44:29 +02:00
|
|
|
tempSaveObj = JSON.parse(decodedSaveString, Reviver);
|
2017-07-25 16:39:56 +02:00
|
|
|
|
2017-08-30 19:44:29 +02:00
|
|
|
tempPlayer = JSON.parse(tempSaveObj.PlayerSave, Reviver);
|
2017-08-01 21:10:21 +02:00
|
|
|
|
2019-04-13 03:22:46 +02:00
|
|
|
// Parse Decimal.js objects
|
2017-08-01 21:10:21 +02:00
|
|
|
tempPlayer.money = new Decimal(tempPlayer.money);
|
|
|
|
|
2017-06-08 06:57:40 +02:00
|
|
|
tempAllServers = JSON.parse(tempSaveObj.AllServersSave, Reviver);
|
|
|
|
tempCompanies = JSON.parse(tempSaveObj.CompaniesSave, Reviver);
|
|
|
|
tempFactions = JSON.parse(tempSaveObj.FactionsSave, Reviver);
|
|
|
|
tempSpecialServerIps = JSON.parse(tempSaveObj.SpecialServerIpsSave, Reviver);
|
|
|
|
if (tempSaveObj.hasOwnProperty("AliasesSave")) {
|
|
|
|
try {
|
|
|
|
tempAliases = JSON.parse(tempSaveObj.AliasesSave, Reviver);
|
|
|
|
} catch(e) {
|
2017-08-30 19:44:29 +02:00
|
|
|
console.log("Parsing Aliases save failed: " + e);
|
2017-06-08 06:57:40 +02:00
|
|
|
tempAliases = {};
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
tempAliases = {};
|
|
|
|
}
|
2017-06-30 18:44:03 +02:00
|
|
|
if (tempSaveObj.hasOwnProperty("GlobalAliases")) {
|
|
|
|
try {
|
|
|
|
tempGlobalAliases = JSON.parse(tempSaveObj.AliasesSave, Reviver);
|
|
|
|
} catch(e) {
|
2017-08-30 19:44:29 +02:00
|
|
|
console.log("Parsing Global Aliases save failed: " + e);
|
2017-06-30 18:44:03 +02:00
|
|
|
tempGlobalAliases = {};
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
tempGlobalAliases = {};
|
|
|
|
}
|
2017-06-08 06:57:40 +02:00
|
|
|
if (tempSaveObj.hasOwnProperty("MessagesSave")) {
|
|
|
|
try {
|
|
|
|
tempMessages = JSON.parse(tempSaveObj.MessagesSave, Reviver);
|
|
|
|
} catch(e) {
|
2017-08-30 19:44:29 +02:00
|
|
|
console.log("Parsing Messages save failed: " + e);
|
2017-06-08 06:57:40 +02:00
|
|
|
initMessages();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
initMessages();
|
|
|
|
}
|
2017-07-03 21:42:11 +02:00
|
|
|
if (saveObj.hasOwnProperty("StockMarketSave")) {
|
|
|
|
try {
|
2018-02-18 04:08:54 +01:00
|
|
|
tempStockMarket = JSON.parse(tempSaveObj.StockMarketSave, Reviver);
|
2017-07-03 21:42:11 +02:00
|
|
|
} catch(e) {
|
2017-08-30 19:44:29 +02:00
|
|
|
console.log("Parsing StockMarket save failed: " + e);
|
2017-07-03 21:42:11 +02:00
|
|
|
tempStockMarket = {};
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
tempStockMarket = {};
|
|
|
|
}
|
2017-06-08 06:57:40 +02:00
|
|
|
if (tempSaveObj.hasOwnProperty("VersionSave")) {
|
|
|
|
try {
|
|
|
|
var ver = JSON.parse(tempSaveObj.VersionSave, Reviver);
|
2018-11-16 04:45:03 +01:00
|
|
|
evaluateVersionCompatibility(ver);
|
2017-06-08 06:57:40 +02:00
|
|
|
} catch(e) {
|
2018-11-16 02:28:23 +01:00
|
|
|
console.error("Parsing Version save failed: " + e);
|
2017-06-08 06:57:40 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
}
|
2019-04-14 11:08:10 +02:00
|
|
|
if (tempPlayer.inGang() && tempSaveObj.hasOwnProperty("AllGangsSave")) {
|
2017-08-13 07:01:33 +02:00
|
|
|
try {
|
2018-02-18 04:08:54 +01:00
|
|
|
loadAllGangs(tempSaveObj.AllGangsSave);
|
2017-08-13 07:01:33 +02:00
|
|
|
} catch(e) {
|
2018-12-27 03:38:07 +01:00
|
|
|
console.error(`Failed to parse AllGangsSave: {e}`);
|
|
|
|
throw e;
|
2017-08-13 07:01:33 +02:00
|
|
|
}
|
|
|
|
}
|
2017-06-08 06:57:40 +02:00
|
|
|
} catch(e) {
|
2017-08-30 19:44:29 +02:00
|
|
|
dialogBoxCreate("Error importing game: " + e.toString());
|
2017-06-08 06:57:40 +02:00
|
|
|
return false;
|
|
|
|
}
|
2017-07-25 16:39:56 +02:00
|
|
|
|
2019-04-13 03:22:46 +02:00
|
|
|
// Since the save file is valid, load everything for real
|
2017-08-30 19:44:29 +02:00
|
|
|
saveString = decodeURIComponent(escape(atob(saveString)));
|
|
|
|
saveObj = JSON.parse(saveString, Reviver);
|
2017-07-25 16:39:56 +02:00
|
|
|
|
2017-08-30 19:44:29 +02:00
|
|
|
loadPlayer(saveObj.PlayerSave);
|
|
|
|
loadAllServers(saveObj.AllServersSave);
|
|
|
|
loadCompanies(saveObj.CompaniesSave);
|
|
|
|
loadFactions(saveObj.FactionsSave);
|
|
|
|
loadSpecialServerIps(saveObj.SpecialServerIpsSave);
|
2017-07-25 16:39:56 +02:00
|
|
|
|
2017-08-30 19:44:29 +02:00
|
|
|
if (saveObj.hasOwnProperty("AliasesSave")) {
|
|
|
|
try {
|
|
|
|
loadAliases(saveObj.AliasesSave);
|
|
|
|
} catch(e) {
|
|
|
|
loadAliases("");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
loadAliases("");
|
2017-06-08 06:57:40 +02:00
|
|
|
}
|
2017-08-30 19:44:29 +02:00
|
|
|
if (saveObj.hasOwnProperty("GlobalAliasesSave")) {
|
|
|
|
try {
|
|
|
|
loadGlobalAliases(saveObj.GlobalAliasesSave);
|
|
|
|
} catch(e) {
|
|
|
|
loadGlobalAliases("");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
loadGlobalAliases("");
|
|
|
|
}
|
|
|
|
if (saveObj.hasOwnProperty("MessagesSave")) {
|
|
|
|
try {
|
|
|
|
loadMessages(saveObj.MessagesSave);
|
|
|
|
} catch(e) {
|
|
|
|
initMessages();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
initMessages();
|
|
|
|
}
|
|
|
|
if (saveObj.hasOwnProperty("StockMarketSave")) {
|
|
|
|
try {
|
|
|
|
loadStockMarket(saveObj.StockMarketSave);
|
|
|
|
} catch(e) {
|
|
|
|
loadStockMarket("");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
loadStockMarket("");
|
|
|
|
}
|
|
|
|
if (saveObj.hasOwnProperty("SettingsSave")) {
|
|
|
|
try {
|
2018-07-31 05:02:12 +02:00
|
|
|
Settings.load(saveObj.SettingsSave);
|
2017-08-30 19:44:29 +02:00
|
|
|
} catch(e) {
|
2018-07-31 05:02:12 +02:00
|
|
|
Settings.init();
|
2017-08-30 19:44:29 +02:00
|
|
|
}
|
|
|
|
} else {
|
2018-07-31 05:02:12 +02:00
|
|
|
Settings.init();
|
2017-08-30 19:44:29 +02:00
|
|
|
}
|
2018-03-12 20:39:04 +01:00
|
|
|
if (saveObj.hasOwnProperty("FconfSettingsSave")) {
|
|
|
|
try {
|
|
|
|
loadFconf(saveObj.FconfSettingsSave);
|
|
|
|
} catch(e) {
|
|
|
|
console.log("ERROR: Failed to load .fconf settings when importing");
|
|
|
|
}
|
|
|
|
}
|
2017-08-30 19:44:29 +02:00
|
|
|
if (saveObj.hasOwnProperty("VersionSave")) {
|
|
|
|
try {
|
|
|
|
var ver = JSON.parse(saveObj.VersionSave, Reviver);
|
2018-11-16 04:45:03 +01:00
|
|
|
evaluateVersionCompatibility(ver);
|
2017-09-01 18:59:11 +02:00
|
|
|
|
2017-08-30 19:44:29 +02:00
|
|
|
if (ver != CONSTANTS.Version) {
|
|
|
|
createNewUpdateText();
|
|
|
|
}
|
|
|
|
} catch(e) {
|
|
|
|
createNewUpdateText();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
createNewUpdateText();
|
|
|
|
}
|
2019-04-14 11:08:10 +02:00
|
|
|
if (Player.inGang() && saveObj.hasOwnProperty("AllGangsSave")) {
|
2017-08-30 19:44:29 +02:00
|
|
|
try {
|
|
|
|
loadAllGangs(saveObj.AllGangsSave);
|
|
|
|
} catch(e) {
|
|
|
|
console.log("ERROR: Failed to parse AllGangsSave: " + e);
|
|
|
|
}
|
2017-07-03 21:42:11 +02:00
|
|
|
}
|
2017-07-25 16:39:56 +02:00
|
|
|
|
2018-05-02 19:38:11 +02:00
|
|
|
var popupId = "import-game-restart-game-notice";
|
|
|
|
var txt = createElement("p", {
|
2018-09-08 03:53:11 +02:00
|
|
|
innerText:"Imported game! You need to SAVE the game and then RELOAD the page " +
|
2018-05-02 19:38:11 +02:00
|
|
|
"to make sure everything runs smoothly"
|
|
|
|
});
|
|
|
|
var gotitBtn = createElement("a", {
|
|
|
|
class:"a-link-button", float:"right", padding:"6px", innerText:"Got it!",
|
|
|
|
clickListener:()=>{
|
|
|
|
removeElementById(popupId);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
createPopup(popupId, [txt, gotitBtn]);
|
2017-06-08 07:08:53 +02:00
|
|
|
gameOptionsBoxClose();
|
2017-07-25 16:39:56 +02:00
|
|
|
|
2019-04-13 03:22:46 +02:00
|
|
|
// Re-start game
|
2017-06-08 17:59:22 +02:00
|
|
|
console.log("Importing game");
|
2019-04-13 03:22:46 +02:00
|
|
|
Engine.setDisplayElements(); // Sets variables for important DOM elements
|
|
|
|
Engine.init(); // Initialize buttons, work, etc.
|
2017-06-08 17:59:22 +02:00
|
|
|
|
2019-04-13 03:22:46 +02:00
|
|
|
// Calculate the number of cycles have elapsed while offline
|
2017-06-08 17:59:22 +02:00
|
|
|
Engine._lastUpdate = new Date().getTime();
|
|
|
|
var lastUpdate = Player.lastUpdate;
|
|
|
|
var numCyclesOffline = Math.floor((Engine._lastUpdate - lastUpdate) / Engine._idleSpeed);
|
2017-07-25 16:39:56 +02:00
|
|
|
|
2019-04-13 03:22:46 +02:00
|
|
|
// Process offline progress
|
|
|
|
var offlineProductionFromScripts = loadAllRunningScripts(); // This also takes care of offline production for those scripts
|
2017-06-08 17:59:22 +02:00
|
|
|
if (Player.isWorking) {
|
|
|
|
console.log("work() called in load() for " + numCyclesOffline * Engine._idleSpeed + " milliseconds");
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2017-07-25 16:39:56 +02:00
|
|
|
|
2019-04-13 03:22:46 +02:00
|
|
|
// Hacknet Nodes offline progress
|
2019-03-25 04:03:24 +01:00
|
|
|
var offlineProductionFromHacknetNodes = processHacknetEarnings(numCyclesOffline);
|
|
|
|
const hacknetProdInfo = hasHacknetServers() ?
|
|
|
|
`${numeralWrapper.format(offlineProductionFromHacknetNodes, "0.000a")} hashes` :
|
|
|
|
`${numeralWrapper.formatMoney(offlineProductionFromHacknetNodes)}`;
|
2017-07-25 16:39:56 +02:00
|
|
|
|
2019-04-13 03:22:46 +02:00
|
|
|
// Passive faction rep gain offline
|
2017-06-08 17:59:22 +02:00
|
|
|
processPassiveFactionRepGain(numCyclesOffline);
|
2017-07-25 16:39:56 +02:00
|
|
|
|
2019-04-13 03:22:46 +02:00
|
|
|
// Update total playtime
|
2017-06-08 17:59:22 +02:00
|
|
|
var time = numCyclesOffline * Engine._idleSpeed;
|
|
|
|
if (Player.totalPlaytime == null) {Player.totalPlaytime = 0;}
|
2017-06-17 19:47:04 +02:00
|
|
|
if (Player.playtimeSinceLastAug == null) {Player.playtimeSinceLastAug = 0;}
|
2018-06-22 21:38:25 +02:00
|
|
|
if (Player.playtimeSinceLastBitnode == null) {Player.playtimeSinceLastBitnode = 0;}
|
2017-06-08 17:59:22 +02:00
|
|
|
Player.totalPlaytime += time;
|
2017-06-17 19:47:04 +02:00
|
|
|
Player.playtimeSinceLastAug += time;
|
2018-06-22 21:38:25 +02:00
|
|
|
Player.playtimeSinceLastBitnode += time;
|
2017-07-25 16:39:56 +02:00
|
|
|
|
2019-04-13 03:22:46 +02:00
|
|
|
// Re-apply augmentations
|
2017-06-08 17:59:22 +02:00
|
|
|
Player.reapplyAllAugmentations();
|
2017-07-25 16:39:56 +02:00
|
|
|
|
2019-04-13 03:22:46 +02:00
|
|
|
// Clear terminal
|
2017-06-08 20:32:38 +02:00
|
|
|
$("#terminal tr:not(:last)").remove();
|
2017-07-25 16:39:56 +02:00
|
|
|
|
2017-06-08 17:59:22 +02:00
|
|
|
Player.lastUpdate = Engine._lastUpdate;
|
2019-04-13 03:22:46 +02:00
|
|
|
Engine.start(); // Run main game loop and Scripts loop
|
2019-02-12 10:14:38 +01:00
|
|
|
const timeOfflineString = convertTimeMsToTimeElapsedString(time);
|
|
|
|
dialogBoxCreate(`Offline for ${timeOfflineString}. While you were offline, your scripts ` +
|
|
|
|
"generated <span class='money-gold'>" +
|
2019-03-25 04:03:24 +01:00
|
|
|
numeralWrapper.formatMoney(offlineProductionFromScripts) + "</span> " +
|
|
|
|
"and your Hacknet Nodes generated <span class='money-gold'>" + hacknetProdInfo + "</span>");
|
2017-06-08 06:57:40 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-06-08 01:35:56 +02:00
|
|
|
BitburnerSaveObject.prototype.exportGame = function() {
|
2019-05-14 10:35:37 +02:00
|
|
|
const saveString = this.getSaveString();
|
2017-07-25 16:39:56 +02:00
|
|
|
|
2019-05-14 10:35:37 +02:00
|
|
|
// Save file name is based on current timestamp and BitNode
|
|
|
|
const epochTime = Math.round(Date.now() / 1000);
|
|
|
|
const bn = Player.bitNodeN;
|
|
|
|
const filename = `bitburnerSave_BN${bn}x${SourceFileFlags[bn]}_${epochTime}.json`;
|
2017-06-08 06:57:40 +02:00
|
|
|
var file = new Blob([saveString], {type: 'text/plain'});
|
|
|
|
if (window.navigator.msSaveOrOpenBlob) {// IE10+
|
2017-07-25 16:39:56 +02:00
|
|
|
window.navigator.msSaveOrOpenBlob(file, filename);
|
2017-06-08 06:57:40 +02:00
|
|
|
} else { // Others
|
|
|
|
var a = document.createElement("a"),
|
|
|
|
url = URL.createObjectURL(file);
|
|
|
|
a.href = url;
|
2019-05-14 10:35:37 +02:00
|
|
|
a.download = filename;
|
2017-06-08 06:57:40 +02:00
|
|
|
document.body.appendChild(a);
|
|
|
|
a.click();
|
2019-02-20 09:42:27 +01:00
|
|
|
setTimeoutRef(function() {
|
2017-06-08 06:57:40 +02:00
|
|
|
document.body.removeChild(a);
|
2017-07-25 16:39:56 +02:00
|
|
|
window.URL.revokeObjectURL(url);
|
|
|
|
}, 0);
|
2017-06-08 06:57:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BitburnerSaveObject.prototype.importGame = function() {
|
|
|
|
if (window.File && window.FileReader && window.FileList && window.Blob) {
|
|
|
|
var fileSelector = clearEventListeners("import-game-file-selector");
|
|
|
|
fileSelector.addEventListener("change", openImportFileHandler, false);
|
|
|
|
$("#import-game-file-selector").click();
|
|
|
|
} else {
|
|
|
|
dialogBoxCreate("ERR: Your browser does not support HTML5 File API. Cannot import.");
|
|
|
|
}
|
2017-07-25 16:39:56 +02:00
|
|
|
|
2017-06-08 01:35:56 +02:00
|
|
|
}
|
|
|
|
|
2017-10-12 04:00:22 +02:00
|
|
|
BitburnerSaveObject.prototype.deleteGame = function(db) {
|
2019-04-13 03:22:46 +02:00
|
|
|
// Delete from local storage
|
2017-05-05 03:08:44 +02:00
|
|
|
if (window.localStorage.getItem("bitburnerSave")) {
|
|
|
|
window.localStorage.removeItem("bitburnerSave");
|
|
|
|
}
|
2017-10-12 04:00:22 +02:00
|
|
|
|
2019-04-13 03:22:46 +02:00
|
|
|
// Delete from indexedDB
|
2017-10-12 04:00:22 +02:00
|
|
|
var request = db.transaction(["savestring"], "readwrite").objectStore("savestring").delete("save");
|
|
|
|
request.onsuccess = function(e) {
|
|
|
|
console.log("Successfully deleted save from indexedDb");
|
|
|
|
}
|
|
|
|
request.onerror = function(e) {
|
|
|
|
console.log("Failed to delete save from indexedDb: " + e);
|
|
|
|
}
|
2018-07-19 18:17:43 +02:00
|
|
|
createStatusText("Game deleted!");
|
2017-05-05 03:08:44 +02:00
|
|
|
}
|
|
|
|
|
2017-08-30 19:44:29 +02:00
|
|
|
function createNewUpdateText() {
|
2017-07-25 16:39:56 +02:00
|
|
|
dialogBoxCreate("New update!<br>" +
|
|
|
|
"Please report any bugs/issues through the github repository " +
|
|
|
|
"or the Bitburner subreddit (reddit.com/r/bitburner).<br><br>" +
|
2017-06-07 02:28:20 +02:00
|
|
|
CONSTANTS.LatestUpdate);
|
|
|
|
}
|
|
|
|
|
2018-07-19 04:23:49 +02:00
|
|
|
function createBetaUpdateText() {
|
|
|
|
dialogBoxCreate("You are playing on the beta environment! This branch of the game " +
|
2018-07-20 20:21:43 +02:00
|
|
|
"features the latest developments in the game. This version may be unstable.<br>" +
|
|
|
|
"Please report any bugs/issues through the github repository (https://github.com/danielyxie/bitburner/issues) " +
|
2018-07-19 04:23:49 +02:00
|
|
|
"or the Bitburner subreddit (reddit.com/r/bitburner).<br><br>" +
|
|
|
|
CONSTANTS.LatestUpdate);
|
|
|
|
}
|
|
|
|
|
2017-05-05 03:08:44 +02:00
|
|
|
|
|
|
|
BitburnerSaveObject.prototype.toJSON = function() {
|
|
|
|
return Generic_toJSON("BitburnerSaveObject", this);
|
|
|
|
}
|
|
|
|
|
|
|
|
BitburnerSaveObject.fromJSON = function(value) {
|
|
|
|
return Generic_fromJSON(BitburnerSaveObject, value.data);
|
|
|
|
}
|
|
|
|
|
2017-06-08 06:57:40 +02:00
|
|
|
Reviver.constructors.BitburnerSaveObject = BitburnerSaveObject;
|
|
|
|
|
|
|
|
function openImportFileHandler(evt) {
|
|
|
|
var file = evt.target.files[0];
|
|
|
|
if (!file) {
|
|
|
|
dialogBoxCreate("Invalid file selected");
|
|
|
|
return;
|
|
|
|
}
|
2017-07-25 16:39:56 +02:00
|
|
|
|
2017-06-08 06:57:40 +02:00
|
|
|
var reader = new FileReader();
|
|
|
|
reader.onload = function(e) {
|
|
|
|
var contents = e.target.result;
|
|
|
|
loadImportedGame(saveObject, contents);
|
|
|
|
};
|
|
|
|
reader.readAsText(file);
|
2017-07-25 16:39:56 +02:00
|
|
|
}
|
2017-08-30 19:44:29 +02:00
|
|
|
|
|
|
|
export {saveObject, loadGame};
|