Merge pull request #64 from danielyxie/dev

Dev v0.21.0
This commit is contained in:
danielyxie 2017-06-16 22:40:20 -05:00 committed by GitHub
commit 9581798bcf
23 changed files with 967 additions and 687 deletions

@ -26,7 +26,7 @@
height: 100%; height: 100%;
margin-left: 10%; margin-left: 10%;
width: 99%; width: 99%;
color: #66ff33; color: var(--my-font-color);
overflow-y: scroll; overflow-y: scroll;
} }
@ -62,7 +62,7 @@
margin-right: 0px; margin-right: 0px;
padding-left: 6px; padding-left: 6px;
width: 100%; width: 100%;
border: 2px solid white; border: 2px solid var(--my-highlight-color);
} }
#script-editor-filename-tag { #script-editor-filename-tag {
@ -71,6 +71,7 @@
padding-bottom: 0px; padding-bottom: 0px;
float:center; float:center;
background-color: #555; background-color: #555;
color: white;
} }
#script-editor-filename { #script-editor-filename {
@ -83,7 +84,7 @@ background-color: #555;
padding: 2px; padding: 2px;
border: 2px solid white; border: 2px solid var(--my-highlight-color);
-webkit-box-shadow: -webkit-box-shadow:
inset 0 0 8px rgba(0,0,0,0.1), inset 0 0 8px rgba(0,0,0,0.1),
0 0 16px rgba(0,0,0,0.1); 0 0 16px rgba(0,0,0,0.1);
@ -101,7 +102,7 @@ background-color: #555;
} }
#script-editor-text { #script-editor-text {
color: #66ff33; color: var(--my-font-color);
height: 80%; height: 80%;
width: 100%; width: 100%;
margin-left: 6px; margin-left: 6px;
@ -110,7 +111,7 @@ background-color: #555;
padding-top: 6px; padding-top: 6px;
padding-bottom: 6px; padding-bottom: 6px;
border: 2px solid white; border: 2px solid var(--my-highlight-color);
-webkit-box-shadow: -webkit-box-shadow:
inset 0 0 8px rgba(0,0,0,0.1), inset 0 0 8px rgba(0,0,0,0.1),
0 0 16px rgba(0,0,0,0.1); 0 0 16px rgba(0,0,0,0.1);
@ -198,7 +199,7 @@ background-color: #555;
.active-scripts-script-header { .active-scripts-script-header {
background-color: #555; background-color: #555;
color: #66ff33; color: var(--my-font-color);
padding: 4px; padding: 4px;
padding-left: 10px; padding-left: 10px;
cursor: pointer; cursor: pointer;
@ -220,7 +221,7 @@ background-color: #555;
.active-scripts-script-header:after { .active-scripts-script-header:after {
content: '\02795'; /* "plus" sign (+) */ content: '\02795'; /* "plus" sign (+) */
font-size: 13px; font-size: 13px;
color: #66ff33; color: var(--my-font-color);
float: right; float: right;
margin-left: 5px; margin-left: 5px;
} }
@ -228,7 +229,7 @@ background-color: #555;
.active-scripts-script-header.active:after { .active-scripts-script-header.active:after {
content: "\2796"; /* "minus" sign (-) */ content: "\2796"; /* "minus" sign (-) */
font-size: 13px; font-size: 13px;
color: #66ff33; color: var(--my-font-color);
float: right; float: right;
margin-left: 5px; margin-left: 5px;
} }
@ -291,7 +292,7 @@ background-color: #555;
margin: 6px; margin: 6px;
padding: 6px; padding: 6px;
width: 85%; width: 85%;
border: 2px solid white; border: 2px solid var(--my-highlight-color);
-webkit-box-shadow: -webkit-box-shadow:
inset 0 0 8px rgba(0,0,0,0.1), inset 0 0 8px rgba(0,0,0,0.1),
0 0 16px rgba(0,0,0,0.1); 0 0 16px rgba(0,0,0,0.1);
@ -375,7 +376,7 @@ background-color: #555;
height: 100%; height: 100%;
margin-left: 10%; margin-left: 10%;
width: 99%; width: 99%;
color: #66ff33; color: var(--my-font-color);
overflow-y: auto; overflow-y: auto;
} }
@ -425,7 +426,7 @@ background-color: #555;
padding: 6px; padding: 6px;
margin: 6px; margin: 6px;
display: inline-block; display: inline-block;
color: #66ff33; color: var(--my-font-color);
} }
#faction-donate-amount-txt { #faction-donate-amount-txt {
@ -450,7 +451,7 @@ div.faction-clear {
height: 100%; height: 100%;
margin-left: 10%; margin-left: 10%;
width: 99%; width: 99%;
color: #66ff33; color: var(--my-font-color);
} }
#faction-augmentations-container p, #faction-augmentations-container p,
@ -480,7 +481,7 @@ div.faction-clear {
height: 100%; height: 100%;
margin-left: 10%; margin-left: 10%;
width: 99%; width: 99%;
color: #66ff33; color: var(--my-font-color);
overflow-y: scroll; overflow-y: scroll;
} }
@ -492,7 +493,7 @@ div.faction-clear {
#augmentations-list h2, #augmentations-list h2,
#augmentations-list p { #augmentations-list p {
margin: 4px; margin: 4px;
color: #66ff33; color: var(--my-font-color);
padding: 8px; padding: 8px;
width: 70%; width: 70%;
background-color: #333; background-color: #333;
@ -522,7 +523,7 @@ div.faction-clear {
/* Location */ /* Location */
#location-container { #location-container {
color: #66ff33; color: var(--my-font-color);
position: fixed; position: fixed;
padding: 6px; padding: 6px;
height: 100%; height: 100%;

@ -8,11 +8,13 @@
width: 100%; /* Full width */ width: 100%; /* Full width */
height: 100%; /* Full height */ height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */ overflow: auto; /* Enable scroll if needed */
background-color: black; /* Fallback color */ /*background-color: black; /* Fallback color */
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ /*background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
background-color: rbga(var(--my-background-color), 0.4);
} }
.dialog-box-container { .dialog-box-container,
#log-box-container {
display: block; display: block;
position: absolute; position: absolute;
z-index: 2; z-index: 2;
@ -23,18 +25,19 @@
left: 50%; left: 50%;
margin: -10% 0 0 -25%; margin: -10% 0 0 -25%;
overflow: auto; overflow: auto;
background-color: black; background-color: var(--my-background-color);
background-color: rgba(0,0,0,0.4); border: 5px solid var(--my-highlight-color);
border: 5px solid #FFFFFF;
} }
.dialog-box-content { .dialog-box-content,
#log-box-content {
z-index: 2; z-index: 2;
background-color: black; background-color: var(--my-background-color);
padding: 10px; padding: 10px;
} }
.dialog-box-close-button { .dialog-box-close-button,
#log-box-close {
color: #aaa; color: #aaa;
float: right; float: right;
font-size: 20px; font-size: 20px;
@ -48,7 +51,9 @@
} }
.dialog-box-close-button:hover, .dialog-box-close-button:hover,
.dialog-box-close-button:focus { .dialog-box-close-button:focus,
#log-box-close:hover,
#log-box-close:focus {
color: white; color: white;
text-decoration: none; text-decoration: none;
cursor: pointer; cursor: pointer;
@ -60,12 +65,12 @@
} }
#purchase-server-box-content { #purchase-server-box-content {
background-color: black; background-color: var(--my-background-color);
margin: 15% auto; /* 15% from the top and centered */ margin: 15% auto; /* 15% from the top and centered */
padding: 12px; padding: 12px;
border: 5px solid #FFFFFF; border: 5px solid var(--my-highlight-color);;
width: 80%; /* Could be more or less, depending on screen size */ width: 80%; /* Could be more or less, depending on screen size */
color: #66ff33; color: var(--my-font-color);
} }
#purchase-server-box-input { #purchase-server-box-input {
@ -85,14 +90,14 @@
#purchase-server-box-confirm:hover, #purchase-server-box-confirm:hover,
#purchase-server-box-confirm:focus { #purchase-server-box-confirm:focus {
color: #66ff33; color: var(--my-font-color);
text-decoration: none; text-decoration: none;
cursor: pointer; cursor: pointer;
} }
#purchase-server-box-cancel:hover, #purchase-server-box-cancel:hover,
#purchase-server-box-cancel:focus { #purchase-server-box-cancel:focus {
color: #66ff33; color: var(--my-font-color);
text-decoration: none; text-decoration: none;
cursor: pointer; cursor: pointer;
} }
@ -103,12 +108,12 @@
} }
#purchase-ram-for-home-box-content { #purchase-ram-for-home-box-content {
background-color: black; background-color: var(--my-background-color);
margin: 15% auto; /* 15% from the top and centered */ margin: 15% auto; /* 15% from the top and centered */
padding: 12px; padding: 12px;
border: 5px solid #FFFFFF; border: 5px solid var(--my-highlight-color);
width: 50%; /* Could be more or less, depending on screen size */ width: 50%; /* Could be more or less, depending on screen size */
color: #66ff33; color: var(--my-font-color);
} }
#purchase-ram-for-home-box-confirm, #purchase-ram-for-home-box-confirm,
@ -124,14 +129,14 @@
#purchase-ram-for-home-box-confirm:hover, #purchase-ram-for-home-box-confirm:hover,
#purchase-ram-for-home-box-confirm:focus { #purchase-ram-for-home-box-confirm:focus {
color: #66ff33; color: var(--my-font-color);
text-decoration: none; text-decoration: none;
cursor: pointer; cursor: pointer;
} }
#purchase-ram-for-home-box-cancel:hover, #purchase-ram-for-home-box-cancel:hover,
#purchase-ram-for-home-box-cancel:focus { #purchase-ram-for-home-box-cancel:focus {
color: #66ff33; color: var(--my-font-color);
text-decoration: none; text-decoration: none;
cursor: pointer; cursor: pointer;
} }
@ -142,12 +147,12 @@
} }
#purchase-augmentation-box-content { #purchase-augmentation-box-content {
background-color: black; background-color: var(--my-background-color);
margin: 15% auto; /* 15% from the top and centered */ margin: 15% auto; /* 15% from the top and centered */
padding: 8px; padding: 8px;
border: 5px solid #FFFFFF; border: 5px solid var(--my-highlight-color);;
width: 80%; /* Could be more or less, depending on screen size */ width: 80%; /* Could be more or less, depending on screen size */
color: #66ff33; color: var(--my-font-color);
} }
#purchase-augmentation-box-confirm, #purchase-augmentation-box-confirm,
@ -163,14 +168,14 @@
#purchase-augmentation-box-confirm:hover, #purchase-augmentation-box-confirm:hover,
#purchase-augmentation-box-confirm:focus { #purchase-augmentation-box-confirm:focus {
color: #66ff33; color: var(--my-font-color);
text-decoration: none; text-decoration: none;
cursor: pointer; cursor: pointer;
} }
#purchase-augmentation-box-cancel:hover, #purchase-augmentation-box-cancel:hover,
#purchase-augmentation-box-cancel:focus { #purchase-augmentation-box-cancel:focus {
color: #66ff33; color: var(--my-font-color);
text-decoration: none; text-decoration: none;
cursor: pointer; cursor: pointer;
} }
@ -181,12 +186,12 @@
} }
#faction-invitation-box-content { #faction-invitation-box-content {
background-color: black; background-color: var(--my-background-color);
margin: 15% auto; /* 15% from the top and centered */ margin: 15% auto; /* 15% from the top and centered */
padding: 10px; padding: 10px;
border: 5px solid #FFFFFF; border: 5px solid var(--my-highlight-color);;
width: 80%; /* Could be more or less, depending on screen size */ width: 80%; /* Could be more or less, depending on screen size */
color: #66ff33; color: var(--my-font-color);
} }
#faction-invitation-box-warning { #faction-invitation-box-warning {
@ -225,12 +230,12 @@
} }
#travel-box-content { #travel-box-content {
background-color: black; background-color: var(--my-background-color);
margin: 15% auto; /* 15% from the top and centered */ margin: 15% auto; /* 15% from the top and centered */
padding: 10px; padding: 10px;
border: 5px solid #FFFFFF; border: 5px solid var(--my-highlight-color);;
width: 50%; /* Could be more or less, depending on screen size */ width: 50%; /* Could be more or less, depending on screen size */
color: #66ff33; color: var(--my-font-color);
} }
#travel-box-text { #travel-box-text {
@ -268,12 +273,12 @@
} }
#game-options-content { #game-options-content {
background-color: black; background-color: var(--my-background-color);
margin: 15% auto; /* 15% from the top and centered */ margin: 15% auto; /* 15% from the top and centered */
padding: 10px; padding: 10px;
border: 5px solid #FFFFFF; border: 5px solid var(--my-highlight-color);
width: 50%; /* Could be more or less, depending on screen size */ width: 50%; /* Could be more or less, depending on screen size */
color: #66ff33; color: var(--my-font-color);
} }
#game-options-close-button { #game-options-close-button {
@ -301,3 +306,4 @@
#import-game-file-selector { #import-game-file-selector {
display:none; display:none;
} }

@ -1,25 +1,34 @@
/** This removes all padding and margins as well as /** This removes all padding and margins as well as
setting a default font size and family for the page **/ setting a default font size and family for the page **/
:root{
--my-font-color: #66ff33;
--my-background-color: #000000;
--my-highlight-color: #ffffff;
}
* { * {
margin: 0; margin: 0;
padding: 0; padding: 0;
font-size: 16px; font-size: 16px;
font-family: 'Lucida Console', 'Lucida Sans Unicode', 'Fira Mono', 'Consolas', 'Courier New', Courier, monospace, 'Times New Roman'; font-family: 'Lucida Console', 'Lucida Sans Unicode', 'Fira Mono', 'Consolas', 'Courier New', Courier, monospace, 'Times New Roman';
background-color: #252527; /*background-color: #252527;*/
background-color: black; background-color: var(--my-background-color);
} }
p { p {
color: #66ff33; color: var(--my-font-color);
} }
h1 { h1 {
font-size: 22px; font-size: 22px;
color: #66ff33; color: var(--my-font-color);
} }
h2 { h2 {
color: #66ff33; color: var(--my-font-color);
} }
ul { ul {
@ -151,8 +160,8 @@ tr:focus {
.tooltip .tooltiptext { .tooltip .tooltiptext {
visibility: hidden; visibility: hidden;
width: 300px; width: 300px;
background-color: black; background-color: var(--my-background-color);
border: 2px solid white; border: 2px solid var(--my-highlight-color);;
color: white; color: white;
text-align: center; text-align: center;
padding: 4px; padding: 4px;
@ -228,6 +237,7 @@ tr:focus {
right: 0; right: 0;
bottom: 0; bottom: 0;
padding: 4px; padding: 4px;
margin-right: 14px;
background-color: transparent; background-color: transparent;
z-index: 2; z-index: 2;
} }
@ -241,10 +251,10 @@ tr:focus {
position: absolute; /* Stay in place */ position: absolute; /* Stay in place */
right: 0; right: 0;
top: 0; top: 0;
height: 175px; /* Full height */ height: 185px; /* Full height */
/*margin: 50% auto;*/ /*margin: 50% auto;*/
padding: 5px; padding: 5px;
border: 2px solid #66ff33; border: 2px solid var(--my-highlight-color);
width: 18%; width: 18%;
overflow: auto; /* Enable scroll if needed */ overflow: auto; /* Enable scroll if needed */
background-color: #444; /* Fallback color */ background-color: #444; /* Fallback color */
@ -253,12 +263,13 @@ tr:focus {
#character-overview-text { #character-overview-text {
padding: 4px; padding: 4px;
margin: 12px; margin: 10px;
color: white; color: white;
background-color: #444; background-color: #444;
} }
#character-overview-save-button { #character-overview-save-button,
#character-overview-options-button {
color: #aaa; color: #aaa;
font-size: 16px; font-size: 16px;
font-weight: bold; font-weight: bold;
@ -271,8 +282,14 @@ tr:focus {
} }
#character-overview-save-button:hover, #character-overview-save-button:hover,
#character-overview-save-button:focus { #character-overview-save-button:focus,
#character-overview-options-button:hover,
#character-overview-options-button:focus {
color: white; color: white;
text-decoration: none; text-decoration: none;
cursor: pointer; cursor: pointer;
} }
#character-overview-options-button {
display: inline-block;
}

@ -15,11 +15,12 @@
font-size: 16px; font-size: 16px;
overflow: auto; overflow: auto;
overflow-y: scroll; overflow-y: scroll;
background-color: var(--my-background-color);
} }
#terminal-input { #terminal-input {
background-color: black; background-color: var(--my-background-color);
color: #66ff33; color: var(--my-font-color);
transition: height 1s; transition: height 1s;
} }
@ -29,10 +30,10 @@
padding: 0px !important; padding: 0px !important;
margin: 0px !important; margin: 0px !important;
border: 0px; border: 0px;
background-color: black; background-color: var(--my-background-color);
font-size: 16px; font-size: 16px;
outline: none; outline: none;
color: #66ff33; color: var(--my-font-color);
} }

@ -1,5 +1,5 @@
#work-in-progress-container { #work-in-progress-container {
color: #66ff33; color: var(--my-font-color);
position: fixed; position: fixed;
padding-top: 10px; padding-top: 10px;
padding-left: 10px; padding-left: 10px;
@ -8,7 +8,7 @@
} }
#work-in-progress-text { #work-in-progress-text {
color: #66ff33; color: var(--my-font-color);
width: 70%; width: 70%;
} }

