Merge pull request #157 from danielyxie/dev

v0.32.1
This commit is contained in:
danielyxie 2017-11-02 22:14:01 -05:00 committed by GitHub
commit b7c16e69a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 10066 additions and 3303 deletions

@ -73,8 +73,7 @@
padding: 10px;
}
.dialog-box-close-button,
#log-box-close {
.dialog-box-close-button {
float: right;
color: #aaa;
font-size: 20px;
@ -89,13 +88,21 @@
#log-box-close {
position: fixed;
right: 26%;
right: 27%;
}
#log-box-kill-script {
right: 11%;
position: relative;
}
#log-box-close, #log-box-kill-script {
float:right;
display:inline-block;
}
.dialog-box-close-button:hover,
.dialog-box-close-button:focus,
#log-box-close:hover,
#log-box-close:focus {
.dialog-box-close-button:focus,{
color: white;
text-decoration: none;
cursor: pointer;

11325
dist/bundle.js vendored

File diff suppressed because one or more lines are too long

@ -781,10 +781,12 @@
If you purchase access to the TIX API, you will retain that access even after
you 'reset' by installing Augmentations.
</p>
<a id="stock-market-buy-tix-api" class="a-link-button-inactive"> Buy Trade Information eXchange (TIX) API Access - COMING SOON</a>
<a id="stock-market-buy-tix-api" class="a-link-button-inactive">Buy Trade Information eXchange (TIX) API Access</a>
<a id="stock-market-investopedia" class='a-link-button'>Investopedia</a>
<p id="stock-market-commission"> </p>
<a id="stock-market-mode" class="a-link-button tooltip"></a>
<a id="stock-market-expand-tickers" class="a-link-button tooltip">Expand tickers</a>
<a id="stock-market-collapse-tickers" class="a-link-button tooltip">Collapse tickers</a>
<ul id="stock-market-list" style="list-style:none;">
</ul>
</div>
@ -792,7 +794,8 @@
<!-- Log Box -->
<div id="log-box-container">
<div id="log-box-content">
<span id="log-box-close"> &times; </span>
<span id="log-box-close" class="popup-box-button"> Close </span>
<span id="log-box-kill-script" class="popup-box-button">Kill Script</span>
<p id="log-box-text-header"> </p>
<p id="log-box-text"> </p>
</div>

@ -1,3 +1,6 @@
import {Locations} from "./src/Location.js";
import {getRandomInt} from "../utils/HelperFunctions.js";
/*
Products
For certain industries, players can creat their own custom products
@ -204,3 +207,229 @@ Industries:
will fluctuate based on company performance. Then you can sell whatever
shares you have left on the stock market.
*/
var TOTALSHARES = 1000000000; //Total number of shares you have at your company
function Material(params={}) {
this.name = params.name ? params.name : "";
this.qty = 0; //Quantity
this.qlt = 0; //Quality
this.dmd = 0; //Demand
this.cmp = 0; //Competition
this.mku = 0; //Markup
//How much space it takes in a Warehouse
this.siz = params.size ? params.size : 0;
this.purc = 0; //How much of this material is being purchased per second
this.cost = 0; //$ Cost per material
//Material requirements. An object that maps the name of a material to how much it requires
//to make 1 unit of the product.
this.req = params.req ? params.req : {};
}
var Materials = {
Water: new Material({name: "Water", size: 0.1}),
Energy: new Material
Food: 13,
Plants: 14,
Metal: 15,
Hardware: 16,
Chemicals: 17,
RealEstate: 18,
Drugs: 19,
Robots: 20,
AICores:21,
SciResearch: 22
}
function Product(params={}) {
"use strict"
this.name = params.name ? params.name : 0;
this.dmd = params.demand ? params.demand : 0;
this.cmp = params.competition ? params.competition : 0;
this.mku = params.markup ? params.markup : 0;
this.qlt = params.quality ? params.quality : 0;
this.qty = 0;
this.per = params.performance ? params.performance : 0;
this.dur = params.durability ? params.durability : 0;
this.rel = params.reliability ? params.reliability : 0;
this.aes = params.aesthetics ? params.aesthetics : 0;
this.fea = params.features ? params.features : 0;
this.loc = params.location ? params.location : "";
this.siz = params.size ? params.size : 0; //How much space it takes in the warehouse
//Material requirements. An object that maps the name of a material to how much it requires
//to make 1 unit of the product.
this.req = params.req ? params.req : {};
}
var Industries = {
Energy: 50,
Utilities: 51,
Agriculture: 52,
Fishing: 53,
Mining: 54,
Food: 55,
Tobacco: 56,
Chemical: 57,
Pharmaceutical: 58,
Computer: 59,
Robotics: 60,
Software: 61,
Healthcare: 62,
RealEstate: 63,
}
function Industry(params={}) {
"use strict"
this.offices = { //Maps locations to offices. 0 if no office at that location
Locations.Aevum: 0,
Locations.Chonqing: 0,
Locations.Sector12: 0,
Locations.NewTokyo: 0,
Locations.Ishima: 0,
Locations.Volhaven: 0
};
this.warehouses = { //Maps locations to warehouses. 0 if no warehouse at that location
Locations.Aevum: 0,
Locations.Chonqing: 0,
Locations.Sector12: 0,
Locations.NewTokyo: 0,
Locations.Ishima: 0,
Locations.Volhaven: 0
};
this.type = params.type ? params.type : 0;
this.materials = {}; //Contains both materials that are created and required
this.products = {};
this.awareness = 0;
this.popularity = 0;
this.startingCost = 0;
/* The following are factors for how much production/other things are increased by
different factors. The production increase always has diminishing returns,
and they are all reprsented by inverse exponentials.
The number for these properties represent the denominator in the inverse
exponential (aka higher number = more diminishing returns); */
this.reFac = 0; //Real estate Factor
this.sciFac = 0; //Scientific Research Factor
this.hwFac = 0; //Hardware factor
this.robFac = 0; //Robotics Factor
this.aiFac = 0; //AI Cores factor;
this.advFac = 0; //Advertising factor
this.init();
}
Industry.prototype.init = function() {
//Set the unique properties of an industry (how much its affected by real estate/scientific research, etc.)
switch (this.type) {
case Industries.Energy:
break;
case Industries.Utilities:
break;
case Industries.Agriculture:
break;
case Industries.Fishing:
break;
case Industries.Mining:
break;
case Industries.Food:
break;
case Industries.Tobacco:
break;
case Industries.Chemical:
break;
case Industries.Pharmaceutical:
break;
case Industries.Computer:
break;
case Industries.Robotics:
break;
case Industries.Software:
break;
case Industries.Healthcare:
break;
case Industries.RealEstate:
break;
default:
console.log("ERR: Invalid Industry Type passed into Industry.init()");
return;
}
}
var EmployeePositions = {
Operations: 1,
Engineer: 2,
Business: 3,
Accounting: 4,
Management: 5,
RandD: 6
}
function Employee(params={}) {
"use strict"
if (!(this instanceof Employee)) {
return new Employee(params);
}
this.name = params.name ? params.name : "Bobby";
this.mor = params.morale ? params.morale : getRandomInt(50, 100);
this.hap = params.happiness ? params.happiness : getRandomInt(50, 100);
this.ene = params.energy ? params.energy : getRandomInt(50, 100);
this.age = params.age ? params.age : getRandomInt(20, 50);
this.int = params.intelligence ? params.intelligence : getRandomInt(10, 50);
this.cha = params.charisma ? params.charisma : getRandomInt(10, 50);
this.exp = params.experience ? params.experience : getRandomInt(10, 50);
this.cre = params.creativity ? params.creativity : getRandomInt(10, 50);
this.eff = params.efficiency ? params.efficiency : getRandomInt(10, 50);
this.sal = params.salary ? params.salary : getRandomInt(0.1, 5);
this.pro = 0; //Calculated
this.off = params.officeSpace ? params.officeSpace : {};
this.loc = params.officeSpace ? params.officeSpace.loc : "";
this.pos = 0;
}
var OfficeSpaceTiers = {
Basic: 7,
Enhanced: 8,
Luxurious: 9,
Extravagant: 10
}
function OfficeSpace(params={}) {
"use strict"
this.loc = params.loc ? params.loc : "";
this.cost = params.cost ? params.cost : 1;
this.size = params.size ? params.size : 1;
this.comf = params.comfort ? params.comfort : 1;
this.beau = parms.beauty ? params.beauty : 1;
this.tier = OfficeSpaceTiers.Basic;
this.employees = [];
}
function Warehouse(params={}) {
"use strict"
this.loc = params.loc ? params.loc : "";
this.size = params.size ? params.size : 0;
this.materials = {};
this.products = {};
}
function Company() {
"use strict"
this.industries = [];
//Financial stats
this.funds = 0;
this.revenue = 0;
this.expenses = 0;
this.valuation = 0; //Private investory valuation of company before you go public.
this.numShares = TOTALSHARES;
this.sharePrice = 0;
}

@ -1,5 +1,5 @@
let CONSTANTS = {
Version: "0.32.0",
Version: "0.32.1",
//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
@ -647,10 +647,21 @@ let CONSTANTS = {
"have purchased. It takes an optional parameter specifying whether the hostname or IP addresses will be returned. If this " +
"parameter is not specified, it is true by default and hostnames will be returned<br><br>" +
"<i><u>round(n)</u></i><br>Rounds the number n to the nearest integer. If the argument passed in is not a number, then the function will return 0.<br><br>" +
"<i><u>write(port, data)</u></i><br>Writes data to a port. The first argument must be a number between 1 and 10 that specifies the port. The second " +
"argument defines the data to write to the port. If the second argument is not specified then it will write an empty string to the port.<br><br>" +
"<i><u>read(port)</u></i><br>Reads data from a port. The first argument must be a number between 1 and 10 that specifies the port. A port is a serialized queue. " +
"This function will remove the first element from the queue and return it. If the queue is empty, then the string 'NULL PORT DATA' will be returned. <br><br>" +
"<i><u>write(port, data='', mode='a')</u></i><br>This function can be used to either write data to a port or to a text file (.txt).<br><br>" +
"If the first argument is a number between 1 and 10, then it specifies a port and this function will write data to a port. If the second " +
"argument is not specified then it will write an empty string to the port. The third argument, mode, is not used when writing data to a port.<br><br>" +
"If the first argument is a string, then it specifies the name of a text file (.txt) and this function will write data to a text file. " +
"The second argument defines the data to be written to the text file. If it is not specified then it is an empty string by default. " +
"This third argument, mode, defines how the data will be written to the text file. If mode is set to 'w', then the data is written in 'write' " +
"mode which means that it will overwrite the existing data on the file, or it will create a new file if it does not already exist. Otherwise, " +
"the data will be written in 'append' mode which means that the data will be added at the end of the existing file, or it will create a new file if it " +
"does not already exist. If mode isn't specified then it will be 'a' for 'append' mode by default.<br><br>" +
"<i><u>read(port)</u></i><br>This function is used to read data from a port or from a text file (.txt).<br><br>" +
"This function takes a single argument. If this argument is a number between 1 and 10, then it specifies a port and it will read data from " +
"a port. A port is a serialized queue. This function will remove the first element from the queue and return it. If the queue is empty, " +
"then the string 'NULL PORT DATA' will be returned.<br><br>" +
"If the first argument is a string, then it specifies the name of a text file and this function will return the data in the " +
"specified text file. If the text file does not exist, an empty string will be returned<br><br>" +
"<i><u>scriptRunning(scriptname, hostname/ip)</u></i><br>Returns a boolean indicating whether any instance of the specified script is running " +
"on a server, regardless of its arguments. This is different than the isRunning() function because it does not " +
"try to identify a specific instance of a running script by its arguments.<br><br>" +
@ -696,6 +707,11 @@ let CONSTANTS = {
"Returns the amount of time in milliseconds that have passed since you last installed Augmentations (or destroyed a BitNode).<br><br>" +
"<i><u>sprintf()/vsprintf()</u></i><br>" +
"<a href='https://github.com/alexei/sprintf.js' target='_blank'>See this link for details</a><br><br>" +
"<i><u>prompt(message)</u></i><br>" +
"Prompts the player with a dialog box with two options: 'Yes' and 'No'. This function will returns true if " +
"the player clicks 'Yes' and false if the player click's 'No'. The script's execution is halted until the " +
"player selects 'Yes' or 'No'. The function takes a single string as an argument which specifies the text " +
"that appears on the dialog box.<br><br>" +
"<u><h1>Hacknet Nodes API</h1></u><br>" +
"Netscript provides the following API for accessing and upgrading your Hacknet Nodes through scripts. This API does NOT work offline.<br><br>" +
"<i><u>hacknetnodes</u></i><br>A special variable. This is an array that maps to the Player's Hacknet Nodes. The Hacknet Nodes are accessed through " +
@ -1096,6 +1112,14 @@ let CONSTANTS = {
"World Stock Exchange account and TIX API Access<br>",
LatestUpdate:
"v0.32.1<br>" +
"-Updated Netscript's 'interpreter/engine' to use the Bluebird promise library instead of native promises. " +
"It should now be faster and more memory-efficient. If this has broken any Netscript features please report it through Github or the subreddit (reddit.com/r/bitburner)<br>" +
"-Rebalanced stock market (adjusted parameters such as the volatility/trends/starting price of certain stocks)<br>" +
"-Added prompt() Netscript function<br>" +
"-Added 'Buy Max' and 'Sell All' functions to Stock Market UI<br>" +
"-Added 'Portfolio' Mode to Stock Market UI so you can only view stocks you have a position/order in<br>" +
"-Added a button to kill a script from its log display box<br><br>" +
"v0.32.0<br>" +
"-Released BitNode-8: Ghost of Wall Street<br>" +
"-Re-designed Stock Market UI<br>" +

@ -13,72 +13,72 @@ import {printArray} from "../utils/HelperFunctions.js";
import {isValidIPAddress} from "../utils/IPAddress.js";
import {isString} from "../utils/StringHelperFunctions.js";
var Promise = require("bluebird");
Promise.config({
warnings: false,
longStackTraces: false,
cancellation: true,
monitoring: false
});
/* Evaluator
* Evaluates/Interprets the Abstract Syntax Tree generated by Acorns parser
*
* Returns a promise
*/
function evaluate(exp, workerScript) {
return new Promise(function(resolve, reject) {
/* return new Promise(function(resolve, reject) {*/
return Promise.delay(Settings.CodeInstructionRunTime).then(function() {
var env = workerScript.env;
if (env.stopFlag) {return reject(workerScript);}
if (env.stopFlag) {return Promise.reject(workerScript);}
if (exp == null) {
return reject(makeRuntimeRejectMsg(workerScript, "Error: NULL expression"));
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Error: NULL expression"));
}
setTimeout(function() {
if (env.stopFlag) {return reject(workerScript);}
if (env.stopFlag) {return Promise.reject(workerScript);}
switch (exp.type) {
case "BlockStatement":
case "Program":
var evaluateProgPromise = evaluateProg(exp, workerScript, 0); //TODO: make every block/program use individual enviroment
evaluateProgPromise.then(function(w) {
resolve(workerScript);
}, function(e) {
return evaluateProgPromise.then(function(w) {
return Promise.resolve(workerScript);
}).catch(function(e) {
if (e.constructor === Array && e.length === 2 && e[0] === "RETURNSTATEMENT") {
reject(e);
return Promise.reject(e);
} else if (isString(e)) {
workerScript.errorMessage = e;
reject(workerScript);
return Promise.reject(workerScript);
} else if (e instanceof WorkerScript) {
reject(e);
return Promise.reject(e);
} else {
reject(workerScript);
return Promise.reject(workerScript);
}
});
break;
case "Literal":
resolve(exp.value);
return Promise.resolve(exp.value);
break;
case "Identifier":
if (!(exp.name in env.vars)){
reject(makeRuntimeRejectMsg(workerScript, "variable " + exp.name + " not defined"));
return Promise.reject(makeRuntimeRejectMsg(workerScript, "variable " + exp.name + " not defined"));
}
resolve(env.get(exp.name))
return Promise.resolve(env.get(exp.name))
break;
case "ExpressionStatement":
var e = evaluate(exp.expression, workerScript);
e.then(function(res) {
resolve(res);
}, function(e) {
reject(e);
});
return evaluate(exp.expression, workerScript);
break;
case "ArrayExpression":
var argPromises = exp.elements.map(function(arg) {
return evaluate(arg, workerScript);
});
Promise.all(argPromises).then(function(array) {
resolve(array)
}).catch(function(e) {
reject(e);
return Promise.all(argPromises).then(function(array) {
return Promise.resolve(array)
});
break;
case "CallExpression":
evaluate(exp.callee, workerScript).then(function(func) {
var argPromises = exp.arguments.map(function(arg) {
return evaluate(exp.callee, workerScript).then(function(func) {
return Promise.map(exp.arguments, function(arg) {
return evaluate(arg, workerScript);
});
Promise.all(argPromises).then(function(args) {
}).then(function(args) {
if (func instanceof Node) { //Player-defined function
//Create new Environment for the function
//Should be automatically garbage collected...
@ -101,129 +101,102 @@ function evaluate(exp, workerScript) {
funcWorkerScript.env = funcEnv;
workerScript.fnWorker = funcWorkerScript;
evaluate(func.body, funcWorkerScript).then(function(res) {
return evaluate(func.body, funcWorkerScript).then(function(res) {
//If the function finished successfuly, that means there
//was no return statement since a return statement rejects. So resolve to null
resolve(null);
workerScript.fnWorker = null;
return Promise.resolve(null);
}).catch(function(e) {
if (e.constructor === Array && e.length === 2 && e[0] === "RETURNSTATEMENT") {
//Return statement from function
resolve(e[1]);
return Promise.resolve(e[1]);
workerScript.fnWorker = null;
} else if (isString(e)) {
reject(makeRuntimeRejectMsg(workerScript, e));
return Promise.reject(makeRuntimeRejectMsg(workerScript, e));
} else if (e instanceof WorkerScript) {
//Parse out the err message from the WorkerScript and re-reject
var errorMsg = e.errorMessage;
var errorTextArray = errorMsg.split("|");
if (errorTextArray.length === 4) {
errorMsg = errorTextArray[3];
reject(makeRuntimeRejectMsg(workerScript, errorMsg));
return Promise.reject(makeRuntimeRejectMsg(workerScript, errorMsg));
} else {
if (env.stopFlag) {
reject(workerScript);
return Promise.reject(workerScript);
} else {
reject(makeRuntimeRejectMsg(workerScript, "Error in one of your functions. Could not identify which function"));
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Error in one of your functions. Could not identify which function"));
}
}
} else if (e instanceof Error) {
reject(makeRuntimeRejectMsg(workerScript, e.toString()));
return Promise.reject(makeRuntimeRejectMsg(workerScript, e.toString()));
}
});
} else if (exp.callee.type == "MemberExpression"){
evaluate(exp.callee.object, workerScript).then(function(object) {
return evaluate(exp.callee.object, workerScript).then(function(object) {
try {
var res = func.apply(object,args);
resolve(res);
return Promise.resolve(res);
} catch (e) {
reject(makeRuntimeRejectMsg(workerScript, e));
return Promise.reject(makeRuntimeRejectMsg(workerScript, e));
}
}).catch(function(e) {
reject(e);
});
} else {
try {
var out = func.apply(null,args);
if (out instanceof Promise){
out.then(function(res) {
resolve(res)
return out.then(function(res) {
return Promise.resolve(res)
}).catch(function(e) {
reject(e);
return Promise.reject(e);
});
} else {
resolve(out);
return Promise.resolve(out);
}
} catch (e) {
if (isScriptErrorMessage(e)) {
reject(e);
return Promise.reject(e);
} else {
reject(makeRuntimeRejectMsg(workerScript, e));
return Promise.reject(makeRuntimeRejectMsg(workerScript, e));
}
}
}
}).catch(function(e) {
reject(e);
});
}).catch(function(e) {
reject(e);
});
break;
case "MemberExpression":
var pObject = evaluate(exp.object, workerScript);
pObject.then(function(object) {
return evaluate(exp.object, workerScript).then(function(object) {
if (exp.computed){
var p = evaluate(exp.property, workerScript);
p.then(function(index) {
return evaluate(exp.property, workerScript).then(function(index) {
if (index >= object.length) {
return reject(makeRuntimeRejectMsg(workerScript, "Invalid index for arrays"));
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Invalid index for arrays"));
}
resolve(object[index]);
return Promise.resolve(object[index]);
}).catch(function(e) {
reject(makeRuntimeRejectMsg(workerScript, "Invalid MemberExpression"));
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Invalid MemberExpression"));
});
} else {
try {
resolve(object[exp.property.name])
return Promise.resolve(object[exp.property.name])
} catch (e) {
return reject(makeRuntimeRejectMsg(workerScript, "Failed to get property: " + e.toString()));
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Failed to get property: " + e.toString()));
}
}
}).catch(function(e) {
reject(e);
});
break;
case "LogicalExpression":
case "BinaryExpression":
var p = evalBinary(exp, workerScript, resolve, reject);
p.then(function(res) {
resolve(res);
}).catch(function(e) {
reject(e);
});
return evalBinary(exp, workerScript);
break;
case "UnaryExpression":
var p = evalUnary(exp, workerScript, resolve, reject);
p.then(function(res) {
resolve(res);
}).catch(function(e) {
reject(e);
});
return evalUnary(exp, workerScript);
break;
case "AssignmentExpression":
var p = evalAssignment(exp, workerScript);
p.then(function(res) {
resolve(res);
}).catch(function(e) {
reject(e);
});
return evalAssignment(exp, workerScript);
break;
case "UpdateExpression":
if (exp.argument.type==="Identifier"){
if (exp.argument.name in env.vars){
if (exp.prefix){
resolve(env.get(exp.argument.name))
}
if (exp.operator === "++" || exp.operator === "--") {
switch (exp.operator) {
case "++":
env.set(exp.argument.name,env.get(exp.argument.name)+1);
@ -231,191 +204,176 @@ function evaluate(exp, workerScript) {
case "--":
env.set(exp.argument.name,env.get(exp.argument.name)-1);
break;
default: break;
}
return Promise.resolve(env.get(exp.argument.name));
}
//Not sure what prefix UpdateExpressions there would be besides ++/--
if (exp.prefix){
return Promise.resolve(env.get(exp.argument.name))
}
switch (exp.operator){
default:
reject(makeRuntimeRejectMsg(workerScript, "Unrecognized token: " + exp.type + ". You are trying to use code that is currently unsupported"));
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Unrecognized token: " + exp.type + ". You are trying to use code that is currently unsupported"));
}
if (env.prefix){
return;
}
resolve(env.get(exp.argument.name))
return Promise.resolve(env.get(exp.argument.name))
} else {
reject(makeRuntimeRejectMsg(workerScript, "variable " + exp.argument.name + " not defined"));
return Promise.reject(makeRuntimeRejectMsg(workerScript, "variable " + exp.argument.name + " not defined"));
}
} else {
reject(makeRuntimeRejectMsg(workerScript, "argument must be an identifier"));
return Promise.reject(makeRuntimeRejectMsg(workerScript, "argument must be an identifier"));
}
break;
case "EmptyStatement":
resolve(false);
return Promise.resolve(false);
break;
case "ReturnStatement":
console.log("Evaluating Return Statement");
//var lineNum = getErrorLineNumber(exp, workerScript);
//reject(makeRuntimeRejectMsg(workerScript, "Return statements are not yet implemented in Netscript (line " + (lineNum+1) + ")"));
evaluate(exp.argument, workerScript).then(function(res) {
reject(["RETURNSTATEMENT", res]);
}).catch(function(e) {
reject(e);
return evaluate(exp.argument, workerScript).then(function(res) {
return Promise.reject(["RETURNSTATEMENT", res]);
});
break;
case "BreakStatement":
reject("BREAKSTATEMENT");
return Promise.reject("BREAKSTATEMENT");
break;
case "ContinueStatement":
reject("CONTINUESTATEMENT");
return Promise.reject("CONTINUESTATEMENT");
break;
case "IfStatement":
evaluateIf(exp, workerScript).then(function(forLoopRes) {
resolve(forLoopRes);
}).catch(function(e) {
reject(e);
});
return evaluateIf(exp, workerScript);
break;
case "SwitchStatement":
var lineNum = getErrorLineNumber(exp, workerScript);
reject(makeRuntimeRejectMsg(workerScript, "Switch statements are not yet implemented in Netscript (line " + (lineNum+1) + ")"));
break;e
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Switch statements are not yet implemented in Netscript (line " + (lineNum+1) + ")"));
break;
case "WhileStatement":
evaluateWhile(exp, workerScript).then(function(forLoopRes) {
resolve(forLoopRes);
return evaluateWhile(exp, workerScript).then(function(res) {
return Promise.resolve(res);
}).catch(function(e) {
if (e == "BREAKSTATEMENT" ||
(e instanceof WorkerScript && e.errorMessage == "BREAKSTATEMENT")) {
return resolve("whileLoopBroken");
return Promise.resolve("whileLoopBroken");
} else {
reject(e);
return Promise.reject(e);
}
});
break;
case "ForStatement":
evaluate(exp.init, workerScript).then(function(expInit) {
return evaluate(exp.init, workerScript).then(function(expInit) {
return evaluateFor(exp, workerScript);
}).then(function(forLoopRes) {
resolve("forLoopDone");
return Promise.resolve("forLoopDone");
}).catch(function(e) {
if (e == "BREAKSTATEMENT" ||
(e instanceof WorkerScript && e.errorMessage == "BREAKSTATEMENT")) {
return resolve("forLoopBroken");
return Promise.resolve("forLoopBroken");
} else {
reject(e);
return Promise.reject(e);
}
});
break;
case "FunctionDeclaration":
if (exp.id && exp.id.name) {
env.set(exp.id.name, exp);
resolve(true);
return Promise.resolve(true);
} else {
var lineNum = getErrorLineNumber(exp, workerScript);
reject(makeRuntimeRejectMsg(workerScript, "Invalid function declaration at line " + lineNum+1));
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Invalid function declaration at line " + lineNum+1));
}
break;
default:
var lineNum = getErrorLineNumber(exp, workerScript);
reject(makeRuntimeRejectMsg(workerScript, "Unrecognized token: " + exp.type + " (line " + (lineNum+1) + "). This is currently unsupported in Netscript"));
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Unrecognized token: " + exp.type + " (line " + (lineNum+1) + "). This is currently unsupported in Netscript"));
break;
} //End switch
}, Settings.CodeInstructionRunTime); //End setTimeout, the Netscript operation run time
}).catch(function(e) {
return Promise.reject(e);
}); // End Promise
}
function evalBinary(exp, workerScript){
return new Promise(function(resolve, reject) {
var expLeftPromise = evaluate(exp.left, workerScript);
expLeftPromise.then(function(expLeft) {
return evaluate(exp.left, workerScript).then(function(expLeft) {
//Short circuiting
if (expLeft == true && exp.operator === "||") {
return resolve(true);
return Promise.resolve(true);
}
if (expLeft == false && exp.operator === "&&") {
return resolve(false);
return Promise.resolve(false);
}
var expRightPromise = evaluate(exp.right, workerScript);
expRightPromise.then(function(expRight) {
return evaluate(exp.right, workerScript).then(function(expRight) {
switch (exp.operator){
case "===":
case "==":
resolve(expLeft===expRight);
return Promise.resolve(expLeft===expRight);
break;
case "!==":
case "!=":
resolve(expLeft!==expRight);
return Promise.resolve(expLeft!==expRight);
break;
case "<":
resolve(expLeft<expRight);
return Promise.resolve(expLeft<expRight);
break;
case "<=":
resolve(expLeft<=expRight);
return Promise.resolve(expLeft<=expRight);
break;
case ">":
resolve(expLeft>expRight);
return Promise.resolve(expLeft>expRight);
break;
case ">=":
resolve(expLeft>=expRight);
return Promise.resolve(expLeft>=expRight);
break;
case "+":
resolve(expLeft+expRight);
return Promise.resolve(expLeft+expRight);
break;
case "-":
resolve(expLeft-expRight);
return Promise.resolve(expLeft-expRight);
break;
case "*":
resolve(expLeft*expRight);
return Promise.resolve(expLeft*expRight);
break;
case "/":
if (expRight === 0) {
reject(makeRuntimeRejectMsg(workerScript, "ERROR: Divide by zero"));
return Promise.reject(makeRuntimeRejectMsg(workerScript, "ERROR: Divide by zero"));
} else {
resolve(expLeft/expRight);
return Promise.resolve(expLeft/expRight);
}
break;
case "%":
resolve(expLeft%expRight);
return Promise.resolve(expLeft%expRight);
break;
case "in":
resolve(expLeft in expRight);
return Promise.resolve(expLeft in expRight);
break;
case "instanceof":
resolve(expLeft instanceof expRight);
return Promise.resolve(expLeft instanceof expRight);
break;
case "||":
resolve(expLeft || expRight);
return Promise.resolve(expLeft || expRight);
break;
case "&&":
resolve(expLeft && expRight);
return Promise.resolve(expLeft && expRight);
break;
default:
reject(makeRuntimeRejectMsg(workerScript, "Unsupported operator: " + exp.operator));
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Unsupported operator: " + exp.operator));
}
}, function(e) {
reject(e);
});
}, function(e) {
reject(e);
});
});
}
function evalUnary(exp, workerScript){
var env = workerScript.env;
return new Promise(function(resolve, reject) {
if (env.stopFlag) {return reject(workerScript);}
var p = evaluate(exp.argument, workerScript);
p.then(function(res) {
if (env.stopFlag) {return Promise.reject(workerScript);}
return evaluate(exp.argument, workerScript).then(function(res) {
if (exp.operator == "!") {
resolve(!res);
return Promise.resolve(!res);
} else if (exp.operator == "-") {
if (isNaN(res)) {
resolve(res);
return Promise.resolve(res);
} else {
resolve(-1 * res);
return Promise.resolve(-1 * res);
}
} else {
reject(makeRuntimeRejectMsg(workerScript, "Unimplemented unary operator: " + exp.operator));
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Unimplemented unary operator: " + exp.operator));
}
}).catch(function(e) {
reject(e);
});
});
}
@ -423,59 +381,48 @@ function evalUnary(exp, workerScript){
//The return value is an array of the form:
// [0th index (leftmost), array name, 1st index, 2nd index, ...]
function getArrayElement(exp, workerScript) {
return new Promise(function(resolve, reject) {
var indices = [];
var iPromise = evaluate(exp.property, workerScript);
iPromise.then(function(idx) {
return evaluate(exp.property, workerScript).then(function(idx) {
if (isNaN(idx)) {
return reject(makeRuntimeRejectMsg(workerScript, "Invalid access to array. Index is not a number: " + idx));
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Invalid access to array. Index is not a number: " + idx));
} else {
if (exp.object.name === undefined && exp.object.object) {
var recursePromise = getArrayElement(exp.object, workerScript);
recursePromise.then(function(res) {
return getArrayElement(exp.object, workerScript).then(function(res) {
res.push(idx);
indices = res;
return resolve(indices);
return Promise.resolve(indices);
}).catch(function(e) {
return reject(e);
return Promise.reject(e);
});
} else {
indices.push(idx);
indices.push(exp.object.name);
return resolve(indices);
return Promise.resolve(indices);
}
}
}).catch(function(e) {
console.log(e);
console.log("Error getting index in getArrayElement: " + e.toString());
return reject(e);
});
});
}
function evalAssignment(exp, workerScript) {
var env = workerScript.env;
return new Promise(function(resolve, reject) {
if (env.stopFlag) {return reject(workerScript);}
if (env.stopFlag) {return Promise.reject(workerScript);}
if (exp.left.type != "Identifier" && exp.left.type != "MemberExpression") {
return reject(makeRuntimeRejectMsg(workerScript, "Cannot assign to " + JSON.stringify(exp.left)));
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Cannot assign to " + JSON.stringify(exp.left)));
}
if (exp.operator !== "=" && !(exp.left.name in env.vars)){
return reject(makeRuntimeRejectMsg(workerScript, "variable " + exp.left.name + " not defined"));
return Promise.reject(makeRuntimeRejectMsg(workerScript, "variable " + exp.left.name + " not defined"));
}
var expRightPromise = evaluate(exp.right, workerScript);
expRightPromise.then(function(expRight) {
return evaluate(exp.right, workerScript).then(function(expRight) {
if (exp.left.type == "MemberExpression") {
//Assign to array element
//Array object designed by exp.left.object.name
//Index designated by exp.left.property
var getArrayElementPromise = getArrayElement(exp.left, workerScript);
getArrayElementPromise.then(function(res) {
return getArrayElement(exp.left, workerScript).then(function(res) {
if (!(res instanceof Array) || res.length < 2) {
return reject(makeRuntimeRejectMsg(workerScript, "Error evaluating array assignment. This is (probably) a bug please report to game dev"));
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Error evaluating array assignment. This is (probably) a bug please report to game dev"));
}
//The array name is the second value
@ -483,32 +430,10 @@ function evalAssignment(exp, workerScript) {
arrName = arrName[0];
env.setArrayElement(arrName, res, expRight);
return resolve(false);
return Promise.resolve(false);
}).catch(function(e) {
return reject(e);
return Promise.reject(e);
});
/*
var name = exp.left.object.name;
if (!(name in env.vars)){
reject(makeRuntimeRejectMsg(workerScript, "variable " + name + " not defined"));
}
var arr = env.get(name);
if (arr.constructor === Array || arr instanceof Array) {
var iPromise = evaluate(exp.left.property, workerScript);
iPromise.then(function(idx) {
if (isNaN(idx)) {
return reject(makeRuntimeRejectMsg(workerScript, "Invalid access to array. Index is not a number: " + idx));
} else if (idx >= arr.length || idx < 0) {
return reject(makeRuntimeRejectMsg(workerScript, "Out of bounds: Invalid index in [] operator"));
} else {
env.setArrayElement(name, idx, expRight);
}
}).catch(function(e) {
return reject(e);
});
} else {
return reject(makeRuntimeRejectMsg(workerScript, "Trying to access a non-array variable using the [] operator"));
}*/
} else {
//Other assignments
try {
@ -532,202 +457,193 @@ function evalAssignment(exp, workerScript) {
env.set(exp.left.name,env.get(exp.left.name) % expRight);
break;
default:
reject(makeRuntimeRejectMsg(workerScript, "Bitwise assignment is not implemented"));
return Promise.reject(makeRuntimeRejectMsg(workerScript, "Bitwise assignment is not implemented"));
}
resolve(false);
return Promise.resolve(false);
} catch (e) {
return reject(makeRuntimeRejectMsg(workerScript, "Failed to set environment variable: " + e.toString()));
return Promise.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 evaluateIf(exp, workerScript, i) {
var env = workerScript.env;
return new Promise(function(resolve, reject) {
evaluate(exp.test, workerScript).then(function(condRes) {
return evaluate(exp.test, workerScript).then(function(condRes) {
if (condRes) {
evaluate(exp.consequent, workerScript).then(function(res) {
resolve(true);
return evaluate(exp.consequent, workerScript).then(function(res) {
return Promise.resolve(true);
}, function(e) {
reject(e);
return Promise.reject(e);
});
} else if (exp.alternate) {
evaluate(exp.alternate, workerScript).then(function(res) {
resolve(true);
return evaluate(exp.alternate, workerScript).then(function(res) {
return Promise.resolve(true);
}, function(e) {
reject(e);
return Promise.reject(e);
});
} else {
resolve("endIf")
return Promise.resolve("endIf");
}
}, function(e) {
reject(e);
});
});
}
//Evaluate the looping part of a for loop (Initialization block is NOT done in here)
function evaluateFor(exp, workerScript) {
var env = workerScript.env;
if (env.stopFlag) {return Promise.reject(workerScript);}
return new Promise(function(resolve, reject) {
if (env.stopFlag) {reject(workerScript); return;}
var pCond = evaluate(exp.test, workerScript);
pCond.then(function(resCond) {
function recurse() {
//Don't return a promise so the promise chain is broken on each recursion (saving memory)
evaluate(exp.test, workerScript).then(function(resCond) {
if (resCond) {
//Run the for loop code
var pBody = evaluate(exp.body, workerScript);
//After the code executes make a recursive call
pBody.then(function(resCode) {
var pUpdate = evaluate(exp.update, workerScript);
pUpdate.then(function(resPostloop) {
var recursiveCall = evaluateFor(exp, workerScript);
recursiveCall.then(function(foo) {
resolve("endForLoop");
}, function(e) {
reject(e);
});
}, function(e) {
reject(e);
});
}, function(e) {
return evaluate(exp.body, workerScript).then(function(res) {
return evaluate(exp.update, workerScript);
}).catch(function(e) {
if (e == "CONTINUESTATEMENT" ||
(e instanceof WorkerScript && e.errorMessage == "CONTINUESTATEMENT")) {
//Continue statement, recurse to next iteration
var pUpdate = evaluate(exp.update, workerScript);
pUpdate.then(function(resPostloop) {
var recursiveCall = evaluateFor(exp, workerScript);
recursiveCall.then(function(foo) {
resolve("endForLoop");
}, function(e) {
reject(e);
});
}, function(e) {
reject(e);
return evaluate(exp.update, workerScript).then(function(resPostloop) {
return evaluateFor(exp, workerScript);
}).then(function(foo) {
return Promise.resolve("endForLoop");
}).catch(function(e) {
return Promise.reject(e);
});
} else {
reject(e);
return Promise.reject(e);
}
}).then(recurse, reject).catch(function(e) {
return Promise.reject(e);
});
} else {
resolve("endForLoop"); //Doesn't need to resolve to any particular value
resolve();
}
}, function(e) {
}).catch(function(e) {
reject(e);
});
}
recurse();
});
/*
return evaluate(exp.test, workerScript).then(function(resCond) {
if (resCond) {
//Execute code (body), update, and then recurse
return evaluate(exp.body, workerScript).then(function(resCode) {
return evaluate(exp.update, workerScript);
}).catch(function(e) {
if (e == "CONTINUESTATEMENT" ||
(e instanceof WorkerScript && e.errorMessage == "CONTINUESTATEMENT")) {
//Continue statement, recurse to next iteration
return evaluate(exp.update, workerScript).then(function(resPostloop) {
return evaluateFor(exp, workerScript);
}).then(function(foo) {
return Promise.resolve("endForLoop");
}).catch(function(e) {
return Promise.reject(e);
});
} else {
return Promise.reject(e);
}
}).then(function(resPostloop) {
return evaluateFor(exp, workerScript);
}).then(function(foo) {
return Promise.resolve("endForLoop");
});
} else {
return Promise.resolve("endForLoop"); //Doesn't need to resolve to any particular value
}
});*/
}
function evaluateWhile(exp, workerScript) {
var env = workerScript.env;
if (env.stopFlag) {return Promise.reject(workerScript);}
return new Promise(function (resolve, reject) {
if (env.stopFlag) {reject(workerScript); return;}
var pCond = new Promise(function(resolve, reject) {
setTimeout(function() {
var evaluatePromise = evaluate(exp.test, workerScript);
evaluatePromise.then(function(resCond) {
resolve(resCond);
}, function(e) {
reject(e);
});
}, CONSTANTS.CodeInstructionRunTime);
});
pCond.then(function(resCond) {
function recurse() {
//Don't return a promise so the promise chain is broken on each recursion (saving memory)
evaluate(exp.test, workerScript).then(function(resCond) {
if (resCond) {
//Run the while loop code
var pCode = new Promise(function(resolve, reject) {
setTimeout(function() {
var evaluatePromise = evaluate(exp.body, workerScript);
evaluatePromise.then(function(resCode) {
resolve(resCode);
}, function(e) {
return evaluate(exp.body, workerScript).catch(function(e) {
if (e == "CONTINUESTATEMENT" ||
(e instanceof WorkerScript && e.errorMessage == "CONTINUESTATEMENT")) {
//Continue statement, recurse
var recursiveCall = evaluateWhile(exp, workerScript);
recursiveCall.then(function(foo) {
resolve("endWhileLoop");
return evaluateWhile(exp, workerScript).then(function(foo) {
return Promise.resolve("endWhileLoop");
}, function(e) {
reject(e);
return Promise.reject(e);
});
} else {
reject(e);
return Promise.reject(e);
}
});
}, CONSTANTS.CodeInstructionRunTime);
});
//After the code executes make a recursive call
pCode.then(function(resCode) {
var recursiveCall = evaluateWhile(exp, workerScript);
recursiveCall.then(function(foo) {
resolve("endWhileLoop");
}, function(e) {
reject(e);
});
}, function(e) {
reject(e);
}).then(recurse, reject).catch(function(e) {
return Promise.reject(e);
});
} else {
resolve("endWhileLoop"); //Doesn't need to resolve to any particular value
resolve();
}
}, function(e) {
}).catch(function(e) {
reject(e);
});
}
recurse();
});
}
function evaluateProg(exp, workerScript, index) {
var env = workerScript.env;
return new Promise(function(resolve, reject) {
if (env.stopFlag) {reject(workerScript); return;}
if (env.stopFlag) {return Promise.reject(workerScript);}
if (index >= exp.body.length) {
resolve("progFinished");
return Promise.resolve("progFinished");
} else {
//Evaluate this line of code in the prog
var code = new Promise(function(resolve, reject) {
setTimeout(function() {
var evaluatePromise = evaluate(exp.body[index], workerScript);
evaluatePromise.then(function(evalRes) {
resolve(evalRes);
}, function(e) {
reject(e);
});
}, CONSTANTS.CodeInstructionRunTime);
});
//After the code finishes evaluating, evaluate the next line recursively
code.then(function(codeRes) {
var nextLine = evaluateProg(exp, workerScript, index + 1);
nextLine.then(function(nextLineRes) {
resolve(workerScript);
}, function(e) {
reject(e);
});
}, function(e) {
reject(e);
return evaluate(exp.body[index], workerScript).then(function(res) {
return evaluateProg(exp, workerScript, index + 1);
}).then(function(res) {
return Promise.resolve(workerScript);
}).catch(function(e) {
return Promise.reject(e);
});
}
});
}
function killNetscriptDelay(workerScript) {
/*
if (workerScript instanceof WorkerScript) {
if (workerScript.delay) {
workerScript.delay.cancel();
}
}
*/
if (workerScript instanceof WorkerScript) {
if (workerScript.delay) {
clearTimeout(workerScript.delay);
workerScript.delayResolve();
}
}
}
function netscriptDelay(time, workerScript) {
return new Promise(function(resolve) {
var delay = setTimeout(resolve, time);
workerScript.killTrigger = function() {
clearTimeout(delay);
/*
workerScript.delay = new Promise(function(resolve, reject, onCancel) {
Promise.delay(time).then(function() {
resolve();
};
workerScript.delay = null;
});
onCancel(function() {
console.log("Cancelling and rejecting this Promise");
reject(workerScript);
})
});
return workerScript.delay;
*/
return new Promise(function(resolve, reject) {
workerScript.delay = setTimeout(()=>{
workerScript.delay = null;
resolve();
}, time);
workerScript.delayResolve = resolve;
});
}
@ -885,4 +801,4 @@ export {makeRuntimeRejectMsg, netscriptDelay, runScriptFromScript,
scriptCalculateHackingChance, scriptCalculateHackingTime,
scriptCalculateExpGain, scriptCalculatePercentMoneyHacked,
scriptCalculateGrowTime, scriptCalculateWeakenTime, evaluate,
isScriptErrorMessage};
isScriptErrorMessage, killNetscriptDelay};

@ -30,6 +30,7 @@ import {getCostOfNextHacknetNode,
purchaseHacknet} from "./HacknetNode.js";
import {Locations} from "./Location.js";
import {Message, Messages} from "./Message.js";
import {inMission} from "./Missions.js";
import {Player} from "./Player.js";
import {Script, findRunningScript, RunningScript} from "./Script.js";
import {Server, getServer, AddToAllServers,
@ -59,6 +60,9 @@ import {dialogBoxCreate} from "../utils/DialogBox.js"
import {printArray, powerOfTwo} from "../utils/HelperFunctions.js";
import {createRandomIp} from "../utils/IPAddress.js";
import {formatNumber, isString, isHTML} from "../utils/StringHelperFunctions.js";
import {yesNoBoxClose, yesNoBoxGetYesButton,
yesNoBoxGetNoButton, yesNoBoxCreate,
yesNoBoxOpen} from "../utils/YesNoBox.js";
var hasSingularitySF=false, hasAISF=false, hasBn11SF=false, hasWallStreetSF=false;
var singularitySFLvl=1, wallStreetSFLvl=1;
@ -1346,15 +1350,40 @@ function NetscriptFunctions(workerScript) {
getTimeSinceLastAug : function() {
return Player.playtimeSinceLastAug;
},
prompt : function(txt) {
if (yesNoBoxOpen) {
workerScript.scriptRef.log("ERROR: confirm() failed because a pop-up dialog box is already open");
return false;
}
if (!isString(txt)) {txt = String(txt);}
var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton();
yesBtn.innerHTML = "Yes";
noBtn.innerHTML = "No";
return new Promise(function(resolve, reject) {
yesBtn.addEventListener("click", ()=>{
yesNoBoxClose();
resolve(true);
});
noBtn.addEventListener("click", ()=>{
yesNoBoxClose();
resolve(false);
});
yesNoBoxCreate(txt);
});
},
/* Singularity Functions */
universityCourse(universityName, className) {
universityCourse : function(universityName, className) {
if (Player.bitNodeN != 4) {
if (!(hasSingularitySF && singularitySFLvl >= 1)) {
throw makeRuntimeRejectMsg(workerScript, "Cannot run universityCourse(). It is a Singularity Function and requires SourceFile-4 (level 1) to run.");
return false;
}
}
if (inMission) {
workerScript.scriptRef.log("ERROR: universityCourse() failed because you are in the middle of a mission.");
return;
}
if (Player.isWorking) {
var txt = Player.singularityStopWork();
workerScript.scriptRef.log(txt);
@ -1423,13 +1452,17 @@ function NetscriptFunctions(workerScript) {
return true;
},
gymWorkout(gymName, stat) {
gymWorkout : function(gymName, stat) {
if (Player.bitNodeN != 4) {
if (!(hasSingularitySF && singularitySFLvl >= 1)) {
throw makeRuntimeRejectMsg(workerScript, "Cannot run gymWorkout(). It is a Singularity Function and requires SourceFile-4 (level 1) to run.");
return false;
}
}
if (inMission) {
workerScript.scriptRef.log("ERROR: universityCourse() failed because you are in the middle of a mission.");
return;
}
if (Player.isWorking) {
var txt = Player.singularityStopWork();
workerScript.scriptRef.log(txt);
@ -1757,6 +1790,11 @@ function NetscriptFunctions(workerScript) {
}
}
if (inMission) {
workerScript.scriptRef.log("ERROR: universityCourse() failed because you are in the middle of a mission.");
return;
}
if (Player.companyPosition == "" || !(Player.companyPosition instanceof CompanyPosition)) {
workerScript.scriptRef.log("ERROR: workForCompany() failed because you do not have a job");
return false;
@ -1910,6 +1948,11 @@ function NetscriptFunctions(workerScript) {
}
}
if (inMission) {
workerScript.scriptRef.log("ERROR: universityCourse() failed because you are in the middle of a mission.");
return;
}
if (!factionExists(name)) {
workerScript.scriptRef.log("ERROR: Faction specified in workForFaction() does not exist.");
return false;
@ -2005,7 +2048,10 @@ function NetscriptFunctions(workerScript) {
return false;
}
}
if (inMission) {
workerScript.scriptRef.log("ERROR: universityCourse() failed because you are in the middle of a mission.");
return;
}
if (Player.isWorking) {
var txt = Player.singularityStopWork();
workerScript.scriptRef.log(txt);
@ -2085,14 +2131,17 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("Began creating program: " + name);
return true;
},
commitCrime(crime) {
commitCrime : function(crime) {
if (Player.bitNodeN != 4) {
if (!(hasSingularitySF && singularitySFLvl >= 3)) {
throw makeRuntimeRejectMsg(workerScript, "Cannot run commitCrime(). It is a Singularity Function and requires SourceFile-4 (level 3) to run.");
return;
}
}
if (inMission) {
workerScript.scriptRef.log("ERROR: universityCourse() failed because you are in the middle of a mission.");
return;
}
if (Player.isWorking) {
var txt = Player.singularityStopWork();
workerScript.scriptRef.log(txt);

@ -4,7 +4,8 @@ import {addActiveScriptsItem,
import {CONSTANTS} from "./Constants.js";
import {Engine} from "./engine.js";
import {Environment} from "./NetscriptEnvironment.js";
import {evaluate, isScriptErrorMessage} from "./NetscriptEvaluator.js";
import {evaluate, isScriptErrorMessage,
killNetscriptDelay} from "./NetscriptEvaluator.js";
import {AllServers} from "./Server.js";
import {Settings} from "./Settings.js";
@ -24,7 +25,8 @@ function WorkerScript(runningScriptObj) {
this.scriptRef = runningScriptObj;
this.errorMessage = "";
this.args = runningScriptObj.args;
this.killTrigger = function() {}; //CB func used to clear any delays (netscriptDelay())
//this.killTrigger = function() {}; //CB func used to clear any delays (netscriptDelay())
this.delay = null;
this.fnWorker = null; //Workerscript for a function call
}
@ -110,8 +112,8 @@ function runScriptsLoop() {
w.running = false;
w.env.stopFlag = true;
w.scriptRef.log("Script finished running");
}, function(w) {
//console.log(w);
}).catch(function(w) {
console.log(w);
if (w instanceof Error) {
dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer");
console.log("ERROR: Evaluating workerscript returns an Error. THIS SHOULDN'T HAPPEN: " + w.toString());
@ -165,10 +167,10 @@ function killWorkerScript(runningScriptObj, serverIp) {
if (workerScripts[i].name == runningScriptObj.filename && workerScripts[i].serverIp == serverIp &&
compareArrays(workerScripts[i].args, runningScriptObj.args)) {
workerScripts[i].env.stopFlag = true;
workerScripts[i].killTrigger();
killNetscriptDelay(workerScripts[i]);
if (workerScripts[i].fnWorker) {
workerScripts[i].fnWorker.env.stopFlag = true;
workerScripts[i].fnWorker.killTrigger();
killNetscriptDelay(workerScripts[i].fnWorker);
}
return true;
}

@ -190,8 +190,11 @@ function PlayerObject() {
this.totalPlaytime = 0;
this.playtimeSinceLastAug = 0;
//Script production since last Aug installation
//Production since last Augmentation installation
this.scriptProdSinceLastAug = 0;
this.stockProdSinceLastAug = 0;
this.crimeProdSinceLastAug = 0;
this.jobProdSinceLastAug = 0;
};
PlayerObject.prototype.init = function() {

@ -265,6 +265,10 @@ function loadBitVerse(destroyedBitNodeNum) {
return writeRedPillLine(".......................................");
}).then(function() {
return writeRedPillLine("Welcome to the Bitverse...");
}).then(function() {
return writeRedPillLine(" ");
}).then(function() {
return writeRedPillLine("(Enter a new BitNode using the image above)");
}).then(function() {
return Promise.resolve(true);
}).catch(function(e){

@ -82,12 +82,12 @@ BitburnerSaveObject.prototype.saveGame = function(db) {
}
request.onsuccess = function(e) {
console.log("Saved game to IndexedDB!");
//console.log("Saved game to IndexedDB!");
}
try {
window.localStorage.setItem("bitburnerSave", saveString);
console.log("Saved game to LocalStorage!");
//console.log("Saved game to LocalStorage!");
} catch(e) {
if (e.code == 22) {
Engine.createStatusText("Save failed for localStorage! Check console(F12)");

@ -528,6 +528,7 @@ function RunningScript(script, args) {
this.server = script.server; //IP Address only
this.logs = []; //Script logging. Array of strings, with each element being a log entry
this.logUpd = false;
//Stats to display on the Scripts menu, and used to determine offline progress
this.offlineRunningTime = 0.01; //Seconds
@ -551,6 +552,7 @@ RunningScript.prototype.log = function(txt) {
this.logs.shift();
}
this.logs.push(txt);
this.logUpd = true;
}
RunningScript.prototype.displayLog = function() {

@ -6,7 +6,9 @@ import {WorkerScript} from "./NetscriptWorker.js";
import {Player} from "./Player.js";
import {dialogBoxCreate} from "../utils/DialogBox.js";
import {clearEventListeners, getRandomInt} from "../utils/HelperFunctions.js";
import {clearEventListeners, getRandomInt,
removeElementById,
clearEventListenersEl} from "../utils/HelperFunctions.js";
import {Reviver, Generic_toJSON,
Generic_fromJSON} from "../utils/JSONReviver.js";
import numeral from "../utils/numeral.min.js";
@ -247,11 +249,11 @@ function initStockMarket() {
}
var ecorp = Locations.AevumECorp;
var ecorpStk = new Stock(ecorp, StockSymbols[ecorp], 0.5, true, 16, getRandomInt(20000, 25000));
var ecorpStk = new Stock(ecorp, StockSymbols[ecorp], 0.45, true, 19, getRandomInt(20000, 25000));
StockMarket[ecorp] = ecorpStk;
var megacorp = Locations.Sector12MegaCorp;
var megacorpStk = new Stock(megacorp, StockSymbols[megacorp], 0.5, true, 16, getRandomInt(25000, 33000));
var megacorpStk = new Stock(megacorp, StockSymbols[megacorp], 0.45, true, 19, getRandomInt(25000, 33000));
StockMarket[megacorp] = megacorpStk;
var blade = Locations.Sector12BladeIndustries;
@ -267,7 +269,7 @@ function initStockMarket() {
StockMarket[omnitek] = omnitekStk;
var foursigma = Locations.Sector12FourSigma;
var foursigmaStk = new Stock(foursigma, StockSymbols[foursigma], 1.1, true, 18, getRandomInt(60000, 70000));
var foursigmaStk = new Stock(foursigma, StockSymbols[foursigma], 1.05, true, 18, getRandomInt(60000, 70000));
StockMarket[foursigma] = foursigmaStk;
var kuaigong = Locations.ChongqingKuaiGongInternational;
@ -275,7 +277,7 @@ function initStockMarket() {
StockMarket[kuaigong] = kuaigongStk;
var fulcrum = Locations.AevumFulcrumTechnologies;
var fulcrumStk = new Stock(fulcrum, StockSymbols[fulcrum], 1.25, true, 17, getRandomInt(30000, 35000));
var fulcrumStk = new Stock(fulcrum, StockSymbols[fulcrum], 1.25, true, 16, getRandomInt(30000, 35000));
StockMarket[fulcrum] = fulcrumStk;
var storm = Locations.IshimaStormTechnologies;
@ -335,7 +337,7 @@ function initStockMarket() {
StockMarket[rho] = rhoStk;
var alpha = Locations.Sector12AlphaEnterprises;
var alphaStk = new Stock(alpha, StockSymbols[alpha], 2, true, 10, getRandomInt(5000, 7500));
var alphaStk = new Stock(alpha, StockSymbols[alpha], 1.9, true, 10, getRandomInt(5000, 7500));
StockMarket[alpha] = alphaStk;
var syscore = Locations.VolhavenSysCoreSecurities;
@ -359,15 +361,15 @@ function initStockMarket() {
StockMarket[fns] = fnsStk;
var sigmacosm = "Sigma Cosmetics";
var sigmacosmStk = new Stock(sigmacosm, StockSymbols[sigmacosm], 3, true, 0, getRandomInt(2000, 3000));
var sigmacosmStk = new Stock(sigmacosm, StockSymbols[sigmacosm], 2.8, true, 0, getRandomInt(2000, 3000));
StockMarket[sigmacosm] = sigmacosmStk;
var joesguns = "Joes Guns";
var joesgunsStk = new Stock(joesguns, StockSymbols[joesguns], 4, true, 1, getRandomInt(500, 1000));
var joesgunsStk = new Stock(joesguns, StockSymbols[joesguns], 3.8, true, 1, getRandomInt(500, 1000));
StockMarket[joesguns] = joesgunsStk;
var catalyst = "Catalyst Ventures";
var catalystStk = new Stock(catalyst, StockSymbols[catalyst], 1.6, true, 20, getRandomInt(500, 1000));
var catalystStk = new Stock(catalyst, StockSymbols[catalyst], 1.5, true, 14, getRandomInt(500, 1000));
StockMarket[catalyst] = catalystStk;
var microdyne = "Microdyne Technologies";
@ -502,9 +504,7 @@ function shortStock(stock, shares, workerScript=null) {
var newTotal = origTotal + totalPrice;
stock.playerShortShares += shares;
stock.playerAvgShortPx = newTotal / stock.playerShortShares;
if (Engine.currentPage === Engine.Page.StockMarket) {
updateStockPlayerPosition(stock);
}
if (tixApi) {
workerScript.scriptRef.log("Bought a short position of " + formatNumber(shares, 0) + " shares of " + stock.symbol + " at " +
numeral(stock.price).format('($0.000a)') + " per share. Paid " +
@ -546,9 +546,7 @@ function sellShort(stock, shares, workerScript=null) {
if (stock.playerShortShares === 0) {
stock.playerAvgShortPx = 0;
}
if (Engine.currentPage === Engine.Page.StockMarket) {
updateStockPlayerPosition(stock);
}
if (tixApi) {
workerScript.scriptRef.log("Sold your short position of " + shares + " shares of " + stock.symbol + " at " +
numeral(stock.price).format('($0.000a)') + " per share. After commissions, you gained " +
@ -685,6 +683,8 @@ function setStockMarketContentCreated(b) {
}
var stockMarketContentCreated = false;
var stockMarketPortfolioMode = false;
var COMM = CONSTANTS.StockMarketCommission;
function displayStockMarketContent() {
if (Player.hasWseAccount == null) {Player.hasWseAccount = false;}
if (Player.hasTixApiAccess == null) {Player.hasTixApiAccess = false;}
@ -722,6 +722,27 @@ function displayStockMarketContent() {
return false;
});
var stockList = document.getElementById("stock-market-list");
if (stockList == null) {return;}
if (!Player.hasWseAccount) {
stockMarketContentCreated = false;
while (stockList.firstChild) {
stockList.removeChild(stockList.firstChild);
}
return;
}
//Create stock market content if you have an account
if (!stockMarketContentCreated && Player.hasWseAccount) {
console.log("Creating Stock Market UI");
document.getElementById("stock-market-commission").innerHTML =
"Commission Fees: Every transaction you make has a $" +
formatNumber(CONSTANTS.StockMarketCommission, 2) + " commission fee.<br><br>" +
"WARNING: When you reset after installing Augmentations, the Stock Market is reset. " +
"This means all your positions are lost, so make sure to sell your stocks before installing " +
"Augmentations!";
var investopediaButton = clearEventListeners("stock-market-investopedia");
investopediaButton.addEventListener("click", function() {
var txt = "When making a transaction on the stock market, there are two " +
@ -767,26 +788,38 @@ function displayStockMarketContent() {
return false;
});
var stockList = document.getElementById("stock-market-list");
if (stockList == null) {return;}
if (!Player.hasWseAccount) {
stockMarketContentCreated = false;
while (stockList.firstChild) {
stockList.removeChild(stockList.firstChild);
}
return;
//Switch to Portfolio Mode Button
var modeBtn = clearEventListeners("stock-market-mode");
if (modeBtn) {
modeBtn.innerHTML = "Switch to 'Portfolio' Mode" +
"<span class='tooltiptext'>Displays only the stocks for which you have shares or orders</span>";
modeBtn.addEventListener("click", switchToPortfolioMode);
}
//Create stock market content if you have an account
if (!stockMarketContentCreated && Player.hasWseAccount) {
console.log("Creating Stock Market UI");
document.getElementById("stock-market-commission").innerHTML =
"Commission Fees: Every transaction you make has a $" +
formatNumber(CONSTANTS.StockMarketCommission, 2) + " commission fee.<br><br>" +
"WARNING: When you reset after installing Augmentations, the Stock Market is reset. " +
"This means all your positions are lost, so make sure to sell your stocks before installing " +
"Augmentations!";
//Expand/Collapse tickers buttons
var expandBtn = clearEventListeners("stock-market-expand-tickers"),
collapseBtn = clearEventListeners("stock-market-collapse-tickers"),
stockList = document.getElementById("stock-market-list");
if (expandBtn) {
expandBtn.addEventListener("click", ()=>{
var tickerHdrs = stockList.getElementsByClassName("accordion-header");
for (var i = 0; i < tickerHdrs.length; ++i) {
if (!tickerHdrs[i].classList.contains("active")) {
tickerHdrs[i].click();
}
}
});
}
if (collapseBtn) {
collapseBtn.addEventListener("click",()=>{
var tickerHdrs = stockList.getElementsByClassName("accordion-header");
for (var i = 0; i < tickerHdrs.length; ++i) {
if (tickerHdrs[i].classList.contains("active")) {
tickerHdrs[i].click();
}
}
});
}
for (var name in StockMarket) {
if (StockMarket.hasOwnProperty(name)) {
@ -804,13 +837,74 @@ function displayStockMarketContent() {
if (StockMarket.hasOwnProperty(name)) {
var stock = StockMarket[name];
updateStockTicker(stock, null);
updateStockPlayerPosition(stock);
updateStockOrderList(stock);
}
}
}
}
//Displays only stocks you have position/order in
function switchToPortfolioMode() {
stockMarketPortfolioMode = true;
var stockList = document.getElementById("stock-market-list");
if (stockList == null) {return;}
var modeBtn = clearEventListeners("stock-market-mode");
if (modeBtn) {
modeBtn.innerHTML = "Switch to 'All stocks' Mode" +
"<span class='tooltiptext'>Displays all stocks on the WSE</span>";
modeBtn.addEventListener("click", switchToDisplayAllMode);
}
while(stockList.firstChild) {stockList.removeChild(stockList.firstChild);}
//Get Order book (create it if it hasn't been created)
var orderBook = StockMarket["Orders"];
if (orderBook == null) {
var orders = {};
for (var name in StockMarket) {
if (StockMarket.hasOwnProperty(name)) {
var stock = StockMarket[name];
if (!(stock instanceof Stock)) {continue;}
orders[stock.symbol] = [];
}
}
StockMarket["Orders"] = orders;
}
for (var name in StockMarket) {
if (StockMarket.hasOwnProperty(name)) {
var stock = StockMarket[name];
if (!(stock instanceof Stock)) {continue;} //orders property is an array
var stockOrders = orderBook[stock.symbol];
if (stock.playerShares === 0 && stock.playerShortShares === 0 &&
stockOrders.length === 0) {continue;}
createStockTicker(stock);
}
}
setStockTickerClickHandlers();
}
//Displays all stocks
function switchToDisplayAllMode() {
stockMarketPortfolioMode = false;
var stockList = document.getElementById("stock-market-list");
if (stockList == null) {return;}
var modeBtn = clearEventListeners("stock-market-mode");
if (modeBtn) {
modeBtn.innerHTML = "Switch to 'Portfolio' Mode" +
"<span class='tooltiptext'>Displays only the stocks for which you have shares or orders</span>";
modeBtn.addEventListener("click", switchToPortfolioMode);
}
while(stockList.firstChild) {stockList.removeChild(stockList.firstChild);}
for (var name in StockMarket) {
if (StockMarket.hasOwnProperty(name)) {
var stock = StockMarket[name];
if (!(stock instanceof Stock)) {continue;} //orders property is an array
createStockTicker(stock);
}
}
setStockTickerClickHandlers();
}
function createStockTicker(stock) {
if (!(stock instanceof Stock)) {
console.log("Invalid stock in createStockSticker()");
@ -825,6 +919,7 @@ function createStockTicker(stock) {
//Div for entire panel
var stockDiv = document.createElement("div");
stockDiv.classList.add("accordion-panel");
stockDiv.setAttribute("id", tickerId + "-panel");
/* Create panel DOM */
var qtyInput = document.createElement("input"),
@ -832,6 +927,8 @@ function createStockTicker(stock) {
orderTypeSelect = document.createElement("select"),
buyButton = document.createElement("span"),
sellButton = document.createElement("span"),
buyMaxButton = document.createElement("span"),
sellAllButton = document.createElement("span"),
positionTxt = document.createElement("p"),
orderList = document.createElement("ul");
@ -952,6 +1049,76 @@ function createStockTicker(stock) {
return false;
});
buyMaxButton.classList.add("stock-market-input");
buyMaxButton.classList.add("a-link-button");
buyMaxButton.innerHTML = "Buy MAX";
buyMaxButton.addEventListener("click", ()=>{
var pos = longShortSelect.options[longShortSelect.selectedIndex].text;
pos === "Long" ? pos = PositionTypes.Long : pos = PositionTypes.Short;
var ordType = orderTypeSelect.options[orderTypeSelect.selectedIndex].text;
var money = Player.money.toNumber();
switch (ordType) {
case "Market Order":
var shares = Math.floor((money - COMM) / stock.price);
pos === PositionTypes.Long ? buyStock(stock, shares) : shortStock(stock, shares, null);
break;
case "Limit Order":
case "Stop Order":
var yesBtn = yesNoTxtInpBoxGetYesButton(),
noBtn = yesNoTxtInpBoxGetNoButton();
yesBtn.innerText = "Place Buy " + ordType;
noBtn.innerText = "Cancel Order";
yesBtn.addEventListener("click", ()=>{
var price = Number(yesNoTxtInpBoxGetInput()), type;
if (ordType === "Limit Order") {
type = OrderTypes.LimitBuy;
} else {
type = OrderTypes.StopBuy;
}
var shares = Math.floor((money-COMM) / price);
placeOrder(stock, shares, price, type, pos);
yesNoTxtInpBoxClose();
});
noBtn.addEventListener("click", ()=>{
yesNoTxtInpBoxClose();
});
yesNoTxtInpBoxCreate("Enter the price for your " + ordType);
break;
default:
console.log("ERROR: Invalid order type");
break;
}
return false;
});
sellAllButton.classList.add("stock-market-input");
sellAllButton.classList.add("a-link-button");
sellAllButton.innerHTML = "Sell ALL";
sellAllButton.addEventListener("click", ()=>{
var pos = longShortSelect.options[longShortSelect.selectedIndex].text;
pos === "Long" ? pos = PositionTypes.Long : pos = PositionTypes.Short;
var ordType = orderTypeSelect.options[orderTypeSelect.selectedIndex].text;
switch (ordType) {
case "Market Order":
if (pos === PositionTypes.Long) {
var shares = stock.playerShares;
sellStock(stock, shares);
} else {
var shares = stock.playerShortShares;
sellShort(stock, shares, null);
}
break;
case "Limit Order":
case "Stop Order":
dialogBoxCreate("ERROR: 'Sell All' only works for Market Orders")
break;
default:
console.log("ERROR: Invalid order type");
break;
}
return false;
});
positionTxt.setAttribute("id", tickerId + "-position-text");
positionTxt.classList.add("stock-market-position-text");
stock.posTxtEl = positionTxt;
@ -964,6 +1131,8 @@ function createStockTicker(stock) {
stockDiv.appendChild(orderTypeSelect);
stockDiv.appendChild(buyButton);
stockDiv.appendChild(sellButton);
stockDiv.appendChild(buyMaxButton);
stockDiv.appendChild(sellAllButton);
stockDiv.appendChild(positionTxt);
stockDiv.appendChild(orderList);
@ -972,6 +1141,7 @@ function createStockTicker(stock) {
document.getElementById("stock-market-list").appendChild(li);
updateStockTicker(stock, true);
updateStockPlayerPosition(stock);
updateStockOrderList(stock);
}
@ -1008,11 +1178,11 @@ function updateStockTicker(stock, increase) {
var hdr = document.getElementById(tickerId + "-hdr");
if (hdr == null) {
console.log("ERROR: Couldn't find ticker element for stock: " + stock.symbol);
if (!stockMarketPortfolioMode) {console.log("ERROR: Couldn't find ticker element for stock: " + stock.symbol);}
return;
}
hdr.innerHTML = stock.name + " - " + stock.symbol + " - $" + formatNumber(stock.price, 2);
if (increase !== null) {
if (increase != null) {
increase ? hdr.style.color = "#66ff33" : hdr.style.color = "red";
}
@ -1029,6 +1199,25 @@ function updateStockPlayerPosition(stock) {
return;
}
var tickerId = "stock-market-ticker-" + stock.symbol;
if (stockMarketPortfolioMode) {
if (stock.playerShares === 0 && stock.playerShortShares === 0 &&
StockMarket["Orders"] && StockMarket["Orders"][stock.symbol] &&
StockMarket["Orders"][stock.symbol].length === 0) {
removeElementById(tickerId + "-hdr");
removeElementById(tickerId + "-panel");
return;
} else {
//If the ticker hasn't been created, create it (handles updating)
//If it has been created, continue normally
if (document.getElementById(tickerId + "-hdr") == null) {
createStockTicker(stock);
setStockTickerClickHandlers();
return;
}
}
}
if (!(stock.posTxtEl instanceof Element)) {
stock.posTxtEl = document.getElementById(tickerId + "-position-text");
}
@ -1077,7 +1266,7 @@ function updateStockOrderList(stock) {
var tickerId = "stock-market-ticker-" + stock.symbol;
var orderList = document.getElementById(tickerId + "-order-list");
if (orderList == null) {
console.log("ERROR: Could not find order list for " + stock.symbol);
if (!stockMarketPortfolioMode) {console.log("ERROR: Could not find order list for " + stock.symbol);}
return;
}
@ -1092,6 +1281,24 @@ function updateStockOrderList(stock) {
return;
}
if (stockMarketPortfolioMode) {
if (stock.playerShares === 0 && stock.playerShortShares === 0 &&
StockMarket["Orders"] && StockMarket["Orders"][stock.symbol] &&
StockMarket["Orders"][stock.symbol].length === 0) {
removeElementById(tickerId + "-hdr");
removeElementById(tickerId + "-panel");
return;
} else {
//If the ticker hasn't been created, create it (handles updating)
//If it has been created, continue normally
if (document.getElementById(tickerId + "-hdr") == null) {
createStockTicker(stock);
setStockTickerClickHandlers();
return;
}
}
}
//Remove everything from list
while (orderList.firstChild) {
orderList.removeChild(orderList.firstChild);

@ -493,7 +493,7 @@ let Terminal = {
else {rootAccess = "NO";}
post("Root Access: " + rootAccess);
post("Required hacking skill: " + Player.getCurrentServer().requiredHackingSkill);
post("Estimated server security level(1-100): " + formatNumber(addOffset(Player.getCurrentServer().hackDifficulty, 5), 3));
post("Estimated server security level: " + formatNumber(addOffset(Player.getCurrentServer().hackDifficulty, 5), 3));
post("Estimated chance to hack: " + formatNumber(addOffset(Player.calculateHackingChance() * 100, 5), 2) + "%");
post("Estimated time to hack: " + formatNumber(addOffset(Player.calculateHackingTime(), 5), 3) + " seconds");
post("Estimated total money available on server: $" + formatNumber(addOffset(Player.getCurrentServer().moneyAvailable, 5), 2));

@ -38,6 +38,14 @@ function clearEventListenersEl(el) {
return newElem;
}
//Given its id, this function removes an element AND its children
function removeElementById(id) {
var elem = document.getElementById(id);
if (elem == null) {return;}
while(elem.firstChild) {elem.removeChild(elem.firstChild);}
elem.parentNode.removeChild(elem);
}
function getRandomInt(min, max) {
if (min > max) {return getRandomInt(max, min);}
return Math.floor(Math.random() * (max - min + 1)) + min;
@ -67,4 +75,5 @@ function powerOfTwo(n) {
}
export {sizeOfObject, addOffset, clearEventListeners, getRandomInt,
compareArrays, printArray, powerOfTwo, clearEventListenersEl};
compareArrays, printArray, powerOfTwo, clearEventListenersEl,
removeElementById};

@ -1,4 +1,5 @@
import {printArray} from "./HelperFunctions.js";
import {killWorkerScript} from "../src/NetscriptWorker.js";
import {printArray, clearEventListeners} from "./HelperFunctions.js";
$(document).keydown(function(event) {
if (logBoxOpened && event.keyCode == 27) {
@ -15,6 +16,7 @@ function logBoxInit() {
logBoxClose();
return false;
});
document.getElementById("log-box-text-header").style.display = "inline-block";
};
document.addEventListener("DOMContentLoaded", logBoxInit, false);
@ -35,23 +37,30 @@ function logBoxOpen() {
var logBoxOpened = false;
var logBoxCurrentScript = null;
//ram argument is in GB
function logBoxCreate(script) {
logBoxCurrentScript = script;
var killScriptBtn = clearEventListeners("log-box-kill-script");
killScriptBtn.addEventListener("click", ()=>{
killWorkerScript(script, script.server);
return false;
});
document.getElementById('log-box-kill-script').style.display = "inline-block";
logBoxOpen();
document.getElementById("log-box-text-header").innerHTML =
logBoxCurrentScript.filename + " " + printArray(logBoxCurrentScript.args) + ":<br><br>";
logBoxCurrentScript.logUpd = true;
logBoxUpdateText();
}
function logBoxUpdateText() {
var txt = document.getElementById("log-box-text");
if (logBoxCurrentScript && logBoxOpened && txt) {
if (logBoxCurrentScript && logBoxOpened && txt && logBoxCurrentScript.logUpd) {
txt.innerHTML = "";
for (var i = 0; i < logBoxCurrentScript.logs.length; ++i) {
txt.innerHTML += logBoxCurrentScript.logs[i];
txt.innerHTML += "<br>";
}
logBoxCurrentScript.logUpd = false;
}
}

@ -22,6 +22,7 @@ function yesNoBoxGetNoButton() {
}
function yesNoBoxCreate(txt) {
if (yesNoBoxOpen) {return false;} //Already open
yesNoBoxOpen = true;
var textElement = document.getElementById("yes-no-box-text");
if (textElement) {
@ -34,6 +35,7 @@ function yesNoBoxCreate(txt) {
} else {
console.log("ERROR: Container not found for YesNoBox");
}
return true;
}
/* Generic Yes-No POp-up Box with Text input */