Refactored Code using Bluebird Promises. Still has memory issues. Added Buy Max and Sell All to stock market UI

This commit is contained in:
danielyxie 2017-11-01 17:56:30 -05:00
parent 7c4ac00f5a
commit 52967d7f9d
7 changed files with 9443 additions and 3119 deletions

11001
dist/bundle.js vendored

File diff suppressed because one or more lines are too long

@ -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,201 @@ 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
var Materials = {
Water: 11,
Energy: 12,
Food: 13,
Plants: 14,
Metal: 15,
Hardware: 16,
Chemicals: 17,
RealEstate: 18,
Drugs: 19,
Robots: 20,
AICores:21,
SciResearch: 22
}
function Material(params={}) {
this.name = params.name ? params.name : "";
this.qty = 0;
this.qlt = 0;
this.dmd = 0;
this.cmp = 0;
this.mku = 0;
//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
this.req = params.req ? params.req : [];
}
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
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 = {};
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;
}
}
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;
}

@ -13,72 +13,79 @@ 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)
return Promise.all(argPromises).then(function(array) {
return Promise.resolve(array)
}).catch(function(e) {
reject(e);
return Promise.reject(e);
});
break;
case "CallExpression":
evaluate(exp.callee, workerScript).then(function(func) {
return evaluate(exp.callee, workerScript).then(function(func) {
/*
var argPromises = exp.arguments.map(function(arg) {
return evaluate(arg, workerScript);
});
Promise.all(argPromises).then(function(args) {
Promise.all(argPromises).then(function(args) {*/
return Promise.map(exp.arguments, function(arg) {
return evaluate(arg, workerScript);
}).then(function(args) {
if (func instanceof Node) { //Player-defined function
//Create new Environment for the function
//Should be automatically garbage collected...
@ -101,129 +108,122 @@ 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);
return Promise.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);
return Promise.reject(e);
});
}).catch(function(e) {
reject(e);
return Promise.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);
return Promise.reject(e);
});
break;
case "LogicalExpression":
case "BinaryExpression":
var p = evalBinary(exp, workerScript, resolve, reject);
p.then(function(res) {
resolve(res);
return evalBinary(exp, workerScript).then(function(res) {
return Promise.resolve(res);
}).catch(function(e) {
reject(e);
return Promise.reject(e);
});
break;
case "UnaryExpression":
var p = evalUnary(exp, workerScript, resolve, reject);
p.then(function(res) {
resolve(res);
return evalUnary(exp, workerScript).then(function(res) {
return Promise.resolve(res);
}).catch(function(e) {
reject(e);
return Promise.reject(e);
});
break;
case "AssignmentExpression":
var p = evalAssignment(exp, workerScript);
p.then(function(res) {
resolve(res);
return evalAssignment(exp, workerScript).then(function(res) {
return Promise.resolve(res);
}).catch(function(e) {
reject(e);
return Promise.reject(e);
});
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 +231,188 @@ 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]);
return evaluate(exp.argument, workerScript).then(function(res) {
return Promise.reject(["RETURNSTATEMENT", res]);
}).catch(function(e) {
reject(e);
return Promise.reject(e);
});
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);
return evaluateIf(exp, workerScript).then(function(forLoopRes) {
return Promise.resolve(forLoopRes);
}).catch(function(e) {
reject(e);
return Promise.reject(e);
});
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(forLoopRes) {
return Promise.resolve(forLoopRes);
}).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);
return Promise.reject(e);
});
}, function(e) {
reject(e);
});
return Promise.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);
});
return Promise.reject(e);
});
}
@ -423,59 +420,52 @@ 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);
});
return Promise.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 +473,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,203 +500,147 @@ 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);
});
return Promise.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);
});
return Promise.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;
return new Promise(function(resolve, reject) {
if (env.stopFlag) {reject(workerScript); return;}
var pCond = evaluate(exp.test, workerScript);
pCond.then(function(resCond) {
if (env.stopFlag) {return Promise.reject(workerScript);}
return 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) {
//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
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(function(resPostloop) {
return evaluateFor(exp, workerScript);
}).then(function(foo) {
return Promise.resolve("endForLoop");
}).catch(function(e) {
return Promise.reject(e);
});
} else {
resolve("endForLoop"); //Doesn't need to resolve to any particular value
return Promise.resolve("endForLoop"); //Doesn't need to resolve to any particular value
}
}, function(e) {
reject(e);
});
return Promise.reject(e);
});
}
function evaluateWhile(exp, workerScript) {
var env = workerScript.env;
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) {
if (env.stopFlag) {return Promise.reject(workerScript);}
return Promise.delay(CONSTANTS.CodeInstructionRunTime).then(function() {
return 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).then(function(resCode) {
return Promise.resolve(resCode);
}).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");
}).then(function(resCode) {
return evaluateWhile(exp, workerScript).then(function(foo) {
return Promise.resolve("endWhileLoop");
}, function(e) {
reject(e);
return Promise.reject(e);
});
}, function(e) {
reject(e);
}).catch(function(e) {
return Promise.reject(e);
});
} else {
resolve("endWhileLoop"); //Doesn't need to resolve to any particular value
return Promise.resolve("endWhileLoop"); //Doesn't need to resolve to any particular value
}
}, function(e) {
reject(e);
});
}).catch(function(e) {
return Promise.reject(e);
});
}
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();
}
}
}
function netscriptDelay(time, workerScript) {
return new Promise(function(resolve) {
var delay = setTimeout(resolve, time);
workerScript.killTrigger = function() {
clearTimeout(delay);
resolve();
};
});
var delay = Promise.delay(time, true);
workerScript.delay = delay;
return delay;
}
function makeRuntimeRejectMsg(workerScript, msg) {
@ -885,4 +797,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,22 @@ function NetscriptFunctions(workerScript) {
getTimeSinceLastAug : function() {
return Player.playtimeSinceLastAug;
},
confirm : function(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 +1434,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 +1772,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 +1930,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 +2030,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 +2113,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
}
@ -93,7 +95,7 @@ function runScriptsLoop() {
if (workerScripts[i].running == false && workerScripts[i].env.stopFlag == false) {
try {
var ast = parse(workerScripts[i].code);
//console.log(ast);
console.log(ast);
} catch (e) {
console.log("Error parsing script: " + workerScripts[i].name);
dialogBoxCreate("Syntax ERROR in " + workerScripts[i].name + ":<br>" + e);
@ -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,11 +167,16 @@ 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;
killNetscriptDelay(workerScripts[i].fnWorker);
}
/*workerScripts[i].killTrigger();
if (workerScripts[i].fnWorker) {
workerScripts[i].fnWorker.env.stopFlag = true;
workerScripts[i].fnWorker.killTrigger();
}
}*/
return true;
}
}

@ -367,7 +367,7 @@ function initStockMarket() {
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.6, true, 15, getRandomInt(500, 1000));
StockMarket[catalyst] = catalystStk;
var microdyne = "Microdyne Technologies";
@ -408,8 +408,8 @@ function stockMarketCycle() {
for (var name in StockMarket) {
if (StockMarket.hasOwnProperty(name)) {
var stock = StockMarket[name];
var thresh = 0.6;
if (stock.b) {thresh = 0.4;}
var thresh = 0.59;
if (stock.b) {thresh = 0.41;}
if (Math.random() < thresh) {
stock.b = !stock.b;
}
@ -832,6 +832,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 +954,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.toMoney();
switch (ordType) {
case "Market Order":
var shares = Math.floor(money / 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 / 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 +1036,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);

@ -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 */