/* SaveObject.js * Defines the object used to save/load games */ var saveObject = new BitburnerSaveObject(); function BitburnerSaveObject() { this.PlayerSave = ""; this.AllServersSave = ""; this.CompaniesSave = ""; this.FactionsSave = ""; this.SpecialServerIpsSave = ""; this.AliasesSave = ""; this.MessagesSave = ""; this.StockMarketSave = ""; this.VersionSave = ""; } BitburnerSaveObject.prototype.saveGame = function() { this.PlayerSave = JSON.stringify(Player); //Delete all logs from all running scripts var TempAllServers = JSON.parse(JSON.stringify(AllServers), Reviver); //var TempAllServers = jQuery.extend(true, {}, AllServers); //Deep copy 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 = []; } } this.AllServersSave = JSON.stringify(TempAllServers); this.CompaniesSave = JSON.stringify(Companies); this.FactionsSave = JSON.stringify(Factions); this.SpecialServerIpsSave = JSON.stringify(SpecialServerIps); this.AliasesSave = JSON.stringify(Aliases); this.MessagesSave = JSON.stringify(Messages); this.StockMarketSave = JSON.stringify(StockMarket); this.VersionSave = JSON.stringify(CONSTANTS.Version); var saveString = btoa(unescape(encodeURIComponent(JSON.stringify(this)))); window.localStorage.setItem("bitburnerSave", saveString); console.log("Game saved!"); Engine.createStatusText("Game saved!"); } loadGame = function(saveObj) { if (!window.localStorage.getItem("bitburnerSave")) { console.log("No save file to load"); return false; } var saveString = decodeURIComponent(escape(atob(window.localStorage.getItem("bitburnerSave")))); saveObj = JSON.parse(saveString, Reviver); Player = JSON.parse(saveObj.PlayerSave, Reviver); AllServers = JSON.parse(saveObj.AllServersSave, Reviver); Companies = JSON.parse(saveObj.CompaniesSave, Reviver); Factions = JSON.parse(saveObj.FactionsSave, Reviver); SpecialServerIps = JSON.parse(saveObj.SpecialServerIpsSave, Reviver); if (saveObj.hasOwnProperty("AliasesSave")) { try { Aliases = JSON.parse(saveObj.AliasesSave, Reviver); } catch(e) { Aliases = {}; } } else { Aliases = {}; } if (saveObj.hasOwnProperty("MessagesSave")) { try { Messages = JSON.parse(saveObj.MessagesSave, Reviver); } catch(e) { initMessages(); } } else { initMessages(); } if (saveObj.hasOwnProperty("StockMarketSave")) { try { StockMarket = JSON.parse(saveObj.StockMarketSave, Reviver); } catch(e) { StockMarket = {}; } } else { StockMarket = {}; } if (saveObj.hasOwnProperty("VersionSave")) { try { var ver = JSON.parse(saveObj.VersionSave, Reviver); if (ver != CONSTANTS.Version) { if (CONSTANTS.Version == "0.21.0" || CONSTANTS.Version == "0.22.0" || CONSTANTS.Version == "0.22.1") { dialogBoxCreate("All scripts automatically killed for the sake of compatibility " + "with new version. If the game is still broken, try the following: " + "Options -> Soft Reset -> Save Game -> Reload page. If that STILL " + "doesn't work contact the dev"); //This is the big update that might break games. Kill all running scripts for (var ip in AllServers) { if (AllServers.hasOwnProperty(ip)) { AllServers[ip].runningScripts = []; AllServers[ip].runningScripts.length = 0; } } } if (CONSTANTS.Version == "0.23.0") { Augmentations = JSON.parse(saveObj.AugmentationsSave, Reviver); } createNewUpdateText(); } } catch(e) { createNewUpdateText(); } } else { createNewUpdateText(); } return true; } loadImportedGame = function(saveObj, saveString) { var tempSaveObj = null; var tempPlayer = null; var tempAllServers = null; var tempCompanies = null; var tempFactions = null; var tempSpecialServerIps = null; var tempAugmentations = null; var tempAliases = null; var tempMessages = null; var tempStockMarket = null; try { saveString = decodeURIComponent(escape(atob(saveString))); tempSaveObj = new BitburnerSaveObject(); tempSaveObj = JSON.parse(saveString, Reviver); tempPlayer = JSON.parse(tempSaveObj.PlayerSave, Reviver); tempAllServers = JSON.parse(tempSaveObj.AllServersSave, Reviver); tempCompanies = JSON.parse(tempSaveObj.CompaniesSave, Reviver); tempFactions = JSON.parse(tempSaveObj.FactionsSave, Reviver); tempSpecialServerIps = JSON.parse(tempSaveObj.SpecialServerIpsSave, Reviver); tempAugmentations = JSON.parse(tempSaveObj.AugmentationsSave, Reviver); if (tempSaveObj.hasOwnProperty("AliasesSave")) { try { tempAliases = JSON.parse(tempSaveObj.AliasesSave, Reviver); } catch(e) { tempAliases = {}; } } else { tempAliases = {}; } if (tempSaveObj.hasOwnProperty("MessagesSave")) { try { tempMessages = JSON.parse(tempSaveObj.MessagesSave, Reviver); } catch(e) { initMessages(); } } else { initMessages(); } if (saveObj.hasOwnProperty("StockMarketSave")) { try { tempStockMarket = JSON.parse(saveObj.StockMarketSave, Reviver); } catch(e) { tempStockMarket = {}; } } else { tempStockMarket = {}; } if (tempSaveObj.hasOwnProperty("VersionSave")) { try { var ver = JSON.parse(tempSaveObj.VersionSave, Reviver); if (ver != CONSTANTS.Version) { createNewUpdateText(); } if (ver != CONSTANTS.Version) { if (CONSTANTS.Version == "0.21.0" || CONSTANTS.Version == "0.22.0" || CONSTANTS.Version == "0.22.1") { console.log("here"); //This is the big update that might break games. Kill all running scripts for (var ip in tempAllServers) { if (tempAllServers.hasOwnProperty(ip)) { tempAllServers[ip].runningScripts = []; tempAllServers[ip].runningScripts.length = 0; } } } if (CONSTANTS.Version == "0.23.0") { tempAugmentations = JSON.parse(saveObj.AugmentationsSave, Reviver); } createNewUpdateText(); } } catch(e) { createNewUpdateText(); } } else { createNewUpdateText(); } } catch(e) { dialogBoxCreate("Error importing game"); return false; } saveObj = tempSaveObj; Player = tempPlayer; AllServers = tempAllServers; Companies = tempCompanies; Factions = tempFactions; SpecialServerIps = tempSpecialServerIps; Augmentations = tempAugmentations; if (tempAliases) { Aliases = tempAliases; } if (tempMessages) { Messages = tempMessages; } if (tempStockMarket) { StockMarket = tempStockMarket; } dialogBoxCreate("Imported game"); gameOptionsBoxClose(); //Re-start game console.log("Importing game"); Engine.setDisplayElements(); //Sets variables for important DOM elements Engine.init(); //Initialize buttons, work, etc. CompanyPositions.init(); //Calculate the number of cycles have elapsed while offline Engine._lastUpdate = new Date().getTime(); var lastUpdate = Player.lastUpdate; var numCyclesOffline = Math.floor((Engine._lastUpdate - lastUpdate) / Engine._idleSpeed); /* Process offline progress */ var offlineProductionFromScripts = loadAllRunningScripts(); //This also takes care of offline production for those scripts 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); } } //Hacknet Nodes offline progress var offlineProductionFromHacknetNodes = processAllHacknetNodeEarnings(numCyclesOffline); //Passive faction rep gain offline processPassiveFactionRepGain(numCyclesOffline); //Update total playtime var time = numCyclesOffline * Engine._idleSpeed; if (Player.totalPlaytime == null) {Player.totalPlaytime = 0;} if (Player.playtimeSinceLastAug == null) {Player.playtimeSinceLastAug = 0;} Player.totalPlaytime += time; Player.playtimeSinceLastAug += time; //Re-apply augmentations Player.reapplyAllAugmentations(); //Clear terminal $("#terminal tr:not(:last)").remove(); Player.lastUpdate = Engine._lastUpdate; Engine.start(); //Run main game loop and Scripts loop dialogBoxCreate("While you were offline, your scripts generated $" + formatNumber(offlineProductionFromScripts, 2) + " and your Hacknet Nodes generated $" + formatNumber(offlineProductionFromHacknetNodes, 2)); return true; } BitburnerSaveObject.prototype.exportGame = function() { this.PlayerSave = JSON.stringify(Player); this.AllServersSave = JSON.stringify(AllServers); this.CompaniesSave = JSON.stringify(Companies); this.FactionsSave = JSON.stringify(Factions); this.SpecialServerIpsSave = JSON.stringify(SpecialServerIps); this.AugmentationsSave = JSON.stringify(Augmentations); this.AliasesSave = JSON.stringify(Aliases); this.MessagesSave = JSON.stringify(Messages); this.VersionSave = JSON.stringify(CONSTANTS.Version); var saveString = btoa(unescape(encodeURIComponent(JSON.stringify(this)))); var file = new Blob([saveString], {type: 'text/plain'}); if (window.navigator.msSaveOrOpenBlob) {// IE10+ window.navigator.msSaveOrOpenBlob(file, filename); } else { // Others var a = document.createElement("a"), url = URL.createObjectURL(file); a.href = url; a.download = "bitburnerSave.json"; document.body.appendChild(a); a.click(); setTimeout(function() { document.body.removeChild(a); window.URL.revokeObjectURL(url); }, 0); } } 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."); } } BitburnerSaveObject.prototype.deleteGame = function() { if (window.localStorage.getItem("bitburnerSave")) { window.localStorage.removeItem("bitburnerSave"); } Engine.createStatusText("Game deleted!"); } createNewUpdateText = function() { dialogBoxCreate("New update!
" + "Please report any bugs/issues through the github repository " + "or the Bitburner subreddit (reddit.com/r/bitburner).

" + CONSTANTS.LatestUpdate); } BitburnerSaveObject.prototype.toJSON = function() { return Generic_toJSON("BitburnerSaveObject", this); } BitburnerSaveObject.fromJSON = function(value) { return Generic_fromJSON(BitburnerSaveObject, value.data); } Reviver.constructors.BitburnerSaveObject = BitburnerSaveObject; //Import game function openImportFileHandler(evt) { var file = evt.target.files[0]; if (!file) { dialogBoxCreate("Invalid file selected"); return; } var reader = new FileReader(); reader.onload = function(e) { var contents = e.target.result; loadImportedGame(saveObject, contents); }; reader.readAsText(file); }