From 840df3087f86c99b05a5e00bcf10e28fe378a4c1 Mon Sep 17 00:00:00 2001 From: danielyxie Date: Fri, 8 Feb 2019 18:46:30 -0800 Subject: [PATCH] Various QOL improvements and bug fixes --- doc/source/basicgameplay/terminal.rst | 45 ++++++++++++++ doc/source/netscript/netscriptfunctions.rst | 20 ++++++ doc/source/netscript/netscriptmisc.rst | 14 ++++- src/ActiveScriptsUI.js | 68 +++++++++++---------- src/Augmentation/Augmentation.ts | 4 ++ src/Constants.ts | 7 ++- src/NetscriptFunctions.js | 46 +++++++++++--- src/NetscriptWorker.js | 7 ++- src/PersonObjects/Resleeving/Resleeve.ts | 2 +- src/Prestige.js | 16 +++-- src/Terminal.js | 39 +++++++++--- src/engine.js | 2 +- utils/StringHelperFunctions.ts | 4 +- utils/helpers/arrayToString.ts | 15 ++++- 14 files changed, 221 insertions(+), 68 deletions(-) diff --git a/doc/source/basicgameplay/terminal.rst b/doc/source/basicgameplay/terminal.rst index 3f4db5583..da1da41c3 100644 --- a/doc/source/basicgameplay/terminal.rst +++ b/doc/source/basicgameplay/terminal.rst @@ -454,3 +454,48 @@ do not allow cross-origin origin sharing (CORS). This includes websites such as gist and pastebin. One notable site it will work on is rawgithub. Example:: $ wget https://raw.githubusercontent.com/danielyxie/bitburner/master/README.md game_readme.txt + +Argument Parsing +---------------- +When evaluating a terminal command, arguments are initially parsed based on whitespace (usually spaces). +Each whitespace character signifies the end of an argument, and potentially the start +of new one. For most terminal commands, this is all you need to know. + +When running scripts, however, it is important to know in more detail how arguments are parsed. +There are two main points: + +1. Quotation marks can be used to wrap a single argument and force it to be parsed as + a string. Any whitespace inside the quotation marks will not cause a new argument + to be parsed. +2. Anything that can represent a number is automatically cast to a number, unless its + surrounded by quotation marks. + +Here's an example to show how these rules work. Consider the following script `argType.script`:: + + tprint("Number of args: " + args.length); + for (var i = 0; i < args.length; ++i) { + tprint(typeof args[i]); + } + +Then if we run the following terminal command:: + + $ run argType.script 123 1e3 "5" "this is a single argument" + +We'll see the following in the Terminal:: + + Running script with 1 thread(s) and args: [123, 1000, "5", "this is a single argument"]. + May take a few seconds to start up the process... + argType.script: Number of args: 4 + argType.script: number + argType.script: number + argType.script: string + argType.script: string + +Chaining Commands +----------------- +You can run multiple Terminal commands at once by separating each command +with a semicolon (;). + +Example:: + + $ run foo.script; tail foo.script diff --git a/doc/source/netscript/netscriptfunctions.rst b/doc/source/netscript/netscriptfunctions.rst index 47574fa14..5eac68ac5 100644 --- a/doc/source/netscript/netscriptfunctions.rst +++ b/doc/source/netscript/netscriptfunctions.rst @@ -1211,6 +1211,26 @@ vsprintf See `this link `_ for details. +nFormat +^^^^^^^ + +.. js:function:: nFormat(n, format) + + :param number n: Number to format + :param string format: Formatter + + Converts a number into a string with the specified formatter. This uses the + `numeraljs `_ library, so the formatters must be compatible + with that. + + This is the same function that the game itself uses to display numbers. + + Examples:: + + nFormat(1.23e9, "$0.000a"); // Returns "$1.230b" + nFormat(12345.678, "0,0"); // Returns "12,346" + nFormat(0.84, "0.0%"); // Returns "84.0% + prompt ^^^^^^ diff --git a/doc/source/netscript/netscriptmisc.rst b/doc/source/netscript/netscriptmisc.rst index d7525c239..877d28c33 100644 --- a/doc/source/netscript/netscriptmisc.rst +++ b/doc/source/netscript/netscriptmisc.rst @@ -209,7 +209,19 @@ to specify a namespace for the import:: //... } -Note that exporting functions is not required. +.. warning:: For those who are experienced with JavaScript, note that the `export` + keyword should **NOT** be used in :ref:`netscript1`, as this will break the script. + It can, however, be used in :ref:`netscriptjs` (but it's not required). + +Importing in NetscriptJS +^^^^^^^^^^^^^^^^^^^^^^^^ +There is a minor annoyance when using the `import` feature in :ref:`netscriptjs`. +If you make a change in a NetscriptJS script, then you have to manually "refresh" all other +scripts that import from that script. + +The easiest way to do this is to simply save and then refresh the game. Alternatively, +you can open up all the scripts that need to be "refreshed" in the script editor +and then simply re-save them. Standard, Built-In JavaScript Objects ------------------------------------- diff --git a/src/ActiveScriptsUI.js b/src/ActiveScriptsUI.js index dcf841088..cb86c0b1a 100644 --- a/src/ActiveScriptsUI.js +++ b/src/ActiveScriptsUI.js @@ -1,21 +1,22 @@ import {workerScripts, - killWorkerScript} from "./NetscriptWorker"; -import {Player} from "./Player"; -import {getServer} from "./Server"; -import {numeralWrapper} from "./ui/numeralFormat"; -import {dialogBoxCreate} from "../utils/DialogBox"; -import {createAccordionElement} from "../utils/uiHelpers/createAccordionElement"; -import {arrayToString} from "../utils/helpers/arrayToString"; -import {createElement} from "../utils/uiHelpers/createElement"; -import {createProgressBarText} from "../utils/helpers/createProgressBarText"; -import {exceptionAlert} from "../utils/helpers/exceptionAlert"; -import {getElementById} from "../utils/uiHelpers/getElementById"; -import {logBoxCreate} from "../utils/LogBox"; -import {formatNumber} from "../utils/StringHelperFunctions"; -import {removeChildrenFromElement} from "../utils/uiHelpers/removeChildrenFromElement"; -import {removeElement} from "../utils/uiHelpers/removeElement"; -import {roundToTwo} from "../utils/helpers/roundToTwo"; -import {Page, routing} from "./ui/navigationTracking"; + killWorkerScript} from "./NetscriptWorker"; +import {Player} from "./Player"; +import {getServer} from "./Server"; +import {numeralWrapper} from "./ui/numeralFormat"; +import {dialogBoxCreate} from "../utils/DialogBox"; +import {createAccordionElement} from "../utils/uiHelpers/createAccordionElement"; +import {arrayToString} from "../utils/helpers/arrayToString"; +import {createElement} from "../utils/uiHelpers/createElement"; +import {createProgressBarText} from "../utils/helpers/createProgressBarText"; +import {exceptionAlert} from "../utils/helpers/exceptionAlert"; +import {getElementById} from "../utils/uiHelpers/getElementById"; +import {logBoxCreate} from "../utils/LogBox"; +import {formatNumber, + convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions"; +import {removeChildrenFromElement} from "../utils/uiHelpers/removeChildrenFromElement"; +import {removeElement} from "../utils/uiHelpers/removeElement"; +import {roundToTwo} from "../utils/helpers/roundToTwo"; +import {Page, routing} from "./ui/navigationTracking"; /* { * serverName: { @@ -242,9 +243,9 @@ function updateActiveScriptsItems(maxTasks=150) { } } - getElementById("active-scripts-total-production-active").innerText = numeralWrapper.format(total, '$0.000a'); - getElementById("active-scripts-total-prod-aug-total").innerText = numeralWrapper.format(Player.scriptProdSinceLastAug, '$0.000a'); - getElementById("active-scripts-total-prod-aug-avg").innerText = numeralWrapper.format(Player.scriptProdSinceLastAug / (Player.playtimeSinceLastAug/1000), '$0.000a'); + getElementById("active-scripts-total-production-active").innerText = numeralWrapper.formatMoney(total); + getElementById("active-scripts-total-prod-aug-total").innerText = numeralWrapper.formatMoney(Player.scriptProdSinceLastAug); + getElementById("active-scripts-total-prod-aug-avg").innerText = numeralWrapper.formatMoney(Player.scriptProdSinceLastAug / (Player.playtimeSinceLastAug/1000)); return total; } @@ -252,7 +253,7 @@ function updateActiveScriptsItems(maxTasks=150) { function updateActiveScriptsItemContent(workerscript) { var server = getServer(workerscript.serverIp); if (server == null) { - console.log("ERROR: Invalid server IP for workerscript."); + console.log("ERROR: Invalid server IP for workerscript in updateActiveScriptsItemContent()."); return; } let hostname = server.hostname; @@ -280,7 +281,7 @@ function updateActiveScriptsItemContent(workerscript) { function updateActiveScriptsText(workerscript, item, itemName) { var server = getServer(workerscript.serverIp); if (server == null) { - console.log("ERROR: Invalid server IP for workerscript."); + console.log("ERROR: Invalid server IP for workerscript for updateActiveScriptsText()"); return; } let hostname = server.hostname; @@ -298,24 +299,27 @@ function updateActiveScriptsText(workerscript, item, itemName) { removeChildrenFromElement(item); - //Online - var onlineTotalMoneyMade = "Total online production: $" + formatNumber(workerscript.scriptRef.onlineMoneyMade, 2); - var onlineTotalExpEarned = (Array(26).join(" ") + formatNumber(workerscript.scriptRef.onlineExpGained, 2) + " hacking exp").replace( / /g, " "); + var onlineTime = "Online Time: " + convertTimeMsToTimeElapsedString(workerscript.scriptRef.onlineRunningTime * 1e3); + var offlineTime = "Offline Time: " + convertTimeMsToTimeElapsedString(workerscript.scriptRef.offlineRunningTime * 1e3); - var onlineMpsText = "Online production rate: $" + formatNumber(onlineMps, 2) + "/second"; + //Online + var onlineTotalMoneyMade = "Total online production: " + numeralWrapper.formatMoney(workerscript.scriptRef.onlineMoneyMade); + var onlineTotalExpEarned = (Array(26).join(" ") + numeralWrapper.formatBigNumber(workerscript.scriptRef.onlineExpGained) + " hacking exp").replace( / /g, " "); + + var onlineMpsText = "Online production rate: " + numeralWrapper.formatMoney(onlineMps) + " / second"; var onlineEps = workerscript.scriptRef.onlineExpGained / workerscript.scriptRef.onlineRunningTime; - var onlineEpsText = (Array(25).join(" ") + formatNumber(onlineEps, 4) + " hacking exp/second").replace( / /g, " "); + var onlineEpsText = (Array(25).join(" ") + numeralWrapper.formatBigNumber(onlineEps) + " hacking exp / second").replace( / /g, " "); //Offline - var offlineTotalMoneyMade = "Total offline production: $" + formatNumber(workerscript.scriptRef.offlineMoneyMade, 2); - var offlineTotalExpEarned = (Array(27).join(" ") + formatNumber(workerscript.scriptRef.offlineExpGained, 2) + " hacking exp").replace( / /g, " "); + var offlineTotalMoneyMade = "Total offline production: " + numeralWrapper.formatMoney(workerscript.scriptRef.offlineMoneyMade); + var offlineTotalExpEarned = (Array(27).join(" ") + numeralWrapper.formatBigNumber(workerscript.scriptRef.offlineExpGained) + " hacking exp").replace( / /g, " "); var offlineMps = workerscript.scriptRef.offlineMoneyMade / workerscript.scriptRef.offlineRunningTime; - var offlineMpsText = "Offline production rate: $" + formatNumber(offlineMps, 2) + "/second"; + var offlineMpsText = "Offline production rate: " + numeralWrapper.formatMoney(offlineMps) + " / second"; var offlineEps = workerscript.scriptRef.offlineExpGained / workerscript.scriptRef.offlineRunningTime; - var offlineEpsText = (Array(26).join(" ") + formatNumber(offlineEps, 4) + " hacking exp/second").replace( / /g, " "); + var offlineEpsText = (Array(26).join(" ") + numeralWrapper.formatBigNumber(offlineEps) + " hacking exp / second").replace( / /g, " "); - item.innerHTML = onlineTotalMoneyMade + "
" + onlineTotalExpEarned + "
" + + item.innerHTML = onlineTime + "
" + offlineTime + "
" + onlineTotalMoneyMade + "
" + onlineTotalExpEarned + "
" + onlineMpsText + "
" + onlineEpsText + "
" + offlineTotalMoneyMade + "
" + offlineTotalExpEarned + "
" + offlineMpsText + "
" + offlineEpsText + "
"; return onlineMps; diff --git a/src/Augmentation/Augmentation.ts b/src/Augmentation/Augmentation.ts index 019467af4..b57b48703 100644 --- a/src/Augmentation/Augmentation.ts +++ b/src/Augmentation/Augmentation.ts @@ -78,6 +78,9 @@ export class Augmentation { // The Player/Person classes mults: IMap = {} + // Initial cost. Doesn't change when you purchase multiple Augmentation + startingCost: number = 0; + constructor(params: IConstructorParams={ info: "", moneyCost: 0, name: "", repCost: 0 }) { this.name = params.name; this.info = params.info; @@ -85,6 +88,7 @@ export class Augmentation { this.baseRepRequirement = params.repCost * CONSTANTS.AugmentationRepMultiplier * BitNodeMultipliers.AugmentationRepCost; this.baseCost = params.moneyCost * CONSTANTS.AugmentationCostMultiplier * BitNodeMultipliers.AugmentationMoneyCost; + this.startingCost = this.baseCost; this.level = 0; diff --git a/src/Constants.ts b/src/Constants.ts index 3207785de..16289feac 100644 --- a/src/Constants.ts +++ b/src/Constants.ts @@ -512,17 +512,22 @@ export let CONSTANTS: IMap = { ` v0.43.1 * Terminal changes: - ** Quoted arguments are now properly parsed. (e.g. run f.script "this is one argument" will be correctly parsed) + ** Quoted arguments are now properly parsed. (e.g. 'run f.script "this is one argument"' will be correctly parsed) ** Errors are now shown in red text ** 'unalias' command now has a different format and no longer needs the quotations + ** Bug Fix: Fixed several edge cases where autocomplete wasnt working properly * Added two new Bladeburner skills for increasing money and experience gain * Made some minor adjustments to Bladeburner UI * Corporation "Smart Factories" and "Smart Storage" upgrades have slightly lower price multipliers + * Added nFormat Netscript function * Added 6 new Coding Contract problems * Updated documentation with list of all Coding Contract problems + * Minor improvements for 'Active Scripts' UI * Implemented several optimizations for active scripts. The game should now use less memory and the savefile should be slightly smaller when there are many scripts running * Bug Fix: A Stock Forecast should no longer go above 1 (i.e. 100%) + * Bug Fix: The cost of Resleeves should no longer be affected by buying Augs + * Bug Fix: You can now call the prompt() Netscript function from multiple scripts simultaneously ` } diff --git a/src/NetscriptFunctions.js b/src/NetscriptFunctions.js index 708e9d0bc..bc9c9b167 100644 --- a/src/NetscriptFunctions.js +++ b/src/NetscriptFunctions.js @@ -51,6 +51,7 @@ import {StockMarket, StockSymbols, SymbolToStockMap, sellStock, updateStockPlayerPosition, shortStock, sellShort, OrderTypes, PositionTypes, placeOrder, cancelOrder} from "./StockMarket/StockMarket"; +import {numeralWrapper} from "./ui/numeralFormat"; import {post} from "./ui/postToTerminal"; import {TextFile, getTextFile, createTextFile} from "./TextFile"; @@ -76,6 +77,10 @@ import {yesNoBoxClose, yesNoBoxGetYesButton, yesNoBoxGetNoButton, yesNoBoxCreate, yesNoBoxOpen} from "../utils/YesNoBox"; +import { createElement } from "../utils/uiHelpers/createElement"; +import { createPopup } from "../utils/uiHelpers/createPopup"; +import { removeElementById } from "../utils/uiHelpers/removeElementById"; + var hasCorporationSF = false, //Source-File 3 hasSingularitySF = false, //Source-File 4 hasAISF = false, //Source-File 5 @@ -2453,6 +2458,14 @@ function NetscriptFunctions(workerScript) { return runningScriptObj.onlineExpGained / runningScriptObj.onlineRunningTime; } }, + nFormat : function(n, format) { + if (workerScript.checkingRam) { return 0; } + if (isNaN(n) || isNaN(parseFloat(n)) || typeof format !== "string") { + return ""; + } + + return numeralWrapper.format(parseFloat(n), format); + }, getTimeSinceLastAug : function() { if (workerScript.checkingRam) { return updateStaticRam("getTimeSinceLastAug", CONSTANTS.ScriptGetHackTimeRamCost); @@ -2467,19 +2480,32 @@ function NetscriptFunctions(workerScript) { return false; } if (!isString(txt)) {txt = String(txt);} - var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton(); - yesBtn.innerHTML = "Yes"; - noBtn.innerHTML = "No"; + + // The id for this popup will consist of the first 20 characters of the prompt string.. + // Thats hopefully good enough to be unique + const popupId = `prompt-popup-${txt.slice(0, 20)}`; + const textElement = createElement("p", { innerHTML: txt }); + return new Promise(function(resolve, reject) { - yesBtn.addEventListener("click", ()=>{ - yesNoBoxClose(); - resolve(true); + const yesBtn = createElement("button", { + class: "popup-box-button", + innerText: "Yes", + clickListener: () => { + removeElementById(popupId); + resolve(true); + }, }); - noBtn.addEventListener("click", ()=>{ - yesNoBoxClose(); - resolve(false); + + const noBtn = createElement("button", { + class: "popup-box-button", + innerText: "No", + clickListener: () => { + removeElementById(popupId); + resolve(false); + }, }); - yesNoBoxCreate(txt); + + createPopup(popupId, [textElement, yesBtn, noBtn]); }); }, wget : async function(url, target, ip=workerScript.serverIp) { diff --git a/src/NetscriptWorker.js b/src/NetscriptWorker.js index 1d38eb5c3..4bc3377d4 100644 --- a/src/NetscriptWorker.js +++ b/src/NetscriptWorker.js @@ -219,6 +219,8 @@ function startNetscript1Script(workerScript) { let fnPromise = entry.apply(null, fnArgs); fnPromise.then(function(res) { cb(res); + }).catch(function(e) { + // Do nothing? }); } int.setProperty(scope, name, int.createAsyncFunction(tempWrapper)); @@ -278,7 +280,7 @@ function startNetscript1Script(workerScript) { return new Promise(function(resolve, reject) { function runInterpreter() { try { - if (workerScript.env.stopFlag) {return reject(workerScript);} + if (workerScript.env.stopFlag) { return reject(workerScript); } if (interpreter.step()) { window.setTimeout(runInterpreter, Settings.CodeInstructionRunTime); @@ -498,7 +500,7 @@ function runScriptsLoop() { p = startNetscript2Script(workerScripts[i]); } else { p = startNetscript1Script(workerScripts[i]); - if (!(p instanceof Promise)) {continue;} + if (!(p instanceof Promise)) { continue; } } //Once the code finishes (either resolved or rejected, doesnt matter), set its @@ -539,7 +541,6 @@ function runScriptsLoop() { } w.running = false; w.env.stopFlag = true; - } else if (isScriptErrorMessage(w)) { dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer"); console.log("ERROR: Evaluating workerscript returns only error message rather than WorkerScript object. THIS SHOULDN'T HAPPEN: " + w.toString()); diff --git a/src/PersonObjects/Resleeving/Resleeve.ts b/src/PersonObjects/Resleeving/Resleeve.ts index f2092208e..0cd330ad0 100644 --- a/src/PersonObjects/Resleeving/Resleeve.ts +++ b/src/PersonObjects/Resleeving/Resleeve.ts @@ -44,7 +44,7 @@ export class Resleeve extends Person { console.error(`Could not find Augmentation ${this.augmentations[i].name}`); continue; } - totalAugmentationCost += aug!.baseCost; + totalAugmentationCost += aug!.startingCost; } return (totalExp * CostPerExp) + (totalAugmentationCost * Math.pow(NumAugsExponent, this.augmentations.length)); diff --git a/src/Prestige.js b/src/Prestige.js index 0c81225ab..a71e322a7 100755 --- a/src/Prestige.js +++ b/src/Prestige.js @@ -34,6 +34,9 @@ import {initStockMarket, initSymbolToStockMap, stockMarketContentCreated, setStockMarketContentCreated} from "./StockMarket/StockMarket"; import {Terminal, postNetburnerText} from "./Terminal"; + +import {Page, routing} from "./ui/navigationTracking"; + import Decimal from "decimal.js"; import {dialogBoxCreate} from "../utils/DialogBox"; import {removeElementById} from "../utils/uiHelpers/removeElementById"; @@ -45,6 +48,13 @@ let BitNode8StartingMoney = 250e6; //Prestige by purchasing augmentation function prestigeAugmentation() { + // Load Terminal Screen + var mainMenu = document.getElementById("mainmenu-container"); + mainMenu.style.visibility = "visible"; + Terminal.resetTerminalInput(); + Engine.loadTerminalContent(); + routing.navigateTo(Page.Terminal); + initBitNodeMultipliers(); Player.prestigeAugmentation(); @@ -146,12 +156,6 @@ function prestigeAugmentation() { var watchlist = document.getElementById("stock-market-watchlist-filter"); watchlist.value = ""; //Reset watchlist filter - //Load Terminal Screen - var mainMenu = document.getElementById("mainmenu-container"); - mainMenu.style.visibility = "visible"; - Terminal.resetTerminalInput(); - Engine.loadTerminalContent(); - // Refresh Main Menu (the 'World' menu, specifically) document.getElementById("world-menu-header").click(); document.getElementById("world-menu-header").click(); diff --git a/src/Terminal.js b/src/Terminal.js index 55f62f13d..aea383f2d 100644 --- a/src/Terminal.js +++ b/src/Terminal.js @@ -165,7 +165,7 @@ $(document).keydown(function(event) { const semiColonIndex = input.lastIndexOf(";"); if(semiColonIndex !== -1) { - input = input.slice(semiColonIndex+1); + input = input.slice(semiColonIndex + 1); } input = input.trim(); @@ -310,6 +310,14 @@ function tabCompletion(command, arg, allPossibilities, index=0) { } } + const textBox = document.getElementById("terminal-input-text-box"); + if (textBox == null) { + console.warn(`Couldn't find terminal input DOM element (id=terminal-input-text-box) when trying to autocomplete`); + return; + } + const oldValue = textBox.value; + const semiColonIndex = oldValue.lastIndexOf(";"); + var val = ""; if (allPossibilities.length == 0) { return; @@ -321,10 +329,7 @@ function tabCompletion(command, arg, allPossibilities, index=0) { val = command + " " + allPossibilities[0]; } - const textBox = document.getElementById("terminal-input-text-box"); - const oldValue = textBox.value; - const semiColonIndex = oldValue.lastIndexOf(";"); - if(semiColonIndex === -1) { + if (semiColonIndex === -1) { // no ; replace the whole thing. textBox.value = val; } else { @@ -332,7 +337,7 @@ function tabCompletion(command, arg, allPossibilities, index=0) { textBox.value = textBox.value.slice(0, semiColonIndex+1)+" "+val; } - document.getElementById("terminal-input-text-box").focus(); + textBox.focus(); } else { var longestStartSubstr = longestCommonStart(allPossibilities); //If the longest common starting substring of remaining possibilities is the same @@ -348,8 +353,15 @@ function tabCompletion(command, arg, allPossibilities, index=0) { post("> " + command); post(allOptionsStr); } else { - document.getElementById("terminal-input-text-box").value = longestStartSubstr; - document.getElementById("terminal-input-text-box").focus(); + if (semiColonIndex === -1) { + // No ; just replace the whole thing + textBox.value = longestStartSubstr; + } else { + // Multiple commands, so only replace after the last semicolon + textBox.value = textBox.value.slice(0, semiColonIndex + 1) + " " + longestStartSubstr; + } + + textBox.focus(); } } else { if (longestStartSubstr == arg) { @@ -357,8 +369,15 @@ function tabCompletion(command, arg, allPossibilities, index=0) { post("> " + command + " " + arg); post(allOptionsStr); } else { - document.getElementById("terminal-input-text-box").value = command + " " + longestStartSubstr; - document.getElementById("terminal-input-text-box").focus(); + if (semiColonIndex == -1) { + // No ; so just replace the whole thing + textBox.value = command + " " + longestStartSubstr; + } else { + // Multiple commands, so only replace after the last semiclon + textBox.value = textBox.value.slice(0, semiColonIndex + 1) + " " + command + " " + longestStartSubstr; + } + + textBox.focus(); } } diff --git a/src/engine.js b/src/engine.js index 67640ad2a..1e2e06d77 100644 --- a/src/engine.js +++ b/src/engine.js @@ -1032,7 +1032,6 @@ const Engine = { //is necessary and then resets the counter checkCounters: function() { if (Engine.Counters.autoSaveCounter <= 0) { - saveObject.saveGame(indexedDb); if (Settings.AutosaveInterval == null) { Settings.AutosaveInterval = 60; } @@ -1040,6 +1039,7 @@ const Engine = { Engine.Counters.autoSaveCounter = Infinity; } else { Engine.Counters.autoSaveCounter = Settings.AutosaveInterval * 5; + saveObject.saveGame(indexedDb); } } diff --git a/utils/StringHelperFunctions.ts b/utils/StringHelperFunctions.ts index c9fbb1c5c..9fc02133c 100644 --- a/utils/StringHelperFunctions.ts +++ b/utils/StringHelperFunctions.ts @@ -10,8 +10,8 @@ function replaceAt(base: string, index: number, character: string): string { /* Converts a date representing time in milliseconds to a string with the format H hours M minutes and S seconds -e.g. 10000 -> "0 hours 0 minutes and 10 seconds" - 120000 -> "0 0 hours 2 minutes and 0 seconds" +e.g. 10000 -> "10 seconds" + 120000 -> "2 minutes and 0 seconds" */ function convertTimeMsToTimeElapsedString(time: number): string { const millisecondsPerSecond: number = 1000; diff --git a/utils/helpers/arrayToString.ts b/utils/helpers/arrayToString.ts index 91db38ce4..f6645bf74 100644 --- a/utils/helpers/arrayToString.ts +++ b/utils/helpers/arrayToString.ts @@ -1,6 +1,19 @@ /** * Returns the input array as a comma separated string. + * + * Does several things that Array.toString() doesn't do + * - Adds brackets around the array + * - Adds quotation marks around strings */ export function arrayToString(a: T[]) { - return `[${a.join(", ")}]`; + const vals: any[] = []; + for (let i = 0; i < a.length; ++i) { + let elem: any = a[i]; + if (typeof elem === "string") { + elem = `"${elem}"`; + } + vals.push(elem); + } + + return `[${vals.join(", ")}]`; }