@ -25,6 +25,7 @@
<script src="utils/TravelBox.js"></script> <script src="utils/TravelBox.js"></script>
<script src="utils/PurchaseRamForHomeBox.js"></script> <script src="utils/PurchaseRamForHomeBox.js"></script>
<script src="utils/GameOptions.js"></script> <script src="utils/GameOptions.js"></script>
<script src="utils/LogBox.js"></script>
<!-- Netscript --> <!-- Netscript -->
<script src="src/NetscriptWorker.js"></script> <script src="src/NetscriptWorker.js"></script>
@ -645,6 +646,14 @@
<a id="location-slums-heist" class="a-link-button tooltip"> Heist </a> <a id="location-slums-heist" class="a-link-button tooltip"> Heist </a>
</div> </div>
<!-- Log Box -->
<div id="log-box-container">
<div id="log-box-content">
<span id="log-box-close"> &times; </span>
<p id="log-box-text"> </p>
</div>
</div>
<!-- Purchase Server Pop-up Box --> <!-- Purchase Server Pop-up Box -->
<div id="purchase-server-box-container" class="popup-box-container"> <div id="purchase-server-box-container" class="popup-box-container">
<div id="purchase-server-box-content"> <div id="purchase-server-box-content">
@ -732,6 +741,7 @@
<div id="character-overview-container"> <div id="character-overview-container">
<p id="character-overview-text"> </p> <p id="character-overview-text"> </p>
<span id="character-overview-save-button"> Save Game </span> <span id="character-overview-save-button"> Save Game </span>
<span id="character-overview-options-button"> Options </span>
</div> </div>
</div> </div>

