diff --git a/README.md b/README.md
index 3ff79b42c..489b0163e 100644
--- a/README.md
+++ b/README.md
@@ -26,9 +26,9 @@ TESTING TODO:
Scripts tab that shows script stats
Seems to work, at least the basics (for online production)
-
-Tasks TODO:
Script offline progress
+
+Tasks TODO:
ctrl+C functionality for all running command like hack(), analyze(), and tail
Scroll all the way down when something is post()ed
Script logging functionality? Logs to internal "log file" (property of script itself)
diff --git a/index.html b/index.html
index d9708f22a..4d6d1e32b 100644
--- a/index.html
+++ b/index.html
@@ -66,6 +66,10 @@
+
+
+
+
Save Game
diff --git a/src/Netscript/Evaluator.js b/src/Netscript/Evaluator.js
index feb553b4e..228ff3f31 100644
--- a/src/Netscript/Evaluator.js
+++ b/src/Netscript/Evaluator.js
@@ -226,15 +226,18 @@ function evaluate(exp, workerScript) {
if (moneyGained <= 0) {moneyGained = 0;}
server.moneyAvailable -= moneyGained;
- Player.money += moneyGained;
+ Player.gainMoney(moneyGained);
workerScript.scriptRef.onlineMoneyMade += moneyGained;
Player.hacking_exp += expGainedOnSuccess;
+ workerScript.scriptRef.onlineExpGained += expGainedOnSuccess;
console.log("Script successfully hacked " + server.hostname + " for $" + moneyGained + " and " + expGainedOnSuccess + " exp");
resolve("Hack success");
} else {
//Player only gains 25% exp for failure? TODO Can change this later to balance
Player.hacking_exp += expGainedOnFailure;
+ workerScript.scriptRef.onlineExpGained += expGainedOnFailure;
+
console.log("Script unsuccessful to hack " + server.hostname + ". Gained " + expGainedOnFailure + "exp");
resolve("Hack failure");
}
diff --git a/src/Player.js b/src/Player.js
index d99f1b29e..18223bc19 100644
--- a/src/Player.js
+++ b/src/Player.js
@@ -69,6 +69,9 @@ function PlayerObject() {
//Flag to let the engine know the player is starting a hack
this.startAction = false;
this.actionTime = 0;
+
+ //Used to store the last update time.
+ this.lastUpdate = new Date().getTime();
};
PlayerObject.prototype.init = function() {
@@ -167,6 +170,12 @@ PlayerObject.prototype.analyze = function() {
this.startAction = true;
}
+PlayerObject.prototype.gainMoney = function(money) {
+ this.money += money;
+ this.total_money += money;
+ this.lifetime_money += money;
+}
+
//Functions for saving and loading the Player data
PlayerObject.prototype.toJSON = function() {
return Generic_toJSON("PlayerObject", this);
diff --git a/src/Script.js b/src/Script.js
index 6611fcf33..549419dba 100644
--- a/src/Script.js
+++ b/src/Script.js
@@ -71,24 +71,18 @@ function Script() {
/* Properties to calculate offline progress. Only applies for infinitely looping scripts */
- //Time it takes to execute one iteration of the entire script
- //Each function takes CONSTANTS.CodeInstructionRunTime seconds,
- //plus hacking time plus and sleep commands
- this.executionTimeMillis = 0;
-
//Number of instructions ("lines") in the code. Any call ending in a ;
- //is considered one instruction. Used to calculate executionTime
+ //is considered one instruction. Used to calculate ramUsage
this.numInstructions = 0;
-
- //Which servers are hacked in one iteration of the script. May contain duplicates
- this.serversHacked = [];
//Stats to display on the Scripts menu, and used to determine offline progress
this.offlineRunningTime = 0; //Seconds
this.offlineMoneyMade = 0;
+ this.offlineExpGained = 0;
this.onlineRunningTime = 0; //Seconds
this.onlineMoneyMade = 0;
- this.lastUpdate = 0;
+ this.onlineExpGained = 0;
+
};
//Get the script data from the Script Editor and save it to the object
@@ -107,8 +101,13 @@ Script.prototype.saveScript = function() {
//Calculate/update number of instructions, ram usage, execution time, etc.
this.updateNumInstructions();
this.updateRamUsage();
- this.updateExecutionTime();
+ //Clear the stats when the script is updated
+ this.offlineRunningTime = 0; //Seconds
+ this.offlineMoneyMade = 0;
+ this.onlineRunningTime = 0; //Seconds
+ this.onlineMoneyMade = 0;
+ this.lastUpdate = 0;
}
}
@@ -126,61 +125,6 @@ Script.prototype.updateRamUsage = function() {
this.ramUsage = this.numInstructions * .2;
}
-//Calculate the execution time of the script. This is used to calculate how much a script
-//generates when the user is offline
-//This is calculated based on the number of instructions and any calls to hack().
-//Every instruction takes a flat time of X seconds (defined in Constants.js)
-//Every hack instructions takes an ADDITIONAl time of however long it takes to hack that server
-Script.prototype.updateExecutionTime = function() {
- //TODO Maybe do this based on the average production/s of the script( which I'm adding in
- //as a property)
- /*
- var executionTime = 0;
-
- //Ever instruction takes CONSTANTS.CodeOfflineExecutionTime seconds
- console.log("numInstructions: " + this.numInstructions.toString());
- executionTime += (this.numInstrutions * CONSTANTS.CodeOfflineExecutionTime);
- console.log("ExecutionTime after taking into account instructions: " + executionTime.toString());
-
- //Search the code's text for every occurrence of hack()
- hackIndices = getIndicesOf('hack("', this.code, true);
- for (var i = 0; i < hackIndices.length; ++i) {
- //Get the full hack() call substring
- var startIndex = hackIndices[i];
- console.log("startIndex: " + startIndex.toString());
- var endIndex = startIndex;
-
- while (this.code.substr(endIndex, 2) != ");") {
- console.log("endIndex: " + endIndex.toString());
- ++endIndex;
- if (endIndex == this.code.length - 1) {
- //Bad code...
- console.log("Could not find ending to hack call");
- return;
- }
- }
- ++endIndex; // This puts endIndex at the semicolon
-
- var hackCall = this.code.substring(startIndex, endIndex);
- console.log("hackCall: " + hackCall);
- var argument = hackCall.match(/"([^']+)"/)[1]; //Extract the argument, which must be btw 2 quotes
-
- //Check if its an ip or a hostname. Then get the server and calculate hack time accordingly
- var server = null;
- if (isValidIPAddress(argument)) {
- server = AllServers[argument];
- } else {
- server = GetServerByHostname(argument);
- }
- console.log("Server hostname: " + server.hostname);
- executionTime += scriptCalculateHackingTime(server);
- }
-
- this.executionTimeMillis = executionTime * 1000;
- console.log("Script calculated to have an offline execution time of " + executionTime.toString() + "seconds");
- */
-}
-
Script.prototype.toJSON = function() {
return Generic_toJSON("Script", this);
}
@@ -209,8 +153,53 @@ loadAllRunningScripts = function() {
var script = server.getScript(server.runningScripts[j]);
if (script == null) {continue;}
addWorkerScript(script, server);
+
+ //Offline production
+ scriptCalculateOfflineProduction(script);
}
}
}
console.log("Loaded " + count.toString() + " running scripts");
+}
+
+scriptCalculateOfflineProduction = function(script) {
+ //The Player object stores the last update time from when we were online
+ var thisUpdate = new Date().getTime();
+ var lastUpdate = Player.lastUpdate;
+ var timePassed = (thisUpdate - lastUpdate) / 1000; //Seconds
+ console.log("Offline for " + timePassed.toString() + " seconds");
+
+ //Calculate the "confidence" rating of the script's true production. This is based
+ //entirely off of time. We will arbitrarily say that if a script has been running for
+ //120 minutes (7200 sec) then we are completely confident in its ability
+ var confidence = (script.onlineRunningTime) / 7200;
+ if (confidence >= 1) {confidence = 1;}
+ console.log("onlineRunningTime: " + script.onlineRunningTime.toString());
+ console.log("Confidence: " + confidence.toString());
+
+ //A script's offline production will always be at most half of its online production.
+ var production = (1/2) * (script.onlineMoneyMade / script.onlineRunningTime) * timePassed;
+ production *= confidence;
+
+ var expGain = (1/2) * (script.onlineExpGained / script.onlineRunningTime) * timePassed;
+ expGain *= confidence;
+
+ //Account for production in Player and server
+ Player.gainMoney(production);
+ Player.hacking_exp += expGain;
+
+ var server = AllServers[script.server];
+ server.moneyAvailable -= production;
+ if (server.moneyAvailable < 0) {server.moneyAvailable = 0;}
+
+ //Update script stats
+ script.offlineMoneyMade += production;
+ script.offlineRunningTime += timePassed;
+ script.offlineExpGained += expGain;
+
+ //TODO EXP
+
+ //DEBUG
+ var serverName = AllServers[script.server].hostname;
+ console.log(script.filename + " from server " + serverName + " generated $" + production.toString() + " while offline");
}
\ No newline at end of file
diff --git a/src/Terminal.js b/src/Terminal.js
index 19f3c8077..5b41a2409 100644
--- a/src/Terminal.js
+++ b/src/Terminal.js
@@ -16,7 +16,7 @@ var hackProgressPost = function(input) {
}
var postNetburnerText = function() {
- post("Netburner v1.0");
+ post("Netburner v0.1");
}
//Defines what happens when enter is pressed (keycode 13)
@@ -37,14 +37,29 @@ $(document).keyup(function(event) {
});
//Keep terminal in focus
+terminalCtrlPressed = false;
$(document).ready(function() {
if (Engine.currentPage == Engine.Page.Terminal) {
$('.terminal-input').focus();
}
});
-$(document).keydown(function() {
+$(document).keydown(function(e) {
if (Engine.currentPage == Engine.Page.Terminal) {
- $('.terminal-input').focus();
+ if (e.which == 17) {
+ terminalCtrlPressed = true;
+ } else if (terminalCtrlPressed == true) {
+ //Don't focus
+ } else {
+ $('.terminal-input').focus();
+ terminalCtrlPressed = false;
+ }
+ }
+})
+$(document).keyup(function(e) {
+ if (Engine.currentPage == Engine.Page.Terminal) {
+ if (e.which == 17) {
+ terminalCtrlPressed = false;
+ }
}
})
@@ -79,7 +94,7 @@ var Terminal = {
if (moneyGained <= 0) {moneyGained = 0;}
Player.getCurrentServer().moneyAvailable -= moneyGained;
- Player.money += moneyGained;
+ Player.gainMoney(moneyGained);
Player.hacking_exp += expGainedOnSuccess;
diff --git a/src/engine.js b/src/engine.js
index 89340eb09..d82d2e357 100644
--- a/src/engine.js
+++ b/src/engine.js
@@ -154,7 +154,7 @@ var Engine = {
/* Display character info */
displayCharacterInfo: function() {
- Engine.Display.characterInfo.innerHTML = 'Money: $' + Player.money + '
' +
+ Engine.Display.characterInfo.innerHTML = 'Money: $' + Player.money.toFixed(2) + '
' +
'Hacking Level: ' + Player.hacking_skill + '
' +
'Strength: ' + Player.strength + '
' +
'Defense: ' + Player.defense + '
' +
@@ -162,7 +162,7 @@ var Engine = {
'Agility: ' + Player.agility + '
' +
'Charisma: ' + Player.charisma + '
' +
'Servers owned: ' + Player.purchasedServers.length + '
' +
- 'Hacking Experience: ' + Player.hacking_exp + '
';
+ 'Hacking Experience: ' + Player.hacking_exp.toFixed(4) + '
';
},
/* Functions used to update information on the Active Scripts page */
@@ -170,7 +170,6 @@ var Engine = {
//Creates and adds the object for a given workerScript
addActiveScriptsItem: function(workerscript) {
- console.log("addActiveScriptsItem called");
var item = document.createElement("li");
Engine.createActiveScriptsText(workerscript, item);
@@ -217,17 +216,22 @@ var Engine = {
//Server ip/hostname
var hostname = workerscript.getServer().hostname;
- var serverIpHostname = "Server: " + hostname + "(" + workerscript.serverIp + ")";
+ var serverIpHostname = "Server: " + hostname + " (" + workerscript.serverIp + ")";
- //Online money/s
+ //Online
var onlineMps = workerscript.scriptRef.onlineMoneyMade / workerscript.scriptRef.onlineRunningTime;
var onlineMpsText = "Online production: $" + onlineMps.toFixed(2) + "/second";
+ var onlineEps = workerscript.scriptRef.onlineExpGained / workerscript.scriptRef.onlineRunningTime;
+ var onlineEpsText = (Array(20).join(" ") + onlineEps.toFixed(4) + " exp/second").replace( / /g, " ");
- //Offline money/s
+ //Offline
var offlineMps = workerscript.scriptRef.offlineMoneyMade / workerscript.scriptRef.offlineRunningTime;
var offlineMpsText = "Offline production: $" + offlineMps.toFixed(2) + "/second";
+ var offlineEps = workerscript.scriptRef.offlineExpGained / workerscript.scriptRef.offlineRunningTime;
+ var offlineEpsText = (Array(21).join(" ") + offlineEps.toFixed(4) + " exp/second").replace( / /g, " ");
- itemText.innerHTML = serverIpHostname + "
" + onlineMpsText + "
" + offlineMpsText + "
";
+ itemText.innerHTML = serverIpHostname + "
" + onlineMpsText + "
" + onlineEpsText + "
" +
+ offlineMpsText + "
" + offlineEpsText + "
";
item.appendChild(itemText);
},
@@ -246,6 +250,7 @@ var Engine = {
//Update the game engine by the calculated number of cycles
Engine.updateGame(diff);
Engine._lastUpdate = _thisUpdate - offset;
+ Player.lastUpdate = _thisUpdate - offset;
}
window.requestAnimationFrame(Engine.idleTimer);
@@ -272,8 +277,6 @@ var Engine = {
//Update the running time of all active scripts
updateOnlineScriptTimes(numCycles);
-
-
},
//Counters for the main event loop. Represent the number of game cycles are required
@@ -360,7 +363,7 @@ var Engine = {
if (Engine.loadSave()) {
console.log("Loaded game from save");
CompanyPositions.init();
- loadAllRunningScripts();
+ loadAllRunningScripts(); //This also takes care of offline production
} else {
//No save found, start new game
console.log("Initializing new game");
@@ -397,9 +400,6 @@ var Engine = {
//Active scripts list
Engine.ActiveScriptsList = document.getElementById("active-scripts-list");
-
-
-
Engine.Clickables.saveMainMenuButton = document.getElementById("save-game-link");
Engine.Clickables.saveMainMenuButton.addEventListener("click", function() {
Engine.saveGame();