Merge pull request #88 from danielyxie/dev

Dev v0.25.0
This commit is contained in:
danielyxie 2017-07-13 12:59:36 -04:00 committed by GitHub
commit 702f70f240
20 changed files with 5131 additions and 2011 deletions

@ -15,21 +15,18 @@
position: fixed;
}
/* Script Editor */
/* This temp element is used for auto adjusting filename field */
.tmp-element {
visibility: hidden;
white-space: pre;
}
#script-editor-container {
position: fixed;
padding-top: 10px;
}
#script-editor-buttons-wrapper {
width: 100%;
padding-right: 0xp;
@ -37,10 +34,15 @@
}
#script-editor-save-and-close-button,
#script-editor-netscript-doc-button {
#script-editor-netscript-doc-button,
#script-editor-status-text {
display: inline-block;
}
#script-editor-status-text {
margin: 10px;
}
#script-editor-save-and-close-button {
float:left;
}

@ -94,6 +94,10 @@ tr:focus {
}
/* Make html links ("a" elements) nice looking buttons with this class */
a:link, a:visited {
color:white;
}
.a-link-button {
text-decoration: none;
background-color: #555;

@ -30,12 +30,10 @@
<!-- Netscript -->
<script src="src/NetscriptWorker.js"></script>
<script src="src/NetscriptInputStream.js"></script>
<script src="src/NetscriptTokenizer.js"></script>
<script src="src/NetscriptParser.js"></script>
<script src="src/NetscriptEvaluator.js"></script>
<script src="src/NetscriptEnvironment.js"></script>
<script src="src/NetscriptFunctions.js"></script>
<script src="utils/acorn.js"></script>
<!-- Main game files -->
<script src="src/Constants.js"></script>
@ -150,6 +148,7 @@
<textarea id="script-editor-text" tabindex="2" autofocus> </textarea>
<div id="script-editor-buttons-wrapper">
<span id="script-editor-save-and-close-button" class="a-link-button">Save & Close (Ctrl + b)</span>
<p id="script-editor-status-text"> </p>
<span id="script-editor-netscript-doc-button" class="a-link-button"> Netscript Documentation </span>
</div>
</div>
@ -746,7 +745,7 @@
you 'reset' by installing Augmentations.
</p>
<a id="stock-market-buy-tix-api" class="a-link-button-inactive">
Buy Trade Information eXchange (TEX) API Access - COMING SOON
Buy Trade Information eXchange (TIX) API Access - COMING SOON
</a>
<p id="stock-market-commission"> </p>

@ -162,7 +162,7 @@ initAugmentations = function() {
//Combat stat augmentations
var HemoRecirculator = new Augmentation(AugmentationNames.HemoRecirculator);
HemoRecirculator.setInfo("A heart implant that greatly increases the body's ability to effectively use and pump " +
"blood. <br><br> This augmentation increases all of the player's combat stats by 10%.")
"blood. <br><br> This augmentation increases all of the player's combat stats by 8%.")
HemoRecirculator.setRequirements(4000, 9000000);
HemoRecirculator.addToFactions(["Tetrads", "The Dark Army", "The Syndicate"]);
if (augmentationExists(AugmentationNames.HemoRecirculator)) {
@ -175,7 +175,7 @@ initAugmentations = function() {
Targeting1.setInfo("This cranial implant is embedded within the player's inner ear structure and optic nerves. It regulates and enhances the user's " +
"balance and hand-eye coordination. It is also capable of augmenting reality by projecting digital information " +
"directly onto the retina. These enhancements allow the player to better lock-on and keep track of enemies. <br><br>" +
"This augmentation increases the player's dexterity by 15%.");
"This augmentation increases the player's dexterity by 10%.");
Targeting1.addToFactions(["Slum Snakes", "The Dark Army", "The Syndicate", "Sector-12", "Volhaven", "Ishima",
"OmniTek Incorporated", "KuaiGong International", "Blade Industries"]);
if (augmentationExists(AugmentationNames.Targeting1)) {
@ -187,7 +187,7 @@ initAugmentations = function() {
Targeting2.setRequirements(3500, 8500000);
Targeting2.setInfo("This is an upgrade of the Augmented Targeting I cranial implant, which is capable of augmenting reality " +
"and enhances the user's balance and hand-eye coordination. <br><br>This upgrade increases the player's dexterity " +
"by an additional 25%.");
"by an additional 20%.");
Targeting2.addToFactions(["The Dark Army", "The Syndicate", "Sector-12", "Volhaven", "Ishima",
"OmniTek Incorporated", "KuaiGong International", "Blade Industries"]);
if (augmentationExists(AugmentationNames.Targeting2)) {
@ -199,7 +199,7 @@ initAugmentations = function() {
Targeting3.setRequirements(11000, 23000000);
Targeting3.setInfo("This is an upgrade of the Augmented Targeting II cranial implant, which is capable of augmenting reality " +
"and enhances the user's balance and hand-eye coordination. <br><br>This upgrade increases the player's dexterity " +
"by an additional 40%.");
"by an additional 30%.");
Targeting3.addToFactions(["The Dark Army", "The Syndicate", "OmniTek Incorporated",
"KuaiGong International", "Blade Industries", "The Covenant"]);
if (augmentationExists(AugmentationNames.Targeting3)) {
@ -233,7 +233,7 @@ initAugmentations = function() {
AddToAugmentations(SynfibrilMuscle)
var CombatRib1 = new Augmentation(AugmentationNames.CombatRib1);
CombatRib1.setRequirements(2500, 4500000);
CombatRib1.setRequirements(3000, 4750000);
CombatRib1.setInfo("The human body's ribs are replaced with artificial ribs that automatically and continuously release cognitive " +
"and performance-enhancing drugs into the bloodstream, improving the user's abilities in combat.<br><br>" +
"This augmentation increases the player's strength and defense by 10%.");
@ -245,7 +245,7 @@ initAugmentations = function() {
AddToAugmentations(CombatRib1);
var CombatRib2 = new Augmentation(AugmentationNames.CombatRib2);
CombatRib2.setRequirements(7000, 12000000);
CombatRib2.setRequirements(7500, 13000000);
CombatRib2.setInfo("This is an upgrade to the Combat Rib I augmentation, and is capable of releasing even more potent combat-enhancing " +
"drugs into the bloodstream.<br><br>This upgrade increases the player's strength and defense by an additional 15%.")
CombatRib2.addToFactions(["The Dark Army", "The Syndicate", "Sector-12", "Volhaven", "Ishima",
@ -256,7 +256,7 @@ initAugmentations = function() {
AddToAugmentations(CombatRib2);
var CombatRib3 = new Augmentation(AugmentationNames.CombatRib3);
CombatRib3.setRequirements(12000, 22000000);
CombatRib3.setRequirements(14000, 24000000);
CombatRib3.setInfo("This is an upgrade to the Combat Rib II augmentation, and is capable of releasing even more potent combat-enhancing " +
"drugs into the bloodstream<br><br>. This upgrade increases the player's strength and defense by an additional 20%.");
CombatRib3.addToFactions(["The Dark Army", "The Syndicate", "OmniTek Incorporated",
@ -267,7 +267,7 @@ initAugmentations = function() {
AddToAugmentations(CombatRib3);
var NanofiberWeave = new Augmentation(AugmentationNames.NanofiberWeave);
NanofiberWeave.setRequirements(14000, 20000000);
NanofiberWeave.setRequirements(15000, 25000000);
NanofiberWeave.setInfo("Synthetic nanofibers are woven into the skin's extracellular matrix using electrospinning. " +
"This improves the skin's ability to regenerate itself and protect the body from external stresses and forces.<br><br>" +
"This augmentation increases the player's strength and defense by 25%.");
@ -309,7 +309,7 @@ initAugmentations = function() {
GrapheneBoneLacings.setRequirements(450000, 850000000);
GrapheneBoneLacings.setInfo("A graphene-based material is grafted and fused into the user's bones, significantly increasing " +
"their density and tensile strength.<br><br>" +
"This augmentation increases the player's strength and defense by 75%.");
"This augmentation increases the player's strength and defense by 70%.");
GrapheneBoneLacings.addToFactions(["Fulcrum Secret Technologies", "The Covenant"]);
if (augmentationExists(AugmentationNames.GrapheneBoneLacings)) {
delete Augmentations[AugmentationNames.GrapheneBoneLacings];
@ -322,7 +322,7 @@ initAugmentations = function() {
"Not only is the Bionic Spine physically stronger than a human spine, but it is also capable of digitally " +
"stimulating and regulating the neural signals that are sent and received by the spinal cord. This results in " +
"greatly improved senses and reaction speeds.<br><br>" +
"This augmentation increases all of the player's combat stats by 18%.");
"This augmentation increases all of the player's combat stats by 16%.");
BionicSpine.addToFactions(["Speakers for the Dead", "The Syndicate", "KuaiGong International",
"OmniTek Incorporated", "Blade Industries"]);
if (augmentationExists(AugmentationNames.BionicSpine)) {
@ -334,7 +334,7 @@ initAugmentations = function() {
GrapheneBionicSpine.setRequirements(650000, 1200000000);
GrapheneBionicSpine.setInfo("An upgrade to the Bionic Spine augmentation. It fuses the implant with an advanced graphene " +
"material to make it much stronger and lighter.<br><br>" +
"This augmentation increases all of the player's combat stats by 65%.");
"This augmentation increases all of the player's combat stats by 60%.");
GrapheneBionicSpine.addToFactions(["Fulcrum Secret Technologies", "ECorp"]);
if (augmentationExists(AugmentationNames.GrapheneBionicSpine)) {
delete Augmentations[AugmentationNames.GrapheneBionicSpine];
@ -390,7 +390,7 @@ initAugmentations = function() {
AddToAugmentations(TITN41Injection);
var EnhancedSocialInteractionImplant = new Augmentation(AugmentationNames.EnhancedSocialInteractionImplant);
EnhancedSocialInteractionImplant.setRequirements(150000, 250000000);
EnhancedSocialInteractionImplant.setRequirements(150000, 275000000);
EnhancedSocialInteractionImplant.setInfo("A cranial implant that greatly assists in the user's ability to analyze social situations " +
"and interactions. The system uses a wide variety of factors such as facial expression, body " +
"language, and the voice's tone/inflection to determine the best course of action during social" +
@ -751,7 +751,7 @@ initAugmentations = function() {
FocusWire.setInfo("A cranial implant that stops procrastination by blocking specific neural pathways " +
"in the brain.<br><br>" +
"This augmentation: <br>" +
"Increases all experience gains by 10%<br>" +
"Increases all experience gains by 5%<br>" +
"Increases the amount of money the player gains from working by 20%<br>" +
"Increases the amount of reputation the player gains when working for a company by 10%");
FocusWire.addToFactions(["Bachman & Associates", "Clarke Incorporated", "Four Sigma", "KuaiGong International"]);
@ -775,7 +775,7 @@ initAugmentations = function() {
AddToAugmentations(PCDNI);
var PCDNIOptimizer = new Augmentation(AugmentationNames.PCDNIOptimizer);
PCDNIOptimizer.setRequirements(200000, 875000000);
PCDNIOptimizer.setRequirements(200000, 900000000);
PCDNIOptimizer.setInfo("This is a submodule upgrade to the PC Direct-Neural Interface augmentation. It " +
"improves the performance of the interface and gives the user more control options " +
"to the connected computer.<br><br>" +
@ -789,7 +789,7 @@ initAugmentations = function() {
AddToAugmentations(PCDNIOptimizer);
var PCDNINeuralNetwork = new Augmentation(AugmentationNames.PCDNINeuralNetwork);
PCDNINeuralNetwork.setRequirements(600000, 1300000000);
PCDNINeuralNetwork.setRequirements(600000, 1500000000);
PCDNINeuralNetwork.setInfo("This is an additional installation that upgrades the functionality of the " +
"PC Direct-Neural Interface augmentation. When connected to a computer, " +
"The NeuroNet Injector upgrade allows the user to use his/her own brain's " +
@ -922,7 +922,7 @@ initAugmentations = function() {
AddToAugmentations(Neurotrainer1);
var Neurotrainer2 = new Augmentation(AugmentationNames.Neurotrainer2);
Neurotrainer2.setRequirements(4000, 8500000);
Neurotrainer2.setRequirements(4000, 9000000);
Neurotrainer2.setInfo("A decentralized cranial implant that improves the brain's ability to learn. This " +
"is a more powerful version of the Neurotrainer I augmentation, but it does not " +
"require Neurotrainer I to be installed as a prerequisite.<br><br>" +
@ -934,7 +934,7 @@ initAugmentations = function() {
AddToAugmentations(Neurotrainer2);
var Neurotrainer3 = new Augmentation(AugmentationNames.Neurotrainer3);
Neurotrainer3.setRequirements(10000, 25000000);
Neurotrainer3.setRequirements(10000, 26000000);
Neurotrainer3.setInfo("A decentralized cranial implant that improves the brain's ability to learn. This " +
"is a more powerful version of the Neurotrainer I and Neurotrainer II augmentation, " +
"but it does not require either of them to be installed as a prerequisite.<br><br>" +
@ -983,7 +983,7 @@ initAugmentations = function() {
"Increases the player's agility by 10% <br>" +
"Increases the player's defense by 10% <br>" +
"Increases the amount of money the player gains from crimes by 25%");
LuminCloaking2.setRequirements(2000, 5000000);
LuminCloaking2.setRequirements(2000, 6000000);
LuminCloaking2.addToFactions(["Slum Snakes", "Tetrads"]);
if (augmentationExists(AugmentationNames.LuminCloaking2)) {
delete Augmentations[AugmentationNames.LuminCloaking2];
@ -997,7 +997,7 @@ initAugmentations = function() {
"Increases the player's dexterity by 10%<br>" +
"Increases the player's dexterity experience gain rate by 15%<br>" +
"Increases the amount of money the player gains from crimes by 25%");
SmartSonar.setRequirements(9000, 12000000);
SmartSonar.setRequirements(9000, 15000000);
SmartSonar.addToFactions(["Slum Snakes"]);
if (augmentationExists(AugmentationNames.SmartSonar)) {
delete Augmentations[AugmentationNames.SmartSonar];
@ -1011,7 +1011,7 @@ initAugmentations = function() {
"This augmentation: <br>" +
"Increases all of the player's stats by 5%<br>" +
"Increases the player's experience gain rate for all stats by 10%");
PowerRecirculator.setRequirements(10000, 33000000);
PowerRecirculator.setRequirements(10000, 36000000);
PowerRecirculator.addToFactions(["Tetrads", "The Dark Army", "The Syndicate", "NWO"]);
if (augmentationExists(AugmentationNames.PowerRecirculator)) {
delete Augmentations[AugmentationNames.PowerRecirculator];
@ -1032,7 +1032,7 @@ initAugmentations = function() {
"Increases the player's hacking speed by 10%<br>" +
"Increases the player's chance of successfully performing a hack by 30%<br>" +
"Increases the amount of money the player gains from hacking by 100%");
QLink.setRequirements(750000, 1200000000);
QLink.setRequirements(750000, 1300000000);
QLink.addToFactions(["Illuminati"]);
if (augmentationExists(AugmentationNames.QLink)) {
delete Augmentations[AugmentationNames.QLink];
@ -1058,7 +1058,7 @@ initAugmentations = function() {
"This augmentation: <br>" +
"Increases all of the player's combat stats by 75%<br>" +
"Increases the player's hacking skill by 15%");
SPTN97.setRequirements(500000, 950000000);
SPTN97.setRequirements(500000, 975000000);
SPTN97.addToFactions(["The Covenant"]);
if (augmentationExists(AugmentationNames.SPTN97)) {
delete Augmentations[AugmentationNames.SPTN97];
@ -1070,7 +1070,7 @@ initAugmentations = function() {
HiveMind.setInfo("A brain implant developed by ECorp. They do not reveal what " +
"exactly the implant does, but they promise that it will greatly " +
"enhance your abilities.");
HiveMind.setRequirements(600000, 1000000000);
HiveMind.setRequirements(600000, 1100000000);
HiveMind.addToFactions(["ECorp"]);
if (augmentationExists(AugmentationNames.HiveMind)) {
delete Augmentations[AugmentationNames.HiveMind];
@ -1086,7 +1086,7 @@ initAugmentations = function() {
"This augmentation:<br>" +
"Increases all of the player's combat stats by 35%<br>" +
"Increases all of the player's combat stat experience gain rate by 35%");
CordiARCReactor.setRequirements(450000, 975000000);
CordiARCReactor.setRequirements(450000, 1000000000);
CordiARCReactor.addToFactions(["MegaCorp"]);
if (augmentationExists(AugmentationNames.CordiARCReactor)) {
delete Augmentations[AugmentationNames.CordiARCReactor];
@ -1103,7 +1103,7 @@ initAugmentations = function() {
"Increases the player's charisma experience gain rate by 50%<br>" +
"Increases the amount of reputation the player gains for a company by 25%<br>" +
"Increases the amount of reputation the player gains for a faction by 25%");
SmartJaw.setRequirements(150000, 500000000);
SmartJaw.setRequirements(150000, 550000000);
SmartJaw.addToFactions(["Bachman & Associates"]);
if (augmentationExists(AugmentationNames.SmartJaw)) {
delete Augmentations[AugmentationNames.SmartJaw];
@ -1117,7 +1117,7 @@ initAugmentations = function() {
"body's skin and bone cells, granting them the ability to repair " +
"and restructure themselves. <br><br>" +
"This augmentation increases the player's strength and defense by 55%");
Neotra.setRequirements(225000, 550000000);
Neotra.setRequirements(225000, 575000000);
Neotra.addToFactions(["Blade Industries"]);
if (augmentationExists(AugmentationNames.Neotra)) {
delete Augmentations[AugmentationNames.Neotra];
@ -1132,7 +1132,7 @@ initAugmentations = function() {
"This augmentation: <br>" +
"Increases all of the player's stats by 20%<br>" +
"Increases the player's experience gain rate for all stats by 15%");
Xanipher.setRequirements(350000, 800000000);
Xanipher.setRequirements(350000, 850000000);
Xanipher.addToFactions(["NWO"]);
if (augmentationExists(AugmentationNames.Xanipher)) {
delete Augmentations[AugmentationNames.Xanipher];
@ -1145,7 +1145,7 @@ initAugmentations = function() {
"of negligible senescence, preventing the body from " +
"deteriorating with age. <br><br>" +
"This augmentation increases all of the player's stats by 20%");
nextSENS.setRequirements(175000, 375000000);
nextSENS.setRequirements(175000, 385000000);
nextSENS.addToFactions(["Clarke Incorporated"]);
if (augmentationExists(AugmentationNames.nextSENS)) {
delete Augmentations[AugmentationNames.nextSENS];
@ -1160,7 +1160,7 @@ initAugmentations = function() {
"This augmentation:<br>" +
"Increases the player's hacking skill by 20%<br>" +
"Increases the player's hacking experience gain rate by 25%");
OmniTekInfoLoad.setRequirements(250000, 550000000)
OmniTekInfoLoad.setRequirements(250000, 575000000)
OmniTekInfoLoad.addToFactions(["OmniTek Incorporated"]);
if (augmentationExists(AugmentationNames.OmniTekInfoLoad)) {
delete Augmentations[AugmentationNames.OmniTekInfoLoad];
@ -1177,7 +1177,7 @@ initAugmentations = function() {
"skin cells, allowing users to generate their own energy " +
"and nutrition using solar power. <br><br>" +
"This augmentation increases the player's strength, defense, and agility by 40%");
PhotosyntheticCells.setRequirements(225000, 525000000);
PhotosyntheticCells.setRequirements(225000, 550000000);
PhotosyntheticCells.addToFactions(["KuaiGong International"]);
if (augmentationExists(AugmentationNames.PhotosyntheticCells)) {
delete Augmentations[AugmentationNames.PhotosyntheticCells];
@ -1195,7 +1195,7 @@ initAugmentations = function() {
"Increases the player's chance of successfully performing a hack by 10%<br>" +
"Increases the player's hacking speed by 5%<br>" +
"Lets the player start with the FTPCrack.exe and relaySMTP.exe programs after a reset");
Neurolink.setRequirements(350000, 850000000);
Neurolink.setRequirements(350000, 875000000);
Neurolink.addToFactions(["BitRunners"]);
if (augmentationExists(AugmentationNames.Neurolink)) {
delete Augmentations[AugmentationNames.Neurolink];
@ -1213,7 +1213,7 @@ initAugmentations = function() {
"Increases the player's hacking skill by 10%<br>" +
"Increases the player's hacking speed by 2%<br>" +
"Increases the amount of money the player gains from hacking by 10%");
TheBlackHand.setRequirements(40000, 100000000);
TheBlackHand.setRequirements(40000, 110000000);
TheBlackHand.addToFactions(["The Black Hand"]);
if (augmentationExists(AugmentationNames.TheBlackHand)) {
delete Augmentations[AugmentationNames.TheBlackHand];
@ -1396,13 +1396,13 @@ applyAugmentation = function(aug, reapply=false) {
switch(aug.name) {
//Combat stat augmentations
case AugmentationNames.Targeting1:
Player.dexterity_mult *= 1.15;
Player.dexterity_mult *= 1.10;
break;
case AugmentationNames.Targeting2:
Player.dexterity_mult *= 1.25;
Player.dexterity_mult *= 1.20;
break;
case AugmentationNames.Targeting3:
Player.dexterity_mult *= 1.40;
Player.dexterity_mult *= 1.30;
break;
case AugmentationNames.SyntheticHeart: //High level
Player.agility_mult *= 1.5;
@ -1436,20 +1436,20 @@ applyAugmentation = function(aug, reapply=false) {
Player.dexterity_mult *= 1.05;
break;
case AugmentationNames.GrapheneBoneLacings: //High level
Player.strength_mult *= 1.75;
Player.defense_mult *= 1.75;
Player.strength_mult *= 1.7;
Player.defense_mult *= 1.7;
break;
case AugmentationNames.BionicSpine: //Med level
Player.strength_mult *= 1.18;
Player.defense_mult *= 1.18;
Player.agility_mult *= 1.18;
Player.dexterity_mult *= 1.18;
Player.strength_mult *= 1.16;
Player.defense_mult *= 1.16;
Player.agility_mult *= 1.16;
Player.dexterity_mult *= 1.16;
break;
case AugmentationNames.GrapheneBionicSpine: //High level
Player.strength_mult *= 1.65;
Player.defense_mult *= 1.65;
Player.agility_mult *= 1.65;
Player.dexterity_mult *= 1.65;
Player.strength_mult *= 1.6;
Player.defense_mult *= 1.6;
Player.agility_mult *= 1.6;
Player.dexterity_mult *= 1.6;
break;
case AugmentationNames.BionicLegs: //Med level
Player.agility_mult *= 1.6;
@ -1579,12 +1579,12 @@ applyAugmentation = function(aug, reapply=false) {
Player.charisma_mult *= 1.1;
break;
case AugmentationNames.FocusWire: //Med level
Player.hacking_exp_mult *= 1.1;
Player.strength_exp_mult *= 1.1;
Player.defense_exp_mult *= 1.1;
Player.dexterity_exp_mult *= 1.1;
Player.agility_exp_mult *= 1.1;
Player.charisma_exp_mult *= 1.1;
Player.hacking_exp_mult *= 1.05;
Player.strength_exp_mult *= 1.05;
Player.defense_exp_mult *= 1.05;
Player.dexterity_exp_mult *= 1.05;
Player.agility_exp_mult *= 1.05;
Player.charisma_exp_mult *= 1.05;
Player.company_rep_mult *= 1.1;
Player.work_money_mult *= 1.2;
break;
@ -1710,10 +1710,10 @@ applyAugmentation = function(aug, reapply=false) {
Player.crime_money_mult *= 1.25;
break;
case AugmentationNames.HemoRecirculator:
Player.strength_mult *= 1.1;
Player.defense_mult *= 1.1;
Player.agility_mult *= 1.1;
Player.dexterity_mult *= 1.1;
Player.strength_mult *= 1.08;
Player.defense_mult *= 1.08;
Player.agility_mult *= 1.08;
Player.dexterity_mult *= 1.08;
break;
case AugmentationNames.SmartSonar:
Player.dexterity_mult *= 1.1;

@ -1,5 +1,5 @@
CONSTANTS = {
Version: "0.24.1",
Version: "0.25.0",
//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
@ -11,7 +11,7 @@ CONSTANTS = {
/* Base costs */
BaseCostFor1GBOfRamHome: 32000,
BaseCostFor1GBOfRamServer: 55000, //1 GB of RAM
BaseCostFor1GBOfRamServer: 60000, //1 GB of RAM
BaseCostFor1GBOfRamHacknetNode: 30000,
BaseCostForHacknetNode: 1000,
@ -19,9 +19,9 @@ CONSTANTS = {
/* Hacknet Node constants */
HacknetNodeMoneyGainPerLevel: 1.55,
HacknetNodePurchaseNextMult: 1.75, //Multiplier when purchasing an additional hacknet node
HacknetNodeUpgradeLevelMult: 1.045, //Multiplier for cost when upgrading level
HacknetNodeUpgradeRamMult: 1.28, //Multiplier for cost when upgrading RAM
HacknetNodePurchaseNextMult: 1.85, //Multiplier when purchasing an additional hacknet node
HacknetNodeUpgradeLevelMult: 1.05, //Multiplier for cost when upgrading level
HacknetNodeUpgradeRamMult: 1.29, //Multiplier for cost when upgrading RAM
HacknetNodeUpgradeCoreMult: 1.49, //Multiplier for cost when buying another core
HacknetNodeMaxLevel: 200,
@ -34,7 +34,7 @@ CONSTANTS = {
/* Augmentation */
//NeuroFlux Governor cost multiplier as you level up
NeuroFluxGovernorLevelMult: 1.13,
NeuroFluxGovernorLevelMult: 1.14,
/* Script related things */
//Time (ms) it takes to run one operation in Netscript.
@ -71,6 +71,10 @@ CONSTANTS = {
ScriptHNUpgLevelRamCost: 0.4,
ScriptHNUpgRamRamCost: 0.6,
ScriptHNUpgCoreRamCost: 0.8,
ScriptGetStockRamCost: 2.0,
ScriptBuySellStockRamCost: 2.5,
ScriptPurchaseServerRamCost: 2.0,
ScriptRoundRamCost: 0.05,
MultithreadingRAMCost: 1,
@ -96,8 +100,8 @@ CONSTANTS = {
InfiltrationMoneyValue: 2000, //Convert "secret" value to money
//Stock market constants
WSEAccountCost: 50000000,
TIXAPICost: 1000000000,
WSEAccountCost: 200000000,
TIXAPICost: 5000000000,
StockMarketCommission: 100000,
//Hospital/Health
@ -327,6 +331,10 @@ CONSTANTS = {
"the execution of a script is when it saves/loads. </strong><br><br>",
TutorialNetscriptText: "Netscript is a programming language implemented for this game. The language has " +
"your basic programming constructs and several built-in commands that are used to hack. <br><br>" +
"<u><h1>Official Wiki and Documentation</h1></u><br>" +
"<a href='http://bitburner.wikia.com/wiki/Netscript' target='_blank'>Check out Bitburner's wiki for the official Netscript documentation</a>" +
". The wiki documentation will contain more details and " +
"code examples than this documentation page. Also, it can be opened up in another tab/window for convenience!<br><br>" +
"<u><h1> Variables and data types </h1></u><br>" +
"The following data types are supported by Netscript: <br>" +
"numeric - Integers and floats (eg. 6, 10.4999)<br>" +
@ -354,41 +362,7 @@ CONSTANTS = {
"&nbsp;==<br>" +
"&nbsp;!=<br><br>" +
"<u><h1> Arrays </h1></u><br>" +
"Arrays are special container objects. Arrays can hold 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>" +
"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 " +
"operator on the array's name: <br><br>" +
"print(thisIsAnArray[0]); <br>" +
"thisIsAnArray[1] = 5;<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 " +
"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. " +
"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>" +
"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>" +
"Netscript arrays have the same properties and functions as javascript arrays. For information see javascripts <a href=\"https://www.w3schools.com/js/js_arrays.asp\" target='_blank'>array</a> documentation.<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>" +
@ -427,9 +401,7 @@ CONSTANTS = {
"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. Returns " +
"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>" +
"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>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>scan(hostname/ip)</i><br>Returns an array containing the hostnames of all servers that are one node away from the specified server. " +
"The argument must be a string containing the IP or hostname of the target server. The hostnames in the returned array are strings.<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>" +
@ -528,6 +500,14 @@ CONSTANTS = {
"<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 " +
"a new Hacknet Node then the function will return false. Does NOT work offline<br><br>" +
"<i>purchaseServer(hostname, ram)</i><br> Purchases a server with the specified hostname and amount of RAM. The first argument can be any data type, " +
"but it will be converted to a string using Javascript's String function. Anything that resolves to an empty string will cause the function to fail. " +
"The second argument specified the amount of RAM (in GB) for the server. This argument must resolve to a numeric and it must be a power of 2 " +
"(2, 4, 8, etc...). <br><br>" +
"Purchasing a server using this Netscript function is twice as expensive as manually purchasing a server from a location in the World.<br><br>" +
"This function returns the hostname of the newly purchased server as a string. If the function fails to purchase a server, then it will return " +
"an empty string. The function will fail if the arguments passed in are invalid or if the player does not have enough money to purchase the specified server.<br><br>" +
"<i>round(n)</i><br>Rounds the number n to the nearest integer. If the argument passed in is not a number, then the function will return 0.<br><br>" +
"<u><h1>Hacknet Nodes API</h1></u><br>" +
"Netscript provides the following API for accessing and upgrading your Hacknet Nodes through scripts. This API does NOT work offline.<br><br>" +
"<i>hacknetnodes</i><br> A special variable. This is an array that maps to the Player's Hacknet Nodes. The Hacknet Nodes are accessed through " +
@ -549,54 +529,74 @@ CONSTANTS = {
"to a level of at least 75, RAM to at least 8GB, and number of cores to at least 2.<br><br>" +
"while(hacknetnodes.length < 4) {<br>" +
"&nbsp;&nbsp;&nbsp;&nbsp;purchaseHacknetNode();<br>" +
"};<br>" +
"for (i = 0; i < 4; i = i+1) {<br>" +
"}<br>" +
"for (i = 0; i < 4; i = i++) {<br>" +
"&nbsp;&nbsp;&nbsp;&nbsp;while (hacknetnodes[i].level <= 75) {<br>" +
"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hacknetnodes[i].upgradeLevel(5);<br>" +
"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep(10000);<br>" +
"&nbsp;&nbsp;&nbsp;&nbsp;};<br>" +
"};<br>" +
"for (i = 0; i < 4; i = i+1) {<br>" +
"&nbsp;&nbsp;&nbsp;&nbsp;}<br>" +
"}<br>" +
"for (i = 0; i < 4; i = i++) {<br>" +
"&nbsp;&nbsp;&nbsp;&nbsp;while (hacknetnodes[i].ram < 8) {<br>" +
"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hacknetnodes[i].upgradeRam();<br>" +
"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep(10000);<br>" +
"&nbsp;&nbsp;&nbsp;&nbsp;};<br>" +
"};<br>" +
"for (i = 0; i < 4; i = i+1) {<br>" +
"&nbsp;&nbsp;&nbsp;&nbsp;}<br>" +
"}<br>" +
"for (i = 0; i < 4; i = i++) {<br>" +
"&nbsp;&nbsp;&nbsp;&nbsp;while (hacknetnodes[i].cores < 2) {<br>" +
"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;hacknetnodes[i].upgradeCore();<br>" +
"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep(10000);<br>" +
"&nbsp;&nbsp;&nbsp;&nbsp;};<br>" +
"};<br><br>" +
"&nbsp;&nbsp;&nbsp;&nbsp;}<br>" +
"}<br><br>" +
"<u><h1>Trade Information eXchange (TIX) API</h1></u><br>" +
"<i>getStockPrice(sym)</i><br>Returns the price of a stock. The argument passed in must be the stock's symbol (NOT THE COMPANY NAME!). The symbol " +
"is a sequence of two to four capital letters. The symbol argument must be a string. <br><br>" +
"Example: getStockPrice('FSIG');<br><br>" +
"<i>getStockPosition(sym)</i><br>Returns an array of two elements that represents the player's position in a stock. The first element " +
"in the array is the number of shares the player owns of the specified stock. The second element in the array is the average price of the player's " +
"shares. Both elements are numbers. The argument passed in must be the stock's symbol, which is a sequence of two to four capital letters.<br><br>" +
"Example: <br><br>pos = getStockPosition('ECP');<br>shares = pos[0];<br>avgPx = pos[1];<br><br>"+
"<i>buyStock(sym, shares)</i><br>Attempts to purchase shares of a stock. The first argument must be a string with the stock's symbol. The second argument " +
"must be the number of shares to purchase.<br><br>" +
"If the player does not have enough money to purchase specified number of shares, then no shares will be purchased (it will not purchase the most you can afford). " +
"Remember that every transaction on the stock exchange costs a certain commission fee.<br><br>" +
"The function will return true if it successfully purchases the specified number of shares of stock, and false otherwise.<br><br>" +
"<i>sellStock(sym, shares)</i><br>Attempts to sell shares of a stock. The first argument must be a string with the stock's symbol. The second argument " +
"must be the number of shares to sell.<br><br>" +
"If the specified number of shares in the function exceeds the amount that the player actually owns, then this function will sell all owned shares. " +
"Remember that every transaction on the stock exchange costs a certain commission fee.<br><br>" +
"The net profit made from selling stocks with this function is reflected in the script's statistics. This net profit is calculated as: <br><br>" +
"shares * (sell price - average price of purchased shares)<br><br>" +
"This function will return true if the shares of stock are successfully sold and false otherwise.<br><br>" +
"<u><h1>While loops </h1></u><br>" +
"A while loop is a control flow statement that repeatedly executes code as long as a condition is met. <br><br> " +
"<i>while (<i>[cond]</i>) {<br>&nbsp;&nbsp;&nbsp;&nbsp;<i>[code]</i><br>}</i><br><br>" +
"As long as <i>[cond]</i> remains true, the code block <i>[code]</i> will continuously execute. Example: <br><br>" +
"<i>i = 0; <br> while (i < 10) { <br>&nbsp;&nbsp;&nbsp;&nbsp;hack('foodnstuff');<br>&nbsp;&nbsp;&nbsp;&nbsp;i = i + 1;<br> }; </i><br><br>" +
"<i>i = 0; <br> while (i < 10) { <br>&nbsp;&nbsp;&nbsp;&nbsp;hack('foodnstuff');<br>&nbsp;&nbsp;&nbsp;&nbsp;i = i + 1;<br> } </i><br><br>" +
"This code above repeats the 'hack('foodnstuff')' command 10 times before it stops and exits. <br><br>" +
"<i>while(true) { <br>&nbsp;&nbsp;&nbsp;&nbsp; hack('foodnstuff'); <br> }; </i><br><br> " +
"<i>while(true) { <br>&nbsp;&nbsp;&nbsp;&nbsp; hack('foodnstuff'); <br> }</i><br><br> " +
"This while loop above is an infinite loop (continuously runs until the script is manually stopped) that repeatedly runs the 'hack('foodnstuff')' command. " +
"Note that a semicolon is needed at closing bracket of the while loop, UNLESS it is at the end of the code<br><br> " +
"<u><h1>For loops</h1></u><br>" +
"A for loop is another control flow statement that allows code to be repeated by iterations. The structure is: <br><br> " +
"<i>for (<i>[init]</i>; <i>[cond]</i>; <i>[post]</i>) {<br>&nbsp;&nbsp;&nbsp;&nbsp;<i>code</i> <br> }; </i><br><br>" +
"<i>for (<i>[init]</i>; <i>[cond]</i>; <i>[post]</i>) {<br>&nbsp;&nbsp;&nbsp;&nbsp;<i>code</i> <br> } </i><br><br>" +
"The <i>[init]</i> expression evaluates before the for loop begins. The for loop will continue to execute " +
"as long as <i>[cond]</i> is met. The <i>[post]</i> expression will evaluate at the end of every iteration " +
"of the for loop. The following example shows code that will run the 'hack('foodnstuff');' command 10 times " +
" using a for loop: <br><br>" +
"<i>for (i = 0; i < 10; i = i+1) { <br>&nbsp;&nbsp;&nbsp;&nbsp;hack('foodnstuff');<br>}; </i><br><br>" +
"<i>for (i = 0; i < 10; i = i++) { <br>&nbsp;&nbsp;&nbsp;&nbsp;hack('foodnstuff');<br>} </i><br><br>" +
"<u><h1> If statements </h1></u><br>" +
"If/Elif/Else statements are conditional statements used to perform different actions based on different conditions: <br><br>" +
"<i>if (condition1) {<br>&nbsp;&nbsp;&nbsp;&nbsp;code1<br>} elif (condition2) {<br>&nbsp;&nbsp;&nbsp;&nbsp;code2<br>} else {<br>" +
"If/Else if/Else statements are conditional statements used to perform different actions based on different conditions: <br><br>" +
"<i>if (condition1) {<br>&nbsp;&nbsp;&nbsp;&nbsp;code1<br>} else if (condition2) {<br>&nbsp;&nbsp;&nbsp;&nbsp;code2<br>} else {<br>" +
"&nbsp;&nbsp;&nbsp;&nbsp;code3<br>}</i><br><br>" +
"In the code above, first <i>condition1</i> will be checked. If this condition is true, then <i>code1</i> will execute and the " +
"rest of the if/elif/else statement will be skipped. If <i>condition1</i> is NOT true, then the code will then go on to check " +
"<i>condition2</i>. If <i>condition2</i> is true, then <i>code2</i> will be executed, and the rest of the if/elif/else statement " +
"rest of the if/else if/else statement will be skipped. If <i>condition1</i> is NOT true, then the code will then go on to check " +
"<i>condition2</i>. If <i>condition2</i> is true, then <i>code2</i> will be executed, and the rest of the if/else if/else statement " +
"will be skipped. If none of the conditions are true, then the code within the else block (<i>code3</i>) will be executed. " +
"Note that a conditional statement can have any number of elif statements. <br><br>" +
"Note that a conditional statement can have any number of 'else if' statements. <br><br>" +
"Example: <br><br>" +
"if(getServerMoneyAvailable('foodnstuff') > 200000) {<br>&nbsp;&nbsp;&nbsp;&nbsp;hack('foodnstuff');<br>" +
"} else {<br>&nbsp;&nbsp;&nbsp;&nbsp;grow('foodnstuff');<br>};<br><br>" +
"} else {<br>&nbsp;&nbsp;&nbsp;&nbsp;grow('foodnstuff');<br>}<br><br>" +
"The code above will use the getServerMoneyAvailable() function to check how much money there is on the 'foodnstuff' server. " +
"If there is more than $200,000, then it will try to hack that server. If there is $200,000 or less on the server, " +
"then the code will call grow('foodnstuff') instead and add more money to the server.<br><br>",
@ -699,6 +699,32 @@ CONSTANTS = {
"World Stock Exchange account and TIX API Access<br>",
Changelog:
"v0.25.0<br> " +
"-Refactored Netscript to use the open-source Acorns Parser. This re-implementation was done by Github users MrNuggelz. " +
"This has resulted in several changes in the Netscript language. Some scripts might break because of these changes. " +
"Changes listed below: <br>" +
"-Arrays are now fully functional Javascript arrays. You no longer need to use the 'Array' keyword to declare them. <br>" +
"-The length(), clear/clear(), insert(), and remove() functions no longer work for arrays. <br>" +
"-All Javascript array methods are available (splice(), push(), pop(), join(), shift(), indexOf(), etc. See documentation)<br>" +
"-Variables assigned to arrays are now passed by value rather than reference<br>" +
"-Incrementing/Decrementing are now available (i++, ++i)<br>" +
"-You no longer need semicolons at the end of block statements<br>" +
"-Netscript's Hacknet Node API functions no longer log anything<br>" +
"-Stock prices now update every ~6 seconds when the game is active (was 10 seconds before)<br>" +
"-Added a new mechanic that affects how stock prices change<br>" +
"-Script editor now has dynamic indicators for RAM Usage and Line number<br>" +
"-Augmentation Rebalancing - Many late game augmentations are now slightly more expensive. Several early game " +
"augmentations had their effects slightly decreased<br>" +
"-Increased the amount of rewards (both money and rep) you get from infiltration<br>" +
"-Purchasing servers is now slightly more expensive<br>" +
"-Calling the Netscript function getServerMoneyAvailable('home') now return's the player's money<br>" +
"-Added round(n) Netscript function - Rounds a number<br>" +
"-Added purchaseServer(hostname, ram) Netscript function<br>" +
"-Added the TIX API. This must be purchased in the WSE. It persists through resets. Access to the TIX API " +
"allows you to write scripts that perform automated algorithmic trading. See Netscript documentation<br>" +
"-Minor rebalancing in a lot of different areas<br>" +
"-Changed the format of IP Addresses so that they are smaller (will consist mostly of single digit numbers now). This will reduce " +
"the size of the game's save file.<br><br>" +
"v0.24.1<br>" +
"-Adjusted cost of upgrading home computer RAM. Should be a little cheaper for the first few upgrades (up to ~64GB), and " +
"then will start being more expensive than before. High RAM upgrades should now be significantly more expensive than before.<br>" +
@ -914,7 +940,7 @@ CONSTANTS = {
"-Updated Tutorial<br>" +
"-Created a Hacknet Node API for Netscript that allows you to access and upgrade your Hacknet Nodes. See the Netscript documentation for more details. WARNING The old upgradeHacknetNode() and getNumHacknetNodes() functions waere removed so any script that has these will no longer work <br><br>" +
"v0.15 <br>" +
"-Slightly reduced production multiplier for Hacknet Node RAM<br>" +
"-Slightly reduced production multiplier for Hacknet Node RAM<br>" +
"-Faction pages now scroll<br>" +
"-Slightly increased amount of money gained from hacking<br>" +
"-Added 'alias' command<br>" +
@ -925,36 +951,31 @@ CONSTANTS = {
"-You can now see what an Augmentation does and its price even while its locked<br><br>",
LatestUpdate:
"v0.24.1<br>" +
"-Adjusted cost of upgrading home computer RAM. Should be a little cheaper for the first few upgrades (up to ~64GB), and " +
"then will start being more expensive than before. High RAM upgrades should now be significantly more expensive than before.<br>" +
"-Slightly lowered the starting money available on most mid-game and end-game servers (servers with required hacking level " +
"greater than 200) by about 10-15%<br>" +
"-Rebalanced company/company position reputation gains and requirements<br>" +
"-Studying at a university now gives slightly more EXP and early jobs give slightly less EXP<br>" +
"-Studying at a university is now considerably more expensive<br>" +
"-Rebalanced stock market<br>" +
"-Significantly increased cost multiplier for purchasing additional Hacknet Nodes<br>" +
"-The rate at which facility security level increases during infiltration for each clearance level " +
"was lowered slightly for all companies<br>" +
"-Updated Faction descriptions<br>" +
"-Changed the way alias works. Normal aliases now only work at the start of a Terminal command (they will only " +
"replace the first word in the Terminal command). You can also create global aliases that work on any part of the " +
'command, like before. Declare global aliases by entering the optional -g flag: alias -g name="value" - Courtesy of Github user MrNuggelz<br>' +
"-'top' Terminal command implemented courtesy of Github user LTCNugget. Currently, the formatting gets screwed up " +
"if your script names are really long.<br><br>" +
"v0.24.0<br>" +
"-Players now have HP, which is displayed in the top right. To regain HP, visit the hospital. Currently " +
"the only way to lose HP is through infiltration<br>" +
"-Infiltration - Attempt to infiltrate a company and steal their classified secrets. See 'Companies' documentation for more details<br>" +
"-Stock Market - Added the World Stock Exchange (WSE), a brokerage that lets you buy/sell stocks. To begin trading you must first purchase " +
"an account. A WSE account will persist even after resetting by installing Augmentations. How the stock market works should hopefully be " +
"self explanatory. There is no documentation about it currently, I will add some later. NOTE: Stock prices only change when the game is open. " +
"The Stock Market is reset when installing Augmentations, which means you will lose all your stocks<br>" +
"-Decreased money gained from hacking by ~12%<br>" +
"-Increased reputation required for all Augmentations by ~40%<br>" +
"-Cost increase when purchasing multiple augmentations increased from 75% to 90%<br>" +
"-Added basic variable runtime to Netscript operations. Basic commands run in 100ms. Any function incurs another 100ms in runtime (200ms total). " +
"Any function that starts with getServer incurs another 100ms runtime (300ms total). exec() and scp() require 400ms total. <br>" +
"-Slightly reduced the amount of experience gained from hacking<br>",
"v0.25.0<br> " +
"-Refactored Netscript to use the open-source Acorns Parser. This re-implementation was done by Github users MrNuggelz. " +
"This has resulted in several changes in the Netscript language. Some scripts might break because of these changes. " +
"Changes listed below: <br>" +
"-Arrays are now fully functional Javascript arrays. You no longer need to use the 'Array' keyword to declare them. <br>" +
"-The length(), clear/clear(), insert(), and remove() functions no longer work for arrays. <br>" +
"-All Javascript array methods are available (splice(), push(), pop(), join(), shift(), indexOf(), etc. See documentation)<br>" +
"-Variables assigned to arrays are now passed by value rather than reference<br>" +
"-Incrementing/Decrementing are now available (i++, ++i)<br>" +
"-You no longer need semicolons at the end of block statements<br>" +
"-Netscript's Hacknet Node API functions no longer log anything<br>" +
"-Stock prices now update every ~6 seconds when the game is active (was 10 seconds before)<br>" +
"-Added a new mechanic that affects how stock prices change<br>" +
"-Script editor now has dynamic indicators for RAM Usage and Line number<br>" +
"-Augmentation Rebalancing - Many late game augmentations are now slightly more expensive. Several early game " +
"augmentations had their effects slightly decreased<br>" +
"-Increased the amount of rewards (both money and rep) you get from infiltration<br>" +
"-Purchasing servers is now slightly more expensive<br>" +
"-Calling the Netscript function getServerMoneyAvailable('home') now return's the player's money<br>" +
"-Added round(n) Netscript function - Rounds a number<br>" +
"-Added purchaseServer(hostname, ram) Netscript function<br>" +
"-Added the TIX API. This must be purchased in the WSE. It persists through resets. Access to the TIX API " +
"allows you to write scripts that perform automated algorithmic trading. See Netscript documentation<br>" +
"-Minor rebalancing in a lot of different areas<br>" +
"-Changed the format of IP Addresses so that they are smaller (will consist mostly of single digit numbers now). This will reduce " +
"the size of the game's save file.<br>",
}

@ -34,7 +34,7 @@ document.addEventListener("DOMContentLoaded", hacknetNodesInit, false);
function HacknetNode(name) {
this.level = 1;
this.ram = 1; //GB
this.numCores = 1;
this.cores = 1;
this.name = name;
@ -50,7 +50,7 @@ HacknetNode.prototype.updateMoneyGainRate = function() {
this.moneyGainRatePerSecond = (this.level * gainPerLevel) *
Math.pow(1.035, this.ram-1) *
((this.numCores + 5) / 6) * Player.hacknet_node_money_mult;
((this.cores + 5) / 6) * Player.hacknet_node_money_mult;
if (isNaN(this.moneyGainRatePerSecond)) {
this.moneyGainRatePerSecond = 0;
dialogBoxCreate("Error in calculating Hacknet Node production. Please report to game developer");
@ -85,6 +85,11 @@ HacknetNode.prototype.purchaseLevelUpgrade = function(levels=1) {
return true;
}
//Wrapper function for Netscript
HacknetNode.prototype.upgradeLevel = function(levels=1) {
return this.purchaseLevelUpgrade(levels);
}
HacknetNode.prototype.calculateRamUpgradeCost = function() {
var numUpgrades = Math.log2(this.ram);
@ -106,23 +111,33 @@ HacknetNode.prototype.purchaseRamUpgrade = function() {
return true;
}
//Wrapper function for Netscript
HacknetNode.prototype.upgradeRam = function() {
return this.purchaseRamUpgrade();
}
HacknetNode.prototype.calculateCoreUpgradeCost = function() {
var coreBaseCost = CONSTANTS.BaseCostForHacknetNodeCore;
var mult = CONSTANTS.HacknetNodeUpgradeCoreMult;
return coreBaseCost * Math.pow(mult, this.numCores-1) * Player.hacknet_node_core_cost_mult;
return coreBaseCost * Math.pow(mult, this.cores-1) * Player.hacknet_node_core_cost_mult;
}
HacknetNode.prototype.purchaseCoreUpgrade = function() {
var cost = this.calculateCoreUpgradeCost();
if (isNaN(cost)) {return false;}
if (cost > Player.money) {return false;}
if (this.numCores >= CONSTANTS.HacknetNodeMaxCores) {return false;}
if (this.cores >= CONSTANTS.HacknetNodeMaxCores) {return false;}
Player.loseMoney(cost);
++this.numCores;
++this.cores;
this.updateMoneyGainRate();
return true;
}
//Wrapper function for Netscript
HacknetNode.prototype.upgradeCore = function() {
return this.purchaseCoreUpgrade();
}
/* Saving and loading HackNets */
HacknetNode.prototype.toJSON = function() {
return Generic_toJSON("HacknetNode", this);
@ -150,8 +165,8 @@ purchaseHacknet = function() {
var cost = getCostOfNextHacknetNode();
if (isNaN(cost)) {throw new Error("Cost is NaN"); return;}
if (cost > Player.money) {
dialogBoxCreate("You cannot afford to purchase a Hacknet Node!");
return;
//dialogBoxCreate("You cannot afford to purchase a Hacknet Node!");
return false;
}
//Auto generate a name for the node for now...TODO
@ -165,6 +180,7 @@ purchaseHacknet = function() {
displayHacknetNodesContent();
updateTotalHacknetProduction();
return numOwned;
}
//Calculates the total production from all HacknetNodes
@ -361,7 +377,7 @@ updateHacknetNodeDomElement = function(nodeObj) {
" ($" + formatNumber(nodeObj.moneyGainRatePerSecond, 2) + " / second) <br>" +
"Level: " + nodeObj.level + "<br>" +
"RAM: " + nodeObj.ram + "GB<br>" +
"Cores: " + nodeObj.numCores;
"Cores: " + nodeObj.cores;
//Upgrade level
var upgradeLevelButton = document.getElementById("hacknet-node-upgrade-level-" + nodeName);
@ -408,7 +424,7 @@ updateHacknetNodeDomElement = function(nodeObj) {
//Upgrade Cores
var upgradeCoreButton = document.getElementById("hacknet-node-upgrade-core-" + nodeName);
if (upgradeCoreButton == null) {throw new Error("Cannot find upgrade cores button element");}
if (nodeObj.numCores >= CONSTANTS.HacknetNodeMaxCores) {
if (nodeObj.cores >= CONSTANTS.HacknetNodeMaxCores) {
upgradeCoreButton.innerHTML = "MAX CORES";
upgradeCoreButton.setAttribute("class", "a-link-button-inactive");
} else {

@ -369,7 +369,7 @@ displayLocationContent = function() {
purchaseTor.style.display = "block";
purchaseHomeRam.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumECorp,
6000, 100, 150, 13);
6000, 106, 150, 13);
break;
case Locations.AevumBachmanAndAssociates:
@ -382,7 +382,7 @@ displayLocationContent = function() {
businessJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumBachmanAndAssociates,
1500, 36, 60, 9.5);
1500, 38, 60, 9.5);
break;
case Locations.AevumClarkeIncorporated:
@ -395,7 +395,7 @@ displayLocationContent = function() {
businessJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumClarkeIncorporated,
2400, 28, 75, 9);
2400, 30, 75, 9);
break;
case Locations.AevumFulcrumTechnologies:
@ -414,7 +414,7 @@ displayLocationContent = function() {
purchaseTor.style.display = "block";
purchaseHomeRam.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumFulcrumTechnologies,
6000, 84, 100, 15);
6000, 88, 100, 15);
break;
case Locations.AevumAeroCorp:
@ -426,7 +426,7 @@ displayLocationContent = function() {
networkEngineerJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumAeroCorp,
2000, 26, 50, 10);
2000, 28, 50, 10);
break;
case Locations.AevumGalacticCybersystems:
@ -439,7 +439,7 @@ displayLocationContent = function() {
networkEngineerJob.style.display = "block";
businessJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumGalacticCybersystems,
1400, 24, 50, 9);
1400, 26, 50, 9);
break;
case Locations.AevumWatchdogSecurity:
@ -453,7 +453,7 @@ displayLocationContent = function() {
securityJob.style.display = "block";
agentJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumWatchdogSecurity,
850, 12, 30, 7.5);
850, 14, 30, 7.5);
break;
case Locations.AevumRhoConstruction:
@ -462,7 +462,7 @@ displayLocationContent = function() {
softwareJob.style.display = "block";
businessJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumRhoConstruction,
600, 8, 20, 4);
600, 10, 20, 4);
break;
case Locations.AevumPolice:
@ -471,7 +471,7 @@ displayLocationContent = function() {
softwareJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumPolice,
700, 10, 25, 5);
700, 12, 25, 5);
break;
case Locations.AevumNetLinkTechnologies:
@ -489,7 +489,7 @@ displayLocationContent = function() {
purchaseTor.style.display = "block";
purchaseHomeRam.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumNetLinkTechnologies,
150, 5, 15, 3);
160, 8, 15, 3);
break;
case Locations.AevumCrushFitnessGym:
@ -523,7 +523,7 @@ displayLocationContent = function() {
businessJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.ChongqingKuaiGongInternational,
5500, 42, 100, 14);
5500, 44, 100, 14);
break;
case Locations.ChongqingSolarisSpaceSystems:
@ -564,7 +564,7 @@ displayLocationContent = function() {
businessJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12MegaCorp,
6000, 100, 125, 15);
6000, 104, 125, 15);
break;
case Locations.Sector12BladeIndustries:
@ -577,7 +577,7 @@ displayLocationContent = function() {
businessJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12BladeIndustries,
3000, 40, 100, 10);
3000, 42, 100, 10);
break;
case Locations.Sector12FourSigma:
@ -590,7 +590,7 @@ displayLocationContent = function() {
businessJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12FourSigma,
1500, 50, 100, 14.5);
1500, 52, 100, 14.5);
break;
case Locations.Sector12IcarusMicrosystems:
@ -603,7 +603,7 @@ displayLocationContent = function() {
networkEngineerJob.style.display = "block";
businessJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12IcarusMicrosystems,
900, 28, 70, 11);
900, 30, 70, 11);
break;
case Locations.Sector12UniversalEnergy:
@ -616,7 +616,7 @@ displayLocationContent = function() {
networkEngineerJob.style.display = "block";
businessJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12UniversalEnergy,
775, 20, 50, 9.5);
775, 22, 50, 9.5);
break;
case Locations.Sector12DeltaOne:
@ -628,7 +628,7 @@ displayLocationContent = function() {
networkEngineerJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12DeltaOne,
1200, 30, 75, 10);
1200, 34, 75, 10);
break;
case Locations.Sector12CIA:
@ -641,7 +641,7 @@ displayLocationContent = function() {
securityJob.style.display = "block";
agentJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12CIA,
1450, 38, 80, 12);
1450, 40, 80, 12);
break;
case Locations.Sector12NSA:
@ -654,7 +654,7 @@ displayLocationContent = function() {
securityJob.style.display = "block";
agentJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12NSA,
1400, 34, 80, 11);
1400, 36, 80, 11);
break;
case Locations.Sector12AlphaEnterprises:
@ -668,7 +668,7 @@ displayLocationContent = function() {
purchaseTor.style.display = "block";
purchaseHomeRam.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12AlphaEnterprises,
250, 10, 40, 4.5);
250, 12, 40, 4.5);
break;
case Locations.Sector12CarmichaelSecurity:
@ -682,7 +682,7 @@ displayLocationContent = function() {
securityJob.style.display = "block";
agentJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12CarmichaelSecurity,
500, 14, 60, 4.5);
500, 16, 60, 4.5);
break;
case Locations.Sector12FoodNStuff:
@ -698,7 +698,7 @@ displayLocationContent = function() {
employeeJob.style.display = "block";
employeePartTimeJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12JoesGuns,
100, 4, 20, 3.5);
120, 6, 20, 3.5);
break;
case Locations.Sector12IronGym:
@ -731,7 +731,7 @@ displayLocationContent = function() {
securityEngineerJob.style.display = "block";
networkEngineerJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.NewTokyoDefComm,
1300, 24, 70, 9);
1300, 26, 70, 9);
break;
case Locations.NewTokyoVitaLife:
@ -744,7 +744,7 @@ displayLocationContent = function() {
networkEngineerJob.style.display = "block";
businessJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.NewTokyoVitaLife,
750, 18, 100, 8);
750, 20, 100, 8);
break;
case Locations.NewTokyoGlobalPharmaceuticals:
@ -758,7 +758,7 @@ displayLocationContent = function() {
businessJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.NewTokyoGlobalPharmaceuticals,
900, 20, 80, 8.5);
900, 22, 80, 8.5);
break;
case Locations.NewTokyoNoodleBar:
@ -797,7 +797,7 @@ displayLocationContent = function() {
purchase256gb.style.display = "block";
purchaseHomeRam.style.display = "block";
setInfiltrateButton(infiltrate, Locations.IshimaStormTechnologies,
700, 20, 100, 10);
700, 22, 100, 10);
break;
case Locations.IshimaNovaMedical:
@ -810,7 +810,7 @@ displayLocationContent = function() {
networkEngineerJob.style.display = "block";
businessJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.IshimaNovaMedical,
600, 16, 50, 7.5);
600, 18, 50, 7.5);
break;
case Locations.IshimaOmegaSoftware:
@ -828,7 +828,7 @@ displayLocationContent = function() {
purchaseTor.style.display = "block";
purchaseHomeRam.style.display = "block";
setInfiltrateButton(infiltrate, Locations.IshimaOmegaSoftware,
200, 5, 40, 4);
200, 8, 40, 4);
break;
case Locations.VolhavenTravelAgency:
@ -861,7 +861,7 @@ displayLocationContent = function() {
purchase512gb.style.display = "block";
purchase1tb.style.display = "block";
setInfiltrateButton(infiltrate, Locations.VolhavenOmniTekIncorporated,
1500, 38, 100, 9.5);
1500, 40, 100, 9.5);
break;
case Locations.VolhavenNWO:
@ -874,7 +874,7 @@ displayLocationContent = function() {
businessJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.VolhavenNWO,
1800, 48, 200, 11);
1800, 50, 200, 11);
break;
case Locations.VolhavenHeliosLabs:
@ -886,7 +886,7 @@ displayLocationContent = function() {
securityEngineerJob.style.display = "block";
networkEngineerJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.VolhavenHeliosLabs,
1200, 24, 75, 9);
1200, 26, 75, 9);
break;
case Locations.VolhavenOmniaCybersystems:
@ -898,7 +898,7 @@ displayLocationContent = function() {
networkEngineerJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.VolhavenOmniaCybersystems,
900, 24, 90, 9.5);
900, 26, 90, 9.5);
break;
case Locations.VolhavenLexoCorp:
@ -912,7 +912,7 @@ displayLocationContent = function() {
businessJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.VolhavenLexoCorp,
500, 10, 40, 5.5);
500, 12, 40, 5.5);
break;
case Locations.VolhavenSysCoreSecurities:
@ -923,7 +923,7 @@ displayLocationContent = function() {
securityEngineerJob.style.display = "block";
networkEngineerJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.VolhavenSysCoreSecurities,
600, 12, 50, 6);
600, 14, 50, 6);
break;
case Locations.VolhavenCompuTek:
@ -944,7 +944,7 @@ displayLocationContent = function() {
purchaseTor.style.display = "block";
purchaseHomeRam.style.display = "block";
setInfiltrateButton(infiltrate, Locations.VolhavenCompuTek,
300, 8, 35, 5);
300, 10, 35, 5);
break;
case Locations.VolhavenMilleniumFitnessGym:

@ -1,8 +1,12 @@
/* Environment
* NetScript program environment
*/
function Environment(parent) {
this.vars = Object.create(parent ? parent.vars : null);
function Environment(workerScript,parent) {
if (parent){
this.vars = parent.vars;
} else {
this.vars = NetscriptFunctions(workerScript);
}
this.parent = parent;
this.stopFlag = false;
}
@ -44,7 +48,20 @@ Environment.prototype = {
}
return (scope || this).vars[name] = value;
},
setArrayElement: function(name, idx, value) {
var scope = this.lookup(name);
if (!scope && this.parent) {
console.log("Here");
throw new Error("Undefined variable " + name);
}
var arr = (scope || this).vars[name];
if (!(arr.constructor === Array || arr instanceof Array)) {
throw new Error("Variable is not an array: " + name);
}
return (scope || this).vars[name][idx] = value;
},
//Creates (or overwrites) a variable in the current scope
def: function(name, value) {
return this.vars[name] = value;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,25 +0,0 @@
/* InputStream class. Creates a "stream object" that provides operations to read
* from a string. */
function InputStream(input) {
var pos = 0, line = 1, col = 0;
return {
next : next,
peek : peek,
eof : eof,
croak : croak,
};
function next() {
var ch = input.charAt(pos++);
if (ch == "\n") line++, col = 0; else col++;
return ch;
}
function peek() {
return input.charAt(pos);
}
function eof() {
return peek() == "";
}
function croak(msg) {
throw new Error(msg + " (" + line + ":" + col + ")");
}
}

@ -1,326 +0,0 @@
/* Parser
* Creates Abstract Syntax Tree Nodes
* Operates on a stream of tokens from the Tokenizer
*/
var FALSE = {type: "bool", value: false};
function Parser(input) {
var PRECEDENCE = {
"=": 1,
"||": 2,
"&&": 3,
"<": 7, ">": 7, "<=": 7, ">=": 7, "==": 7, "!=": 7,
"+": 10, "-": 10,
"*": 20, "/": 20, "%": 20,
};
return parse_toplevel();
//Returns true if the next token is a punc type with value ch
function is_punc(ch) {
var tok = input.peek();
return tok && tok.type == "punc" && (!ch || tok.value == ch) && tok;
}
//Returns true if the next token is the kw keyword
function is_kw(kw) {
var tok = input.peek();
return tok && tok.type == "kw" && (!kw || tok.value == kw) && tok;
}
//Returns true if the next token is an op type with the given op value
function is_op(op) {
var tok = input.peek();
return tok && tok.type == "op" && (!op || tok.value == op) && tok;
}
//Checks that the next character is the given punctuation character and throws
//an error if it's not. If it is, skips over it in the input
function checkPuncAndSkip(ch) {
if (is_punc(ch)) input.next();
else input.croak("Expecting punctuation: \"" + ch + "\"");
}
//Checks that the next character is the given keyword and throws an error
//if its not. If it is, skips over it in the input
function checkKeywordAndSkip(kw) {
if (is_kw(kw)) input.next();
else input.croak("Expecting keyword: \"" + kw + "\"");
}
//Checks that the next character is the given operator and throws an error
//if its not. If it is, skips over it in the input
function checkOpAndSkip(op) {
if (is_op(op)) input.next();
else input.croak("Expecting operator: \"" + op + "\"");
}
function unexpected() {
input.croak("Unexpected token: " + JSON.stringify(input.peek()));
}
function maybe_binary(left, my_prec) {
var tok = is_op();
if (tok) {
var his_prec = PRECEDENCE[tok.value];
if (his_prec > my_prec) {
input.next();
return maybe_binary({
type : tok.value == "=" ? "assign" : "binary",
operator : tok.value,
left : left,
right : maybe_binary(parse_atom(), his_prec)
}, my_prec);
}
}
return left;
}
function delimited(start, stop, separator, parser) {
var a = [], first = true;
checkPuncAndSkip(start);
while (!input.eof()) {
if (is_punc(stop)) break;
if (first) first = false; else checkPuncAndSkip(separator);
if (is_punc(stop)) break;
a.push(parser());
}
checkPuncAndSkip(stop);
return a;
}
function parse_call(func) {
return {
type: "call",
func: func,
args: delimited("(", ")", ",", parse_expression),
};
}
function parse_varname() {
var name = input.next();
if (name.type != "var") input.croak("Expecting variable name");
return name.value;
}
/* type: "if",
* cond: [ {"type": "var", "value": "cond1"}, {"type": "var", "value": "cond2"}...]
* then: [ {"type": "var", "value": "then1"}, {"type": "var", "value": "then2"}...]
* else: {"type": "var", "value": "foo"}
*/
function parse_if() {
checkKeywordAndSkip("if");
//Conditional
var cond = parse_expression();
//Body
var then = parse_expression();
var ret = {
type: "if",
cond: [],
then: [],
};
ret.cond.push(cond);
ret.then.push(then);
// Parse all elif branches
while (is_kw("elif")) {
input.next();
var cond = parse_expression();
var then = parse_expression();
ret.cond.push(cond);
ret.then.push(then);
}
// Parse else branch, if it exists
if (is_kw("else")) {
input.next();
ret.else = parse_expression();
}
return ret;
}
/* for (init, cond, postloop) {code;}
*
* type: "for",
* init: assign node,
* cond: var node,
* postloop: assign node
* code: prog node
*/
function parse_for() {
checkKeywordAndSkip("for");
temp = delimited("(", ")", ";", parse_expression);
var splitExpressions = temp.slice();
code = parse_expression();
if (splitExpressions.length != 3) {
throw new Error("for statement has incorrect number of arguments");
}
//TODO Check type of the init, cond, and postloop nodes
return {
type: "for",
init: splitExpressions[0],
cond: splitExpressions[1],
postloop: splitExpressions[2],
code: code
}
}
/* while (cond) {}
*
* type: "while",
* cond: var node
* code: prog node
*/
function parse_while() {
checkKeywordAndSkip("while");
var cond = parse_expression();
var code = parse_expression();
return {
type: "while",
cond: cond,
code: code
}
}
/* hacknetnodes[i].operator
*/
function parse_hacknetnodes() {
var index = null;
if (is_punc("[")) {
index = parse_expression();
if (index.type != "index") {
unexpected();
}
}
if (is_punc(".")) {
checkPuncAndSkip(".");
var op = maybe_call(function() {
var tok = input.next();
return tok;
});
return {
type: "var",
value: "hacknetnodes",
index: index,
op: op,
};
}
unexpected();
}
//Declaring a new array with Array[1,2,3]
function parse_arraydecl() {
var array = delimited("[", "]", ",", parse_expression);
return {type: "var",
value: "array",
array: array
};
}
//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() {
var index = delimited("[", "]", ";", parse_expression);
var val = 0;
if (index.length == 1) {
val = index[0];
} else {
unexpected();
}
return { type: "index", value: val };
}
function parse_bool() {
return {
type : "bool",
value : input.next().value == "true"
};
}
function maybe_call(expr) {
expr = expr();
return is_punc("(") ? parse_call(expr) : expr;
}
function parse_atom() {
return maybe_call(function(){
if (is_punc("(")) {
input.next();
var exp = parse_expression();
checkPuncAndSkip(")");
return exp;
}
if (is_punc("{")) return parse_prog();
if (is_punc("[")) return parse_arrayindex();
if (is_kw("if")) return parse_if();
if (is_kw("for")) return parse_for();
if (is_kw("while")) return parse_while();
if (is_kw("true") || is_kw("false")) return parse_bool();
var tok = input.next();
if (tok.type == "var" && tok.value == "hacknetnodes") return parse_hacknetnodes();
if (tok.type == "var" && tok.value == "Array") return parse_arraydecl();
if (tok.type == "var" && (is_punc("[") || is_punc("."))) {
return parse_arrayop(tok);
}
if (tok.type == "var" || tok.type == "num" || tok.type == "str")
return tok;
unexpected();
});
}
function parse_toplevel() {
var prog = [];
while (!input.eof()) {
prog.push(parse_expression());
if (!input.eof()) checkPuncAndSkip(";");
}
//Return the top level Abstract Syntax Tree, where the top node is a "prog" node
return { type: "prog", prog: prog };
}
function parse_prog() {
var prog = delimited("{", "}", ";", parse_expression);
if (prog.length == 0) return FALSE;
if (prog.length == 1) return prog[0];
return { type: "prog", prog: prog };
}
function parse_expression() {
return maybe_call(function(){
return maybe_binary(parse_atom(), 0);
});
}
}

@ -1,168 +0,0 @@
/* Tokenizer
* Acts on top of the InputStream class. Takes in a character input stream and and parses it into tokens.
* Tokens can be accessed with peek() and next().
*
* Token types:
* {type: "punc", value: "(" } // punctuation: parens, comma, semicolon etc.
* {type: "num", value: 5 } // numbers (including floats)
* {type: "str", value: "Hello World!" } // strings
* {type: "kw", value: "for/if/..." } // keywords, see defs below
* {type: "var", value: "a" } // identifiers/variables
* {type: "op", value: "!=" } // operator characters
* {type: "bool", value: "true" } // Booleans
*
*/
function Tokenizer(input) {
var current = null;
var keywords = " if elif else true false while for ";
return {
next : next,
peek : peek,
eof : eof,
croak : input.croak
}
function is_keyword(x) {
return keywords.indexOf(" " + x + " ") >= 0;
}
function is_digit(ch) {
return /[0-9]/i.test(ch);
}
//An identifier can start with any letter or an underscore
function is_id_start(ch) {
return /[a-z_]/i.test(ch);
}
function is_id(ch) {
return is_id_start(ch) || "?!-<>=0123456789".indexOf(ch) >= 0;
}
function is_op_char(ch) {
return "+-*/%=&|<>!".indexOf(ch) >= 0;
}
function is_punc(ch) {
return ",;(){}[].".indexOf(ch) >= 0;
}
function is_whitespace(ch) {
return " \t\n".indexOf(ch) >= 0;
}
function read_while(predicate) {
var str = "";
while (!input.eof() && predicate(input.peek()))
str += input.next();
return str;
}
function read_number() {
var has_dot = false;
//Reads the number from the input. Checks for only a single decimal point
var number = read_while(function(ch){
if (ch == ".") {
if (has_dot) return false;
has_dot = true;
return true;
}
return is_digit(ch);
});
return { type: "num", value: parseFloat(number) };
}
//This function also checks the identifier against a list of known keywords (defined at the top)
//and will return a kw object rather than identifier if it is one
function read_ident() {
//Identifier must start with a letter or underscore..and can contain anything from ?!-<>=0123456789
var id = read_while(is_id);
return {
type : is_keyword(id) ? "kw" : "var",
value : id
};
}
function read_escaped(end) {
var escaped = false, str = "";
input.next(); //Skip the quotation mark
while (!input.eof()) {
var ch = input.next();
if (escaped) {
str += ch;
escaped = false;
} else if (ch == "\\") {
escaped = true;
} else if (ch == end) {
break;
} else {
str += ch;
}
}
return str;
}
function read_string(ch) {
if (ch == '"') {
return { type: "str", value: read_escaped('"') };
} else if (ch == '\'') {
return { type: "str", value: read_escaped('\'') };
}
}
//Only supports single-line comments right now
function skip_comment() {
read_while(function(ch){ return ch != "\n" });
input.next();
}
//Gets the next token
function read_next() {
//Skip over whitespace
read_while(is_whitespace);
if (input.eof()) return null;
//Peek the next character and decide what to do based on what that
//next character is
var ch = input.peek();
if (ch == "//") {
skip_comment();
return read_next();
}
if (ch == '"' || ch == '\'') return read_string(ch);
if (is_digit(ch)) return read_number();
if (is_id_start(ch)) return read_ident();
if (is_punc(ch)) return {
type : "punc",
value : input.next()
}
if (is_op_char(ch)) return {
type : "op",
value : read_while(is_op_char)
}
}
function peek() {
//Returns current token, unless its null in which case it grabs the next one
//and returns it
return current || (current = read_next());
}
function next() {
//The token might have been peaked already, in which case read_next() was already
//called so just return current
var tok = current;
current = null;
return tok || read_next();
}
function eof() {
return peek() == null;
}
}

@ -8,7 +8,8 @@ function WorkerScript(runningScriptObj) {
this.running = false;
this.serverIp = null;
this.code = runningScriptObj.scriptRef.code;
this.env = new Environment();
this.env = new Environment(this);
this.env.set("args", runningScriptObj.args);
this.output = "";
this.ramUsage = 0;
this.scriptRef = runningScriptObj;
@ -31,7 +32,7 @@ function runScriptsLoop() {
//If it isn't running, start the script
if (workerScripts[i].running == false && workerScripts[i].env.stopFlag == false) {
try {
var ast = Parser(Tokenizer(InputStream(workerScripts[i].code)));
var ast = acorn.parse(workerScripts[i].code);
//console.log(ast);
} catch (e) {
console.log("Error parsing script: " + workerScripts[i].name);

@ -33,6 +33,18 @@ function scriptEditorInit() {
};
document.addEventListener("DOMContentLoaded", scriptEditorInit, false);
//Updates line number and RAM usage in script
function upgradeScriptEditorContent() {
var txt = $("#script-editor-text")[0];
var lineNum = txt.value.substr(0, txt.selectionStart).split("\n").length;
var code = document.getElementById("script-editor-text").value;
var codeCopy = code.repeat(1);
var ramUsage = calculateRamUsage(codeCopy);
document.getElementById("script-editor-status-text").innerText =
"Line Number: " + lineNum + ", RAM: " + formatNumber(ramUsage, 2).toString() + "GB";
}
//Define key commands in script editor (ctrl o to save + close, etc.)
$(document).keydown(function(e) {
if (Engine.currentPage == Engine.Page.ScriptEditor) {
@ -126,10 +138,17 @@ Script.prototype.saveScript = function() {
//Updates how much RAM the script uses when it is running.
Script.prototype.updateRamUsage = function() {
var baseRam = 1.4;
var codeCopy = this.code.repeat(1);
this.ramUsage = calculateRamUsage(codeCopy);
console.log("ram usage: " + this.ramUsage);
if (isNaN(this.ramUsage)) {
dialogBoxCreate("ERROR in calculating ram usage. This is a bug, please report to game develoepr");
}
}
function calculateRamUsage(codeCopy) {
codeCopy = codeCopy.replace(/\s/g,''); //Remove all whitespace
var baseRam = 1.4;
var whileCount = numOccurrences(codeCopy, "while(");
var forCount = numOccurrences(codeCopy, "for(");
var ifCount = numOccurrences(codeCopy, "if(");
@ -150,6 +169,7 @@ Script.prototype.updateRamUsage = function() {
var getHostnameCount = numOccurrences(codeCopy, "getHostname(");
var getHackingLevelCount = numOccurrences(codeCopy, "getHackingLevel(");
var getServerMoneyAvailableCount = numOccurrences(codeCopy, "getServerMoneyAvailable(");
var getServerMaxMoneyCount = numOccurrences(codeCopy, "getServerMaxMoney(");
var getServerSecurityCount = numOccurrences(codeCopy, "getServerSecurityLevel(");
var getServerBaseSecurityCount = numOccurrences(codeCopy, "getServerBaseSecurityLevel(");
var getServerReqdHackingCount = numOccurrences(codeCopy, "getServerRequiredHackingLevel(");
@ -161,43 +181,50 @@ Script.prototype.updateRamUsage = function() {
var hnUpgLevelCount = numOccurrences(codeCopy, ".upgradeLevel(");
var hnUpgRamCount = numOccurrences(codeCopy, ".upgradeRam()");
var hnUpgCoreCount = numOccurrences(codeCopy, ".upgradeCore()");
var scriptGetStockCount = numOccurrences(codeCopy, "getStockPrice(") +
numOccurrences(codeCopy, "getStockPosition(");
var scriptBuySellStockCount = numOccurrences(codeCopy, "buyStock(") +
numOccurrences(codeCopy, "sellStock(");
var scriptPurchaseServerCount = numOccurrences(codeCopy, "purchaseServer(");
var scriptRoundCount = numOccurrences(codeCopy, "round(");
this.ramUsage = baseRam +
((whileCount * CONSTANTS.ScriptWhileRamCost) +
(forCount * CONSTANTS.ScriptForRamCost) +
(ifCount * CONSTANTS.ScriptIfRamCost) +
(hackCount * CONSTANTS.ScriptHackRamCost) +
(growCount * CONSTANTS.ScriptGrowRamCost) +
(weakenCount * CONSTANTS.ScriptWeakenRamCost) +
(scanCount * CONSTANTS.ScriptScanRamCost) +
(nukeCount * CONSTANTS.ScriptNukeRamCost) +
(brutesshCount * CONSTANTS.ScriptBrutesshRamCost) +
(ftpcrackCount * CONSTANTS.ScriptFtpcrackRamCost) +
(relaysmtpCount * CONSTANTS.ScriptRelaysmtpRamCost) +
(httpwormCount * CONSTANTS.ScriptHttpwormRamCost) +
(sqlinjectCount * CONSTANTS.ScriptSqlinjectRamCost) +
(runCount * CONSTANTS.ScriptRunRamCost) +
(execCount * CONSTANTS.ScriptExecRamCost) +
(scpCount * CONSTANTS.ScriptScpRamCost) +
(hasRootAccessCount * CONSTANTS.ScriptHasRootAccessRamCost) +
(getHostnameCount * CONSTANTS.ScriptGetHostnameRamCost) +
(getHackingLevelCount * CONSTANTS.ScriptGetHackingLevelRamCost) +
(getServerMoneyAvailableCount * CONSTANTS.ScriptGetServerMoneyRamCost) +
(getServerSecurityCount * CONSTANTS.ScriptGetServerSecurityRamCost) +
(getServerBaseSecurityCount * CONSTANTS.ScriptGetServerSecurityRamCost) +
(getServerReqdHackingCount * CONSTANTS.ScriptGetServerReqdHackRamCost) +
(fileExistsCount * CONSTANTS.ScriptFileExistsRamCost) +
(isRunningCount * CONSTANTS.ScriptIsRunningRamCost) +
(numOperators * CONSTANTS.ScriptOperatorRamCost) +
(purchaseHacknetCount * CONSTANTS.ScriptPurchaseHacknetRamCost) +
(hacknetnodesArrayCount * CONSTANTS.ScriptHacknetNodesRamCost) +
(hnUpgLevelCount * CONSTANTS.ScriptHNUpgLevelRamCost) +
(hnUpgRamCount * CONSTANTS.ScriptHNUpgRamRamCost) +
(hnUpgCoreCount * CONSTANTS.ScriptHNUpgCoreRamCost));
console.log("ram usage: " + this.ramUsage);
if (isNaN(this.ramUsage)) {
dialogBoxCreate("ERROR in calculating ram usage. This is a bug, please report to game develoepr");
}
return baseRam +
((whileCount * CONSTANTS.ScriptWhileRamCost) +
(forCount * CONSTANTS.ScriptForRamCost) +
(ifCount * CONSTANTS.ScriptIfRamCost) +
(hackCount * CONSTANTS.ScriptHackRamCost) +
(growCount * CONSTANTS.ScriptGrowRamCost) +
(weakenCount * CONSTANTS.ScriptWeakenRamCost) +
(scanCount * CONSTANTS.ScriptScanRamCost) +
(nukeCount * CONSTANTS.ScriptNukeRamCost) +
(brutesshCount * CONSTANTS.ScriptBrutesshRamCost) +
(ftpcrackCount * CONSTANTS.ScriptFtpcrackRamCost) +
(relaysmtpCount * CONSTANTS.ScriptRelaysmtpRamCost) +
(httpwormCount * CONSTANTS.ScriptHttpwormRamCost) +
(sqlinjectCount * CONSTANTS.ScriptSqlinjectRamCost) +
(runCount * CONSTANTS.ScriptRunRamCost) +
(execCount * CONSTANTS.ScriptExecRamCost) +
(scpCount * CONSTANTS.ScriptScpRamCost) +
(hasRootAccessCount * CONSTANTS.ScriptHasRootAccessRamCost) +
(getHostnameCount * CONSTANTS.ScriptGetHostnameRamCost) +
(getHackingLevelCount * CONSTANTS.ScriptGetHackingLevelRamCost) +
(getServerMoneyAvailableCount * CONSTANTS.ScriptGetServerMoneyRamCost) +
(getServerMaxMoneyCount * CONSTANTS.ScriptGetServerMoneyRamCost) +
(getServerSecurityCount * CONSTANTS.ScriptGetServerSecurityRamCost) +
(getServerBaseSecurityCount * CONSTANTS.ScriptGetServerSecurityRamCost) +
(getServerReqdHackingCount * CONSTANTS.ScriptGetServerReqdHackRamCost) +
(fileExistsCount * CONSTANTS.ScriptFileExistsRamCost) +
(isRunningCount * CONSTANTS.ScriptIsRunningRamCost) +
(numOperators * CONSTANTS.ScriptOperatorRamCost) +
(purchaseHacknetCount * CONSTANTS.ScriptPurchaseHacknetRamCost) +
(hacknetnodesArrayCount * CONSTANTS.ScriptHacknetNodesRamCost) +
(hnUpgLevelCount * CONSTANTS.ScriptHNUpgLevelRamCost) +
(hnUpgRamCount * CONSTANTS.ScriptHNUpgRamRamCost) +
(hnUpgCoreCount * CONSTANTS.ScriptHNUpgCoreRamCost) +
(scriptGetStockCount * CONSTANTS.ScriptGetStockRamCost) +
(scriptBuySellStockCount * CONSTANTS.ScriptBuySellStockRamCost) +
(scriptPurchaseServerCount * CONSTANTS.ScriptPurchaseServerRamCost) +
(scriptRoundCount * CONSTANTS.ScriptRoundRamCost));
}
Script.prototype.toJSON = function() {

@ -225,10 +225,20 @@ function initSymbolToStockMap() {
}
}
function stockMarketCycle() {
console.log("Cycling the Stock Market");
for (var name in StockMarket) {
if (StockMarket.hasOwnProperty(name)) {
var stock = StockMarket[name];
stock.b = !stock.b;
}
}
}
//Returns true if successful, false otherwise
function buyStock(stock, shares) {
if (shares == 0) {return false;}
if (stock == null || shares < 0) {
if (stock == null || shares < 0 || isNaN(shares)) {
dialogBoxCreate("Failed to buy stock. This may be a bug, contact developer");
return false;
}
@ -257,7 +267,7 @@ function buyStock(stock, shares) {
//Returns true if successful and false otherwise
function sellStock(stock, shares) {
if (shares == 0) {return false;}
if (stock == null || shares < 0) {
if (stock == null || shares < 0 || isNaN(shares)) {
dialogBoxCreate("Failed to sell stock. This may be a bug, contact developer");
return false;
}
@ -328,8 +338,9 @@ function displayStockMarketContent() {
if (Player.hasWseAccount == null) {Player.hasWseAccount = false;}
if (Player.hasTixApiAccess == null) {Player.hasTixApiAccess = false;}
//Purchase WSE Account button
var wseAccountButton = clearEventListeners("stock-market-buy-account");
wseAccountButton.innerText = "Buy WSE Account - $" + formatNumber(CONSTANTS.WSEAccountCost, 2).toString()
wseAccountButton.innerText = "Buy WSE Account - $" + formatNumber(CONSTANTS.WSEAccountCost, 2).toString();
if (!Player.hasWseAccount && Player.money >= CONSTANTS.WSEAccountCost) {
wseAccountButton.setAttribute("class", "a-link-button");
} else {
@ -343,6 +354,22 @@ function displayStockMarketContent() {
return false;
});
//Purchase TIX API Access account
var tixApiAccessButton = clearEventListeners("stock-market-buy-tix-api");
tixApiAccessButton.innerText = "Buy Trade Information eXchange (TIX) API Access - $" +
formatNumber(CONSTANTS.TIXAPICost, 2).toString();
if (!Player.hasTixApiAccess && Player.money >= CONSTANTS.TIXAPICost) {
tixApiAccessButton.setAttribute("class", "a-link-button");
} else {
tixApiAccessButton.setAttribute("class", "a-link-button-inactive");
}
tixApiAccessButton.addEventListener("click", function() {
Player.hasTixApiAccess = true;
Player.loseMoney(CONSTANTS.TIXAPICost);
displayStockMarketContent();
return false;
});
var stockList = document.getElementById("stock-market-list");
if (stockList == null) {return;}

@ -116,6 +116,7 @@ var Engine = {
document.getElementById("script-editor-text").value = code;
}
document.getElementById("script-editor-text").focus();
upgradeScriptEditorContent();
Engine.currentPage = Engine.Page.ScriptEditor;
},
@ -568,7 +569,9 @@ var Engine = {
checkFactionInvitations: 100, //Check whether you qualify for any faction invitations every 5 minutes
passiveFactionGrowth: 600,
messages: 300,
stockTick: 50, //Update stock prices
stockTick: 30, //Update stock prices
sCr: 1500,
updateScriptEditorDisplay: 5,
},
decrementAllCounters: function(numCycles = 1) {
@ -648,7 +651,32 @@ var Engine = {
if (Player.hasWseAccount) {
updateStockPrices();
}
Engine.Counters.stockTick = 50;
Engine.Counters.stockTick = 30;
}
if (Engine.Counters.sCr <= 0) {
//Assume 4Sig will always indicate state of market
if (Player.hasWseAccount) {
console.log("Determining stock market cycle");
var thresh = 0.66;
var stock = StockMarket[Locations.Sector12FourSigma];
if (stock == null) {
console.log("ERR: Could not find 4Sigma stock");
return;
}
if (stock.b) {thresh = 0.34;}
if (Math.random() < thresh) {
stockMarketCycle();
}
}
Engine.Counters.sCr = 1500;
}
if (Engine.Counters.updateScriptEditorDisplay <= 0) {
if (Engine.currentPage == Engine.Page.ScriptEditor) {
upgradeScriptEditorContent();
}
Engine.Counters.updateScriptEditorDisplay = 5;
}
},

@ -50,4 +50,10 @@ function compareArrays(a1, a2) {
function printArray(a) {
return "[" + a.join(", ") + "]";
}
//Returns bool indicating whether or not its a power of 2
function powerOfTwo(n) {
if (isNaN(n)) {return false;}
return n && (n & (n-1)) === 0;
}

@ -3,10 +3,10 @@
//Generate a random IP address
//Will not return an IP address that already exists in the AllServers array
createRandomIp = function() {
var ip = createRandomByte() +'.' +
createRandomByte() +'.' +
createRandomByte() +'.' +
createRandomByte();
var ip = createRandomByte(99) +'.' +
createRandomByte(9) +'.' +
createRandomByte(9) +'.' +
createRandomByte(9);
//If the Ip already exists, recurse to create a new one
if (ipExists(ip)) {
@ -27,8 +27,8 @@ ipExists = function(ip) {
return false;
}
createRandomByte = function() {
return Math.round(Math.random()*256);
createRandomByte = function(n=9) {
return Math.round(Math.random()*n);
}
isValidIPAddress = function(ipaddress) {

3631
utils/acorn.js Normal file

File diff suppressed because it is too large Load Diff