@ -117,7 +117,12 @@ function addActiveScriptsItem(workerscript) {
} }
//Create the element itself. Each element is an accordion collapsible //Create the element itself. Each element is an accordion collapsible
var itemName = "active-scripts-" + server.hostname + "-" + workerscript.name; var itemNameArray = ["active", "scripts", server.hostname, workerscript.name];
for (var i = 0; i < workerscript.args.length; ++i) {
itemNameArray.push(workerscript.args[i].toString());
}
var itemName = itemNameArray.join("-");
//var itemName = "active-scripts-" + server.hostname + "-" + workerscript.name;
var item = document.createElement("li"); var item = document.createElement("li");
item.setAttribute("id", itemName); item.setAttribute("id", itemName);
@ -147,7 +152,12 @@ function deleteActiveScriptsItem(workerscript) {
console.log("ERROR: Invalid server IP for workerscript."); console.log("ERROR: Invalid server IP for workerscript.");
return; return;
} }
var itemName = "active-scripts-" + server.hostname + "-" + workerscript.name; var itemNameArray = ["active", "scripts", server.hostname, workerscript.name];
for (var i = 0; i < workerscript.args.length; ++i) {
itemNameArray.push(workerscript.args[i].toString());
}
var itemName = itemNameArray.join("-");
//var itemName = "active-scripts-" + server.hostname + "-" + workerscript.name;
var li = document.getElementById(itemName); var li = document.getElementById(itemName);
if (li == null) { if (li == null) {
console.log("could not find Active scripts li element for: " + workerscript.name); console.log("could not find Active scripts li element for: " + workerscript.name);
@ -174,7 +184,12 @@ function updateActiveScriptsItemContent(workerscript) {
console.log("ERROR: Invalid server IP for workerscript."); console.log("ERROR: Invalid server IP for workerscript.");
return; return;
} }
var itemName = "active-scripts-" + server.hostname + "-" + workerscript.name; var itemNameArray = ["active", "scripts", server.hostname, workerscript.name];
for (var i = 0; i < workerscript.args.length; ++i) {
itemNameArray.push(workerscript.args[i].toString());
}
var itemName = itemNameArray.join("-");
//var itemName = "active-scripts-" + server.hostname + "-" + workerscript.name;
var itemContent = document.getElementById(itemName + "-content") var itemContent = document.getElementById(itemName + "-content")
//Clear the item //Clear the item
@ -190,7 +205,8 @@ function createActiveScriptsText(workerscript, item) {
var itemText = document.createElement("p"); var itemText = document.createElement("p");
//Server ip/hostname //Server ip/hostname
var serverIpHostname = "Threads: " + workerscript.scriptRef.threads; var threads = "Threads: " + workerscript.scriptRef.threads;
var args = "Args: " + printArray(workerscript.args);
//Online //Online
var onlineTotalMoneyMade = "Total online production: $" + formatNumber(workerscript.scriptRef.onlineMoneyMade, 2); var onlineTotalMoneyMade = "Total online production: $" + formatNumber(workerscript.scriptRef.onlineMoneyMade, 2);
@ -210,7 +226,7 @@ function createActiveScriptsText(workerscript, item) {
var offlineEps = workerscript.scriptRef.offlineExpGained / workerscript.scriptRef.offlineRunningTime; var offlineEps = workerscript.scriptRef.offlineExpGained / workerscript.scriptRef.offlineRunningTime;
var offlineEpsText = (Array(26).join(" ") + formatNumber(offlineEps, 4) + " hacking exp/second").replace( / /g, "&nbsp;"); var offlineEpsText = (Array(26).join(" ") + formatNumber(offlineEps, 4) + " hacking exp/second").replace( / /g, "&nbsp;");
itemText.innerHTML = serverIpHostname + "<br>" + onlineTotalMoneyMade + "<br>" + onlineTotalExpEarned + "<br>" + itemText.innerHTML = threads + "<br>" + args + "<br>" + onlineTotalMoneyMade + "<br>" + onlineTotalExpEarned + "<br>" +
onlineMpsText + "<br>" + onlineEpsText + "<br>" + offlineTotalMoneyMade + "<br>" + offlineTotalExpEarned + "<br>" + onlineMpsText + "<br>" + onlineEpsText + "<br>" + offlineTotalMoneyMade + "<br>" + offlineTotalExpEarned + "<br>" +
offlineMpsText + "<br>" + offlineEpsText + "<br>"; offlineMpsText + "<br>" + offlineEpsText + "<br>";

@ -1411,7 +1411,7 @@ initAugmentations = function() {
"<br><br>This augmentation: <br>" + "<br><br>This augmentation: <br>" +
"Increases the player's strength and defense by 20%<br>" + "Increases the player's strength and defense by 20%<br>" +
"Increases the player's crime success rate by 10%<br>" + "Increases the player's crime success rate by 10%<br>" +
"Increases thea mount of money the player gains from crimes by 10%"); "Increases the amount of money the player gains from crimes by 10%");
BrachiBlades.setRequirements(5000, 18000000); BrachiBlades.setRequirements(5000, 18000000);
BrachiBlades.addToFactions(["The Syndicate"]); BrachiBlades.addToFactions(["The Syndicate"]);
if (augmentationExists(AugmentationNames.BrachiBlades)) { if (augmentationExists(AugmentationNames.BrachiBlades)) {

@ -1,5 +1,5 @@
CONSTANTS = { CONSTANTS = {
Version: "0.20.2", Version: "0.21.0",
//Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience //Max level for any skill, assuming no multipliers. Determined by max numerical value in javascript for experience
//and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then //and the skill level formula in Player.js. Note that all this means it that when experience hits MAX_INT, then
@ -78,7 +78,7 @@ CONSTANTS = {
AugmentationRepMultiplier: 1.5, //Used for balancing rep cost without having to readjust every value AugmentationRepMultiplier: 1.5, //Used for balancing rep cost without having to readjust every value
//Maximum number of log entries for a script //Maximum number of log entries for a script
MaxLogCapacity: 40, MaxLogCapacity: 50,
//How much a TOR router costs //How much a TOR router costs
TorRouterCost: 200000, TorRouterCost: 200000,
@ -150,32 +150,34 @@ CONSTANTS = {
CrimeHeist: "pull off the ultimate heist", CrimeHeist: "pull off the ultimate heist",
//Text that is displayed when the 'help' command is ran in Terminal //Text that is displayed when the 'help' command is ran in Terminal
HelpText: 'alias [name="value"] Create aliases for Terminal commands, or list existing aliases<br>' + HelpText: 'alias [name="value"] Create aliases for Terminal commands, or list existing aliases<br>' +
"analyze Get statistics and information about current machine <br>" + "analyze Get statistics and information about current machine <br>" +
"cat [message] Display a .msg file<br>" + "cat [message] Display a .msg file<br>" +
"clear Clear all text on the terminal <br>" + "check [script] [args...] Print logs to Terminal for the script with the specified name and arguments<br>" +
"cls See 'clear' command <br>" + "clear Clear all text on the terminal <br>" +
"connect [ip/hostname] Connects to the machine given by its IP or hostname <br>" + "cls See 'clear' command <br>" +
"free Check the machine's memory (RAM) usage<br>" + "connect [ip/hostname] Connects to the machine given by its IP or hostname <br>" +
"hack Hack the current machine<br>" + "free Check the machine's memory (RAM) usage<br>" +
"help Display this help text<br>" + "hack Hack the current machine<br>" +
"home Connect to home computer<br>" + "help Display this help text<br>" +
"hostname Displays the hostname of the machine<br>" + "home Connect to home computer<br>" +
"ifconfig Displays the IP address of the machine<br>" + "hostname Displays the hostname of the machine<br>" +
"kill [script] Stops a script that is running on the current machine<br>" + "ifconfig Displays the IP address of the machine<br>" +
"killall Stops all running scripts on the current machine<br>" + "kill [script] [args...] Stops a script on the current server with the specified name and arguments<br>" +
"ls Displays all programs and scripts on the machine<br>" + "killall Stops all running scripts on the current machine<br>" +
"mem [script] [-t] [n] Displays the amount of RAM the script requires to run with n threads<br>" + "ls Displays all programs and scripts on the machine<br>" +
"nano [script] Text editor - Open up and edit a script<br>" + "mem [script] [-t] [n] Displays the amount of RAM the script requires to run with n threads<br>" +
"ps Display all scripts that are currently running<br>" + "nano [script] Text editor - Open up and edit a script<br>" +
"rm Delete a script/program from the machine. (WARNING: Permanent)<br>" + "ps Display all scripts that are currently running<br>" +
"run [name] [-t] [n] Execute a program or a script with n threads<br>" + "rm Delete a script/program from the machine. (WARNING: Permanent)<br>" +
"scan Displays all available network connections<br>" + "run [name] [-t] [n] [args...] Execute a program or a script with n threads and the specified arguments<br>" +
"scan-analyze [depth] Displays hacking-related information for all servers up to <i>depth</i> nodes away<br>" + "scan Displays all available network connections<br>" +
"scp [script] [server] Copies a script to a destination server (specified by ip or hostname)<br>" + "scan-analyze [depth] Displays hacking-related information for all servers up to <i>depth</i> nodes away<br>" +
"sudov Shows whether or not you have root access on this computer<br>" + "scp [script] [server] Copies a script to a destination server (specified by ip or hostname)<br>" +
"tail [script] Display script logs (logs contain details about active scripts)<br>" + "sudov Shows whether or not you have root access on this computer<br>" +
"top Display all running scripts and their RAM usage<br>", "tail [script] [args...] Display dynamic logs for the script with the specified name and arguments<br>" +
"theme [preset] | bg txt hlgt Change the color scheme of the UI<br>" +
"top Display all running scripts and their RAM usage<br>",
/* Tutorial related things */ /* Tutorial related things */
TutorialGettingStartedText: "Todo...", TutorialGettingStartedText: "Todo...",
@ -248,16 +250,30 @@ CONSTANTS = {
"syntax will vary a little bit. </strong> <br><br>" + "syntax will vary a little bit. </strong> <br><br>" +
"Running a script requires RAM. The more complex a script is, the more RAM " + "Running a script requires RAM. The more complex a script is, the more RAM " +
"it requires to run. Scripts can be run on any server you have root access to. <br><br>" + "it requires to run. Scripts can be run on any server you have root access to. <br><br>" +
"Here are some Terminal commands that are useful when working with scripts: <br>" + "Here are some Terminal commands that are useful when working with scripts: <br><br>" +
"free - Shows the current server's RAM usage and availability <br>" + "<i>check [script] [args...]</i><br>Prints the logs of the script specified by the name and arguments to Terminal. Arguments should be separated " +
"kill [script] - Stops a script that is running <br>" + "by a space. Note that scripts are uniquely " +
"mem [script] [-t] [n] - Check how much RAM a script requires to run with n threads<br>" + "identified by their arguments as well as their name. For example, if you ran a script 'foo.script' with the argument 'foodnstuff' then in order to 'check' it you must " +
"nano [script] - Create/Edit a script <br>" + "also add the 'foodnstuff' argument to the check command as so: <br>check foo.script foodnstuff<br><br>" +
"ps - Displays all scripts that are actively running on the current server<br>" + "<i>free</i><br>Shows the current server's RAM usage and availability <br><br>" +
"rm [script] - Delete a script<br>" + "<i>kill [script] [args...]</i><br>Stops a script that is running with the specified script name and arguments. " +
"run [script] [-t] [n] - Run a script with n threads<br>" + "Arguments should be separated by a space. Note that " +
"tail [script] - Displays a script's logs<br>" + "scripts are uniquely identified by their arguments as well as their name. For example, if you ran a script 'foo.script' with the " +
"top - Displays all active scripts and their RAM usage <br><br>" + "argument 1 and 2, then just typing 'kill foo.script' will not work. You have to use 'kill foo.script 1 2'. <br><br>" +
"<i>mem [script] [-t] [n]</i><br>Check how much RAM a script requires to run with n threads<br><br>" +
"<i>nano [script]</i><br>Create/Edit a script. The name of the script must end with the '.script' extension <br><br>" +
"<i>ps</i><br>Displays all scripts that are actively running on the current server<br><br>" +
"<i>rm [script]</i><br>Delete a script<br><br>" +
"<i>run [script] [-t] [n] [args...]</i><br>Run a script with n threads and the specified arguments. Each argument should be separated by a space. " +
"Both the arguments and thread specification are optional. If neither are specified, then the script will be run single-threaded with no arguments.<br>" +
"Examples:<br>run foo.script<br>The command above will run 'foo.script' single-threaded with no arguments." +
"<br>run foo.script -t 10<br>The command above will run 'foo.script' with 10 threads and no arguments." +
"<br>run foo.script foodnstuff sigma-cosmetics 10<br>The command above will run 'foo.script' single-threaded with three arguments: [foodnstuff, sigma-cosmetics, 10]" +
"<br>run foo.script -t 50 foodnstuff<br>The command above will run 'foo.script' with 50 threads and a single argument: [foodnstuff]<br><br>" +
"<i>tail [script] [args...]</i><br>Displays the logs of the script specified by the name and arguments. Note that scripts are uniquely " +
"identified by their arguments as well as their name. For example, if you ran a script 'foo.script' with the argument 'foodnstuff' then in order to 'tail' it you must " +
"also add the 'foodnstuff' argument to the tail command as so: <br>tail foo.script foodnstuff<br><br>" +
"<i>top</i><br>Displays all active scripts and their RAM usage <br><br>" +
"<u><h1> Multithreading scripts </h1></u><br>" + "<u><h1> Multithreading scripts </h1></u><br>" +
"Scripts can be multithreaded. A multithreaded script runs the script's code once in each thread. The result is that " + "Scripts can be multithreaded. A multithreaded script runs the script's code once in each thread. The result is that " +
"every call to the hack(), grow(), and weaken() Netscript functions will have its effect multiplied by the number of scripts. " + "every call to the hack(), grow(), and weaken() Netscript functions will have its effect multiplied by the number of scripts. " +
@ -318,22 +334,52 @@ CONSTANTS = {
"&nbsp;==<br>" + "&nbsp;==<br>" +
"&nbsp;!=<br><br>" + "&nbsp;!=<br><br>" +
"<u><h1> Arrays </h1></u><br>" + "<u><h1> Arrays </h1></u><br>" +
"Note: Currently arrays are fixed-size once they are declared. Eventually, functionality will be added to make these " + "Arrays are special container objects. Arrays can hold many values under a single name. Each value in the array " +
"dynamic arrays <br><br>" +
"Arrays are special container objects. Arrays can holy many values under a single name. Each value in the array " +
"can be accessed using an index number. The following example shows how to declare an array: <br><br>" + "can be accessed using an index number. The following example shows how to declare an array: <br><br>" +
"thisIsAnArray = Array[1, 2, 3, 'bitburner!', false];<br><br>" + "thisIsAnArray = Array[1, 2, 3, 'bitburner!', false];<br><br>" +
"Note that the values in an array can be different types. To access this array we just declared, we can use the index " + "Note that the values in an array can be different types. To access this array we just declared, we can use the index " +
"operator on the array's name: <br><br>" + "operator on the array's name: <br><br>" +
"print(thisIsAnArray[0]); <br>" + "print(thisIsAnArray[0]); <br>" +
"thisIsAnArray[1] = 5<br>" + "thisIsAnArray[1] = 5;<br>" +
"thisIsAnArray[3] = 'string concatenation ' + 123<br><br>" + "thisIsAnArray[3] = 'string concatenation ' + 123;<br><br>" +
"Note that arrays are indexed starting at index 0. Using an index that is too large or less than 0 will result in an " + "Note that arrays are indexed starting at index 0. Using an index that is too large or less than 0 will result in an " +
"out of bounds runtime error. <br><br>" + "out of bounds runtime error. <br><br>" +
"If an element in an array is assigned to a value that includes a variable, then it holds a reference to that variable. " + "If an element in an array is assigned to a value that includes a variable, then it holds a reference to that variable. " +
"What this means is that if the variable changes, the array element will also change accordingly. For example:<br><br>" + "What this means is that if the variable changes, the array element will also change accordingly. For example:<br><br>" +
"x = 10;<br>testArr = Array[x];<br>print(testArr[0]);<br>x = 20;<br>print(testArr[0]);<br><br>" + "x = 10;<br>testArr = Array[x];<br>print(testArr[0]);<br>x = 20;<br>print(testArr[0]);<br><br>" +
"This code will print: <br><br>10<br>20<br><br>" + "This code will print: <br><br>10<br>20<br><br>" +
"<strong>Array functions</strong><br>" +
"Arrays have built-in functions/properties that can be used to more easily access and manipulate the containers. <br><br>"+
"<i>length/length()</i><br>Returns the number of elements in the array.<br>" +
"The example below will print out 5:<br><br>" +
"arr = Array[1, 2, 3, 4, 5];<br>print(arr.length);<br><br>" +
"<i>clear/clear()</i><br>Removes all elements from the array.<br>" +
"The example below creates an array with three strings and then uses clear to remove all of those strings. The result is that 'arr' will be " +
"an empty array.<br><br>" +
"arr = Array['str1', 'str2', 'str3'];<br>arr.clear();<br><br>" +
"<i>push(e)</i><br>Adds the element e to the end of the array.<br>" +
"The example below will create an array holding one element: the number 1. It will then push the number 2 onto the array. The result " +
"is that 'arr' will be an array of size 2 with arr[0] == 1 and arr[1] == 2<br><br>" +
"arr = Array[1];<br>arr.push(2);<br><br>" +
"<i>insert(e)</i><br>Inserts an element e into an array at a specified index. Every element in the array that is at or after " +
"the specified index is shifted down. The array must be indexed with the [] operator when using this function.<br>" +
"The following example will insert the number 2 into index 1 of the array. The result afterwards is that 'arr' will hold the values [1, 2, 3, 4].<br><br>" +
"arr = Array[1, 3, 4];<br>arr[1].insert(2);<br><br>" +
"<i>remove()</i><br>Removes an element from a specified index. Every element in the array that is after the specified index " +
"will be shifted up. The array must be indexed with the [] operator when using this function.<br>" +
"The following example will remove the first element of the array. The result afterwards is that 'arr' will hold the values [2, 3].<br><br>" +
"arr = Array[1, 2, 3];<br>arr[0].remove();<br><br>" +
"<u><h1> Script Arguments </h1></u><br>" +
"Arguments passed into a script can be accessed using a special array called 'args'. The arguments can be accessed like a normal array using the [] " +
"operator. (args[0], args[1], args[2]...) <br><br>" +
"For example, let's say we want to make a generic script 'generic-run.script' and we plan to pass two arguments into that script. The first argument will be the name of " +
"another script, and the second argument will be a number. This generic script will run the script specified in the first argument " +
"with the amount of threads specified in the second element. The code would look like:<br><br>" +
"run(args[0], args[1]);<br><br>" +
"It is also possible to get the number of arguments that was passed into a script using:<br><br>" +
"args.length<br><br>" +
"Note that none of the other functions that typically work with arrays, such as remove(), insert(), clear(), etc., will work on the " +
"args array.<br><br>" +
"<u><h1> Functions </h1></u><br>" + "<u><h1> Functions </h1></u><br>" +
"You can NOT define you own functions in Netscript (yet), but there are several built in functions that " + "You can NOT define you own functions in Netscript (yet), but there are several built in functions that " +
"you may use: <br><br> " + "you may use: <br><br> " +
@ -361,36 +407,56 @@ CONSTANTS = {
"any server, regardless of where the script is running. This command requires root access to the target server, but " + "any server, regardless of where the script is running. This command requires root access to the target server, but " +
"there is no required hacking level to run the command. Grants 3 hacking exp when it completes. Returns " + "there is no required hacking level to run the command. Grants 3 hacking exp when it completes. Returns " +
"0.1. Works offline at a slower rate<br> Example: weaken('foodnstuff');<br><br>" + "0.1. Works offline at a slower rate<br> Example: weaken('foodnstuff');<br><br>" +
"<i>print(x)</i> <br> Prints a value or a variable to the scripts logs (which can be viewed with the 'tail [script]' terminal command )<br><br>" + "<i>print(x)</i> <br> Prints a value or a variable to the scripts logs (which can be viewed with the 'tail [script]' terminal command ). <br>" +
"WARNING: Do NOT call print() on an array. The script will crash. You can, however, call print on single elements of an array. For example, if " +
"the variable 'a' is an array, then do NOT call print(a), but it is okay to call print(a[0]).<br><br>" +
"<i>nuke(hostname/ip)</i><br>Run NUKE.exe on the target server. NUKE.exe must exist on your home computer. Does NOT work while offline <br> Example: nuke('foodnstuff'); <br><br>" + "<i>nuke(hostname/ip)</i><br>Run NUKE.exe on the target server. NUKE.exe must exist on your home computer. Does NOT work while offline <br> Example: nuke('foodnstuff'); <br><br>" +
"<i>brutessh(hostname/ip)</i><br>Run BruteSSH.exe on the target server. BruteSSH.exe must exist on your home computer. Does NOT work while offline <br> Example: brutessh('foodnstuff');<br><br>" + "<i>brutessh(hostname/ip)</i><br>Run BruteSSH.exe on the target server. BruteSSH.exe must exist on your home computer. Does NOT work while offline <br> Example: brutessh('foodnstuff');<br><br>" +
"<i>ftpcrack(hostname/ip)</i><br>Run FTPCrack.exe on the target server. FTPCrack.exe must exist on your home computer. Does NOT work while offline <br> Example: ftpcrack('foodnstuff');<br><br>" + "<i>ftpcrack(hostname/ip)</i><br>Run FTPCrack.exe on the target server. FTPCrack.exe must exist on your home computer. Does NOT work while offline <br> Example: ftpcrack('foodnstuff');<br><br>" +
"<i>relaysmtp(hostname/ip)</i><br>Run relaySMTP.exe on the target server. relaySMTP.exe must exist on your home computer. Does NOT work while offline <br> Example: relaysmtp('foodnstuff');<br><br>" + "<i>relaysmtp(hostname/ip)</i><br>Run relaySMTP.exe on the target server. relaySMTP.exe must exist on your home computer. Does NOT work while offline <br> Example: relaysmtp('foodnstuff');<br><br>" +
"<i>httpworm(hostname/ip)</i><br>Run HTTPWorm.exe on the target server. HTTPWorm.exe must exist on your home computer. Does NOT work while offline <br> Example: httpworm('foodnstuff');<br><br>" + "<i>httpworm(hostname/ip)</i><br>Run HTTPWorm.exe on the target server. HTTPWorm.exe must exist on your home computer. Does NOT work while offline <br> Example: httpworm('foodnstuff');<br><br>" +
"<i>sqlinject(hostname/ip)</i><br>Run SQLInject.exe on the target server. SQLInject.exe must exist on your home computer. Does NOT work while offline <br> Example: sqlinject('foodnstuff');<br><br>" + "<i>sqlinject(hostname/ip)</i><br>Run SQLInject.exe on the target server. SQLInject.exe must exist on your home computer. Does NOT work while offline <br> Example: sqlinject('foodnstuff');<br><br>" +
"<i>run(script, [numThreads])</i> <br> Run a script as a separate process. The first argument that is passed in is the name of the script as a string. This function can only " + "<i>run(script, [numThreads], [args...])</i> <br> Run a script as a separate process. The first argument that is passed in is the name of the script as a string. This function can only " +
"be used to run scripts located on the current server (the server running the script that calls this function). The second argument " + "be used to run scripts located on the current server (the server running the script that calls this function). The second argument " +
"is optional, and it specifies how many threads to run the script with. If it is omitted, then the script will be run single-threaded. " + "is optional, and it specifies how many threads to run the script with. This argument must be a number greater than 0. If it is omitted, then the script will be run single-threaded. Any additional arguments will specify " +
"This second argument must be a number that is greater than 0. " + "arguments to pass into the new script that is being run. If arguments are specified for the new script, then the second argument numThreads argument must be filled in with a value.<br><br>" +
"Returns true if the script is successfully started, and false otherwise. Requires a significant amount " + "Returns true if the script is successfully started, and false otherwise. Requires a significant amount " +
"of RAM to run this command. Does NOT work while offline <br>Example: run('hack-foodnstuff.script'); <br> The example above will try and launch the 'hack-foodnstuff.script' script on " + "of RAM to run this command. Does NOT work while offline <br><br>" +
"the current server, if it exists. <br><br>" + "The simplest way to use the run command is to call it with just the script name. The following example will run 'foo.script' single-threaded with no arguments:<br><br>" +
"<i>exec(script, hostname/ip, [numThreads])</i><br>Run a script as a separate process on another server. The first argument is the name of the script as a string. The " + "run('foo.script');<br><br>" +
"The following example will run 'foo.script' but with 5 threads instead of single-threaded:<br><br>" +
"run('foo.script', 5);<br><br>" +
"The following example will run 'foo.script' single-threaded, and will pass the string 'foodnstuff' into the script as an argument:<br><br>" +
"run('foo.script', 1, 'foodnstuff');<br><br>" +
"<i>exec(script, hostname/ip, [numThreads], [args...])</i><br>Run a script as a separate process on another server. The first argument is the name of the script as a string. The " +
"second argument is a string with the hostname or IP of the 'target server' on which to run the script. The specified script must exist on the target server. " + "second argument is a string with the hostname or IP of the 'target server' on which to run the script. The specified script must exist on the target server. " +
"The third argument is optional, and it specifies how many threads to run the script with. If it is omitted, then the script will be run single-threaded. " + "The third argument is optional, and it specifies how many threads to run the script with. If it is omitted, then the script will be run single-threaded. " +
"This argument must be a number that is greater than 0. Returns " + "This argument must be a number that is greater than 0. Any additional arguments will specify arguments to pass into the new script that is being run. If " +
"true if the script is successfully started, and false otherwise. Does NOT work while offline<br> " + "arguments are specified for the new script, then the third argument numThreads must be filled in with a value.<br><br>Returns " +
"Example: exec('generic-hack.script', 'foodnstuff'); <br> The example above will try to launch the script 'generic-hack.script' on the 'foodnstuff' server.<br><br>" + "true if the script is successfully started, and false otherwise. Does NOT work while offline<br><br> " +
"<i>kill(script, [hostname/ip])</i><br> Kills a script on a server. The first argument must be a string with the name of the script. The name is case-sensitive. " + "The simplest way to use the exec command is to call it with just the script name and the target server. The following example will try to run 'generic-hack.script' " +
"The second argument must be a string with the hostname or IP of the target server. The function will try to kill the specified script on the target server. " + "on the 'foodnstuff' server:<br><br>" +
"The second argument is optional. If it is omitted, then the function will try to kill the specified script on the current server (the server running " + "exec('generic-hack.script', 'foodnstuff');<br><br>" +
"the script that calls this function). If the script is found on the specified server and is running, then it will be killed and this function " + "The following example will try to run the script 'generic-hack.script' on the 'joesguns' server with 10 threads:<br><br>" +
"will return true. Otherwise, this function will return false. <br> " + "exec('generic-hack.script', 'joesguns', 10);<br><br>" +
"Example: kill('foo.script', 'foodnstuff');<br>" + "The following example will try to run the script 'foo.script' on the 'foodnstuff' server with 5 threads. It will also pass the number 1 and the string 'test' in as arguments " +
"Example: kill('foo.script');<br>" + "to the script.<br><br>" +
"The first example above will look for a script called 'foo.script' on the 'foodnstuff' server. If the script exists and is running, then it will " + "exec('foo.script', 'foodnstuff', 5, 1, 'test');<br><br>" +
"be killed and the function will return true. Otherwise false will be returned. The second example above will do the same thing, except on the " + "<i>kill(script, hostname/ip, [args...])</i><br> Kills the script on the target server specified by the script's name and arguments. Remember that " +
"current server (the server running the script that calls the kill() function).<br><br>" + "scripts are uniquely identified by both their name and arguments. For example, if 'foo.script' is run with the argument 1, then this is not the " +
"same as 'foo.script' run with the argument 2, even though they have the same code. <br><br>" +
"The first argument must be a string with the name of the script. The name is case-sensitive. " +
"The second argument must be a string with the hostname or IP of the target server. Any additional arguments to the function will specify the arguments passed " +
"into the script that should be killed. <br><br>The function will try to kill the specified script on the target server. " +
"If the script is found on the specified server and is running, then it will be killed and this function " +
"will return true. Otherwise, this function will return false. <br><br>" +
"Examples:<br>" +
"If you are trying to kill a script named 'foo.script' on the 'foodnstuff' server that was ran with no arguments, use this:<br><br>" +
"kill('foo.script', 'foodnstuff');<br><br>" +
"If you are trying to kill a script named 'foo.script' on the current server that was ran with no arguments, use this:<br><br>" +
"kill('foo.script', getHostname());<br><br>" +
"If you are trying to kill a script named 'foo.script' on the current server that was ran with the arguments 1 and 'foodnstuff', use this:<br><br>" +
"kill('foo.script', getHostname(), 1, 'foodnstuff');<br><br>" +
"<i>killall(hostname/ip)</i><br> Kills all running scripts on the specified server. This function takes a single argument which " + "<i>killall(hostname/ip)</i><br> Kills all running scripts on the specified server. This function takes a single argument which " +
"must be a string containing the hostname or IP of the target server. This function will always return true. <br><br>" + "must be a string containing the hostname or IP of the target server. This function will always return true. <br><br>" +
"<i>scp(script, hostname/ip)</i><br>Copies a script to another server. The first argument is a string with the filename of the script " + "<i>scp(script, hostname/ip)</i><br>Copies a script to another server. The first argument is a string with the filename of the script " +
@ -416,14 +482,18 @@ CONSTANTS = {
"Example: fileExists('ftpcrack.exe');<br><br>" + "Example: fileExists('ftpcrack.exe');<br><br>" +
"The first example above will return true if the script named 'foo.script' exists on the 'foodnstuff' server, and false otherwise. The second example above will " + "The first example above will return true if the script named 'foo.script' exists on the 'foodnstuff' server, and false otherwise. The second example above will " +
"return true if the current server (the server on which this function runs) contains the FTPCrack.exe program, and false otherwise. <br><br>" + "return true if the current server (the server on which this function runs) contains the FTPCrack.exe program, and false otherwise. <br><br>" +
"<i>isRunning(filename, [hostname/ip])</i><br> Returns a boolean (true or false) indicating whether the specified script is running on a server. " + "<i>isRunning(filename, hostname/ip, [args...])</i><br> Returns a boolean (true or false) indicating whether the specified script is running on a server. " +
"Remember that a script is uniquely identified by both its name and its arguments. <br><br>" +
"The first argument must be a string with the name of the script. The script name is case sensitive. The second argument is a string with the " + "The first argument must be a string with the name of the script. The script name is case sensitive. The second argument is a string with the " +
"hostname or IP of the target server. The function will check whether the script is running on that target server. The second argument is optional. " + "hostname or IP of the target server. Any additional arguments passed to the function will specify the arguments passed into the target script. " +
"If it is omitted, then the function will check if the script is running on the current server (the server running the script that calls this function). <br>" + "The function will check whether the script is running on that target server.<br>" +
"Example: isRunning('foo.script', 'foodnstuff');<br>" + "Example: isRunning('foo.script', 'foodnstuff');<br>" +
"Example: isRunning('foo.script'); <br><br>" + "Example: isRunning('foo.script', getHostname());<br>" +
"The first example above will return true if there is a script called 'foo.script' is running on the 'foodnstuff' server, and false otherwise. The second " + "Example: isRunning('foo.script', 'joesguns', 1, 5, 'test');<br><br>" +
"example above will return true if there is a script called 'foo.script' running on the current server, and false otherwise. <br><br>" + "The first example above will return true if there is a script named 'foo.script' with no arguments running on the 'foodnstuff' server, and false otherwise. The second " +
"example above will return true if there is a script named 'foo.script' with no arguments running on the current server, and false otherwise. " +
"The third example above will return true if there is a script named 'foo.script' with the arguments 1, 5, and 'test' running on the 'joesguns' server, and " +
"false otherwise.<br><br>" +
"<i>purchaseHacknetNode()</i><br> Purchases a new Hacknet Node. Returns a number with the index of the Hacknet Node. This index is equivalent to the number " + "<i>purchaseHacknetNode()</i><br> Purchases a new Hacknet Node. Returns a number with the index of the Hacknet Node. This index is equivalent to the number " +
"at the end of the Hacknet Node's name (e.g The Hacknet Node named 'hacknet-node-4' will have an index of 4). If the player cannot afford to purchase " + "at the end of the Hacknet Node's name (e.g The Hacknet Node named 'hacknet-node-4' will have an index of 4). If the player cannot afford to purchase " +
"a new Hacknet Node then the function will return false. Does NOT work offline<br><br>" + "a new Hacknet Node then the function will return false. Does NOT work offline<br><br>" +
@ -573,6 +643,27 @@ CONSTANTS = {
"RAM Upgrades on your home computer", "RAM Upgrades on your home computer",
Changelog: Changelog:
"v0.21.0<br>" +
"-Added dynamic arrays. See Netscript documentation<br>" +
"-Added ability to pass arguments into scripts. See documentation<br>" +
"-The implementation/function signature of functions that deal with scripts have changed. Therefore, some old scripts might not " +
"work anymore. Some of these functions include run(), exec(), isRunning(), kill(), and some others I may have forgot about. " +
"Please check the updated Netscript documentation if you run into issues." +
"-Note that scripts are now uniquely identified by the script name and their arguments. For example, you can run " +
"a script using <br>run foodnstuff.script 1<br> and you can also run the same script with a different argument " +
"<br>run foodnstuff.script 2<br>These will be considered two different scripts. To kill the first script you must " +
"run <br>kill foodnstuff.script 1<br> and to kill the second you must run <br>kill foodnstuff.script 2<br> Similar concepts " +
"apply for Terminal Commands such as tail, and Netscript commands such as run(), exec(), kill(), isRunning(), etc.<br>" +
"-Added basic theme functionality using the 'theme' Terminal command - All credit goes to /u/0x726564646974 who implemented the awesome feature<br>" +
"-Optimized Script objects, which were causing save errors when the player had too many scripts<br>" +
"-Formula for determining exp gained from hacking was changed<br>" +
"-Fixed bug where you could purchase Darkweb items without TOR router<br>" +
"-Slightly increased cost multiplier for Home Computer RAM<br>" +
"-Fixed bug where you could hack too much money from a server (and bring its money available below zero)<br>" +
"-Changed tail command so that it brings up a display box with dynamic log contents. To get " +
"old functionality where the logs are printed to the Terminal, use the new 'check' command<br>" +
"-As a result of the change above, you can no longer call tail/check on scripts that are not running<br>" +
"-Added autocompletion for buying Programs in Darkweb<br>" +
"v0.20.2<br>" + "v0.20.2<br>" +
"-Fixed several small bugs<br>" + "-Fixed several small bugs<br>" +
"-Added basic array functionality to Netscript<br>" + "-Added basic array functionality to Netscript<br>" +
@ -701,49 +792,25 @@ CONSTANTS = {
"-You can now see what an Augmentation does and its price even while its locked<br><br>", "-You can now see what an Augmentation does and its price even while its locked<br><br>",
LatestUpdate: LatestUpdate:
"v0.20.2<br>" + "v0.21.0<br>" +
"-Fixed several small bugs<br>" + "-Added dynamic arrays. See Netscript documentation<br>" +
"-Added basic array functionality to Netscript<br>" + "-Added ability to pass arguments into scripts. See documentation<br>" +
"-Added ability to run scripts with multiple threads. Running a script with n threads will multiply the effects of all " + "-The implementation/function signature of functions that deal with scripts have changed. Therefore, some old scripts might not " +
"hack(), grow(), and weaken() commands by n. However, running a script with multiple threads has drawbacks in terms of " + "work anymore. Some of these functions include run(), exec(), isRunning(), kill(), and some others I may have forgot about. " +
"RAM usage. A script's ram usage when it is 'multithreaded' is calculated as: base cost * numThreads * (1.02 ^ numThreads). " + "Please check the updated Netscript documentation if you run into issues." +
"A script can be run multithreaded using the 'run [script] -t n' Terminal command or by passing in an argument to the " + "-Note that scripts are now uniquely identified by the script name and their arguments. For example, you can run " +
"run() and exec() Netscript commands. See documentation.<br>" + "a script using <br>run foodnstuff.script 1<br> and you can also run the same script with a different argument " +
"-RAM is slightly (~10%) more expensive (affects purchasing server and upgrading RAM on home computer)<br>" + "<br>run foodnstuff.script 2<br>These will be considered two different scripts. To kill the first script you must " +
"-NeuroFlux Governor augmentation cost multiplier decreased<br>" + "run <br>kill foodnstuff.script 1<br> and to kill the second you must run <br>kill foodnstuff.script 2<br> Similar concepts " +
"-Netscript default operation runtime lowered to 200ms (was 500ms previously)<br><br>" + "apply for Terminal Commands such as tail, and Netscript commands such as run(), exec(), kill(), isRunning(), etc.<br>" +
"v0.20.1<br>" + "-Added basic theme functionality using the 'theme' Terminal command - All credit goes to /u/0x726564646974 who implemented the awesome feature<br>" +
"-Fixed bug where sometimes scripts would crash without showing the error<br>" + "-Optimized Script objects, which were causing save errors when the player had too many scripts<br>" +
"-Added Deepscan programs to Dark Web<br>" + "-Formula for determining exp gained from hacking was changed<br>" +
"-Declining a faction invite will stop you from receiving invitations from that faction for the rest of the run<br>" + "-Fixed bug where you could purchase Darkweb items without TOR router<br>" +
"-(BETA) Added functionality to export/import saves. WARNING This is only lightly tested. You cannot choose where to save your file " + "-Slightly increased cost multiplier for Home Computer RAM<br>" +
"it just goes to the default save location. Also I have no idea what will happen if you try to import a file " + "-Fixed bug where you could hack too much money from a server (and bring its money available below zero)<br>" +
"that is not a valid save. I will address these in later updates<br><br>" + "-Changed tail command so that it brings up a display box with dynamic log contents. To get " +
"v0.20.0<br>" + "old functionality where the logs are printed to the Terminal, use the new 'check' command<br>" +
"-Refactored Netscript Interpreter code. Operations in Netscript should now run significantly faster (Every operation " + "-As a result of the change above, you can no longer call tail/check on scripts that are not running<br>" +
"such as a variable assignment, a function call, a binary operator, getting a variable's value, etc. used to take up to several seconds, " + "-Added autocompletion for buying Programs in Darkweb<br>",
"now each one should only take ~500 milliseconds). <br><br>" +
"-Percentage money stolen when hacking lowered to compensate for faster script speeds<br><br>" +
"-Hacking experience granted by grow() halved<br><br>" +
"-Weaken() is now ~11% faster, but only grants 3 base hacking exp upon completion instead of 5 <br><br>" +
"-Rebalancing of script RAM costs. Base RAM Cost for a script increased from 1GB to 1.5GB. Loops, hack(), grow() " +
"and weaken() all cost slightly less RAM than before <br><br>" +
"-Added getServerRequiredHackingLevel(server) Netscript command. <br><br>" +
"-Added fileExists(file, [server]) Netscript command, which is used to check if a script/program exists on a " +
"specified server<br><br>" +
"-Added isRunning(script, [server]) Netscript command, which is used to check if a script is running on the specified server<br><br>" +
"-Added killall Terminal command. Kills all running scripts on the current machine<br><br>" +
"-Added kill() and killall() Netscript commands. Used to kill scripts on specified machines. See Netscript documentation<br><br>" +
"-Re-designed 'Active Scripts' tab<br><br>" +
"-Hacknet Node base production rate lowered from 1.6 to 1.55 ($/second)<br><br>" +
"-Increased monetary cost of RAM (Upgrading home computer and purchasing servers will now be more expensive)<br><br>" +
"-NEW GROWTH MECHANICS - The rate of growth on a server now depends on a server's security level. A higher security level " +
"will result in lower growth on a server when using the grow() command. Furthermore, calling grow() on a server raises that " +
"server's security level by 0.004. For reference, if a server has a security level of 10 " +
"it will have approximately the same growth rate as before. <br><br>" +
"-Server growth no longer happens naturally<br><br>" +
"-Servers now have a maximum limit to their money. This limit is 50 times it's starting money<br><br>" +
"-Hacking now grants 10% less hacking experience<br><br>" +
"-You can now edit scripts that are running<br><br>" +
"-Augmentations cost ~11% more money and 25% more faction reputation<br><br>",
} }

@ -28,6 +28,26 @@ function evaluate(exp, workerScript) {
reject(e); reject(e);
}); });
return; return;
} else if (exp.value == "args") {
if (exp.index) {
var iPromise = evaluate(exp.index.value, workerScript);
iPromise.then(function(i) {
if (isNaN(i)) {
reject(makeRuntimeRejectMsg(workerScript, "Invalid access to args array. Index is not a number: " + i));
} else if (i >= workerScript.args.length || i < 0) {
reject(makeRuntimeRejectMsg(workerScript, "Out of bounds: Invalid index in [] operator"));
} else {
resolve(workerScript.args[i]);
}
}, function(e) {
reject(e);
});
} else if (exp.op && exp.op.type == "var" && exp.op.value == "length") {
resolve(workerScript.args.length);
} else {
reject(makeRuntimeRejectMsg(workerScript, "Invalid access to args array"));
}
return;
} else if (exp.value == "array") { } else if (exp.value == "array") {
//A raw array. This will be called under something like this: //A raw array. This will be called under something like this:
// x = Array[1, 2, 3]; // x = Array[1, 2, 3];
@ -40,25 +60,13 @@ function evaluate(exp, workerScript) {
} }
try { try {
var res = env.get(exp.value); var res = env.get(exp.value);
if (exp.index) { if (res.constructor === Array || res instanceof Array) {
//If theres an index field, then this variable is supposed to be an array var evalArrayPromise = netscriptArray(exp, workerScript);
//and the user needs to be indexing it evalArrayPromise.then(function(res) {
if (res.constructor === Array || res instanceof Array) { resolve(res);
var iPromise = evaluate(exp.index.value, workerScript); }, function(e) {
iPromise.then(function(i) { reject(e);
if (i >= res.length || i < 0) { });
return reject(makeRuntimeRejectMsg(workerScript, "Out of bounds: Invalid index in [] operator"));
} else {
return evaluate(res[i], workerScript);
}
}).then(function(res) {
resolve(res);
}).catch(function(e) {
reject(e);
});
} else {
reject(makeRuntimeRejectMsg(workerScript, "Trying to access a non-array variable using the [] operator"));
}
} else { } else {
resolve(res); resolve(res);
} }
@ -255,8 +263,8 @@ function evaluate(exp, workerScript) {
reject(e); reject(e);
}); });
} else if (exp.func.value == "run") { } else if (exp.func.value == "run") {
if (exp.args.length != 1 && exp.args.length != 2) { if (exp.args.length < 1) {
return reject(makeRuntimeRejectMsg(workerScript, "run() call has incorrect number of arguments. Takes 1 or 2 arguments")); return reject(makeRuntimeRejectMsg(workerScript, "run() call has incorrect number of arguments. Usage: run(scriptname, [numThreads], [arg1], [arg2]...)"));
} }
var argPromises = exp.args.map(function(arg) { var argPromises = exp.args.map(function(arg) {
return evaluate(arg, workerScript); return evaluate(arg, workerScript);
@ -266,9 +274,14 @@ function evaluate(exp, workerScript) {
if (env.stopFlag) {return reject(workerScript);} if (env.stopFlag) {return reject(workerScript);}
var scriptname = args[0]; var scriptname = args[0];
var threads = 1; var threads = 1;
if (exp.args.length == 2) { if (exp.args.length >= 2) {
threads = args[1]; threads = args[1];
} }
var argsForNewScript = [];
for (var i = 2; i < exp.args.length; ++i) {
argsForNewScript.push(args[i]);
}
if (isNaN(threads) || threads < 1) { if (isNaN(threads) || threads < 1) {
return reject(makeRuntimeRejectMsg(workerScript, "Invalid argument for thread count passed into run(). Must be numeric and greater than 0")); return reject(makeRuntimeRejectMsg(workerScript, "Invalid argument for thread count passed into run(). Must be numeric and greater than 0"));
} }
@ -277,7 +290,7 @@ function evaluate(exp, workerScript) {
return reject(makeRuntimeRejectMsg(workerScript, "Could not find server. This is a bug in the game. Report to game dev")); return reject(makeRuntimeRejectMsg(workerScript, "Could not find server. This is a bug in the game. Report to game dev"));
} }
var runScriptPromise = runScriptFromScript(scriptServer, scriptname, workerScript, threads); var runScriptPromise = runScriptFromScript(scriptServer, scriptname, argsForNewScript, workerScript, threads);
return runScriptPromise; return runScriptPromise;
}).then(function(res) { }).then(function(res) {
resolve(res); resolve(res);
@ -285,8 +298,8 @@ function evaluate(exp, workerScript) {
reject(e); reject(e);
}); });
} else if (exp.func.value == "exec") { } else if (exp.func.value == "exec") {
if (exp.args.length != 2 && exp.args.length != 3) { if (exp.args.length < 2) {
return reject(makeRuntimeRejectMsg(workerScript, "exec() call has incorrect number of arguments. Takes 2 arguments")); return reject(makeRuntimeRejectMsg(workerScript, "exec() call has incorrect number of arguments. Usage: exec(scriptname, server, [numThreads], [arg1], [arg2]...)"));
} }
var argPromises = exp.args.map(function(arg) { var argPromises = exp.args.map(function(arg) {
return evaluate(arg, workerScript); return evaluate(arg, workerScript);
@ -295,9 +308,14 @@ function evaluate(exp, workerScript) {
Promise.all(argPromises).then(function(args) { Promise.all(argPromises).then(function(args) {
if (env.stopFlag) {return reject(workerScript);} if (env.stopFlag) {return reject(workerScript);}
var threads = 1; var threads = 1;
if (exp.args.length == 3) { if (exp.args.length >= 3) {
threads = args[2]; threads = args[2];
} }
var argsForNewScript = [];
for (var i = 3; i < exp.args.length; ++i) {
argsForNewScript.push(args[i]);
}
if (isNaN(threads) || threads < 1) { if (isNaN(threads) || threads < 1) {
return reject(makeRuntimeRejectMsg(workerScript, "Invalid argument for thread count passed into exec(). Must be numeric and greater than 0")); return reject(makeRuntimeRejectMsg(workerScript, "Invalid argument for thread count passed into exec(). Must be numeric and greater than 0"));
} }
@ -306,42 +324,43 @@ function evaluate(exp, workerScript) {
return reject(makeRuntimeRejectMsg(workerScript, "Invalid hostname/ip passed into exec() command: " + args[1])); return reject(makeRuntimeRejectMsg(workerScript, "Invalid hostname/ip passed into exec() command: " + args[1]));
} }
return runScriptFromScript(server, args[0], workerScript, threads); return runScriptFromScript(server, args[0], argsForNewScript, workerScript, threads);
}).then(function(res) { }).then(function(res) {
resolve(res); resolve(res);
}).catch(function(e) { }).catch(function(e) {
reject(e); reject(e);
}); });
} else if (exp.func.value == "kill") { } else if (exp.func.value == "kill") {
if (exp.args.length != 1 && exp.args.length != 2) { if (exp.args.length < 2) {
return reject(makeRuntimeRejectMsg(workerScript, "kill() call has incorrect number of arguments. Takes 1 or 2 arguments")); return reject(makeRuntimeRejectMsg(workerScript, "kill() call has incorrect number of arguments. Usage: kill(scriptname, server, [arg1], [arg2]...)"));
} }
var argPromises = exp.args.map(function(arg) { var argPromises = exp.args.map(function(arg) {
return evaluate(arg, workerScript); return evaluate(arg, workerScript);
}); });
var filename = "";
Promise.all(argPromises).then(function(args) { Promise.all(argPromises).then(function(args) {
if (env.stopFlag) {return reject(workerScript);} if (env.stopFlag) {return reject(workerScript);}
filename = args[0]; var filename = args[0];
if (exp.args.length == 1) { var server = getServer(args[1]);
return Promise.resolve(workerScript.serverIp);
} else {
return evaluate(exp.args[1], workerScript);
}
}).then(function(ip) {
var server = getServer(ip);
if (server == null) { if (server == null) {
workerScript.scriptRef.log("kill() failed. Invalid IP or hostname passed in: " + ip); workerScript.scriptRef.log("kill() failed. Invalid IP or hostname passed in: " + ip);
return reject(makeRuntimeRejectMsg(workerScript, "Invalid IP or hostname passed into kill() command")); return reject(makeRuntimeRejectMsg(workerScript, "Invalid IP or hostname passed into kill() command"));
} }
var argsForKillTarget = [];
var res = killWorkerScript(filename, server.ip); for (var i = 2; i < exp.args.length; ++i) {
argsForKillTarget.push(args[i]);
}
var runningScriptObj = findRunningScript(filename, argsForKillTarget, server);
if (runningScriptObj == null) {
workerScript.scriptRef.log("kill() failed. No such script "+ filename + " on " + server.hostname + " with args: " + printArray(argsForKillTarget));
return Promise.resolve(false);
}
var res = killWorkerScript(runningScriptObj, server.ip);
if (res) { if (res) {
workerScript.scriptRef.log("Killing " + filename + ". May take up to a few minutes for the scripts to die..."); workerScript.scriptRef.log("Killing " + filename + " on " + server.hostname + " with args: " + printArray(argsForKillTarget) + ". May take up to a few minutes for the scripts to die...");
return Promise.resolve(true); return Promise.resolve(true);
} else { } else {
workerScript.scriptRef.log("kill() failed. No such script "+ filename + " on " + server.hostname); workerScript.scriptRef.log("kill() failed. No such script "+ filename + " on " + server.hostname + " with args: " + printArray(argsForKillTarget));
return Promise.resolve(false); return Promise.resolve(false);
} }
}).then(function(res) { }).then(function(res) {
@ -361,10 +380,10 @@ function evaluate(exp, workerScript) {
workerScript.scriptRef.log("killall() failed. Invalid IP or hostname passed in: " + ip); workerScript.scriptRef.log("killall() failed. Invalid IP or hostname passed in: " + ip);
return reject(makeRuntimeRejectMsg(workerScript, "Invalid IP or hostname passed into killall() command")); return reject(makeRuntimeRejectMsg(workerScript, "Invalid IP or hostname passed into killall() command"));
} }
workerScript.scriptRef.log("killall(): Killing all scripts on " + server.hostname + ". May take a few minutes for the scripts to die"); for (var i = server.runningScripts.length-1; i >= 0; --i) {
for (var i = server.runningScripts.length; i >= 0; --i) {
killWorkerScript(server.runningScripts[i], server.ip); killWorkerScript(server.runningScripts[i], server.ip);
} }
workerScript.scriptRef.log("killall(): Killing all scripts on " + server.hostname + ". May take a few minutes for the scripts to die");
resolve(true); resolve(true);
}, function(e) { }, function(e) {
reject(e); reject(e);
@ -532,35 +551,31 @@ function evaluate(exp, workerScript) {
reject(e); reject(e);
}); });
} else if (exp.func.value == "isRunning") { } else if (exp.func.value == "isRunning") {
if (exp.args.length != 1 && exp.args.length != 2) { if (exp.args.length < 2) {
return reject(makeRuntimeRejectMsg(workerScript, "isRunning() call has incorrect number of arguments. Takes 1 or 2 arguments")); return reject(makeRuntimeRejectMsg(workerScript, "isRunning() call has incorrect number of arguments. Usage: isRunning(scriptname, server, [arg1], [arg2]...)"));
} }
var argPromises = exp.args.map(function(arg) { var argPromises = exp.args.map(function(arg) {
return evaluate(arg, workerScript); return evaluate(arg, workerScript);
}); });
var filename = ""; var filename = "";
var argsForTargetScript = [];
Promise.all(argPromises).then(function(args) { Promise.all(argPromises).then(function(args) {
if (env.stopFlag) {return reject(workerScript);} if (env.stopFlag) {return reject(workerScript);}
filename = args[0]; filename = args[0];
if (exp.args.length == 1) { var ip = args[1];
return Promise.resolve(workerScript.serverIp); for (var i = 2; i < args.length; ++i) {
} else { argsForTargetScript.push(args[i]);
return evaluate(exp.args[1], workerScript);
} }
}).then(function(ip) {
var server = getServer(ip); var server = getServer(ip);
if (server == null) { if (server == null) {
workerScript.scriptRef.log("isRunning() failed. Invalid IP or hostname passed in: " + ip); workerScript.scriptRef.log("isRunning() failed. Invalid IP or hostname passed in: " + ip);
return reject(makeRuntimeRejectMsg(workerScript, "Invalid IP or hostname passed into isRunning() command")); return reject(makeRuntimeRejectMsg(workerScript, "Invalid IP or hostname passed into isRunning() command"));
} }
var runningScriptObj = findRunningScript(filename, argsForTargetScript, server);
for (var i = 0; i < server.runningScripts.length; ++i) { if (runningScriptObj != null) {
if (filename == server.runningScripts[i]) { return resolve(true);
return resolve(true);
}
} }
return resolve(false); return resolve(false);
}).catch(function(e) { }).catch(function(e) {
reject(e); reject(e);
@ -763,7 +778,7 @@ function evaluateHacknetNode(exp, workerScript) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
setTimeout(function() { setTimeout(function() {
if (exp.index == null) { if (exp.index == null) {
if ((exp.op.type == "call" && exp.op.value == "length") || if ((exp.op.type == "call" && exp.op.func.value == "length") ||
(exp.op.type == "var" && exp.op.value == "length")) { (exp.op.type == "var" && exp.op.value == "length")) {
resolve(Player.hacknetNodes.length); resolve(Player.hacknetNodes.length);
workerScript.scriptRef.log("hacknetnodes.length returned " + Player.hacknetNodes.length); workerScript.scriptRef.log("hacknetnodes.length returned " + Player.hacknetNodes.length);
@ -938,45 +953,41 @@ function apply_op(op, a, b) {
} }
//Run a script from inside a script using run() command //Run a script from inside a script using run() command
function runScriptFromScript(server, scriptname, workerScript, threads=1) { function runScriptFromScript(server, scriptname, args, workerScript, threads=1) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
var env = workerScript.env; var env = workerScript.env;
if (env.stopFlag) {reject(workerScript); return;} if (env.stopFlag) {reject(workerScript); return;}
setTimeout(function() { setTimeout(function() {
//Check if the script is already running //Check if the script is already running
for (var i = 0; i < server.runningScripts.length; ++i) { var runningScriptObj = findRunningScript(scriptname, args, server);
if (server.runningScripts[i] == scriptname) { if (runningScriptObj != null) {
workerScript.scriptRef.log(scriptname + " is already running on " + server.hostname); workerScript.scriptRef.log(scriptname + " is already running on " + server.hostname);
resolve(false); return resolve(false);
return;
}
} }
//Check if the script exists and if it does run it //Check if the script exists and if it does run it
for (var i = 0; i < server.scripts.length; ++i) { for (var i = 0; i < server.scripts.length; ++i) {
if (server.scripts[i].filename == scriptname) { if (server.scripts[i].filename == scriptname) {
//Check for admin rights and that there is enough RAM availble to run //Check for admin rights and that there is enough RAM availble to run
var ramUsage = server.scripts[i].ramUsage; var script = server.scripts[i];
var ramUsage = script.ramUsage;
ramUsage = ramUsage * threads * Math.pow(1.02, threads-1); ramUsage = ramUsage * threads * Math.pow(1.02, threads-1);
var ramAvailable = server.maxRam - server.ramUsed; var ramAvailable = server.maxRam - server.ramUsed;
if (server.hasAdminRights == false) { if (server.hasAdminRights == false) {
workerScript.scriptRef.log("Cannot run script " + scriptname + " on " + server.hostname + " because you do not have root access!"); workerScript.scriptRef.log("Cannot run script " + scriptname + " on " + server.hostname + " because you do not have root access!");
resolve(false); return resolve(false);
return;
} else if (ramUsage > ramAvailable){ } else if (ramUsage > ramAvailable){
workerScript.scriptRef.log("Cannot run script " + scriptname + "(t=" + threads + ") on " + server.hostname + " because there is not enough available RAM!"); workerScript.scriptRef.log("Cannot run script " + scriptname + "(t=" + threads + ") on " + server.hostname + " because there is not enough available RAM!");
resolve(false); return resolve(false);
return;
} else { } else {
//Able to run script //Able to run script
workerScript.scriptRef.log("Running script: " + scriptname + " on " + server.hostname + " with " + threads + " threads. May take a few seconds to start up..."); 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 script = server.scripts[i]; var runningScriptObj = new RunningScript(script, args);
script.threads = threads; runningScriptObj.threads = threads;
server.runningScripts.push(script.filename); //Push onto runningScripts server.runningScripts.push(runningScriptObj); //Push onto runningScripts
addWorkerScript(script, server); addWorkerScript(runningScriptObj, server);
resolve(true); return resolve(true);
return;
} }
} }
} }
@ -1018,7 +1029,10 @@ function scriptCalculateHackingTime(server) {
//The same as Player's calculateExpGain() function but takes in the server as an argument //The same as Player's calculateExpGain() function but takes in the server as an argument
function scriptCalculateExpGain(server) { function scriptCalculateExpGain(server) {
return (server.hackDifficulty * Player.hacking_exp_mult * 0.9); if (server.baseDifficulty == null) {
server.baseDifficulty = server.hackDifficulty;
}
return (server.baseDifficulty * Player.hacking_exp_mult * 0.5 + 4);
} }
//The same as Player's calculatePercentMoneyHacked() function but takes in the server as an argument //The same as Player's calculatePercentMoneyHacked() function but takes in the server as an argument

@ -1,72 +1,76 @@
/* Netscript Functions /* Netscript Functions
* Implementation for Netscript features */ * Implementation for Netscript features */
/* function netscriptArray(exp, workerScript) {
function netscriptAssign(exp, workerScript) {
var env = workerScript.env; var env = workerScript.env;
var arr = env.get(exp.value);
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
if (env.stopFlag) {return reject(workerScript);} if (exp.index == null || exp.index == undefined) {
if ((exp.op.type == "call" && exp.op.func.value == "length") ||
if (exp.left.type != "var") { (exp.op.type == "var" && exp.op.value == "length")) {
return reject(makeRuntimeRejectMsg(workerScript, "Cannot assign to " + JSON.stringify(exp.left))); return resolve(arr.length);
} } else if ((exp.op.type == "call" && exp.op.func.value == "clear") ||
(exp.op.type == "var" && exp.op.value == "clear")) {
//Assigning an element in an array arr.length = 0;
if (exp.left.index) { return resolve(true);
try { } else if (exp.op.type == "call" && exp.op.func.value == "push") {
var res = env.get(exp.left.value); if (exp.op.args.length == 1) {
if (res.constructor === Array || res instanceof Array) { var entry = Object.assign({}, exp.op.args[0]);
var i = 0; arr.push(entry);
var iPromise = evaluate(exp.left.index.value, workerScript); return resolve(true);
iPromise.then(function(idx) {
if (idx >= res.length || idx < 0) {
return reject(makeRuntimeRejectMsg(workerScript, "Out of bounds: Invalid index in [] operator"));
} else {
//TODO evaluate exp.right here....and then determine its type and
//set the type and value below accordingly
i = idx;
return evaluate(exp.right, workerScript);
}
}).then(function(right) {
console.log("evaluate right with result: " + right);
if (right === true || right === false) {
res[i].type = "bool";
res[i].value = right;
} else if (!isNaN(right) || typeof right == 'number') {
res[i].type = "num";
res[i].value = right;
} else { //String
res[i].type = "str";
res[i].value = right.toString();
}
console.log(res);
return resolve(true);
}).then(function(finalRes) {
resolve(finalRes);
}).catch(function(e) {
return reject(e);
});
} else { } else {
return reject(makeRuntimeRejectMsg(workerScript, "Trying to access a non-array variable using the [] operator")); return reject(makeRuntimeRejectMsg(workerScript, "Invalid number of arguments passed into array.push() command. Takes 1 argument"));
} }
} catch(e) { } else {
return reject(makeRuntimeRejectMsg(workerScript, e.toString())); return reject(makeRuntimeRejectMsg(workerScript, "Invalid operation on an array"));
} }
} else {
var expRightPromise = evaluate(exp.right, workerScript);
expRightPromise.then(function(expRight) {
try {
env.set(exp.left.value, expRight);
} catch (e) {
return 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);
});
} }
//The array is being indexed
var indexPromise = evaluate(exp.index.value, workerScript);
indexPromise.then(function(i) {
if (isNaN(i)) {
return reject(makeRuntimeRejectMsg(workerScript, "Invalid access to array. Index is not a number: " + idx));
} else if (i >= arr.length || i < 0) {
return reject(makeRuntimeRejectMsg(workerScript, "Out of bounds: Invalid index in [] operator"));
} else {
if (exp.op && exp.op.type == "call") {
switch(exp.op.func.value) {
case "insert":
if (exp.op.args.length == 1) {
var entry = Object.assign({}, exp.op.args[0]);
arr.splice(i, 0, entry);
return resolve(arr.length);
} else {
return reject(makeRuntimeRejectMsg(workerScript, "Invalid number of arguments passed into array insert() call. Takes 1 argument"));
}
break;
case "remove":
if (exp.op.args.length == 0) {
return resolve(arr.splice(i, 1));
} else {
return reject(makeRuntimeRejectMsg(workerScript, "Invalid number of arguments passed into array remove() call. Takes 1 argument"));
}
break;
default:
return reject(makeRuntimeRejectMsg(workerScript, "Invalid call on array element: " + exp.op.func.value));
break;
}
} else {
//Return the indexed element
var resPromise = evaluate(arr[i], workerScript);
resPromise.then(function(res) {
resolve(res);
}, function(e) {
reject(e);
});
}
}
}, function(e) {
reject(e);
});
}); });
} }
*/
function netscriptAssign(exp, workerScript) { function netscriptAssign(exp, workerScript) {
var env = workerScript.env; var env = workerScript.env;
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
@ -84,7 +88,9 @@ function netscriptAssign(exp, workerScript) {
var i = 0; var i = 0;
var iPromise = evaluate(exp.left.index.value, workerScript); var iPromise = evaluate(exp.left.index.value, workerScript);
iPromise.then(function(idx) { iPromise.then(function(idx) {
if (idx >= res.length || idx < 0) { if (isNaN(idx)) {
return reject(makeRuntimeRejectMsg(workerScript, "Invalid access to array. Index is not a number: " + idx));
} else if (idx >= res.length || idx < 0) {
return reject(makeRuntimeRejectMsg(workerScript, "Out of bounds: Invalid index in [] operator")); return reject(makeRuntimeRejectMsg(workerScript, "Out of bounds: Invalid index in [] operator"));
} else { } else {
//Clone res to be exp.right //Clone res to be exp.right
@ -181,10 +187,12 @@ function netscriptHack(exp, workerScript) {
var moneyGained = scriptCalculatePercentMoneyHacked(server); var moneyGained = scriptCalculatePercentMoneyHacked(server);
moneyGained = Math.floor(server.moneyAvailable * moneyGained) * threads; moneyGained = Math.floor(server.moneyAvailable * moneyGained) * threads;
//Safety check //Over-the-top safety checks
if (moneyGained <= 0) {moneyGained = 0;} if (moneyGained <= 0) {moneyGained = 0;}
if (moneyGained > server.moneyAvailable) {moneyGained = server.moneyAvailable;}
server.moneyAvailable -= moneyGained; server.moneyAvailable -= moneyGained;
if (server.moneyAvailable < 0) {server.moneyAvailable = 0;}
Player.gainMoney(moneyGained); Player.gainMoney(moneyGained);
workerScript.scriptRef.onlineMoneyMade += moneyGained; workerScript.scriptRef.onlineMoneyMade += moneyGained;
workerScript.scriptRef.recordHack(server.ip, moneyGained, threads); workerScript.scriptRef.recordHack(server.ip, moneyGained, threads);
@ -416,7 +424,7 @@ function netscriptRunHttpwormProgram(exp, workerScript, server) {
var env = workerScript.env; var env = workerScript.env;
if (env.stopFlag) {return Promise.reject(workerScript);} if (env.stopFlag) {return Promise.reject(workerScript);}
if (!server.httpPortOpen) { if (!server.httpPortOpen) {
workerScript.scriptRef.log("Executed HTTPWorm.exe virus on " + server.hostname + " to open HTTP port (25)"); workerScript.scriptRef.log("Executed HTTPWorm.exe virus on " + server.hostname + " to open HTTP port (80)");
server.httpPortOpen = true; server.httpPortOpen = true;
++server.openPortCount; ++server.openPortCount;
} else { } else {

@ -216,8 +216,8 @@ function Parser(input) {
unexpected(); unexpected();
} }
function parse_array() { //Declaring a new array with Array[1,2,3]
//Declaring a new array with Array[1,2,3] function parse_arraydecl() {
var array = delimited("[", "]", ",", parse_expression); var array = delimited("[", "]", ",", parse_expression);
return {type: "var", return {type: "var",
value: "array", value: "array",
@ -225,14 +225,38 @@ function Parser(input) {
}; };
} }
//Parsing an operation on an array, such as accessing, push(), etc.
//tok is a reference to a token of type var
function parse_arrayop(tok) {
//Returns a variable node except with an extra "index" field so
//we can identify it as an index
if (is_punc("[")) {
var index = parse_arrayindex();
if (index.type != "index") {
unexpected();
}
}
var op = null;
if (is_punc(".")) {
checkPuncAndSkip(".");
op = maybe_call(function() {
var callTok = input.next();
return callTok;
});
}
tok.index = index;
tok.op = op; //Will be null if no operation
return tok;
}
function parse_arrayindex() { function parse_arrayindex() {
var index = delimited("[", "]", ";", parse_expression); var index = delimited("[", "]", ";", parse_expression);
var val = 0; var val = 0;
if (index.length == 1 && (index[0].type == "num" || index[0].type == "var")) { if (index.length == 1) {
val = index[0]; val = index[0];
} else { } else {
val = 0; unexpected();
console.log("WARNING: Extra indices passed in")
} }
return { type: "index", value: val }; return { type: "index", value: val };
@ -267,16 +291,9 @@ function Parser(input) {
var tok = input.next(); var tok = input.next();
if (tok.type == "var" && tok.value == "hacknetnodes") return parse_hacknetnodes(); if (tok.type == "var" && tok.value == "hacknetnodes") return parse_hacknetnodes();
if (tok.type == "var" && tok.value == "Array") return parse_array(); if (tok.type == "var" && tok.value == "Array") return parse_arraydecl();
if (tok.type == "var" && is_punc("[")) { if (tok.type == "var" && (is_punc("[") || is_punc("."))) {
//Returns a variable node except with an extra "index" field so return parse_arrayop(tok);
//we can identify it as an index
var index = parse_arrayindex();
if (index.type != "index") {
unexpected();
}
tok.index = index;
return tok;
} }
if (tok.type == "var" || tok.type == "num" || tok.type == "str") if (tok.type == "var" || tok.type == "num" || tok.type == "str")
return tok; return tok;

@ -3,16 +3,17 @@
//TODO Tested For and while and generic call statements. Have not tested if statements //TODO Tested For and while and generic call statements. Have not tested if statements
/* Actual Worker Code */ /* Actual Worker Code */
function WorkerScript(script) { function WorkerScript(runningScriptObj) {
this.name = ""; this.name = runningScriptObj.filename;
this.running = false; this.running = false;
this.serverIp = null; this.serverIp = null;
this.code = ""; this.code = runningScriptObj.scriptRef.code;
this.env = new Environment(); this.env = new Environment();
this.output = ""; this.output = "";
this.ramUsage = 0; this.ramUsage = 0;
this.scriptRef = script; this.scriptRef = runningScriptObj;
this.errorMessage = ""; this.errorMessage = "";
this.args = runningScriptObj.args;
} }
//Returns the server on which the workerScript is running //Returns the server on which the workerScript is running
@ -47,33 +48,12 @@ function runScriptsLoop() {
console.log("Stopping script " + w.name + " because it finished running naturally"); console.log("Stopping script " + w.name + " because it finished running naturally");
w.running = false; w.running = false;
w.env.stopFlag = true; w.env.stopFlag = true;
w.scriptRef.log("Script finished running");
}, function(w) { }, function(w) {
if (w instanceof Error) { if (w instanceof Error) {
//Error text format: |serverip|scriptname|error message dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer");
var errorText = w.toString(); console.log("ERROR: Evaluating workerscript returns an Error. THIS SHOULDN'T HAPPEN");
if (Engine.Debug) { return;
console.log("Error in script: " + errorText);
}
var errorTextArray = errorText.split("|");
if (errorTextArray.length != 4) {
console.log("ERROR: Something wrong with Error text in evaluator...");
console.log("Error text: " + errorText);
return;
}
var serverIp = errorTextArray[1];
var scriptName = errorTextArray[2];
var errorMsg = errorTextArray[3];
dialogBoxCreate("Script runtime error:<br>Server Ip: " + serverIp + "<br>Script name: " + scriptName + "<br>" + errorMsg);
//Find the corresponding workerscript and set its flags to kill it
for (var i = 0; i < workerScripts.length; ++i) {
if (workerScripts[i].serverIp == serverIp && workerScripts[i].name == scriptName) {
workerScripts[i].running = false;
workerScripts[i].env.stopFlag = true;
return;
}
}
} else if (w instanceof WorkerScript) { } else if (w instanceof WorkerScript) {
if (isScriptErrorMessage(w.errorMessage)) { if (isScriptErrorMessage(w.errorMessage)) {
var errorTextArray = w.errorMessage.split("|"); var errorTextArray = w.errorMessage.split("|");
@ -86,31 +66,20 @@ function runScriptsLoop() {
var scriptName = errorTextArray[2]; var scriptName = errorTextArray[2];
var errorMsg = errorTextArray[3]; var errorMsg = errorTextArray[3];
dialogBoxCreate("Script runtime error: <br>Server Ip: " + serverIp + "<br>Script name: " + scriptName + "<br>" + errorMsg); dialogBoxCreate("Script runtime error: <br>Server Ip: " + serverIp +
"<br>Script name: " + scriptName +
"<br>Args:" + printArray(w.args) + "<br>" + errorMsg);
w.scriptRef.log("Script crashed with runtime error");
} else {
w.scriptRef.log("Script killed");
} }
w.running = false; w.running = false;
w.env.stopFlag = true; w.env.stopFlag = true;
} else if (isScriptErrorMessage(w)) { } else if (isScriptErrorMessage(w)) {
var errorTextArray = errorText.split("|"); dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer");
if (errorTextArray.length != 4) { console.log("ERROR: Evaluating workerscript returns only error message rather than WorkerScript object. THIS SHOULDN'T HAPPEN");
console.log("ERROR: Something wrong with Error text in evaluator..."); return;
console.log("Error text: " + errorText);
return;
}
var serverIp = errorTextArray[1];
var scriptName = errorTextArray[2];
var errorMsg = errorTextArray[3];
dialogBoxCreate("Script runtime error: <br>Server Ip: " + serverIp + "<br>Script name: " + scriptName + "<br>" + errorMsg);
//Find the corresponding workerscript and set its flags to kill it
for (var i = 0; i < workerScripts.length; ++i) {
if (workerScripts[i].serverIp == serverIp && workerScripts[i].name == scriptName) {
workerScripts[i].running = false;
workerScripts[i].env.stopFlag = true;
return;
}
}
} else { } else {
dialogBoxCreate("An unknown script died for an unknown reason. This is a bug please contact game dev"); dialogBoxCreate("An unknown script died for an unknown reason. This is a bug please contact game dev");
} }
@ -127,7 +96,8 @@ function runScriptsLoop() {
var ip = workerScripts[i].serverIp; var ip = workerScripts[i].serverIp;
var name = workerScripts[i].name; var name = workerScripts[i].name;
for (var j = 0; j < AllServers[ip].runningScripts.length; j++) { for (var j = 0; j < AllServers[ip].runningScripts.length; j++) {
if (AllServers[ip].runningScripts[j] == name) { if (AllServers[ip].runningScripts[j].filename == name &&
compareArrays(AllServers[ip].runningScripts[j].args, workerScripts[i].args)) {
AllServers[ip].runningScripts.splice(j, 1); AllServers[ip].runningScripts.splice(j, 1);
break; break;
} }
@ -150,9 +120,10 @@ function runScriptsLoop() {
//Queues a script to be killed by settings its stop flag to true. Then, the code will reject //Queues a script to be killed by settings its stop flag to true. Then, the code will reject
//all of its promises recursively, and when it does so it will no longer be running. //all of its promises recursively, and when it does so it will no longer be running.
//The runScriptsLoop() will then delete the script from worker scripts //The runScriptsLoop() will then delete the script from worker scripts
function killWorkerScript(scriptName, serverIp) { function killWorkerScript(runningScriptObj, serverIp) {
for (var i = 0; i < workerScripts.length; i++) { for (var i = 0; i < workerScripts.length; i++) {
if (workerScripts[i].name == scriptName && workerScripts[i].serverIp == serverIp) { if (workerScripts[i].name == runningScriptObj.filename && workerScripts[i].serverIp == serverIp &&
compareArrays(workerScripts[i].args, runningScriptObj.args)) {
workerScripts[i].env.stopFlag = true; workerScripts[i].env.stopFlag = true;
return true; return true;
} }
@ -161,23 +132,21 @@ function killWorkerScript(scriptName, serverIp) {
} }
//Queues a script to be run //Queues a script to be run
function addWorkerScript(script, server) { function addWorkerScript(runningScriptObj, server) {
var filename = script.filename; var filename = runningScriptObj.filename;
//Update server's ram usage //Update server's ram usage
var threads = 1; var threads = 1;
if (script.threads && !isNaN(script.threads)) { if (runningScriptObj.threads && !isNaN(runningScriptObj.threads)) {
threads = script.threads; threads = runningScriptObj.threads;
} else { } else {
script.threads = 1; runningScriptObj.threads = 1;
} }
var ramUsage = script.ramUsage * threads * Math.pow(1.02, threads-1); var ramUsage = runningScriptObj.scriptRef.ramUsage * threads * Math.pow(1.02, threads-1);
server.ramUsed += ramUsage; server.ramUsed += ramUsage;
//Create the WorkerScript //Create the WorkerScript
var s = new WorkerScript(script); var s = new WorkerScript(runningScriptObj);
s.name = filename;
s.code = script.code;
s.serverIp = server.ip; s.serverIp = server.ip;
s.ramUsage = ramUsage; s.ramUsage = ramUsage;

@ -213,7 +213,7 @@ PlayerObject.prototype.updateSkillLevels = function() {
//The formula is: //The formula is:
// (2 * hacking_chance_multiplier * hacking_skill - requiredLevel) 100 - difficulty // (2 * hacking_chance_multiplier * hacking_skill - requiredLevel) 100 - difficulty
// ----------------------------------------------------------- * ----------------- // ----------------------------------------------------------- * -----------------
// (hacking_chance_multiplier * hacking_skill) 100 // (2 * hacking_chance_multiplier * hacking_skill) 100
PlayerObject.prototype.calculateHackingChance = function() { PlayerObject.prototype.calculateHackingChance = function() {
var difficultyMult = (100 - this.getCurrentServer().hackDifficulty) / 100; var difficultyMult = (100 - this.getCurrentServer().hackDifficulty) / 100;
var skillMult = (2 * this.hacking_chance_mult * this.hacking_skill); var skillMult = (2 * this.hacking_chance_mult * this.hacking_skill);
@ -254,7 +254,11 @@ PlayerObject.prototype.calculatePercentMoneyHacked = function() {
//The formula is: //The formula is:
// difficulty * requiredLevel * hacking_multiplier // difficulty * requiredLevel * hacking_multiplier
PlayerObject.prototype.calculateExpGain = function() { PlayerObject.prototype.calculateExpGain = function() {
return (this.getCurrentServer().hackDifficulty * this.hacking_exp_mult * 0.9); var s = this.getCurrentServer();
if (s.baseDifficulty == null) {
s.baseDifficulty = s.hackDifficulty;
}
return (s.baseDifficulty * this.hacking_exp_mult * 0.5 + 4);
} }
//Hack/Analyze a server. Return the amount of time the hack will take. This lets the Terminal object know how long to disable itself for //Hack/Analyze a server. Return the amount of time the hack will take. This lets the Terminal object know how long to disable itself for

@ -107,7 +107,7 @@ function prestigeAugmentation() {
Player.lastUpdate = new Date().getTime(); Player.lastUpdate = new Date().getTime();
//Delete all running scripts objects //Delete all Worker Scripts objects
for (var i = 0; i < workerScripts.length; ++i) { for (var i = 0; i < workerScripts.length; ++i) {
deleteActiveScriptsItem(workerScripts[i]); deleteActiveScriptsItem(workerScripts[i]);
workerScripts[i].env.stopFlag = true; workerScripts[i].env.stopFlag = true;
@ -158,7 +158,6 @@ function prestigeAugmentation() {
//Reset statistics of all scripts on home computer //Reset statistics of all scripts on home computer
for (var i = 0; i < homeComp.scripts.length; ++i) { for (var i = 0; i < homeComp.scripts.length; ++i) {
var s = homeComp.scripts[i]; var s = homeComp.scripts[i];
s.reset();
} }
//Delete messages on home computer //Delete messages on home computer
homeComp.messages.length = 0; homeComp.messages.length = 0;

@ -72,14 +72,6 @@ function saveAndCloseScriptEditor() {
filename += ".script"; filename += ".script";
//If the current script matches one thats currently running, throw an error
for (var i = 0; i < Player.getCurrentServer().runningScripts.length; i++) {
if (filename == Player.getCurrentServer().runningScripts[i].filename) {
dialogBoxCreate("Cannot write to script that is currently running!");
return;
}
}
//If the current script already exists on the server, overwrite it //If the current script already exists on the server, overwrite it
for (var i = 0; i < Player.getCurrentServer().scripts.length; i++) { for (var i = 0; i < Player.getCurrentServer().scripts.length; i++) {
if (filename == Player.getCurrentServer().scripts[i].filename) { if (filename == Player.getCurrentServer().scripts[i].filename) {
@ -112,22 +104,6 @@ function Script() {
this.code = ""; this.code = "";
this.ramUsage = 0; this.ramUsage = 0;
this.server = ""; //IP of server this script is on this.server = ""; //IP of server this script is on
this.logs = []; //Script logging. Array of strings, with each element being a log entry
//Stats to display on the Scripts menu, and used to determine offline progress
this.offlineRunningTime = 0.01; //Seconds
this.offlineMoneyMade = 0;
this.offlineExpGained = 0;
this.onlineRunningTime = 0.01; //Seconds
this.onlineMoneyMade = 0;
this.onlineExpGained = 0;
this.moneyStolenMap = new AllServersMap();
this.numTimesHackMap = new AllServersMap();
this.numTimesGrowMap = new AllServersMap();
this.numTimesWeakenMap = new AllServersMap();
this.threads = 1;
}; };
//Get the script data from the Script Editor and save it to the object //Get the script data from the Script Editor and save it to the object
@ -145,65 +121,9 @@ Script.prototype.saveScript = function() {
//Calculate/update ram usage, execution time, etc. //Calculate/update ram usage, execution time, etc.
this.updateRamUsage(); this.updateRamUsage();
//Clear the stats when the script is updated
this.reset();
} }
} }
Script.prototype.reset = function() {
this.updateRamUsage();
this.offlineRunningTime = 0.01; //Seconds
this.offlineMoneyMade = 0;
this.offlineExpGained = 0;
this.onlineRunningTime = 0.01; //Seconds
this.onlineMoneyMade = 0;
this.onlineExpGained = 0;
this.logs = [];
if (this.moneyStolenMap != null) {
try {
this.moneyStolenMap.reset();
} catch(e) {
this.moneyStolenMap = null;
}
} else {
this.moneyStolenMap = new AllServersMap();
}
if (this.numTimesHackMap != null) {
try {
this.numTimesHackMap.reset();
} catch(e) {
this.numTimesHackMap = null;
}
} else {
this.numTimesHackMap = new AllServersMap();
}
if (this.numTimesGrowMap != null) {
try {
this.numTimesGrowMap.reset();
} catch(e) {
this.numTimesGrowMap = null;
}
} else {
this.numTimesGrowMap = new AllServersMap();
}
if (this.numTimesWeakenMap != null) {
try {
this.numTimesWeakenMap.reset();
} catch(e) {
this.numTimesWeakenMap = null;
}
} else {
this.numTimesWeakenMap = new AllServersMap();
}
}
//Updates how much RAM the script uses when it is running. //Updates how much RAM the script uses when it is running.
Script.prototype.updateRamUsage = function() { Script.prototype.updateRamUsage = function() {
var baseRam = 1.4; var baseRam = 1.4;
@ -276,50 +196,6 @@ Script.prototype.updateRamUsage = function() {
} }
} }
Script.prototype.log = function(txt) {
if (this.logs.length > CONSTANTS.MaxLogCapacity) {
//Delete first element and add new log entry to the end.
//TODO Eventually it might be better to replace this with circular array
//to improve performance
this.logs.shift();
}
this.logs.push(txt);
}
Script.prototype.displayLog = function() {
for (var i = 0; i < this.logs.length; ++i) {
post(this.logs[i]);
}
}
//Update the moneyStolen and numTimesHack maps when hacking
Script.prototype.recordHack = function(serverIp, moneyGained, n=1) {
if (this.moneyStolenMap == null) {
this.moneyStolenMap = new AllServersMap();
}
if (this.numTimesHackMap == null) {
this.numTimesHackMap = new AllServersMap();
}
this.moneyStolenMap[serverIp] += moneyGained;
this.numTimesHackMap[serverIp] += n;
}
//Update the grow map when calling grow()
Script.prototype.recordGrow = function(serverIp, n=1) {
if (this.numTimesGrowMap == null) {
this.numTimesGrowMap = new AllServersMap();
}
this.numTimesGrowMap[serverIp] += n;
}
//Update the weaken map when calling weaken() {
Script.prototype.recordWeaken = function(serverIp, n=1) {
if (this.numTimesWeakenMap == null) {
this.numTimesWeakenMap = new AllServersMap();
}
this.numTimesWeakenMap[serverIp] += n;
}
Script.prototype.toJSON = function() { Script.prototype.toJSON = function() {
return Generic_toJSON("Script", this); return Generic_toJSON("Script", this);
} }
@ -331,7 +207,6 @@ Script.fromJSON = function(value) {
Reviver.constructors.Script = Script; Reviver.constructors.Script = Script;
//Called when the game is loaded. Loads all running scripts (from all servers) //Called when the game is loaded. Loads all running scripts (from all servers)
//into worker scripts so that they will start running //into worker scripts so that they will start running
loadAllRunningScripts = function() { loadAllRunningScripts = function() {
@ -346,13 +221,10 @@ loadAllRunningScripts = function() {
for (var j = 0; j < server.runningScripts.length; ++j) { for (var j = 0; j < server.runningScripts.length; ++j) {
count++; count++;
//runningScripts array contains only names, so find the actual script object addWorkerScript(server.runningScripts[j], server);
var script = server.getScript(server.runningScripts[j]);
if (script == null) {continue;}
addWorkerScript(script, server);
//Offline production //Offline production
total += scriptCalculateOfflineProduction(script); total += scriptCalculateOfflineProduction(server.runningScripts[j]);
} }
} }
} }
@ -360,7 +232,7 @@ loadAllRunningScripts = function() {
console.log("Loaded " + count.toString() + " running scripts"); console.log("Loaded " + count.toString() + " running scripts");
} }
scriptCalculateOfflineProduction = function(script) { scriptCalculateOfflineProduction = function(runningScriptObj) {
//The Player object stores the last update time from when we were online //The Player object stores the last update time from when we were online
var thisUpdate = new Date().getTime(); var thisUpdate = new Date().getTime();
var lastUpdate = Player.lastUpdate; var lastUpdate = Player.lastUpdate;
@ -370,26 +242,38 @@ scriptCalculateOfflineProduction = function(script) {
//Calculate the "confidence" rating of the script's true production. This is based //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 //entirely off of time. We will arbitrarily say that if a script has been running for
//4 hours (14400 sec) then we are completely confident in its ability //4 hours (14400 sec) then we are completely confident in its ability
var confidence = (script.onlineRunningTime) / 14400; var confidence = (runningScriptObj.onlineRunningTime) / 14400;
if (confidence >= 1) {confidence = 1;} if (confidence >= 1) {confidence = 1;}
console.log("onlineRunningTime: " + script.onlineRunningTime);
console.log("Confidence: " + confidence);
var totalOfflineProduction = 0; //Grow
for (var ip in script.moneyStolenMap) { for (var ip in runningScriptObj.numTimesGrowMap) {
if (script.moneyStolenMap.hasOwnProperty(ip)) { if (runningScriptObj.numTimesGrowMap.hasOwnProperty(ip)) {
if (script.moneyStolenMap[ip] == 0 || script.moneyStolenMap[ip] == null) {continue;} if (runningScriptObj.numTimesGrowMap[ip] == 0 || runningScriptObj.numTimesGrowMap[ip] == null) {continue;}
var serv = AllServers[ip]; var serv = AllServers[ip];
if (serv == null) {continue;} if (serv == null) {continue;}
var production = 0.5 * script.moneyStolenMap[ip] / script.onlineRunningTime * timePassed; var timesGrown = Math.round(0.5 * runningScriptObj.numTimesGrowMap[ip] / runningScriptObj.onlineRunningTime * timePassed);
console.log(runningScriptObj.filename + " called grow() on " + serv.hostname + " " + timesGrown + " times while offline");
runningScriptObj.log("Called grow() on " + serv.hostname + " " + timesGrown + " times while offline");
var growth = processSingleServerGrowth(serv, timesGrown * 450);
runningScriptObj.log(serv.hostname + " grown by " + formatNumber(growth * 100 - 100, 6) + "% from grow() calls made while offline");
}
}
var totalOfflineProduction = 0;
for (var ip in runningScriptObj.moneyStolenMap) {
if (runningScriptObj.moneyStolenMap.hasOwnProperty(ip)) {
if (runningScriptObj.moneyStolenMap[ip] == 0 || runningScriptObj.moneyStolenMap[ip] == null) {continue;}
var serv = AllServers[ip];
if (serv == null) {continue;}
var production = 0.5 * runningScriptObj.moneyStolenMap[ip] / runningScriptObj.onlineRunningTime * timePassed;
production *= confidence; production *= confidence;
if (production > serv.moneyAvailable) { if (production > serv.moneyAvailable) {
production = serv.moneyAvailable; production = serv.moneyAvailable;
} }
totalOfflineProduction += production; totalOfflineProduction += production;
Player.gainMoney(production); Player.gainMoney(production);
console.log(script.filename + " generated $" + production + " while offline by hacking " + serv.hostname); console.log(runningScriptObj.filename + " generated $" + production + " while offline by hacking " + serv.hostname);
script.log(script.filename + " generated $" + production + " while offline by hacking " + serv.hostname); runningScriptObj.log(runningScriptObj.filename + " generated $" + production + " while offline by hacking " + serv.hostname);
serv.moneyAvailable -= production; serv.moneyAvailable -= production;
if (serv.moneyAvailable < 0) {serv.moneyAvailable = 0;} if (serv.moneyAvailable < 0) {serv.moneyAvailable = 0;}
} }
@ -397,60 +281,148 @@ scriptCalculateOfflineProduction = function(script) {
//Offline EXP gain //Offline EXP gain
//A script's offline production will always be at most half of its online production. //A script's offline production will always be at most half of its online production.
var expGain = 0.5 * (script.onlineExpGained / script.onlineRunningTime) * timePassed; var expGain = 0.5 * (runningScriptObj.onlineExpGained / runningScriptObj.onlineRunningTime) * timePassed;
expGain *= confidence; expGain *= confidence;
Player.gainHackingExp(expGain); Player.gainHackingExp(expGain);
//Update script stats //Update script stats
script.offlineMoneyMade += totalOfflineProduction; runningScriptObj.offlineMoneyMade += totalOfflineProduction;
script.offlineRunningTime += timePassed; runningScriptObj.offlineRunningTime += timePassed;
script.offlineExpGained += expGain; runningScriptObj.offlineExpGained += expGain;
//Fortify a server's security based on how many times it was hacked //Fortify a server's security based on how many times it was hacked
for (var ip in script.numTimesHackMap) { for (var ip in runningScriptObj.numTimesHackMap) {
if (script.numTimesHackMap.hasOwnProperty(ip)) { if (runningScriptObj.numTimesHackMap.hasOwnProperty(ip)) {
if (script.numTimesHackMap[ip] == 0 || script.numTimesHackMap[ip] == null) {continue;} if (runningScriptObj.numTimesHackMap[ip] == 0 || runningScriptObj.numTimesHackMap[ip] == null) {continue;}
var serv = AllServers[ip]; var serv = AllServers[ip];
if (serv == null) {continue;} if (serv == null) {continue;}
var timesHacked = Math.round(0.5 * script.numTimesHackMap[ip] / script.onlineRunningTime * timePassed); var timesHacked = Math.round(0.5 * runningScriptObj.numTimesHackMap[ip] / runningScriptObj.onlineRunningTime * timePassed);
console.log(script.filename + " hacked " + serv.hostname + " " + timesHacked + " times while offline"); console.log(runningScriptObj.filename + " hacked " + serv.hostname + " " + timesHacked + " times while offline");
script.log("Hacked " + serv.hostname + " " + timesHacked + " times while offline"); runningScriptObj.log("Hacked " + serv.hostname + " " + timesHacked + " times while offline");
serv.fortify(CONSTANTS.ServerFortifyAmount * timesHacked); serv.fortify(CONSTANTS.ServerFortifyAmount * timesHacked);
} }
} }
//Weaken //Weaken
for (var ip in script.numTimesWeakenMap) { for (var ip in runningScriptObj.numTimesWeakenMap) {
if (script.numTimesWeakenMap.hasOwnProperty(ip)) { if (runningScriptObj.numTimesWeakenMap.hasOwnProperty(ip)) {
if (script.numTimesWeakenMap[ip] == 0 || script.numTimesWeakenMap[ip] == null) {continue;} if (runningScriptObj.numTimesWeakenMap[ip] == 0 || runningScriptObj.numTimesWeakenMap[ip] == null) {continue;}
var serv = AllServers[ip]; var serv = AllServers[ip];
if (serv == null) {continue;} if (serv == null) {continue;}
var timesWeakened = Math.round(0.5 * script.numTimesWeakenMap[ip] / script.onlineRunningTime * timePassed); var timesWeakened = Math.round(0.5 * runningScriptObj.numTimesWeakenMap[ip] / runningScriptObj.onlineRunningTime * timePassed);
console.log(script.filename + " called weaken() on " + serv.hostname + " " + timesWeakened + " times while offline"); console.log(runningScriptObj.filename + " called weaken() on " + serv.hostname + " " + timesWeakened + " times while offline");
script.log("Called weaken() on " + serv.hostname + " " + timesWeakened + " times while offline"); runningScriptObj.log("Called weaken() on " + serv.hostname + " " + timesWeakened + " times while offline");
serv.weaken(CONSTANTS.ServerWeakenAmount * timesWeakened); serv.weaken(CONSTANTS.ServerWeakenAmount * timesWeakened);
} }
} }
//Grow
for (var ip in script.numTimesGrowMap) {
if (script.numTimesGrowMap.hasOwnProperty(ip)) {
if (script.numTimesGrowMap[ip] == 0 || script.numTimesGrowMap[ip] == null) {continue;}
var serv = AllServers[ip];
if (serv == null) {continue;}
var timesGrown = Math.round(0.5 * script.numTimesGrowMap[ip] / script.onlineRunningTime * timePassed);
console.log(script.filename + " called grow() on " + serv.hostname + " " + timesGrown + " times while offline");
script.log("Called grow() on " + serv.hostname + " " + timesGrown + " times while offline");
var growth = processSingleServerGrowth(serv, timesGrown * 450);
script.log(serv.hostname + " grown by " + formatNumber(growth * 100 - 100, 6) + "% from grow() calls made while offline");
}
}
return totalOfflineProduction; return totalOfflineProduction;
} }
//Creates a function that creates a map/dictionary with the IP of each existing server as //Returns a RunningScript object matching the filename and arguments on the
//designated server, and false otherwise
function findRunningScript(filename, args, server) {
for (var i = 0; i < server.runningScripts.length; ++i) {
if (server.runningScripts[i].filename == filename &&
compareArrays(server.runningScripts[i].args, args)) {
return server.runningScripts[i];
}
}
return null;
}
function RunningScript(script, args) {
if (script == null || script == undefined) {return;}
this.filename = script.filename;
this.args = args;
this.scriptRef = script;
this.server = script.server; //IP Address only
this.logs = []; //Script logging. Array of strings, with each element being a log entry
//Stats to display on the Scripts menu, and used to determine offline progress
this.offlineRunningTime = 0.01; //Seconds
this.offlineMoneyMade = 0;
this.offlineExpGained = 0;
this.onlineRunningTime = 0.01; //Seconds
this.onlineMoneyMade = 0;
this.onlineExpGained = 0;
this.threads = 1;
this.moneyStolenMap = new AllServersMap();
this.numTimesHackMap = new AllServersMap();
this.numTimesGrowMap = new AllServersMap();
this.numTimesWeakenMap = new AllServersMap();
}
RunningScript.prototype.reset = function() {
this.scriptRef.updateRamUsage();
this.offlineRunningTime = 0.01; //Seconds
this.offlineMoneyMade = 0;
this.offlineExpGained = 0;
this.onlineRunningTime = 0.01; //Seconds
this.onlineMoneyMade = 0;
this.onlineExpGained = 0;
this.logs = [];
}
RunningScript.prototype.log = function(txt) {
if (this.logs.length > CONSTANTS.MaxLogCapacity) {
//Delete first element and add new log entry to the end.
//TODO Eventually it might be better to replace this with circular array
//to improve performance
this.logs.shift();
}
this.logs.push(txt);
}
RunningScript.prototype.displayLog = function() {
for (var i = 0; i < this.logs.length; ++i) {
post(this.logs[i]);
}
}
//Update the moneyStolen and numTimesHack maps when hacking
RunningScript.prototype.recordHack = function(serverIp, moneyGained, n=1) {
if (this.moneyStolenMap == null) {
this.moneyStolenMap = new AllServersMap();
}
if (this.numTimesHackMap == null) {
this.numTimesHackMap = new AllServersMap();
}
this.moneyStolenMap[serverIp] += moneyGained;
this.numTimesHackMap[serverIp] += n;
}
//Update the grow map when calling grow()
RunningScript.prototype.recordGrow = function(serverIp, n=1) {
if (this.numTimesGrowMap == null) {
this.numTimesGrowMap = new AllServersMap();
}
this.numTimesGrowMap[serverIp] += n;
}
//Update the weaken map when calling weaken() {
RunningScript.prototype.recordWeaken = function(serverIp, n=1) {
if (this.numTimesWeakenMap == null) {
this.numTimesWeakenMap = new AllServersMap();
}
this.numTimesWeakenMap[serverIp] += n;
}
RunningScript.prototype.toJSON = function() {
return Generic_toJSON("RunningScript", this);
}
RunningScript.fromJSON = function(value) {
return Generic_fromJSON(RunningScript, value.data);
}
//Creates an object that creates a map/dictionary with the IP of each existing server as
//a key, and 0 as the value. This is used to keep track of how much money a script //a key, and 0 as the value. This is used to keep track of how much money a script
//hacks from that server //hacks from that server
function AllServersMap() { function AllServersMap() {

@ -21,7 +21,7 @@ function Server() {
this.cpuSpeed = 1; //MHz this.cpuSpeed = 1; //MHz
this.scripts = []; this.scripts = [];
this.runningScripts = []; //Names (and only names) of scripts being run this.runningScripts = []; //Stores RunningScript objects
this.programs = []; this.programs = [];
this.messages = []; this.messages = [];
@ -695,7 +695,7 @@ processSingleServerGrowth = function(server, numCycles) {
var numServerGrowthCyclesAdjusted = numServerGrowthCycles * serverGrowthPercentage; var numServerGrowthCyclesAdjusted = numServerGrowthCycles * serverGrowthPercentage;
//Apply serverGrowth for the calculated number of growth cycles //Apply serverGrowth for the calculated number of growth cycles
var serverGrowth = Math.pow(adjGrowthRate, numServerGrowthCyclesAdjusted * Player.hacking_grow_mult) ; var serverGrowth = Math.pow(adjGrowthRate, numServerGrowthCyclesAdjusted * Player.hacking_grow_mult);
if (serverGrowth < 1) { if (serverGrowth < 1) {
console.log("WARN: serverGrowth calculated to be less than 1"); console.log("WARN: serverGrowth calculated to be less than 1");
serverGrowth = 1; serverGrowth = 1;

@ -2,18 +2,18 @@
/* Write text to terminal */ /* Write text to terminal */
var post = function(input) { var post = function(input) {
$("#terminal-input").before('<tr class="posted"><td style="color: #66ff33;">' + input.replace( / /g, "&nbsp;" ) + '</td></tr>'); $("#terminal-input").before('<tr class="posted"><td style="color: var(--my-font-color); background-color: var(--my-background-color);">' + input.replace( / /g, "&nbsp;" ) + '</td></tr>');
updateTerminalScroll(); updateTerminalScroll();
} }
//Same thing as post but the td cells have ids so they can be animated for the hack progress bar //Same thing as post but the td cells have ids so they can be animated for the hack progress bar
var hackProgressBarPost = function(input) { var hackProgressBarPost = function(input) {
$("#terminal-input").before('<tr class="posted"><td id="hack-progress-bar" style="color: #66ff33;">' + input + '</td></tr>'); $("#terminal-input").before('<tr class="posted"><td id="hack-progress-bar" style="color: var(--my-font-color); background-color: var(--my-background-color);">' + input + '</td></tr>');
updateTerminalScroll(); updateTerminalScroll();
} }
var hackProgressPost = function(input) { var hackProgressPost = function(input) {
$("#terminal-input").before('<tr class="posted"><td id="hack-progress" style="color: #66ff33;">' + input + '</td></tr>'); $("#terminal-input").before('<tr class="posted"><td id="hack-progress" style="color: var(--my-font-color); background-color: var(--my-background-color);">' + input + '</td></tr>');
updateTerminalScroll(); updateTerminalScroll();
} }
@ -235,10 +235,16 @@ function determineAllPossibilitiesForTabCompletion(input, index=0) {
//Autocomplete the command //Autocomplete the command
if (index == -1) { if (index == -1) {
return ["alias", "analyze", "cat", "clear", "cls", "connect", "free", return ["alias", "analyze", "cat", "check", "clear", "cls", "connect", "free",
"hack", "help", "home", "hostname", "ifconfig", "kill", "killall", "hack", "help", "home", "hostname", "ifconfig", "kill", "killall",
"ls", "mem", "nano", "ps", "rm", "run", "scan", "scan-analyze", "ls", "mem", "nano", "ps", "rm", "run", "scan", "scan-analyze",
"scp", "sudov", "tail", "top"]; "scp", "sudov", "tail", "theme", "top"];
}
if (input.startsWith ("buy ")) {
return [Programs.BruteSSHProgram, Programs.FTPCrackProgram, Programs.RelaySMTPProgram,
Programs.HTTPWormProgram, Programs.SQLInjectProgram, Programs.DeepscanV1,
Programs.DeepscanV2];
} }
if (input.startsWith("scp ") && index == 1) { if (input.startsWith("scp ") && index == 1) {
@ -263,7 +269,7 @@ function determineAllPossibilitiesForTabCompletion(input, index=0) {
if (input.startsWith("kill ") || input.startsWith("nano ") || if (input.startsWith("kill ") || input.startsWith("nano ") ||
input.startsWith("tail ") || input.startsWith("rm ") || input.startsWith("tail ") || input.startsWith("rm ") ||
input.startsWith("mem ") || input.startsWith("mem ") || input.startsWith("check ") ||
(input.startsWith("scp ") && index == 0)) { (input.startsWith("scp ") && index == 0)) {
//All Scripts //All Scripts
for (var i = 0; i < currServ.scripts.length; ++i) { for (var i = 0; i < currServ.scripts.length; ++i) {
@ -564,6 +570,7 @@ var Terminal = {
/****************** END INTERACTIVE TUTORIAL ******************/ /****************** END INTERACTIVE TUTORIAL ******************/
/* Command parser */ /* Command parser */
var s = Player.getCurrentServer();
switch (commandArray[0].toLowerCase()) { switch (commandArray[0].toLowerCase()) {
case "alias": case "alias":
if (commandArray.length == 1) { if (commandArray.length == 1) {
@ -595,7 +602,11 @@ var Terminal = {
$('input[class=terminal-input]').prop('disabled', true); $('input[class=terminal-input]').prop('disabled', true);
break; break;
case "buy": case "buy":
executeDarkwebTerminalCommand(commandArray); if (SpecialServerIps.hasOwnProperty("Darkweb Server")) {
executeDarkwebTerminalCommand(commandArray);
} else {
post("You need to be connected to the Dark Web to use the buy command");
}
break; break;
case "cat": case "cat":
if (commandArray.length != 2) { if (commandArray.length != 2) {
@ -606,7 +617,6 @@ var Terminal = {
if (filename.endsWith(".msg") == false) { if (filename.endsWith(".msg") == false) {
post("Error: Only .msg files are viewable with cat (filename must end with .msg)"); return; post("Error: Only .msg files are viewable with cat (filename must end with .msg)"); return;
} }
var s = Player.getCurrentServer();
for (var i = 0; i < s.messages.length; ++i) { for (var i = 0; i < s.messages.length; ++i) {
if (s.messages[i].filename == filename) { if (s.messages[i].filename == filename) {
showMessage(s.messages[i]); showMessage(s.messages[i]);
@ -614,6 +624,31 @@ var Terminal = {
} }
} }
post("Error: No such file " + filename); post("Error: No such file " + filename);
break;
case "check":
if (commandArray.length < 2) {
post("Incorrect number of arguments. Usage: check [script] [arg1] [arg2]...");
} else {
var results = commandArray[1].split(" ");
var scriptName = results[0];
var args = [];
for (var i = 1; i < results.length; ++i) {
args.push(results[i]);
}
//Can only tail script files
if (scriptName.endsWith(".script") == false) {
post("Error: tail can only be called on .script files (filename must end with .script)"); return;
}
//Check that the script exists on this machine
var runningScript = findRunningScript(scriptName, args, s);
if (runningScript == null) {
post("Error: No such script exists");
return;
}
logBoxCreate(runningScript);
}
break; break;
case "clear": case "clear":
case "cls": case "cls":
@ -704,23 +739,25 @@ var Terminal = {
post(Player.getCurrentServer().ip); post(Player.getCurrentServer().ip);
break; break;
case "kill": case "kill":
if (commandArray.length != 2) { if (commandArray.length < 2) {
post("Incorrect usage of kill command. Usage: kill [scriptname]"); return; post("Incorrect usage of kill command. Usage: kill [scriptname] [arg1] [arg2]..."); return;
} }
var results = commandArray[1].split(" ");
var scriptName = commandArray[1]; var scriptName = results[0];
for (var i = 0; i < Player.getCurrentServer().runningScripts.length; i++) { var args = [];
if (Player.getCurrentServer().runningScripts[i] == scriptName) { for (var i = 1; i < results.length; ++i) {
killWorkerScript(scriptName, Player.getCurrentServer().ip); args.push(results[i]);
post("Killing " + scriptName + ". May take up to a few minutes for the scripts to die..."); }
return; var runningScript = findRunningScript(scriptName, args, s);
} if (runningScript == null) {
} post("No such script is running. Nothing to kill");
post("No such script is running. Nothing to kill"); return;
}
killWorkerScript(runningScript, s.ip);
post("Killing " + scriptName + ". May take up to a few minutes for the scripts to die...");
break; break;
case "killall": case "killall":
var s = Player.getCurrentServer(); for (var i = s.runningScripts.length-1; i >= 0; --i) {
for (var i = s.runningScripts.length; i >= 0; --i) {
killWorkerScript(s.runningScripts[i], s.ip); killWorkerScript(s.runningScripts[i], s.ip);
} }
post("Killing all running scripts. May take up to a few minutes for the scripts to die..."); post("Killing all running scripts. May take up to a few minutes for the scripts to die...");
@ -788,8 +825,13 @@ var Terminal = {
if (commandArray.length != 1) { if (commandArray.length != 1) {
post("Incorrect usage of ps command. Usage: ps"); return; post("Incorrect usage of ps command. Usage: ps"); return;
} }
for (var i = 0; i < Player.getCurrentServer().runningScripts.length; i++) { for (var i = 0; i < s.runningScripts.length; i++) {
post(Player.getCurrentServer().runningScripts[i]); var rsObj = s.runningScripts[i];
var res = rsObj.filename;
for (var j = 0; j < rsObj.args.length; ++j) {
res += (" " + rsObj.args[j].toString());
}
post(res);
} }
break; break;
case "rm": case "rm":
@ -799,7 +841,6 @@ var Terminal = {
//Check programs //Check programs
var delTarget = commandArray[1]; var delTarget = commandArray[1];
var s = Player.getCurrentServer();
for (var i = 0; i < s.programs.length; ++i) { for (var i = 0; i < s.programs.length; ++i) {
if (s.programs[i] == delTarget) { if (s.programs[i] == delTarget) {
s.programs.splice(i, 1); s.programs.splice(i, 1);
@ -811,11 +852,13 @@ var Terminal = {
for (var i = 0; i < s.scripts.length; ++i) { for (var i = 0; i < s.scripts.length; ++i) {
if (s.scripts[i].filename == delTarget) { if (s.scripts[i].filename == delTarget) {
//Check that the script isnt currently running //Check that the script isnt currently running
if (s.runningScripts.indexOf(delTarget) > -1) { for (var j = 0; j < s.runningScripts.length; ++j) {
post("Cannot delete a script that is currently running!"); if (s.runningScripts[j].filename == delTarget) {
} else { post("Cannot delete a script that is currently running!");
s.scripts.splice(i, 1); return;
}
} }
s.scripts.splice(i, 1);
return; return;
} }
} }
@ -825,7 +868,7 @@ var Terminal = {
case "run": case "run":
//Run a program or a script //Run a program or a script
if (commandArray.length != 2) { if (commandArray.length != 2) {
post("Incorrect number of arguments. Usage: run [program/script] [-t] [number threads]"); post("Incorrect number of arguments. Usage: run [program/script] [-t] [num threads] [arg1] [arg2]...");
} else { } else {
var executableName = commandArray[1]; var executableName = commandArray[1];
//Check if its a script or just a program/executable //Check if its a script or just a program/executable
@ -931,10 +974,15 @@ var Terminal = {
} }
break; break;
case "tail": case "tail":
if (commandArray.length != 2) { if (commandArray.length < 2) {
post("Incorrect number of arguments. Usage: tail [script]"); post("Incorrect number of arguments. Usage: tail [script] [arg1] [arg2]...");
} else { } else {
var scriptName = commandArray[1]; var results = commandArray[1].split(" ");
var scriptName = results[0];
var args = [];
for (var i = 1; i < results.length; ++i) {
args.push(results[i]);
}
//Can only tail script files //Can only tail script files
if (scriptName.endsWith(".script") == false) { if (scriptName.endsWith(".script") == false) {
@ -942,17 +990,52 @@ var Terminal = {
} }
//Check that the script exists on this machine //Check that the script exists on this machine
var currScripts = Player.getCurrentServer().scripts; var runningScript = findRunningScript(scriptName, args, s);
for (var i = 0; i < currScripts.length; ++i) { if (runningScript == null) {
if (scriptName == currScripts[i].filename) { post("Error: No such script exists");
currScripts[i].displayLog(); return;
return;
}
} }
logBoxCreate(runningScript);
post("Error: No such script exists");
} }
break; break;
case "theme":
//todo support theme saving
var args = commandArray[1] ? commandArray[1].split(" ") : [];
if(args.length != 1 && args.length != 3) {
post("Incorrect number of arguments.");
post("Usage: theme [default|muted|solarized] | [background color hex] [text color hex] [highlight color hex]");
}else if(args.length == 1){
var themeName = args[0];
if(themeName == "default"){
document.body.style.setProperty('--my-highlight-color',"#ffffff");
document.body.style.setProperty('--my-font-color',"#66ff33");
document.body.style.setProperty('--my-background-color',"#000000");
}else if(themeName == "muted"){
document.body.style.setProperty('--my-highlight-color',"#ffffff");
document.body.style.setProperty('--my-font-color',"#66ff33");
document.body.style.setProperty('--my-background-color',"#252527");
}else if(themeName == "solarized"){
document.body.style.setProperty('--my-highlight-color',"#6c71c4");
document.body.style.setProperty('--my-font-color',"#839496");
document.body.style.setProperty('--my-background-color',"#002b36");
}else{
post("Theme not found");
}
}else{
inputBackgroundHex = args[0];
inputTextHex = args[1];
inputHighlightHex = args[2];
if(/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(inputBackgroundHex) &&
/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(inputTextHex) &&
/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(inputHighlightHex)){
document.body.style.setProperty('--my-highlight-color',inputHighlightHex);
document.body.style.setProperty('--my-font-color',inputTextHex);
document.body.style.setProperty('--my-background-color',inputBackgroundHex);
}else{
post("Invalid Hex Input for theme");
}
}
break;
case "top": case "top":
//TODO List each's script RAM usage //TODO List each's script RAM usage
post("Not yet implemented"); post("Not yet implemented");
@ -1155,35 +1238,71 @@ var Terminal = {
var server = Player.getCurrentServer(); var server = Player.getCurrentServer();
var numThreads = 1; var numThreads = 1;
//Get the number of threads var args = [];
if (scriptName.indexOf(" -t ") != -1) { var results = scriptName.split(" ");
var results = scriptName.split(" "); if (results.length <= 0) {
if (results.length != 3) { post("This is a bug. Please contact developer");
post("Invalid use of run command. Usage: run [script] [-t] [number threads]"); }
return; scriptName = results[0];
if (results.length > 1) {
if (results.length >= 3 && results[1] == "-t") {
numThreads = Math.round(Number(results[2]));
if (isNaN(numThreads) || numThreads < 1) {
post("Invalid number of threads specified. Number of threads must be greater than 0");
return;
}
for (var i = 3; i < results.length; ++i) {
var arg = results[i];
//Forced string
if ((arg.startsWith("'") && arg.endsWith("'")) ||
(arg.startsWith('"') && arg.endsWith('"'))) {
args.push(arg.slice(1, -1));
continue;
}
//Number
var tempNum = Number(arg);
if (!isNaN(tempNum)) {
args.push(tempNum);
continue;
}
//Otherwise string
args.push(arg);
}
} else {
for (var i = 1; i < results.length; ++i) {
var arg = results[i];
//Forced string
if ((arg.startsWith("'") && arg.endsWith("'")) ||
(arg.startsWith('"') && arg.endsWith('"'))) {
args.push(arg.slice(1, -1));
continue;
}
//Number
var tempNum = Number(arg);
if (!isNaN(tempNum)) {
args.push(tempNum);
continue;
}
//Otherwise string
args.push(arg);
}
} }
numThreads = Math.round(Number(results[2]));
if (isNaN(numThreads) || numThreads < 1) {
post("Invalid number of threads specified. Number of threads must be greater than 0");
return;
}
scriptName = results[0];
} }
//Check if this script is already running //Check if this script is already running
for (var i = 0; i < server.runningScripts.length; i++) { if (findRunningScript(scriptName, args, server) != null) {
if (server.runningScripts[i] == scriptName) { post("ERROR: This script is already running. Cannot run multiple instances");
post("ERROR: This script is already running. Cannot run multiple instances"); return;
return; }
}
}
//Check if the script exists and if it does run it //Check if the script exists and if it does run it
for (var i = 0; i < server.scripts.length; i++) { for (var i = 0; i < server.scripts.length; i++) {
if (server.scripts[i].filename == scriptName) { if (server.scripts[i].filename == scriptName) {
//Check for admin rights and that there is enough RAM availble to run //Check for admin rights and that there is enough RAM availble to run
var script = server.scripts[i]; var script = server.scripts[i];
script.threads = numThreads;
var ramUsage = script.ramUsage * numThreads * Math.pow(1.02, numThreads-1); var ramUsage = script.ramUsage * numThreads * Math.pow(1.02, numThreads-1);
var ramAvailable = server.maxRam - server.ramUsed; var ramAvailable = server.maxRam - server.ramUsed;
@ -1192,13 +1311,17 @@ var Terminal = {
return; return;
} else if (ramUsage > ramAvailable){ } else if (ramUsage > ramAvailable){
post("This machine does not have enough RAM to run this script with " + post("This machine does not have enough RAM to run this script with " +
script.threads + " threads. Script requires " + ramUsage + "GB of RAM"); numThreads + " threads. Script requires " + ramUsage + "GB of RAM");
return; return;
}else { } else {
//Able to run script //Able to run script
post("Running script with " + script.threads + " thread(s). May take a few seconds to start up the process..."); post("Running script with " + numThreads + " thread(s) and args: " + printArray(args) + ".");
server.runningScripts.push(script.filename); //Push onto runningScripts post("May take a few seconds to start up the process...");
addWorkerScript(script, server); var runningScriptObj = new RunningScript(script, args);
runningScriptObj.threads = numThreads;
server.runningScripts.push(runningScriptObj);
addWorkerScript(runningScriptObj, server);
return; return;
} }
} }

@ -545,6 +545,10 @@ var Engine = {
displayCreateProgramContent(); displayCreateProgramContent();
} }
if (logBoxOpened) {
logBoxUpdateText();
}
Engine.Counters.updateDisplays = 3; Engine.Counters.updateDisplays = 3;
} }
@ -908,13 +912,17 @@ var Engine = {
return false; return false;
}); });
//Character Overview Save button //Character Overview buttons
var charOverviewSaveButton = document.getElementById("character-overview-save-button"); document.getElementById("character-overview-save-button").addEventListener("click", function() {
charOverviewSaveButton.addEventListener("click", function() {
saveObject.saveGame(); saveObject.saveGame();
return false; return false;
}); });
document.getElementById("character-overview-options-button").addEventListener("click", function() {
gameOptionsBoxOpen();
return false;
});
//Script Editor Netscript documentation button //Script Editor Netscript documentation button
var netscriptDocButton = document.getElementById("script-editor-netscript-doc-button"); var netscriptDocButton = document.getElementById("script-editor-netscript-doc-button");
netscriptDocButton.addEventListener("click", function() { netscriptDocButton.addEventListener("click", function() {

@ -2,22 +2,6 @@
dialogBoxes = []; dialogBoxes = [];
//Close dialog box when clicking outside //Close dialog box when clicking outside
/*
$(document).click(function(event) {
if (dialogBoxOpened) {
if (!$(event.target).closest('.dialog-box-container').length){
--dialogBoxCount;
dialogBoxes.splice(0, 1);
$(".dialog-box-container").remove();
if (dialogBoxes.length == 0) {
dialogBoxOpened = false;
} else {
dialogBoxes[0].style.display +
}
}
}
});*/
$(document).click(function(event) { $(document).click(function(event) {
if (dialogBoxOpened && dialogBoxes.length >= 1) { if (dialogBoxOpened && dialogBoxes.length >= 1) {
if (!$(event.target).closest(dialogBoxes[0]).length){ if (!$(event.target).closest(dialogBoxes[0]).length){
@ -34,18 +18,6 @@ $(document).click(function(event) {
//Dialog box close buttons //Dialog box close buttons
/*
$(document).on('click', '.dialog-box-close-button', function( event ) {
console.log("clicked close button");
if (dialogBoxOpened) {
$(this).closest('.dialog-box-container').remove();
--dialogBoxCount;
if (dialogBoxes.length == 0) {
dialogBoxOpened = false;
}
}
});
*/
$(document).on('click', '.dialog-box-close-button', function( event ) { $(document).on('click', '.dialog-box-close-button', function( event ) {
if (dialogBoxOpened && dialogBoxes.length >= 1) { if (dialogBoxOpened && dialogBoxes.length >= 1) {
dialogBoxes[0].remove(); dialogBoxes[0].remove();

@ -33,3 +33,20 @@ function clearEventListeners(elemId) {
function getRandomInt(min, max) { function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min; return Math.floor(Math.random() * (max - min + 1)) + min;
} }
//Returns true if all elements are equal, and false otherwise
//Assumes both arguments are arrays and that there are no nested arrays
function compareArrays(a1, a2) {
if (a1.length != a2.length) {
return false;
}
for (var i = 0; i < a1.length; ++i) {
if (a1[i] != a2[i]) {return false;}
}
return true;
}
function printArray(a) {
return "[" + a.join(", ") + "]";
}

59
utils/LogBox.js Normal file

@ -0,0 +1,59 @@
/* Log Box */
//Close box when clicking outside
/*
$(document).click(function(event) {
if (logBoxOpened) {
if ( $(event.target).closest("#log-box-container").get(0) == null ) {
logBoxClose();
}
}
});
*/
function logBoxInit() {
var closeButton = document.getElementById("log-box-close");
logBoxClose();
//Close Dialog box
closeButton.addEventListener("click", function() {
logBoxClose();
return false;
});
};
document.addEventListener("DOMContentLoaded", logBoxInit, false);
logBoxClose = function() {
logBoxOpened = false;
var logBox = document.getElementById("log-box-container");
logBox.style.display = "none";
}
logBoxOpen = function() {
logBoxOpened = true;
var logBox = document.getElementById("log-box-container");
logBox.style.display = "block";
}
var logBoxOpened = false;
var logBoxCurrentScript = null;
//ram argument is in GB
logBoxCreate = function(script) {
logBoxCurrentScript = script;
logBoxOpen();
logBoxUpdateText();
}
logBoxUpdateText = function() {
var txt = document.getElementById("log-box-text");
if (logBoxCurrentScript && logBoxOpened && txt) {
txt.innerHTML = logBoxCurrentScript.filename + ":<br>";
for (var i = 0; i < logBoxCurrentScript.logs.length; ++i) {
txt.innerHTML += logBoxCurrentScript.logs[i];
txt.innerHTML += "<br>";
}
}
}

@ -36,7 +36,7 @@ purchaseRamForHomeBoxCreate = function() {
//Calculate cost //Calculate cost
//Have cost increase by some percentage each time RAM has been upgraded //Have cost increase by some percentage each time RAM has been upgraded
var cost = currentRam * CONSTANTS.BaseCostFor1GBOfRamHome; var cost = currentRam * CONSTANTS.BaseCostFor1GBOfRamHome;
var mult = Math.pow(1.40, numUpgrades); var mult = Math.pow(1.43, numUpgrades);
cost = cost * mult; cost = cost * mult;
purchaseRamForHomeBoxSetText("Would you like to purchase additional RAM for your home computer? <br><br>" + purchaseRamForHomeBoxSetText("Would you like to purchase additional RAM for your home computer? <br><br>" +