2017-08-30 19:44:29 +02:00
import { BitNodeMultipliers } from "./BitNode.js" ;
import { CONSTANTS } from "./Constants.js" ;
import { Player } from "./Player.js" ;
import { Environment } from "./NetscriptEnvironment.js" ;
import { WorkerScript , addWorkerScript } from "./NetscriptWorker.js" ;
import { Server } from "./Server.js" ;
import { Settings } from "./Settings.js" ;
import { Script , findRunningScript ,
RunningScript } from "./Script.js" ;
import { printArray } from "../utils/HelperFunctions.js" ;
import { isValidIPAddress } from "../utils/IPAddress.js" ;
import { isString } from "../utils/StringHelperFunctions.js" ;
2016-11-17 23:25:40 +01:00
/ * E v a l u a t o r
* Evaluates the Abstract Syntax Tree for Netscript
* generated by the Parser class
* /
2016-11-30 00:07:24 +01:00
// Evaluator should return a Promise, so that any call to evaluate() can just
//wait for that promise to finish before continuing
function evaluate ( exp , workerScript ) {
2017-06-05 06:48:37 +02:00
return new Promise ( function ( resolve , reject ) {
2016-11-30 00:07:24 +01:00
var env = workerScript . env ;
2017-06-05 06:48:37 +02:00
if ( env . stopFlag ) { return reject ( workerScript ) ; }
2017-05-01 07:39:48 +02:00
if ( exp == null ) {
2017-06-05 06:48:37 +02:00
return reject ( makeRuntimeRejectMsg ( workerScript , "Error: NULL expression" ) ) ;
2017-05-01 07:39:48 +02:00
}
2017-06-05 06:48:37 +02:00
setTimeout ( function ( ) {
if ( env . stopFlag ) { return reject ( workerScript ) ; }
switch ( exp . type ) {
2017-06-28 11:47:42 +02:00
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 ) {
2017-08-30 19:44:29 +02:00
if ( isString ( e ) ) {
2017-06-28 11:47:42 +02:00
workerScript . errorMessage = e ;
reject ( workerScript ) ;
} else if ( e instanceof WorkerScript ) {
2017-06-05 06:48:37 +02:00
reject ( e ) ;
2017-06-11 00:44:33 +02:00
} else {
2017-06-28 11:47:42 +02:00
reject ( workerScript ) ;
2017-06-11 00:44:33 +02:00
}
2017-06-28 11:47:42 +02:00
} ) ;
break ;
case "Literal" :
resolve ( exp . value ) ;
break ;
case "Identifier" :
if ( ! ( exp . name in env . vars ) ) {
2017-08-30 19:44:29 +02:00
reject ( makeRuntimeRejectMsg ( workerScript , "variable " + exp . name + " not defined" ) ) ;
2017-06-05 06:48:37 +02:00
}
2017-06-28 11:47:42 +02:00
resolve ( env . get ( exp . name ) )
2017-06-05 06:48:37 +02:00
break ;
2017-06-28 11:47:42 +02:00
case "ExpressionStatement" :
var e = evaluate ( exp . expression , workerScript ) ;
e . then ( function ( res ) {
resolve ( "expression done" ) ;
} , function ( e ) {
2017-06-05 06:48:37 +02:00
reject ( e ) ;
} ) ;
break ;
2017-06-28 11:47:42 +02:00
case "ArrayExpression" :
var argPromises = exp . elements . map ( function ( arg ) {
return evaluate ( arg , workerScript ) ;
} ) ;
Promise . all ( argPromises ) . then ( function ( array ) {
resolve ( array )
2017-06-05 06:48:37 +02:00
} ) . catch ( function ( e ) {
reject ( e ) ;
} ) ;
break ;
2017-06-28 11:47:42 +02:00
case "CallExpression" :
evaluate ( exp . callee , workerScript ) . then ( function ( func ) {
var argPromises = exp . arguments . map ( function ( arg ) {
return evaluate ( arg , workerScript ) ;
} ) ;
Promise . all ( argPromises ) . then ( function ( args ) {
if ( exp . callee . type == "MemberExpression" ) {
evaluate ( exp . callee . object , workerScript ) . then ( function ( object ) {
try {
2017-07-13 18:54:29 +02:00
var res = func . apply ( object , args ) ;
resolve ( res ) ;
2017-06-28 11:47:42 +02:00
} catch ( e ) {
reject ( makeRuntimeRejectMsg ( workerScript , e ) ) ;
}
} ) . catch ( function ( e ) {
2017-05-12 06:59:07 +02:00
reject ( e ) ;
} ) ;
} else {
2017-06-28 11:47:42 +02:00
try {
var out = func . apply ( null , args ) ;
if ( out instanceof Promise ) {
out . then ( function ( res ) {
resolve ( res )
} ) . catch ( function ( e ) {
reject ( e ) ;
} ) ;
} else {
resolve ( out ) ;
}
} catch ( e ) {
2017-07-13 18:54:29 +02:00
if ( isScriptErrorMessage ( e ) ) {
reject ( e ) ;
} else {
reject ( makeRuntimeRejectMsg ( workerScript , e ) ) ;
}
2017-06-28 11:47:42 +02:00
}
2017-05-12 06:59:07 +02:00
}
2017-06-28 11:47:42 +02:00
} ) . catch ( function ( e ) {
reject ( e ) ;
} ) ;
} ) . catch ( function ( e ) {
2017-05-12 06:59:07 +02:00
reject ( e ) ;
} ) ;
2017-06-05 06:48:37 +02:00
break ;
2017-06-28 11:47:42 +02:00
case "MemberExpression" :
var pObject = evaluate ( exp . object , workerScript ) ;
pObject . then ( function ( object ) {
if ( exp . computed ) {
var p = evaluate ( exp . property , workerScript ) ;
p . then ( function ( index ) {
2017-07-29 18:25:40 +02:00
if ( index >= object . length ) {
return reject ( makeRuntimeRejectMsg ( workerScript , "Invalid index for arrays" ) ) ;
}
2017-06-28 11:47:42 +02:00
resolve ( object [ index ] ) ;
} ) . catch ( function ( e ) {
2017-07-29 18:25:40 +02:00
console . log ( "here" ) ;
2017-06-28 11:47:42 +02:00
reject ( makeRuntimeRejectMsg ( workerScript , "Invalid MemberExpression" ) ) ;
} ) ;
} else {
try {
resolve ( object [ exp . property . name ] )
} catch ( e ) {
return reject ( makeRuntimeRejectMsg ( workerScript , "Failed to get property: " + e . toString ( ) ) ) ;
}
}
2017-06-05 06:48:37 +02:00
} ) . catch ( function ( e ) {
reject ( e ) ;
} ) ;
break ;
2017-06-28 11:47:42 +02:00
case "LogicalExpression" :
case "BinaryExpression" :
var p = evalBinary ( exp , workerScript , resolve , reject ) ;
p . then ( function ( res ) {
resolve ( res ) ;
} ) . catch ( function ( e ) {
2017-06-05 06:48:37 +02:00
reject ( e ) ;
} ) ;
break ;
2017-07-27 04:56:14 +02:00
case "UnaryExpression" :
var p = evalUnary ( exp , workerScript , resolve , reject ) ;
p . then ( function ( res ) {
resolve ( res ) ;
} ) . catch ( function ( e ) {
reject ( e ) ;
} ) ;
break ;
2017-06-28 11:47:42 +02:00
case "AssignmentExpression" :
var p = evalAssignment ( exp , workerScript ) ;
p . then ( function ( res ) {
resolve ( res ) ;
} ) . catch ( function ( e ) {
reject ( e ) ;
2017-06-05 06:48:37 +02:00
} ) ;
break ;
2017-06-28 11:47:42 +02:00
case "UpdateExpression" :
if ( exp . argument . type === "Identifier" ) {
if ( exp . argument . name in env . vars ) {
if ( exp . prefix ) {
resolve ( env . get ( exp . argument . name ) )
}
switch ( exp . operator ) {
case "++" :
env . set ( exp . argument . name , env . get ( exp . argument . name ) + 1 ) ;
2017-06-05 06:48:37 +02:00
break ;
2017-06-28 11:47:42 +02:00
case "--" :
env . set ( exp . argument . name , env . get ( exp . argument . name ) - 1 ) ;
break ;
default :
reject ( makeRuntimeRejectMsg ( workerScript , "Unrecognized token: " + exp . type + ". This is a bug please report to game developer" ) ) ;
2017-06-05 19:50:32 +02:00
}
2017-06-28 11:47:42 +02:00
if ( env . prefix ) {
return ;
2017-06-05 19:50:32 +02:00
}
2017-06-28 11:47:42 +02:00
resolve ( env . get ( exp . argument . name ) )
} else {
2017-08-30 19:44:29 +02:00
reject ( makeRuntimeRejectMsg ( workerScript , "variable " + exp . argument . name + " not defined" ) ) ;
2017-06-26 01:39:17 +02:00
}
2017-06-05 06:48:37 +02:00
} else {
2017-06-28 11:47:42 +02:00
reject ( makeRuntimeRejectMsg ( workerScript , "argument must be an identifier" ) ) ;
}
break ;
case "EmptyStatement" :
resolve ( false ) ;
break ;
case "ReturnStatement" :
reject ( makeRuntimeRejectMsg ( workerScript , "Not implemented ReturnStatement" ) ) ;
break ;
case "BreakStatement" :
2017-08-15 22:22:46 +02:00
reject ( "BREAKSTATEMENT" ) ;
//reject(makeRuntimeRejectMsg(workerScript, "Not implemented BreakStatement"));
2017-06-28 11:47:42 +02:00
break ;
case "IfStatement" :
evaluateIf ( exp , workerScript ) . then ( function ( forLoopRes ) {
resolve ( "forLoopDone" ) ;
} ) . catch ( function ( e ) {
reject ( e ) ;
} ) ;
break ;
case "SwitchStatement" :
reject ( makeRuntimeRejectMsg ( workerScript , "Not implemented SwitchStatement" ) ) ;
break ; e
case "WhileStatement" :
evaluateWhile ( exp , workerScript ) . then ( function ( forLoopRes ) {
resolve ( "forLoopDone" ) ;
} ) . catch ( function ( e ) {
2017-08-15 22:22:46 +02:00
if ( e == "BREAKSTATEMENT" ||
( e instanceof WorkerScript && e . errorMessage == "BREAKSTATEMENT" ) ) {
return resolve ( "whileLoopBroken" ) ;
} else {
reject ( e ) ;
}
2017-06-28 11:47:42 +02:00
} ) ;
break ;
case "ForStatement" :
evaluate ( exp . init , workerScript ) . then ( function ( expInit ) {
return evaluateFor ( exp , workerScript ) ;
} ) . then ( function ( forLoopRes ) {
resolve ( "forLoopDone" ) ;
} ) . catch ( function ( e ) {
2017-08-15 22:22:46 +02:00
if ( e == "BREAKSTATEMENT" ||
( e instanceof WorkerScript && e . errorMessage == "BREAKSTATEMENT" ) ) {
return resolve ( "forLoopBroken" ) ;
} else {
reject ( e ) ;
}
2017-06-28 11:47:42 +02:00
} ) ;
2017-06-05 06:48:37 +02:00
break ;
default :
reject ( makeRuntimeRejectMsg ( workerScript , "Unrecognized token: " + exp . type + ". This is a bug please report to game developer" ) ) ;
break ;
} //End switch
2017-07-25 16:39:56 +02:00
} , Settings . CodeInstructionRunTime ) ; //End setTimeout, the Netscript operation run time
2017-06-05 06:48:37 +02:00
} ) ; // End Promise
2016-11-17 23:25:40 +01:00
}
2017-06-28 11:47:42 +02:00
function evalBinary ( exp , workerScript ) {
return new Promise ( function ( resolve , reject ) {
var expLeftPromise = evaluate ( exp . left , workerScript ) ;
expLeftPromise . then ( function ( expLeft ) {
var expRightPromise = evaluate ( exp . right , workerScript ) ;
expRightPromise . then ( function ( expRight ) {
switch ( exp . operator ) {
case "===" :
case "==" :
resolve ( expLeft === expRight ) ;
break ;
case "!==" :
case "!=" :
resolve ( expLeft !== expRight ) ;
break ;
case "<" :
resolve ( expLeft < expRight ) ;
break ;
case "<=" :
resolve ( expLeft <= expRight ) ;
break ;
case ">" :
resolve ( expLeft > expRight ) ;
break ;
case ">=" :
resolve ( expLeft >= expRight ) ;
break ;
case "+" :
resolve ( expLeft + expRight ) ;
break ;
case "-" :
resolve ( expLeft - expRight ) ;
break ;
case "*" :
resolve ( expLeft * expRight ) ;
break ;
case "/" :
2017-08-16 02:18:04 +02:00
if ( expRight === 0 ) {
reject ( makeRuntimeRejectMsg ( workerScript , "ERROR: Divide by zero" ) ) ;
} else {
resolve ( expLeft / expRight ) ;
}
2017-06-28 11:47:42 +02:00
break ;
case "%" :
resolve ( expLeft % expRight ) ;
break ;
case "in" :
resolve ( expLeft in expRight ) ;
break ;
case "instanceof" :
resolve ( expLeft instanceof expRight ) ;
break ;
case "||" :
resolve ( expLeft || expRight ) ;
break ;
case "&&" :
resolve ( expLeft && expRight ) ;
break ;
default :
reject ( makeRuntimeRejectMsg ( workerScript , "Bitwise operators are not implemented" ) ) ;
2017-05-12 06:59:07 +02:00
}
} , function ( e ) {
reject ( e ) ;
} ) ;
2017-06-28 11:47:42 +02:00
} , function ( e ) {
reject ( e ) ;
} ) ;
} ) ;
}
function evalUnary ( exp , workerScript ) {
2017-07-27 04:56:14 +02:00
var env = workerScript . env ;
2017-06-28 11:47:42 +02:00
return new Promise ( function ( resolve , reject ) {
2017-07-27 04:56:14 +02:00
if ( env . stopFlag ) { return reject ( workerScript ) ; }
var p = evaluate ( exp . argument , workerScript ) ;
p . then ( function ( res ) {
if ( exp . operator == "!" ) {
resolve ( ! res ) ;
} else if ( exp . operator == "-" ) {
if ( isNaN ( res ) ) {
resolve ( res ) ;
} else {
resolve ( - 1 * res ) ;
}
} else {
reject ( makeRuntimeRejectMsg ( workerScript , "Unimplemented unary operator: " + exp . operator ) ) ;
2017-06-28 11:47:42 +02:00
}
2017-07-27 04:56:14 +02:00
} ) . catch ( function ( e ) {
reject ( e ) ;
2017-06-28 11:47:42 +02:00
} ) ;
} ) ;
}
function evalAssignment ( exp , workerScript ) {
var env = workerScript . env ;
return new Promise ( function ( resolve , reject ) {
if ( env . stopFlag ) { return reject ( workerScript ) ; }
2017-07-13 18:54:29 +02:00
if ( exp . left . type != "Identifier" && exp . left . type != "MemberExpression" ) {
2017-06-28 11:47:42 +02:00
return reject ( makeRuntimeRejectMsg ( workerScript , "Cannot assign to " + JSON . stringify ( exp . left ) ) ) ;
2017-05-12 06:59:07 +02:00
}
2017-06-28 11:47:42 +02:00
if ( exp . operator !== "=" && ! ( exp . left . name in env . vars ) ) {
2017-08-30 19:44:29 +02:00
return reject ( makeRuntimeRejectMsg ( workerScript , "variable " + exp . left . name + " not defined" ) ) ;
2017-06-28 11:47:42 +02:00
}
2017-07-25 16:39:56 +02:00
2017-06-28 11:47:42 +02:00
var expRightPromise = evaluate ( exp . right , workerScript ) ;
expRightPromise . then ( function ( expRight ) {
2017-07-13 18:54:29 +02:00
if ( exp . left . type == "MemberExpression" ) {
//Assign to array element
//Array object designed by exp.left.object.name
//Index designated by exp.left.property
var name = exp . left . object . name ;
if ( ! ( name in env . vars ) ) {
2017-08-30 19:44:29 +02:00
reject ( makeRuntimeRejectMsg ( workerScript , "variable " + name + " not defined" ) ) ;
2017-07-13 18:54:29 +02:00
}
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 {
switch ( exp . operator ) {
case "=" :
env . set ( exp . left . name , expRight ) ;
break ;
case "+=" :
env . set ( exp . left . name , env . get ( exp . left . name ) + expRight ) ;
break ;
case "-=" :
env . set ( exp . left . name , env . get ( exp . left . name ) - expRight ) ;
break ;
case "*=" :
env . set ( exp . left . name , env . get ( exp . left . name ) * expRight ) ;
break ;
case "/=" :
env . set ( exp . left . name , env . get ( exp . left . name ) / expRight ) ;
break ;
case "%=" :
env . set ( exp . left . name , env . get ( exp . left . name ) % expRight ) ;
break ;
default :
reject ( makeRuntimeRejectMsg ( workerScript , "Bitwise assignment is not implemented" ) ) ;
}
} catch ( e ) {
return reject ( makeRuntimeRejectMsg ( workerScript , "Failed to set environment variable: " + e . toString ( ) ) ) ;
2017-06-28 11:47:42 +02:00
}
}
resolve ( false ) ; //Return false so this doesnt cause conditionals to evaluate
} , function ( e ) {
reject ( e ) ;
} ) ;
} ) ;
}
//Returns true if any of the if statements evaluated, false otherwise. Therefore, the else statement
//should evaluate if this returns false
function evaluateIf ( exp , workerScript , i ) {
var env = workerScript . env ;
return new Promise ( function ( resolve , reject ) {
evaluate ( exp . test , workerScript ) . then ( function ( condRes ) {
if ( condRes ) {
evaluate ( exp . consequent , workerScript ) . then ( function ( res ) {
resolve ( true ) ;
} , function ( e ) {
reject ( e ) ;
} ) ;
} else if ( exp . alternate ) {
evaluate ( exp . alternate , workerScript ) . then ( function ( res ) {
resolve ( true ) ;
} , function ( e ) {
reject ( e ) ;
} ) ;
} else {
resolve ( "endIf" )
}
} , function ( e ) {
reject ( e ) ;
} ) ;
2017-05-12 06:59:07 +02:00
} ) ;
}
2016-11-30 00:07:24 +01:00
//Evaluate the looping part of a for loop (Initialization block is NOT done in here)
function evaluateFor ( exp , workerScript ) {
2016-12-15 23:22:42 +01:00
var env = workerScript . env ;
2016-11-30 00:07:24 +01:00
return new Promise ( function ( resolve , reject ) {
2017-05-30 15:57:24 +02:00
if ( env . stopFlag ) { reject ( workerScript ) ; return ; }
2017-07-25 16:39:56 +02:00
2017-06-28 11:47:42 +02:00
var pCond = evaluate ( exp . test , workerScript ) ;
2016-11-30 00:07:24 +01:00
pCond . then ( function ( resCond ) {
if ( resCond ) {
//Run the for loop code
2017-06-28 11:47:42 +02:00
var pBody = evaluate ( exp . body , workerScript ) ;
2016-11-30 00:07:24 +01:00
//After the code executes make a recursive call
2017-06-28 11:47:42 +02:00
pBody . then ( function ( resCode ) {
var pUpdate = evaluate ( exp . update , workerScript ) ;
pUpdate . then ( function ( resPostloop ) {
2016-11-30 00:07:24 +01:00
var recursiveCall = evaluateFor ( exp , workerScript ) ;
recursiveCall . then ( function ( foo ) {
resolve ( "endForLoop" ) ;
2016-12-15 23:22:42 +01:00
} , function ( e ) {
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
2016-12-15 23:22:42 +01:00
} , function ( e ) {
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
2016-12-15 23:22:42 +01:00
} , function ( e ) {
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
} else {
resolve ( "endForLoop" ) ; //Doesn't need to resolve to any particular value
}
2016-12-15 23:22:42 +01:00
} , function ( e ) {
2017-08-15 22:22:46 +02:00
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
} ) ;
}
function evaluateWhile ( exp , workerScript ) {
2016-12-15 23:22:42 +01:00
var env = workerScript . env ;
2017-07-25 16:39:56 +02:00
2016-11-30 00:07:24 +01:00
return new Promise ( function ( resolve , reject ) {
2017-05-30 15:57:24 +02:00
if ( env . stopFlag ) { reject ( workerScript ) ; return ; }
2017-07-25 16:39:56 +02:00
2016-11-30 00:07:24 +01:00
var pCond = new Promise ( function ( resolve , reject ) {
setTimeout ( function ( ) {
2017-06-28 11:47:42 +02:00
var evaluatePromise = evaluate ( exp . test , workerScript ) ;
2016-11-30 00:07:24 +01:00
evaluatePromise . then ( function ( resCond ) {
resolve ( resCond ) ;
2016-12-15 23:22:42 +01:00
} , function ( e ) {
2017-07-25 16:39:56 +02:00
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
} , CONSTANTS . CodeInstructionRunTime ) ;
} ) ;
2017-07-25 16:39:56 +02:00
2016-11-30 00:07:24 +01:00
pCond . then ( function ( resCond ) {
if ( resCond ) {
//Run the while loop code
var pCode = new Promise ( function ( resolve , reject ) {
setTimeout ( function ( ) {
2017-06-28 11:47:42 +02:00
var evaluatePromise = evaluate ( exp . body , workerScript ) ;
2016-11-30 00:07:24 +01:00
evaluatePromise . then ( function ( resCode ) {
resolve ( resCode ) ;
2016-12-15 23:22:42 +01:00
} , function ( e ) {
2017-08-15 22:22:46 +02:00
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
} , CONSTANTS . CodeInstructionRunTime ) ;
} ) ;
2017-07-25 16:39:56 +02:00
2016-11-30 00:07:24 +01:00
//After the code executes make a recursive call
pCode . then ( function ( resCode ) {
var recursiveCall = evaluateWhile ( exp , workerScript ) ;
recursiveCall . then ( function ( foo ) {
resolve ( "endWhileLoop" ) ;
2016-12-15 23:22:42 +01:00
} , function ( e ) {
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
2016-12-15 23:22:42 +01:00
} , function ( e ) {
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
} else {
2017-08-15 22:22:46 +02:00
resolve ( "endWhileLoop" ) ; //Doesn't need to resolve to any particular value
2016-11-30 00:07:24 +01:00
}
2016-12-15 23:22:42 +01:00
} , function ( e ) {
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
} ) ;
}
function evaluateProg ( exp , workerScript , index ) {
2016-12-15 23:22:42 +01:00
var env = workerScript . env ;
2017-07-25 16:39:56 +02:00
2016-11-30 00:07:24 +01:00
return new Promise ( function ( resolve , reject ) {
2017-05-30 15:57:24 +02:00
if ( env . stopFlag ) { reject ( workerScript ) ; return ; }
2017-07-25 16:39:56 +02:00
2017-06-28 11:47:42 +02:00
if ( index >= exp . body . length ) {
2016-11-30 00:07:24 +01:00
resolve ( "progFinished" ) ;
} else {
//Evaluate this line of code in the prog
var code = new Promise ( function ( resolve , reject ) {
setTimeout ( function ( ) {
2017-06-28 11:47:42 +02:00
var evaluatePromise = evaluate ( exp . body [ index ] , workerScript ) ;
2016-11-30 00:07:24 +01:00
evaluatePromise . then ( function ( evalRes ) {
resolve ( evalRes ) ;
2016-12-15 23:22:42 +01:00
} , function ( e ) {
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
} , CONSTANTS . CodeInstructionRunTime ) ;
} ) ;
2017-07-25 16:39:56 +02:00
2016-11-30 00:07:24 +01:00
//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 ) {
2016-12-06 17:59:20 +01:00
resolve ( workerScript ) ;
2016-12-15 23:22:42 +01:00
} , function ( e ) {
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
2016-12-15 23:22:42 +01:00
} , function ( e ) {
reject ( e ) ;
2016-11-30 00:07:24 +01:00
} ) ;
}
} ) ;
}
2017-06-05 06:48:37 +02:00
function netscriptDelay ( time ) {
2017-07-25 16:39:56 +02:00
return new Promise ( function ( resolve ) {
2017-06-05 06:48:37 +02:00
setTimeout ( resolve , time ) ;
} ) ;
}
2017-05-25 14:18:34 +02:00
function makeRuntimeRejectMsg ( workerScript , msg ) {
return "|" + workerScript . serverIp + "|" + workerScript . name + "|" + msg ;
}
2016-11-17 23:25:40 +01:00
function apply _op ( op , a , b ) {
function num ( x ) {
if ( typeof x != "number" )
throw new Error ( "Expected number but got " + x ) ;
return x ;
}
function div ( x ) {
if ( num ( x ) == 0 )
throw new Error ( "Divide by zero" ) ;
return x ;
}
switch ( op ) {
2017-05-23 20:17:37 +02:00
case "+" : return a + b ;
2016-11-17 23:25:40 +01:00
case "-" : return num ( a ) - num ( b ) ;
case "*" : return num ( a ) * num ( b ) ;
case "/" : return num ( a ) / div ( b ) ;
case "%" : return num ( a ) % div ( b ) ;
case "&&" : return a !== false && b ;
case "||" : return a !== false ? a : b ;
case "<" : return num ( a ) < num ( b ) ;
case ">" : return num ( a ) > num ( b ) ;
case "<=" : return num ( a ) <= num ( b ) ;
case ">=" : return num ( a ) >= num ( b ) ;
case "==" : return a === b ;
case "!=" : return a !== b ;
}
throw new Error ( "Can't apply operator " + op ) ;
2017-05-15 08:35:09 +02:00
}
//Run a script from inside a script using run() command
2017-06-17 04:53:57 +02:00
function runScriptFromScript ( server , scriptname , args , workerScript , threads = 1 ) {
2017-07-13 18:54:29 +02:00
//Check if the script is already running
var runningScriptObj = findRunningScript ( scriptname , args , server ) ;
if ( runningScriptObj != null ) {
workerScript . scriptRef . log ( scriptname + " is already running on " + server . hostname ) ;
return Promise . resolve ( false ) ;
}
2017-06-28 11:47:42 +02:00
2017-07-13 18:54:29 +02:00
//Check if the script exists and if it does run it
for ( var i = 0 ; i < server . scripts . length ; ++ i ) {
if ( server . scripts [ i ] . filename == scriptname ) {
//Check for admin rights and that there is enough RAM availble to run
var script = server . scripts [ i ] ;
var ramUsage = script . ramUsage ;
ramUsage = ramUsage * threads * Math . pow ( CONSTANTS . MultithreadingRAMCost , threads - 1 ) ;
var ramAvailable = server . maxRam - server . ramUsed ;
2017-06-28 11:47:42 +02:00
2017-07-13 18:54:29 +02:00
if ( server . hasAdminRights == false ) {
workerScript . scriptRef . log ( "Cannot run script " + scriptname + " on " + server . hostname + " because you do not have root access!" ) ;
return Promise . resolve ( false ) ;
} else if ( ramUsage > ramAvailable ) {
workerScript . scriptRef . log ( "Cannot run script " + scriptname + "(t=" + threads + ") on " + server . hostname + " because there is not enough available RAM!" ) ;
return Promise . resolve ( false ) ;
} else {
//Able to run script
workerScript . scriptRef . log ( "Running script: " + scriptname + " on " + server . hostname + " with " + threads + " threads and args: " + printArray ( args ) + ". May take a few seconds to start up..." ) ;
var runningScriptObj = new RunningScript ( script , args ) ;
runningScriptObj . threads = threads ;
server . runningScripts . push ( runningScriptObj ) ; //Push onto runningScripts
addWorkerScript ( runningScriptObj , server ) ;
return Promise . resolve ( true ) ;
2017-05-15 08:35:09 +02:00
}
2017-06-28 11:47:42 +02:00
}
2017-07-13 18:54:29 +02:00
}
workerScript . scriptRef . log ( "Could not find script " + scriptname + " on " + server . hostname ) ;
return Promise . resolve ( false ) ;
2017-05-15 08:35:09 +02:00
}
2016-12-14 00:52:32 +01:00
2017-05-01 07:39:48 +02:00
function isScriptErrorMessage ( msg ) {
2017-08-30 19:44:29 +02:00
if ( ! isString ( msg ) ) { return false ; }
let splitMsg = msg . split ( "|" ) ;
2017-05-01 07:39:48 +02:00
if ( splitMsg . length != 4 ) {
return false ;
}
var ip = splitMsg [ 1 ] ;
if ( ! isValidIPAddress ( ip ) ) {
return false ;
}
return true ;
}
2016-12-14 00:52:32 +01:00
//The same as Player's calculateHackingChance() function but takes in the server as an argument
function scriptCalculateHackingChance ( server ) {
var difficultyMult = ( 100 - server . hackDifficulty ) / 100 ;
2017-07-22 00:54:55 +02:00
var skillMult = ( 1.75 * Player . hacking _skill ) ;
2016-12-14 00:52:32 +01:00
var skillChance = ( skillMult - server . requiredHackingSkill ) / skillMult ;
2017-05-24 15:49:52 +02:00
var chance = skillChance * difficultyMult * Player . hacking _chance _mult ;
2017-07-22 00:54:55 +02:00
if ( chance > 1 ) { return 1 ; }
2017-04-17 14:26:54 +02:00
if ( chance < 0 ) { return 0 ; }
else { return chance ; }
2016-12-14 00:52:32 +01:00
}
//The same as Player's calculateHackingTime() function but takes in the server as an argument
function scriptCalculateHackingTime ( server ) {
var difficultyMult = server . requiredHackingSkill * server . hackDifficulty ;
2017-05-03 06:38:58 +02:00
var skillFactor = ( 2.5 * difficultyMult + 500 ) / ( Player . hacking _skill + 50 ) ;
2017-06-18 06:36:16 +02:00
var hackingTime = 5 * skillFactor / Player . hacking _speed _mult ; //This is in seconds
2016-12-14 21:29:40 +01:00
return hackingTime ;
2016-12-14 00:52:32 +01:00
}
2017-07-25 16:39:56 +02:00
//The same as Player's calculateExpGain() function but takes in the server as an argument
2016-12-14 00:52:32 +01:00
function scriptCalculateExpGain ( server ) {
2017-06-15 03:19:52 +02:00
if ( server . baseDifficulty == null ) {
server . baseDifficulty = server . hackDifficulty ;
}
2017-08-30 19:44:29 +02:00
return ( server . baseDifficulty * Player . hacking _exp _mult * 0.3 + 3 ) * BitNodeMultipliers . HackExpGain ;
2016-12-14 00:52:32 +01:00
}
//The same as Player's calculatePercentMoneyHacked() function but takes in the server as an argument
function scriptCalculatePercentMoneyHacked ( server ) {
var difficultyMult = ( 100 - server . hackDifficulty ) / 100 ;
var skillMult = ( Player . hacking _skill - ( server . requiredHackingSkill - 1 ) ) / Player . hacking _skill ;
2017-07-22 00:54:55 +02:00
var percentMoneyHacked = difficultyMult * skillMult * Player . hacking _money _mult / 240 ;
2017-04-18 06:32:17 +02:00
if ( percentMoneyHacked < 0 ) { return 0 ; }
if ( percentMoneyHacked > 1 ) { return 1 ; }
2017-08-30 19:44:29 +02:00
return percentMoneyHacked * BitNodeMultipliers . ScriptHackMoney ;
2017-05-24 15:49:52 +02:00
}
2017-05-31 19:37:32 +02:00
//Amount of time to execute grow() in milliseconds
2017-05-24 15:49:52 +02:00
function scriptCalculateGrowTime ( server ) {
var difficultyMult = server . requiredHackingSkill * server . hackDifficulty ;
var skillFactor = ( 2.5 * difficultyMult + 500 ) / ( Player . hacking _skill + 50 ) ;
2017-06-21 19:19:08 +02:00
var growTime = 16 * skillFactor / Player . hacking _speed _mult ; //This is in seconds
2017-05-24 15:49:52 +02:00
return growTime * 1000 ;
2017-05-31 19:37:32 +02:00
}
//Amount of time to execute weaken() in milliseconds
function scriptCalculateWeakenTime ( server ) {
var difficultyMult = server . requiredHackingSkill * server . hackDifficulty ;
var skillFactor = ( 2.5 * difficultyMult + 500 ) / ( Player . hacking _skill + 50 ) ;
2017-07-22 00:54:55 +02:00
var weakenTime = 20 * skillFactor / Player . hacking _speed _mult ; //This is in seconds
2017-05-31 19:37:32 +02:00
return weakenTime * 1000 ;
2017-07-25 16:39:56 +02:00
}
2017-08-30 19:44:29 +02:00
export { makeRuntimeRejectMsg , netscriptDelay , runScriptFromScript ,
scriptCalculateHackingChance , scriptCalculateHackingTime ,
scriptCalculateExpGain , scriptCalculatePercentMoneyHacked ,
scriptCalculateGrowTime , scriptCalculateWeakenTime , evaluate ,
isScriptErrorMessage } ;