mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-19 12:45:45 +01:00
commit
1d0515a957
2
dist/engine.bundle.js
vendored
2
dist/engine.bundle.js
vendored
File diff suppressed because one or more lines are too long
80
dist/vendor.bundle.js
vendored
80
dist/vendor.bundle.js
vendored
File diff suppressed because one or more lines are too long
@ -29,7 +29,7 @@ List of all Source-Files
|
|||||||
| | * Each level of this Source-File opens up more of the Singularity Functions to use |
|
| | * Each level of this Source-File opens up more of the Singularity Functions to use |
|
||||||
+------------------------------------+-------------------------------------------------------------------------------------+
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
| BitNode-5: Artificial Intelligence | * Unlocks :ref:`gameplay_intelligence` |
|
| BitNode-5: Artificial Intelligence | * Unlocks :ref:`gameplay_intelligence` |
|
||||||
| | * Unlocks getBitNodeMultipliers() Netscript function |
|
| | * Unlocks :js:func:`getBitNodeMultipliers` Netscript function |
|
||||||
| | * Increases all of the player's hacking-related multipliers by 8%/12%/14% |
|
| | * Increases all of the player's hacking-related multipliers by 8%/12%/14% |
|
||||||
+------------------------------------+-------------------------------------------------------------------------------------+
|
+------------------------------------+-------------------------------------------------------------------------------------+
|
||||||
| BitNode-6: Bladeburners | * Unlocks the Bladeburner feature in other BitNodes |
|
| BitNode-6: Bladeburners | * Unlocks the Bladeburner feature in other BitNodes |
|
||||||
|
@ -76,3 +76,135 @@ Notes
|
|||||||
^^^^^
|
^^^^^
|
||||||
|
|
||||||
* The *scp* Terminal command does not work on Coding Contracts
|
* The *scp* Terminal command does not work on Coding Contracts
|
||||||
|
|
||||||
|
List of all Problem Types
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
The following is a list of all of the problem types that a Coding Contract can contain.
|
||||||
|
The list contains the name of (i.e. the value returned by
|
||||||
|
:js:func:`getContractType`) and a brief summary of the problem it poses.
|
||||||
|
|
||||||
|
+------------------------------------+------------------------------------------------------------------------------------------+
|
||||||
|
| Name | Problem Summary |
|
||||||
|
+====================================+==========================================================================================+
|
||||||
|
| Find Largest Prime Factor | | Given a number, find its largest prime factor. A prime factor |
|
||||||
|
| | | is a factor that is a prime number. |
|
||||||
|
+------------------------------------+------------------------------------------------------------------------------------------+
|
||||||
|
| Subarray with Maximum Sum | | Given an array of integers, find the contiguous subarray (containing |
|
||||||
|
| | | at least one number) which has the largest sum and return that sum. |
|
||||||
|
+------------------------------------+------------------------------------------------------------------------------------------+
|
||||||
|
| Total Ways to Sum | | Given a number, how many different ways can that number be written as |
|
||||||
|
| | | a sum of at least two positive integers? |
|
||||||
|
+------------------------------------+------------------------------------------------------------------------------------------+
|
||||||
|
| Spiralize Matrix | | Given an array of array of numbers representing a 2D matrix, return the |
|
||||||
|
| | | elements of that matrix in clockwise spiral order. |
|
||||||
|
| | | |
|
||||||
|
| | | Example: The spiral order of |
|
||||||
|
| | | |
|
||||||
|
| | | [1, 2, 3, 4] |
|
||||||
|
| | | [5, 6, 7, 8] |
|
||||||
|
| | | [9, 10, 11, 12] |
|
||||||
|
| | | |
|
||||||
|
| | | is [1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7] |
|
||||||
|
+------------------------------------+------------------------------------------------------------------------------------------+
|
||||||
|
| Array Jumping Game | | You are given an array of integers where each element represents the |
|
||||||
|
| | | maximum possible jump distance from that position. For example, if you |
|
||||||
|
| | | are at position i and your maximum jump length is n, then you can jump |
|
||||||
|
| | | to any position from i to i+n. |
|
||||||
|
| | | |
|
||||||
|
| | | Assuming you are initially positioned at the start of the array, determine |
|
||||||
|
| | | whether you are able to reach the last index of the array EXACTLY. |
|
||||||
|
+------------------------------------+------------------------------------------------------------------------------------------+
|
||||||
|
| Merge Overlapping Intervals | | Given an array of intervals, merge all overlapping intervals. An interval |
|
||||||
|
| | | is an array with two numbers, where the first number is always less than |
|
||||||
|
| | | the second (e.g. [1, 5]). |
|
||||||
|
| | | |
|
||||||
|
| | | The intervals must be returned in ASCENDING order. |
|
||||||
|
| | | |
|
||||||
|
| | | Example: |
|
||||||
|
| | | [[1, 3], [8, 10], [2, 6], [10, 16]] |
|
||||||
|
| | | merges into [[1, 6], [8, 16]] |
|
||||||
|
+------------------------------------+------------------------------------------------------------------------------------------+
|
||||||
|
| Generate IP Addresses | | Given a string containing only digits, return an array with all possible |
|
||||||
|
| | | valid IP address combinations that can be created from the string. |
|
||||||
|
| | | |
|
||||||
|
| | | An octet in the IP address cannot begin with '0' unless the number itself |
|
||||||
|
| | | is actually 0. For example, "192.168.010.1" is NOT a valid IP. |
|
||||||
|
| | | |
|
||||||
|
| | | Examples: |
|
||||||
|
| | | 25525511135 -> [255.255.11.135, 255.255.111.35] |
|
||||||
|
| | | 1938718066 -> [193.87.180.66] |
|
||||||
|
+------------------------------------+------------------------------------------------------------------------------------------+
|
||||||
|
| Algorithmic Stock Trader I | | You are given an array of numbers representing stock prices, where the |
|
||||||
|
| | | i-th element represents the stock price on day i. |
|
||||||
|
| | | |
|
||||||
|
| | | Determine the maximum possible profit you can earn using at most one |
|
||||||
|
| | | transaction (i.e. you can buy an sell the stock once). If no profit |
|
||||||
|
| | | can be made, then the answer should be 0. Note that you must buy the stock |
|
||||||
|
| | | before you can sell it. |
|
||||||
|
+------------------------------------+------------------------------------------------------------------------------------------+
|
||||||
|
| Algorithmic Stock Trader II | | You are given an array of numbers representing stock prices, where the |
|
||||||
|
| | | i-th element represents the stock price on day i. |
|
||||||
|
| | | |
|
||||||
|
| | | Determine the maximum possible profit you can earn using as many transactions |
|
||||||
|
| | | as you'd like. A transaction is defined as buying and then selling one |
|
||||||
|
| | | share of the stock. Note that you cannot engage in multiple transactions at |
|
||||||
|
| | | once. In other words, you must sell the stock before you buy it again. If no |
|
||||||
|
| | | profit can be made, then the answer should be 0. |
|
||||||
|
+------------------------------------+------------------------------------------------------------------------------------------+
|
||||||
|
| Algorithmic Stock Trader III | | You are given an array of numbers representing stock prices, where the |
|
||||||
|
| | | i-th element represents the stock price on day i. |
|
||||||
|
| | | |
|
||||||
|
| | | Determine the maximum possible profit you can earn using at most two |
|
||||||
|
| | | transactions. A transaction is defined as buying and then selling one share |
|
||||||
|
| | | of the stock. Note that you cannot engage in multiple transactions at once. |
|
||||||
|
| | | In other words, you must sell the stock before you buy it again. If no profit |
|
||||||
|
| | | can be made, then the answer should be 0. |
|
||||||
|
+------------------------------------+------------------------------------------------------------------------------------------+
|
||||||
|
| Algorithmic Stock Trader IV | | You are given an array with two elements. The first element is an integer k. |
|
||||||
|
| | | The second element is an array of numbers representing stock prices, where the |
|
||||||
|
| | | i-th element represents the stock price on day i. |
|
||||||
|
| | | |
|
||||||
|
| | | Determine the maximum possible profit you can earn using at most k transactions. |
|
||||||
|
| | | A transaction is defined as buying and then selling one share of the stock. |
|
||||||
|
| | | Note that you cannot engage in multiple transactions at once. In other words, |
|
||||||
|
| | | you must sell the stock before you can buy it. If no profit can be made, then |
|
||||||
|
| | | the answer should be 0. |
|
||||||
|
+------------------------------------+------------------------------------------------------------------------------------------+
|
||||||
|
| Minimum Path Sum in a Triangle | | You are given a 2D array of numbers (array of array of numbers) that represents a |
|
||||||
|
| | | triangle (the first array has one element, and each array has one more element than |
|
||||||
|
| | | the one before it, forming a triangle). Find the minimum path sum from the top to the |
|
||||||
|
| | | bottom of the triangle. In each step of the path, you may only move to adjacent |
|
||||||
|
| | | numbers in the row below. |
|
||||||
|
+------------------------------------+------------------------------------------------------------------------------------------+
|
||||||
|
| Unique Paths in a Grid I | | You are given an array with two numbers: [m, n]. These numbers represent a |
|
||||||
|
| | | m x n grid. Assume you are initially positioned in the top-left corner of that |
|
||||||
|
| | | grid and that you are trying to reach the bottom-right corner. On each step, |
|
||||||
|
| | | you may only move down or to the right. |
|
||||||
|
| | | |
|
||||||
|
| | |
|
||||||
|
| | | Determine how many unique paths there are from start to finish. |
|
||||||
|
+------------------------------------+------------------------------------------------------------------------------------------+
|
||||||
|
| Unique Paths in a Grid II | | You are given a 2D array of numbers (array of array of numbers) representing |
|
||||||
|
| | | a grid. The 2D array contains 1's and 0's, where 1 represents an obstacle and |
|
||||||
|
| | |
|
||||||
|
| | | 0 represents a free space. |
|
||||||
|
| | | |
|
||||||
|
| | | Assume you are initially positioned in top-left corner of that grid and that you |
|
||||||
|
| | | are trying to reach the bottom-right corner. In each step, you may only move down |
|
||||||
|
| | | or to the right. Furthermore, you cannot move onto spaces which have obstacles. |
|
||||||
|
| | | |
|
||||||
|
| | | Determine how many unique paths there are from start to finish. |
|
||||||
|
+------------------------------------+------------------------------------------------------------------------------------------+
|
||||||
|
| Sanitize Parentheses in Expression | | Given a string with parentheses and letters, remove the minimum number of invalid |
|
||||||
|
| | | parentheses in order to validate the string. If there are multiple minimal ways |
|
||||||
|
| | | to validate the string, provide all of the possible results. |
|
||||||
|
| | | |
|
||||||
|
| | | The answer should be provided as an array of strings. If it is impossible to validate |
|
||||||
|
| | | the string, the result should be an array with only an empty string. |
|
||||||
|
| | | |
|
||||||
|
| | | Examples: |
|
||||||
|
| | | ()())() -> ["()()()", "(())()"] |
|
||||||
|
| | | (a)())() -> ["(a)()()", "(a())()"] |
|
||||||
|
| | | )( -> [""] |
|
||||||
|
+------------------------------------+------------------------------------------------------------------------------------------+
|
||||||
|
@ -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::
|
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
|
$ 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
|
||||||
|
@ -3,6 +3,28 @@
|
|||||||
Changelog
|
Changelog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
v0.43.1 - 2/11/2019
|
||||||
|
-------------------
|
||||||
|
* Terminal changes:
|
||||||
|
* 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 wasn't 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: Duplicate Sleeves now use their own stats to determine crime success rate, instead of the host consciousness' stats
|
||||||
|
* Bug Fix: You can now call the prompt() Netscript function from multiple scripts simultaneously
|
||||||
|
|
||||||
|
|
||||||
v0.43.0 - 2/4/2019
|
v0.43.0 - 2/4/2019
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
@ -1211,6 +1211,26 @@ vsprintf
|
|||||||
|
|
||||||
See `this link <https://github.com/alexei/sprintf.js>`_ for details.
|
See `this link <https://github.com/alexei/sprintf.js>`_ 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 <http://numeraljs.com/>`_ 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
|
prompt
|
||||||
^^^^^^
|
^^^^^^
|
||||||
|
|
||||||
|
@ -312,6 +312,9 @@ getStockForecast
|
|||||||
that the stock's price has a 30% chance of increasing and a 70% chance of
|
that the stock's price has a 30% chance of increasing and a 70% chance of
|
||||||
decreasing during the next tick.
|
decreasing during the next tick.
|
||||||
|
|
||||||
|
In order to use this function, you must first purchase access to the Four Sigma (4S)
|
||||||
|
Market Data TIX API.
|
||||||
|
|
||||||
purchase4SMarketData
|
purchase4SMarketData
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
@ -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
|
Standard, Built-In JavaScript Objects
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
"ajv-keywords": "^2.0.0",
|
"ajv-keywords": "^2.0.0",
|
||||||
"async": "^2.6.1",
|
"async": "^2.6.1",
|
||||||
"autosize": "^4.0.2",
|
"autosize": "^4.0.2",
|
||||||
"bluebird": "^3.5.1",
|
|
||||||
"brace": "^0.11.1",
|
"brace": "^0.11.1",
|
||||||
"codemirror": "^5.43.0",
|
"codemirror": "^5.43.0",
|
||||||
"decimal.js": "7.2.3",
|
"decimal.js": "7.2.3",
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
import {workerScripts,
|
import {workerScripts,
|
||||||
killWorkerScript} from "./NetscriptWorker";
|
killWorkerScript} from "./NetscriptWorker";
|
||||||
import {Player} from "./Player";
|
import {Player} from "./Player";
|
||||||
import {getServer} from "./Server";
|
import {getServer} from "./Server";
|
||||||
import {numeralWrapper} from "./ui/numeralFormat";
|
import {numeralWrapper} from "./ui/numeralFormat";
|
||||||
import {dialogBoxCreate} from "../utils/DialogBox";
|
import {dialogBoxCreate} from "../utils/DialogBox";
|
||||||
import {createAccordionElement} from "../utils/uiHelpers/createAccordionElement";
|
import {createAccordionElement} from "../utils/uiHelpers/createAccordionElement";
|
||||||
import {arrayToString} from "../utils/helpers/arrayToString";
|
import {arrayToString} from "../utils/helpers/arrayToString";
|
||||||
import {createElement} from "../utils/uiHelpers/createElement";
|
import {createElement} from "../utils/uiHelpers/createElement";
|
||||||
import {createProgressBarText} from "../utils/helpers/createProgressBarText";
|
import {createProgressBarText} from "../utils/helpers/createProgressBarText";
|
||||||
import {exceptionAlert} from "../utils/helpers/exceptionAlert";
|
import {exceptionAlert} from "../utils/helpers/exceptionAlert";
|
||||||
import {getElementById} from "../utils/uiHelpers/getElementById";
|
import {getElementById} from "../utils/uiHelpers/getElementById";
|
||||||
import {logBoxCreate} from "../utils/LogBox";
|
import {logBoxCreate} from "../utils/LogBox";
|
||||||
import {formatNumber} from "../utils/StringHelperFunctions";
|
import {formatNumber,
|
||||||
import {removeChildrenFromElement} from "../utils/uiHelpers/removeChildrenFromElement";
|
convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
|
||||||
import {removeElement} from "../utils/uiHelpers/removeElement";
|
import {removeChildrenFromElement} from "../utils/uiHelpers/removeChildrenFromElement";
|
||||||
import {roundToTwo} from "../utils/helpers/roundToTwo";
|
import {removeElement} from "../utils/uiHelpers/removeElement";
|
||||||
import {Page, routing} from "./ui/navigationTracking";
|
import {roundToTwo} from "../utils/helpers/roundToTwo";
|
||||||
|
import {Page, routing} from "./ui/navigationTracking";
|
||||||
|
|
||||||
/* {
|
/* {
|
||||||
* serverName: {
|
* serverName: {
|
||||||
@ -166,7 +167,7 @@ function addActiveScriptsItem(workerscript) {
|
|||||||
margin: "4px",
|
margin: "4px",
|
||||||
padding: "4px",
|
padding: "4px",
|
||||||
clickListener: () => {
|
clickListener: () => {
|
||||||
killWorkerScript(workerscript.scriptRef, workerscript.scriptRef.scriptRef.server);
|
killWorkerScript(workerscript.scriptRef, workerscript.scriptRef.server);
|
||||||
dialogBoxCreate("Killing script, may take a few minutes to complete...");
|
dialogBoxCreate("Killing script, may take a few minutes to complete...");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -242,9 +243,9 @@ function updateActiveScriptsItems(maxTasks=150) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getElementById("active-scripts-total-production-active").innerText = numeralWrapper.format(total, '$0.000a');
|
getElementById("active-scripts-total-production-active").innerText = numeralWrapper.formatMoney(total);
|
||||||
getElementById("active-scripts-total-prod-aug-total").innerText = numeralWrapper.format(Player.scriptProdSinceLastAug, '$0.000a');
|
getElementById("active-scripts-total-prod-aug-total").innerText = numeralWrapper.formatMoney(Player.scriptProdSinceLastAug);
|
||||||
getElementById("active-scripts-total-prod-aug-avg").innerText = numeralWrapper.format(Player.scriptProdSinceLastAug / (Player.playtimeSinceLastAug/1000), '$0.000a');
|
getElementById("active-scripts-total-prod-aug-avg").innerText = numeralWrapper.formatMoney(Player.scriptProdSinceLastAug / (Player.playtimeSinceLastAug/1000));
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,7 +253,7 @@ function updateActiveScriptsItems(maxTasks=150) {
|
|||||||
function updateActiveScriptsItemContent(workerscript) {
|
function updateActiveScriptsItemContent(workerscript) {
|
||||||
var server = getServer(workerscript.serverIp);
|
var server = getServer(workerscript.serverIp);
|
||||||
if (server == null) {
|
if (server == null) {
|
||||||
console.log("ERROR: Invalid server IP for workerscript.");
|
console.log("ERROR: Invalid server IP for workerscript in updateActiveScriptsItemContent().");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let hostname = server.hostname;
|
let hostname = server.hostname;
|
||||||
@ -280,7 +281,7 @@ function updateActiveScriptsItemContent(workerscript) {
|
|||||||
function updateActiveScriptsText(workerscript, item, itemName) {
|
function updateActiveScriptsText(workerscript, item, itemName) {
|
||||||
var server = getServer(workerscript.serverIp);
|
var server = getServer(workerscript.serverIp);
|
||||||
if (server == null) {
|
if (server == null) {
|
||||||
console.log("ERROR: Invalid server IP for workerscript.");
|
console.log("ERROR: Invalid server IP for workerscript for updateActiveScriptsText()");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let hostname = server.hostname;
|
let hostname = server.hostname;
|
||||||
@ -298,24 +299,27 @@ function updateActiveScriptsText(workerscript, item, itemName) {
|
|||||||
|
|
||||||
removeChildrenFromElement(item);
|
removeChildrenFromElement(item);
|
||||||
|
|
||||||
//Online
|
var onlineTime = "Online Time: " + convertTimeMsToTimeElapsedString(workerscript.scriptRef.onlineRunningTime * 1e3);
|
||||||
var onlineTotalMoneyMade = "Total online production: $" + formatNumber(workerscript.scriptRef.onlineMoneyMade, 2);
|
var offlineTime = "Offline Time: " + convertTimeMsToTimeElapsedString(workerscript.scriptRef.offlineRunningTime * 1e3);
|
||||||
var onlineTotalExpEarned = (Array(26).join(" ") + formatNumber(workerscript.scriptRef.onlineExpGained, 2) + " hacking exp").replace( / /g, " ");
|
|
||||||
|
|
||||||
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 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
|
//Offline
|
||||||
var offlineTotalMoneyMade = "Total offline production: $" + formatNumber(workerscript.scriptRef.offlineMoneyMade, 2);
|
var offlineTotalMoneyMade = "Total offline production: " + numeralWrapper.formatMoney(workerscript.scriptRef.offlineMoneyMade);
|
||||||
var offlineTotalExpEarned = (Array(27).join(" ") + formatNumber(workerscript.scriptRef.offlineExpGained, 2) + " hacking exp").replace( / /g, " ");
|
var offlineTotalExpEarned = (Array(27).join(" ") + numeralWrapper.formatBigNumber(workerscript.scriptRef.offlineExpGained) + " hacking exp").replace( / /g, " ");
|
||||||
|
|
||||||
var offlineMps = workerscript.scriptRef.offlineMoneyMade / workerscript.scriptRef.offlineRunningTime;
|
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 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 + "<br>" + onlineTotalExpEarned + "<br>" +
|
item.innerHTML = onlineTime + "<br>" + offlineTime + "<br>" + onlineTotalMoneyMade + "<br>" + onlineTotalExpEarned + "<br>" +
|
||||||
onlineMpsText + "<br>" + onlineEpsText + "<br>" + offlineTotalMoneyMade + "<br>" + offlineTotalExpEarned + "<br>" +
|
onlineMpsText + "<br>" + onlineEpsText + "<br>" + offlineTotalMoneyMade + "<br>" + offlineTotalExpEarned + "<br>" +
|
||||||
offlineMpsText + "<br>" + offlineEpsText + "<br>";
|
offlineMpsText + "<br>" + offlineEpsText + "<br>";
|
||||||
return onlineMps;
|
return onlineMps;
|
||||||
|
@ -90,7 +90,10 @@ function removeAlias(name) {
|
|||||||
//Aliases only applied to "whole words", one level deep
|
//Aliases only applied to "whole words", one level deep
|
||||||
function substituteAliases(origCommand) {
|
function substituteAliases(origCommand) {
|
||||||
var commandArray = origCommand.split(" ");
|
var commandArray = origCommand.split(" ");
|
||||||
if (commandArray.length>0){
|
if (commandArray.length > 0){
|
||||||
|
// For the unalias command, dont substite
|
||||||
|
if (commandArray[0] === "unalias") { return commandArray.join(" "); }
|
||||||
|
|
||||||
var alias = getAlias(commandArray[0]);
|
var alias = getAlias(commandArray[0]);
|
||||||
if (alias != null) {
|
if (alias != null) {
|
||||||
commandArray[0] = alias;
|
commandArray[0] = alias;
|
||||||
|
@ -78,6 +78,9 @@ export class Augmentation {
|
|||||||
// The Player/Person classes
|
// The Player/Person classes
|
||||||
mults: IMap<number> = {}
|
mults: IMap<number> = {}
|
||||||
|
|
||||||
|
// Initial cost. Doesn't change when you purchase multiple Augmentation
|
||||||
|
startingCost: number = 0;
|
||||||
|
|
||||||
constructor(params: IConstructorParams={ info: "", moneyCost: 0, name: "", repCost: 0 }) {
|
constructor(params: IConstructorParams={ info: "", moneyCost: 0, name: "", repCost: 0 }) {
|
||||||
this.name = params.name;
|
this.name = params.name;
|
||||||
this.info = params.info;
|
this.info = params.info;
|
||||||
@ -85,6 +88,7 @@ export class Augmentation {
|
|||||||
|
|
||||||
this.baseRepRequirement = params.repCost * CONSTANTS.AugmentationRepMultiplier * BitNodeMultipliers.AugmentationRepCost;
|
this.baseRepRequirement = params.repCost * CONSTANTS.AugmentationRepMultiplier * BitNodeMultipliers.AugmentationRepCost;
|
||||||
this.baseCost = params.moneyCost * CONSTANTS.AugmentationCostMultiplier * BitNodeMultipliers.AugmentationMoneyCost;
|
this.baseCost = params.moneyCost * CONSTANTS.AugmentationCostMultiplier * BitNodeMultipliers.AugmentationMoneyCost;
|
||||||
|
this.startingCost = this.baseCost;
|
||||||
|
|
||||||
this.level = 0;
|
this.level = 0;
|
||||||
|
|
||||||
|
@ -364,6 +364,11 @@ function initBitNodeMultipliers() {
|
|||||||
var inc = Math.pow(1.02, sf12Lvl);
|
var inc = Math.pow(1.02, sf12Lvl);
|
||||||
var dec = 1/inc;
|
var dec = 1/inc;
|
||||||
BitNodeMultipliers.HackingLevelMultiplier = dec;
|
BitNodeMultipliers.HackingLevelMultiplier = dec;
|
||||||
|
BitNodeMultipliers.StrengthLevelMultiplier = dec;
|
||||||
|
BitNodeMultipliers.DefenseLevelMultiplier = dec;
|
||||||
|
BitNodeMultipliers.DexterityLevelMultiplier = dec;
|
||||||
|
BitNodeMultipliers.AgilityLevelMultiplier = dec;
|
||||||
|
BitNodeMultipliers.CharismaLevelMultiplier = dec;
|
||||||
|
|
||||||
BitNodeMultipliers.ServerMaxMoney = dec;
|
BitNodeMultipliers.ServerMaxMoney = dec;
|
||||||
BitNodeMultipliers.ServerStartingMoney = dec;
|
BitNodeMultipliers.ServerStartingMoney = dec;
|
||||||
@ -373,6 +378,10 @@ function initBitNodeMultipliers() {
|
|||||||
//Does not scale, otherwise security might start at 300+
|
//Does not scale, otherwise security might start at 300+
|
||||||
BitNodeMultipliers.ServerStartingSecurity = 1.5;
|
BitNodeMultipliers.ServerStartingSecurity = 1.5;
|
||||||
|
|
||||||
|
BitNodeMultipliers.PurchasedServerCost = inc;
|
||||||
|
BitNodeMultipliers.PurchasedServerLimit = dec;
|
||||||
|
BitNodeMultipliers.PurchasedServerMaxRam = dec;
|
||||||
|
|
||||||
BitNodeMultipliers.ManualHackMoney = dec;
|
BitNodeMultipliers.ManualHackMoney = dec;
|
||||||
BitNodeMultipliers.ScriptHackMoney = dec;
|
BitNodeMultipliers.ScriptHackMoney = dec;
|
||||||
BitNodeMultipliers.CompanyWorkMoney = dec;
|
BitNodeMultipliers.CompanyWorkMoney = dec;
|
||||||
|
@ -156,7 +156,6 @@ $(document).keydown(function(event) {
|
|||||||
if (!(Player.bladeburner instanceof Bladeburner)) {return;}
|
if (!(Player.bladeburner instanceof Bladeburner)) {return;}
|
||||||
let consoleHistory = Player.bladeburner.consoleHistory;
|
let consoleHistory = Player.bladeburner.consoleHistory;
|
||||||
|
|
||||||
//NOTE: Keycodes imported from Terminal.js
|
|
||||||
if (event.keyCode === KEY.ENTER) {
|
if (event.keyCode === KEY.ENTER) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
var command = DomElems.consoleInput.value;
|
var command = DomElems.consoleInput.value;
|
||||||
@ -355,6 +354,8 @@ function Skill(params={name:"foo", desc:"foo"}) {
|
|||||||
if (params.effCha) {this.effCha = params.effCha;}
|
if (params.effCha) {this.effCha = params.effCha;}
|
||||||
|
|
||||||
if (params.stamina) {this.stamina = params.stamina;}
|
if (params.stamina) {this.stamina = params.stamina;}
|
||||||
|
if (params.money) {this.money = params.money;}
|
||||||
|
if (params.expGain) {this.expGain = params.expGain;}
|
||||||
|
|
||||||
//Equipment
|
//Equipment
|
||||||
if (params.weaponAbility) {this.weaponAbility = params.weaponAbility;}
|
if (params.weaponAbility) {this.weaponAbility = params.weaponAbility;}
|
||||||
@ -367,17 +368,19 @@ Skill.prototype.calculateCost = function(currentLevel) {
|
|||||||
var Skills = {};
|
var Skills = {};
|
||||||
var SkillNames = {
|
var SkillNames = {
|
||||||
BladesIntuition: "Blade's Intuition",
|
BladesIntuition: "Blade's Intuition",
|
||||||
Reaper: "Reaper",
|
|
||||||
Cloak: "Cloak",
|
Cloak: "Cloak",
|
||||||
Marksman: "Marksman",
|
Marksman: "Marksman",
|
||||||
WeaponProficiency: "Weapon Proficiency",
|
WeaponProficiency: "Weapon Proficiency",
|
||||||
Overclock: "Overclock",
|
|
||||||
EvasiveSystem: "Evasive System",
|
|
||||||
ShortCircuit: "Short-Circuit",
|
ShortCircuit: "Short-Circuit",
|
||||||
DigitalObserver: "Digital Observer",
|
DigitalObserver: "Digital Observer",
|
||||||
Datamancer: "Datamancer",
|
|
||||||
Tracer: "Tracer",
|
Tracer: "Tracer",
|
||||||
CybersEdge: "Cyber's Edge"
|
Overclock: "Overclock",
|
||||||
|
Reaper: "Reaper",
|
||||||
|
EvasiveSystem: "Evasive System",
|
||||||
|
Datamancer: "Datamancer",
|
||||||
|
CybersEdge: "Cyber's Edge",
|
||||||
|
HandsOfMidas: "Hands of Midas",
|
||||||
|
Hyperdrive: "Hyperdrive",
|
||||||
}
|
}
|
||||||
|
|
||||||
//Base Class for Contracts, Operations, and BlackOps
|
//Base Class for Contracts, Operations, and BlackOps
|
||||||
@ -998,23 +1001,25 @@ Bladeburner.prototype.getCurrentCity = function() {
|
|||||||
|
|
||||||
Bladeburner.prototype.resetSkillMultipliers = function() {
|
Bladeburner.prototype.resetSkillMultipliers = function() {
|
||||||
this.skillMultipliers = {
|
this.skillMultipliers = {
|
||||||
successChanceAll:1,
|
successChanceAll: 1,
|
||||||
successChanceStealth:1,
|
successChanceStealth: 1,
|
||||||
successChanceKill:1,
|
successChanceKill: 1,
|
||||||
successChanceContract:1,
|
successChanceContract: 1,
|
||||||
successChanceOperation:1,
|
successChanceOperation: 1,
|
||||||
successChanceEstimate:1,
|
successChanceEstimate: 1,
|
||||||
actionTime:1,
|
actionTime: 1,
|
||||||
effHack:1,
|
effHack: 1,
|
||||||
effStr:1,
|
effStr: 1,
|
||||||
effDef:1,
|
effDef: 1,
|
||||||
effDex:1,
|
effDex: 1,
|
||||||
effAgi:1,
|
effAgi: 1,
|
||||||
effCha:1,
|
effCha: 1,
|
||||||
effInt:1,
|
effInt: 1,
|
||||||
stamina:1,
|
stamina: 1,
|
||||||
weaponAbility:1,
|
money: 1,
|
||||||
gunAbility:1,
|
expGain: 1,
|
||||||
|
weaponAbility: 1,
|
||||||
|
gunAbility: 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1197,7 +1202,7 @@ Bladeburner.prototype.completeAction = function() {
|
|||||||
//Earn money for contracts
|
//Earn money for contracts
|
||||||
var moneyGain = 0;
|
var moneyGain = 0;
|
||||||
if (!isOperation) {
|
if (!isOperation) {
|
||||||
moneyGain = ContractBaseMoneyGain * rewardMultiplier;
|
moneyGain = ContractBaseMoneyGain * rewardMultiplier * this.skillMultipliers.money;
|
||||||
Player.gainMoney(moneyGain);
|
Player.gainMoney(moneyGain);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1526,13 +1531,14 @@ Bladeburner.prototype.gainActionStats = function(action, success) {
|
|||||||
|
|
||||||
var unweightedGain = time * BaseStatGain * successMult * difficultyMult;
|
var unweightedGain = time * BaseStatGain * successMult * difficultyMult;
|
||||||
var unweightedIntGain = time * BaseIntGain * successMult * difficultyMult;
|
var unweightedIntGain = time * BaseIntGain * successMult * difficultyMult;
|
||||||
Player.gainHackingExp(unweightedGain * action.weights.hack * Player.hacking_exp_mult);
|
const skillMult = this.skillMultipliers.expGain;
|
||||||
Player.gainStrengthExp(unweightedGain * action.weights.str * Player.strength_exp_mult);
|
Player.gainHackingExp(unweightedGain * action.weights.hack * Player.hacking_exp_mult * skillMult);
|
||||||
Player.gainDefenseExp(unweightedGain * action.weights.def * Player.defense_exp_mult);
|
Player.gainStrengthExp(unweightedGain * action.weights.str * Player.strength_exp_mult * skillMult);
|
||||||
Player.gainDexterityExp(unweightedGain * action.weights.dex * Player.dexterity_exp_mult);
|
Player.gainDefenseExp(unweightedGain * action.weights.def * Player.defense_exp_mult * skillMult);
|
||||||
Player.gainAgilityExp(unweightedGain * action.weights.agi * Player.agility_exp_mult);
|
Player.gainDexterityExp(unweightedGain * action.weights.dex * Player.dexterity_exp_mult * skillMult);
|
||||||
Player.gainCharismaExp(unweightedGain * action.weights.cha * Player.charisma_exp_mult);
|
Player.gainAgilityExp(unweightedGain * action.weights.agi * Player.agility_exp_mult * skillMult);
|
||||||
Player.gainIntelligenceExp(unweightedIntGain * action.weights.int);
|
Player.gainCharismaExp(unweightedGain * action.weights.cha * Player.charisma_exp_mult * skillMult);
|
||||||
|
Player.gainIntelligenceExp(unweightedIntGain * action.weights.int * skillMult);
|
||||||
}
|
}
|
||||||
|
|
||||||
Bladeburner.prototype.randomEvent = function() {
|
Bladeburner.prototype.randomEvent = function() {
|
||||||
@ -2193,6 +2199,12 @@ Bladeburner.prototype.createSkillsContent = function() {
|
|||||||
case "stamina":
|
case "stamina":
|
||||||
DomElems.actionsAndSkillsDesc.innerHTML += "Stamina: x" + mult + "<br>";
|
DomElems.actionsAndSkillsDesc.innerHTML += "Stamina: x" + mult + "<br>";
|
||||||
break;
|
break;
|
||||||
|
case "money":
|
||||||
|
DomElems.actionsAndSkillsDesc.innerHTML += "Contract Money: x" + mult + "<br>";
|
||||||
|
break;
|
||||||
|
case "expGain":
|
||||||
|
DomElems.actionsAndSkillsDesc.innerHTML += "Exp Gain: x" + mult + "<br>";
|
||||||
|
break;
|
||||||
case "weaponAbility":
|
case "weaponAbility":
|
||||||
//DomElems.actionsAndSkillsDesc.innerHTML +=
|
//DomElems.actionsAndSkillsDesc.innerHTML +=
|
||||||
break;
|
break;
|
||||||
@ -2862,12 +2874,23 @@ Bladeburner.prototype.parseCommandArguments = function(command) {
|
|||||||
//Returns an array with command and its arguments in each index.
|
//Returns an array with command and its arguments in each index.
|
||||||
//e.g. skill "blade's intuition" foo returns [skill, blade's intuition, foo]
|
//e.g. skill "blade's intuition" foo returns [skill, blade's intuition, foo]
|
||||||
//The input to this fn will be trimmed and will have all whitespace replaced w/ a single space
|
//The input to this fn will be trimmed and will have all whitespace replaced w/ a single space
|
||||||
var args = [];
|
const args = [];
|
||||||
var start = 0, i = 0;
|
let start = 0, i = 0;
|
||||||
while (i < command.length) {
|
while (i < command.length) {
|
||||||
var c = command.charAt(i);
|
const c = command.charAt(i);
|
||||||
if (c === '"') {
|
if (c === '"') { // Double quotes
|
||||||
var endQuote = command.indexOf('"', i+1);
|
const endQuote = command.indexOf('"', i+1);
|
||||||
|
if (endQuote !== -1 && (endQuote === command.length-1 || command.charAt(endQuote+1) === " ")) {
|
||||||
|
args.push(command.substr(i+1, (endQuote - i - 1)));
|
||||||
|
if (endQuote === command.length-1) {
|
||||||
|
start = i = endQuote+1;
|
||||||
|
} else {
|
||||||
|
start = i = endQuote+2; //Skip the space
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (c === "'") { // Single quotes, same thing as above
|
||||||
|
const endQuote = command.indexOf("'", i+1);
|
||||||
if (endQuote !== -1 && (endQuote === command.length-1 || command.charAt(endQuote+1) === " ")) {
|
if (endQuote !== -1 && (endQuote === command.length-1 || command.charAt(endQuote+1) === " ")) {
|
||||||
args.push(command.substr(i+1, (endQuote - i - 1)));
|
args.push(command.substr(i+1, (endQuote - i - 1)));
|
||||||
if (endQuote === command.length-1) {
|
if (endQuote === command.length-1) {
|
||||||
@ -2884,7 +2907,7 @@ Bladeburner.prototype.parseCommandArguments = function(command) {
|
|||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
if (start !== i) {args.push(command.substr(start, i-start));}
|
if (start !== i) {args.push(command.substr(start, i-start));}
|
||||||
console.log("Bladeburner.parseCommandArguments returned: " + args);
|
console.log("Bladeburner console command parsing returned: " + args);
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3417,12 +3440,12 @@ Bladeburner.prototype.startActionNetscriptFn = function(type, name, workerScript
|
|||||||
try {
|
try {
|
||||||
this.startAction(actionId);
|
this.startAction(actionId);
|
||||||
if (workerScript.shouldLog("startAction")) {
|
if (workerScript.shouldLog("startAction")) {
|
||||||
workerScript.scriptRef.log("Starting bladeburner action with type " + type + " and name " + name);
|
workerScript.log("Starting bladeburner action with type " + type + " and name " + name);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
this.resetAction();
|
this.resetAction();
|
||||||
workerScript.scriptRef.log("ERROR: bladeburner.startAction() failed to start action of type " + type + " due to invalid name: " + name +
|
workerScript.log("ERROR: bladeburner.startAction() failed to start action of type " + type + " due to invalid name: " + name +
|
||||||
"Note that this name is case-sensitive and whitespace-sensitive");
|
"Note that this name is case-sensitive and whitespace-sensitive");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -3764,13 +3787,6 @@ function initBladeburner() {
|
|||||||
baseCost:5, costInc:2,
|
baseCost:5, costInc:2,
|
||||||
successChanceAll:3
|
successChanceAll:3
|
||||||
});
|
});
|
||||||
Skills[SkillNames.Reaper] = new Skill({
|
|
||||||
name:SkillNames.Reaper,
|
|
||||||
desc:"Each level of this skill increases your " +
|
|
||||||
"effective combat stats for Bladeburner actions by 3%",
|
|
||||||
baseCost:3, costInc:2,
|
|
||||||
effStr:3, effDef:3, effDex:3, effAgi:3
|
|
||||||
});
|
|
||||||
Skills[SkillNames.Cloak] = new Skill({
|
Skills[SkillNames.Cloak] = new Skill({
|
||||||
name:SkillNames.Cloak,
|
name:SkillNames.Cloak,
|
||||||
desc:"Each level of this skill increases your " +
|
desc:"Each level of this skill increases your " +
|
||||||
@ -3782,20 +3798,6 @@ function initBladeburner() {
|
|||||||
//TODO Marksman
|
//TODO Marksman
|
||||||
//TODO Weapon Proficiency
|
//TODO Weapon Proficiency
|
||||||
|
|
||||||
Skills[SkillNames.Overclock] = new Skill({
|
|
||||||
name:SkillNames.Overclock,
|
|
||||||
desc:"Each level of this skill decreases the time it takes " +
|
|
||||||
"to attempt a Contract, Operation, and BlackOp by 1% (Max Level: 95)",
|
|
||||||
baseCost:5, costInc:1.1, maxLvl:95,
|
|
||||||
actionTime:1
|
|
||||||
});
|
|
||||||
Skills[SkillNames.EvasiveSystem] = new Skill({
|
|
||||||
name:SkillNames.EvasiveSystem,
|
|
||||||
desc:"Each level of this skill increases your effective " +
|
|
||||||
"dexterity and agility for Bladeburner actions by 5%",
|
|
||||||
baseCost:2, costInc: 1,
|
|
||||||
effDex:5, effAgi:5
|
|
||||||
});
|
|
||||||
Skills[SkillNames.ShortCircuit] = new Skill({
|
Skills[SkillNames.ShortCircuit] = new Skill({
|
||||||
name:SkillNames.ShortCircuit,
|
name:SkillNames.ShortCircuit,
|
||||||
desc:"Each level of this skill increases your success chance " +
|
desc:"Each level of this skill increases your success chance " +
|
||||||
@ -3810,15 +3812,6 @@ function initBladeburner() {
|
|||||||
baseCost:5, costInc:2,
|
baseCost:5, costInc:2,
|
||||||
successChanceOperation:4
|
successChanceOperation:4
|
||||||
});
|
});
|
||||||
Skills[SkillNames.Datamancer] = new Skill({
|
|
||||||
name:SkillNames.Datamancer,
|
|
||||||
desc:"Each level of this skill increases your effectiveness in " +
|
|
||||||
"synthoid population analysis and investigation by 5%. " +
|
|
||||||
"This affects all actions that can potentially increase " +
|
|
||||||
"the accuracy of your synthoid population/community estimates.",
|
|
||||||
baseCost:3,costInc:1,
|
|
||||||
successChanceEstimate:5
|
|
||||||
});
|
|
||||||
Skills[SkillNames.Tracer] = new Skill({
|
Skills[SkillNames.Tracer] = new Skill({
|
||||||
name:SkillNames.Tracer,
|
name:SkillNames.Tracer,
|
||||||
desc:"Each level of this skill increases your success chance in " +
|
desc:"Each level of this skill increases your success chance in " +
|
||||||
@ -3826,13 +3819,53 @@ function initBladeburner() {
|
|||||||
baseCost:3, costInc:2,
|
baseCost:3, costInc:2,
|
||||||
successChanceContract:4
|
successChanceContract:4
|
||||||
});
|
});
|
||||||
|
Skills[SkillNames.Overclock] = new Skill({
|
||||||
|
name:SkillNames.Overclock,
|
||||||
|
desc:"Each level of this skill decreases the time it takes " +
|
||||||
|
"to attempt a Contract, Operation, and BlackOp by 1% (Max Level: 95)",
|
||||||
|
baseCost:4, costInc:1.1, maxLvl:95,
|
||||||
|
actionTime:1
|
||||||
|
});
|
||||||
|
Skills[SkillNames.Reaper] = new Skill({
|
||||||
|
name:SkillNames.Reaper,
|
||||||
|
desc:"Each level of this skill increases your effective combat stats for Bladeburner actions by 3%",
|
||||||
|
baseCost:3, costInc:2,
|
||||||
|
effStr:3, effDef:3, effDex:3, effAgi:3
|
||||||
|
});
|
||||||
|
Skills[SkillNames.EvasiveSystem] = new Skill({
|
||||||
|
name:SkillNames.EvasiveSystem,
|
||||||
|
desc:"Each level of this skill increases your effective " +
|
||||||
|
"dexterity and agility for Bladeburner actions by 5%",
|
||||||
|
baseCost:2, costInc: 1,
|
||||||
|
effDex:5, effAgi:5
|
||||||
|
});
|
||||||
|
Skills[SkillNames.Datamancer] = new Skill({
|
||||||
|
name:SkillNames.Datamancer,
|
||||||
|
desc:"Each level of this skill increases your effectiveness in " +
|
||||||
|
"synthoid population analysis and investigation by 5%. " +
|
||||||
|
"This affects all actions that can potentially increase " +
|
||||||
|
"the accuracy of your synthoid population/community estimates.",
|
||||||
|
baseCost:3, costInc:1,
|
||||||
|
successChanceEstimate:5
|
||||||
|
});
|
||||||
Skills[SkillNames.CybersEdge] = new Skill({
|
Skills[SkillNames.CybersEdge] = new Skill({
|
||||||
name:SkillNames.CybersEdge,
|
name:SkillNames.CybersEdge,
|
||||||
desc:"Each level of this skill increases your max " +
|
desc:"Each level of this skill increases your max stamina by 2%",
|
||||||
"stamina by 2%",
|
|
||||||
baseCost:1, costInc:3,
|
baseCost:1, costInc:3,
|
||||||
stamina:2
|
stamina:2
|
||||||
});
|
});
|
||||||
|
Skills[SkillNames.HandsOfMidas] = new Skill({
|
||||||
|
name: SkillNames.HandsOfMidas,
|
||||||
|
desc: "Each level of this skill increases the amount of money you receive from Contracts by 5%",
|
||||||
|
baseCost: 2, costInc: 2.5,
|
||||||
|
money: 5,
|
||||||
|
});
|
||||||
|
Skills[SkillNames.Hyperdrive] = new Skill({
|
||||||
|
name: SkillNames.Hyperdrive,
|
||||||
|
desc: "Each level of this skill increases the experience earned from Contracts, Operations, and BlackOps by 4%",
|
||||||
|
baseCost: 1, costInc: 3,
|
||||||
|
expGain: 4,
|
||||||
|
});
|
||||||
|
|
||||||
//General Actions
|
//General Actions
|
||||||
var actionName = "Training";
|
var actionName = "Training";
|
||||||
|
@ -10,9 +10,7 @@ import { getRandomInt } from "../utils/helpers/getRandomInt";
|
|||||||
|
|
||||||
export function generateRandomContract() {
|
export function generateRandomContract() {
|
||||||
// First select a random problem type
|
// First select a random problem type
|
||||||
const problemTypes = Object.keys(CodingContractTypes);
|
let problemType = getRandomProblemType();
|
||||||
let randIndex = getRandomInt(0, problemTypes.length - 1);
|
|
||||||
let problemType = problemTypes[randIndex];
|
|
||||||
|
|
||||||
// Then select a random reward type. 'Money' will always be the last reward type
|
// Then select a random reward type. 'Money' will always be the last reward type
|
||||||
const reward = getRandomReward();
|
const reward = getRandomReward();
|
||||||
@ -26,6 +24,22 @@ export function generateRandomContract() {
|
|||||||
randServer.addContract(contract);
|
randServer.addContract(contract);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function generateRandomContractOnHome() {
|
||||||
|
// First select a random problem type
|
||||||
|
let problemType = getRandomProblemType();
|
||||||
|
|
||||||
|
// Then select a random reward type. 'Money' will always be the last reward type
|
||||||
|
const reward = getRandomReward();
|
||||||
|
|
||||||
|
// Choose random server
|
||||||
|
const serv = Player.getHomeComputer();
|
||||||
|
|
||||||
|
let contractFn = getRandomFilename(serv, reward);
|
||||||
|
let contract = new CodingContract(contractFn, problemType, reward);
|
||||||
|
|
||||||
|
serv.addContract(contract);
|
||||||
|
}
|
||||||
|
|
||||||
export function generateContract(params) {
|
export function generateContract(params) {
|
||||||
// Problem Type
|
// Problem Type
|
||||||
let problemType;
|
let problemType;
|
||||||
@ -33,8 +47,7 @@ export function generateContract(params) {
|
|||||||
if (params.problemType != null && problemTypes.includes(params.problemType)) {
|
if (params.problemType != null && problemTypes.includes(params.problemType)) {
|
||||||
problemType = params.problemType;
|
problemType = params.problemType;
|
||||||
} else {
|
} else {
|
||||||
let randIndex = getRandomInt(0, problemTypes.length - 1);
|
problemType = getRandomProblemType();
|
||||||
problemType = problemTypes[randIndex];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reward Type - This is always random for now
|
// Reward Type - This is always random for now
|
||||||
@ -91,6 +104,13 @@ function sanitizeRewardType(rewardType) {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRandomProblemType() {
|
||||||
|
const problemTypes = Object.keys(CodingContractTypes);
|
||||||
|
let randIndex = getRandomInt(0, problemTypes.length - 1);
|
||||||
|
|
||||||
|
return problemTypes[randIndex];
|
||||||
|
}
|
||||||
|
|
||||||
function getRandomReward() {
|
function getRandomReward() {
|
||||||
let reward = {};
|
let reward = {};
|
||||||
reward.type = getRandomInt(0, CodingContractRewardType.Money);
|
reward.type = getRandomInt(0, CodingContractRewardType.Money);
|
||||||
|
@ -1,9 +1,17 @@
|
|||||||
|
import { codingContractTypesMetadata,
|
||||||
|
DescriptionFunc,
|
||||||
|
GeneratorFunc,
|
||||||
|
SolverFunc } from "./data/codingcontracttypes";
|
||||||
|
|
||||||
|
import { IMap } from "./types";
|
||||||
|
|
||||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
|
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
|
||||||
|
import { KEY } from "../utils/helpers/keyCodes";
|
||||||
import { createElement } from "../utils/uiHelpers/createElement";
|
import { createElement } from "../utils/uiHelpers/createElement";
|
||||||
import { createPopup } from "../utils/uiHelpers/createPopup";
|
import { createPopup } from "../utils/uiHelpers/createPopup";
|
||||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||||
import { codingContractTypesMetadata, DescriptionFunc, GeneratorFunc, SolverFunc } from "./data/codingcontracttypes";
|
|
||||||
import { IMap } from "./types";
|
|
||||||
|
|
||||||
/* tslint:disable:no-magic-numbers completed-docs max-classes-per-file no-console */
|
/* tslint:disable:no-magic-numbers completed-docs max-classes-per-file no-console */
|
||||||
|
|
||||||
@ -171,18 +179,22 @@ export class CodingContract {
|
|||||||
const contractType: CodingContractType = CodingContractTypes[this.type];
|
const contractType: CodingContractType = CodingContractTypes[this.type];
|
||||||
const popupId: string = `coding-contract-prompt-popup-${this.fn}`;
|
const popupId: string = `coding-contract-prompt-popup-${this.fn}`;
|
||||||
const txt: HTMLElement = createElement("p", {
|
const txt: HTMLElement = createElement("p", {
|
||||||
innerText: ["You are attempting to solve a Coding Contract. You have",
|
innerHTML: ["You are attempting to solve a Coding Contract. You have",
|
||||||
`${this.getMaxNumTries() - this.tries} tries remaining,`,
|
`${this.getMaxNumTries() - this.tries} tries remaining,`,
|
||||||
"after which the contract will self-destruct.\n\n",
|
"after which the contract will self-destruct.<br><br>",
|
||||||
`${contractType.desc(this.data)}`].join(" "),
|
`${contractType.desc(this.data).replace(/\n/g, "<br>")}`].join(" "),
|
||||||
});
|
});
|
||||||
let answerInput: HTMLInputElement;
|
let answerInput: HTMLInputElement;
|
||||||
let solveBtn: HTMLElement;
|
let solveBtn: HTMLElement;
|
||||||
|
let cancelBtn: HTMLElement;
|
||||||
answerInput = createElement("input", {
|
answerInput = createElement("input", {
|
||||||
onkeydown: (e: any) => {
|
onkeydown: (e: any) => {
|
||||||
if (e.keyCode === 13 && answerInput.value !== "") {
|
if (e.keyCode === KEY.ENTER && answerInput.value !== "") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
solveBtn.click();
|
solveBtn.click();
|
||||||
|
} else if (e.keyCode === KEY.ESC) {
|
||||||
|
e.preventDefault();
|
||||||
|
cancelBtn.click();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
placeholder: "Enter Solution here",
|
placeholder: "Enter Solution here",
|
||||||
@ -200,7 +212,7 @@ export class CodingContract {
|
|||||||
},
|
},
|
||||||
innerText: "Solve",
|
innerText: "Solve",
|
||||||
});
|
});
|
||||||
const cancelBtn: HTMLElement = createElement("a", {
|
cancelBtn = createElement("a", {
|
||||||
class: "a-link-button",
|
class: "a-link-button",
|
||||||
clickListener: () => {
|
clickListener: () => {
|
||||||
resolve(CodingContractResult.Cancelled);
|
resolve(CodingContractResult.Cancelled);
|
||||||
|
@ -8,6 +8,7 @@ import { IMap } from "../../types";
|
|||||||
const AllSoftwarePositions: IMap<boolean> = {};
|
const AllSoftwarePositions: IMap<boolean> = {};
|
||||||
const AllITPositions: IMap<boolean> = {};
|
const AllITPositions: IMap<boolean> = {};
|
||||||
const AllNetworkEngineerPositions: IMap<boolean> = {};
|
const AllNetworkEngineerPositions: IMap<boolean> = {};
|
||||||
|
const SecurityEngineerPositions: IMap<boolean> = {};
|
||||||
const AllTechnologyPositions: IMap<boolean> = {};
|
const AllTechnologyPositions: IMap<boolean> = {};
|
||||||
const AllBusinessPositions: IMap<boolean> = {};
|
const AllBusinessPositions: IMap<boolean> = {};
|
||||||
const AllAgentPositions: IMap<boolean> = {};
|
const AllAgentPositions: IMap<boolean> = {};
|
||||||
@ -40,6 +41,7 @@ posNames.NetworkEngineerCompanyPositions.forEach((e) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
AllTechnologyPositions[posNames.SecurityEngineerCompanyPositions[0]] = true;
|
AllTechnologyPositions[posNames.SecurityEngineerCompanyPositions[0]] = true;
|
||||||
|
SecurityEngineerPositions[posNames.SecurityEngineerCompanyPositions[0]] = true;
|
||||||
|
|
||||||
posNames.BusinessCompanyPositions.forEach((e) => {
|
posNames.BusinessCompanyPositions.forEach((e) => {
|
||||||
AllBusinessPositions[e] = true;
|
AllBusinessPositions[e] = true;
|
||||||
@ -373,6 +375,7 @@ export const companiesMetadata: IConstructorParams[] = [
|
|||||||
companyPositions: Object.assign({},
|
companyPositions: Object.assign({},
|
||||||
SoftwarePositionsUpToHeadOfEngineering,
|
SoftwarePositionsUpToHeadOfEngineering,
|
||||||
AllNetworkEngineerPositions,
|
AllNetworkEngineerPositions,
|
||||||
|
SecurityEngineerPositions,
|
||||||
AllITPositions,
|
AllITPositions,
|
||||||
AllSecurityPositions,
|
AllSecurityPositions,
|
||||||
AllAgentPositions
|
AllAgentPositions
|
||||||
@ -387,6 +390,7 @@ export const companiesMetadata: IConstructorParams[] = [
|
|||||||
companyPositions: Object.assign({},
|
companyPositions: Object.assign({},
|
||||||
SoftwarePositionsUpToHeadOfEngineering,
|
SoftwarePositionsUpToHeadOfEngineering,
|
||||||
AllNetworkEngineerPositions,
|
AllNetworkEngineerPositions,
|
||||||
|
SecurityEngineerPositions,
|
||||||
AllITPositions,
|
AllITPositions,
|
||||||
AllSecurityPositions,
|
AllSecurityPositions,
|
||||||
AllAgentPositions
|
AllAgentPositions
|
||||||
@ -492,8 +496,9 @@ export const companiesMetadata: IConstructorParams[] = [
|
|||||||
info: "",
|
info: "",
|
||||||
companyPositions: Object.assign({},
|
companyPositions: Object.assign({},
|
||||||
AllTechnologyPositions,
|
AllTechnologyPositions,
|
||||||
|
AllSoftwareConsultantPositions,
|
||||||
AllAgentPositions,
|
AllAgentPositions,
|
||||||
AllSecurityPositions
|
AllSecurityPositions,
|
||||||
),
|
),
|
||||||
expMultiplier: 1.2,
|
expMultiplier: 1.2,
|
||||||
salaryMultiplier: 1.2,
|
salaryMultiplier: 1.2,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import {IMap} from "./types";
|
import {IMap} from "./types";
|
||||||
|
|
||||||
export let CONSTANTS: IMap<any> = {
|
export let CONSTANTS: IMap<any> = {
|
||||||
Version: "0.43.0",
|
Version: "0.43.1",
|
||||||
|
|
||||||
//Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience
|
//Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience
|
||||||
//and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then
|
//and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then
|
||||||
@ -510,27 +510,25 @@ export let CONSTANTS: IMap<any> = {
|
|||||||
|
|
||||||
LatestUpdate:
|
LatestUpdate:
|
||||||
`
|
`
|
||||||
v0.43.0
|
v0.43.1
|
||||||
* Added BitNode-10: Digital Carbon
|
* Terminal changes:
|
||||||
|
** 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
|
||||||
|
|
||||||
* Stock Market Changes:
|
* Added two new Bladeburner skills for increasing money and experience gain
|
||||||
** Each stock now has a maximum number of shares you can purchase (both Long and Short positions combined)
|
* Made some minor adjustments to Bladeburner UI
|
||||||
** Added getStockMaxShares() Netscript function to the TIX API
|
* Corporation "Smart Factories" and "Smart Storage" upgrades have slightly lower price multipliers
|
||||||
** The cost of 4S Market Data TIX API Access increased from $20b to $25b
|
* Added nFormat Netscript function
|
||||||
|
* Added 6 new Coding Contract problems
|
||||||
* Job Changes:
|
* Updated documentation with list of all Coding Contract problems
|
||||||
** You can now hold multiple jobs at once. This means you no longer lose reputation when leaving a company
|
* Minor improvements for 'Active Scripts' UI
|
||||||
** Because of this change, the getCharacterInformation() Netscript function returns a slightly different value
|
* 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%)
|
||||||
* Script Editor Changes:
|
* Bug Fix: The cost of Resleeves should no longer be affected by buying Augs
|
||||||
** Added new script editor: CodeMirror. You can choose between the old editor (Ace) or CodeMirror
|
* Bug Fix: Duplicate Sleeves now use their own stats to determine crime success rate, instead of the host consciousness' stats
|
||||||
** Navigation keyboard shortcuts no longer work if the script editor is focused
|
* Bug Fix: You can now call the prompt() Netscript function from multiple scripts simultaneously
|
||||||
|
|
||||||
* Trying to programmatically run a script (run(), exec()) with a 'threads' argument of 0 will now cause the function to return false without running the script
|
|
||||||
* Home Computer RAM is now capped at 2 ^ 30 GB (1073741824 GB)
|
|
||||||
* The maximum amount, maximum RAM, and cost of purchasing servers can now vary between different BitNodes (new BitNode multipliers)
|
|
||||||
* Pop-up dialog boxes are a little bit bigger
|
|
||||||
* Bug Fix: When importing scripts, "./" will now be properly ignored (e.g. import { foo } from "./lib.script" )
|
|
||||||
`
|
`
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,12 @@ import { IMap } from "../../types";
|
|||||||
// [index in Corporation upgrades array, base price, price mult, benefit mult (additive), name, desc]
|
// [index in Corporation upgrades array, base price, price mult, benefit mult (additive), name, desc]
|
||||||
export const CorporationUpgrades: IMap<any[]> = {
|
export const CorporationUpgrades: IMap<any[]> = {
|
||||||
//Smart factories, increases production
|
//Smart factories, increases production
|
||||||
"0": [0, 2e9, 1.07, 0.03,
|
"0": [0, 2e9, 1.06, 0.03,
|
||||||
"Smart Factories", "Advanced AI automatically optimizes the operation and productivity " +
|
"Smart Factories", "Advanced AI automatically optimizes the operation and productivity " +
|
||||||
"of factories. Each level of this upgrade increases your global production by 3% (additive)."],
|
"of factories. Each level of this upgrade increases your global production by 3% (additive)."],
|
||||||
|
|
||||||
//Smart warehouses, increases storage size
|
//Smart warehouses, increases storage size
|
||||||
"1": [1, 2e9, 1.07, .1,
|
"1": [1, 2e9, 1.06, .1,
|
||||||
"Smart Storage", "Advanced AI automatically optimizes your warehouse storage methods. " +
|
"Smart Storage", "Advanced AI automatically optimizes your warehouse storage methods. " +
|
||||||
"Each level of this upgrade increases your global warehouse storage size by 10% (additive)."],
|
"Each level of this upgrade increases your global warehouse storage size by 10% (additive)."],
|
||||||
|
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
import { CONSTANTS } from "../Constants";
|
import { CONSTANTS } from "../Constants";
|
||||||
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
|
import { IPlayerOrSleeve } from "../PersonObjects/IPlayerOrSleeve";
|
||||||
|
|
||||||
export interface IConstructorParams {
|
export interface IConstructorParams {
|
||||||
hacking_success_weight?: number;
|
hacking_success_weight?: number;
|
||||||
strength_success_weight?: number;
|
strength_success_weight?: number;
|
||||||
@ -17,29 +20,6 @@ export interface IConstructorParams {
|
|||||||
kills?: number;
|
kills?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IPlayer {
|
|
||||||
startCrime(crimeType: string,
|
|
||||||
hackExp: number,
|
|
||||||
strExp: number,
|
|
||||||
defExp: number,
|
|
||||||
dexExp: number,
|
|
||||||
agiExp: number,
|
|
||||||
chaExp: number,
|
|
||||||
money: number,
|
|
||||||
time: number,
|
|
||||||
singParams: any): void;
|
|
||||||
|
|
||||||
hacking_skill: number;
|
|
||||||
strength: number;
|
|
||||||
defense: number;
|
|
||||||
dexterity: number;
|
|
||||||
agility: number;
|
|
||||||
charisma: number;
|
|
||||||
intelligence: number;
|
|
||||||
|
|
||||||
crime_success_mult: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Crime {
|
export class Crime {
|
||||||
// Number representing the difficulty of the crime. Used for success chance calculations
|
// Number representing the difficulty of the crime. Used for success chance calculations
|
||||||
difficulty: number = 0;
|
difficulty: number = 0;
|
||||||
@ -129,7 +109,7 @@ export class Crime {
|
|||||||
return this.time;
|
return this.time;
|
||||||
}
|
}
|
||||||
|
|
||||||
successRate(p: IPlayer): number {
|
successRate(p: IPlayerOrSleeve): number {
|
||||||
let chance: number = (this.hacking_success_weight * p.hacking_skill +
|
let chance: number = (this.hacking_success_weight * p.hacking_skill +
|
||||||
this.strength_success_weight * p.strength +
|
this.strength_success_weight * p.strength +
|
||||||
this.defense_success_weight * p.defense +
|
this.defense_success_weight * p.defense +
|
||||||
|
@ -1,23 +1,26 @@
|
|||||||
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
|
||||||
import { generateRandomContract } from "./CodingContractGenerator";
|
import { CodingContractTypes } from "./CodingContracts";
|
||||||
import { Programs } from "./Programs/Programs";
|
import { generateContract,
|
||||||
import { Factions } from "./Faction/Factions";
|
generateRandomContract,
|
||||||
import { Player } from "./Player";
|
generateRandomContractOnHome } from "./CodingContractGenerator";
|
||||||
import { AllServers } from "./Server";
|
import { Programs } from "./Programs/Programs";
|
||||||
import { hackWorldDaemon } from "./RedPill";
|
import { Factions } from "./Faction/Factions";
|
||||||
|
import { Player } from "./Player";
|
||||||
|
import { AllServers } from "./Server";
|
||||||
|
import { hackWorldDaemon } from "./RedPill";
|
||||||
import { StockMarket,
|
import { StockMarket,
|
||||||
SymbolToStockMap } from "./StockMarket/StockMarket";
|
SymbolToStockMap } from "./StockMarket/StockMarket";
|
||||||
import { Stock } from "./StockMarket/Stock";
|
import { Stock } from "./StockMarket/Stock";
|
||||||
import { Terminal } from "./Terminal";
|
import { Terminal } from "./Terminal";
|
||||||
|
|
||||||
import { numeralWrapper } from "./ui/numeralFormat";
|
import { numeralWrapper } from "./ui/numeralFormat";
|
||||||
|
|
||||||
import { dialogBoxCreate } from "../utils/DialogBox";
|
import { dialogBoxCreate } from "../utils/DialogBox";
|
||||||
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
|
||||||
import { createElement } from "../utils/uiHelpers/createElement";
|
import { createElement } from "../utils/uiHelpers/createElement";
|
||||||
import { createOptionElement } from "../utils/uiHelpers/createOptionElement";
|
import { createOptionElement } from "../utils/uiHelpers/createOptionElement";
|
||||||
import { getSelectText } from "../utils/uiHelpers/getSelectData";
|
import { getSelectText } from "../utils/uiHelpers/getSelectData";
|
||||||
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||||
|
|
||||||
const devMenuContainerId = "dev-menu-container";
|
const devMenuContainerId = "dev-menu-container";
|
||||||
|
|
||||||
@ -226,6 +229,24 @@ export function createDevMenu() {
|
|||||||
innerText: "Receive Invite to Faction",
|
innerText: "Receive Invite to Faction",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const factionsReputationInput = createElement("input", {
|
||||||
|
placeholder: "Rep to add to faction",
|
||||||
|
type: "number",
|
||||||
|
});
|
||||||
|
|
||||||
|
const factionsReputationButton = createElement("button", {
|
||||||
|
class: "std-button",
|
||||||
|
innerText: "Add rep to faction",
|
||||||
|
clickListener: () => {
|
||||||
|
const facName = getSelectText(factionsDropdown);
|
||||||
|
const fac = Factions[facName];
|
||||||
|
const rep = parseFloat(factionsReputationInput.value);
|
||||||
|
if (fac != null && !isNaN(rep)) {
|
||||||
|
fac.playerReputation += rep;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// Augmentations
|
// Augmentations
|
||||||
const augmentationsHeader = createElement("h2", {innerText: "Augmentations"});
|
const augmentationsHeader = createElement("h2", {innerText: "Augmentations"});
|
||||||
|
|
||||||
@ -429,6 +450,31 @@ export function createDevMenu() {
|
|||||||
innerText: "Generate Random Contract",
|
innerText: "Generate Random Contract",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const generateRandomContractOnHomeBtn = createElement("button", {
|
||||||
|
class: "std-button",
|
||||||
|
clickListener: () => {
|
||||||
|
generateRandomContractOnHome();
|
||||||
|
},
|
||||||
|
innerText: "Generate Random Contract on Home Comp",
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateContractWithTypeSelector = createElement("select", { margin: "5px" });
|
||||||
|
const contractTypes = Object.keys(CodingContractTypes);
|
||||||
|
for (let i = 0; i < contractTypes.length; ++i) {
|
||||||
|
generateContractWithTypeSelector.add(createOptionElement(contractTypes[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
const generateContractWithTypeBtn = createElement("button", {
|
||||||
|
class: "std-button",
|
||||||
|
clickListener: () => {
|
||||||
|
generateContract({
|
||||||
|
problemType: getSelectText(generateContractWithTypeSelector),
|
||||||
|
server: "home",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
innerText: "Generate Specified Contract Type on Home Comp",
|
||||||
|
});
|
||||||
|
|
||||||
// Stock Market
|
// Stock Market
|
||||||
const stockmarketHeader = createElement("h2", {innerText: "Stock Market"});
|
const stockmarketHeader = createElement("h2", {innerText: "Stock Market"});
|
||||||
|
|
||||||
@ -535,6 +581,9 @@ export function createDevMenu() {
|
|||||||
devMenuContainer.appendChild(factionsHeader);
|
devMenuContainer.appendChild(factionsHeader);
|
||||||
devMenuContainer.appendChild(factionsDropdown);
|
devMenuContainer.appendChild(factionsDropdown);
|
||||||
devMenuContainer.appendChild(factionsAddButton);
|
devMenuContainer.appendChild(factionsAddButton);
|
||||||
|
devMenuContainer.appendChild(createElement("br"));
|
||||||
|
devMenuContainer.appendChild(factionsReputationInput);
|
||||||
|
devMenuContainer.appendChild(factionsReputationButton);
|
||||||
devMenuContainer.appendChild(augmentationsHeader);
|
devMenuContainer.appendChild(augmentationsHeader);
|
||||||
devMenuContainer.appendChild(augmentationsDropdown);
|
devMenuContainer.appendChild(augmentationsDropdown);
|
||||||
devMenuContainer.appendChild(augmentationsQueueButton);
|
devMenuContainer.appendChild(augmentationsQueueButton);
|
||||||
@ -563,6 +612,10 @@ export function createDevMenu() {
|
|||||||
devMenuContainer.appendChild(createElement("br"));
|
devMenuContainer.appendChild(createElement("br"));
|
||||||
devMenuContainer.appendChild(contractsHeader);
|
devMenuContainer.appendChild(contractsHeader);
|
||||||
devMenuContainer.appendChild(generateRandomContractBtn);
|
devMenuContainer.appendChild(generateRandomContractBtn);
|
||||||
|
devMenuContainer.appendChild(generateRandomContractOnHomeBtn);
|
||||||
|
devMenuContainer.appendChild(createElement("br"));
|
||||||
|
devMenuContainer.appendChild(generateContractWithTypeSelector);
|
||||||
|
devMenuContainer.appendChild(generateContractWithTypeBtn);
|
||||||
devMenuContainer.appendChild(stockmarketHeader);
|
devMenuContainer.appendChild(stockmarketHeader);
|
||||||
devMenuContainer.appendChild(stockInput);
|
devMenuContainer.appendChild(stockInput);
|
||||||
devMenuContainer.appendChild(stockPriceChangeInput);
|
devMenuContainer.appendChild(stockPriceChangeInput);
|
||||||
|
@ -33,7 +33,7 @@ export const TerminalHelpText: string =
|
|||||||
"tail [script] [args...] Displays dynamic logs for the specified script<br>" +
|
"tail [script] [args...] Displays dynamic logs for the specified script<br>" +
|
||||||
"theme [preset] | bg txt hlgt Change the color scheme of the UI<br>" +
|
"theme [preset] | bg txt hlgt Change the color scheme of the UI<br>" +
|
||||||
"top Displays all running scripts and their RAM usage<br>" +
|
"top Displays all running scripts and their RAM usage<br>" +
|
||||||
'unalias "[alias name]" Deletes the specified alias<br>' +
|
'unalias [alias name] Deletes the specified alias<br>' +
|
||||||
"wget [url] [target file] Retrieves code/text from a web server<br>";
|
"wget [url] [target file] Retrieves code/text from a web server<br>";
|
||||||
|
|
||||||
interface IMap<T> {
|
interface IMap<T> {
|
||||||
@ -215,12 +215,12 @@ export const HelpTexts: IMap<string> = {
|
|||||||
top: "top<br>" +
|
top: "top<br>" +
|
||||||
"Prints a list of all scripts running on the current server as well as their thread count and how much " +
|
"Prints a list of all scripts running on the current server as well as their thread count and how much " +
|
||||||
"RAM they are using in total.",
|
"RAM they are using in total.",
|
||||||
unalias: 'unalias "[alias name]"<br>' +
|
unalias: 'unalias [alias name]<br>' +
|
||||||
"Deletes the specified alias. Note that the double quotation marks are required. <br><br>" +
|
"Deletes the specified alias. Note that the double quotation marks are required. <br><br>" +
|
||||||
"As an example, if an alias was declared using:<br><br>" +
|
"As an example, if an alias was declared using:<br><br>" +
|
||||||
'alias r="run"<br><br>' +
|
'alias r="run"<br><br>' +
|
||||||
"Then it could be removed using:<br><br>" +
|
"Then it could be removed using:<br><br>" +
|
||||||
'unalias "r"<br><br>' +
|
'unalias r<br><br>' +
|
||||||
"It is not necessary to differentiate between global and non-global aliases when using 'unalias'",
|
"It is not necessary to differentiate between global and non-global aliases when using 'unalias'",
|
||||||
wget: "wget [url] [target file]<br>" +
|
wget: "wget [url] [target file]<br>" +
|
||||||
"Retrieves data from a URL and downloads it to a file on the current server. The data can only " +
|
"Retrieves data from a URL and downloads it to a file on the current server. The data can only " +
|
||||||
|
@ -24,8 +24,8 @@ function initLiterature() {
|
|||||||
title = "The Beginner's Guide to Hacking";
|
title = "The Beginner's Guide to Hacking";
|
||||||
fn = "hackers-starting-handbook.lit";
|
fn = "hackers-starting-handbook.lit";
|
||||||
txt = "Some resources:<br><br>" +
|
txt = "Some resources:<br><br>" +
|
||||||
"<a class='a-link-button' href='https://bitburner.readthedocs.io/en/latest/netscriptlearntoprogram.html' target='_blank' style='margin:4px'>Learn to Program</a><br><br>" +
|
"<a class='a-link-button' href='https://bitburner.readthedocs.io/en/latest/netscript/netscriptlearntoprogram.html' target='_blank' style='margin:4px'>Learn to Program</a><br><br>" +
|
||||||
"<a class='a-link-button' href='https://bitburner.readthedocs.io/en/latest/netscriptjs.html' target='_blank' style='margin:4px'>For Experienced JavaScript Developers: NetscriptJS</a><br><br>" +
|
"<a class='a-link-button' href='https://bitburner.readthedocs.io/en/latest/netscript/netscriptjs.html' target='_blank' style='margin:4px'>For Experienced JavaScript Developers: NetscriptJS</a><br><br>" +
|
||||||
"<a class='a-link-button' href='https://bitburner.readthedocs.io/en/latest/netscript.html' target='_blank' style='margin:4px'>Netscript Documentation</a><br><br>" +
|
"<a class='a-link-button' href='https://bitburner.readthedocs.io/en/latest/netscript.html' target='_blank' style='margin:4px'>Netscript Documentation</a><br><br>" +
|
||||||
"When starting out, hacking is the most profitable way to earn money and progress. This " +
|
"When starting out, hacking is the most profitable way to earn money and progress. This " +
|
||||||
"is a brief collection of tips/pointers on how to make the most out of your hacking scripts.<br><br>" +
|
"is a brief collection of tips/pointers on how to make the most out of your hacking scripts.<br><br>" +
|
||||||
|
@ -13,10 +13,10 @@ function unknownBladeburnerExceptionMessage(functionName, err) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function checkBladeburnerAccess(workerScript, functionName) {
|
function checkBladeburnerAccess(workerScript, functionName) {
|
||||||
const accessDenied = `${functionName}() failed because you do not` +
|
const accessDenied = `${functionName}() failed because you do not ` +
|
||||||
" currently have access to the Bladeburner API. This is either" +
|
"currently have access to the Bladeburner API. To access the Bladeburner API" +
|
||||||
" because you are not currently employed at the Bladeburner division" +
|
"you must be employed at the Bladeburner division, AND you must either be in " +
|
||||||
" or because you do not have Source-File 7";
|
"BitNode-7 or have Source-File 7.";
|
||||||
const hasAccess = Player.bladeburner instanceof Bladeburner && (Player.bitNodeN === 7 || Player.sourceFiles.some(a=>{return a.n === 7}));
|
const hasAccess = Player.bladeburner instanceof Bladeburner && (Player.bitNodeN === 7 || Player.sourceFiles.some(a=>{return a.n === 7}));
|
||||||
if(!hasAccess) {
|
if(!hasAccess) {
|
||||||
throw makeRuntimeRejectMsg(workerScript, accessDenied);
|
throw makeRuntimeRejectMsg(workerScript, accessDenied);
|
||||||
|
@ -13,692 +13,7 @@ import {arrayToString} from "../utils/helpers/arrayToString
|
|||||||
import {isValidIPAddress} from "../utils/helpers/isValidIPAddress";
|
import {isValidIPAddress} from "../utils/helpers/isValidIPAddress";
|
||||||
import {isString} from "../utils/helpers/isString";
|
import {isString} from "../utils/helpers/isString";
|
||||||
|
|
||||||
var Promise = require("bluebird");
|
export function evaluateImport(exp, workerScript, checkingRam=false) {
|
||||||
|
|
||||||
Promise.config({
|
|
||||||
warnings: false,
|
|
||||||
longStackTraces: false,
|
|
||||||
cancellation: true,
|
|
||||||
monitoring: false
|
|
||||||
});
|
|
||||||
/* Evaluator
|
|
||||||
* Evaluates/Interprets the Abstract Syntax Tree generated by Acorns parser
|
|
||||||
*
|
|
||||||
* Returns a promise
|
|
||||||
*/
|
|
||||||
function evaluate(exp, workerScript) {
|
|
||||||
return Promise.delay(Settings.CodeInstructionRunTime).then(function() {
|
|
||||||
var env = workerScript.env;
|
|
||||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
|
||||||
if (exp == null) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Error: NULL expression", exp));
|
|
||||||
}
|
|
||||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
|
||||||
switch (exp.type) {
|
|
||||||
case "BlockStatement":
|
|
||||||
case "Program":
|
|
||||||
var evaluateProgPromise = evaluateProg(exp, workerScript, 0); //TODO: make every block/program use individual enviroment
|
|
||||||
return evaluateProgPromise.then(function(w) {
|
|
||||||
return Promise.resolve(workerScript);
|
|
||||||
}).catch(function(e) {
|
|
||||||
if (e.constructor === Array && e.length === 2 && e[0] === "RETURNSTATEMENT") {
|
|
||||||
return Promise.reject(e);
|
|
||||||
} else if (isString(e)) {
|
|
||||||
workerScript.errorMessage = e;
|
|
||||||
return Promise.reject(workerScript);
|
|
||||||
} else if (e instanceof WorkerScript) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
} else {
|
|
||||||
return Promise.reject(workerScript);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case "Literal":
|
|
||||||
return Promise.resolve(exp.value);
|
|
||||||
break;
|
|
||||||
case "Identifier":
|
|
||||||
//Javascript constructor() method can be used as an exploit to run arbitrary code
|
|
||||||
if (exp.name == "constructor") {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Illegal usage of constructor() method. If you have your own function named 'constructor', you must re-name it.", exp));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(exp.name in env.vars)){
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "variable " + exp.name + " not defined", exp));
|
|
||||||
}
|
|
||||||
return Promise.resolve(env.get(exp.name))
|
|
||||||
break;
|
|
||||||
case "ExpressionStatement":
|
|
||||||
return evaluate(exp.expression, workerScript);
|
|
||||||
break;
|
|
||||||
case "ArrayExpression":
|
|
||||||
var argPromises = exp.elements.map(function(arg) {
|
|
||||||
return evaluate(arg, workerScript);
|
|
||||||
});
|
|
||||||
return Promise.all(argPromises).then(function(array) {
|
|
||||||
return Promise.resolve(array)
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case "CallExpression":
|
|
||||||
return evaluate(exp.callee, workerScript).then(function(func) {
|
|
||||||
return Promise.map(exp.arguments, function(arg) {
|
|
||||||
return evaluate(arg, workerScript);
|
|
||||||
}).then(function(args) {
|
|
||||||
if (func instanceof Node) { //Player-defined function
|
|
||||||
//Create new Environment for the function
|
|
||||||
//Should be automatically garbage collected...
|
|
||||||
var funcEnv = env.extend();
|
|
||||||
|
|
||||||
//Define function arguments in this new environment
|
|
||||||
for (var i = 0; i < func.params.length; ++i) {
|
|
||||||
var arg;
|
|
||||||
if (i >= args.length) {
|
|
||||||
arg = null;
|
|
||||||
} else {
|
|
||||||
arg = args[i];
|
|
||||||
}
|
|
||||||
funcEnv.def(func.params[i].name, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Create a new WorkerScript for this function evaluation
|
|
||||||
var funcWorkerScript = new WorkerScript(workerScript.scriptRef);
|
|
||||||
funcWorkerScript.serverIp = workerScript.serverIp;
|
|
||||||
funcWorkerScript.env = funcEnv;
|
|
||||||
workerScript.fnWorker = funcWorkerScript;
|
|
||||||
|
|
||||||
return evaluate(func.body, funcWorkerScript).then(function(res) {
|
|
||||||
//If the function finished successfuly, that means there
|
|
||||||
//was no return statement since a return statement rejects. So resolve to null
|
|
||||||
workerScript.fnWorker = null;
|
|
||||||
return Promise.resolve(null);
|
|
||||||
}).catch(function(e) {
|
|
||||||
if (e.constructor === Array && e.length === 2 && e[0] === "RETURNSTATEMENT") {
|
|
||||||
//Return statement from function
|
|
||||||
return Promise.resolve(e[1]);
|
|
||||||
workerScript.fnWorker = null;
|
|
||||||
} else if (isString(e)) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, e));
|
|
||||||
} else if (e instanceof WorkerScript) {
|
|
||||||
//Parse out the err message from the WorkerScript and re-reject
|
|
||||||
var errorMsg = e.errorMessage;
|
|
||||||
var errorTextArray = errorMsg.split("|");
|
|
||||||
if (errorTextArray.length === 4) {
|
|
||||||
errorMsg = errorTextArray[3];
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, errorMsg));
|
|
||||||
} else {
|
|
||||||
if (env.stopFlag) {
|
|
||||||
return Promise.reject(workerScript);
|
|
||||||
} else {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Error in one of your functions. Could not identify which function"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (e instanceof Error) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, e.toString()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else if (exp.callee.type === "MemberExpression"){
|
|
||||||
return evaluate(exp.callee.object, workerScript).then(function(object) {
|
|
||||||
try {
|
|
||||||
if (func === "NETSCRIPTFOREACH") {
|
|
||||||
return evaluateForeach(object, args, workerScript).then(function(res) {
|
|
||||||
return Promise.resolve(res);
|
|
||||||
}).catch(function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
var res = func.apply(object,args);
|
|
||||||
return Promise.resolve(res);
|
|
||||||
} catch (e) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, e, exp));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
var out = func.apply(null,args);
|
|
||||||
if (out instanceof Promise){
|
|
||||||
return out.then(function(res) {
|
|
||||||
return Promise.resolve(res)
|
|
||||||
}).catch(function(e) {
|
|
||||||
if (isScriptErrorMessage(e)) {
|
|
||||||
//Functions don't have line number appended in error message, so add it
|
|
||||||
var num = getErrorLineNumber(exp, workerScript);
|
|
||||||
e += " (Line " + num + ")";
|
|
||||||
}
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return Promise.resolve(out);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
if (isScriptErrorMessage(e)) {
|
|
||||||
if (isScriptErrorMessage(e)) {
|
|
||||||
//Functions don't have line number appended in error message, so add it
|
|
||||||
var num = getErrorLineNumber(exp, workerScript);
|
|
||||||
e += " (Line " + num + ")";
|
|
||||||
}
|
|
||||||
return Promise.reject(e);
|
|
||||||
} else {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, e, exp));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case "MemberExpression":
|
|
||||||
return evaluate(exp.object, workerScript).then(function(object) {
|
|
||||||
if (exp.computed){
|
|
||||||
return evaluate(exp.property, workerScript).then(function(index) {
|
|
||||||
if (index >= object.length) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Invalid index for arrays", exp));
|
|
||||||
}
|
|
||||||
return Promise.resolve(object[index]);
|
|
||||||
}).catch(function(e) {
|
|
||||||
if (e instanceof WorkerScript || isScriptErrorMessage(e)) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
} else {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Invalid MemberExpression", exp));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (exp.property.name === "constructor") {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Illegal usage of constructor() method. If you have your own function named 'constructor', you must re-name it.", exp));
|
|
||||||
}
|
|
||||||
if (object != null && object instanceof Array && exp.property.name === "forEach") {
|
|
||||||
return "NETSCRIPTFOREACH";
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return Promise.resolve(object[exp.property.name])
|
|
||||||
} catch (e) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Failed to get property: " + e.toString(), exp));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case "LogicalExpression":
|
|
||||||
case "BinaryExpression":
|
|
||||||
return evalBinary(exp, workerScript);
|
|
||||||
break;
|
|
||||||
case "UnaryExpression":
|
|
||||||
return evalUnary(exp, workerScript);
|
|
||||||
break;
|
|
||||||
case "AssignmentExpression":
|
|
||||||
return evalAssignment(exp, workerScript);
|
|
||||||
break;
|
|
||||||
case "VariableDeclaration":
|
|
||||||
return evalVariableDeclaration(exp, workerScript);
|
|
||||||
break;
|
|
||||||
case "UpdateExpression":
|
|
||||||
if (exp.argument.type==="Identifier"){
|
|
||||||
if (exp.argument.name in env.vars){
|
|
||||||
if (exp.operator === "++" || exp.operator === "--") {
|
|
||||||
switch (exp.operator) {
|
|
||||||
case "++":
|
|
||||||
env.set(exp.argument.name,env.get(exp.argument.name)+1);
|
|
||||||
break;
|
|
||||||
case "--":
|
|
||||||
env.set(exp.argument.name,env.get(exp.argument.name)-1);
|
|
||||||
break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
return Promise.resolve(env.get(exp.argument.name));
|
|
||||||
}
|
|
||||||
//Not sure what prefix UpdateExpressions there would be besides ++/--
|
|
||||||
if (exp.prefix){
|
|
||||||
return Promise.resolve(env.get(exp.argument.name))
|
|
||||||
}
|
|
||||||
switch (exp.operator){
|
|
||||||
default:
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Unrecognized token: " + exp.type + ". You are trying to use code that is currently unsupported", exp));
|
|
||||||
}
|
|
||||||
return Promise.resolve(env.get(exp.argument.name))
|
|
||||||
} else {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "variable " + exp.argument.name + " not defined", exp));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "argument must be an identifier", exp));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "EmptyStatement":
|
|
||||||
return Promise.resolve(false);
|
|
||||||
break;
|
|
||||||
case "ReturnStatement":
|
|
||||||
return evaluate(exp.argument, workerScript).then(function(res) {
|
|
||||||
return Promise.reject(["RETURNSTATEMENT", res]);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case "BreakStatement":
|
|
||||||
return Promise.reject("BREAKSTATEMENT");
|
|
||||||
break;
|
|
||||||
case "ContinueStatement":
|
|
||||||
return Promise.reject("CONTINUESTATEMENT");
|
|
||||||
break;
|
|
||||||
case "IfStatement":
|
|
||||||
return evaluateIf(exp, workerScript);
|
|
||||||
break;
|
|
||||||
case "SwitchStatement":
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Switch statements are not yet implemented in Netscript", exp));
|
|
||||||
break;
|
|
||||||
case "WhileStatement":
|
|
||||||
return evaluateWhile(exp, workerScript).then(function(res) {
|
|
||||||
return Promise.resolve(res);
|
|
||||||
}).catch(function(e) {
|
|
||||||
if (e == "BREAKSTATEMENT" ||
|
|
||||||
(e instanceof WorkerScript && e.errorMessage == "BREAKSTATEMENT")) {
|
|
||||||
return Promise.resolve("whileLoopBroken");
|
|
||||||
} else {
|
|
||||||
return Promise.reject(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case "ForStatement":
|
|
||||||
return evaluate(exp.init, workerScript).then(function(expInit) {
|
|
||||||
return evaluateFor(exp, workerScript);
|
|
||||||
}).then(function(forLoopRes) {
|
|
||||||
return Promise.resolve("forLoopDone");
|
|
||||||
}).catch(function(e) {
|
|
||||||
if (e == "BREAKSTATEMENT" ||
|
|
||||||
(e instanceof WorkerScript && e.errorMessage == "BREAKSTATEMENT")) {
|
|
||||||
return Promise.resolve("forLoopBroken");
|
|
||||||
} else {
|
|
||||||
return Promise.reject(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case "FunctionDeclaration":
|
|
||||||
if (exp.id && exp.id.name) {
|
|
||||||
env.set(exp.id.name, exp);
|
|
||||||
return Promise.resolve(true);
|
|
||||||
} else {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Invalid function declaration", exp));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "ImportDeclaration":
|
|
||||||
return evaluateImport(exp, workerScript).then(function(res) {
|
|
||||||
return Promise.resolve(res);
|
|
||||||
}).catch(function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case "ThrowStatement":
|
|
||||||
return evaluate(exp.argument, workerScript).then(function(res) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, res));
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Unrecognized token: " + exp.type + ". This is currently unsupported in Netscript", exp));
|
|
||||||
break;
|
|
||||||
} //End switch
|
|
||||||
}).catch(function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
}); // End Promise
|
|
||||||
}
|
|
||||||
|
|
||||||
function evalBinary(exp, workerScript){
|
|
||||||
return evaluate(exp.left, workerScript).then(function(expLeft) {
|
|
||||||
//Short circuiting
|
|
||||||
if (expLeft && exp.operator === "||") {
|
|
||||||
return Promise.resolve(expLeft);
|
|
||||||
}
|
|
||||||
if (!expLeft && exp.operator === "&&") {
|
|
||||||
return Promise.resolve(expLeft);
|
|
||||||
}
|
|
||||||
return evaluate(exp.right, workerScript).then(function(expRight) {
|
|
||||||
switch (exp.operator){
|
|
||||||
case "===":
|
|
||||||
case "==":
|
|
||||||
return Promise.resolve(expLeft===expRight);
|
|
||||||
break;
|
|
||||||
case "!==":
|
|
||||||
case "!=":
|
|
||||||
return Promise.resolve(expLeft!==expRight);
|
|
||||||
break;
|
|
||||||
case "<":
|
|
||||||
return Promise.resolve(expLeft<expRight);
|
|
||||||
break;
|
|
||||||
case "<=":
|
|
||||||
return Promise.resolve(expLeft<=expRight);
|
|
||||||
break;
|
|
||||||
case ">":
|
|
||||||
return Promise.resolve(expLeft>expRight);
|
|
||||||
break;
|
|
||||||
case ">=":
|
|
||||||
return Promise.resolve(expLeft>=expRight);
|
|
||||||
break;
|
|
||||||
case "+":
|
|
||||||
return Promise.resolve(expLeft+expRight);
|
|
||||||
break;
|
|
||||||
case "-":
|
|
||||||
return Promise.resolve(expLeft-expRight);
|
|
||||||
break;
|
|
||||||
case "*":
|
|
||||||
return Promise.resolve(expLeft*expRight);
|
|
||||||
break;
|
|
||||||
case "/":
|
|
||||||
if (expRight === 0) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "ERROR: Divide by zero"));
|
|
||||||
} else {
|
|
||||||
return Promise.resolve(expLeft/expRight);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "%":
|
|
||||||
return Promise.resolve(expLeft%expRight);
|
|
||||||
break;
|
|
||||||
case "in":
|
|
||||||
return Promise.resolve(expLeft in expRight);
|
|
||||||
break;
|
|
||||||
case "instanceof":
|
|
||||||
return Promise.resolve(expLeft instanceof expRight);
|
|
||||||
break;
|
|
||||||
case "||":
|
|
||||||
return Promise.resolve(expLeft || expRight);
|
|
||||||
break;
|
|
||||||
case "&&":
|
|
||||||
return Promise.resolve(expLeft && expRight);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Unsupported operator: " + exp.operator));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function evalUnary(exp, workerScript){
|
|
||||||
var env = workerScript.env;
|
|
||||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
|
||||||
return evaluate(exp.argument, workerScript).then(function(res) {
|
|
||||||
if (exp.operator == "!") {
|
|
||||||
return Promise.resolve(!res);
|
|
||||||
} else if (exp.operator == "-") {
|
|
||||||
if (isNaN(res)) {
|
|
||||||
return Promise.resolve(res);
|
|
||||||
} else {
|
|
||||||
return Promise.resolve(-1 * res);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Unimplemented unary operator: " + exp.operator));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//Takes in a MemberExpression that should represent a Netscript array (possible multidimensional)
|
|
||||||
//The return value is an array of the form:
|
|
||||||
// [0th index (leftmost), array name, 1st index, 2nd index, ...]
|
|
||||||
function getArrayElement(exp, workerScript) {
|
|
||||||
var indices = [];
|
|
||||||
return evaluate(exp.property, workerScript).then(function(idx) {
|
|
||||||
if (isNaN(idx)) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Invalid access to array. Index is not a number: " + idx));
|
|
||||||
} else {
|
|
||||||
if (exp.object.name === undefined && exp.object.object) {
|
|
||||||
return getArrayElement(exp.object, workerScript).then(function(res) {
|
|
||||||
res.push(idx);
|
|
||||||
indices = res;
|
|
||||||
return Promise.resolve(indices);
|
|
||||||
}).catch(function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
indices.push(idx);
|
|
||||||
indices.push(exp.object.name);
|
|
||||||
return Promise.resolve(indices);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function evalAssignment(exp, workerScript) {
|
|
||||||
var env = workerScript.env;
|
|
||||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
|
||||||
|
|
||||||
if (exp.left.type != "Identifier" && exp.left.type != "MemberExpression") {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Cannot assign to " + JSON.stringify(exp.left)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exp.operator !== "=" && !(exp.left.name in env.vars)){
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "variable " + exp.left.name + " not defined"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return evaluate(exp.right, workerScript).then(function(expRight) {
|
|
||||||
if (exp.left.type == "MemberExpression") {
|
|
||||||
if (!exp.left.computed) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Cannot assign to an object's property. This is currently unsupported in Netscript", exp));
|
|
||||||
}
|
|
||||||
//Assign to array element
|
|
||||||
//Array object designed by exp.left.object.name
|
|
||||||
//Index designated by exp.left.property
|
|
||||||
return getArrayElement(exp.left, workerScript).then(function(res) {
|
|
||||||
if (!(res instanceof Array) || res.length < 2) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Error evaluating array assignment. This is (probably) a bug please report to game dev"));
|
|
||||||
}
|
|
||||||
|
|
||||||
//The array name is the second value
|
|
||||||
var arrName = res.splice(1, 1);
|
|
||||||
arrName = arrName[0];
|
|
||||||
|
|
||||||
var res;
|
|
||||||
try {
|
|
||||||
res = env.setArrayElement(arrName, res, expRight);
|
|
||||||
} catch (e) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, e));
|
|
||||||
}
|
|
||||||
return Promise.resolve(res);
|
|
||||||
}).catch(function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
//Other assignments
|
|
||||||
try {
|
|
||||||
var assign;
|
|
||||||
switch (exp.operator) {
|
|
||||||
case "=":
|
|
||||||
assign = expRight; break;
|
|
||||||
case "+=":
|
|
||||||
assign = env.get(exp.left.name) + expRight; break;
|
|
||||||
case "-=":
|
|
||||||
assign = env.get(exp.left.name) - expRight; break;
|
|
||||||
case "*=":
|
|
||||||
assign = env.get(exp.left.name) * expRight; break;
|
|
||||||
case "/=":
|
|
||||||
assign = env.get(exp.left.name) / expRight; break;
|
|
||||||
case "%=":
|
|
||||||
assign = env.get(exp.left.name) % expRight; break;
|
|
||||||
default:
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Bitwise assignment is not implemented"));
|
|
||||||
}
|
|
||||||
env.set(exp.left.name, assign);
|
|
||||||
return Promise.resolve(assign);
|
|
||||||
} catch (e) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Failed to set environment variable: " + e.toString()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function evalVariableDeclaration(exp, workerScript) {
|
|
||||||
var env = workerScript.env;
|
|
||||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
|
||||||
|
|
||||||
if (!(exp.declarations instanceof Array)) {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Variable declarations parsed incorrectly. This may be a syntax error"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exp.kind !== "var") {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Only 'var' declarations are currently allowed (let, const, etc. are not allowed)"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.all(exp.declarations.map((decl)=>{
|
|
||||||
evalVariableDeclarator(decl, workerScript);
|
|
||||||
})).then(function(res) {
|
|
||||||
return Promise.resolve(res);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//A Variable Declaration contains an array of Variable Declarators
|
|
||||||
function evalVariableDeclarator(exp, workerScript) {
|
|
||||||
var env = workerScript.env;
|
|
||||||
if (exp.type !== "VariableDeclarator") {
|
|
||||||
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Invalid AST Node passed into evalVariableDeclarator: " + exp.type));
|
|
||||||
}
|
|
||||||
if (exp.init == null) {
|
|
||||||
env.set(exp.id.name, null);
|
|
||||||
return Promise.resolve(null);
|
|
||||||
} else {
|
|
||||||
return evaluate(exp.init, workerScript).then(function(initValue) {
|
|
||||||
env.set(exp.id.name, initValue);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function evaluateIf(exp, workerScript, i) {
|
|
||||||
var env = workerScript.env;
|
|
||||||
return evaluate(exp.test, workerScript).then(function(condRes) {
|
|
||||||
if (condRes) {
|
|
||||||
return evaluate(exp.consequent, workerScript).then(function(res) {
|
|
||||||
return Promise.resolve(true);
|
|
||||||
}, function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
} else if (exp.alternate) {
|
|
||||||
return evaluate(exp.alternate, workerScript).then(function(res) {
|
|
||||||
return Promise.resolve(true);
|
|
||||||
}, function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return Promise.resolve("endIf");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//Evaluate the looping part of a for loop (Initialization block is NOT done in here)
|
|
||||||
function evaluateFor(exp, workerScript) {
|
|
||||||
var env = workerScript.env;
|
|
||||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
|
||||||
return new Promise(function(resolve, reject) {
|
|
||||||
function recurse() {
|
|
||||||
//Don't return a promise so the promise chain is broken on each recursion (saving memory)
|
|
||||||
evaluate(exp.test, workerScript).then(function(resCond) {
|
|
||||||
if (resCond) {
|
|
||||||
return evaluate(exp.body, workerScript).then(function(res) {
|
|
||||||
return evaluate(exp.update, workerScript);
|
|
||||||
}).catch(function(e) {
|
|
||||||
if (e == "CONTINUESTATEMENT" ||
|
|
||||||
(e instanceof WorkerScript && e.errorMessage == "CONTINUESTATEMENT")) {
|
|
||||||
//Continue statement, recurse to next iteration
|
|
||||||
return evaluate(exp.update, workerScript).then(function(resPostloop) {
|
|
||||||
return evaluateFor(exp, workerScript);
|
|
||||||
}).then(function(foo) {
|
|
||||||
return Promise.resolve("endForLoop");
|
|
||||||
}).catch(function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return Promise.reject(e);
|
|
||||||
}
|
|
||||||
}).then(recurse, reject).catch(function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
}).catch(function(e) {
|
|
||||||
reject(e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
recurse();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function evaluateForeach(arr, args, workerScript) {
|
|
||||||
console.log("evaluateForeach called");
|
|
||||||
if (!(arr instanceof Array)) {
|
|
||||||
return Promise.reject("Invalid array passed into forEach");
|
|
||||||
}
|
|
||||||
if (!(args instanceof Array) && args.length != 1) {
|
|
||||||
return Promise.reject("Invalid argument passed into forEach");
|
|
||||||
}
|
|
||||||
var func = args[0];
|
|
||||||
if (typeof func !== "function") {
|
|
||||||
return Promise.reject("Invalid function passed into forEach");
|
|
||||||
}
|
|
||||||
console.log(func);
|
|
||||||
return new Promise(function(resolve, reject) {
|
|
||||||
//Don't return a promise so the promise chain is broken on each recursion
|
|
||||||
function recurse(i) {
|
|
||||||
console.log("recurse() called with i: " + i);
|
|
||||||
if (i >= arr.length) {
|
|
||||||
resolve();
|
|
||||||
} else {
|
|
||||||
return Promise.delay(Settings.CodeInstructionRunTime).then(function() {
|
|
||||||
console.log("About to apply function");
|
|
||||||
var res = func.apply(null, [arr[i]]);
|
|
||||||
console.log("Applied function");
|
|
||||||
++i;
|
|
||||||
Promise.resolve(res).then(function(val) {
|
|
||||||
recurse(i);
|
|
||||||
}, reject).catch(function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
recurse(0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function evaluateWhile(exp, workerScript) {
|
|
||||||
var env = workerScript.env;
|
|
||||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
function recurse() {
|
|
||||||
//Don't return a promise so the promise chain is broken on each recursion (saving memory)
|
|
||||||
evaluate(exp.test, workerScript).then(function(resCond) {
|
|
||||||
if (resCond) {
|
|
||||||
return evaluate(exp.body, workerScript).catch(function(e) {
|
|
||||||
if (e == "CONTINUESTATEMENT" ||
|
|
||||||
(e instanceof WorkerScript && e.errorMessage == "CONTINUESTATEMENT")) {
|
|
||||||
//Continue statement, recurse
|
|
||||||
return evaluateWhile(exp, workerScript).then(function(foo) {
|
|
||||||
return Promise.resolve("endWhileLoop");
|
|
||||||
}, function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return Promise.reject(e);
|
|
||||||
}
|
|
||||||
}).then(recurse, reject).catch(function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
}).catch(function(e) {
|
|
||||||
reject(e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
recurse();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function evaluateProg(exp, workerScript, index) {
|
|
||||||
var env = workerScript.env;
|
|
||||||
if (env.stopFlag) {return Promise.reject(workerScript);}
|
|
||||||
if (index >= exp.body.length) {
|
|
||||||
return Promise.resolve("progFinished");
|
|
||||||
} else {
|
|
||||||
//Evaluate this line of code in the prog
|
|
||||||
//After the code finishes evaluating, evaluate the next line recursively
|
|
||||||
return evaluate(exp.body[index], workerScript).then(function(res) {
|
|
||||||
return evaluateProg(exp, workerScript, index + 1);
|
|
||||||
}).then(function(res) {
|
|
||||||
return Promise.resolve(workerScript);
|
|
||||||
}).catch(function(e) {
|
|
||||||
return Promise.reject(e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function evaluateImport(exp, workerScript, checkingRam=false) {
|
|
||||||
//When its checking RAM, it exports an array of nodes for each imported function
|
//When its checking RAM, it exports an array of nodes for each imported function
|
||||||
var ramCheckRes = [];
|
var ramCheckRes = [];
|
||||||
|
|
||||||
@ -808,7 +123,7 @@ function evaluateImport(exp, workerScript, checkingRam=false) {
|
|||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function killNetscriptDelay(workerScript) {
|
export function killNetscriptDelay(workerScript) {
|
||||||
if (workerScript instanceof WorkerScript) {
|
if (workerScript instanceof WorkerScript) {
|
||||||
if (workerScript.delay) {
|
if (workerScript.delay) {
|
||||||
clearTimeout(workerScript.delay);
|
clearTimeout(workerScript.delay);
|
||||||
@ -817,7 +132,7 @@ function killNetscriptDelay(workerScript) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function netscriptDelay(time, workerScript) {
|
export function netscriptDelay(time, workerScript) {
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
workerScript.delay = setTimeout(()=>{
|
workerScript.delay = setTimeout(()=>{
|
||||||
workerScript.delay = null;
|
workerScript.delay = null;
|
||||||
@ -827,7 +142,7 @@ function netscriptDelay(time, workerScript) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeRuntimeRejectMsg(workerScript, msg, exp=null) {
|
export function makeRuntimeRejectMsg(workerScript, msg, exp=null) {
|
||||||
var lineNum = "";
|
var lineNum = "";
|
||||||
if (exp != null) {
|
if (exp != null) {
|
||||||
var num = getErrorLineNumber(exp, workerScript);
|
var num = getErrorLineNumber(exp, workerScript);
|
||||||
@ -837,7 +152,7 @@ function makeRuntimeRejectMsg(workerScript, msg, exp=null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Run a script from inside a script using run() command
|
//Run a script from inside a script using run() command
|
||||||
function runScriptFromScript(server, scriptname, args, workerScript, threads=1) {
|
export function runScriptFromScript(server, scriptname, args, workerScript, threads=1) {
|
||||||
//Check if the script is already running
|
//Check if the script is already running
|
||||||
var runningScriptObj = findRunningScript(scriptname, args, server);
|
var runningScriptObj = findRunningScript(scriptname, args, server);
|
||||||
if (runningScriptObj != null) {
|
if (runningScriptObj != null) {
|
||||||
@ -887,8 +202,8 @@ function runScriptFromScript(server, scriptname, args, workerScript, threads=1)
|
|||||||
return Promise.resolve(false);
|
return Promise.resolve(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getErrorLineNumber(exp, workerScript) {
|
export function getErrorLineNumber(exp, workerScript) {
|
||||||
var code = workerScript.scriptRef.scriptRef.code;
|
var code = workerScript.scriptRef.codeCode();
|
||||||
|
|
||||||
//Split code up to the start of the node
|
//Split code up to the start of the node
|
||||||
try {
|
try {
|
||||||
@ -899,7 +214,7 @@ function getErrorLineNumber(exp, workerScript) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isScriptErrorMessage(msg) {
|
export function isScriptErrorMessage(msg) {
|
||||||
if (!isString(msg)) {return false;}
|
if (!isString(msg)) {return false;}
|
||||||
let splitMsg = msg.split("|");
|
let splitMsg = msg.split("|");
|
||||||
if (splitMsg.length != 4){
|
if (splitMsg.length != 4){
|
||||||
@ -911,6 +226,3 @@ function isScriptErrorMessage(msg) {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export {makeRuntimeRejectMsg, netscriptDelay, runScriptFromScript, evaluate,
|
|
||||||
isScriptErrorMessage, killNetscriptDelay, evaluateImport};
|
|
||||||
|
@ -51,6 +51,7 @@ import {StockMarket, StockSymbols, SymbolToStockMap,
|
|||||||
sellStock, updateStockPlayerPosition,
|
sellStock, updateStockPlayerPosition,
|
||||||
shortStock, sellShort, OrderTypes,
|
shortStock, sellShort, OrderTypes,
|
||||||
PositionTypes, placeOrder, cancelOrder} from "./StockMarket/StockMarket";
|
PositionTypes, placeOrder, cancelOrder} from "./StockMarket/StockMarket";
|
||||||
|
import {numeralWrapper} from "./ui/numeralFormat";
|
||||||
import {post} from "./ui/postToTerminal";
|
import {post} from "./ui/postToTerminal";
|
||||||
import {TextFile, getTextFile, createTextFile} from "./TextFile";
|
import {TextFile, getTextFile, createTextFile} from "./TextFile";
|
||||||
|
|
||||||
@ -72,9 +73,10 @@ import {arrayToString} from "../utils/helpers/array
|
|||||||
import {createRandomIp} from "../utils/IPAddress";
|
import {createRandomIp} from "../utils/IPAddress";
|
||||||
import {formatNumber, isHTML} from "../utils/StringHelperFunctions";
|
import {formatNumber, isHTML} from "../utils/StringHelperFunctions";
|
||||||
import {isString} from "../utils/helpers/isString";
|
import {isString} from "../utils/helpers/isString";
|
||||||
import {yesNoBoxClose, yesNoBoxGetYesButton,
|
|
||||||
yesNoBoxGetNoButton, yesNoBoxCreate,
|
import { createElement } from "../utils/uiHelpers/createElement";
|
||||||
yesNoBoxOpen} from "../utils/YesNoBox";
|
import { createPopup } from "../utils/uiHelpers/createPopup";
|
||||||
|
import { removeElementById } from "../utils/uiHelpers/removeElementById";
|
||||||
|
|
||||||
var hasCorporationSF = false, //Source-File 3
|
var hasCorporationSF = false, //Source-File 3
|
||||||
hasSingularitySF = false, //Source-File 4
|
hasSingularitySF = false, //Source-File 4
|
||||||
@ -2453,6 +2455,14 @@ function NetscriptFunctions(workerScript) {
|
|||||||
return runningScriptObj.onlineExpGained / runningScriptObj.onlineRunningTime;
|
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() {
|
getTimeSinceLastAug : function() {
|
||||||
if (workerScript.checkingRam) {
|
if (workerScript.checkingRam) {
|
||||||
return updateStaticRam("getTimeSinceLastAug", CONSTANTS.ScriptGetHackTimeRamCost);
|
return updateStaticRam("getTimeSinceLastAug", CONSTANTS.ScriptGetHackTimeRamCost);
|
||||||
@ -2462,24 +2472,33 @@ function NetscriptFunctions(workerScript) {
|
|||||||
},
|
},
|
||||||
prompt : function(txt) {
|
prompt : function(txt) {
|
||||||
if (workerScript.checkingRam) {return 0;}
|
if (workerScript.checkingRam) {return 0;}
|
||||||
if (yesNoBoxOpen) {
|
|
||||||
workerScript.scriptRef.log("ERROR: confirm() failed because a pop-up dialog box is already open");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!isString(txt)) {txt = String(txt);}
|
if (!isString(txt)) {txt = String(txt);}
|
||||||
var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton();
|
|
||||||
yesBtn.innerHTML = "Yes";
|
// The id for this popup will consist of the first 20 characters of the prompt string..
|
||||||
noBtn.innerHTML = "No";
|
// 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) {
|
return new Promise(function(resolve, reject) {
|
||||||
yesBtn.addEventListener("click", ()=>{
|
const yesBtn = createElement("button", {
|
||||||
yesNoBoxClose();
|
class: "popup-box-button",
|
||||||
resolve(true);
|
innerText: "Yes",
|
||||||
|
clickListener: () => {
|
||||||
|
removeElementById(popupId);
|
||||||
|
resolve(true);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
noBtn.addEventListener("click", ()=>{
|
|
||||||
yesNoBoxClose();
|
const noBtn = createElement("button", {
|
||||||
resolve(false);
|
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) {
|
wget : async function(url, target, ip=workerScript.serverIp) {
|
||||||
@ -4702,8 +4721,17 @@ function NetscriptFunctions(workerScript) {
|
|||||||
}
|
}
|
||||||
let data = contract.getData();
|
let data = contract.getData();
|
||||||
if (data.constructor === Array) {
|
if (data.constructor === Array) {
|
||||||
// Pass a copy
|
// For two dimensional arrays, we have to copy the internal arrays using
|
||||||
return data.slice();
|
// slice() as well. As of right now, no contract has arrays that have
|
||||||
|
// more than two dimensions
|
||||||
|
const copy = data.slice();
|
||||||
|
for (let i = 0; i < copy.length; ++i) {
|
||||||
|
if (data[i].constructor === Array) {
|
||||||
|
copy[i] = data[i].slice();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return copy;
|
||||||
} else {
|
} else {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -28,8 +28,8 @@ const walk = require("acorn/dist/walk");
|
|||||||
function WorkerScript(runningScriptObj) {
|
function WorkerScript(runningScriptObj) {
|
||||||
this.name = runningScriptObj.filename;
|
this.name = runningScriptObj.filename;
|
||||||
this.running = false;
|
this.running = false;
|
||||||
this.serverIp = null;
|
this.serverIp = runningScriptObj.server;
|
||||||
this.code = runningScriptObj.scriptRef.code;
|
this.code = runningScriptObj.getCode();
|
||||||
this.env = new Environment(this);
|
this.env = new Environment(this);
|
||||||
this.env.set("args", runningScriptObj.args.slice());
|
this.env.set("args", runningScriptObj.args.slice());
|
||||||
this.output = "";
|
this.output = "";
|
||||||
@ -219,6 +219,8 @@ function startNetscript1Script(workerScript) {
|
|||||||
let fnPromise = entry.apply(null, fnArgs);
|
let fnPromise = entry.apply(null, fnArgs);
|
||||||
fnPromise.then(function(res) {
|
fnPromise.then(function(res) {
|
||||||
cb(res);
|
cb(res);
|
||||||
|
}).catch(function(e) {
|
||||||
|
// Do nothing?
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
int.setProperty(scope, name, int.createAsyncFunction(tempWrapper));
|
int.setProperty(scope, name, int.createAsyncFunction(tempWrapper));
|
||||||
@ -278,7 +280,7 @@ function startNetscript1Script(workerScript) {
|
|||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
function runInterpreter() {
|
function runInterpreter() {
|
||||||
try {
|
try {
|
||||||
if (workerScript.env.stopFlag) {return reject(workerScript);}
|
if (workerScript.env.stopFlag) { return reject(workerScript); }
|
||||||
|
|
||||||
if (interpreter.step()) {
|
if (interpreter.step()) {
|
||||||
window.setTimeout(runInterpreter, Settings.CodeInstructionRunTime);
|
window.setTimeout(runInterpreter, Settings.CodeInstructionRunTime);
|
||||||
@ -498,7 +500,7 @@ function runScriptsLoop() {
|
|||||||
p = startNetscript2Script(workerScripts[i]);
|
p = startNetscript2Script(workerScripts[i]);
|
||||||
} else {
|
} else {
|
||||||
p = startNetscript1Script(workerScripts[i]);
|
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
|
//Once the code finishes (either resolved or rejected, doesnt matter), set its
|
||||||
@ -539,7 +541,6 @@ function runScriptsLoop() {
|
|||||||
}
|
}
|
||||||
w.running = false;
|
w.running = false;
|
||||||
w.env.stopFlag = true;
|
w.env.stopFlag = true;
|
||||||
|
|
||||||
} else if (isScriptErrorMessage(w)) {
|
} else if (isScriptErrorMessage(w)) {
|
||||||
dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer");
|
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());
|
console.log("ERROR: Evaluating workerscript returns only error message rather than WorkerScript object. THIS SHOULDN'T HAPPEN: " + w.toString());
|
||||||
@ -588,7 +589,7 @@ function addWorkerScript(runningScriptObj, server) {
|
|||||||
} else {
|
} else {
|
||||||
runningScriptObj.threads = 1;
|
runningScriptObj.threads = 1;
|
||||||
}
|
}
|
||||||
var ramUsage = roundToTwo(runningScriptObj.scriptRef.ramUsage * threads);
|
var ramUsage = roundToTwo(runningScriptObj.getRamUsage() * threads);
|
||||||
var ramAvailable = server.maxRam - server.ramUsed;
|
var ramAvailable = server.maxRam - server.ramUsed;
|
||||||
if (ramUsage > ramAvailable) {
|
if (ramUsage > ramAvailable) {
|
||||||
dialogBoxCreate("Not enough RAM to run script " + runningScriptObj.filename + " with args " +
|
dialogBoxCreate("Not enough RAM to run script " + runningScriptObj.filename + " with args " +
|
||||||
@ -601,7 +602,6 @@ function addWorkerScript(runningScriptObj, server) {
|
|||||||
|
|
||||||
//Create the WorkerScript
|
//Create the WorkerScript
|
||||||
var s = new WorkerScript(runningScriptObj);
|
var s = new WorkerScript(runningScriptObj);
|
||||||
s.serverIp = server.ip;
|
|
||||||
s.ramUsage = ramUsage;
|
s.ramUsage = ramUsage;
|
||||||
|
|
||||||
//Add the WorkerScript to the Active Scripts list
|
//Add the WorkerScript to the Active Scripts list
|
||||||
|
@ -24,6 +24,7 @@ export interface IPlayer {
|
|||||||
queuedAugmentations: IPlayerOwnedAugmentation[];
|
queuedAugmentations: IPlayerOwnedAugmentation[];
|
||||||
resleeves: Resleeve[];
|
resleeves: Resleeve[];
|
||||||
sleeves: Sleeve[];
|
sleeves: Sleeve[];
|
||||||
|
sleevesFromCovenant: number;
|
||||||
sourceFiles: IPlayerOwnedSourceFile[];
|
sourceFiles: IPlayerOwnedSourceFile[];
|
||||||
|
|
||||||
// Stats
|
// Stats
|
||||||
|
24
src/PersonObjects/IPlayerOrSleeve.ts
Normal file
24
src/PersonObjects/IPlayerOrSleeve.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// Interface that represents either the player (PlayerObject) or
|
||||||
|
// a Sleeve. Used for functions that need to take in both.
|
||||||
|
|
||||||
|
export interface IPlayerOrSleeve {
|
||||||
|
// Stats
|
||||||
|
hacking_skill: number;
|
||||||
|
strength: number;
|
||||||
|
defense: number;
|
||||||
|
dexterity: number;
|
||||||
|
agility: number;
|
||||||
|
charisma: number;
|
||||||
|
intelligence: number;
|
||||||
|
|
||||||
|
// Experience
|
||||||
|
hacking_exp: number;
|
||||||
|
strength_exp: number;
|
||||||
|
defense_exp: number;
|
||||||
|
dexterity_exp: number;
|
||||||
|
agility_exp: number;
|
||||||
|
charisma_exp: number;
|
||||||
|
|
||||||
|
// Multipliers
|
||||||
|
crime_success_mult: number;
|
||||||
|
}
|
@ -41,6 +41,7 @@ export abstract class Person {
|
|||||||
dexterity: number = 1;
|
dexterity: number = 1;
|
||||||
agility: number = 1;
|
agility: number = 1;
|
||||||
charisma: number = 1;
|
charisma: number = 1;
|
||||||
|
intelligence: number = 1;
|
||||||
hp: number = 10;
|
hp: number = 10;
|
||||||
max_hp: number = 10;
|
max_hp: number = 10;
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ export class Resleeve extends Person {
|
|||||||
console.error(`Could not find Augmentation ${this.augmentations[i].name}`);
|
console.error(`Could not find Augmentation ${this.augmentations[i].name}`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
totalAugmentationCost += aug!.baseCost;
|
totalAugmentationCost += aug!.startingCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (totalExp * CostPerExp) + (totalAugmentationCost * Math.pow(NumAugsExponent, this.augmentations.length));
|
return (totalExp * CostPerExp) + (totalAugmentationCost * Math.pow(NumAugsExponent, this.augmentations.length));
|
||||||
|
@ -184,7 +184,7 @@ export class Sleeve extends Person {
|
|||||||
this.resetTaskStatus();
|
this.resetTaskStatus();
|
||||||
return retValue;
|
return retValue;
|
||||||
}
|
}
|
||||||
if (Math.random() < crime.successRate(p)) {
|
if (Math.random() < crime.successRate(this)) {
|
||||||
// Success
|
// Success
|
||||||
const successGainRates: ITaskTracker = createTaskTracker();
|
const successGainRates: ITaskTracker = createTaskTracker();
|
||||||
|
|
||||||
|
48
src/PersonObjects/Sleeve/SleeveCovenantPurchases.ts
Normal file
48
src/PersonObjects/Sleeve/SleeveCovenantPurchases.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* Implements the purchasing of extra Duplicate Sleeves from The Covenant
|
||||||
|
*/
|
||||||
|
import { Sleeve } from "./Sleeve";
|
||||||
|
import { IPlayer } from "../IPlayer";
|
||||||
|
|
||||||
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
|
|
||||||
|
import { dialogBoxCreate } from "../../../utils/DialogBox";
|
||||||
|
import { yesNoBoxCreate,
|
||||||
|
yesNoBoxClose,
|
||||||
|
yesNoBoxGetYesButton,
|
||||||
|
yesNoBoxGetNoButton } from "../../../utils/YesNoBox";
|
||||||
|
|
||||||
|
export const MaxSleevesFromCovenant: number = 5;
|
||||||
|
|
||||||
|
export function createPurchaseSleevesFromCovenantPopup(p: IPlayer) {
|
||||||
|
if (p.sleevesFromCovenant >= MaxSleevesFromCovenant) { return; }
|
||||||
|
|
||||||
|
// First sleeve purchased costs the base amount. Then, the price of
|
||||||
|
// each successive one increases by the same amount
|
||||||
|
const baseCostPerExtraSleeve: number = 10e12;
|
||||||
|
const cost: number = (p.sleevesFromCovenant + 1) * baseCostPerExtraSleeve;
|
||||||
|
|
||||||
|
const yesBtn = yesNoBoxGetYesButton();
|
||||||
|
const noBtn = yesNoBoxGetNoButton();
|
||||||
|
|
||||||
|
yesBtn!.addEventListener("click", () => {
|
||||||
|
if (p.canAfford(cost)) {
|
||||||
|
p.loseMoney(cost);
|
||||||
|
p.sleevesFromCovenant += 1;
|
||||||
|
p.sleeves.push(new Sleeve());
|
||||||
|
yesNoBoxClose();
|
||||||
|
} else {
|
||||||
|
dialogBoxCreate("You cannot afford to purchase a Duplicate Sleeve", false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
noBtn!.addEventListener("click", () => {
|
||||||
|
yesNoBoxClose();
|
||||||
|
});
|
||||||
|
|
||||||
|
const txt = `Would you like to purchase an additional Duplicate Sleeve from The Covenant for ` +
|
||||||
|
`${numeralWrapper.formatMoney(cost)}?<br><br>` +
|
||||||
|
`These Duplicate Sleeves are permanent. You can purchase a total of 5 Duplicate ` +
|
||||||
|
`Sleeves from The Covenant`;
|
||||||
|
yesNoBoxCreate(txt);
|
||||||
|
}
|
@ -652,10 +652,12 @@ function setSleeveTask(sleeve: Sleeve, elems: ISleeveUIElems): boolean {
|
|||||||
res = sleeve.workoutAtGym(playerRef!, detailValue2, detailValue);
|
res = sleeve.workoutAtGym(playerRef!, detailValue2, detailValue);
|
||||||
break;
|
break;
|
||||||
case "Shock Recovery":
|
case "Shock Recovery":
|
||||||
|
sleeve.finishTask(playerRef!);
|
||||||
sleeve.currentTask = SleeveTaskType.Recovery;
|
sleeve.currentTask = SleeveTaskType.Recovery;
|
||||||
res = true;
|
res = true;
|
||||||
break;
|
break;
|
||||||
case "Synchronize":
|
case "Synchronize":
|
||||||
|
sleeve.finishTask(playerRef!);
|
||||||
sleeve.currentTask = SleeveTaskType.Sync;
|
sleeve.currentTask = SleeveTaskType.Sync;
|
||||||
res = true;
|
res = true;
|
||||||
break;
|
break;
|
||||||
@ -715,7 +717,7 @@ function updateSleeveTaskDescription(sleeve: Sleeve, elems: ISleeveUIElems): voi
|
|||||||
elems.taskDescription!.innerText = `This sleeve is currently doing ${detailValue2} for ${sleeve.currentTaskLocation}.`;
|
elems.taskDescription!.innerText = `This sleeve is currently doing ${detailValue2} for ${sleeve.currentTaskLocation}.`;
|
||||||
break;
|
break;
|
||||||
case "Commit Crime":
|
case "Commit Crime":
|
||||||
elems.taskDescription!.innerText = `This sleeve is currently attempting to ${Crimes[detailValue].type} (Success Rate: ${numeralWrapper.formatPercentage(Crimes[detailValue].successRate(playerRef))}).`;
|
elems.taskDescription!.innerText = `This sleeve is currently attempting to ${Crimes[detailValue].type} (Success Rate: ${numeralWrapper.formatPercentage(Crimes[detailValue].successRate(sleeve))}).`;
|
||||||
break;
|
break;
|
||||||
case "Take University Course":
|
case "Take University Course":
|
||||||
elems.taskDescription!.innerText = `This sleeve is currently studying/taking a course at ${sleeve.currentTaskLocation}.`;
|
elems.taskDescription!.innerText = `This sleeve is currently studying/taking a course at ${sleeve.currentTaskLocation}.`;
|
||||||
|
@ -34,6 +34,9 @@ import {initStockMarket, initSymbolToStockMap,
|
|||||||
stockMarketContentCreated,
|
stockMarketContentCreated,
|
||||||
setStockMarketContentCreated} from "./StockMarket/StockMarket";
|
setStockMarketContentCreated} from "./StockMarket/StockMarket";
|
||||||
import {Terminal, postNetburnerText} from "./Terminal";
|
import {Terminal, postNetburnerText} from "./Terminal";
|
||||||
|
|
||||||
|
import {Page, routing} from "./ui/navigationTracking";
|
||||||
|
|
||||||
import Decimal from "decimal.js";
|
import Decimal from "decimal.js";
|
||||||
import {dialogBoxCreate} from "../utils/DialogBox";
|
import {dialogBoxCreate} from "../utils/DialogBox";
|
||||||
import {removeElementById} from "../utils/uiHelpers/removeElementById";
|
import {removeElementById} from "../utils/uiHelpers/removeElementById";
|
||||||
@ -45,6 +48,13 @@ let BitNode8StartingMoney = 250e6;
|
|||||||
|
|
||||||
//Prestige by purchasing augmentation
|
//Prestige by purchasing augmentation
|
||||||
function prestigeAugmentation() {
|
function prestigeAugmentation() {
|
||||||
|
// Load Terminal Screen
|
||||||
|
var mainMenu = document.getElementById("mainmenu-container");
|
||||||
|
mainMenu.style.visibility = "visible";
|
||||||
|
Terminal.resetTerminalInput();
|
||||||
|
Engine.loadTerminalContent();
|
||||||
|
routing.navigateTo(Page.Terminal);
|
||||||
|
|
||||||
initBitNodeMultipliers();
|
initBitNodeMultipliers();
|
||||||
|
|
||||||
Player.prestigeAugmentation();
|
Player.prestigeAugmentation();
|
||||||
@ -146,12 +156,6 @@ function prestigeAugmentation() {
|
|||||||
var watchlist = document.getElementById("stock-market-watchlist-filter");
|
var watchlist = document.getElementById("stock-market-watchlist-filter");
|
||||||
watchlist.value = ""; //Reset 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)
|
// Refresh Main Menu (the 'World' menu, specifically)
|
||||||
document.getElementById("world-menu-header").click();
|
document.getElementById("world-menu-header").click();
|
||||||
document.getElementById("world-menu-header").click();
|
document.getElementById("world-menu-header").click();
|
||||||
|
108
src/Script.js
108
src/Script.js
@ -650,7 +650,8 @@ async function calculateRamUsage(codeCopy) {
|
|||||||
var workerScript = new WorkerScript({
|
var workerScript = new WorkerScript({
|
||||||
filename:"foo",
|
filename:"foo",
|
||||||
scriptRef: {code:""},
|
scriptRef: {code:""},
|
||||||
args:[]
|
args:[],
|
||||||
|
getCode: function() { return ""; }
|
||||||
});
|
});
|
||||||
workerScript.checkingRam = true; //Netscript functions will return RAM usage
|
workerScript.checkingRam = true; //Netscript functions will return RAM usage
|
||||||
workerScript.serverIp = currServ.ip;
|
workerScript.serverIp = currServ.ip;
|
||||||
@ -778,10 +779,9 @@ Reviver.constructors.Script = Script;
|
|||||||
//Called when the game is loaded. Loads all running scripts (from all servers)
|
//Called when the game is loaded. Loads all running scripts (from all servers)
|
||||||
//into worker scripts so that they will start running
|
//into worker scripts so that they will start running
|
||||||
function loadAllRunningScripts() {
|
function loadAllRunningScripts() {
|
||||||
var count = 0;
|
|
||||||
var total = 0;
|
var total = 0;
|
||||||
let skipScriptLoad = (window.location.href.toLowerCase().indexOf("?noscripts") !== -1);
|
let skipScriptLoad = (window.location.href.toLowerCase().indexOf("?noscripts") !== -1);
|
||||||
if (skipScriptLoad) {console.log("Skipping the load of any scripts during startup");}
|
if (skipScriptLoad) { console.info("Skipping the load of any scripts during startup"); }
|
||||||
for (var property in AllServers) {
|
for (var property in AllServers) {
|
||||||
if (AllServers.hasOwnProperty(property)) {
|
if (AllServers.hasOwnProperty(property)) {
|
||||||
var server = AllServers[property];
|
var server = AllServers[property];
|
||||||
@ -799,8 +799,6 @@ function loadAllRunningScripts() {
|
|||||||
server.runningScripts.length = 0;
|
server.runningScripts.length = 0;
|
||||||
} else {
|
} else {
|
||||||
for (var j = 0; j < server.runningScripts.length; ++j) {
|
for (var j = 0; j < server.runningScripts.length; ++j) {
|
||||||
count++;
|
|
||||||
server.runningScripts[j].scriptRef.module = "";
|
|
||||||
addWorkerScript(server.runningScripts[j], server);
|
addWorkerScript(server.runningScripts[j], server);
|
||||||
|
|
||||||
//Offline production
|
//Offline production
|
||||||
@ -809,8 +807,8 @@ function loadAllRunningScripts() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
console.log("Loaded " + count.toString() + " running scripts");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function scriptCalculateOfflineProduction(runningScriptObj) {
|
function scriptCalculateOfflineProduction(runningScriptObj) {
|
||||||
@ -827,7 +825,7 @@ function scriptCalculateOfflineProduction(runningScriptObj) {
|
|||||||
|
|
||||||
//Data map: [MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
|
//Data map: [MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
|
||||||
|
|
||||||
//Grow
|
// Grow
|
||||||
for (var ip in runningScriptObj.dataMap) {
|
for (var ip in runningScriptObj.dataMap) {
|
||||||
if (runningScriptObj.dataMap.hasOwnProperty(ip)) {
|
if (runningScriptObj.dataMap.hasOwnProperty(ip)) {
|
||||||
if (runningScriptObj.dataMap[ip][2] == 0 || runningScriptObj.dataMap[ip][2] == null) {continue;}
|
if (runningScriptObj.dataMap[ip][2] == 0 || runningScriptObj.dataMap[ip][2] == null) {continue;}
|
||||||
@ -841,6 +839,7 @@ function scriptCalculateOfflineProduction(runningScriptObj) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Money from hacking
|
||||||
var totalOfflineProduction = 0;
|
var totalOfflineProduction = 0;
|
||||||
for (var ip in runningScriptObj.dataMap) {
|
for (var ip in runningScriptObj.dataMap) {
|
||||||
if (runningScriptObj.dataMap.hasOwnProperty(ip)) {
|
if (runningScriptObj.dataMap.hasOwnProperty(ip)) {
|
||||||
@ -862,19 +861,19 @@ function scriptCalculateOfflineProduction(runningScriptObj) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Offline EXP gain
|
// Offline EXP gain
|
||||||
//A script's offline production will always be at most half of its online production.
|
// A script's offline production will always be at most half of its online production.
|
||||||
var expGain = 0.5 * (runningScriptObj.onlineExpGained / runningScriptObj.onlineRunningTime) * timePassed;
|
var expGain = 0.5 * (runningScriptObj.onlineExpGained / runningScriptObj.onlineRunningTime) * timePassed;
|
||||||
expGain *= confidence;
|
expGain *= confidence;
|
||||||
|
|
||||||
Player.gainHackingExp(expGain);
|
Player.gainHackingExp(expGain);
|
||||||
|
|
||||||
//Update script stats
|
// Update script stats
|
||||||
runningScriptObj.offlineMoneyMade += totalOfflineProduction;
|
runningScriptObj.offlineMoneyMade += totalOfflineProduction;
|
||||||
runningScriptObj.offlineRunningTime += timePassed;
|
runningScriptObj.offlineRunningTime += timePassed;
|
||||||
runningScriptObj.offlineExpGained += expGain;
|
runningScriptObj.offlineExpGained += expGain;
|
||||||
|
|
||||||
//Fortify a server's security based on how many times it was hacked
|
// Fortify a server's security based on how many times it was hacked
|
||||||
for (var ip in runningScriptObj.dataMap) {
|
for (var ip in runningScriptObj.dataMap) {
|
||||||
if (runningScriptObj.dataMap.hasOwnProperty(ip)) {
|
if (runningScriptObj.dataMap.hasOwnProperty(ip)) {
|
||||||
if (runningScriptObj.dataMap[ip][1] == 0 || runningScriptObj.dataMap[ip][1] == null) {continue;}
|
if (runningScriptObj.dataMap[ip][1] == 0 || runningScriptObj.dataMap[ip][1] == null) {continue;}
|
||||||
@ -887,7 +886,7 @@ function scriptCalculateOfflineProduction(runningScriptObj) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Weaken
|
// Weaken
|
||||||
for (var ip in runningScriptObj.dataMap) {
|
for (var ip in runningScriptObj.dataMap) {
|
||||||
if (runningScriptObj.dataMap.hasOwnProperty(ip)) {
|
if (runningScriptObj.dataMap.hasOwnProperty(ip)) {
|
||||||
if (runningScriptObj.dataMap[ip][3] == 0 || runningScriptObj.dataMap[ip][3] == null) {continue;}
|
if (runningScriptObj.dataMap[ip][3] == 0 || runningScriptObj.dataMap[ip][3] == null) {continue;}
|
||||||
@ -916,11 +915,11 @@ function findRunningScript(filename, args, server) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function RunningScript(script, args) {
|
function RunningScript(script, args) {
|
||||||
if (script == null || script == undefined) {return;}
|
if (script == null || script == undefined) { return; }
|
||||||
this.filename = script.filename;
|
this.filename = script.filename;
|
||||||
this.args = args;
|
this.args = args;
|
||||||
this.scriptRef = script;
|
|
||||||
this.server = script.server; //IP Address only
|
this.server = script.server; //IP Address only
|
||||||
|
this.ramUsage = script.ramUsage;
|
||||||
|
|
||||||
this.logs = []; //Script logging. Array of strings, with each element being a log entry
|
this.logs = []; //Script logging. Array of strings, with each element being a log entry
|
||||||
this.logUpd = false;
|
this.logUpd = false;
|
||||||
@ -935,8 +934,40 @@ function RunningScript(script, args) {
|
|||||||
|
|
||||||
this.threads = 1;
|
this.threads = 1;
|
||||||
|
|
||||||
//[MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
|
// Holds a map of all servers, where server = key and the value for each
|
||||||
this.dataMap = new AllServersMap([0, 0, 0, 0], true);
|
// server is an array of four numbers. The four numbers represent:
|
||||||
|
// [MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
|
||||||
|
// This data is used for offline progress
|
||||||
|
this.dataMap = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
RunningScript.prototype.getCode = function() {
|
||||||
|
const server = AllServers[this.server];
|
||||||
|
if (server == null) { return ""; }
|
||||||
|
for (let i = 0; i < server.scripts.length; ++i) {
|
||||||
|
if (server.scripts[i].filename === this.filename) {
|
||||||
|
return server.scripts[i].code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
RunningScript.prototype.getRamUsage = function() {
|
||||||
|
if (this.ramUsage != null && this.ramUsage > 0) { return this.ramUsage; } // Use cached value
|
||||||
|
|
||||||
|
const server = AllServers[this.server];
|
||||||
|
if (server == null) { return 0; }
|
||||||
|
for (let i = 0; i < server.scripts.length; ++i) {
|
||||||
|
if (server.scripts[i].filename === this.filename) {
|
||||||
|
// Cache the ram usage for the next call
|
||||||
|
this.ramUsage = server.scripts[i].ramUsage;
|
||||||
|
return this.ramUsage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
RunningScript.prototype.log = function(txt) {
|
RunningScript.prototype.log = function(txt) {
|
||||||
@ -966,9 +997,8 @@ RunningScript.prototype.clearLog = function() {
|
|||||||
|
|
||||||
//Update the moneyStolen and numTimesHack maps when hacking
|
//Update the moneyStolen and numTimesHack maps when hacking
|
||||||
RunningScript.prototype.recordHack = function(serverIp, moneyGained, n=1) {
|
RunningScript.prototype.recordHack = function(serverIp, moneyGained, n=1) {
|
||||||
if (this.dataMap == null) {
|
if (this.dataMap[serverIp] == null || this.dataMap[serverIp].constructor !== Array) {
|
||||||
//[MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
|
this.dataMap[serverIp] = [0, 0, 0, 0];
|
||||||
this.dataMap = new AllServersMap([0, 0, 0, 0], true);
|
|
||||||
}
|
}
|
||||||
this.dataMap[serverIp][0] += moneyGained;
|
this.dataMap[serverIp][0] += moneyGained;
|
||||||
this.dataMap[serverIp][1] += n;
|
this.dataMap[serverIp][1] += n;
|
||||||
@ -976,18 +1006,16 @@ RunningScript.prototype.recordHack = function(serverIp, moneyGained, n=1) {
|
|||||||
|
|
||||||
//Update the grow map when calling grow()
|
//Update the grow map when calling grow()
|
||||||
RunningScript.prototype.recordGrow = function(serverIp, n=1) {
|
RunningScript.prototype.recordGrow = function(serverIp, n=1) {
|
||||||
if (this.dataMap == null) {
|
if (this.dataMap[serverIp] == null || this.dataMap[serverIp].constructor !== Array) {
|
||||||
//[MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
|
this.dataMap[serverIp] = [0, 0, 0, 0];
|
||||||
this.dataMap = new AllServersMap([0, 0, 0, 0], true);
|
|
||||||
}
|
}
|
||||||
this.dataMap[serverIp][2] += n;
|
this.dataMap[serverIp][2] += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Update the weaken map when calling weaken() {
|
//Update the weaken map when calling weaken() {
|
||||||
RunningScript.prototype.recordWeaken = function(serverIp, n=1) {
|
RunningScript.prototype.recordWeaken = function(serverIp, n=1) {
|
||||||
if (this.dataMap == null) {
|
if (this.dataMap[serverIp] == null || this.dataMap[serverIp].constructor !== Array) {
|
||||||
//[MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
|
this.dataMap[serverIp] = [0, 0, 0, 0];
|
||||||
this.dataMap = new AllServersMap([0, 0, 0, 0], true);
|
|
||||||
}
|
}
|
||||||
this.dataMap[serverIp][3] += n;
|
this.dataMap[serverIp][3] += n;
|
||||||
}
|
}
|
||||||
@ -1003,33 +1031,5 @@ RunningScript.fromJSON = function(value) {
|
|||||||
|
|
||||||
Reviver.constructors.RunningScript = RunningScript;
|
Reviver.constructors.RunningScript = RunningScript;
|
||||||
|
|
||||||
//Creates an object that creates a map/dictionary with the IP of each existing server as
|
|
||||||
//a key. Initializes every key with a specified value that can either by a number or an array
|
|
||||||
function AllServersMap(arr=false, filterOwned=false) {
|
|
||||||
for (var ip in AllServers) {
|
|
||||||
if (AllServers.hasOwnProperty(ip)) {
|
|
||||||
if (filterOwned && (AllServers[ip].purchasedByPlayer || AllServers[ip].hostname === "home")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (arr) {
|
|
||||||
this[ip] = [0, 0, 0, 0];
|
|
||||||
} else {
|
|
||||||
this[ip] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AllServersMap.prototype.toJSON = function() {
|
|
||||||
return Generic_toJSON("AllServersMap", this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
AllServersMap.fromJSON = function(value) {
|
|
||||||
return Generic_fromJSON(AllServersMap, value.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
Reviver.constructors.AllServersMap = AllServersMap;
|
|
||||||
|
|
||||||
export {loadAllRunningScripts, findRunningScript,
|
export {loadAllRunningScripts, findRunningScript,
|
||||||
RunningScript, Script, AllServersMap, scriptEditorInit, isScriptFilename};
|
RunningScript, Script, scriptEditorInit, isScriptFilename};
|
||||||
|
@ -33,8 +33,10 @@ export function getPurchaseServerLimit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getPurchaseServerMaxRam() {
|
export function getPurchaseServerMaxRam() {
|
||||||
// TODO ensure this is a power of 2?
|
const ram = Math.round(CONSTANTS.PurchasedServerMaxRam * BitNodeMultipliers.PurchasedServerMaxRam);
|
||||||
return Math.round(CONSTANTS.PurchasedServerMaxRam * BitNodeMultipliers.PurchasedServerMaxRam);
|
|
||||||
|
// Round this to the nearest power of 2
|
||||||
|
return 1 << 31 - Math.clz32(ram);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manually purchase a server (NOT through Netscript)
|
// Manually purchase a server (NOT through Netscript)
|
||||||
|
@ -640,6 +640,7 @@ function processStockPrices(numCycles=1) {
|
|||||||
} else {
|
} else {
|
||||||
stock.otlkMag -= otlkMagChange;
|
stock.otlkMag -= otlkMagChange;
|
||||||
}
|
}
|
||||||
|
if (stock.otlkMag > 50) { stock.otlkMag = 50; } // Cap so the "forecast" is between 0 and 100
|
||||||
if (stock.otlkMag < 0) {
|
if (stock.otlkMag < 0) {
|
||||||
stock.otlkMag *= -1;
|
stock.otlkMag *= -1;
|
||||||
stock.b = !stock.b;
|
stock.b = !stock.b;
|
||||||
|
1061
src/Terminal.js
1061
src/Terminal.js
File diff suppressed because it is too large
Load Diff
@ -30,6 +30,14 @@ function removeBracketsFromArrayString(str: string) {
|
|||||||
return strCpy;
|
return strCpy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function removeQuotesFromString(str: string) {
|
||||||
|
let strCpy: string = str;
|
||||||
|
if (strCpy.startsWith('"') || strCpy.startsWith("'")) { strCpy = strCpy.slice(1); }
|
||||||
|
if (strCpy.endsWith('"') || strCpy.endsWith("'")) { strCpy = strCpy.slice(0, -1); }
|
||||||
|
|
||||||
|
return strCpy;
|
||||||
|
}
|
||||||
|
|
||||||
function convert2DArrayToString(arr: any[][]) {
|
function convert2DArrayToString(arr: any[][]) {
|
||||||
const components: string[] = [];
|
const components: string[] = [];
|
||||||
arr.forEach((e: any) => {
|
arr.forEach((e: any) => {
|
||||||
@ -73,7 +81,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
|||||||
desc: (n: number[]) => {
|
desc: (n: number[]) => {
|
||||||
return ["Given the following integer array, find the contiguous subarray",
|
return ["Given the following integer array, find the contiguous subarray",
|
||||||
"(containing at least one number) which has the largest sum and return that sum.",
|
"(containing at least one number) which has the largest sum and return that sum.",
|
||||||
"'Sum' refers to the sum of all the numbers in the subarray.",
|
"'Sum' refers to the sum of all the numbers in the subarray.\n",
|
||||||
`${n.toString()}`].join(" ");
|
`${n.toString()}`].join(" ");
|
||||||
},
|
},
|
||||||
difficulty: 1,
|
difficulty: 1,
|
||||||
@ -152,8 +160,8 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
|||||||
},
|
},
|
||||||
difficulty: 2,
|
difficulty: 2,
|
||||||
gen: () => {
|
gen: () => {
|
||||||
const m: number = getRandomInt(1, 10);
|
const m: number = getRandomInt(1, 15);
|
||||||
const n: number = getRandomInt(1, 10);
|
const n: number = getRandomInt(1, 15);
|
||||||
const matrix: number[][] = [];
|
const matrix: number[][] = [];
|
||||||
matrix.length = m;
|
matrix.length = m;
|
||||||
for (let i: number = 0; i < m; ++i) {
|
for (let i: number = 0; i < m; ++i) {
|
||||||
@ -493,4 +501,422 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
|||||||
return release2.toString() === ans;
|
return release2.toString() === ans;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: (data: any[]) => {
|
||||||
|
const k: number = (<number>data[0]);
|
||||||
|
const prices: number[] = (<number[]>data[1]);
|
||||||
|
return ["You are given the following array with two elements:\n\n",
|
||||||
|
`[${k}, [${prices}]]\n\n`,
|
||||||
|
"The first element is an integer k. The second element is an",
|
||||||
|
"array of stock prices (which are numbers) where the i-th element",
|
||||||
|
"represents the stock price on day i.\n\n",
|
||||||
|
"Determine the maximum possible profit you can earn using at most",
|
||||||
|
"k transactions. A transaction is defined as buying and then selling",
|
||||||
|
"one share of the stock. Note that you cannot engage in multiple",
|
||||||
|
"transactions at once. In other words, you must sell the stock before",
|
||||||
|
"you can buy it again.\n\n",
|
||||||
|
"If no profit can be made, then the answer should be 0."].join(" ");
|
||||||
|
},
|
||||||
|
difficulty: 8,
|
||||||
|
gen: () => {
|
||||||
|
const k: number = getRandomInt(2, 10);
|
||||||
|
const len: number = getRandomInt(1, 50);
|
||||||
|
const prices: number[] = [];
|
||||||
|
prices.length = len;
|
||||||
|
for (let i = 0; i < len; ++i) {
|
||||||
|
prices[i] = getRandomInt(1, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [k, prices];
|
||||||
|
},
|
||||||
|
name: "Algorithmic Stock Trader IV",
|
||||||
|
numTries: 10,
|
||||||
|
solver: (data: any[], ans: string) => {
|
||||||
|
const k: number = (<number>data[0]);
|
||||||
|
const prices: number[] = (<number[]>data[1]);
|
||||||
|
|
||||||
|
const len = prices.length;
|
||||||
|
if (len < 2) { return (parseInt(ans) === 0); }
|
||||||
|
if (k > len / 2) {
|
||||||
|
let res: number = 0;
|
||||||
|
for (let i = 1; i < len; ++i) {
|
||||||
|
res += Math.max(prices[i] - prices[i-1], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (parseInt(ans) === res);
|
||||||
|
}
|
||||||
|
|
||||||
|
const hold: number[] = [];
|
||||||
|
const rele: number[] = [];
|
||||||
|
hold.length = k + 1;
|
||||||
|
rele.length = k + 1;
|
||||||
|
for (let i = 0; i <= k; ++i) {
|
||||||
|
hold[i] = Number.MIN_SAFE_INTEGER;
|
||||||
|
rele[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cur: number;
|
||||||
|
for (let i = 0; i < len; ++i) {
|
||||||
|
cur = prices[i];
|
||||||
|
for (let j = k; j > 0; --j) {
|
||||||
|
rele[j] = Math.max(rele[j], hold[j] + cur);
|
||||||
|
hold[j] = Math.max(hold[j], rele[j-1] - cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (parseInt(ans) === rele[k]);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: (data: number[][]) => {
|
||||||
|
function createTriangleRecurse(data: number[][], level: number = 0): string {
|
||||||
|
const numLevels: number = data.length;
|
||||||
|
if (level >= numLevels) { return ""; }
|
||||||
|
const numSpaces = numLevels - level + 1;
|
||||||
|
|
||||||
|
let str: string = [" ".repeat(numSpaces), "[", data[level].toString(), "]"].join("");
|
||||||
|
if (level < numLevels - 1) {
|
||||||
|
str += ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
return str + "\n" + createTriangleRecurse(data, level+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTriangle(data: number[][]) {
|
||||||
|
return ["[\n", createTriangleRecurse(data), "]"].join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
const triangle = createTriangle(data);
|
||||||
|
|
||||||
|
return ["Given a triangle, find the minimum path sum from top to bottom. In each step",
|
||||||
|
"of the path, you may only move to adjacent numbers in the row below.",
|
||||||
|
"The triangle is represented as a 2D array of numbers:\n\n",
|
||||||
|
`${triangle}\n\n`,
|
||||||
|
"Example: If you are given the following triangle:\n\n" +
|
||||||
|
"[\n",
|
||||||
|
" [2],\n",
|
||||||
|
" [3,4],\n",
|
||||||
|
" [6,5,7],\n",
|
||||||
|
" [4,1,8,3]\n",
|
||||||
|
"]\n\n",
|
||||||
|
"The minimum path sum is 11 (2 -> 3 -> 5 -> 1)."].join(" ");
|
||||||
|
},
|
||||||
|
difficulty: 5,
|
||||||
|
gen: () => {
|
||||||
|
const triangle: number[][] = [];
|
||||||
|
const levels: number = getRandomInt(1, 12);
|
||||||
|
triangle.length = levels;
|
||||||
|
|
||||||
|
for (let row = 0; row < levels; ++row) {
|
||||||
|
triangle[row] = [];
|
||||||
|
triangle[row].length = row + 1;
|
||||||
|
for (let i = 0; i < triangle[row].length; ++i) {
|
||||||
|
triangle[row][i] = getRandomInt(1, 9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return triangle;
|
||||||
|
},
|
||||||
|
name: "Minimum Path Sum in a Triangle",
|
||||||
|
numTries: 10,
|
||||||
|
solver: (data: number[][], ans: string) => {
|
||||||
|
let n: number = data.length;
|
||||||
|
let dp: number[] = data[n-1];
|
||||||
|
for (let i = n-2; i > -1; --i) {
|
||||||
|
for (let j = 0; j < data[i].length; ++j) {
|
||||||
|
dp[j] = Math.min(dp[j], dp[j + 1]) + data[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dp[0] === parseInt(ans);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: (data: number[]) => {
|
||||||
|
const numRows = data[0];
|
||||||
|
const numColumns = data[1];
|
||||||
|
return ["You are in a grid with",
|
||||||
|
`${numRows} rows and ${numColumns} columns, and you are`,
|
||||||
|
"positioned in the top-left corner of that grid. You are trying to",
|
||||||
|
"reach the bottom-right corner of the grid, but you can only",
|
||||||
|
"move down or right on each step. Determine how many",
|
||||||
|
"unique paths there are from start to finish.\n\n",
|
||||||
|
"NOTE: The data returned for this contract is an array",
|
||||||
|
"with the number or rows and columns:\n\n",
|
||||||
|
`[${numRows}, ${numColumns}]`].join(" ");
|
||||||
|
},
|
||||||
|
difficulty: 3,
|
||||||
|
gen: () => {
|
||||||
|
const numRows: number = getRandomInt(1, 14);
|
||||||
|
const numColumns: number = getRandomInt(1, 14);
|
||||||
|
|
||||||
|
return [numRows, numColumns];
|
||||||
|
},
|
||||||
|
name: "Unique Paths in a Grid I",
|
||||||
|
numTries: 10,
|
||||||
|
solver: (data: number[], ans: string) => {
|
||||||
|
let n: number = data[0]; // Number of rows
|
||||||
|
let m: number = data[1]; // Number of columns
|
||||||
|
let currentRow: number[] = [];
|
||||||
|
currentRow.length = n;
|
||||||
|
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
currentRow[i] = 1;
|
||||||
|
}
|
||||||
|
for (let row = 1; row < m; row++) {
|
||||||
|
for (let i = 1; i < n; i++) {
|
||||||
|
currentRow[i] += currentRow[i - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parseInt(ans) === currentRow[n - 1];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: (data: number[][]) => {
|
||||||
|
let gridString: string = "";
|
||||||
|
for (const line of data) {
|
||||||
|
gridString += `${line.toString()},\n`;
|
||||||
|
}
|
||||||
|
return ["You are located in the top-left corner of the following grid:\n\n",
|
||||||
|
`${gridString}\n`,
|
||||||
|
"You are trying reach the bottom-right corner of the grid, but you can only",
|
||||||
|
"move down or right on each step. Furthermore, there are obstacles on the grid",
|
||||||
|
"that you cannot move onto. These obstacles are denoted by '1', while empty",
|
||||||
|
"spaces are denoted by 0.\n\n",
|
||||||
|
"Determine how many unique paths there are from start to finish.\n\n",
|
||||||
|
"NOTE: The data returned for this contract is an 2D array of numbers representing the grid."].join(" ");
|
||||||
|
},
|
||||||
|
difficulty: 5,
|
||||||
|
gen: () => {
|
||||||
|
const numRows: number = getRandomInt(1, 12);
|
||||||
|
const numColumns: number = getRandomInt(1, 12);
|
||||||
|
|
||||||
|
const grid: number[][] = [];
|
||||||
|
grid.length = numRows;
|
||||||
|
for (let i = 0; i < numRows; ++i) {
|
||||||
|
grid[i] = [];
|
||||||
|
grid[i].length = numColumns;
|
||||||
|
grid[i].fill(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let r = 0; r < numRows; ++r) {
|
||||||
|
for (let c = 0; c < numColumns; ++c) {
|
||||||
|
if (r === 0 && c === 0) { continue; }
|
||||||
|
if (r === numRows - 1 && c === numColumns - 1) { continue; }
|
||||||
|
|
||||||
|
// 15% chance of an element being an obstacle
|
||||||
|
if (Math.random() < 0.15) {
|
||||||
|
grid[r][c] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return grid;
|
||||||
|
},
|
||||||
|
name: "Unique Paths in a Grid II",
|
||||||
|
numTries: 10,
|
||||||
|
solver: (data: number[][], ans: string) => {
|
||||||
|
let obstacleGrid: number[][] = [];
|
||||||
|
obstacleGrid.length = data.length;
|
||||||
|
for (let i = 0; i < obstacleGrid.length; ++i) {
|
||||||
|
obstacleGrid[i] = data[i].slice();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < obstacleGrid.length; i++) {
|
||||||
|
for (let j = 0; j < obstacleGrid[0].length; j++) {
|
||||||
|
if (obstacleGrid[i][j] == 1) {
|
||||||
|
obstacleGrid[i][j] = 0;
|
||||||
|
} else if (i==0 && j==0) {
|
||||||
|
obstacleGrid[0][0] = 1;
|
||||||
|
} else {
|
||||||
|
obstacleGrid[i][j] = (i > 0 ? obstacleGrid[i-1][j] : 0) + ( j > 0 ? obstacleGrid[i][j-1] : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (obstacleGrid[obstacleGrid.length -1][obstacleGrid[0].length-1] === parseInt(ans));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: (data: string) => {
|
||||||
|
return ["Given the following string:\n\n",
|
||||||
|
`${data}\n\n`,
|
||||||
|
"remove the minimum number of invalid parentheses in order to validate",
|
||||||
|
"the string. If there are multiple minimal ways to validate the string,",
|
||||||
|
"provide all of the possible results. The answer should be provided",
|
||||||
|
"as an array of strings. If it is impossible to validate the string",
|
||||||
|
"the result should be an array with only an empty string.\n\n",
|
||||||
|
"IMPORTANT: The string may contain letters, not just parentheses.",
|
||||||
|
`Examples:\n`,
|
||||||
|
`"()())()" -> ["()()()", "(())()"]\n`,
|
||||||
|
`"(a)())()" -> ["(a)()()", "(a())()"]\n`,
|
||||||
|
`")( -> [""]`].join(" ");
|
||||||
|
},
|
||||||
|
difficulty: 10,
|
||||||
|
gen: () => {
|
||||||
|
const len: number = getRandomInt(2, 20);
|
||||||
|
let chars: string[] = [];
|
||||||
|
chars.length = len;
|
||||||
|
|
||||||
|
// 80% chance of the first parenthesis being (
|
||||||
|
Math.random() < 0.8 ? chars[0] = "(" : chars[0] = ")";
|
||||||
|
|
||||||
|
for (let i = 1; i < len; ++i) {
|
||||||
|
const roll = Math.random();
|
||||||
|
if (roll < 0.4) {
|
||||||
|
chars[i] = "(";
|
||||||
|
} else if (roll < 0.8) {
|
||||||
|
chars[i] = ")";
|
||||||
|
} else {
|
||||||
|
chars[i] = "a";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return chars.join("");
|
||||||
|
},
|
||||||
|
name: "Sanitize Parentheses in Expression",
|
||||||
|
numTries: 10,
|
||||||
|
solver: (data: string, ans: string) => {
|
||||||
|
let left = 0;
|
||||||
|
let right = 0;
|
||||||
|
let res: string[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < data.length; ++i) {
|
||||||
|
if (data[i] === '(') {
|
||||||
|
++left;
|
||||||
|
} else if (data[i] === ')') {
|
||||||
|
(left > 0) ? --left : ++right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function dfs(pair: number, index: number, left: number, right: number, s: string, solution: string, res: string[]) {
|
||||||
|
if (s.length === index) {
|
||||||
|
if (left === 0 && right === 0 && pair === 0) {
|
||||||
|
for(var i = 0; i < res.length; i++) {
|
||||||
|
if(res[i] === solution) { return; }
|
||||||
|
}
|
||||||
|
res.push(solution);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s[index] === '(') {
|
||||||
|
if (left > 0) {
|
||||||
|
dfs(pair, index + 1, left - 1, right, s, solution, res);
|
||||||
|
}
|
||||||
|
dfs(pair + 1, index + 1, left, right, s, solution + s[index], res);
|
||||||
|
} else if (s[index] === ')') {
|
||||||
|
if (right > 0) dfs(pair, index + 1, left, right - 1, s, solution, res);
|
||||||
|
if (pair > 0) dfs(pair - 1, index + 1, left, right, s, solution + s[index], res);
|
||||||
|
} else {
|
||||||
|
dfs(pair, index + 1, left, right, s, solution + s[index], res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dfs(0, 0, left, right, data, "", res);
|
||||||
|
|
||||||
|
const sanitizedPlayerAns = removeBracketsFromArrayString(ans)
|
||||||
|
.replace(/\s/g, "");
|
||||||
|
|
||||||
|
const playerAnsArray: string[] = sanitizedPlayerAns.split(",");
|
||||||
|
if (playerAnsArray.length !== res.length) { return false; }
|
||||||
|
for (const resultInAnswer of res) {
|
||||||
|
if (!playerAnsArray.includes(resultInAnswer)) { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: (data: any[]) => {
|
||||||
|
const digits: string = data[0];
|
||||||
|
const target: number = data[1];
|
||||||
|
|
||||||
|
return ["You are given the following string which contains only digits between 0 and 9:\n\n",
|
||||||
|
`${digits}\n\n`,
|
||||||
|
`You are also given a target number of ${target}. Return all possible ways`,
|
||||||
|
"you can add the +, -, and * operators to the string such that it evaluates",
|
||||||
|
"to the target number.\n\n",
|
||||||
|
"The provided answer should be an array of strings containing the valid expressions.",
|
||||||
|
"The data provided by this problem is an array with two elements. The first element",
|
||||||
|
"is the string of digits, while the second element is the target number:\n\n",
|
||||||
|
`["${digits}", ${target}]\n\n`,
|
||||||
|
"Examples:\n\n",
|
||||||
|
`Input: digits = "123", target = 6\n`,
|
||||||
|
`Output: ["1+2+3", "1*2*3"]\n\n`,
|
||||||
|
`Input: digits = "105", target = 5\n`,
|
||||||
|
`Output: ["1*0+5", "10-5"]`].join(" ");
|
||||||
|
},
|
||||||
|
difficulty: 10,
|
||||||
|
gen: () => {
|
||||||
|
const numDigits = getRandomInt(4, 12);
|
||||||
|
const digitsArray: string[] = [];
|
||||||
|
digitsArray.length = numDigits;
|
||||||
|
for (let i = 0; i < digitsArray.length; ++i) {
|
||||||
|
if (i === 0) {
|
||||||
|
digitsArray[i] = String(getRandomInt(1, 9));
|
||||||
|
} else {
|
||||||
|
digitsArray[i] = String(getRandomInt(0, 9));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const target: number = getRandomInt(-100, 100);
|
||||||
|
const digits: string = digitsArray.join("");
|
||||||
|
|
||||||
|
return [digits, target];
|
||||||
|
},
|
||||||
|
name: "Find All Valid Math Expressions",
|
||||||
|
numTries: 10,
|
||||||
|
solver: (data: any[], ans: string) => {
|
||||||
|
const num: string = data[0];
|
||||||
|
const target: number = data[1];
|
||||||
|
|
||||||
|
function helper(res: string[], path: string, num: string, target: number, pos: number, evaluated: number, multed: number) {
|
||||||
|
if (pos === num.length) {
|
||||||
|
if (target === evaluated) {
|
||||||
|
res.push(path);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = pos; i < num.length; ++i) {
|
||||||
|
if (i != pos && num[pos] == '0') { break; }
|
||||||
|
let cur = parseInt(num.substring(pos, i+1));
|
||||||
|
|
||||||
|
if (pos === 0) {
|
||||||
|
helper(res, path + cur, num, target, i + 1, cur, cur);
|
||||||
|
} else {
|
||||||
|
helper(res, path + "+" + cur, num, target, i + 1, evaluated + cur, cur);
|
||||||
|
helper(res, path + "-" + cur, num, target, i + 1, evaluated - cur, -cur);
|
||||||
|
helper(res, path + "*" + cur, num, target, i + 1, evaluated - multed + multed * cur, multed * cur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const sanitizedPlayerAns: string = removeBracketsFromArrayString(ans);
|
||||||
|
const sanitizedPlayerAnsArr: string[] = sanitizedPlayerAns.split(",");
|
||||||
|
for (let i = 0; i < sanitizedPlayerAnsArr.length; ++i) {
|
||||||
|
sanitizedPlayerAnsArr[i] = removeQuotesFromString(sanitizedPlayerAnsArr[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num == null || num.length === 0) {
|
||||||
|
if (sanitizedPlayerAnsArr.length === 0) { return true; }
|
||||||
|
if (sanitizedPlayerAnsArr.length === 1 && sanitizedPlayerAnsArr[0] === "") { return true; }
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let result: string[] = [];
|
||||||
|
helper(result, "", num, target, 0, 0, 0);
|
||||||
|
|
||||||
|
for (const expr of result) {
|
||||||
|
if (!sanitizedPlayerAnsArr.includes(expr)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
@ -1032,7 +1032,6 @@ const Engine = {
|
|||||||
//is necessary and then resets the counter
|
//is necessary and then resets the counter
|
||||||
checkCounters: function() {
|
checkCounters: function() {
|
||||||
if (Engine.Counters.autoSaveCounter <= 0) {
|
if (Engine.Counters.autoSaveCounter <= 0) {
|
||||||
saveObject.saveGame(indexedDb);
|
|
||||||
if (Settings.AutosaveInterval == null) {
|
if (Settings.AutosaveInterval == null) {
|
||||||
Settings.AutosaveInterval = 60;
|
Settings.AutosaveInterval = 60;
|
||||||
}
|
}
|
||||||
@ -1040,6 +1039,7 @@ const Engine = {
|
|||||||
Engine.Counters.autoSaveCounter = Infinity;
|
Engine.Counters.autoSaveCounter = Infinity;
|
||||||
} else {
|
} else {
|
||||||
Engine.Counters.autoSaveCounter = Settings.AutosaveInterval * 5;
|
Engine.Counters.autoSaveCounter = Settings.AutosaveInterval * 5;
|
||||||
|
saveObject.saveGame(indexedDb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,12 +8,16 @@ export function post(input: string) {
|
|||||||
postContent(input);
|
postContent(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function postError(input: string) {
|
||||||
|
postContent(`ERROR: ${input}`, { color: "#ff2929" });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds some output to the terminal with an identifier of "hack-progress-bar"
|
* Adds some output to the terminal with an identifier of "hack-progress-bar"
|
||||||
* @param input Text or HTML to output to the terminal
|
* @param input Text or HTML to output to the terminal
|
||||||
*/
|
*/
|
||||||
export function hackProgressBarPost(input: string) {
|
export function hackProgressBarPost(input: string) {
|
||||||
postContent(input, "hack-progress-bar");
|
postContent(input, { id: "hack-progress-bar" });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -21,14 +25,19 @@ export function hackProgressBarPost(input: string) {
|
|||||||
* @param input Text or HTML to output to the terminal
|
* @param input Text or HTML to output to the terminal
|
||||||
*/
|
*/
|
||||||
export function hackProgressPost(input: string) {
|
export function hackProgressPost(input: string) {
|
||||||
postContent(input, "hack-progress");
|
postContent(input, { id: "hack-progress" });
|
||||||
}
|
}
|
||||||
|
|
||||||
function postContent(input: string, id?: string) {
|
interface IPostContentConfig {
|
||||||
|
id?: string; // Replaces class, if specified
|
||||||
|
color?: string; // Additional class for terminal-line. Does NOT replace
|
||||||
|
}
|
||||||
|
|
||||||
|
function postContent(input: string, config: IPostContentConfig = {}) {
|
||||||
// tslint:disable-next-line:max-line-length
|
// tslint:disable-next-line:max-line-length
|
||||||
const style: string = `color: var(--my-font-color); background-color:var(--my-background-color);${id === undefined ? " white-space:pre-wrap;" : ""}`;
|
const style: string = `color: ${config.color != null ? config.color : "var(--my-font-color)"}; background-color:var(--my-background-color);${config.id === undefined ? " white-space:pre-wrap;" : ""}`;
|
||||||
// tslint:disable-next-line:max-line-length
|
// tslint:disable-next-line:max-line-length
|
||||||
const content: string = `<tr class="posted"><td ${id === undefined ? 'class="terminal-line"' : `id="${id}"`} style="${style}">${input}</td></tr>`;
|
const content: string = `<tr class="posted"><td ${config.id === undefined ? `class="terminal-line"` : `id="${config.id}"`} style="${style}">${input}</td></tr>`;
|
||||||
const inputElement: HTMLElement = getElementById("terminal-input");
|
const inputElement: HTMLElement = getElementById("terminal-input");
|
||||||
inputElement.insertAdjacentHTML("beforebegin", content);
|
inputElement.insertAdjacentHTML("beforebegin", content);
|
||||||
scrollTerminalToBottom();
|
scrollTerminalToBottom();
|
||||||
|
@ -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
|
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"
|
e.g. 10000 -> "10 seconds"
|
||||||
120000 -> "0 0 hours 2 minutes and 0 seconds"
|
120000 -> "2 minutes and 0 seconds"
|
||||||
*/
|
*/
|
||||||
function convertTimeMsToTimeElapsedString(time: number): string {
|
function convertTimeMsToTimeElapsedString(time: number): string {
|
||||||
const millisecondsPerSecond: number = 1000;
|
const millisecondsPerSecond: number = 1000;
|
||||||
|
@ -1,6 +1,19 @@
|
|||||||
/**
|
/**
|
||||||
* Returns the input array as a comma separated string.
|
* 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<T>(a: T[]) {
|
export function arrayToString<T>(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(", ")}]`;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ export const KEY: IMap<number> = {
|
|||||||
DOWNARROW: 40,
|
DOWNARROW: 40,
|
||||||
E: 69,
|
E: 69,
|
||||||
ENTER: 13,
|
ENTER: 13,
|
||||||
|
ESC: 27,
|
||||||
F: 70,
|
F: 70,
|
||||||
H: 72,
|
H: 72,
|
||||||
J: 74,
|
J: 74,
|
||||||
|
@ -13,8 +13,6 @@ interface ICreatePopupCloseButtonOptions {
|
|||||||
export function createPopupCloseButton(popup: Element | string, options: ICreatePopupCloseButtonOptions) {
|
export function createPopupCloseButton(popup: Element | string, options: ICreatePopupCloseButtonOptions) {
|
||||||
let button: HTMLButtonElement;
|
let button: HTMLButtonElement;
|
||||||
|
|
||||||
// TODO event listener works with escape. Add and remove event listener
|
|
||||||
// from document
|
|
||||||
function closePopupWithEscFn(e: any): void {
|
function closePopupWithEscFn(e: any): void {
|
||||||
if (e.keyCode === 27) {
|
if (e.keyCode === 27) {
|
||||||
button.click();
|
button.click();
|
||||||
|
Loading…
Reference in New Issue
Block a user