2018-06-26 18:34:11 +02:00
import { BitNodeMultipliers } from "./BitNode" ;
import { CONSTANTS } from "./Constants" ;
import { Player } from "./Player" ;
import { Environment } from "./NetscriptEnvironment" ;
import { WorkerScript , addWorkerScript } from "./NetscriptWorker" ;
import { Server , getServer } from "./Server" ;
import { Settings } from "./Settings" ;
2017-08-30 19:44:29 +02:00
import { Script , findRunningScript ,
2018-06-26 18:34:11 +02:00
RunningScript } from "./Script" ;
2017-08-30 19:44:29 +02:00
2018-06-26 18:34:11 +02:00
import { parse , Node } from "../utils/acorn" ;
import { printArray } from "../utils/HelperFunctions" ;
import { isValidIPAddress } from "../utils/IPAddress" ;
2018-07-04 06:33:55 +02:00
import { isString } from "../utils/helpers/isString" ;
2017-08-30 19:44:29 +02:00
2017-11-01 23:56:30 +01:00
var Promise = require ( "bluebird" ) ;
Promise . config ( {
warnings : false ,
longStackTraces : false ,
cancellation : true ,
monitoring : false
} ) ;
2016-11-17 23:25:40 +01:00
/ * E v a l u a t o r
2017-11-01 23:56:30 +01:00
* Evaluates / Interprets the Abstract Syntax Tree generated by Acorns parser
2017-09-05 03:03:29 +02:00
*
* Returns a promise
2016-11-17 23:25:40 +01:00
* /
2016-11-30 00:07:24 +01:00
function evaluate ( exp , workerScript ) {
2017-11-01 23:56:30 +01:00
return Promise . delay ( Settings . CodeInstructionRunTime ) . then ( function ( ) {
var env = workerScript . env ;
if ( env . stopFlag ) { return Promise . reject ( workerScript ) ; }
if ( exp == null ) {
2018-03-03 22:05:33 +01:00
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Error: NULL expression" , exp ) ) ;
2017-11-01 23:56:30 +01:00
}
if ( env . stopFlag ) { return Promise . reject ( workerScript ) ; }
2017-06-05 06:48:37 +02:00
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
2017-11-01 23:56:30 +01:00
return evaluateProgPromise . then ( function ( w ) {
return Promise . resolve ( workerScript ) ;
} ) . catch ( function ( e ) {
2017-09-29 17:02:33 +02:00
if ( e . constructor === Array && e . length === 2 && e [ 0 ] === "RETURNSTATEMENT" ) {
2017-11-01 23:56:30 +01:00
return Promise . reject ( e ) ;
2017-09-29 17:02:33 +02:00
} else if ( isString ( e ) ) {
2017-06-28 11:47:42 +02:00
workerScript . errorMessage = e ;
2017-11-01 23:56:30 +01:00
return Promise . reject ( workerScript ) ;
2017-06-28 11:47:42 +02:00
} else if ( e instanceof WorkerScript ) {
2017-11-01 23:56:30 +01:00
return Promise . reject ( e ) ;
2017-06-11 00:44:33 +02:00
} else {
2017-11-01 23:56:30 +01:00
return Promise . reject ( workerScript ) ;
2017-06-11 00:44:33 +02:00
}
2017-06-28 11:47:42 +02:00
} ) ;
break ;
case "Literal" :
2017-11-01 23:56:30 +01:00
return Promise . resolve ( exp . value ) ;
2017-06-28 11:47:42 +02:00
break ;
case "Identifier" :
2018-01-27 07:52:39 +01:00
//Javascript constructor() method can be used as an exploit to run arbitrary code
if ( exp . name == "constructor" ) {
2018-03-03 22:05:33 +01:00
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Illegal usage of constructor() method. If you have your own function named 'constructor', you must re-name it." , exp ) ) ;
2018-01-27 07:52:39 +01:00
}
2017-06-28 11:47:42 +02:00
if ( ! ( exp . name in env . vars ) ) {
2018-03-03 22:05:33 +01:00
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "variable " + exp . name + " not defined" , exp ) ) ;
2017-06-05 06:48:37 +02:00
}
2017-11-01 23:56:30 +01:00
return Promise . resolve ( env . get ( exp . name ) )
2017-06-05 06:48:37 +02:00
break ;
2017-06-28 11:47:42 +02:00
case "ExpressionStatement" :
2017-11-01 23:56:30 +01:00
return evaluate ( exp . expression , workerScript ) ;
2017-06-05 06:48:37 +02:00
break ;
2017-06-28 11:47:42 +02:00
case "ArrayExpression" :
var argPromises = exp . elements . map ( function ( arg ) {
return evaluate ( arg , workerScript ) ;
} ) ;
2017-11-01 23:56:30 +01:00
return Promise . all ( argPromises ) . then ( function ( array ) {
return Promise . resolve ( array )
2017-06-05 06:48:37 +02:00
} ) ;
break ;
2017-06-28 11:47:42 +02:00
case "CallExpression" :
2017-11-01 23:56:30 +01:00
return evaluate ( exp . callee , workerScript ) . then ( function ( func ) {
return Promise . map ( exp . arguments , function ( arg ) {
return evaluate ( arg , workerScript ) ;
} ) . then ( function ( args ) {
2017-09-29 17:02:33 +02:00
if ( func instanceof Node ) { //Player-defined function
//Create new Environment for the function
//Should be automatically garbage collected...
var funcEnv = env . extend ( ) ;
//Define function arguments in this new environment
for ( var i = 0 ; i < func . params . length ; ++ i ) {
var arg ;
if ( i >= args . length ) {
arg = null ;
} else {
arg = args [ i ] ;
}
funcEnv . def ( func . params [ i ] . name , arg ) ;
}
//Create a new WorkerScript for this function evaluation
var funcWorkerScript = new WorkerScript ( workerScript . scriptRef ) ;
2017-10-12 04:00:22 +02:00
funcWorkerScript . serverIp = workerScript . serverIp ;
2017-09-29 17:02:33 +02:00
funcWorkerScript . env = funcEnv ;
2017-10-12 04:00:22 +02:00
workerScript . fnWorker = funcWorkerScript ;
2017-09-29 17:02:33 +02:00
2017-11-01 23:56:30 +01:00
return evaluate ( func . body , funcWorkerScript ) . then ( function ( res ) {
2017-10-10 06:56:48 +02:00
//If the function finished successfuly, that means there
//was no return statement since a return statement rejects. So resolve to null
2017-10-12 04:00:22 +02:00
workerScript . fnWorker = null ;
2017-11-01 23:56:30 +01:00
return Promise . resolve ( null ) ;
2017-09-29 17:02:33 +02:00
} ) . catch ( function ( e ) {
2017-10-10 06:56:48 +02:00
if ( e . constructor === Array && e . length === 2 && e [ 0 ] === "RETURNSTATEMENT" ) {
//Return statement from function
2017-11-01 23:56:30 +01:00
return Promise . resolve ( e [ 1 ] ) ;
2017-10-12 04:00:22 +02:00
workerScript . fnWorker = null ;
2017-10-10 06:56:48 +02:00
} else if ( isString ( e ) ) {
2017-11-01 23:56:30 +01:00
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , e ) ) ;
2017-10-04 03:50:13 +02:00
} 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 ] ;
2017-11-01 23:56:30 +01:00
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , errorMsg ) ) ;
2017-10-04 03:50:13 +02:00
} else {
2017-10-12 04:00:22 +02:00
if ( env . stopFlag ) {
2017-11-01 23:56:30 +01:00
return Promise . reject ( workerScript ) ;
2017-10-12 04:00:22 +02:00
} else {
2017-11-01 23:56:30 +01:00
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Error in one of your functions. Could not identify which function" ) ) ;
2017-10-12 04:00:22 +02:00
}
2017-10-04 03:50:13 +02:00
}
} else if ( e instanceof Error ) {
2017-11-01 23:56:30 +01:00
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , e . toString ( ) ) ) ;
2017-10-04 03:50:13 +02:00
}
2017-09-29 17:02:33 +02:00
} ) ;
2018-03-03 22:05:33 +01:00
} else if ( exp . callee . type === "MemberExpression" ) {
2017-11-01 23:56:30 +01:00
return evaluate ( exp . callee . object , workerScript ) . then ( function ( object ) {
2017-06-28 11:47:42 +02:00
try {
2018-02-24 23:55:06 +01:00
if ( func === "NETSCRIPTFOREACH" ) {
return evaluateForeach ( object , args , workerScript ) . then ( function ( res ) {
return Promise . resolve ( res ) ;
} ) . catch ( function ( e ) {
return Promise . reject ( e ) ;
} ) ;
}
2017-07-13 18:54:29 +02:00
var res = func . apply ( object , args ) ;
2017-11-01 23:56:30 +01:00
return Promise . resolve ( res ) ;
2017-06-28 11:47:42 +02:00
} catch ( e ) {
2018-03-03 22:05:33 +01:00
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , e , exp ) ) ;
2017-06-28 11:47:42 +02:00
}
2017-05-12 06:59:07 +02:00
} ) ;
} else {
2017-06-28 11:47:42 +02:00
try {
var out = func . apply ( null , args ) ;
if ( out instanceof Promise ) {
2017-11-01 23:56:30 +01:00
return out . then ( function ( res ) {
return Promise . resolve ( res )
2017-06-28 11:47:42 +02:00
} ) . catch ( function ( e ) {
2018-03-03 22:05:33 +01:00
if ( isScriptErrorMessage ( e ) ) {
//Functions don't have line number appended in error message, so add it
var num = getErrorLineNumber ( exp , workerScript ) ;
e += " (Line " + num + ")" ;
}
2017-11-01 23:56:30 +01:00
return Promise . reject ( e ) ;
2017-06-28 11:47:42 +02:00
} ) ;
} else {
2017-11-01 23:56:30 +01:00
return Promise . resolve ( out ) ;
2017-06-28 11:47:42 +02:00
}
} catch ( e ) {
2017-07-13 18:54:29 +02:00
if ( isScriptErrorMessage ( e ) ) {
2018-03-03 22:05:33 +01:00
if ( isScriptErrorMessage ( e ) ) {
//Functions don't have line number appended in error message, so add it
var num = getErrorLineNumber ( exp , workerScript ) ;
e += " (Line " + num + ")" ;
}
2017-11-01 23:56:30 +01:00
return Promise . reject ( e ) ;
2017-07-13 18:54:29 +02:00
} else {
2018-03-03 22:05:33 +01:00
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , e , exp ) ) ;
2017-07-13 18:54:29 +02:00
}
2017-06-28 11:47:42 +02:00
}
2017-05-12 06:59:07 +02:00
}
2017-06-28 11:47:42 +02:00
} ) ;
2017-05-12 06:59:07 +02:00
} ) ;
2017-06-05 06:48:37 +02:00
break ;
2017-06-28 11:47:42 +02:00
case "MemberExpression" :
2017-11-01 23:56:30 +01:00
return evaluate ( exp . object , workerScript ) . then ( function ( object ) {
2017-06-28 11:47:42 +02:00
if ( exp . computed ) {
2017-11-01 23:56:30 +01:00
return evaluate ( exp . property , workerScript ) . then ( function ( index ) {
2017-07-29 18:25:40 +02:00
if ( index >= object . length ) {
2018-03-03 22:05:33 +01:00
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Invalid index for arrays" , exp ) ) ;
2017-07-29 18:25:40 +02:00
}
2017-11-01 23:56:30 +01:00
return Promise . resolve ( object [ index ] ) ;
2017-06-28 11:47:42 +02:00
} ) . catch ( function ( e ) {
2017-11-09 02:55:21 +01:00
if ( e instanceof WorkerScript || isScriptErrorMessage ( e ) ) {
return Promise . reject ( e ) ;
} else {
2018-03-03 22:05:33 +01:00
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Invalid MemberExpression" , exp ) ) ;
2017-11-09 02:55:21 +01:00
}
2017-06-28 11:47:42 +02:00
} ) ;
} else {
2018-01-27 07:52:39 +01:00
if ( exp . property . name === "constructor" ) {
2018-03-03 22:05:33 +01:00
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Illegal usage of constructor() method. If you have your own function named 'constructor', you must re-name it." , exp ) ) ;
2018-01-27 07:52:39 +01:00
}
2018-02-24 23:55:06 +01:00
if ( object != null && object instanceof Array && exp . property . name === "forEach" ) {
return "NETSCRIPTFOREACH" ;
}
2017-06-28 11:47:42 +02:00
try {
2017-11-01 23:56:30 +01:00
return Promise . resolve ( object [ exp . property . name ] )
2017-06-28 11:47:42 +02:00
} catch ( e ) {
2018-03-03 22:05:33 +01:00
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Failed to get property: " + e . toString ( ) , exp ) ) ;
2017-06-28 11:47:42 +02:00
}
}
2017-06-05 06:48:37 +02:00
} ) ;
break ;
2017-06-28 11:47:42 +02:00
case "LogicalExpression" :
case "BinaryExpression" :
2017-11-02 22:47:09 +01:00
return evalBinary ( exp , workerScript ) ;
2017-06-05 06:48:37 +02:00
break ;
2017-07-27 04:56:14 +02:00
case "UnaryExpression" :
2017-11-02 22:47:09 +01:00
return evalUnary ( exp , workerScript ) ;
2017-07-27 04:56:14 +02:00
break ;
2017-06-28 11:47:42 +02:00
case "AssignmentExpression" :
2017-11-02 22:47:09 +01:00
return evalAssignment ( exp , workerScript ) ;
2017-06-05 06:48:37 +02:00
break ;
2018-06-22 21:39:15 +02:00
case "VariableDeclaration" :
return evalVariableDeclaration ( exp , workerScript ) ;
break ;
2017-06-28 11:47:42 +02:00
case "UpdateExpression" :
if ( exp . argument . type === "Identifier" ) {
if ( exp . argument . name in env . vars ) {
2017-11-01 23:56:30 +01:00
if ( exp . operator === "++" || exp . operator === "--" ) {
switch ( exp . operator ) {
case "++" :
env . set ( exp . argument . name , env . get ( exp . argument . name ) + 1 ) ;
break ;
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 ++/--
2017-06-28 11:47:42 +02:00
if ( exp . prefix ) {
2017-11-01 23:56:30 +01:00
return Promise . resolve ( env . get ( exp . argument . name ) )
2017-06-28 11:47:42 +02:00
}
switch ( exp . operator ) {
default :
2018-03-03 22:05:33 +01:00
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Unrecognized token: " + exp . type + ". You are trying to use code that is currently unsupported" , exp ) ) ;
2017-06-05 19:50:32 +02:00
}
2017-11-01 23:56:30 +01:00
return Promise . resolve ( env . get ( exp . argument . name ) )
2017-06-28 11:47:42 +02:00
} else {
2018-03-03 22:05:33 +01:00
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "variable " + exp . argument . name + " not defined" , exp ) ) ;
2017-06-26 01:39:17 +02:00
}
2017-06-05 06:48:37 +02:00
} else {
2018-03-03 22:05:33 +01:00
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "argument must be an identifier" , exp ) ) ;
2017-06-28 11:47:42 +02:00
}
break ;
case "EmptyStatement" :
2017-11-01 23:56:30 +01:00
return Promise . resolve ( false ) ;
2017-06-28 11:47:42 +02:00
break ;
case "ReturnStatement" :
2017-11-01 23:56:30 +01:00
return evaluate ( exp . argument , workerScript ) . then ( function ( res ) {
return Promise . reject ( [ "RETURNSTATEMENT" , res ] ) ;
2017-09-29 17:02:33 +02:00
} ) ;
2017-06-28 11:47:42 +02:00
break ;
case "BreakStatement" :
2017-11-01 23:56:30 +01:00
return Promise . reject ( "BREAKSTATEMENT" ) ;
2017-06-28 11:47:42 +02:00
break ;
2017-09-21 23:27:31 +02:00
case "ContinueStatement" :
2017-11-01 23:56:30 +01:00
return Promise . reject ( "CONTINUESTATEMENT" ) ;
2017-09-21 23:27:31 +02:00
break ;
2017-06-28 11:47:42 +02:00
case "IfStatement" :
2017-11-02 22:47:09 +01:00
return evaluateIf ( exp , workerScript ) ;
2017-06-28 11:47:42 +02:00
break ;
case "SwitchStatement" :
2018-03-03 22:05:33 +01:00
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Switch statements are not yet implemented in Netscript" , exp ) ) ;
2017-11-01 23:56:30 +01:00
break ;
2017-06-28 11:47:42 +02:00
case "WhileStatement" :
2017-11-02 22:47:09 +01:00
return evaluateWhile ( exp , workerScript ) . then ( function ( res ) {
return Promise . resolve ( res ) ;
2017-06-28 11:47:42 +02:00
} ) . catch ( function ( e ) {
2017-08-15 22:22:46 +02:00
if ( e == "BREAKSTATEMENT" ||
( e instanceof WorkerScript && e . errorMessage == "BREAKSTATEMENT" ) ) {
2017-11-01 23:56:30 +01:00
return Promise . resolve ( "whileLoopBroken" ) ;
2017-08-15 22:22:46 +02:00
} else {
2017-11-01 23:56:30 +01:00
return Promise . reject ( e ) ;
2017-08-15 22:22:46 +02:00
}
2017-06-28 11:47:42 +02:00
} ) ;
break ;
case "ForStatement" :
2017-11-01 23:56:30 +01:00
return evaluate ( exp . init , workerScript ) . then ( function ( expInit ) {
2017-06-28 11:47:42 +02:00
return evaluateFor ( exp , workerScript ) ;
} ) . then ( function ( forLoopRes ) {
2017-11-01 23:56:30 +01:00
return Promise . resolve ( "forLoopDone" ) ;
2017-06-28 11:47:42 +02:00
} ) . catch ( function ( e ) {
2017-08-15 22:22:46 +02:00
if ( e == "BREAKSTATEMENT" ||
( e instanceof WorkerScript && e . errorMessage == "BREAKSTATEMENT" ) ) {
2017-11-01 23:56:30 +01:00
return Promise . resolve ( "forLoopBroken" ) ;
2017-08-15 22:22:46 +02:00
} else {
2017-11-01 23:56:30 +01:00
return Promise . reject ( e ) ;
2017-08-15 22:22:46 +02:00
}
2017-06-28 11:47:42 +02:00
} ) ;
2017-06-05 06:48:37 +02:00
break ;
2017-09-29 17:02:33 +02:00
case "FunctionDeclaration" :
if ( exp . id && exp . id . name ) {
env . set ( exp . id . name , exp ) ;
2017-11-01 23:56:30 +01:00
return Promise . resolve ( true ) ;
2017-09-29 17:02:33 +02:00
} else {
2018-03-03 22:05:33 +01:00
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Invalid function declaration" , exp ) ) ;
2017-09-29 17:02:33 +02:00
}
break ;
2018-03-03 22:05:33 +01:00
case "ImportDeclaration" :
return evaluateImport ( exp , workerScript ) . then ( function ( res ) {
return Promise . resolve ( res ) ;
} ) . catch ( function ( e ) {
return Promise . reject ( e ) ;
} ) ;
break ;
case "ThrowStatement" :
return evaluate ( exp . argument , workerScript ) . then ( function ( res ) {
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , res ) ) ;
} ) ;
break ;
2017-06-05 06:48:37 +02:00
default :
2018-03-03 22:05:33 +01:00
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Unrecognized token: " + exp . type + ". This is currently unsupported in Netscript" , exp ) ) ;
2017-06-05 06:48:37 +02:00
break ;
} //End switch
2017-11-01 23:56:30 +01:00
} ) . catch ( function ( e ) {
return Promise . reject ( e ) ;
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 ) {
2017-11-01 23:56:30 +01:00
return evaluate ( exp . left , workerScript ) . then ( function ( expLeft ) {
//Short circuiting
2018-06-22 21:39:15 +02:00
if ( expLeft && exp . operator === "||" ) {
return Promise . resolve ( expLeft ) ;
2017-11-01 23:56:30 +01:00
}
2018-06-22 21:39:15 +02:00
if ( ! expLeft && exp . operator === "&&" ) {
return Promise . resolve ( expLeft ) ;
2017-11-01 23:56:30 +01:00
}
return evaluate ( exp . right , workerScript ) . then ( function ( expRight ) {
switch ( exp . operator ) {
case "===" :
case "==" :
return Promise . resolve ( expLeft === expRight ) ;
break ;
case "!==" :
case "!=" :
return Promise . resolve ( expLeft !== expRight ) ;
break ;
case "<" :
return Promise . resolve ( expLeft < expRight ) ;
break ;
case "<=" :
return Promise . resolve ( expLeft <= expRight ) ;
break ;
case ">" :
return Promise . resolve ( expLeft > expRight ) ;
break ;
case ">=" :
return Promise . resolve ( expLeft >= expRight ) ;
break ;
case "+" :
return Promise . resolve ( expLeft + expRight ) ;
break ;
case "-" :
return Promise . resolve ( expLeft - expRight ) ;
break ;
case "*" :
return Promise . resolve ( expLeft * expRight ) ;
break ;
case "/" :
if ( expRight === 0 ) {
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "ERROR: Divide by zero" ) ) ;
} else {
return Promise . resolve ( expLeft / expRight ) ;
}
break ;
case "%" :
return Promise . resolve ( expLeft % expRight ) ;
break ;
case "in" :
return Promise . resolve ( expLeft in expRight ) ;
break ;
case "instanceof" :
return Promise . resolve ( expLeft instanceof expRight ) ;
break ;
case "||" :
return Promise . resolve ( expLeft || expRight ) ;
break ;
case "&&" :
return Promise . resolve ( expLeft && expRight ) ;
break ;
default :
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Unsupported operator: " + exp . operator ) ) ;
2017-09-15 16:06:59 +02:00
}
2017-06-28 11:47:42 +02:00
} ) ;
} ) ;
}
function evalUnary ( exp , workerScript ) {
2017-07-27 04:56:14 +02:00
var env = workerScript . env ;
2017-11-01 23:56:30 +01:00
if ( env . stopFlag ) { return Promise . reject ( workerScript ) ; }
return evaluate ( exp . argument , workerScript ) . then ( function ( res ) {
if ( exp . operator == "!" ) {
return Promise . resolve ( ! res ) ;
} else if ( exp . operator == "-" ) {
if ( isNaN ( res ) ) {
return Promise . resolve ( res ) ;
2017-07-27 04:56:14 +02:00
} else {
2017-11-01 23:56:30 +01:00
return Promise . resolve ( - 1 * res ) ;
2017-06-28 11:47:42 +02:00
}
2017-11-01 23:56:30 +01:00
} else {
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Unimplemented unary operator: " + exp . operator ) ) ;
}
2017-06-28 11:47:42 +02:00
} ) ;
}
2017-09-15 16:06:59 +02:00
//Takes in a MemberExpression that should represent a Netscript array (possible multidimensional)
//The return value is an array of the form:
// [0th index (leftmost), array name, 1st index, 2nd index, ...]
function getArrayElement ( exp , workerScript ) {
2017-11-01 23:56:30 +01:00
var indices = [ ] ;
return evaluate ( exp . property , workerScript ) . then ( function ( idx ) {
if ( isNaN ( 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 ) {
return getArrayElement ( exp . object , workerScript ) . then ( function ( res ) {
res . push ( idx ) ;
indices = res ;
return Promise . resolve ( indices ) ;
} ) . catch ( function ( e ) {
return Promise . reject ( e ) ;
} ) ;
2017-09-15 16:06:59 +02:00
} else {
2017-11-01 23:56:30 +01:00
indices . push ( idx ) ;
indices . push ( exp . object . name ) ;
return Promise . resolve ( indices ) ;
2017-09-15 16:06:59 +02:00
}
2017-11-01 23:56:30 +01:00
}
2017-09-15 16:06:59 +02:00
} ) ;
}
2017-06-28 11:47:42 +02:00
function evalAssignment ( exp , workerScript ) {
var env = workerScript . env ;
2017-11-01 23:56:30 +01:00
if ( env . stopFlag ) { return Promise . reject ( workerScript ) ; }
2017-06-28 11:47:42 +02:00
2017-11-01 23:56:30 +01:00
if ( exp . left . type != "Identifier" && exp . left . type != "MemberExpression" ) {
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Cannot assign to " + JSON . stringify ( exp . left ) ) ) ;
}
2017-06-28 11:47:42 +02:00
2017-11-01 23:56:30 +01:00
if ( exp . operator !== "=" && ! ( exp . left . name in env . vars ) ) {
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "variable " + exp . left . name + " not defined" ) ) ;
}
2017-07-25 16:39:56 +02:00
2017-11-01 23:56:30 +01:00
return evaluate ( exp . right , workerScript ) . then ( function ( expRight ) {
if ( exp . left . type == "MemberExpression" ) {
2018-03-03 22:05:33 +01:00
if ( ! exp . left . computed ) {
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Cannot assign to an object's property. This is currently unsupported in Netscript" , exp ) ) ;
}
2017-11-01 23:56:30 +01:00
//Assign to array element
//Array object designed by exp.left.object.name
//Index designated by exp.left.property
return getArrayElement ( exp . left , workerScript ) . then ( function ( res ) {
if ( ! ( res instanceof Array ) || res . length < 2 ) {
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Error evaluating array assignment. This is (probably) a bug please report to game dev" ) ) ;
}
2017-09-15 16:06:59 +02:00
2017-11-01 23:56:30 +01:00
//The array name is the second value
var arrName = res . splice ( 1 , 1 ) ;
arrName = arrName [ 0 ] ;
2017-09-15 16:06:59 +02:00
2018-03-03 22:05:33 +01:00
var res ;
try {
res = env . setArrayElement ( arrName , res , expRight ) ;
} catch ( e ) {
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , e ) ) ;
}
return Promise . resolve ( res ) ;
2017-11-01 23:56:30 +01:00
} ) . catch ( function ( e ) {
return Promise . reject ( e ) ;
} ) ;
} else {
//Other assignments
try {
2018-03-03 22:05:33 +01:00
var assign ;
2017-11-01 23:56:30 +01:00
switch ( exp . operator ) {
case "=" :
2018-03-03 22:05:33 +01:00
assign = expRight ; break ;
2017-11-01 23:56:30 +01:00
case "+=" :
2018-03-03 22:05:33 +01:00
assign = env . get ( exp . left . name ) + expRight ; break ;
2017-11-01 23:56:30 +01:00
case "-=" :
2018-03-03 22:05:33 +01:00
assign = env . get ( exp . left . name ) - expRight ; break ;
2017-11-01 23:56:30 +01:00
case "*=" :
2018-03-03 22:05:33 +01:00
assign = env . get ( exp . left . name ) * expRight ; break ;
2017-11-01 23:56:30 +01:00
case "/=" :
2018-03-03 22:05:33 +01:00
assign = env . get ( exp . left . name ) / expRight ; break ;
2017-11-01 23:56:30 +01:00
case "%=" :
2018-03-03 22:05:33 +01:00
assign = env . get ( exp . left . name ) % expRight ; break ;
2017-11-01 23:56:30 +01:00
default :
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Bitwise assignment is not implemented" ) ) ;
2017-06-28 11:47:42 +02:00
}
2018-03-03 22:05:33 +01:00
env . set ( exp . left . name , assign ) ;
return Promise . resolve ( assign ) ;
2017-11-01 23:56:30 +01:00
} catch ( e ) {
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Failed to set environment variable: " + e . toString ( ) ) ) ;
2017-06-28 11:47:42 +02:00
}
2017-11-01 23:56:30 +01:00
}
2017-06-28 11:47:42 +02:00
} ) ;
}
2018-06-22 21:39:15 +02:00
function evalVariableDeclaration ( exp , workerScript ) {
var env = workerScript . env ;
if ( env . stopFlag ) { return Promise . reject ( workerScript ) ; }
if ( ! ( exp . declarations instanceof Array ) ) {
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Variable declarations parsed incorrectly. This may be a syntax error" ) ) ;
}
if ( exp . kind !== "var" ) {
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Only 'var' declarations are currently allowed (let, const, etc. are not allowed)" ) ) ;
}
return Promise . all ( exp . declarations . map ( ( decl ) => {
evalVariableDeclarator ( decl , workerScript ) ;
} ) ) . then ( function ( res ) {
return Promise . resolve ( res ) ;
} ) ;
}
//A Variable Declaration contains an array of Variable Declarators
function evalVariableDeclarator ( exp , workerScript ) {
var env = workerScript . env ;
if ( exp . type !== "VariableDeclarator" ) {
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Invalid AST Node passed into evalVariableDeclarator: " + exp . type ) ) ;
}
if ( exp . init == null ) {
env . set ( exp . id . name , null ) ;
return Promise . resolve ( null ) ;
} else {
return evaluate ( exp . init , workerScript ) . then ( function ( initValue ) {
env . set ( exp . id . name , initValue ) ;
} ) ;
}
}
2017-06-28 11:47:42 +02:00
function evaluateIf ( exp , workerScript , i ) {
var env = workerScript . env ;
2017-11-01 23:56:30 +01:00
return evaluate ( exp . test , workerScript ) . then ( function ( condRes ) {
if ( condRes ) {
return evaluate ( exp . consequent , workerScript ) . then ( function ( res ) {
return Promise . resolve ( true ) ;
} , function ( e ) {
return Promise . reject ( e ) ;
} ) ;
} else if ( exp . alternate ) {
return evaluate ( exp . alternate , workerScript ) . then ( function ( res ) {
return Promise . resolve ( true ) ;
} , function ( e ) {
return Promise . reject ( e ) ;
} ) ;
} else {
return Promise . resolve ( "endIf" ) ;
}
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 ) {
2017-11-01 23:56:30 +01:00
var env = workerScript . env ;
if ( env . stopFlag ) { return Promise . reject ( workerScript ) ; }
2017-11-02 22:47:09 +01:00
return new Promise ( function ( resolve , reject ) {
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 ) {
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
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 ( recurse , reject ) . catch ( function ( e ) {
return Promise . reject ( e ) ;
} ) ;
} else {
resolve ( ) ;
}
} ) . catch ( function ( e ) {
reject ( e ) ;
} ) ;
}
recurse ( ) ;
} ) ;
2018-02-24 23:55:06 +01:00
}
function evaluateForeach ( arr , args , workerScript ) {
console . log ( "evaluateForeach called" ) ;
if ( ! ( arr instanceof Array ) ) {
return Promise . reject ( "Invalid array passed into forEach" ) ;
}
if ( ! ( args instanceof Array ) && args . length != 1 ) {
return Promise . reject ( "Invalid argument passed into forEach" ) ;
}
var func = args [ 0 ] ;
if ( typeof func !== "function" ) {
return Promise . reject ( "Invalid function passed into forEach" ) ;
}
console . log ( func ) ;
return new Promise ( function ( resolve , reject ) {
//Don't return a promise so the promise chain is broken on each recursion
function recurse ( i ) {
console . log ( "recurse() called with i: " + i ) ;
if ( i >= arr . length ) {
resolve ( ) ;
} else {
return Promise . delay ( Settings . CodeInstructionRunTime ) . then ( function ( ) {
console . log ( "About to apply function" ) ;
var res = func . apply ( null , [ arr [ i ] ] ) ;
console . log ( "Applied function" ) ;
++ i ;
Promise . resolve ( res ) . then ( function ( val ) {
recurse ( i ) ;
} , reject ) . catch ( function ( e ) {
return Promise . reject ( e ) ;
} ) ;
} ) ;
}
2017-11-01 23:56:30 +01:00
}
2018-02-24 23:55:06 +01:00
recurse ( 0 ) ;
} ) ;
2016-11-30 00:07:24 +01:00
}
function evaluateWhile ( exp , workerScript ) {
2017-11-01 23:56:30 +01:00
var env = workerScript . env ;
if ( env . stopFlag ) { return Promise . reject ( workerScript ) ; }
2017-11-02 22:47:09 +01:00
return new Promise ( function ( resolve , reject ) {
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 ) {
return evaluate ( exp . body , workerScript ) . catch ( function ( e ) {
if ( e == "CONTINUESTATEMENT" ||
( e instanceof WorkerScript && e . errorMessage == "CONTINUESTATEMENT" ) ) {
//Continue statement, recurse
return evaluateWhile ( exp , workerScript ) . then ( function ( foo ) {
return Promise . resolve ( "endWhileLoop" ) ;
} , function ( e ) {
return Promise . reject ( e ) ;
} ) ;
} else {
return Promise . reject ( e ) ;
}
} ) . then ( recurse , reject ) . catch ( function ( e ) {
2017-11-01 23:56:30 +01:00
return Promise . reject ( e ) ;
} ) ;
} else {
2017-11-02 22:47:09 +01:00
resolve ( ) ;
2017-11-01 23:56:30 +01:00
}
} ) . catch ( function ( e ) {
2017-11-02 22:47:09 +01:00
reject ( e ) ;
2017-11-01 23:56:30 +01:00
} ) ;
}
2017-11-02 22:47:09 +01:00
recurse ( ) ;
2017-11-01 23:56:30 +01:00
} ) ;
2016-11-30 00:07:24 +01:00
}
function evaluateProg ( exp , workerScript , index ) {
2017-11-01 23:56:30 +01:00
var env = workerScript . env ;
if ( env . stopFlag ) { return Promise . reject ( workerScript ) ; }
if ( index >= exp . body . length ) {
return Promise . resolve ( "progFinished" ) ;
} else {
//Evaluate this line of code in the prog
//After the code finishes evaluating, evaluate the next line recursively
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 ) ;
} ) ;
}
}
2018-03-03 22:05:33 +01:00
function evaluateImport ( exp , workerScript , checkingRam = false ) {
//When its checking RAM, it exports an array of nodes for each imported function
var ramCheckRes = [ ] ;
var env = workerScript . env ;
if ( env . stopFlag ) {
if ( checkingRam ) { return ramCheckRes ; }
return Promise . reject ( workerScript ) ;
}
//Get source script and name of all functions to import
var scriptName = exp . source . value ;
var namespace , namespaceObj , allFns = false , fnNames = [ ] ;
if ( exp . specifiers . length === 1 && exp . specifiers [ 0 ] . type === "ImportNamespaceSpecifier" ) {
allFns = true ;
namespace = exp . specifiers [ 0 ] . local . name ;
} else {
for ( var i = 0 ; i < exp . specifiers . length ; ++ i ) {
fnNames . push ( exp . specifiers [ i ] . local . name ) ;
}
}
//Get the code
var server = getServer ( workerScript . serverIp ) , code = "" ;
if ( server == null ) {
if ( checkingRam ) { return ramCheckRes ; }
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Failed to identify server. This is a bug please report to dev" , exp ) ) ;
}
for ( var i = 0 ; i < server . scripts . length ; ++ i ) {
if ( server . scripts [ i ] . filename === scriptName ) {
code = server . scripts [ i ] . code ;
break ;
2017-11-01 23:56:30 +01:00
}
}
2018-03-03 22:05:33 +01:00
if ( code === "" ) {
if ( checkingRam ) { return ramCheckRes ; }
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Could not find script " + scriptName + " to import" , exp ) ) ;
}
//Create the AST
try {
var ast = parse ( code , { sourceType : "module" } ) ;
} catch ( e ) {
console . log ( "Failed to parse import script" ) ;
if ( checkingRam ) { return ramCheckRes ; }
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Failed to import functions from " + scriptName +
" This is most likely due to a syntax error in the imported script" , exp ) ) ;
}
if ( allFns ) {
//A namespace is implemented as a JS obj
env . set ( namespace , { } ) ;
namespaceObj = env . get ( namespace ) ;
}
//Search through the AST for all imported functions
var queue = [ ast ] ;
while ( queue . length != 0 ) {
var node = queue . shift ( ) ;
switch ( node . type ) {
case "BlockStatement" :
case "Program" :
for ( var i = 0 ; i < node . body . length ; ++ i ) {
if ( node . body [ i ] instanceof Node ) {
queue . push ( node . body [ i ] ) ;
}
}
break ;
case "FunctionDeclaration" :
if ( node . id && node . id . name ) {
if ( allFns ) {
//Import all functions under this namespace
if ( checkingRam ) {
ramCheckRes . push ( node ) ;
} else {
namespaceObj [ node . id . name ] = node ;
}
} else {
//Only import specified functions
if ( fnNames . includes ( node . id . name ) ) {
if ( checkingRam ) {
ramCheckRes . push ( node ) ;
} else {
env . set ( node . id . name , node ) ;
}
}
}
} else {
if ( checkingRam ) { return ramCheckRes ; }
return Promise . reject ( makeRuntimeRejectMsg ( workerScript , "Invalid function declaration in imported script " + scriptName , exp ) ) ;
}
break ;
default :
break ;
}
for ( var prop in node ) {
if ( node . hasOwnProperty ( prop ) ) {
if ( node [ prop ] instanceof Node ) {
queue . push ( node [ prop ] ) ;
}
}
}
}
if ( ! checkingRam ) { workerScript . scriptRef . log ( "Imported functions from " + scriptName ) ; }
if ( checkingRam ) { return ramCheckRes ; }
return Promise . resolve ( true ) ;
}
function killNetscriptDelay ( workerScript ) {
2017-11-02 22:47:09 +01:00
if ( workerScript instanceof WorkerScript ) {
if ( workerScript . delay ) {
clearTimeout ( workerScript . delay ) ;
workerScript . delayResolve ( ) ;
}
}
2016-11-30 00:07:24 +01:00
}
2017-09-15 16:06:59 +02:00
function netscriptDelay ( time , workerScript ) {
2017-11-02 22:47:09 +01:00
return new Promise ( function ( resolve , reject ) {
workerScript . delay = setTimeout ( ( ) => {
workerScript . delay = null ;
resolve ( ) ;
} , time ) ;
workerScript . delayResolve = resolve ;
} ) ;
2017-06-05 06:48:37 +02:00
}
2018-03-03 22:05:33 +01:00
function makeRuntimeRejectMsg ( workerScript , msg , exp = null ) {
var lineNum = "" ;
if ( exp != null ) {
var num = getErrorLineNumber ( exp , workerScript ) ;
lineNum = " (Line " + num + ")"
2016-11-17 23:25:40 +01:00
}
2018-03-03 22:05:33 +01:00
return "|" + workerScript . serverIp + "|" + workerScript . name + "|" + msg + lineNum ;
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
2018-02-24 23:55:06 +01:00
//'null/undefined' arguments are not allowed
for ( var i = 0 ; i < args . length ; ++ i ) {
if ( args [ i ] == null ) {
workerScript . scriptRef . log ( "ERROR: Cannot execute a script with null/undefined as an argument" ) ;
return Promise . resolve ( false ) ;
}
}
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 ;
2017-09-13 16:22:22 +02:00
threads = Math . round ( Number ( threads ) ) ; //Convert to number and round
2018-07-03 05:35:12 +02:00
ramUsage = ramUsage * threads ;
2017-07-13 18:54:29 +02:00
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
2018-06-01 04:36:01 +02:00
if ( workerScript . disableLogs . ALL == null && workerScript . disableLogs . exec == null && workerScript . disableLogs . run == null && workerScript . disableLogs . spawn == null ) {
workerScript . scriptRef . log ( "Running script: " + scriptname + " on " + server . hostname + " with " + threads + " threads and args: " + printArray ( args ) + ". May take a few seconds to start up..." ) ;
}
2017-07-13 18:54:29 +02:00
var runningScriptObj = new RunningScript ( script , args ) ;
runningScriptObj . threads = threads ;
2017-11-01 23:56:30 +01:00
server . runningScripts . push ( runningScriptObj ) ; //Push onto runningScripts
2017-07-13 18:54:29 +02:00
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-09-05 03:03:29 +02:00
function getErrorLineNumber ( exp , workerScript ) {
var code = workerScript . scriptRef . scriptRef . code ;
//Split code up to the start of the node
2018-03-03 22:05:33 +01:00
try {
code = code . substring ( 0 , exp . start ) ;
return ( code . match ( /\n/g ) || [ ] ) . length + 1 ;
} catch ( e ) {
return - 1 ;
}
2017-09-05 03:03:29 +02: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 ) {
2017-11-01 23:56:30 +01:00
var difficultyMult = ( 100 - server . hackDifficulty ) / 100 ;
2017-09-15 16:06:59 +02:00
var skillMult = ( 1.75 * Player . hacking _skill ) + ( 0.2 * Player . intelligence ) ;
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 ) {
2017-11-01 23:56:30 +01:00
var difficultyMult = server . requiredHackingSkill * server . hackDifficulty ;
var skillFactor = ( 2.5 * difficultyMult + 500 ) / ( Player . hacking _skill + 50 + ( 0.1 * Player . intelligence ) ) ;
var hackingTime = 5 * skillFactor / Player . hacking _speed _mult ; //This is in seconds
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 ) {
2017-11-01 23:56:30 +01:00
var difficultyMult = ( 100 - server . hackDifficulty ) / 100 ;
2016-12-14 00:52:32 +01:00
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 ;
2017-11-01 23:56:30 +01:00
var skillFactor = ( 2.5 * difficultyMult + 500 ) / ( Player . hacking _skill + 50 + ( 0.1 * Player . intelligence ) ) ;
var growTime = 16 * skillFactor / Player . hacking _speed _mult ; //This is in seconds
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 ;
2017-11-01 23:56:30 +01:00
var skillFactor = ( 2.5 * difficultyMult + 500 ) / ( Player . hacking _skill + 50 + ( 0.1 * Player . intelligence ) ) ;
var weakenTime = 20 * skillFactor / Player . hacking _speed _mult ; //This is in seconds
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 ,
2018-03-03 22:05:33 +01:00
isScriptErrorMessage , killNetscriptDelay , evaluateImport } ;