Merge pull request #56 from danielyxie/dev

Dev v0.20.2
This commit is contained in:
danielyxie
2017-06-11 15:52:39 -05:00
committed by GitHub
15 changed files with 358 additions and 101 deletions

View File

@ -602,7 +602,6 @@
<a id="location-leadership-class" class="a-link-button">Take Leadership course</a>
<!-- Purchase servers -->
<a id="location-purchase-1gb" class="a-link-button"> Purchase 1GB Server - $75,000</a>
<a id="location-purchase-2gb" class="a-link-button"> Purchase 2GB Server - $150,000</a>
<a id="location-purchase-4gb" class="a-link-button"> Purchase 4GB Server - $300,000</a>
<a id="location-purchase-8gb" class="a-link-button"> Purchase 8GB Server - $600,000</a>

View File

@ -190,8 +190,7 @@ function createActiveScriptsText(workerscript, item) {
var itemText = document.createElement("p");
//Server ip/hostname
var hostname = workerscript.getServer().hostname;
var serverIpHostname = "Server: " + hostname + "(" + workerscript.serverIp + ")";
var serverIpHostname = "Threads: " + workerscript.scriptRef.threads;
//Online
var onlineTotalMoneyMade = "Total online production: $" + formatNumber(workerscript.scriptRef.onlineMoneyMade, 2);

View File

@ -1476,7 +1476,6 @@ applyAugmentation = function(aug, reapply=false) {
Player.defense_mult *= 1.8;
break;
case AugmentationNames.CombatRib1:
//Str and Defense 5%
Player.strength_mult *= 1.15;
Player.defense_mult *= 1.15;
break;

View File

@ -1,5 +1,5 @@
CONSTANTS = {
Version: "0.20.1",
Version: "0.20.2",
//Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience
//and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then
@ -10,8 +10,8 @@ CONSTANTS = {
CorpFactionRepRequirement: 250000,
/* Base costs */
BaseCostFor1GBOfRamHome: 40000,
BaseCostFor1GBOfRamServer: 50000, //1 GB of RAM
BaseCostFor1GBOfRamHome: 45000,
BaseCostFor1GBOfRamServer: 55000, //1 GB of RAM
BaseCostFor1GBOfRamHacknetNode: 30000,
BaseCostForHacknetNode: 1000,
@ -30,11 +30,11 @@ CONSTANTS = {
/* Augmentation */
//NeuroFlux Governor cost multiplier as you level up
NeuroFluxGovernorLevelMult: 1.14,
NeuroFluxGovernorLevelMult: 1.13,
/* Script related things */
//Time (ms) it takes to run one operation in Netscript.
CodeInstructionRunTime: 500,
CodeInstructionRunTime: 200,
//RAM Costs for different commands
ScriptWhileRamCost: 0.2,
@ -165,11 +165,11 @@ CONSTANTS = {
"kill [script] Stops a script that is running 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>" +
"mem [script] Displays the amount of RAM the script requires to run<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>" +
"ps Display all scripts that are currently running<br>" +
"rm Delete a script/program from the machine. (WARNING: Permanent)<br>" +
"run [script/program] Execute a program or a script<br>" +
"run [name] [-t] [n] Execute a program or a script with n threads<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>" +
"scp [script] [server] Copies a script to a destination server (specified by ip or hostname)<br>" +
@ -251,13 +251,29 @@ CONSTANTS = {
"Here are some Terminal commands that are useful when working with scripts: <br>" +
"free - Shows the current server's RAM usage and availability <br>" +
"kill [script] - Stops a script that is running <br>" +
"mem [script] - Check how much RAM a script requires to run<br>" +
"mem [script] [-t] [n] - Check how much RAM a script requires to run with n threads<br>" +
"nano [script] - Create/Edit a script <br>" +
"ps - Displays all scripts that are actively running on the current server<br>" +
"rm [script] - Delete a script<br>" +
"run [script] - Run a script <br>" +
"run [script] [-t] [n] - Run a script with n threads<br>" +
"tail [script] - Displays a script's logs<br>" +
"top - Displays all active scripts and their RAM usage <br><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 " +
"every call to the hack(), grow(), and weaken() Netscript functions will have its effect multiplied by the number of scripts. " +
"For example, if a normal single-threaded script is able to hack $10,000, then running the same script with 5 threads would " +
"yield $50,000. <br><br> " +
"Each additional thread to a script will slightly increase the RAM usage for that thread. The total cost of running a script with " +
"n threads can be calculated with: <br>" +
"base cost * n * (1.02 ^ n) <br>" +
"where the base cost is the amount of RAM required to run the script with a single thread. In the terminal, you can run the " +
"'mem [scriptname] -t n' command to see how much RAM a script requires with n threads. <br><br>" +
"Every method for running a script has an option for making it multihreaded. To run a script with " +
"n threads from a Terminal: <br>" +
"run [scriptname] -t n<br><br>" +
"Using Netscript commands: <br>" +
"run('scriptname.script', m);<br> " +
"exec('scriptname.script, 'targetServer', n);<br><br>" +
"<u><h1> Notes about how scripts work offline </h1> </u><br>" +
"<strong> The scripts that you write and execute are interpreted in Javascript. For this " +
"reason, it is not possible for these scripts to run while offline (when the game is closed). " +
@ -301,6 +317,23 @@ CONSTANTS = {
"&nbsp;>=<br>" +
"&nbsp;==<br>" +
"&nbsp;!=<br><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 holy 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>" +
"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 " +
"operator on the array's name: <br><br>" +
"print(thisIsAnArray[0]); <br>" +
"thisIsAnArray[1] = 5<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 " +
"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. " +
"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>" +
"This code will print: <br><br>10<br>20<br><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 may use: <br><br> " +
@ -335,12 +368,17 @@ CONSTANTS = {
"<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>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)</i> <br> Run a script as a separate process. The 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 same server. Returns true if the script is successfully started, and false otherwise. Requires a significant amount " +
"<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 " +
"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. " +
"This second argument must be a number that is greater than 0. " +
"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 " +
"the current server, if it exists. <br><br>" +
"<i>exec(script, hostname/ip)</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. Returns " +
"<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 " +
"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. " +
"This argument must be a number that is greater than 0. Returns " +
"true if the script is successfully started, and false otherwise. Does NOT work while offline<br> " +
"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>" +
"<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. " +
@ -400,7 +438,7 @@ CONSTANTS = {
"<i>hacknetnodes[i].ram</i><br> Returns the amount of RAM on the corresponding Hacknet Node<br><br>" +
"<i>hacknetnodes[i].cores</i><br> Returns the number of cores on the corresponding Hacknet Node<br><br>" +
"<i>hacknetnodes[i].upgradeLevel(n)</i><br> Tries to upgrade the level of the corresponding Hacknet Node n times. The argument n must be a " +
"positive integer. Returns true if the Hacknet Node's level is successfully upgraded n times, and false otherwise.<br><br>" +
"positive integer. Returns true if the Hacknet Node's level is successfully upgraded n times or up to the max level (200), and false otherwise.<br><br>" +
"<i>hacknetnodes[i].upgradeRam()</i><br> Tries to upgrade the amount of RAM on the corresponding Hacknet Node. Returns true if the " +
"RAM is successfully upgraded, and false otherwise. <br><br>" +
"<i>hacknetnodes[i].upgradeCore()</i><br> Attempts to purchase an additional core for the corresponding Hacknet Node. Returns true if the " +
@ -535,6 +573,17 @@ CONSTANTS = {
"RAM Upgrades on your home computer",
Changelog:
"v0.20.2<br>" +
"-Fixed several small bugs<br>" +
"-Added basic array functionality to Netscript<br>" +
"-Added ability to run scripts with multiple threads. Running a script with n threads will multiply the effects of all " +
"hack(), grow(), and weaken() commands by n. However, running a script with multiple threads has drawbacks in terms of " +
"RAM usage. A script's ram usage when it is 'multithreaded' is calculated as: base cost * numThreads * (1.02 ^ numThreads). " +
"A script can be run multithreaded using the 'run [script] -t n' Terminal command or by passing in an argument to the " +
"run() and exec() Netscript commands. See documentation.<br>" +
"-RAM is slightly (~10%) more expensive (affects purchasing server and upgrading RAM on home computer)<br>" +
"-NeuroFlux Governor augmentation cost multiplier decreased<br>" +
"-Netscript default operation runtime lowered to 200ms (was 500ms previously)<br><br>" +
"v0.20.1<br>" +
"-Fixed bug where sometimes scripts would crash without showing the error<br>" +
"-Added Deepscan programs to Dark Web<br>" +
@ -652,6 +701,17 @@ CONSTANTS = {
"-You can now see what an Augmentation does and its price even while its locked<br><br>",
LatestUpdate:
"v0.20.2<br>" +
"-Fixed several small bugs<br>" +
"-Added basic array functionality to Netscript<br>" +
"-Added ability to run scripts with multiple threads. Running a script with n threads will multiply the effects of all " +
"hack(), grow(), and weaken() commands by n. However, running a script with multiple threads has drawbacks in terms of " +
"RAM usage. A script's ram usage when it is 'multithreaded' is calculated as: base cost * numThreads * (1.02 ^ numThreads). " +
"A script can be run multithreaded using the 'run [script] -t n' Terminal command or by passing in an argument to the " +
"run() and exec() Netscript commands. See documentation.<br>" +
"-RAM is slightly (~10%) more expensive (affects purchasing server and upgrading RAM on home computer)<br>" +
"-NeuroFlux Governor augmentation cost multiplier decreased<br>" +
"-Netscript default operation runtime lowered to 200ms (was 500ms previously)<br><br>" +
"v0.20.1<br>" +
"-Fixed bug where sometimes scripts would crash without showing the error<br>" +
"-Added Deepscan programs to Dark Web<br>" +

View File

@ -74,12 +74,12 @@ HacknetNode.prototype.calculateLevelUpgradeCost = function(levels=1) {
HacknetNode.prototype.purchaseLevelUpgrade = function(levels=1) {
var cost = this.calculateLevelUpgradeCost(levels);
if (isNaN(cost)) {return false;}
if (cost > Player.money) {return false;}
Player.loseMoney(cost);
if (this.level + levels > CONSTANTS.HacknetNodeMaxLevel) {
var diff = Math.max(0, CONSTANTS.HacknetNodeMaxLevel - this.level);
return this.purchaseLevelUpgrade(diff);
}
if (cost > Player.money) {return false;}
Player.loseMoney(cost);
this.level += levels;
this.updateMoneyGainRate();
return true;

View File

@ -124,7 +124,6 @@ displayLocationContent = function() {
var classManagement = document.getElementById("location-management-class");
var classLeadership = document.getElementById("location-leadership-class");
var purchase1gb = document.getElementById("location-purchase-1gb");
var purchase2gb = document.getElementById("location-purchase-2gb");
var purchase4gb = document.getElementById("location-purchase-4gb");
var purchase8gb = document.getElementById("location-purchase-8gb");
@ -210,7 +209,6 @@ displayLocationContent = function() {
classManagement.style.display = "none";
classLeadership.style.display = "none";
purchase1gb.style.display = "none";
purchase2gb.style.display = "none";
purchase4gb.style.display = "none";
purchase8gb.style.display = "none";
@ -224,7 +222,6 @@ displayLocationContent = function() {
purchaseTor.style.display = "none";
purchaseHomeRam.style.display = "none";
purchase1gb.innerHTML = "Purchase 1GB Server - $" + formatNumber(1*CONSTANTS.BaseCostFor1GBOfRamServer, 2);
purchase2gb.innerHTML = "Purchase 2GB Server - $" + formatNumber(2*CONSTANTS.BaseCostFor1GBOfRamServer, 2);
purchase4gb.innerHTML = "Purchase 4GB Server - $" + formatNumber(4*CONSTANTS.BaseCostFor1GBOfRamServer, 2);
purchase8gb.innerHTML = "Purchase 8GB Server - $" + formatNumber(8*CONSTANTS.BaseCostFor1GBOfRamServer, 2);
@ -433,7 +430,6 @@ displayLocationContent = function() {
securityEngineerJob.style.display = "block";
networkEngineerJob.style.display = "block";
purchase1gb.style.display = "block";
purchase2gb.style.display = "block";
purchase4gb.style.display = "block";
purchase8gb.style.display = "block";
@ -594,7 +590,6 @@ displayLocationContent = function() {
softwareJob.style.display = "block";
softwareConsultantJob.style.display = "block";
businessJob.style.display = "block";
purchase1gb.style.display = "block";
purchase2gb.style.display = "block";
purchase4gb.style.display = "block";
purchaseTor.style.display = "block";
@ -1352,7 +1347,6 @@ initLocationButtons = function() {
var work = document.getElementById("location-work");
var purchase1gb = document.getElementById("location-purchase-1gb");
var purchase2gb = document.getElementById("location-purchase-2gb");
var purchase4gb = document.getElementById("location-purchase-4gb");
var purchase8gb = document.getElementById("location-purchase-8gb");
@ -1447,12 +1441,7 @@ initLocationButtons = function() {
Player.applyForPartTimeWaiterJob();
return false;
});
purchase1gb.addEventListener("click", function() {
purchaseServerBoxCreate(1, 1 * CONSTANTS.BaseCostFor1GBOfRamServer);
return false;
});
purchase2gb.addEventListener("click", function() {
purchaseServerBoxCreate(2, 2 * CONSTANTS.BaseCostFor1GBOfRamServer);
return false;

View File

@ -28,7 +28,6 @@ Environment.prototype = {
if (name in this.vars) {
return this.vars[name];
}
console.log("here");
throw new Error("Undefined variable " + name);
},

View File

@ -28,11 +28,42 @@ function evaluate(exp, workerScript) {
reject(e);
});
return;
} else if (exp.value == "array") {
//A raw array. This will be called under something like this:
// x = Array[1, 2, 3];
if (exp.array && exp.array instanceof Array) {
resolve(exp.array);
} else {
reject(makeRuntimeRejectMsg(workerScript, "Invalid array instantiation"));
}
return;
}
try {
resolve(env.get(exp.value));
var res = env.get(exp.value);
if (exp.index) {
//If theres an index field, then this variable is supposed to be an array
//and the user needs to be indexing it
if (res.constructor === Array || res instanceof Array) {
var iPromise = evaluate(exp.index.value, workerScript);
iPromise.then(function(i) {
if (i >= res.length || i < 0) {
return reject(makeRuntimeRejectMsg(workerScript, "Out of bounds: Invalid index in [] operator"));
} else {
return evaluate(res[i], workerScript);
}
}).then(function(res) {
resolve(res);
}).catch(function(e) {
reject(e);
});
} else {
reject(makeRuntimeRejectMsg(workerScript, "Trying to access a non-array variable using the [] operator"));
}
} else {
resolve(res);
}
} catch (e) {
throw new Error("|" + workerScript.serverIp + "|" + workerScript.name + "|" + e.toString());
reject("|" + workerScript.serverIp + "|" + workerScript.name + "|" + e.toString());
}
break;
//Can currently only assign to "var"s
@ -224,25 +255,37 @@ function evaluate(exp, workerScript) {
reject(e);
});
} else if (exp.func.value == "run") {
if (exp.args.length != 1) {
return reject(makeRuntimeRejectMsg(workerScript, "run() call has incorrect number of arguments. Takes 1 argument"));
if (exp.args.length != 1 && exp.args.length != 2) {
return reject(makeRuntimeRejectMsg(workerScript, "run() call has incorrect number of arguments. Takes 1 or 2 arguments"));
}
var scriptNamePromise = evaluate(exp.args[0], workerScript);
scriptNamePromise.then(function(scriptname) {
var argPromises = exp.args.map(function(arg) {
return evaluate(arg, workerScript);
});
Promise.all(argPromises).then(function(args) {
if (env.stopFlag) {return reject(workerScript);}
var scriptname = args[0];
var threads = 1;
if (exp.args.length == 2) {
threads = args[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"));
}
var scriptServer = getServer(workerScript.serverIp);
if (scriptServer == null) {
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);
var runScriptPromise = runScriptFromScript(scriptServer, scriptname, workerScript, threads);
return runScriptPromise;
}).then(function(res) {
resolve(res);
}).catch(function(e) {
reject(e);
});
} else if (exp.func.value == "exec") {
if (exp.args.length != 2) {
if (exp.args.length != 2 && exp.args.length != 3) {
return reject(makeRuntimeRejectMsg(workerScript, "exec() call has incorrect number of arguments. Takes 2 arguments"));
}
var argPromises = exp.args.map(function(arg) {
@ -251,12 +294,19 @@ function evaluate(exp, workerScript) {
Promise.all(argPromises).then(function(args) {
if (env.stopFlag) {return reject(workerScript);}
var threads = 1;
if (exp.args.length == 3) {
threads = args[2];
}
if (isNaN(threads) || threads < 1) {
return reject(makeRuntimeRejectMsg(workerScript, "Invalid argument for thread count passed into exec(). Must be numeric and greater than 0"));
}
var server = getServer(args[1]);
if (server == null) {
return reject(makeRuntimeRejectMsg(workerScript, "Invalid hostname/ip passed into exec() command: " + args[1]));
}
return runScriptFromScript(server, args[0], workerScript);
return runScriptFromScript(server, args[0], workerScript, threads);
}).then(function(res) {
resolve(res);
}).catch(function(e) {
@ -888,7 +938,7 @@ function apply_op(op, a, b) {
}
//Run a script from inside a script using run() command
function runScriptFromScript(server, scriptname, workerScript) {
function runScriptFromScript(server, scriptname, workerScript, threads=1) {
return new Promise(function(resolve, reject) {
var env = workerScript.env;
if (env.stopFlag) {reject(workerScript); return;}
@ -907,6 +957,7 @@ function runScriptFromScript(server, scriptname, workerScript) {
if (server.scripts[i].filename == scriptname) {
//Check for admin rights and that there is enough RAM availble to run
var ramUsage = server.scripts[i].ramUsage;
ramUsage = ramUsage * threads * Math.pow(1.02, threads-1);
var ramAvailable = server.maxRam - server.ramUsed;
if (server.hasAdminRights == false) {
@ -914,13 +965,14 @@ function runScriptFromScript(server, scriptname, workerScript) {
resolve(false);
return;
} else if (ramUsage > ramAvailable){
workerScript.scriptRef.log("Cannot run script " + scriptname + " 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;
} else {
//Able to run script
workerScript.scriptRef.log("Running script: " + scriptname + " on " + server.hostname + ". May take a few seconds to start up...");
workerScript.scriptRef.log("Running script: " + scriptname + " on " + server.hostname + " with " + threads + " threads. May take a few seconds to start up...");
var script = server.scripts[i];
script.threads = threads;
server.runningScripts.push(script.filename); //Push onto runningScripts
addWorkerScript(script, server);
resolve(true);

View File

@ -1,5 +1,6 @@
/* Netscript Functions
* Implementation for Netscript features */
/*
function netscriptAssign(exp, workerScript) {
var env = workerScript.env;
return new Promise(function(resolve, reject) {
@ -9,17 +10,112 @@ function netscriptAssign(exp, workerScript) {
return reject(makeRuntimeRejectMsg(workerScript, "Cannot assign to " + JSON.stringify(exp.left)));
}
var expRightPromise = evaluate(exp.right, workerScript);
expRightPromise.then(function(expRight) {
//Assigning an element in an array
if (exp.left.index) {
try {
env.set(exp.left.value, expRight);
} catch (e) {
return reject(makeRuntimeRejectMsg(workerScript, "Failed to set environment variable: " + e.toString()));
var res = env.get(exp.left.value);
if (res.constructor === Array || res instanceof Array) {
var i = 0;
var iPromise = evaluate(exp.left.index.value, workerScript);
iPromise.then(function(idx) {
if (idx >= res.length || idx < 0) {
return reject(makeRuntimeRejectMsg(workerScript, "Out of bounds: Invalid index in [] operator"));
} else {
//TODO evaluate exp.right here....and then determine its type and
//set the type and value below accordingly
i = idx;
return evaluate(exp.right, workerScript);
}
}).then(function(right) {
console.log("evaluate right with result: " + right);
if (right === true || right === false) {
res[i].type = "bool";
res[i].value = right;
} else if (!isNaN(right) || typeof right == 'number') {
res[i].type = "num";
res[i].value = right;
} else { //String
res[i].type = "str";
res[i].value = right.toString();
}
console.log(res);
return resolve(true);
}).then(function(finalRes) {
resolve(finalRes);
}).catch(function(e) {
return reject(e);
});
} else {
return reject(makeRuntimeRejectMsg(workerScript, "Trying to access a non-array variable using the [] operator"));
}
} catch(e) {
return reject(makeRuntimeRejectMsg(workerScript, e.toString()));
}
resolve(false); //Return false so this doesnt cause conditionals to evaluate
}, function(e) {
reject(e);
});
} else {
var expRightPromise = evaluate(exp.right, workerScript);
expRightPromise.then(function(expRight) {
try {
env.set(exp.left.value, expRight);
} catch (e) {
return reject(makeRuntimeRejectMsg(workerScript, "Failed to set environment variable: " + e.toString()));
}
resolve(false); //Return false so this doesnt cause conditionals to evaluate
}, function(e) {
reject(e);
});
}
});
}
*/
function netscriptAssign(exp, workerScript) {
var env = workerScript.env;
return new Promise(function(resolve, reject) {
if (env.stopFlag) {return reject(workerScript);}
if (exp.left.type != "var") {
return reject(makeRuntimeRejectMsg(workerScript, "Cannot assign to " + JSON.stringify(exp.left)));
}
//Assigning an element in an array
if (exp.left.index) {
try {
var res = env.get(exp.left.value);
if (res.constructor === Array || res instanceof Array) {
var i = 0;
var iPromise = evaluate(exp.left.index.value, workerScript);
iPromise.then(function(idx) {
if (idx >= res.length || idx < 0) {
return reject(makeRuntimeRejectMsg(workerScript, "Out of bounds: Invalid index in [] operator"));
} else {
//Clone res to be exp.right
i = idx;
res[i] = Object.assign({}, exp.right);
return evaluate(exp.right, workerScript);
}
}).then(function(finalRes) {
resolve(finalRes);
}).catch(function(e) {
return reject(e);
});
} else {
return reject(makeRuntimeRejectMsg(workerScript, "Trying to access a non-array variable using the [] operator"));
}
} catch(e) {
return reject(makeRuntimeRejectMsg(workerScript, e.toString()));
}
} else {
var expRightPromise = evaluate(exp.right, workerScript);
expRightPromise.then(function(expRight) {
try {
env.set(exp.left.value, expRight);
} catch (e) {
return reject(makeRuntimeRejectMsg(workerScript, "Failed to set environment variable: " + e.toString()));
}
resolve(false); //Return false so this doesnt cause conditionals to evaluate
}, function(e) {
reject(e);
});
}
});
}
@ -43,6 +139,8 @@ function netscriptBinary(exp, workerScript) {
function netscriptHack(exp, workerScript) {
var env = workerScript.env;
if (env.stopFlag) {return Promise.reject(workerScript);}
var threads = workerScript.scriptRef.threads;
if (isNaN(threads) || threads < 1) {threads = 1;}
if (exp.args.length != 1) {
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Hack() call has incorrect number of arguments. Takes 1 argument"));
@ -69,19 +167,19 @@ function netscriptHack(exp, workerScript) {
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Script crashed because player's hacking skill is not high enough to hack " + server.hostname));
}
workerScript.scriptRef.log("Attempting to hack " + ip + " in " + hackingTime.toFixed(3) + " seconds");
workerScript.scriptRef.log("Attempting to hack " + ip + " in " + hackingTime.toFixed(3) + " seconds (t=" + threads + ")");
return Promise.resolve([server, hackingTime]);
}).then(function([server, hackingTime]) {
console.log("Hacking " + server.hostname + " after " + hackingTime.toString() + " seconds.");
console.log("Hacking " + server.hostname + " after " + hackingTime.toString() + " seconds (t=" + threads + ")");
return netscriptDelay(hackingTime* 1000).then(function() {
if (env.stopFlag) {return Promise.reject(workerScript);}
var hackChance = scriptCalculateHackingChance(server);
var rand = Math.random();
var expGainedOnSuccess = scriptCalculateExpGain(server);
var expGainedOnSuccess = scriptCalculateExpGain(server) * threads;
var expGainedOnFailure = (expGainedOnSuccess / 4);
if (rand < hackChance) { //Success!
var moneyGained = scriptCalculatePercentMoneyHacked(server);
moneyGained = Math.floor(server.moneyAvailable * moneyGained);
moneyGained = Math.floor(server.moneyAvailable * moneyGained) * threads;
//Safety check
if (moneyGained <= 0) {moneyGained = 0;}
@ -89,21 +187,19 @@ function netscriptHack(exp, workerScript) {
server.moneyAvailable -= moneyGained;
Player.gainMoney(moneyGained);
workerScript.scriptRef.onlineMoneyMade += moneyGained;
workerScript.scriptRef.recordHack(server.ip, moneyGained);
workerScript.scriptRef.recordHack(server.ip, moneyGained, threads);
Player.gainHackingExp(expGainedOnSuccess);
workerScript.scriptRef.onlineExpGained += expGainedOnSuccess;
console.log("Script successfully hacked " + server.hostname + " for $" + formatNumber(moneyGained, 2) + " and " + formatNumber(expGainedOnSuccess, 4) + " exp");
workerScript.scriptRef.log("Script SUCCESSFULLY hacked " + server.hostname + " for $" + formatNumber(moneyGained, 2) + " and " + formatNumber(expGainedOnSuccess, 4) + " exp");
server.fortify(CONSTANTS.ServerFortifyAmount);
workerScript.scriptRef.log("Script SUCCESSFULLY hacked " + server.hostname + " for $" + formatNumber(moneyGained, 2) + " and " + formatNumber(expGainedOnSuccess, 4) + " exp (t=" + threads + ")");
server.fortify(CONSTANTS.ServerFortifyAmount * threads);
return Promise.resolve(true);
} else {
//Player only gains 25% exp for failure? TODO Can change this later to balance
Player.gainHackingExp(expGainedOnFailure);
workerScript.scriptRef.onlineExpGained += expGainedOnFailure;
console.log("Script unsuccessful to hack " + server.hostname + ". Gained " + formatNumber(expGainedOnFailure, 4) + " exp");
workerScript.scriptRef.log("Script FAILED to hack " + server.hostname + ". Gained " + formatNumber(expGainedOnFailure, 4) + " exp");
workerScript.scriptRef.log("Script FAILED to hack " + server.hostname + ". Gained " + formatNumber(expGainedOnFailure, 4) + " exp (t=" + threads + ")");
return Promise.resolve(false);
}
});
@ -117,6 +213,8 @@ function netscriptHack(exp, workerScript) {
function netscriptGrow(exp, workerScript) {
var env = workerScript.env;
if (env.stopFlag) {return Promise.reject(workerScript);}
var threads = workerScript.scriptRef.threads;
if (isNaN(threads) || threads < 1) {threads = 1;}
if (exp.args.length != 1) {
return Promise.reject(makeRuntimeRejectMsg(workerScript, "grow() call has incorrect number of arguments. Takes 1 argument"));
}
@ -137,20 +235,20 @@ function netscriptGrow(exp, workerScript) {
var growTime = scriptCalculateGrowTime(server);
console.log("Executing grow() on server " + server.hostname + " in " + formatNumber(growTime/1000, 3) + " seconds")
workerScript.scriptRef.log("Executing grow() on server " + server.hostname + " in " + formatNumber(growTime/1000, 3) + " seconds");
workerScript.scriptRef.log("Executing grow() on server " + server.hostname + " in " + formatNumber(growTime/1000, 3) + " seconds (t=" + threads + ")");
return Promise.resolve([server, growTime]);
}).then(function([server, growTime]) {
if (env.stopFlag) {return Promise.reject(workerScript);}
return netscriptDelay(growTime).then(function() {
if (env.stopFlag) {return Promise.reject(workerScript);}
server.moneyAvailable += 1; //It can be grown even if it has no money
var growthPercentage = processSingleServerGrowth(server, 450);
workerScript.scriptRef.recordGrow(server.ip);
var expGain = 0.5 * Player.hacking_exp_mult;
server.moneyAvailable += (1 * threads); //It can be grown even if it has no money
var growthPercentage = processSingleServerGrowth(server, 450 * threads);
workerScript.scriptRef.recordGrow(server.ip, threads);
var expGain = 0.5 * Player.hacking_exp_mult * threads;
workerScript.scriptRef.log("Available money on " + server.hostname + " grown by "
+ formatNumber(growthPercentage*100 - 100, 6) + "%. Gained " +
formatNumber(expGain, 4) + " hacking exp");
formatNumber(expGain, 4) + " hacking exp (t=" + threads +")");
workerScript.scriptRef.onlineExpGained += expGain;
Player.gainHackingExp(expGain);
return Promise.resolve(growthPercentage);
@ -165,6 +263,8 @@ function netscriptGrow(exp, workerScript) {
function netscriptWeaken(exp, workerScript) {
var env = workerScript.env;
if (env.stopFlag) {return Promise.reject(workerScript);}
var threads = workerScript.scriptRef.threads;
if (isNaN(threads) || threads < 1) {threads = 1;}
if (exp.args.length != 1) {
return Promise.reject(makeRuntimeRejectMsg(workerScript, "weaken() call has incorrect number of arguments. Takes 1 argument"));
}
@ -185,21 +285,22 @@ function netscriptWeaken(exp, workerScript) {
var weakenTime = scriptCalculateWeakenTime(server);
console.log("Executing weaken() on server " + server.hostname + " in " + formatNumber(weakenTime/1000, 3) + " seconds")
workerScript.scriptRef.log("Executing weaken() on server " + server.hostname + " in " + formatNumber(weakenTime/1000, 3) + " seconds");
workerScript.scriptRef.log("Executing weaken() on server " + server.hostname + " in " +
formatNumber(weakenTime/1000, 3) + " seconds (t=" + threads + ")");
return Promise.resolve([server, weakenTime]);
}).then(function([server, weakenTime]) {
if (env.stopFlag) {return Promise.reject(workerScript);}
return netscriptDelay(weakenTime).then(function() {
if (env.stopFlag) {return Promise.reject(workerScript);}
server.weaken(CONSTANTS.ServerWeakenAmount);
workerScript.scriptRef.recordWeaken(server.ip);
var expGain = 3 * Player.hacking_exp_mult;
server.weaken(CONSTANTS.ServerWeakenAmount * threads);
workerScript.scriptRef.recordWeaken(server.ip, threads);
var expGain = 3 * Player.hacking_exp_mult * threads;
workerScript.scriptRef.log("Server security level on " + server.hostname + " weakened to " + server.hackDifficulty +
". Gained " + formatNumber(expGain, 4) + " hacking exp");
". Gained " + formatNumber(expGain, 4) + " hacking exp (t=" + threads + ")");
workerScript.scriptRef.onlineExpGained += expGain;
Player.gainHackingExp(expGain);
return Promise.resolve(CONSTANTS.ServerWeakenAmount);
return Promise.resolve(CONSTANTS.ServerWeakenAmount * threads);
});
}).then(function(res) {
return Promise.resolve(res);

View File

@ -211,17 +211,27 @@ function Parser(input) {
value: "hacknetnodes",
index: index,
op: op,
}
};
}
unexpected();
}
function parse_array() {
//Declaring a new array with Array[1,2,3]
var array = delimited("[", "]", ",", parse_expression);
return {type: "var",
value: "array",
array: array
};
}
function parse_arrayindex() {
var index = delimited("[", "]", ";", parse_expression);
var val = 0;
if (index.length == 1 && (index[0].type == "num" || index[0].type == "var")) {
val = index[0];
} else {
val = 0;
console.log("WARNING: Extra indices passed in")
}
@ -253,12 +263,21 @@ function Parser(input) {
if (is_kw("if")) return parse_if();
if (is_kw("for")) return parse_for();
if (is_kw("while")) return parse_while();
//if (is_kw("hacknetnodes")) return parse_hacknetnodes();
//Note, let for loops be function calls (call node types)
if (is_kw("true") || is_kw("false")) return parse_bool();
var tok = input.next();
if (tok.type == "var" && tok.value == "hacknetnodes") return parse_hacknetnodes();
if (tok.type == "var" && tok.value == "Array") return parse_array();
if (tok.type == "var" && is_punc("[")) {
//Returns a variable node except with an extra "index" field so
//we can identify it as an index
var index = parse_arrayindex();
if (index.type != "index") {
unexpected();
}
tok.index = index;
return tok;
}
if (tok.type == "var" || tok.type == "num" || tok.type == "str")
return tok;
unexpected();

View File

@ -165,14 +165,15 @@ function addWorkerScript(script, server) {
var filename = script.filename;
//Update server's ram usage
server.ramUsed += script.ramUsage;
var ramUsage = script.ramUsage * script.threads * Math.pow(1.02, script.threads-1);
server.ramUsed += ramUsage;
//Create the WorkerScript
var s = new WorkerScript(script);
s.name = filename;
s.code = script.code;
s.serverIp = server.ip;
s.ramUsage = script.ramUsage;
s.ramUsage = ramUsage;
//Add the WorkerScript to the Active Scripts list
addActiveScriptsItem(s);

View File

@ -126,6 +126,8 @@ function Script() {
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
@ -291,7 +293,7 @@ Script.prototype.displayLog = function() {
}
//Update the moneyStolen and numTimesHack maps when hacking
Script.prototype.recordHack = function(serverIp, moneyGained) {
Script.prototype.recordHack = function(serverIp, moneyGained, n=1) {
if (this.moneyStolenMap == null) {
this.moneyStolenMap = new AllServersMap();
}
@ -299,23 +301,23 @@ Script.prototype.recordHack = function(serverIp, moneyGained) {
this.numTimesHackMap = new AllServersMap();
}
this.moneyStolenMap[serverIp] += moneyGained;
this.numTimesHackMap[serverIp] += 1;
this.numTimesHackMap[serverIp] += n;
}
//Update the grow map when calling grow()
Script.prototype.recordGrow = function(serverIp) {
Script.prototype.recordGrow = function(serverIp, n=1) {
if (this.numTimesGrowMap == null) {
this.numTimesGrowMap = new AllServersMap();
}
this.numTimesGrowMap[serverIp] += 1;
this.numTimesGrowMap[serverIp] += n;
}
//Update the weaken map when calling weaken() {
Script.prototype.recordWeaken = function(serverIp) {
Script.prototype.recordWeaken = function(serverIp, n=1) {
if (this.numTimesWeakenMap == null) {
this.numTimesWeakenMap = new AllServersMap();
}
this.numTimesWeakenMap[serverIp] += 1;
this.numTimesWeakenMap[serverIp] += n;
}
Script.prototype.toJSON = function() {

View File

@ -464,8 +464,8 @@ initForeignServers = function() {
AddToAllServers(HongFangTeaHouseServer);
var HaraKiriSushiBarServer = new Server();
HaraKiriSushiBarServer.setHackingParameters(40, 3500000, 15, 40);
HaraKiriSushiBarServer.init(createRandomIp(), "harakiri-sushi", "HaraKiri Sushi Bar Network", true, false, false, false, 4);
HaraKiriSushiBarServer.setHackingParameters(40, 3500000, 15, 40);
HaraKiriSushiBarServer.setPortProperties(0);
AddToAllServers(HaraKiriSushiBarServer);
@ -527,7 +527,7 @@ initForeignServers = function() {
SpecialServerIps.addIp(SpecialServerNames.BitRunnersServer, BitRunnersServer.ip);
var TheBlackHandServer = new Server();
TheBlackHandServer.init(createRandomIp(), "I.I.I.I", "I.I.I.I", true, false, false, false, false, 0);
TheBlackHandServer.init(createRandomIp(), "I.I.I.I", "I.I.I.I", true, false, false, false, 0);
TheBlackHandServer.setHackingParameters(getRandomInt(303, 325), 0, 0, 0);
TheBlackHandServer.setPortProperties(3);
AddToAllServers(TheBlackHandServer);
@ -706,7 +706,7 @@ processSingleServerGrowth = function(server, numCycles) {
server.moneyAvailable = server.moneyMax;
return 1;
}
server.fortify(2 * CONSTANTS.ServerFortifyAmount);
server.fortify(2 * CONSTANTS.ServerFortifyAmount * numServerGrowthCycles);
return serverGrowth;
}

View File

@ -730,13 +730,31 @@ var Terminal = {
break;
case "mem":
if (commandArray.length != 2) {
post("Incorrect usage of mem command. usage: mem [scriptname]"); return;
post("Incorrect usage of mem command. usage: mem [scriptname] [-t] [number threads]"); return;
}
var scriptName = commandArray[1];
var numThreads = 1;
if (scriptName.indexOf(" -t ") != -1) {
var results = scriptName.split(" ");
if (results.length != 3) {
post("Invalid use of run command. Usage: mem [script] [-t] [number threads]");
return;
}
numThreads = Math.round(Number(results[2]));
if (isNaN(numThreads) || numThreads < 1) {
post("Invalid number of threads specified. Number of threads must be greater than 1");
return;
}
scriptName = results[0];
}
var currServ = Player.getCurrentServer();
for (var i = 0; i < currServ.scripts.length; ++i) {
if (scriptName == currServ.scripts[i].filename) {
post("This script requires " + formatNumber(currServ.scripts[i].ramUsage, 2) + "GB of RAM to run");
var scriptBaseRamUsage = currServ.scripts[i].ramUsage;
var ramUsage = scriptBaseRamUsage * numThreads * Math.pow(1.02, numThreads-1);
post("This script requires " + formatNumber(ramUsage, 2) + "GB of RAM to run for " + numThreads + " thread(s)");
return;
}
}
@ -807,7 +825,7 @@ var Terminal = {
case "run":
//Run a program or a script
if (commandArray.length != 2) {
post("Incorrect number of arguments. Usage: run [program/script]");
post("Incorrect number of arguments. Usage: run [program/script] [-t] [number threads]");
} else {
var executableName = commandArray[1];
//Check if its a script or just a program/executable
@ -1135,31 +1153,50 @@ var Terminal = {
runScript: function(scriptName) {
var server = Player.getCurrentServer();
//Check if this script is already running
var numThreads = 1;
//Get the number of threads
if (scriptName.indexOf(" -t ") != -1) {
var results = scriptName.split(" ");
if (results.length != 3) {
post("Invalid use of run command. Usage: run [script] [-t] [number threads]");
return;
}
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
for (var i = 0; i < server.runningScripts.length; i++) {
if (server.runningScripts[i] == scriptName) {
post("ERROR: This script is already running. Cannot run multiple instances");
return;
}
}
//Check if the script exists and if it does run it
for (var i = 0; i < server.scripts.length; i++) {
if (server.scripts[i].filename == scriptName) {
//Check for admin rights and that there is enough RAM availble to run
var ramUsage = server.scripts[i].ramUsage;
var script = server.scripts[i];
script.threads = numThreads;
var ramUsage = script.ramUsage * numThreads * Math.pow(1.02, numThreads-1);
var ramAvailable = server.maxRam - server.ramUsed;
if (server.hasAdminRights == false) {
post("Need root access to run script");
return;
} else if (ramUsage > ramAvailable){
post("This machine does not have enough RAM to run this script. Script requires " + ramUsage + "GB of RAM");
post("This machine does not have enough RAM to run this script with " +
script.threads + " threads. Script requires " + ramUsage + "GB of RAM");
return;
}else {
//Able to run script
post("Running script. May take a few seconds to start up the process...");
var script = server.scripts[i];
post("Running script with " + script.threads + " thread(s). May take a few seconds to start up the process...");
server.runningScripts.push(script.filename); //Push onto runningScripts
addWorkerScript(script, server);
return;

View File

@ -507,7 +507,7 @@ var Engine = {
updateSkillLevelsCounter: 10, //Only update skill levels every 2 seconds. Might improve performance
updateDisplays: 3, //Update displays such as Active Scripts display and character display
createProgramNotifications: 10, //Checks whether any programs can be created and notifies
checkFactionInvitations: 250, //Check whether you qualify for any faction invitations every 5 minutes
checkFactionInvitations: 100, //Check whether you qualify for any faction invitations every 5 minutes
passiveFactionGrowth: 600,
messages: 300,
},
@ -567,7 +567,7 @@ var Engine = {
var randFaction = invitedFactions[Math.floor(Math.random() * invitedFactions.length)];
inviteToFaction(randFaction);
}
Engine.Counters.checkFactionInvitations = 250;
Engine.Counters.checkFactionInvitations = 100;
}
if (Engine.Counters.passiveFactionGrowth <= 0) {