Added ability to pass arguments into scripts

This commit is contained in:
Daniel Xie 2017-06-16 21:53:57 -05:00
parent 7d6a94d7a1
commit 36eb7608d5
12 changed files with 586 additions and 499 deletions

@ -117,7 +117,12 @@ function addActiveScriptsItem(workerscript) {
} }
//Create the element itself. Each element is an accordion collapsible //Create the element itself. Each element is an accordion collapsible
var itemName = "active-scripts-" + server.hostname + "-" + workerscript.name; var itemNameArray = ["active", "scripts", server.hostname, workerscript.name];
for (var i = 0; i < workerscript.args.length; ++i) {
itemNameArray.push(workerscript.args[i].toString());
}
var itemName = itemNameArray.join("-");
//var itemName = "active-scripts-" + server.hostname + "-" + workerscript.name;
var item = document.createElement("li"); var item = document.createElement("li");
item.setAttribute("id", itemName); item.setAttribute("id", itemName);
@ -147,7 +152,12 @@ function deleteActiveScriptsItem(workerscript) {
console.log("ERROR: Invalid server IP for workerscript."); console.log("ERROR: Invalid server IP for workerscript.");
return; return;
} }
var itemName = "active-scripts-" + server.hostname + "-" + workerscript.name; var itemNameArray = ["active", "scripts", server.hostname, workerscript.name];
for (var i = 0; i < workerscript.args.length; ++i) {
itemNameArray.push(workerscript.args[i].toString());
}
var itemName = itemNameArray.join("-");
//var itemName = "active-scripts-" + server.hostname + "-" + workerscript.name;
var li = document.getElementById(itemName); var li = document.getElementById(itemName);
if (li == null) { if (li == null) {
console.log("could not find Active scripts li element for: " + workerscript.name); console.log("could not find Active scripts li element for: " + workerscript.name);
@ -174,7 +184,12 @@ function updateActiveScriptsItemContent(workerscript) {
console.log("ERROR: Invalid server IP for workerscript."); console.log("ERROR: Invalid server IP for workerscript.");
return; return;
} }
var itemName = "active-scripts-" + server.hostname + "-" + workerscript.name; var itemNameArray = ["active", "scripts", server.hostname, workerscript.name];
for (var i = 0; i < workerscript.args.length; ++i) {
itemNameArray.push(workerscript.args[i].toString());
}
var itemName = itemNameArray.join("-");
//var itemName = "active-scripts-" + server.hostname + "-" + workerscript.name;
var itemContent = document.getElementById(itemName + "-content") var itemContent = document.getElementById(itemName + "-content")
//Clear the item //Clear the item
@ -190,7 +205,8 @@ function createActiveScriptsText(workerscript, item) {
var itemText = document.createElement("p"); var itemText = document.createElement("p");
//Server ip/hostname //Server ip/hostname
var serverIpHostname = "Threads: " + workerscript.scriptRef.threads; var threads = "Threads: " + workerscript.scriptRef.threads;
var args = "Args: " + printArray(workerscript.args);
//Online //Online
var onlineTotalMoneyMade = "Total online production: $" + formatNumber(workerscript.scriptRef.onlineMoneyMade, 2); var onlineTotalMoneyMade = "Total online production: $" + formatNumber(workerscript.scriptRef.onlineMoneyMade, 2);
@ -210,7 +226,7 @@ function createActiveScriptsText(workerscript, item) {
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, "&nbsp;"); var offlineEpsText = (Array(26).join(" ") + formatNumber(offlineEps, 4) + " hacking exp/second").replace( / /g, "&nbsp;");
itemText.innerHTML = serverIpHostname + "<br>" + onlineTotalMoneyMade + "<br>" + onlineTotalExpEarned + "<br>" + itemText.innerHTML = threads + "<br>" + args + "<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>";

@ -1411,7 +1411,7 @@ initAugmentations = function() {
"<br><br>This augmentation: <br>" + "<br><br>This augmentation: <br>" +
"Increases the player's strength and defense by 20%<br>" + "Increases the player's strength and defense by 20%<br>" +
"Increases the player's crime success rate by 10%<br>" + "Increases the player's crime success rate by 10%<br>" +
"Increases thea mount of money the player gains from crimes by 10%"); "Increases the amount of money the player gains from crimes by 10%");
BrachiBlades.setRequirements(5000, 18000000); BrachiBlades.setRequirements(5000, 18000000);
BrachiBlades.addToFactions(["The Syndicate"]); BrachiBlades.addToFactions(["The Syndicate"]);
if (augmentationExists(AugmentationNames.BrachiBlades)) { if (augmentationExists(AugmentationNames.BrachiBlades)) {

@ -150,33 +150,33 @@ CONSTANTS = {
CrimeHeist: "pull off the ultimate heist", CrimeHeist: "pull off the ultimate heist",
//Text that is displayed when the 'help' command is ran in Terminal //Text that is displayed when the 'help' command is ran in Terminal
HelpText: 'alias [name="value"] Create aliases for Terminal commands, or list existing aliases<br>' + HelpText: 'alias [name="value"] Create aliases for Terminal commands, or list existing aliases<br>' +
"analyze Get statistics and information about current machine <br>" + "analyze Get statistics and information about current machine <br>" +
"cat [message] Display a .msg file<br>" + "cat [message] Display a .msg file<br>" +
"check [script] Print script logs to Terminal<br>" + "check [script] [args...] Print logs to Terminal for the script with the specified name and arguments<br>" +
"clear Clear all text on the terminal <br>" + "clear Clear all text on the terminal <br>" +
"cls See 'clear' command <br>" + "cls See 'clear' command <br>" +
"connect [ip/hostname] Connects to the machine given by its IP or hostname <br>" + "connect [ip/hostname] Connects to the machine given by its IP or hostname <br>" +
"free Check the machine's memory (RAM) usage<br>" + "free Check the machine's memory (RAM) usage<br>" +
"hack Hack the current machine<br>" + "hack Hack the current machine<br>" +
"help Display this help text<br>" + "help Display this help text<br>" +
"home Connect to home computer<br>" + "home Connect to home computer<br>" +
"hostname Displays the hostname of the machine<br>" + "hostname Displays the hostname of the machine<br>" +
"ifconfig Displays the IP address of the machine<br>" + "ifconfig Displays the IP address of the machine<br>" +
"kill [script] Stops a script that is running on the current machine<br>" + "kill [script] [args...] Stops a script on the current server with the specified name and arguments<br>" +
"killall Stops all running scripts on the current machine<br>" + "killall Stops all running scripts on the current machine<br>" +
"ls Displays all programs and scripts on the machine<br>" + "ls Displays all programs and scripts on the machine<br>" +
"mem [script] [-t] [n] Displays the amount of RAM the script requires to run with n threads<br>" + "mem [script] [-t] [n] Displays the amount of RAM the script requires to run with n threads<br>" +
"nano [script] Text editor - Open up and edit a script<br>" + "nano [script] Text editor - Open up and edit a script<br>" +
"ps Display all scripts that are currently running<br>" + "ps Display all scripts that are currently running<br>" +
"rm Delete a script/program from the machine. (WARNING: Permanent)<br>" + "rm Delete a script/program from the machine. (WARNING: Permanent)<br>" +
"run [name] [-t] [n] Execute a program or a script with n threads<br>" + "run [name] [-t] [n] [args...] Execute a program or a script with n threads and the specified arguments<br>" +
"scan Displays all available network connections<br>" + "scan Displays all available network connections<br>" +
"scan-analyze [depth] Displays hacking-related information for all servers up to <i>depth</i> nodes away<br>" + "scan-analyze [depth] Displays hacking-related information for all servers up to <i>depth</i> nodes away<br>" +
"scp [script] [server] Copies a script to a destination server (specified by ip or hostname)<br>" + "scp [script] [server] Copies a script to a destination server (specified by ip or hostname)<br>" +
"sudov Shows whether or not you have root access on this computer<br>" + "sudov Shows whether or not you have root access on this computer<br>" +
"tail [script] Display script logs (logs contain details about active scripts)<br>" + "tail [script] [args...] Display dynamic logs for the script with the specified name and arguments<br>" +
"top Display all running scripts and their RAM usage<br>", "top Display all running scripts and their RAM usage<br>",
/* Tutorial related things */ /* Tutorial related things */
TutorialGettingStartedText: "Todo...", TutorialGettingStartedText: "Todo...",
@ -249,16 +249,30 @@ CONSTANTS = {
"syntax will vary a little bit. </strong> <br><br>" + "syntax will vary a little bit. </strong> <br><br>" +
"Running a script requires RAM. The more complex a script is, the more RAM " + "Running a script requires RAM. The more complex a script is, the more RAM " +
"it requires to run. Scripts can be run on any server you have root access to. <br><br>" + "it requires to run. Scripts can be run on any server you have root access to. <br><br>" +
"Here are some Terminal commands that are useful when working with scripts: <br>" + "Here are some Terminal commands that are useful when working with scripts: <br><br>" +
"free - Shows the current server's RAM usage and availability <br>" + "<i>check [script] [args...]</i><br>Prints the logs of the script specified by the name and arguments to Terminal. Arguments should be separated " +
"kill [script] - Stops a script that is running <br>" + "by a space. Note that scripts are uniquely " +
"mem [script] [-t] [n] - Check how much RAM a script requires to run with n threads<br>" + "identified by their arguments as well as their name. For example, if you ran a script 'foo.script' with the argument 'foodnstuff' then in order to 'check' it you must " +
"nano [script] - Create/Edit a script <br>" + "also add the 'foodnstuff' argument to the check command as so: <br>check foo.script foodnstuff<br><br>" +
"ps - Displays all scripts that are actively running on the current server<br>" + "<i>free</i><br>Shows the current server's RAM usage and availability <br><br>" +
"rm [script] - Delete a script<br>" + "<i>kill [script] [args...]</i><br>Stops a script that is running with the specified script name and arguments. " +
"run [script] [-t] [n] - Run a script with n threads<br>" + "Arguments should be separated by a space. Note that " +
"tail [script] - Displays a script's logs<br>" + "scripts are uniquely identified by their arguments as well as their name. For example, if you ran a script 'foo.script' with the " +
"top - Displays all active scripts and their RAM usage <br><br>" + "argument 1 and 2, then just typing 'kill foo.script' will not work. You have to use 'kill foo.script 1 2'. <br><br>" +
"<i>mem [script] [-t] [n]</i><br>Check how much RAM a script requires to run with n threads<br><br>" +
"<i>nano [script]</i><br>Create/Edit a script. The name of the script must end with the '.script' extension <br><br>" +
"<i>ps</i><br>Displays all scripts that are actively running on the current server<br><br>" +
"<i>rm [script]</i><br>Delete a script<br><br>" +
"<i>run [script] [-t] [n] [args...]</i><br>Run a script with n threads and the specified arguments. Each argument should be separated by a space. " +
"Both the arguments and thread specification are optional. If neither are specified, then the script will be run single-threaded with no arguments.<br>" +
"Examples:<br>run foo.script<br>The command above will run 'foo.script' single-threaded with no arguments." +
"<br>run foo.script -t 10<br>The command above will run 'foo.script' with 10 threads and no arguments." +
"<br>run foo.script foodnstuff sigma-cosmetics 10<br>The command above will run 'foo.script' single-threaded with three arguments: [foodnstuff, sigma-cosmetics, 10]" +
"<br>run foo.script -t 50 foodnstuff<br>The command above will run 'foo.script' with 50 threads and a single argument: [foodnstuff]<br><br>" +
"<i>tail [script] [args...]</i><br>Displays the logs of the script specified by the name and arguments. Note that scripts are uniquely " +
"identified by their arguments as well as their name. For example, if you ran a script 'foo.script' with the argument 'foodnstuff' then in order to 'tail' it you must " +
"also add the 'foodnstuff' argument to the tail command as so: <br>tail foo.script foodnstuff<br><br>" +
"<i>top</i><br>Displays all active scripts and their RAM usage <br><br>" +
"<u><h1> Multithreading scripts </h1></u><br>" + "<u><h1> Multithreading scripts </h1></u><br>" +
"Scripts can be multithreaded. A multithreaded script runs the script's code once in each thread. The result is that " + "Scripts can be multithreaded. A multithreaded script runs the script's code once in each thread. The result is that " +
"every call to the hack(), grow(), and weaken() Netscript functions will have its effect multiplied by the number of scripts. " + "every call to the hack(), grow(), and weaken() Netscript functions will have its effect multiplied by the number of scripts. " +
@ -319,22 +333,52 @@ CONSTANTS = {
"&nbsp;==<br>" + "&nbsp;==<br>" +
"&nbsp;!=<br><br>" + "&nbsp;!=<br><br>" +
"<u><h1> Arrays </h1></u><br>" + "<u><h1> Arrays </h1></u><br>" +
"Note: Currently arrays are fixed-size once they are declared. Eventually, functionality will be added to make these " +
"dynamic arrays. <br><br>" +
"Arrays are special container objects. Arrays can hold many values under a single name. Each value in the array " + "Arrays are special container objects. Arrays can hold many values under a single name. Each value in the array " +
"can be accessed using an index number. The following example shows how to declare an array: <br><br>" + "can be accessed using an index number. The following example shows how to declare an array: <br><br>" +
"thisIsAnArray = Array[1, 2, 3, 'bitburner!', false];<br><br>" + "thisIsAnArray = Array[1, 2, 3, 'bitburner!', false];<br><br>" +
"Note that the values in an array can be different types. To access this array we just declared, we can use the index " + "Note that the values in an array can be different types. To access this array we just declared, we can use the index " +
"operator on the array's name: <br><br>" + "operator on the array's name: <br><br>" +
"print(thisIsAnArray[0]); <br>" + "print(thisIsAnArray[0]); <br>" +
"thisIsAnArray[1] = 5<br>" + "thisIsAnArray[1] = 5;<br>" +
"thisIsAnArray[3] = 'string concatenation ' + 123<br><br>" + "thisIsAnArray[3] = 'string concatenation ' + 123;<br><br>" +
"Note that arrays are indexed starting at index 0. Using an index that is too large or less than 0 will result in an " + "Note that arrays are indexed starting at index 0. Using an index that is too large or less than 0 will result in an " +
"out of bounds runtime error. <br><br>" + "out of bounds runtime error. <br><br>" +
"If an element in an array is assigned to a value that includes a variable, then it holds a reference to that variable. " + "If an element in an array is assigned to a value that includes a variable, then it holds a reference to that variable. " +
"What this means is that if the variable changes, the array element will also change accordingly. For example:<br><br>" + "What this means is that if the variable changes, the array element will also change accordingly. For example:<br><br>" +
"x = 10;<br>testArr = Array[x];<br>print(testArr[0]);<br>x = 20;<br>print(testArr[0]);<br><br>" + "x = 10;<br>testArr = Array[x];<br>print(testArr[0]);<br>x = 20;<br>print(testArr[0]);<br><br>" +
"This code will print: <br><br>10<br>20<br><br>" + "This code will print: <br><br>10<br>20<br><br>" +
"<strong>Array functions</strong><br>" +
"Arrays have built-in functions/properties that can be used to more easily access and manipulate the containers. <br><br>"+
"<i>length/length()</i><br>Returns the number of elements in the array.<br>" +
"The example below will print out 5:<br><br>" +
"arr = Array[1, 2, 3, 4, 5];<br>print(arr.length);<br><br>" +
"<i>clear/clear()</i><br>Removes all elements from the array.<br>" +
"The example below creates an array with three strings and then uses clear to remove all of those strings. The result is that 'arr' will be " +
"an empty array.<br><br>" +
"arr = Array['str1', 'str2', 'str3'];<br>arr.clear();<br><br>" +
"<i>push(e)</i><br>Adds the element e to the end of the array.<br>" +
"The example below will create an array holding one element: the number 1. It will then push the number 2 onto the array. The result " +
"is that 'arr' will be an array of size 2 with arr[0] == 1 and arr[1] == 2<br><br>" +
"arr = Array[1];<br>arr.push(2);<br><br>" +
"<i>insert(e)</i><br>Inserts an element e into an array at a specified index. Every element in the array that is at or after " +
"the specified index is shifted down. The array must be indexed with the [] operator when using this function.<br>" +
"The following example will insert the number 2 into index 1 of the array. The result afterwards is that 'arr' will hold the values [1, 2, 3, 4].<br><br>" +
"arr = Array[1, 3, 4];<br>arr[1].insert(2);<br><br>" +
"<i>remove()</i><br>Removes an element from a specified index. Every element in the array that is after the specified index " +
"will be shifted up. The array must be indexed with the [] operator when using this function.<br>" +
"The following example will remove the first element of the array. The result afterwards is that 'arr' will hold the values [2, 3].<br><br>" +
"arr = Array[1, 2, 3];<br>arr[0].remove();<br><br>" +
"<u><h1> Script Arguments </h1></u><br>" +
"Arguments passed into a script can be accessed using a special array called 'args'. The arguments can be accessed like a normal array using the [] " +
"operator. (args[0], args[1], args[2]...) <br><br>" +
"For example, let's say we want to make a generic script 'generic-run.script' and we plan to pass two arguments into that script. The first argument will be the name of " +
"another script, and the second argument will be a number. This generic script will run the script specified in the first argument " +
"with the amount of threads specified in the second element. The code would look like:<br><br>" +
"run(args[0], args[1]);<br><br>" +
"It is also possible to get the number of arguments that was passed into a script using:<br><br>" +
"args.length<br><br>" +
"Note that none of the other functions that typically work with arrays, such as remove(), insert(), clear(), etc., will work on the " +
"args array.<br><br>" +
"<u><h1> Functions </h1></u><br>" + "<u><h1> Functions </h1></u><br>" +
"You can NOT define you own functions in Netscript (yet), but there are several built in functions that " + "You can NOT define you own functions in Netscript (yet), but there are several built in functions that " +
"you may use: <br><br> " + "you may use: <br><br> " +
@ -362,36 +406,56 @@ CONSTANTS = {
"any server, regardless of where the script is running. This command requires root access to the target server, but " + "any server, regardless of where the script is running. This command requires root access to the target server, but " +
"there is no required hacking level to run the command. Grants 3 hacking exp when it completes. Returns " + "there is no required hacking level to run the command. Grants 3 hacking exp when it completes. Returns " +
"0.1. Works offline at a slower rate<br> Example: weaken('foodnstuff');<br><br>" + "0.1. Works offline at a slower rate<br> Example: weaken('foodnstuff');<br><br>" +
"<i>print(x)</i> <br> Prints a value or a variable to the scripts logs (which can be viewed with the 'tail [script]' terminal command )<br><br>" + "<i>print(x)</i> <br> Prints a value or a variable to the scripts logs (which can be viewed with the 'tail [script]' terminal command ). <br>" +
"WARNING: Do NOT call print() on an array. The script will crash. You can, however, call print on single elements of an array. For example, if " +
"the variable 'a' is an array, then do NOT call print(a), but it is okay to call print(a[0]).<br><br>" +
"<i>nuke(hostname/ip)</i><br>Run NUKE.exe on the target server. NUKE.exe must exist on your home computer. Does NOT work while offline <br> Example: nuke('foodnstuff'); <br><br>" + "<i>nuke(hostname/ip)</i><br>Run NUKE.exe on the target server. NUKE.exe must exist on your home computer. Does NOT work while offline <br> Example: nuke('foodnstuff'); <br><br>" +
"<i>brutessh(hostname/ip)</i><br>Run BruteSSH.exe on the target server. BruteSSH.exe must exist on your home computer. Does NOT work while offline <br> Example: brutessh('foodnstuff');<br><br>" + "<i>brutessh(hostname/ip)</i><br>Run BruteSSH.exe on the target server. BruteSSH.exe must exist on your home computer. Does NOT work while offline <br> Example: brutessh('foodnstuff');<br><br>" +
"<i>ftpcrack(hostname/ip)</i><br>Run FTPCrack.exe on the target server. FTPCrack.exe must exist on your home computer. Does NOT work while offline <br> Example: ftpcrack('foodnstuff');<br><br>" + "<i>ftpcrack(hostname/ip)</i><br>Run FTPCrack.exe on the target server. FTPCrack.exe must exist on your home computer. Does NOT work while offline <br> Example: ftpcrack('foodnstuff');<br><br>" +
"<i>relaysmtp(hostname/ip)</i><br>Run relaySMTP.exe on the target server. relaySMTP.exe must exist on your home computer. Does NOT work while offline <br> Example: relaysmtp('foodnstuff');<br><br>" + "<i>relaysmtp(hostname/ip)</i><br>Run relaySMTP.exe on the target server. relaySMTP.exe must exist on your home computer. Does NOT work while offline <br> Example: relaysmtp('foodnstuff');<br><br>" +
"<i>httpworm(hostname/ip)</i><br>Run HTTPWorm.exe on the target server. HTTPWorm.exe must exist on your home computer. Does NOT work while offline <br> Example: httpworm('foodnstuff');<br><br>" + "<i>httpworm(hostname/ip)</i><br>Run HTTPWorm.exe on the target server. HTTPWorm.exe must exist on your home computer. Does NOT work while offline <br> Example: httpworm('foodnstuff');<br><br>" +
"<i>sqlinject(hostname/ip)</i><br>Run SQLInject.exe on the target server. SQLInject.exe must exist on your home computer. Does NOT work while offline <br> Example: sqlinject('foodnstuff');<br><br>" + "<i>sqlinject(hostname/ip)</i><br>Run SQLInject.exe on the target server. SQLInject.exe must exist on your home computer. Does NOT work while offline <br> Example: sqlinject('foodnstuff');<br><br>" +
"<i>run(script, [numThreads])</i> <br> Run a script as a separate process. The first argument that is passed in is the name of the script as a string. This function can only " + "<i>run(script, [numThreads], [args...])</i> <br> Run a script as a separate process. The first argument that is passed in is the name of the script as a string. This function can only " +
"be used to run scripts located on the current server (the server running the script that calls this function). The second argument " + "be used to run scripts located on the current server (the server running the script that calls this function). The second argument " +
"is optional, and it specifies how many threads to run the script with. If it is omitted, then the script will be run single-threaded. " + "is optional, and it specifies how many threads to run the script with. This argument must be a number greater than 0. If it is omitted, then the script will be run single-threaded. Any additional arguments will specify " +
"This second argument must be a number that is greater than 0. " + "arguments to pass into the new script that is being run. If arguments are specified for the new script, then the second argument numThreads argument must be filled in with a value.<br><br>" +
"Returns true if the script is successfully started, and false otherwise. Requires a significant amount " + "Returns true if the script is successfully started, and false otherwise. Requires a significant amount " +
"of RAM to run this command. Does NOT work while offline <br>Example: run('hack-foodnstuff.script'); <br> The example above will try and launch the 'hack-foodnstuff.script' script on " + "of RAM to run this command. Does NOT work while offline <br><br>" +
"the current server, if it exists. <br><br>" + "The simplest way to use the run command is to call it with just the script name. The following example will run 'foo.script' single-threaded with no arguments:<br><br>" +
"<i>exec(script, hostname/ip, [numThreads])</i><br>Run a script as a separate process on another server. The first argument is the name of the script as a string. The " + "run('foo.script');<br><br>" +
"The following example will run 'foo.script' but with 5 threads instead of single-threaded:<br><br>" +
"run('foo.script', 5);<br><br>" +
"The following example will run 'foo.script' single-threaded, and will pass the string 'foodnstuff' into the script as an argument:<br><br>" +
"run('foo.script', 1, 'foodnstuff');<br><br>" +
"<i>exec(script, hostname/ip, [numThreads], [args...])</i><br>Run a script as a separate process on another server. The first argument is the name of the script as a string. The " +
"second argument is a string with the hostname or IP of the 'target server' on which to run the script. The specified script must exist on the target server. " + "second argument is a string with the hostname or IP of the 'target server' on which to run the script. The specified script must exist on the target server. " +
"The third argument is optional, and it specifies how many threads to run the script with. If it is omitted, then the script will be run single-threaded. " + "The third argument is optional, and it specifies how many threads to run the script with. If it is omitted, then the script will be run single-threaded. " +
"This argument must be a number that is greater than 0. Returns " + "This argument must be a number that is greater than 0. Any additional arguments will specify arguments to pass into the new script that is being run. If " +
"true if the script is successfully started, and false otherwise. Does NOT work while offline<br> " + "arguments are specified for the enw script, then the third argument numThreads must be filled in with a value.<br><br>Returns " +
"Example: exec('generic-hack.script', 'foodnstuff'); <br> The example above will try to launch the script 'generic-hack.script' on the 'foodnstuff' server.<br><br>" + "true if the script is successfully started, and false otherwise. Does NOT work while offline<br><br> " +
"<i>kill(script, [hostname/ip])</i><br> Kills a script on a server. The first argument must be a string with the name of the script. The name is case-sensitive. " + "The simplest way to use the exec command is to call it with just the script name and the target server. The following example will try to run 'generic-hack.script' " +
"The second argument must be a string with the hostname or IP of the target server. The function will try to kill the specified script on the target server. " + "on the 'foodnstuff' server:<br><br>" +
"The second argument is optional. If it is omitted, then the function will try to kill the specified script on the current server (the server running " + "exec('generic-hack.script', 'foodnstuff');<br><br>" +
"the script that calls this function). If the script is found on the specified server and is running, then it will be killed and this function " + "The following example will try to run the script 'generic-hack.script' on the 'joesguns' server with 10 threads:<br><br>" +
"will return true. Otherwise, this function will return false. <br> " + "exec('generic-hack.script', 'joesguns', 10);<br><br>" +
"Example: kill('foo.script', 'foodnstuff');<br>" + "The following example will try to run the script 'foo.script' on the 'foodnstuff' server with 5 threads. It will also pass the number 1 and the string 'test' in as arguments " +
"Example: kill('foo.script');<br>" + "to the script.<br><br>" +
"The first example above will look for a script called 'foo.script' on the 'foodnstuff' server. If the script exists and is running, then it will " + "exec('foo.script', 'foodnstuff', 5, 1, 'test');<br><br>" +
"be killed and the function will return true. Otherwise false will be returned. The second example above will do the same thing, except on the " + "<i>kill(script, hostname/ip, [args...])</i><br> Kills the script on the target server specified by the script's name and arguments. Remember that " +
"current server (the server running the script that calls the kill() function).<br><br>" + "scripts are uniquely identified by both their name and arguments. For example, if 'foo.script' is run with the argument 1, then this is not the " +
"same as 'foo.script' run with the argument 2, even though they have the same code. <br><br>" +
"The first argument must be a string with the name of the script. The name is case-sensitive. " +
"The second argument must be a string with the hostname or IP of the target server. Any additional arguments to the function will specify the arguments passed " +
"into the script that should be killed. <br><br>The function will try to kill the specified script on the target server. " +
"If the script is found on the specified server and is running, then it will be killed and this function " +
"will return true. Otherwise, this function will return false. <br><br>" +
"Examples:<br>" +
"If you are trying to kill a script named 'foo.script' on the 'foodnstuff' server that was ran with no arguments, use this:<br><br>" +
"kill('foo.script', 'foodnstuff');<br><br>" +
"If you are trying to kill a script named 'foo.script' on the current server that was ran with no arguments, use this:<br><br>" +
"kill('foo.script', getHostname());<br><br>" +
"If you are trying to kill a script named 'foo.script' on the current server that was ran with the arguments 1 and 'foodnstuff', use this:<br><br>" +
"kill('foo.script', getHostname(), 1, 'foodnstuff');<br><br>" +
"<i>killall(hostname/ip)</i><br> Kills all running scripts on the specified server. This function takes a single argument which " + "<i>killall(hostname/ip)</i><br> Kills all running scripts on the specified server. This function takes a single argument which " +
"must be a string containing the hostname or IP of the target server. This function will always return true. <br><br>" + "must be a string containing the hostname or IP of the target server. This function will always return true. <br><br>" +
"<i>scp(script, hostname/ip)</i><br>Copies a script to another server. The first argument is a string with the filename of the script " + "<i>scp(script, hostname/ip)</i><br>Copies a script to another server. The first argument is a string with the filename of the script " +
@ -417,14 +481,18 @@ CONSTANTS = {
"Example: fileExists('ftpcrack.exe');<br><br>" + "Example: fileExists('ftpcrack.exe');<br><br>" +
"The first example above will return true if the script named 'foo.script' exists on the 'foodnstuff' server, and false otherwise. The second example above will " + "The first example above will return true if the script named 'foo.script' exists on the 'foodnstuff' server, and false otherwise. The second example above will " +
"return true if the current server (the server on which this function runs) contains the FTPCrack.exe program, and false otherwise. <br><br>" + "return true if the current server (the server on which this function runs) contains the FTPCrack.exe program, and false otherwise. <br><br>" +
"<i>isRunning(filename, [hostname/ip])</i><br> Returns a boolean (true or false) indicating whether the specified script is running on a server. " + "<i>isRunning(filename, hostname/ip, [args...])</i><br> Returns a boolean (true or false) indicating whether the specified script is running on a server. " +
"Remember that a script is uniquely identified by both its name and its arguments. <br><br>" +
"The first argument must be a string with the name of the script. The script name is case sensitive. The second argument is a string with the " + "The first argument must be a string with the name of the script. The script name is case sensitive. The second argument is a string with the " +
"hostname or IP of the target server. The function will check whether the script is running on that target server. The second argument is optional. " + "hostname or IP of the target server. Any additional arguments passed to the function will specify the arguments passed into the target script. " +
"If it is omitted, then the function will check if the script is running on the current server (the server running the script that calls this function). <br>" + "The function will check whether the script is running on that target server.<br>" +
"Example: isRunning('foo.script', 'foodnstuff');<br>" + "Example: isRunning('foo.script', 'foodnstuff');<br>" +
"Example: isRunning('foo.script'); <br><br>" + "Example: isRunning('foo.script', getHostname());<br>" +
"The first example above will return true if there is a script called 'foo.script' is running on the 'foodnstuff' server, and false otherwise. The second " + "Example: isRunning('foo.script', 'joesguns', 1, 5, 'test');<br><br>" +
"example above will return true if there is a script called 'foo.script' running on the current server, and false otherwise. <br><br>" + "The first example above will return true if there is a script named 'foo.script' with no arguments running on the 'foodnstuff' server, and false otherwise. The second " +
"example above will return true if there is a script named 'foo.script' with no arguments running on the current server, and false otherwise. " +
"The third example above will return true if there is a script named 'foo.script' with the arguments 1, 5, and 'test' running on the 'joesguns' server, and " +
"false otherwise.<br><br>" +
"<i>purchaseHacknetNode()</i><br> Purchases a new Hacknet Node. Returns a number with the index of the Hacknet Node. This index is equivalent to the number " + "<i>purchaseHacknetNode()</i><br> Purchases a new Hacknet Node. Returns a number with the index of the Hacknet Node. This index is equivalent to the number " +
"at the end of the Hacknet Node's name (e.g The Hacknet Node named 'hacknet-node-4' will have an index of 4). If the player cannot afford to purchase " + "at the end of the Hacknet Node's name (e.g The Hacknet Node named 'hacknet-node-4' will have an index of 4). If the player cannot afford to purchase " +
"a new Hacknet Node then the function will return false. Does NOT work offline<br><br>" + "a new Hacknet Node then the function will return false. Does NOT work offline<br><br>" +
@ -575,13 +643,25 @@ CONSTANTS = {
Changelog: Changelog:
"v0.21.0<br>" + "v0.21.0<br>" +
"-Added dynamic arrays. See Netscript documentation<br>" +
"-Added ability to pass arguments into scripts. See documentation<br>" +
"-The implementation/function signature of functions that deal with scripts have changed. Therefore, some old scripts might not " +
"work anymore. Some of these functions include run(), exec(), isRunning(), kill(), and some others I may have forgot about. " +
"Please check the updated Netscript documentation if you run into issues." +
"-Note that scripts are now uniquely identified by the script name and their arguments. For example, you can run " +
"a script using <br>run foodnstuff.script 1<br> and you can also run the same script with a different argument " +
"<br>run foodnstuff.script 2<br>These will be considered two different scripts. To kill the first script you must " +
"run <br>kill foodnstuff.script 1<br> and to kill the second you must run <br>kill foodnstuff.script 2<br> Similar concepts " +
"apply for Terminal Commands such as tail, and Netscript commands such as run(), exec(), kill(), isRunning(), etc.<br>" +
"-Added basic theme functionality - All credit goes to /u/0x726564646974 who implemented the awesome feature<br>" + "-Added basic theme functionality - All credit goes to /u/0x726564646974 who implemented the awesome feature<br>" +
"-Optimized Script objects, which were causing save errors when the player had too many scripts<br>" + "-Optimized Script objects, which were causing save errors when the player had too many scripts<br>" +
"-Formula for determining exp gained from hacking was changed<br>" +
"-Fixed bug where you could purchase Darkweb items without TOR router<br>" + "-Fixed bug where you could purchase Darkweb items without TOR router<br>" +
"-Slightly increased cost multiplier for Home Computer RAM<br>" + "-Slightly increased cost multiplier for Home Computer RAM<br>" +
"-Fixed bug where you could hack too much money from a server (and bring its money available below zero)<br>" +
"-Changed tail command so that it brings up a display box with dynamic log contents. To get " + "-Changed tail command so that it brings up a display box with dynamic log contents. To get " +
"old functionality where the logs are printed to the Terminal, use the new 'check' command<br>" + "old functionality where the logs are printed to the Terminal, use the new 'check' command<br>" +
"-A script's logs now get cleared when the script is run<br>"+ "-As a result of the change above, you can no longer call tail/check on scripts that are not running<br>" +
"-Added autocompletion for buying Programs in Darkweb<br>" + "-Added autocompletion for buying Programs in Darkweb<br>" +
"v0.20.2<br>" + "v0.20.2<br>" +
"-Fixed several small bugs<br>" + "-Fixed several small bugs<br>" +
@ -711,49 +791,25 @@ CONSTANTS = {
"-You can now see what an Augmentation does and its price even while its locked<br><br>", "-You can now see what an Augmentation does and its price even while its locked<br><br>",
LatestUpdate: LatestUpdate:
"v0.20.2<br>" + "v0.21.0<br>" +
"-Fixed several small bugs<br>" + "-Added dynamic arrays. See Netscript documentation<br>" +
"-Added basic array functionality to Netscript<br>" + "-Added ability to pass arguments into scripts. See documentation<br>" +
"-Added ability to run scripts with multiple threads. Running a script with n threads will multiply the effects of all " + "-The implementation/function signature of functions that deal with scripts have changed. Therefore, some old scripts might not " +
"hack(), grow(), and weaken() commands by n. However, running a script with multiple threads has drawbacks in terms of " + "work anymore. Some of these functions include run(), exec(), isRunning(), kill(), and some others I may have forgot about. " +
"RAM usage. A script's ram usage when it is 'multithreaded' is calculated as: base cost * numThreads * (1.02 ^ numThreads). " + "Please check the updated Netscript documentation if you run into issues." +
"A script can be run multithreaded using the 'run [script] -t n' Terminal command or by passing in an argument to the " + "-Note that scripts are now uniquely identified by the script name and their arguments. For example, you can run " +
"run() and exec() Netscript commands. See documentation.<br>" + "a script using <br>run foodnstuff.script 1<br> and you can also run the same script with a different argument " +
"-RAM is slightly (~10%) more expensive (affects purchasing server and upgrading RAM on home computer)<br>" + "<br>run foodnstuff.script 2<br>These will be considered two different scripts. To kill the first script you must " +
"-NeuroFlux Governor augmentation cost multiplier decreased<br>" + "run <br>kill foodnstuff.script 1<br> and to kill the second you must run <br>kill foodnstuff.script 2<br> Similar concepts " +
"-Netscript default operation runtime lowered to 200ms (was 500ms previously)<br><br>" + "apply for Terminal Commands such as tail, and Netscript commands such as run(), exec(), kill(), isRunning(), etc.<br>" +
"v0.20.1<br>" + "-Added basic theme functionality - All credit goes to /u/0x726564646974 who implemented the awesome feature<br>" +
"-Fixed bug where sometimes scripts would crash without showing the error<br>" + "-Optimized Script objects, which were causing save errors when the player had too many scripts<br>" +
"-Added Deepscan programs to Dark Web<br>" + "-Formula for determining exp gained from hacking was changed<br>" +
"-Declining a faction invite will stop you from receiving invitations from that faction for the rest of the run<br>" + "-Fixed bug where you could purchase Darkweb items without TOR router<br>" +
"-(BETA) Added functionality to export/import saves. WARNING This is only lightly tested. You cannot choose where to save your file " + "-Slightly increased cost multiplier for Home Computer RAM<br>" +
"it just goes to the default save location. Also I have no idea what will happen if you try to import a file " + "-Fixed bug where you could hack too much money from a server (and bring its money available below zero)<br>" +
"that is not a valid save. I will address these in later updates<br><br>" + "-Changed tail command so that it brings up a display box with dynamic log contents. To get " +
"v0.20.0<br>" + "old functionality where the logs are printed to the Terminal, use the new 'check' command<br>" +
"-Refactored Netscript Interpreter code. Operations in Netscript should now run significantly faster (Every operation " + "-As a result of the change above, you can no longer call tail/check on scripts that are not running<br>" +
"such as a variable assignment, a function call, a binary operator, getting a variable's value, etc. used to take up to several seconds, " + "-Added autocompletion for buying Programs in Darkweb<br>",
"now each one should only take ~500 milliseconds). <br><br>" +
"-Percentage money stolen when hacking lowered to compensate for faster script speeds<br><br>" +
"-Hacking experience granted by grow() halved<br><br>" +
"-Weaken() is now ~11% faster, but only grants 3 base hacking exp upon completion instead of 5 <br><br>" +
"-Rebalancing of script RAM costs. Base RAM Cost for a script increased from 1GB to 1.5GB. Loops, hack(), grow() " +
"and weaken() all cost slightly less RAM than before <br><br>" +
"-Added getServerRequiredHackingLevel(server) Netscript command. <br><br>" +
"-Added fileExists(file, [server]) Netscript command, which is used to check if a script/program exists on a " +
"specified server<br><br>" +
"-Added isRunning(script, [server]) Netscript command, which is used to check if a script is running on the specified server<br><br>" +
"-Added killall Terminal command. Kills all running scripts on the current machine<br><br>" +
"-Added kill() and killall() Netscript commands. Used to kill scripts on specified machines. See Netscript documentation<br><br>" +
"-Re-designed 'Active Scripts' tab<br><br>" +
"-Hacknet Node base production rate lowered from 1.6 to 1.55 ($/second)<br><br>" +
"-Increased monetary cost of RAM (Upgrading home computer and purchasing servers will now be more expensive)<br><br>" +
"-NEW GROWTH MECHANICS - The rate of growth on a server now depends on a server's security level. A higher security level " +
"will result in lower growth on a server when using the grow() command. Furthermore, calling grow() on a server raises that " +
"server's security level by 0.004. For reference, if a server has a security level of 10 " +
"it will have approximately the same growth rate as before. <br><br>" +
"-Server growth no longer happens naturally<br><br>" +
"-Servers now have a maximum limit to their money. This limit is 50 times it's starting money<br><br>" +
"-Hacking now grants 10% less hacking experience<br><br>" +
"-You can now edit scripts that are running<br><br>" +
"-Augmentations cost ~11% more money and 25% more faction reputation<br><br>",
} }

@ -28,6 +28,26 @@ function evaluate(exp, workerScript) {
reject(e); reject(e);
}); });
return; return;
} else if (exp.value == "args") {
if (exp.index) {
var iPromise = evaluate(exp.index.value, workerScript);
iPromise.then(function(i) {
if (isNaN(i)) {
reject(makeRuntimeRejectMsg(workerScript, "Invalid access to args array. Index is not a number: " + i));
} else if (i >= workerScript.args.length || i < 0) {
reject(makeRuntimeRejectMsg(workerScript, "Out of bounds: Invalid index in [] operator"));
} else {
resolve(workerScript.args[i]);
}
}, function(e) {
reject(e);
});
} else if (exp.op && exp.op.type == "var" && exp.op.value == "length") {
resolve(workerScript.args.length);
} else {
reject(makeRuntimeRejectMsg(workerScript, "Invalid access to args array"));
}
return;
} else if (exp.value == "array") { } else if (exp.value == "array") {
//A raw array. This will be called under something like this: //A raw array. This will be called under something like this:
// x = Array[1, 2, 3]; // x = Array[1, 2, 3];
@ -243,8 +263,8 @@ function evaluate(exp, workerScript) {
reject(e); reject(e);
}); });
} else if (exp.func.value == "run") { } else if (exp.func.value == "run") {
if (exp.args.length != 1 && exp.args.length != 2) { if (exp.args.length < 1) {
return reject(makeRuntimeRejectMsg(workerScript, "run() call has incorrect number of arguments. Takes 1 or 2 arguments")); return reject(makeRuntimeRejectMsg(workerScript, "run() call has incorrect number of arguments. Usage: run(scriptname, [numThreads], [arg1], [arg2]...)"));
} }
var argPromises = exp.args.map(function(arg) { var argPromises = exp.args.map(function(arg) {
return evaluate(arg, workerScript); return evaluate(arg, workerScript);
@ -254,9 +274,14 @@ function evaluate(exp, workerScript) {
if (env.stopFlag) {return reject(workerScript);} if (env.stopFlag) {return reject(workerScript);}
var scriptname = args[0]; var scriptname = args[0];
var threads = 1; var threads = 1;
if (exp.args.length == 2) { if (exp.args.length >= 2) {
threads = args[1]; threads = args[1];
} }
var argsForNewScript = [];
for (var i = 2; i < exp.args.length; ++i) {
argsForNewScript.push(args[i]);
}
if (isNaN(threads) || threads < 1) { if (isNaN(threads) || threads < 1) {
return reject(makeRuntimeRejectMsg(workerScript, "Invalid argument for thread count passed into run(). Must be numeric and greater than 0")); return reject(makeRuntimeRejectMsg(workerScript, "Invalid argument for thread count passed into run(). Must be numeric and greater than 0"));
} }
@ -265,7 +290,7 @@ function evaluate(exp, workerScript) {
return reject(makeRuntimeRejectMsg(workerScript, "Could not find server. This is a bug in the game. Report to game dev")); return reject(makeRuntimeRejectMsg(workerScript, "Could not find server. This is a bug in the game. Report to game dev"));
} }
var runScriptPromise = runScriptFromScript(scriptServer, scriptname, workerScript, threads); var runScriptPromise = runScriptFromScript(scriptServer, scriptname, argsForNewScript, workerScript, threads);
return runScriptPromise; return runScriptPromise;
}).then(function(res) { }).then(function(res) {
resolve(res); resolve(res);
@ -273,8 +298,8 @@ function evaluate(exp, workerScript) {
reject(e); reject(e);
}); });
} else if (exp.func.value == "exec") { } else if (exp.func.value == "exec") {
if (exp.args.length != 2 && exp.args.length != 3) { if (exp.args.length < 2) {
return reject(makeRuntimeRejectMsg(workerScript, "exec() call has incorrect number of arguments. Takes 2 arguments")); return reject(makeRuntimeRejectMsg(workerScript, "exec() call has incorrect number of arguments. Usage: exec(scriptname, server, [numThreads], [arg1], [arg2]...)"));
} }
var argPromises = exp.args.map(function(arg) { var argPromises = exp.args.map(function(arg) {
return evaluate(arg, workerScript); return evaluate(arg, workerScript);
@ -283,9 +308,14 @@ function evaluate(exp, workerScript) {
Promise.all(argPromises).then(function(args) { Promise.all(argPromises).then(function(args) {
if (env.stopFlag) {return reject(workerScript);} if (env.stopFlag) {return reject(workerScript);}
var threads = 1; var threads = 1;
if (exp.args.length == 3) { if (exp.args.length >= 3) {
threads = args[2]; threads = args[2];
} }
var argsForNewScript = [];
for (var i = 3; i < exp.args.length; ++i) {
argsForNewScript.push(args[i]);
}
if (isNaN(threads) || threads < 1) { if (isNaN(threads) || threads < 1) {
return reject(makeRuntimeRejectMsg(workerScript, "Invalid argument for thread count passed into exec(). Must be numeric and greater than 0")); return reject(makeRuntimeRejectMsg(workerScript, "Invalid argument for thread count passed into exec(). Must be numeric and greater than 0"));
} }
@ -294,42 +324,43 @@ function evaluate(exp, workerScript) {
return reject(makeRuntimeRejectMsg(workerScript, "Invalid hostname/ip passed into exec() command: " + args[1])); return reject(makeRuntimeRejectMsg(workerScript, "Invalid hostname/ip passed into exec() command: " + args[1]));
} }
return runScriptFromScript(server, args[0], workerScript, threads); return runScriptFromScript(server, args[0], argsForNewScript, workerScript, threads);
}).then(function(res) { }).then(function(res) {
resolve(res); resolve(res);
}).catch(function(e) { }).catch(function(e) {
reject(e); reject(e);
}); });
} else if (exp.func.value == "kill") { } else if (exp.func.value == "kill") {
if (exp.args.length != 1 && exp.args.length != 2) { if (exp.args.length < 2) {
return reject(makeRuntimeRejectMsg(workerScript, "kill() call has incorrect number of arguments. Takes 1 or 2 arguments")); return reject(makeRuntimeRejectMsg(workerScript, "kill() call has incorrect number of arguments. Usage: kill(scriptname, server, [arg1], [arg2]...)"));
} }
var argPromises = exp.args.map(function(arg) { var argPromises = exp.args.map(function(arg) {
return evaluate(arg, workerScript); return evaluate(arg, workerScript);
}); });
var filename = "";
Promise.all(argPromises).then(function(args) { Promise.all(argPromises).then(function(args) {
if (env.stopFlag) {return reject(workerScript);} if (env.stopFlag) {return reject(workerScript);}
filename = args[0]; var filename = args[0];
if (exp.args.length == 1) { var server = getServer(args[1]);
return Promise.resolve(workerScript.serverIp);
} else {
return evaluate(exp.args[1], workerScript);
}
}).then(function(ip) {
var server = getServer(ip);
if (server == null) { if (server == null) {
workerScript.scriptRef.log("kill() failed. Invalid IP or hostname passed in: " + ip); workerScript.scriptRef.log("kill() failed. Invalid IP or hostname passed in: " + ip);
return reject(makeRuntimeRejectMsg(workerScript, "Invalid IP or hostname passed into kill() command")); return reject(makeRuntimeRejectMsg(workerScript, "Invalid IP or hostname passed into kill() command"));
} }
var argsForKillTarget = [];
var res = killWorkerScript(filename, server.ip); for (var i = 2; i < exp.args.length; ++i) {
argsForKillTarget.push(args[i]);
}
var runningScriptObj = findRunningScript(filename, argsForKillTarget, server);
if (runningScriptObj == null) {
workerScript.scriptRef.log("kill() failed. No such script "+ filename + " on " + server.hostname + " with args: " + printArray(argsForKillTarget));
return Promise.resolve(false);
}
var res = killWorkerScript(runningScriptObj, server.ip);
if (res) { if (res) {
workerScript.scriptRef.log("Killing " + filename + ". May take up to a few minutes for the scripts to die..."); workerScript.scriptRef.log("Killing " + filename + " on " + server.hostname + " with args: " + printArray(argsForKillTarget) + ". May take up to a few minutes for the scripts to die...");
return Promise.resolve(true); return Promise.resolve(true);
} else { } else {
workerScript.scriptRef.log("kill() failed. No such script "+ filename + " on " + server.hostname); workerScript.scriptRef.log("kill() failed. No such script "+ filename + " on " + server.hostname + " with args: " + printArray(argsForKillTarget));
return Promise.resolve(false); return Promise.resolve(false);
} }
}).then(function(res) { }).then(function(res) {
@ -349,10 +380,10 @@ function evaluate(exp, workerScript) {
workerScript.scriptRef.log("killall() failed. Invalid IP or hostname passed in: " + ip); workerScript.scriptRef.log("killall() failed. Invalid IP or hostname passed in: " + ip);
return reject(makeRuntimeRejectMsg(workerScript, "Invalid IP or hostname passed into killall() command")); return reject(makeRuntimeRejectMsg(workerScript, "Invalid IP or hostname passed into killall() command"));
} }
workerScript.scriptRef.log("killall(): Killing all scripts on " + server.hostname + ". May take a few minutes for the scripts to die"); for (var i = server.runningScripts.length-1; i >= 0; --i) {
for (var i = server.runningScripts.length; i >= 0; --i) {
killWorkerScript(server.runningScripts[i], server.ip); killWorkerScript(server.runningScripts[i], server.ip);
} }
workerScript.scriptRef.log("killall(): Killing all scripts on " + server.hostname + ". May take a few minutes for the scripts to die");
resolve(true); resolve(true);
}, function(e) { }, function(e) {
reject(e); reject(e);
@ -520,35 +551,31 @@ function evaluate(exp, workerScript) {
reject(e); reject(e);
}); });
} else if (exp.func.value == "isRunning") { } else if (exp.func.value == "isRunning") {
if (exp.args.length != 1 && exp.args.length != 2) { if (exp.args.length < 2) {
return reject(makeRuntimeRejectMsg(workerScript, "isRunning() call has incorrect number of arguments. Takes 1 or 2 arguments")); return reject(makeRuntimeRejectMsg(workerScript, "isRunning() call has incorrect number of arguments. Usage: isRunning(scriptname, server, [arg1], [arg2]...)"));
} }
var argPromises = exp.args.map(function(arg) { var argPromises = exp.args.map(function(arg) {
return evaluate(arg, workerScript); return evaluate(arg, workerScript);
}); });
var filename = ""; var filename = "";
var argsForTargetScript = [];
Promise.all(argPromises).then(function(args) { Promise.all(argPromises).then(function(args) {
if (env.stopFlag) {return reject(workerScript);} if (env.stopFlag) {return reject(workerScript);}
filename = args[0]; filename = args[0];
if (exp.args.length == 1) { var ip = args[1];
return Promise.resolve(workerScript.serverIp); for (var i = 2; i < args.length; ++i) {
} else { argsForTargetScript.push(args[i]);
return evaluate(exp.args[1], workerScript);
} }
}).then(function(ip) {
var server = getServer(ip); var server = getServer(ip);
if (server == null) { if (server == null) {
workerScript.scriptRef.log("isRunning() failed. Invalid IP or hostname passed in: " + ip); workerScript.scriptRef.log("isRunning() failed. Invalid IP or hostname passed in: " + ip);
return reject(makeRuntimeRejectMsg(workerScript, "Invalid IP or hostname passed into isRunning() command")); return reject(makeRuntimeRejectMsg(workerScript, "Invalid IP or hostname passed into isRunning() command"));
} }
var runningScriptObj = findRunningScript(filename, argsForTargetScript, server);
for (var i = 0; i < server.runningScripts.length; ++i) { if (runningScriptObj != null) {
if (filename == server.runningScripts[i]) { return resolve(true);
return resolve(true);
}
} }
return resolve(false); return resolve(false);
}).catch(function(e) { }).catch(function(e) {
reject(e); reject(e);
@ -926,50 +953,41 @@ function apply_op(op, a, b) {
} }
//Run a script from inside a script using run() command //Run a script from inside a script using run() command
function runScriptFromScript(server, scriptname, workerScript, threads=1) { function runScriptFromScript(server, scriptname, args, workerScript, threads=1) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
var env = workerScript.env; var env = workerScript.env;
if (env.stopFlag) {reject(workerScript); return;} if (env.stopFlag) {reject(workerScript); return;}
setTimeout(function() { setTimeout(function() {
//Check if the script is already running //Check if the script is already running
for (var i = 0; i < server.runningScripts.length; ++i) { var runningScriptObj = findRunningScript(scriptname, args, server);
if (server.runningScripts[i] == scriptname) { if (runningScriptObj != null) {
workerScript.scriptRef.log(scriptname + " is already running on " + server.hostname); workerScript.scriptRef.log(scriptname + " is already running on " + server.hostname);
resolve(false); return resolve(false);
return;
}
} }
//Check if the script exists and if it does run it //Check if the script exists and if it does run it
for (var i = 0; i < server.scripts.length; ++i) { for (var i = 0; i < server.scripts.length; ++i) {
if (server.scripts[i].filename == scriptname) { if (server.scripts[i].filename == scriptname) {
//Check for admin rights and that there is enough RAM availble to run //Check for admin rights and that there is enough RAM availble to run
var ramUsage = server.scripts[i].ramUsage; var script = server.scripts[i];
var ramUsage = script.ramUsage;
ramUsage = ramUsage * threads * Math.pow(1.02, threads-1); ramUsage = ramUsage * threads * Math.pow(1.02, threads-1);
var ramAvailable = server.maxRam - server.ramUsed; var ramAvailable = server.maxRam - server.ramUsed;
if (server.hasAdminRights == false) { if (server.hasAdminRights == false) {
workerScript.scriptRef.log("Cannot run script " + scriptname + " on " + server.hostname + " because you do not have root access!"); workerScript.scriptRef.log("Cannot run script " + scriptname + " on " + server.hostname + " because you do not have root access!");
resolve(false); return resolve(false);
return;
} else if (ramUsage > ramAvailable){ } else if (ramUsage > ramAvailable){
workerScript.scriptRef.log("Cannot run script " + scriptname + "(t=" + threads + ") on " + server.hostname + " because there is not enough available RAM!"); workerScript.scriptRef.log("Cannot run script " + scriptname + "(t=" + threads + ") on " + server.hostname + " because there is not enough available RAM!");
resolve(false); return resolve(false);
return;
} else { } else {
//Able to run script //Able to run script
workerScript.scriptRef.log("Running script: " + scriptname + " on " + server.hostname + " with " + threads + " threads. May take a few seconds to start up..."); workerScript.scriptRef.log("Running script: " + scriptname + " on " + server.hostname + " with " + threads + " threads and args: " + printArray(args) + ". May take a few seconds to start up...");
var script = server.scripts[i]; var runningScriptObj = new RunningScript(script, args);
script.threads = threads; runningScriptObj.threads = threads;
server.runningScripts.push(script.filename); //Push onto runningScripts server.runningScripts.push(runningScriptObj); //Push onto runningScripts
script.moneyStolenMap = new AllServersMap(); addWorkerScript(runningScriptObj, server);
script.numTimesHackMap = new AllServersMap(); return resolve(true);
script.numTimesGrowMap = new AllServersMap();
script.numTimesWeakenMap = new AllServersMap();
script.logs = [];
addWorkerScript(script, server);
resolve(true);
return;
} }
} }
} }

@ -424,7 +424,7 @@ function netscriptRunHttpwormProgram(exp, workerScript, server) {
var env = workerScript.env; var env = workerScript.env;
if (env.stopFlag) {return Promise.reject(workerScript);} if (env.stopFlag) {return Promise.reject(workerScript);}
if (!server.httpPortOpen) { if (!server.httpPortOpen) {
workerScript.scriptRef.log("Executed HTTPWorm.exe virus on " + server.hostname + " to open HTTP port (25)"); workerScript.scriptRef.log("Executed HTTPWorm.exe virus on " + server.hostname + " to open HTTP port (80)");
server.httpPortOpen = true; server.httpPortOpen = true;
++server.openPortCount; ++server.openPortCount;
} else { } else {

@ -3,16 +3,17 @@
//TODO Tested For and while and generic call statements. Have not tested if statements //TODO Tested For and while and generic call statements. Have not tested if statements
/* Actual Worker Code */ /* Actual Worker Code */
function WorkerScript(script) { function WorkerScript(runningScriptObj) {
this.name = ""; this.name = runningScriptObj.filename;
this.running = false; this.running = false;
this.serverIp = null; this.serverIp = null;
this.code = ""; this.code = runningScriptObj.scriptRef.code;
this.env = new Environment(); this.env = new Environment();
this.output = ""; this.output = "";
this.ramUsage = 0; this.ramUsage = 0;
this.scriptRef = script; this.scriptRef = runningScriptObj;
this.errorMessage = ""; this.errorMessage = "";
this.args = runningScriptObj.args;
} }
//Returns the server on which the workerScript is running //Returns the server on which the workerScript is running
@ -31,7 +32,7 @@ function runScriptsLoop() {
if (workerScripts[i].running == false && workerScripts[i].env.stopFlag == false) { if (workerScripts[i].running == false && workerScripts[i].env.stopFlag == false) {
try { try {
var ast = Parser(Tokenizer(InputStream(workerScripts[i].code))); var ast = Parser(Tokenizer(InputStream(workerScripts[i].code)));
console.log(ast); //console.log(ast);
} catch (e) { } catch (e) {
console.log("Error parsing script: " + workerScripts[i].name); console.log("Error parsing script: " + workerScripts[i].name);
dialogBoxCreate("Syntax ERROR in " + workerScripts[i].name + ":<br>" + e); dialogBoxCreate("Syntax ERROR in " + workerScripts[i].name + ":<br>" + e);
@ -47,33 +48,12 @@ function runScriptsLoop() {
console.log("Stopping script " + w.name + " because it finished running naturally"); console.log("Stopping script " + w.name + " because it finished running naturally");
w.running = false; w.running = false;
w.env.stopFlag = true; w.env.stopFlag = true;
w.scriptRef.log("Script finished running");
}, function(w) { }, function(w) {
if (w instanceof Error) { if (w instanceof Error) {
//Error text format: |serverip|scriptname|error message dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer");
var errorText = w.toString(); console.log("ERROR: Evaluating workerscript returns an Error. THIS SHOULDN'T HAPPEN");
if (Engine.Debug) { return;
console.log("Error in script: " + errorText);
}
var errorTextArray = errorText.split("|");
if (errorTextArray.length != 4) {
console.log("ERROR: Something wrong with Error text in evaluator...");
console.log("Error text: " + errorText);
return;
}
var serverIp = errorTextArray[1];
var scriptName = errorTextArray[2];
var errorMsg = errorTextArray[3];
dialogBoxCreate("Script runtime error:<br>Server Ip: " + serverIp + "<br>Script name: " + scriptName + "<br>" + errorMsg);
//Find the corresponding workerscript and set its flags to kill it
for (var i = 0; i < workerScripts.length; ++i) {
if (workerScripts[i].serverIp == serverIp && workerScripts[i].name == scriptName) {
workerScripts[i].running = false;
workerScripts[i].env.stopFlag = true;
return;
}
}
} else if (w instanceof WorkerScript) { } else if (w instanceof WorkerScript) {
if (isScriptErrorMessage(w.errorMessage)) { if (isScriptErrorMessage(w.errorMessage)) {
var errorTextArray = w.errorMessage.split("|"); var errorTextArray = w.errorMessage.split("|");
@ -86,31 +66,20 @@ function runScriptsLoop() {
var scriptName = errorTextArray[2]; var scriptName = errorTextArray[2];
var errorMsg = errorTextArray[3]; var errorMsg = errorTextArray[3];
dialogBoxCreate("Script runtime error: <br>Server Ip: " + serverIp + "<br>Script name: " + scriptName + "<br>" + errorMsg); dialogBoxCreate("Script runtime error: <br>Server Ip: " + serverIp +
"<br>Script name: " + scriptName +
"<br>Args:" + printArray(w.args) + "<br>" + errorMsg);
w.scriptRef.log("Script crashed with runtime error");
} else {
w.scriptRef.log("Script killed");
} }
w.running = false; w.running = false;
w.env.stopFlag = true; w.env.stopFlag = true;
} else if (isScriptErrorMessage(w)) { } else if (isScriptErrorMessage(w)) {
var errorTextArray = errorText.split("|"); dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer");
if (errorTextArray.length != 4) { console.log("ERROR: Evaluating workerscript returns only error message rather than WorkerScript object. THIS SHOULDN'T HAPPEN");
console.log("ERROR: Something wrong with Error text in evaluator..."); return;
console.log("Error text: " + errorText);
return;
}
var serverIp = errorTextArray[1];
var scriptName = errorTextArray[2];
var errorMsg = errorTextArray[3];
dialogBoxCreate("Script runtime error: <br>Server Ip: " + serverIp + "<br>Script name: " + scriptName + "<br>" + errorMsg);
//Find the corresponding workerscript and set its flags to kill it
for (var i = 0; i < workerScripts.length; ++i) {
if (workerScripts[i].serverIp == serverIp && workerScripts[i].name == scriptName) {
workerScripts[i].running = false;
workerScripts[i].env.stopFlag = true;
return;
}
}
} else { } else {
dialogBoxCreate("An unknown script died for an unknown reason. This is a bug please contact game dev"); dialogBoxCreate("An unknown script died for an unknown reason. This is a bug please contact game dev");
} }
@ -127,16 +96,12 @@ function runScriptsLoop() {
var ip = workerScripts[i].serverIp; var ip = workerScripts[i].serverIp;
var name = workerScripts[i].name; var name = workerScripts[i].name;
for (var j = 0; j < AllServers[ip].runningScripts.length; j++) { for (var j = 0; j < AllServers[ip].runningScripts.length; j++) {
if (AllServers[ip].runningScripts[j] == name) { if (AllServers[ip].runningScripts[j].filename == name &&
compareArrays(AllServers[ip].runningScripts[j].args, workerScripts[i].args)) {
AllServers[ip].runningScripts.splice(j, 1); AllServers[ip].runningScripts.splice(j, 1);
break; break;
} }
} }
//Reset the correspondings script's maps to save space
workerScripts[i].scriptRef.moneyStolenMap = {};
workerScripts[i].scriptRef.numTimesHackMap = {};
workerScripts[i].scriptRef.numTimesGrowMap = {};
workerScripts[i].scriptRef.numTimesWeakenMap = {};
//Free RAM //Free RAM
AllServers[ip].ramUsed -= workerScripts[i].ramUsage; AllServers[ip].ramUsed -= workerScripts[i].ramUsage;
@ -155,9 +120,10 @@ function runScriptsLoop() {
//Queues a script to be killed by settings its stop flag to true. Then, the code will reject //Queues a script to be killed by settings its stop flag to true. Then, the code will reject
//all of its promises recursively, and when it does so it will no longer be running. //all of its promises recursively, and when it does so it will no longer be running.
//The runScriptsLoop() will then delete the script from worker scripts //The runScriptsLoop() will then delete the script from worker scripts
function killWorkerScript(scriptName, serverIp) { function killWorkerScript(runningScriptObj, serverIp) {
for (var i = 0; i < workerScripts.length; i++) { for (var i = 0; i < workerScripts.length; i++) {
if (workerScripts[i].name == scriptName && workerScripts[i].serverIp == serverIp) { if (workerScripts[i].name == runningScriptObj.filename && workerScripts[i].serverIp == serverIp &&
compareArrays(workerScripts[i].args, runningScriptObj.args)) {
workerScripts[i].env.stopFlag = true; workerScripts[i].env.stopFlag = true;
return true; return true;
} }
@ -166,23 +132,21 @@ function killWorkerScript(scriptName, serverIp) {
} }
//Queues a script to be run //Queues a script to be run
function addWorkerScript(script, server) { function addWorkerScript(runningScriptObj, server) {
var filename = script.filename; var filename = runningScriptObj.filename;
//Update server's ram usage //Update server's ram usage
var threads = 1; var threads = 1;
if (script.threads && !isNaN(script.threads)) { if (runningScriptObj.threads && !isNaN(runningScriptObj.threads)) {
threads = script.threads; threads = runningScriptObj.threads;
} else { } else {
script.threads = 1; script.threads = 1;
} }
var ramUsage = script.ramUsage * threads * Math.pow(1.02, threads-1); var ramUsage = runningScriptObj.scriptRef.ramUsage * threads * Math.pow(1.02, threads-1);
server.ramUsed += ramUsage; server.ramUsed += ramUsage;
//Create the WorkerScript //Create the WorkerScript
var s = new WorkerScript(script); var s = new WorkerScript(runningScriptObj);
s.name = filename;
s.code = script.code;
s.serverIp = server.ip; s.serverIp = server.ip;
s.ramUsage = ramUsage; s.ramUsage = ramUsage;

@ -107,7 +107,7 @@ function prestigeAugmentation() {
Player.lastUpdate = new Date().getTime(); Player.lastUpdate = new Date().getTime();
//Delete all running scripts objects //Delete all Worker Scripts objects
for (var i = 0; i < workerScripts.length; ++i) { for (var i = 0; i < workerScripts.length; ++i) {
deleteActiveScriptsItem(workerScripts[i]); deleteActiveScriptsItem(workerScripts[i]);
workerScripts[i].env.stopFlag = true; workerScripts[i].env.stopFlag = true;
@ -158,7 +158,6 @@ function prestigeAugmentation() {
//Reset statistics of all scripts on home computer //Reset statistics of all scripts on home computer
for (var i = 0; i < homeComp.scripts.length; ++i) { for (var i = 0; i < homeComp.scripts.length; ++i) {
var s = homeComp.scripts[i]; var s = homeComp.scripts[i];
s.reset();
} }
//Delete messages on home computer //Delete messages on home computer
homeComp.messages.length = 0; homeComp.messages.length = 0;

@ -72,14 +72,6 @@ function saveAndCloseScriptEditor() {
filename += ".script"; filename += ".script";
//If the current script matches one thats currently running, throw an error
for (var i = 0; i < Player.getCurrentServer().runningScripts.length; i++) {
if (filename == Player.getCurrentServer().runningScripts[i].filename) {
dialogBoxCreate("Cannot write to script that is currently running!");
return;
}
}
//If the current script already exists on the server, overwrite it //If the current script already exists on the server, overwrite it
for (var i = 0; i < Player.getCurrentServer().scripts.length; i++) { for (var i = 0; i < Player.getCurrentServer().scripts.length; i++) {
if (filename == Player.getCurrentServer().scripts[i].filename) { if (filename == Player.getCurrentServer().scripts[i].filename) {
@ -112,22 +104,6 @@ function Script() {
this.code = ""; this.code = "";
this.ramUsage = 0; this.ramUsage = 0;
this.server = ""; //IP of server this script is on this.server = ""; //IP of server this script is on
this.logs = []; //Script logging. Array of strings, with each element being a log entry
//Stats to display on the Scripts menu, and used to determine offline progress
this.offlineRunningTime = 0.01; //Seconds
this.offlineMoneyMade = 0;
this.offlineExpGained = 0;
this.onlineRunningTime = 0.01; //Seconds
this.onlineMoneyMade = 0;
this.onlineExpGained = 0;
this.moneyStolenMap = new AllServersMap();
this.numTimesHackMap = new AllServersMap();
this.numTimesGrowMap = new AllServersMap();
this.numTimesWeakenMap = new AllServersMap();
this.threads = 1;
}; };
//Get the script data from the Script Editor and save it to the object //Get the script data from the Script Editor and save it to the object
@ -145,65 +121,9 @@ Script.prototype.saveScript = function() {
//Calculate/update ram usage, execution time, etc. //Calculate/update ram usage, execution time, etc.
this.updateRamUsage(); this.updateRamUsage();
//Clear the stats when the script is updated
this.reset();
} }
} }
Script.prototype.reset = function() {
this.updateRamUsage();
this.offlineRunningTime = 0.01; //Seconds
this.offlineMoneyMade = 0;
this.offlineExpGained = 0;
this.onlineRunningTime = 0.01; //Seconds
this.onlineMoneyMade = 0;
this.onlineExpGained = 0;
this.logs = [];
if (this.moneyStolenMap != null) {
try {
this.moneyStolenMap.reset();
} catch(e) {
this.moneyStolenMap = null;
}
} else {
this.moneyStolenMap = new AllServersMap();
}
if (this.numTimesHackMap != null) {
try {
this.numTimesHackMap.reset();
} catch(e) {
this.numTimesHackMap = null;
}
} else {
this.numTimesHackMap = new AllServersMap();
}
if (this.numTimesGrowMap != null) {
try {
this.numTimesGrowMap.reset();
} catch(e) {
this.numTimesGrowMap = null;
}
} else {
this.numTimesGrowMap = new AllServersMap();
}
if (this.numTimesWeakenMap != null) {
try {
this.numTimesWeakenMap.reset();
} catch(e) {
this.numTimesWeakenMap = null;
}
} else {
this.numTimesWeakenMap = new AllServersMap();
}
}
//Updates how much RAM the script uses when it is running. //Updates how much RAM the script uses when it is running.
Script.prototype.updateRamUsage = function() { Script.prototype.updateRamUsage = function() {
var baseRam = 1.4; var baseRam = 1.4;
@ -276,50 +196,6 @@ Script.prototype.updateRamUsage = function() {
} }
} }
Script.prototype.log = function(txt) {
if (this.logs.length > CONSTANTS.MaxLogCapacity) {
//Delete first element and add new log entry to the end.
//TODO Eventually it might be better to replace this with circular array
//to improve performance
this.logs.shift();
}
this.logs.push(txt);
}
Script.prototype.displayLog = function() {
for (var i = 0; i < this.logs.length; ++i) {
post(this.logs[i]);
}
}
//Update the moneyStolen and numTimesHack maps when hacking
Script.prototype.recordHack = function(serverIp, moneyGained, n=1) {
if (this.moneyStolenMap == null) {
this.moneyStolenMap = new AllServersMap();
}
if (this.numTimesHackMap == null) {
this.numTimesHackMap = new AllServersMap();
}
this.moneyStolenMap[serverIp] += moneyGained;
this.numTimesHackMap[serverIp] += n;
}
//Update the grow map when calling grow()
Script.prototype.recordGrow = function(serverIp, n=1) {
if (this.numTimesGrowMap == null) {
this.numTimesGrowMap = new AllServersMap();
}
this.numTimesGrowMap[serverIp] += n;
}
//Update the weaken map when calling weaken() {
Script.prototype.recordWeaken = function(serverIp, n=1) {
if (this.numTimesWeakenMap == null) {
this.numTimesWeakenMap = new AllServersMap();
}
this.numTimesWeakenMap[serverIp] += n;
}
Script.prototype.toJSON = function() { Script.prototype.toJSON = function() {
return Generic_toJSON("Script", this); return Generic_toJSON("Script", this);
} }
@ -331,7 +207,6 @@ Script.fromJSON = function(value) {
Reviver.constructors.Script = Script; 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
loadAllRunningScripts = function() { loadAllRunningScripts = function() {
@ -346,13 +221,10 @@ loadAllRunningScripts = function() {
for (var j = 0; j < server.runningScripts.length; ++j) { for (var j = 0; j < server.runningScripts.length; ++j) {
count++; count++;
//runningScripts array contains only names, so find the actual script object addWorkerScript(server.runningScripts[j], server);
var script = server.getScript(server.runningScripts[j]);
if (script == null) {continue;}
addWorkerScript(script, server);
//Offline production //Offline production
total += scriptCalculateOfflineProduction(script); total += scriptCalculateOfflineProduction(server.runningScripts[j]);
} }
} }
} }
@ -360,7 +232,7 @@ loadAllRunningScripts = function() {
console.log("Loaded " + count.toString() + " running scripts"); console.log("Loaded " + count.toString() + " running scripts");
} }
scriptCalculateOfflineProduction = function(script) { scriptCalculateOfflineProduction = function(runningScriptObj) {
//The Player object stores the last update time from when we were online //The Player object stores the last update time from when we were online
var thisUpdate = new Date().getTime(); var thisUpdate = new Date().getTime();
var lastUpdate = Player.lastUpdate; var lastUpdate = Player.lastUpdate;
@ -370,38 +242,38 @@ scriptCalculateOfflineProduction = function(script) {
//Calculate the "confidence" rating of the script's true production. This is based //Calculate the "confidence" rating of the script's true production. This is based
//entirely off of time. We will arbitrarily say that if a script has been running for //entirely off of time. We will arbitrarily say that if a script has been running for
//4 hours (14400 sec) then we are completely confident in its ability //4 hours (14400 sec) then we are completely confident in its ability
var confidence = (script.onlineRunningTime) / 14400; var confidence = (runningScriptObj.onlineRunningTime) / 14400;
if (confidence >= 1) {confidence = 1;} if (confidence >= 1) {confidence = 1;}
//Grow //Grow
for (var ip in script.numTimesGrowMap) { for (var ip in runningScriptObj.numTimesGrowMap) {
if (script.numTimesGrowMap.hasOwnProperty(ip)) { if (runningScriptObj.numTimesGrowMap.hasOwnProperty(ip)) {
if (script.numTimesGrowMap[ip] == 0 || script.numTimesGrowMap[ip] == null) {continue;} if (runningScriptObj.numTimesGrowMap[ip] == 0 || runningScriptObj.numTimesGrowMap[ip] == null) {continue;}
var serv = AllServers[ip]; var serv = AllServers[ip];
if (serv == null) {continue;} if (serv == null) {continue;}
var timesGrown = Math.round(0.5 * script.numTimesGrowMap[ip] / script.onlineRunningTime * timePassed); var timesGrown = Math.round(0.5 * runningScriptObj.numTimesGrowMap[ip] / runningScriptObj.onlineRunningTime * timePassed);
console.log(script.filename + " called grow() on " + serv.hostname + " " + timesGrown + " times while offline"); console.log(runningScriptObj.filename + " called grow() on " + serv.hostname + " " + timesGrown + " times while offline");
script.log("Called grow() on " + serv.hostname + " " + timesGrown + " times while offline"); runningScriptObj.log("Called grow() on " + serv.hostname + " " + timesGrown + " times while offline");
var growth = processSingleServerGrowth(serv, timesGrown * 450); var growth = processSingleServerGrowth(serv, timesGrown * 450);
script.log(serv.hostname + " grown by " + formatNumber(growth * 100 - 100, 6) + "% from grow() calls made while offline"); runningScriptObj.log(serv.hostname + " grown by " + formatNumber(growth * 100 - 100, 6) + "% from grow() calls made while offline");
} }
} }
var totalOfflineProduction = 0; var totalOfflineProduction = 0;
for (var ip in script.moneyStolenMap) { for (var ip in runningScriptObj.moneyStolenMap) {
if (script.moneyStolenMap.hasOwnProperty(ip)) { if (runningScriptObj.moneyStolenMap.hasOwnProperty(ip)) {
if (script.moneyStolenMap[ip] == 0 || script.moneyStolenMap[ip] == null) {continue;} if (runningScriptObj.moneyStolenMap[ip] == 0 || runningScriptObj.moneyStolenMap[ip] == null) {continue;}
var serv = AllServers[ip]; var serv = AllServers[ip];
if (serv == null) {continue;} if (serv == null) {continue;}
var production = 0.5 * script.moneyStolenMap[ip] / script.onlineRunningTime * timePassed; var production = 0.5 * runningScriptObj.moneyStolenMap[ip] / runningScriptObj.onlineRunningTime * timePassed;
production *= confidence; production *= confidence;
if (production > serv.moneyAvailable) { if (production > serv.moneyAvailable) {
production = serv.moneyAvailable; production = serv.moneyAvailable;
} }
totalOfflineProduction += production; totalOfflineProduction += production;
Player.gainMoney(production); Player.gainMoney(production);
console.log(script.filename + " generated $" + production + " while offline by hacking " + serv.hostname); console.log(runningScriptObj.filename + " generated $" + production + " while offline by hacking " + serv.hostname);
script.log(script.filename + " generated $" + production + " while offline by hacking " + serv.hostname); runningScriptObj.log(runningScriptObj.filename + " generated $" + production + " while offline by hacking " + serv.hostname);
serv.moneyAvailable -= production; serv.moneyAvailable -= production;
if (serv.moneyAvailable < 0) {serv.moneyAvailable = 0;} if (serv.moneyAvailable < 0) {serv.moneyAvailable = 0;}
} }
@ -409,38 +281,38 @@ scriptCalculateOfflineProduction = function(script) {
//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 * (script.onlineExpGained / script.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
script.offlineMoneyMade += totalOfflineProduction; runningScriptObj.offlineMoneyMade += totalOfflineProduction;
script.offlineRunningTime += timePassed; runningScriptObj.offlineRunningTime += timePassed;
script.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 script.numTimesHackMap) { for (var ip in runningScriptObj.numTimesHackMap) {
if (script.numTimesHackMap.hasOwnProperty(ip)) { if (runningScriptObj.numTimesHackMap.hasOwnProperty(ip)) {
if (script.numTimesHackMap[ip] == 0 || script.numTimesHackMap[ip] == null) {continue;} if (runningScriptObj.numTimesHackMap[ip] == 0 || runningScriptObj.numTimesHackMap[ip] == null) {continue;}
var serv = AllServers[ip]; var serv = AllServers[ip];
if (serv == null) {continue;} if (serv == null) {continue;}
var timesHacked = Math.round(0.5 * script.numTimesHackMap[ip] / script.onlineRunningTime * timePassed); var timesHacked = Math.round(0.5 * runningScriptObj.numTimesHackMap[ip] / runningScriptObj.onlineRunningTime * timePassed);
console.log(script.filename + " hacked " + serv.hostname + " " + timesHacked + " times while offline"); console.log(runningScriptObj.filename + " hacked " + serv.hostname + " " + timesHacked + " times while offline");
script.log("Hacked " + serv.hostname + " " + timesHacked + " times while offline"); runningScriptObj.log("Hacked " + serv.hostname + " " + timesHacked + " times while offline");
serv.fortify(CONSTANTS.ServerFortifyAmount * timesHacked); serv.fortify(CONSTANTS.ServerFortifyAmount * timesHacked);
} }
} }
//Weaken //Weaken
for (var ip in script.numTimesWeakenMap) { for (var ip in runningScriptObj.numTimesWeakenMap) {
if (script.numTimesWeakenMap.hasOwnProperty(ip)) { if (runningScriptObj.numTimesWeakenMap.hasOwnProperty(ip)) {
if (script.numTimesWeakenMap[ip] == 0 || script.numTimesWeakenMap[ip] == null) {continue;} if (runningScriptObj.numTimesWeakenMap[ip] == 0 || runningScriptObj.numTimesWeakenMap[ip] == null) {continue;}
var serv = AllServers[ip]; var serv = AllServers[ip];
if (serv == null) {continue;} if (serv == null) {continue;}
var timesWeakened = Math.round(0.5 * script.numTimesWeakenMap[ip] / script.onlineRunningTime * timePassed); var timesWeakened = Math.round(0.5 * runningScriptObj.numTimesWeakenMap[ip] / runningScriptObj.onlineRunningTime * timePassed);
console.log(script.filename + " called weaken() on " + serv.hostname + " " + timesWeakened + " times while offline"); console.log(runningScriptObj.filename + " called weaken() on " + serv.hostname + " " + timesWeakened + " times while offline");
script.log("Called weaken() on " + serv.hostname + " " + timesWeakened + " times while offline"); runningScriptObj.log("Called weaken() on " + serv.hostname + " " + timesWeakened + " times while offline");
serv.weaken(CONSTANTS.ServerWeakenAmount * timesWeakened); serv.weaken(CONSTANTS.ServerWeakenAmount * timesWeakened);
} }
} }
@ -448,7 +320,109 @@ scriptCalculateOfflineProduction = function(script) {
return totalOfflineProduction; return totalOfflineProduction;
} }
//Creates a function that creates a map/dictionary with the IP of each existing server as //Returns a RunningScript object matching the filename and arguments on the
//designated server, and false otherwise
function findRunningScript(filename, args, server) {
for (var i = 0; i < server.runningScripts.length; ++i) {
if (server.runningScripts[i].filename == filename &&
compareArrays(server.runningScripts[i].args, args)) {
return server.runningScripts[i];
}
}
return null;
}
function RunningScript(script, args) {
if (script == null || script == undefined) {return;}
this.filename = script.filename;
this.args = args;
this.scriptRef = script;
this.server = script.server; //IP Address only
this.logs = []; //Script logging. Array of strings, with each element being a log entry
//Stats to display on the Scripts menu, and used to determine offline progress
this.offlineRunningTime = 0.01; //Seconds
this.offlineMoneyMade = 0;
this.offlineExpGained = 0;
this.onlineRunningTime = 0.01; //Seconds
this.onlineMoneyMade = 0;
this.onlineExpGained = 0;
this.threads = 1;
this.moneyStolenMap = new AllServersMap();
this.numTimesHackMap = new AllServersMap();
this.numTimesGrowMap = new AllServersMap();
this.numTimesWeakenMap = new AllServersMap();
}
RunningScript.prototype.reset = function() {
this.scriptRef.updateRamUsage();
this.offlineRunningTime = 0.01; //Seconds
this.offlineMoneyMade = 0;
this.offlineExpGained = 0;
this.onlineRunningTime = 0.01; //Seconds
this.onlineMoneyMade = 0;
this.onlineExpGained = 0;
this.logs = [];
}
RunningScript.prototype.log = function(txt) {
if (this.logs.length > CONSTANTS.MaxLogCapacity) {
//Delete first element and add new log entry to the end.
//TODO Eventually it might be better to replace this with circular array
//to improve performance
this.logs.shift();
}
this.logs.push(txt);
}
RunningScript.prototype.displayLog = function() {
for (var i = 0; i < this.logs.length; ++i) {
post(this.logs[i]);
}
}
//Update the moneyStolen and numTimesHack maps when hacking
RunningScript.prototype.recordHack = function(serverIp, moneyGained, n=1) {
if (this.moneyStolenMap == null) {
this.moneyStolenMap = new AllServersMap();
}
if (this.numTimesHackMap == null) {
this.numTimesHackMap = new AllServersMap();
}
this.moneyStolenMap[serverIp] += moneyGained;
this.numTimesHackMap[serverIp] += n;
}
//Update the grow map when calling grow()
RunningScript.prototype.recordGrow = function(serverIp, n=1) {
if (this.numTimesGrowMap == null) {
this.numTimesGrowMap = new AllServersMap();
}
this.numTimesGrowMap[serverIp] += n;
}
//Update the weaken map when calling weaken() {
RunningScript.prototype.recordWeaken = function(serverIp, n=1) {
if (this.numTimesWeakenMap == null) {
this.numTimesWeakenMap = new AllServersMap();
}
this.numTimesWeakenMap[serverIp] += n;
}
RunningScript.prototype.toJSON = function() {
return Generic_toJSON("RunningScript", this);
}
RunningScript.fromJSON = function(value) {
return Generic_fromJSON(RunningScript, value.data);
}
//Creates an object that creates a map/dictionary with the IP of each existing server as
//a key, and 0 as the value. This is used to keep track of how much money a script //a key, and 0 as the value. This is used to keep track of how much money a script
//hacks from that server //hacks from that server
function AllServersMap() { function AllServersMap() {

@ -21,7 +21,7 @@ function Server() {
this.cpuSpeed = 1; //MHz this.cpuSpeed = 1; //MHz
this.scripts = []; this.scripts = [];
this.runningScripts = []; //Names (and only names) of scripts being run this.runningScripts = []; //Stores RunningScript objects
this.programs = []; this.programs = [];
this.messages = []; this.messages = [];

@ -570,6 +570,7 @@ var Terminal = {
/****************** END INTERACTIVE TUTORIAL ******************/ /****************** END INTERACTIVE TUTORIAL ******************/
/* Command parser */ /* Command parser */
var s = Player.getCurrentServer();
switch (commandArray[0].toLowerCase()) { switch (commandArray[0].toLowerCase()) {
case "alias": case "alias":
if (commandArray.length == 1) { if (commandArray.length == 1) {
@ -616,7 +617,6 @@ var Terminal = {
if (filename.endsWith(".msg") == false) { if (filename.endsWith(".msg") == false) {
post("Error: Only .msg files are viewable with cat (filename must end with .msg)"); return; post("Error: Only .msg files are viewable with cat (filename must end with .msg)"); return;
} }
var s = Player.getCurrentServer();
for (var i = 0; i < s.messages.length; ++i) { for (var i = 0; i < s.messages.length; ++i) {
if (s.messages[i].filename == filename) { if (s.messages[i].filename == filename) {
showMessage(s.messages[i]); showMessage(s.messages[i]);
@ -626,26 +626,28 @@ var Terminal = {
post("Error: No such file " + filename); post("Error: No such file " + filename);
break; break;
case "check": case "check":
if (commandArray.length != 2) { if (commandArray.length < 2) {
post("Incorrect number of arguments. Usage: check [script]"); post("Incorrect number of arguments. Usage: check [script] [arg1] [arg2]...");
} else { } else {
var scriptName = commandArray[1]; var results = commandArray[1].split(" ");
var scriptName = results[0];
var args = [];
for (var i = 1; i < results.length; ++i) {
args.push(results[i]);
}
//Can only check script files //Can only tail script files
if (scriptName.endsWith(".script") == false) { if (scriptName.endsWith(".script") == false) {
post("Error: check can only be called on .script files (filename must end with .script)"); return; post("Error: tail can only be called on .script files (filename must end with .script)"); return;
} }
//Check that the script exists on this machine //Check that the script exists on this machine
var currScripts = Player.getCurrentServer().scripts; var runningScript = findRunningScript(scriptName, args, s);
for (var i = 0; i < currScripts.length; ++i) { if (runningScript == null) {
if (scriptName == currScripts[i].filename) { post("Error: No such script exists");
currScripts[i].displayLog(); return;
return;
}
} }
logBoxCreate(runningScript);
post("Error: No such script exists");
} }
break; break;
case "clear": case "clear":
@ -737,23 +739,25 @@ var Terminal = {
post(Player.getCurrentServer().ip); post(Player.getCurrentServer().ip);
break; break;
case "kill": case "kill":
if (commandArray.length != 2) { if (commandArray.length < 2) {
post("Incorrect usage of kill command. Usage: kill [scriptname]"); return; post("Incorrect usage of kill command. Usage: kill [scriptname] [arg1] [arg2]..."); return;
} }
var results = commandArray[1].split(" ");
var scriptName = commandArray[1]; var scriptName = results[0];
for (var i = 0; i < Player.getCurrentServer().runningScripts.length; i++) { var args = [];
if (Player.getCurrentServer().runningScripts[i] == scriptName) { for (var i = 1; i < results.length; ++i) {
killWorkerScript(scriptName, Player.getCurrentServer().ip); args.push(results[i]);
post("Killing " + scriptName + ". May take up to a few minutes for the scripts to die..."); }
return; var runningScript = findRunningScript(scriptName, args, s);
} if (runningScript == null) {
} post("No such script is running. Nothing to kill");
post("No such script is running. Nothing to kill"); return;
}
killWorkerScript(runningScript, s.ip);
post("Killing " + scriptName + ". May take up to a few minutes for the scripts to die...");
break; break;
case "killall": case "killall":
var s = Player.getCurrentServer(); for (var i = s.runningScripts.length-1; i >= 0; --i) {
for (var i = s.runningScripts.length; i >= 0; --i) {
killWorkerScript(s.runningScripts[i], s.ip); killWorkerScript(s.runningScripts[i], s.ip);
} }
post("Killing all running scripts. May take up to a few minutes for the scripts to die..."); post("Killing all running scripts. May take up to a few minutes for the scripts to die...");
@ -821,8 +825,13 @@ var Terminal = {
if (commandArray.length != 1) { if (commandArray.length != 1) {
post("Incorrect usage of ps command. Usage: ps"); return; post("Incorrect usage of ps command. Usage: ps"); return;
} }
for (var i = 0; i < Player.getCurrentServer().runningScripts.length; i++) { for (var i = 0; i < s.runningScripts.length; i++) {
post(Player.getCurrentServer().runningScripts[i]); var rsObj = s.runningScripts[i];
var res = rsObj.filename;
for (var j = 0; j < rsObj.args.length; ++j) {
res += (" " + rsObj.args[j].toString());
}
post(res);
} }
break; break;
case "rm": case "rm":
@ -832,7 +841,6 @@ var Terminal = {
//Check programs //Check programs
var delTarget = commandArray[1]; var delTarget = commandArray[1];
var s = Player.getCurrentServer();
for (var i = 0; i < s.programs.length; ++i) { for (var i = 0; i < s.programs.length; ++i) {
if (s.programs[i] == delTarget) { if (s.programs[i] == delTarget) {
s.programs.splice(i, 1); s.programs.splice(i, 1);
@ -844,11 +852,13 @@ var Terminal = {
for (var i = 0; i < s.scripts.length; ++i) { for (var i = 0; i < s.scripts.length; ++i) {
if (s.scripts[i].filename == delTarget) { if (s.scripts[i].filename == delTarget) {
//Check that the script isnt currently running //Check that the script isnt currently running
if (s.runningScripts.indexOf(delTarget) > -1) { for (var j = 0; j < s.runningScripts.length; ++j) {
post("Cannot delete a script that is currently running!"); if (s.runningScripts[j].filename == delTarget) {
} else { post("Cannot delete a script that is currently running!");
s.scripts.splice(i, 1); return;
}
} }
s.scripts.splice(i, 1);
return; return;
} }
} }
@ -858,7 +868,7 @@ var Terminal = {
case "run": case "run":
//Run a program or a script //Run a program or a script
if (commandArray.length != 2) { if (commandArray.length != 2) {
post("Incorrect number of arguments. Usage: run [program/script] [-t] [number threads]"); post("Incorrect number of arguments. Usage: run [program/script] [-t] [num threads] [arg1] [arg2]...");
} else { } else {
var executableName = commandArray[1]; var executableName = commandArray[1];
//Check if its a script or just a program/executable //Check if its a script or just a program/executable
@ -964,10 +974,15 @@ var Terminal = {
} }
break; break;
case "tail": case "tail":
if (commandArray.length != 2) { if (commandArray.length < 2) {
post("Incorrect number of arguments. Usage: tail [script]"); post("Incorrect number of arguments. Usage: tail [script] [arg1] [arg2]...");
} else { } else {
var scriptName = commandArray[1]; var results = commandArray[1].split(" ");
var scriptName = results[0];
var args = [];
for (var i = 1; i < results.length; ++i) {
args.push(results[i]);
}
//Can only tail script files //Can only tail script files
if (scriptName.endsWith(".script") == false) { if (scriptName.endsWith(".script") == false) {
@ -975,15 +990,12 @@ var Terminal = {
} }
//Check that the script exists on this machine //Check that the script exists on this machine
var currScripts = Player.getCurrentServer().scripts; var runningScript = findRunningScript(scriptName, args, s);
for (var i = 0; i < currScripts.length; ++i) { if (runningScript == null) {
if (scriptName == currScripts[i].filename) { post("Error: No such script exists");
logBoxCreate(currScripts[i]); return;
return;
}
} }
logBoxCreate(runningScript);
post("Error: No such script exists");
} }
break; break;
case "theme": case "theme":
@ -1226,35 +1238,71 @@ var Terminal = {
var server = Player.getCurrentServer(); var server = Player.getCurrentServer();
var numThreads = 1; var numThreads = 1;
//Get the number of threads var args = [];
if (scriptName.indexOf(" -t ") != -1) { var results = scriptName.split(" ");
var results = scriptName.split(" "); if (results.length <= 0) {
if (results.length != 3) { post("This is a bug. Please contact developer");
post("Invalid use of run command. Usage: run [script] [-t] [number threads]"); }
return; scriptName = results[0];
if (results.length > 1) {
if (results.length >= 3 && results[1] == "-t") {
numThreads = Math.round(Number(results[2]));
if (isNaN(numThreads) || numThreads < 1) {
post("Invalid number of threads specified. Number of threads must be greater than 0");
return;
}
for (var i = 3; i < results.length; ++i) {
var arg = results[i];
//Forced string
if ((arg.startsWith("'") && arg.endsWith("'")) ||
(arg.startsWith('"') && arg.endsWith('"'))) {
args.push(arg.slice(1, -1));
continue;
}
//Number
var tempNum = Number(arg);
if (!isNaN(tempNum)) {
args.push(tempNum);
continue;
}
//Otherwise string
args.push(arg);
}
} else {
for (var i = 1; i < results.length; ++i) {
var arg = results[i];
//Forced string
if ((arg.startsWith("'") && arg.endsWith("'")) ||
(arg.startsWith('"') && arg.endsWith('"'))) {
args.push(arg.slice(1, -1));
continue;
}
//Number
var tempNum = Number(arg);
if (!isNaN(tempNum)) {
args.push(tempNum);
continue;
}
//Otherwise string
args.push(arg);
}
} }
numThreads = Math.round(Number(results[2]));
if (isNaN(numThreads) || numThreads < 1) {
post("Invalid number of threads specified. Number of threads must be greater than 0");
return;
}
scriptName = results[0];
} }
//Check if this script is already running //Check if this script is already running
for (var i = 0; i < server.runningScripts.length; i++) { if (findRunningScript(scriptName, args, server) != null) {
if (server.runningScripts[i] == scriptName) { post("ERROR: This script is already running. Cannot run multiple instances");
post("ERROR: This script is already running. Cannot run multiple instances"); return;
return; }
}
}
//Check if the script exists and if it does run it //Check if the script exists and if it does run it
for (var i = 0; i < server.scripts.length; i++) { for (var i = 0; i < server.scripts.length; i++) {
if (server.scripts[i].filename == scriptName) { if (server.scripts[i].filename == scriptName) {
//Check for admin rights and that there is enough RAM availble to run //Check for admin rights and that there is enough RAM availble to run
var script = server.scripts[i]; var script = server.scripts[i];
script.threads = numThreads;
var ramUsage = script.ramUsage * numThreads * Math.pow(1.02, numThreads-1); var ramUsage = script.ramUsage * numThreads * Math.pow(1.02, numThreads-1);
var ramAvailable = server.maxRam - server.ramUsed; var ramAvailable = server.maxRam - server.ramUsed;
@ -1263,23 +1311,17 @@ var Terminal = {
return; return;
} else if (ramUsage > ramAvailable){ } else if (ramUsage > ramAvailable){
post("This machine does not have enough RAM to run this script with " + post("This machine does not have enough RAM to run this script with " +
script.threads + " threads. Script requires " + ramUsage + "GB of RAM"); numThreads + " threads. Script requires " + ramUsage + "GB of RAM");
return; return;
}else { } else {
//Able to run script //Able to run script
post("Running script with " + script.threads + " thread(s). May take a few seconds to start up the process..."); post("Running script with " + numThreads + " thread(s) and args: " + printArray(args) + ".");
server.runningScripts.push(script.filename); //Push onto runningScripts post("May take a few seconds to start up the process...");
var runningScriptObj = new RunningScript(script, args);
runningScriptObj.threads = numThreads;
server.runningScripts.push(runningScriptObj);
//Initialize the maps for counting grow/hack/weaken addWorkerScript(runningScriptObj, server);
script.moneyStolenMap = new AllServersMap();
script.numTimesHackMap = new AllServersMap();
script.numTimesGrowMap = new AllServersMap();
script.numTimesWeakenMap = new AllServersMap();
//Clear logs
script.logs = [];
addWorkerScript(script, server);
return; return;
} }
} }

@ -33,3 +33,20 @@ function clearEventListeners(elemId) {
function getRandomInt(min, max) { function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min; return Math.floor(Math.random() * (max - min + 1)) + min;
} }
//Returns true if all elements are equal, and false otherwise
//Assumes both arguments are arrays and that there are no nested arrays
function compareArrays(a1, a2) {
if (a1.length != a2.length) {
return false;
}
for (var i = 0; i < a1.length; ++i) {
if (a1[i] != a2[i]) {return false;}
}
return true;
}
function printArray(a) {
return "[" + a.join(", ") + "]";
}

@ -1,6 +1,7 @@
/* Log Box */ /* Log Box */
//Close box when clicking outside //Close box when clicking outside
/*
$(document).click(function(event) { $(document).click(function(event) {
if (logBoxOpened) { if (logBoxOpened) {
if ( $(event.target).closest("#log-box-container").get(0) == null ) { if ( $(event.target).closest("#log-box-container").get(0) == null ) {
@ -8,7 +9,7 @@ $(document).click(function(event) {
} }
} }
}); });
*/
function logBoxInit() { function logBoxInit() {
var closeButton = document.getElementById("log-box-close"); var closeButton = document.getElementById("log-box-close");