Merge branch 'master' of https://github.com/danielyxie/netburner into bugfixes

This commit is contained in:
danielyxie 2017-09-21 16:30:03 -05:00
commit 398070f053
38 changed files with 16605 additions and 7087 deletions

@ -36,12 +36,10 @@
}
#javascript-editor textarea {
color: var(--my-font-color);
}
.ace_line,
.ace_line * {
color: var(--my-font-color);
background-color:transparent;
margin:0px;
padding:0px;
@ -140,6 +138,26 @@
color: #ffffff;
}
#script-editor-options-panel {
position:absolute;
right: 9%;
bottom:15%;
border:2px solid white;
width:19%;
background-color:#444;
padding:2px;
overflow:auto;
z-index: 1;
color: white;
}
#script-editor-options-panel fieldset {
margin-top:8px;
margin-bottom:8px;
padding: 2px;
font-size:12px;
}
/* Active scripts */
.active-scripts-list {
list-style-type: none;
@ -406,6 +424,7 @@
margin: 6px;
display: inline-block;
color: var(--my-font-color);
background-color:black;
}
#faction-donate-amount-txt {

@ -321,7 +321,7 @@ a:link, a:visited {
position: absolute; /* Stay in place */
right: 0;
top: 0;
height: 195px; /* Full height */
height: 205px; /* Full height */
/*margin: 50% auto;*/
padding: 5px;
border: 2px solid var(--my-highlight-color);

@ -4,7 +4,7 @@
height: 100%;
width: 99%;
overflow: auto;
overflow-y: scroll;
overflow-y: scroll;
}
#terminal {
@ -19,11 +19,6 @@
table-layout:fixed;
}
/*
.posted {
width: 70%;
}*/
#terminal-input {
background-color: var(--my-background-color);
color: var(--my-font-color);
@ -31,8 +26,7 @@
}
.terminal-input {
display: table-cell;
width: 90%;
display: inline-block;
padding: 0px !important;
margin: 0px !important;
border: 0px;

21575
dist/bundle.js vendored

File diff suppressed because one or more lines are too long

@ -105,6 +105,47 @@
<a id="script-editor-netscript-doc-button" class="a-link-button" href="https://bitburner.wikia.com/wiki/Netscript" target="_blank"> Netscript Documentation </a>
</div>
</div> <!-- End wrapper -->
<div id="script-editor-options-panel">
<h1 style="color:white;"> Script Editor Options </h1>
<fieldset>
<label for="script-editor-option-theme">Theme</label>
<select id="script-editor-option-theme">
<option value="Chaos">Chaos</option>
<option value="Chrome">Chrome</option>
<option value="Monokai">Monokai</option>
<option value="Solarized_Dark">Solarized Dark</option>
<option value="Solarized_Light">Solarized Light</option>
<option value="Terminal">Terminal</option>
<option value="Twilight">Twilight</option>
<option value="XCode">XCode</option>
</select>
</fieldset>
<fieldset>
<label for="script-editor-option-keybinding">Key Binding</label>
<select id="script-editor-option-keybinding">
<option value="ace">Ace</option>
<option value="vim">Vim</option>
<option value="emacs">Emacs</option>
</select>
</fieldset>
<fieldset>
<label for="script-editor-option-highlightactiveline">Highlight Active Line</label>
<input type="checkbox" name="script-editor-option-highlightactiveline" id="script-editor-option-highlightactiveline" checked>
</fieldset>
<fieldset>
<label for="script-editor-option-showinvisibles">Show Invisibles</label></td>
<input type="checkbox" name="script-editor-option-showinvisibles" id="script-editor-option-showinvisibles">
</fieldset>
<fieldset>
<label for="script-editor-option-usesofttab">Use Soft Tab</label></td>
<input type="checkbox" name="script-editor-option-usesofttab" id="script-editor-option-usesofttab" checked>
</fieldset>
</div> <!-- End script editor options panel -->
</div>
<!-- Terminal page -->
@ -462,8 +503,9 @@
<p> --------------- </p>
<p id="faction-work-description-text">
Perform work/carry out assignments for your faction to help further its cause! By doing so
you will gain reputation for your faction. You will also gain reputation passively over time,
although at a very slow rate. Note that you cannot
you will earn reputation for your faction. You will also gain reputation passively over time,
although at a very slow rate. Earning reputation will allow you to purchase Augmentations
through this faction, which are powerful upgrades that enhance your abilities. Note that you cannot
use your terminal or create scripts when you are performing a task! <br><br><br><br>
</p>
@ -738,6 +780,7 @@
<div id="log-box-container">
<div id="log-box-content">
<span id="log-box-close"> &times; </span>
<p id="log-box-text-header"> </p>
<p id="log-box-text"> </p>
</div>
</div>
@ -787,6 +830,10 @@
</div>
</div>
<!-- Mission container -->
<div id="mission-container" class="generic-fullscreen-container">
</div>
<!-- Work in progress screen -->
<div id="work-in-progress-container" class="generic-fullscreen-container">
<p id="work-in-progress-text"> </p>

@ -183,6 +183,7 @@ function updateActiveScriptsItems() {
}
document.getElementById("active-scripts-total-prod").innerHTML =
"Total online production rate: $" + formatNumber(total, 2) + " / second";
return total;
}
//Updates the content of the given item in the Active Scripts list
@ -197,7 +198,6 @@ function updateActiveScriptsItemContent(workerscript) {
itemNameArray.push(workerscript.args[i].toString());
}
var itemName = itemNameArray.join("-");
//var itemName = "active-scripts-" + server.hostname + "-" + workerscript.name;
var itemContent = document.getElementById(itemName + "-content")
//Clear the item

@ -53,7 +53,27 @@ function initBitNodes() {
"upgrade its level up to a maximum of 3. This Source-File lets you access and use the Singularity " +
"Functions in other BitNodes. Each level of this Source-File will open up more Singularity Functions " +
"that you can use.");
BitNodes["BitNode5"] = new BitNode(5, "Artificial Intelligence", "COMING SOON"); //Int
BitNodes["BitNode5"] = new BitNode(5, "Artificial Intelligence", "Posthuman", "They said it couldn't be done. They said the human brain, " +
"along with its consciousness and intelligence, couldn't be replicated. They said the complexity " +
"of the brain results from unpredictable, nonlinear interactions that couldn't be modeled " +
"by 1's and 0's. They were wrong.<br><br>" +
"In this BitNode:<br><br>" +
"The base security level of servers is doubled<br>" +
"The starting money on servers is halved, but the maximum money is doubled<br>" +
"Most methods of earning money now give significantly less<br>" +
"Augmentations are more expensive<br>" +
"Hacking experience gain rates are reduced<br><br>" +
"Destroying this BitNode will give you Source-File 5, or if you already have this Source-File it will " +
"upgrade its level up to a maximum of 3. This Source-File grants you a special new stat called Intelligence. " +
"Intelligence is unique because it is permanent and persistent (it never gets reset back to 1). However " +
"gaining Intelligence experience is much slower than other stats, and it is also hidden (you won't know " +
"when you gain experience and how much). Higher Intelligence levels will boost your production for many actions " +
"in the game. <br><br>" +
"In addition, this Source-File will unlock the getBitNodeMultipliers() Netscript function, " +
"and will also raise all of your hacking-related multipliers by:<br><br>" +
"Level 1: 4%<br>" +
"Level 2: 6%<br>" +
"Level 3: 7%");
BitNodes["BitNode6"] = new BitNode(6, "Hacktocracy", "COMING SOON"); //Healthy Hacknet balancing mechanic
BitNodes["BitNode7"] = new BitNode(7, "Do Androids Dream?", "COMING SOON"); //Build androids for automation
BitNodes["BitNode8"] = new BitNode(8, "Ghost of Wall Street", "COMING SOON"); //Trading only viable strategy
@ -87,6 +107,7 @@ let BitNodeMultipliers = {
ServerStartingMoney: 1,
ServerGrowthRate: 1,
ServerWeakenRate: 1,
ServerStartingSecurity: 1,
ManualHackMoney: 1,
ScriptHackMoney: 1,
@ -118,7 +139,7 @@ function initBitNodeMultipliers() {
}
switch (Player.bitNodeN) {
case 1:
case 1: //Source Genesis (every multiplier is 1)
break;
case 2: //Rise of the Underworld
BitNodeMultipliers.ServerMaxMoney = 0.2;
@ -139,6 +160,16 @@ function initBitNodeMultipliers() {
BitNodeMultipliers.CrimeExpGain = 0.5;
BitNodeMultipliers.FactionWorkRepGain = 0.75;
break;
case 5: //Artificial intelligence
BitNodeMultipliers.ServerMaxMoney = 2;
BitNodeMultipliers.ServerStartingSecurity = 2;
BitNodeMultipliers.ServerStartingMoney = 0.5;
BitNodeMultipliers.ScriptHackMoney = 0.25;
BitNodeMultipliers.HacknetNodeMoney = 0.2;
BitNodeMultipliers.CrimeMoney = 0.5;
BitNodeMultipliers.AugmentationMoneyCost = 2;
BitNodeMultipliers.HackExpGain = 0.5;
break;
case 11: //The Big Crash
BitNodeMultipliers.ServerMaxMoney = 0.1;
BitNodeMultipliers.ServerStartingMoney = 0.25;

@ -262,58 +262,58 @@ let CompanyPositions = {
//Constructor: CompanyPosition(name, reqHack, reqStr, reqDef, reqDex, reqAgi, reqCha, reqRep, salary)
//Software
SoftwareIntern: new CompanyPosition("Software Engineering Intern", 1, 0, 0, 0, 0, 0, 0, 30),
JuniorDev: new CompanyPosition("Junior Software Engineer", 51, 0, 0, 0, 0, 0, 8000, 72),
SeniorDev: new CompanyPosition("Senior Software Engineer", 251, 0, 0, 0, 0, 51, 40000, 150),
LeadDev: new CompanyPosition("Lead Software Developer", 401, 0, 0, 0, 0, 151, 200000, 450),
SoftwareIntern: new CompanyPosition("Software Engineering Intern", 1, 0, 0, 0, 0, 0, 0, 33),
JuniorDev: new CompanyPosition("Junior Software Engineer", 51, 0, 0, 0, 0, 0, 8000, 80),
SeniorDev: new CompanyPosition("Senior Software Engineer", 251, 0, 0, 0, 0, 51, 40000, 165),
LeadDev: new CompanyPosition("Lead Software Developer", 401, 0, 0, 0, 0, 151, 200000, 500),
//TODO Through darkweb, maybe?
FreelanceDeveloper: new CompanyPosition("Freelance Developer", 0, 0, 0, 0, 0, 0, 0, 0),
SoftwareConsultant: new CompanyPosition("Software Consultant", 51, 0, 0, 0, 0, 0, 0, 60),
SeniorSoftwareConsultant: new CompanyPosition("Senior Software Consultant", 251, 0, 0, 0, 0, 51, 0, 120),
SoftwareConsultant: new CompanyPosition("Software Consultant", 51, 0, 0, 0, 0, 0, 0, 66),
SeniorSoftwareConsultant: new CompanyPosition("Senior Software Consultant", 251, 0, 0, 0, 0, 51, 0, 132),
//IT
ITIntern: new CompanyPosition("IT Intern", 1, 0, 0, 0, 0, 0, 0, 24),
ITAnalyst: new CompanyPosition("IT Analyst", 26, 0, 0, 0, 0, 0, 7000, 60),
ITManager: new CompanyPosition("IT Manager", 151, 0, 0, 0, 0, 51, 35000, 120),
SysAdmin: new CompanyPosition("Systems Administrator", 251, 0, 0, 0, 0, 76, 175000, 375),
SecurityEngineer: new CompanyPosition("Security Engineer", 151, 0, 0, 0, 0, 26, 35000, 110),
NetworkEngineer: new CompanyPosition("Network Engineer", 151, 0, 0, 0, 0, 26, 35000, 110),
NetworkAdministrator: new CompanyPosition("Network Administrator", 251, 0, 0, 0, 0, 76, 175000, 375),
ITIntern: new CompanyPosition("IT Intern", 1, 0, 0, 0, 0, 0, 0, 26),
ITAnalyst: new CompanyPosition("IT Analyst", 26, 0, 0, 0, 0, 0, 7000, 66),
ITManager: new CompanyPosition("IT Manager", 151, 0, 0, 0, 0, 51, 35000, 132),
SysAdmin: new CompanyPosition("Systems Administrator", 251, 0, 0, 0, 0, 76, 175000, 410),
SecurityEngineer: new CompanyPosition("Security Engineer", 151, 0, 0, 0, 0, 26, 35000, 121),
NetworkEngineer: new CompanyPosition("Network Engineer", 151, 0, 0, 0, 0, 26, 35000, 121),
NetworkAdministrator: new CompanyPosition("Network Administrator", 251, 0, 0, 0, 0, 76, 175000, 410),
//Technology management
HeadOfSoftware: new CompanyPosition("Head of Software", 501, 0, 0, 0, 0, 251, 400000, 720),
HeadOfEngineering: new CompanyPosition("Head of Engineering", 501, 0, 0, 0, 0, 251, 800000, 1500),
VicePresident: new CompanyPosition("Vice President of Technology", 601, 0, 0, 0, 0, 401, 1600000, 2100),
CTO: new CompanyPosition("Chief Technology Officer", 751, 0, 0, 0, 0, 501, 3200000, 2400),
HeadOfSoftware: new CompanyPosition("Head of Software", 501, 0, 0, 0, 0, 251, 400000, 800),
HeadOfEngineering: new CompanyPosition("Head of Engineering", 501, 0, 0, 0, 0, 251, 800000, 1650),
VicePresident: new CompanyPosition("Vice President of Technology", 601, 0, 0, 0, 0, 401, 1600000, 2310),
CTO: new CompanyPosition("Chief Technology Officer", 751, 0, 0, 0, 0, 501, 3200000, 2640),
//Business
BusinessIntern: new CompanyPosition("Business Intern", 1, 0, 0, 0, 0, 1, 0, 42),
BusinessAnalyst: new CompanyPosition("Business Analyst", 6, 0, 0, 0, 0, 51, 8000, 90),
BusinessManager: new CompanyPosition("Business Manager", 51, 0, 0, 0, 0, 101, 40000, 180),
OperationsManager: new CompanyPosition("Operations Manager", 51, 0, 0, 0, 0, 226, 200000, 600),
CFO: new CompanyPosition("Chief Financial Officer", 76, 0, 0, 0, 0, 501, 800000, 1800),
CEO: new CompanyPosition("Chief Executive Officer", 101, 0, 0, 0, 0, 751, 3200000, 3600),
BusinessIntern: new CompanyPosition("Business Intern", 1, 0, 0, 0, 0, 1, 0, 46),
BusinessAnalyst: new CompanyPosition("Business Analyst", 6, 0, 0, 0, 0, 51, 8000, 100),
BusinessManager: new CompanyPosition("Business Manager", 51, 0, 0, 0, 0, 101, 40000, 200),
OperationsManager: new CompanyPosition("Operations Manager", 51, 0, 0, 0, 0, 226, 200000, 660),
CFO: new CompanyPosition("Chief Financial Officer", 76, 0, 0, 0, 0, 501, 800000, 1950),
CEO: new CompanyPosition("Chief Executive Officer", 101, 0, 0, 0, 0, 751, 3200000, 3900),
BusinessConsultant: new CompanyPosition("Business Consultant", 6, 0, 0, 0, 0, 51, 0, 80),
SeniorBusinessConsultant: new CompanyPosition("Senior Business Consultant", 51, 0, 0, 0, 0, 226, 0, 480),
BusinessConsultant: new CompanyPosition("Business Consultant", 6, 0, 0, 0, 0, 51, 0, 88),
SeniorBusinessConsultant: new CompanyPosition("Senior Business Consultant", 51, 0, 0, 0, 0, 226, 0, 525),
//Non-tech/management jobs
PartTimeWaiter: new CompanyPosition("Part-time Waiter", 0, 0, 0, 0, 0, 0, 0, 18),
PartTimeEmployee: new CompanyPosition("Part-time Employee", 0, 0, 0, 0, 0, 0, 0, 18),
PartTimeWaiter: new CompanyPosition("Part-time Waiter", 0, 0, 0, 0, 0, 0, 0, 20),
PartTimeEmployee: new CompanyPosition("Part-time Employee", 0, 0, 0, 0, 0, 0, 0, 20),
Waiter: new CompanyPosition("Waiter", 0, 0, 0, 0, 0, 0, 0, 20),
Employee: new CompanyPosition("Employee", 0, 0, 0, 0, 0, 0, 0, 20),
PoliceOfficer: new CompanyPosition("Police Officer", 11, 101, 101, 101, 101, 51, 8000, 75),
PoliceChief: new CompanyPosition("Police Chief", 101, 301, 301, 301, 301, 151, 36000, 425),
SecurityGuard: new CompanyPosition("Security Guard", 0, 51, 51, 51, 51, 1, 0, 45),
SecurityOfficer: new CompanyPosition("Security Officer", 26, 151, 151, 151, 151, 51, 8000, 175),
SecuritySupervisor: new CompanyPosition("Security Supervisor", 26, 251, 251, 251, 251, 101, 36000, 600),
HeadOfSecurity: new CompanyPosition("Head of Security", 51, 501, 501, 501, 501, 151, 144000, 1200),
FieldAgent: new CompanyPosition("Field Agent", 101, 101, 101, 101, 101, 101, 8000, 300),
SecretAgent: new CompanyPosition("Secret Agent", 201, 251, 251, 251, 251, 201, 32000, 900),
SpecialOperative: new CompanyPosition("Special Operative", 251, 501, 501, 501, 501, 251, 162000, 1800),
Waiter: new CompanyPosition("Waiter", 0, 0, 0, 0, 0, 0, 0, 22),
Employee: new CompanyPosition("Employee", 0, 0, 0, 0, 0, 0, 0, 22),
PoliceOfficer: new CompanyPosition("Police Officer", 11, 101, 101, 101, 101, 51, 8000, 82),
PoliceChief: new CompanyPosition("Police Chief", 101, 301, 301, 301, 301, 151, 36000, 460),
SecurityGuard: new CompanyPosition("Security Guard", 0, 51, 51, 51, 51, 1, 0, 50),
SecurityOfficer: new CompanyPosition("Security Officer", 26, 151, 151, 151, 151, 51, 8000, 195),
SecuritySupervisor: new CompanyPosition("Security Supervisor", 26, 251, 251, 251, 251, 101, 36000, 660),
HeadOfSecurity: new CompanyPosition("Head of Security", 51, 501, 501, 501, 501, 151, 144000, 1320),
FieldAgent: new CompanyPosition("Field Agent", 101, 101, 101, 101, 101, 101, 8000, 330),
SecretAgent: new CompanyPosition("Secret Agent", 201, 251, 251, 251, 251, 201, 32000, 990),
SpecialOperative: new CompanyPosition("Special Operative", 251, 501, 501, 501, 501, 251, 162000, 2000),
init: function() {
//Argument order: hack, str, def, dex, agi, cha

@ -1,5 +1,5 @@
let CONSTANTS = {
Version: "0.28.1",
Version: "0.29.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
@ -58,8 +58,9 @@ let CONSTANTS = {
ScriptScpRamCost: 0.5,
ScriptKillRamCost: 0.5, //Kill and killall
ScriptHasRootAccessRamCost: 0.05,
ScriptGetHostnameRamCost: 0.05,
ScriptGetHackingLevelRamCost: 0.05,
ScriptGetHostnameRamCost: 0.05, //getHostname() and getIp()
ScriptGetHackingLevelRamCost: 0.05, //getHackingLevel() and getIntelligence()
ScriptGetMultipliersRamCost: 4.0, //getHackingMultipliers() and getBitNodeMultipliers()
ScriptGetServerCost: 0.1,
ScriptFileExistsRamCost: 0.1,
ScriptIsRunningRamCost: 0.1,
@ -86,9 +87,9 @@ let CONSTANTS = {
//Server constants
ServerBaseGrowthRate: 1.03, //Unadjusted Growth rate
ServerMaxGrowthRate: 1.0035, //Maximum possible growth rate (max rate accounting for server security)
ServerMaxGrowthRate: 1.0035, //Maximum possible growth rate (max rate accounting for server security)
ServerFortifyAmount: 0.002, //Amount by which server's security increases when its hacked/grown
ServerWeakenAmount: 0.05, //Amount by which server's security decreases when weakened
ServerWeakenAmount: 0.05, //Amount by which server's security decreases when weakened
PurchasedServerLimit: 25,
@ -112,6 +113,18 @@ let CONSTANTS = {
//Hospital/Health
HospitalCostPerHp: 100000,
//Intelligence-related constants
IntelligenceCrimeWeight: 0.05, //Weight for how much int affects crime success rates
IntelligenceInfiltrationWeight: 0.1, //Weight for how much int affects infiltration success rates
IntelligenceCrimeBaseExpGain: 0.0002,
IntelligenceProgramBaseExpGain: 1000, //Program required hack level divided by this to determine int exp gain
IntelligenceTerminalHackBaseExpGain: 200, //Hacking exp divided by this to determine int exp gain
IntelligenceSingFnBaseExpGain: 0.0005,
//Hacking Missions
HackingMissionRepToDiffConversion: 5000, //Faction rep is divided by this to get mission difficulty
HackingMissionRepToRewardConversion: 20, //Faction rep divided byt his to get mission rep reward
//Gang constants
GangRespectToReputationRatio: 2, //Respect is divided by this to get rep gain
MaximumGangMembers: 20,
@ -231,8 +244,10 @@ let CONSTANTS = {
"encounter diminishing returns in your hacking (since you are only hacking a certain percentage). You can " +
"increase the amount of money on a server using a script and the grow() function in Netscript.<br><br>" +
"<h1>Server Security</h1><br>" +
"Each server has a security level, which is denoted by a number between 1 and 100. A higher number means " +
"the server has stronger security. As mentioned above, a server's security level is an important factor " +
"Each server has a security level, typically between 1 and 100. A higher number means the server has stronger security. " +
"It is possible for a server to have a security level of 100 or higher, in which case hacking that server " +
"will become impossible (0% chance to hack).<br><br>" +
"As mentioned above, a server's security level is an important factor " +
"to consider when hacking. You can check a server's security level using the 'analyze' command, although this " +
"only gives an estimate (with 5% uncertainty). You can also check a server's security in a script, using the " +
"<i>getServerSecurityLevel(server)</i> function in Netscript. See the Netscript documentation for more details. " +
@ -396,10 +411,13 @@ let CONSTANTS = {
"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><br>" +
"<i>tprint(x)</i><br>Prints a value or a variable to the Terminal<br><br>" +
"<i>tprint(x)</i><br>Prints a value or a variable to the Terminal<br><br>" +
"<i>clearLog()</i><br>Clears the script's logs. <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>scan(hostname/ip, [hostnames=true])</i><br>Returns an array containing the hostnames or IPs 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 second argument is a boolean that specifies whether " +
"the hostnames or IPs of the scanned servers should be output. If it is true then hostnames will be returned, and if false then IP addresses will. " +
"This second argument is optional and, if ommitted, the function will output " +
"the hostnames of the scanned servers. The hostnames/IPs 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>" +
"<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>" +
@ -449,14 +467,66 @@ let CONSTANTS = {
"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 " +
"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 " +
"to be copied. The second argument is a string with the hostname or IP of the destination server. Returns true if the script is successfully " +
"copied over and false otherwise. <br> Example: scp('hack-template.script', 'foodnstuff');<br><br>" +
"<i>scp(script, [source], destination)</i><br>Copies a script or literature (.lit) file to another server. The first argument is a string with " +
"the filename of the script or literature file " +
"to be copied. The next two arguments are strings containing the hostname/IPs of the source and target server. " +
"The source refers to the server from which the script/literature file will be copied, while the destination " +
"refers to the server to which it will be copied. The source server argument is optional, and if ommitted the source " +
"will be the current server (the server on which the script is running). Returns true if the script/literature file is " +
"successfully copied over and false otherwise. <br><br>" +
"Example: scp('hack-template.script', 'foodnstuff'); //Copies hack-template.script from the current server to foodnstuff<br>" +
"Example: scp('foo.lit', 'helios', 'home'); //Copies foo.lit from the helios server to the home computer<br><br>" +
"<i>ls(hostname/ip)</i><br>Returns an array containing the names of all files on the specified server. The argument must be a " +
"string with the hostname or IP of the target server.<br><br>" +
"<i>hasRootAccess(hostname/ip)</i><br> Returns a boolean (true or false) indicating whether or not the Player has root access to a server. " +
"The argument passed in must be a string with either the hostname or IP of the target server. Does NOT work while offline.<br> " +
"Example:<br>if (hasRootAccess('foodnstuff') == false) {<br>&nbsp;&nbsp;&nbsp;&nbsp;nuke('foodnstuff');<br>}<br><br>" +
"<i>getIp()</i><br>Returns a string with the IP Address of the server that the script is running on <br><br>" +
"<i>getHostname()</i><br>Returns a string with the hostname of the server that the script is running on<br><br>" +
"<i>getHackingLevel()</i><br> Returns the Player's current hacking level. Does NOT work while offline <br><br> " +
"<i>getHackingLevel()</i><br>Returns the Player's current hacking level. Does NOT work while offline<br><br> " +
"<i>getIntelligence()</i><br>Returns the Player's current intelligence level. Requires Source-File 5 to run<br><br>" +
"<i>getHackingMultipliers()</i><br>Returns an object containing the Player's hacking related multipliers. " +
"These multipliers are returned in integer forms, not percentages (e.g. 1.5 instead of 150%). " +
"The object has the following structure:<br><br>" +
"{<br>" +
"chance: Player's hacking chance multiplier<br>" +
"speed: Player's hacking speed multiplier<br>" +
"money: Player's hacking money stolen multiplier<br>" +
"growth: Player's hacking growth multiplier<br>" +
"}<br><br>Example:<br><br>" +
"mults = getHackingMultipliers();<br>" +
"print(mults.chance);<br>" +
"print(mults.growth);<br><br>" +
"<i>getBitNodeMultipliers()</i><br>Returns an object containing the current BitNode multipliers. " +
"This function requires Source-File 5 in order to run. The multipliers are returned in integer forms, not percentages " +
"(e.g. 1.5 instead of 150%). The multipliers represent the difference between the current BitNode and the " +
"original BitNode (BitNode-1). For example, if the 'CrimeMoney' multiplier has a value of 0.1 then that means " +
"that committing crimes in the current BitNode will only give 10% of the money you would have received in " +
"BitNode-1. The object has the following structure (subject to change in the future):<br><br>" +
"{<br>" +
"ServerMaxMoney: 1,<br>" +
"ServerStartingMoney: 1,<br>" +
"ServerGrowthRate: 1,<br>" +
"ServerWeakenRate: 1,<br>" +
"ServerStartingSecurity: 1,<br>" +
"ManualHackMoney: 1,<br>" +
"ScriptHackMoney: 1,<br>" +
"CompanyWorkMoney: 1,<br>" +
"CrimeMoney: 1,<br>" +
"HacknetNodeMoney: 1,<br>" +
"CompanyWorkExpGain: 1,<br>" +
"ClassGymExpGain: 1,<br>" +
"FactionWorkExpGain: 1,<br>" +
"HackExpGain: 1,<br>" +
"CrimeExpGain: 1,<br>" +
"FactionWorkRepGain: 1,<br>" +
"FactionPassiveRepGain: 1,<br>" +
"AugmentationRepCost: 1,<br>" +
"AugmentationMoneyCost: 1,<br>" +
"}<br><br>Example:<br><br>" +
"mults = getBitNodeMultipliers();<br>" +
"print(mults.ServerMaxMoney);<br>" +
"print(mults.HackExpGain);<br><br>" +
"<i>getServerMoneyAvailable(hostname/ip)</i><br> Returns the amount of money available on a server. The argument passed in must be a string with either the " +
"hostname or IP of the target server. Does NOT work while offline <br> Example: getServerMoneyAvailable('foodnstuff');<br><br>" +
"<i>getServerMaxMoney(hostname/ip)</i><br>Returns the maximum amount of money that can be available on a server. The argument passed in must be a string with " +
@ -479,6 +549,8 @@ let CONSTANTS = {
"<i>getServerRam(hostname/ip)</i><br>Returns an array with two elements that gives information about the target server's RAM. The first " +
"element in the array is the amount of RAM that the server has (in GB). The second element in the array is the amount of RAM that " +
"is currently being used on the server.<br><br>" +
"<i>serverExists(hostname/ip)</i><br>Returns a boolean denoting whether or not the specified server exists. The argument " +
"must be a string with the hostname or IP of the target server.<br><br>" +
"<i>fileExists(filename, [hostname/ip])</i><br> Returns a boolean (true or false) indicating whether the specified file exists on a server. " +
"The first argument must be a string with the name of the file. A file can either be a script or a program. A script name is case-sensitive, but a " +
"program is not. For example, fileExists('brutessh.exe') will work fine, even though the actual program is named BruteSSH.exe. <br><br> " +
@ -508,9 +580,10 @@ let CONSTANTS = {
"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>deleteServer(hostname)</i><br>Deletes one of the servers you've purchased with the specified hostname. The function will fail if " +
"there are any scripts running on the specified server. Returns true if successful and false otherwise<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>" +
"<i>write(port, data)</i><br>Writes data to a port. The first argument must be a number between 1 and 10 that specifies the port. The second " +
"argument defines the data to write to the port. If the second argument is not specified then it will write an empty string to the port.<br><br>" +
@ -534,21 +607,46 @@ let CONSTANTS = {
"on the server specified by the hostname/ip. The argument must be a string with the hostname/ip of the target server.<br><br>" +
"<i>getWeakenTime(hostname/ip)</i><br>Returns the amount of time in seconds it takes to execute the weaken() Netscript function " +
"on the server specified by the hostname/ip. The argument must be a string with the hostname/ip of the target server.<br><br>" +
"<i>getScriptIncome([scriptname], [hostname/ip], [args...])</i><br>" +
"Returns the amount of income the specified script generates while online (when the game is open, does not apply for " +
"offline income). This function can also return the total income of all of your active scripts by running the function " +
"with no arguments.<br><br>" +
"Remember that a script is uniquely identified by both its name and its arguments. So for example if you ran a script " +
"with the arguments 'foodnstuff' and '5' then in order to use this function to get that script's income you must " +
"specify those arguments in this function call.<br><br>" +
"The first argument, if specified, must be a string with the name of the script (including the .script extension). " +
"The second argument must be a string with the hostname/IP of the target server. If the first argument is specified " +
"then the second argument must be specified as well. Any additional arguments passed to the function will specify " +
"the arguments passed into the target script.<br><br>" +
"<i>getScriptExpGain([scriptname], [hostname/ip], [args...])</i><br>" +
"Returns the amount of hacking experience the specified script generates while online (when the game is open, does not apply for " +
"offline experience gains). This function can also return the total experience gain rate of all of your active scripts by running the function " +
"with no arguments.<br><br>" +
"Remember that a script is uniquely identified by both its name and its arguments. So for example if you ran a script " +
"with the arguments 'foodnstuff' and '5' then in order to use this function to get that script's income you must " +
"specify those arguments in this function call.<br><br>" +
"The first argument, if specified, must be a string with the name of the script (including the .script extension). " +
"The second argument must be a string with the hostname/IP of the target server. If the first argument is specified " +
"then the second argument must be specified as well. Any additional arguments passed to the function will specify " +
"the arguments passed into the target script.<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 " +
"indexes. These indexes correspond to the number at the end of the name of the Hacknet Node. For example, the first Hacknet Node you purchase " +
"will have the same 'hacknet-node-0' and can be accessed with hacknetnodes[0]. The fourth Hacknet Node you purchase will have the name " +
"'hacknet-node-3' and can be accessed with hacknetnodes[3]. <br><br>" +
"<i>hacknetnodes.length</i><br> Returns the number of Hacknet Nodes that the player owns<br><br>" +
"<i>hacknetnodes[i].level</i><br> Returns the level of the corresponding Hacknet Node<br><br>" +
"<i>hacknetnodes[i].ram</i><br> Returns the amount of RAM on the corresponding Hacknet Node<br><br>" +
"<i>hacknetnodes[i].cores</i><br> Returns the number of cores on the corresponding Hacknet Node<br><br>" +
"<i>hacknetnodes[i].upgradeLevel(n)</i><br> Tries to upgrade the level of the corresponding Hacknet Node n times. The argument n must be a " +
"<i>hacknetnodes.length</i><br>Returns the number of Hacknet Nodes that the player owns<br><br>" +
"<i>hacknetnodes[i].level</i><br>Returns the level of the corresponding Hacknet Node<br><br>" +
"<i>hacknetnodes[i].ram</i><br>Returns the amount of RAM on the corresponding Hacknet Node<br><br>" +
"<i>hacknetnodes[i].cores</i><br>Returns the number of cores on the corresponding Hacknet Node<br><br>" +
"<i>hacknetnodes[i].totalMoneyGenerated</i><br>Returns the total amount of money that the corresponding Hacknet Node has earned<br><br>" +
"<i>hacknetnodes[i].onlineTimeSeconds</i><br>Returns the total amount of time that the corresponding Hacknet Node has existed<br><br>" +
"<i>hacknetnodes[i].moneyGainRatePerSecond</i><br>Returns the income ($ / sec) that the corresponding Hacknet Node earns<br><br>" +
"<i>hacknetnodes[i].upgradeLevel(n)</i><br>Tries to upgrade the level of the corresponding Hacknet Node n times. The argument n must be a " +
"positive integer. Returns true if the Hacknet Node's level is successfully upgraded n times or up to the max level (200), and false otherwise.<br><br>" +
"<i>hacknetnodes[i].upgradeRam()</i><br> Tries to upgrade the amount of RAM on the corresponding Hacknet Node. Returns true if the " +
"<i>hacknetnodes[i].upgradeRam()</i><br>Tries to upgrade the amount of RAM on the corresponding Hacknet Node. Returns true if the " +
"RAM is successfully upgraded, and false otherwise. <br><br>" +
"<i>hacknetnodes[i].upgradeCore()</i><br> Attempts to purchase an additional core for the corresponding Hacknet Node. Returns true if the " +
"<i>hacknetnodes[i].upgradeCore()</i><br>Attempts to purchase an additional core for the corresponding Hacknet Node. Returns true if the " +
"additional core is successfully purchase, and false otherwise. <br><br>" +
"Example: The following is an example of one way a script can be used to automate the purchasing and upgrading of Hacknet Nodes. " +
"This script purchases new Hacknet Nodes until the player has four. Then, it iteratively upgrades each of those four Hacknet Nodes " +
@ -859,14 +957,20 @@ let CONSTANTS = {
"World Stock Exchange account and TIX API Access<br>",
LatestUpdate:
"v0.28.1<br>" +
"-The script editor now uses the open-source Ace editor, which provides a much better experience when coding!<br>" +
"-Added tprint() Netscript function<br><br>" +
"v0.28.0<br>" +
"-Added BitNode-4: The Singularity<br>" +
"-Added BitNode-11: The Big Crash<br>" +
"-Migrated the codebase to use webpack (doesn't affect any in game content, except maybe some slight " +
"performance improvements and there may be bugs that result from dependency errors)"
"v0.29.0<br>" +
"-Added BitNode-5: Artificial Intelligence<br>" +
"-Added getIp(), getIntelligence(), getHackingMultipliers(), and getBitNodeMultipliers() Netscript functions (requires Source-File 5)<br>" +
"-Updated scan() Netscript function so that you can choose to have it print IPs rather than hostnames<br>" +
"-Refactored scp() Netscript function so that it takes an optional 'source server' argument<br>" +
"-For Infiltration, decreased the percentage by which the security level increases by " +
"about 10% for every location<br>" +
"-Using :w in the script editor's Vim keybinding mode should now save and quit to Terminal<br>" +
"-Some minor optimizations that should reduce the size of the save file<br>" +
"-scan-analyze Terminal command will no longer show your purchased servers, unless you pass a '-a' flag into the command<br>" +
"-After installing the Red Pill augmentation from Daedalus, the message telling you to find 'The-Cave' " +
"will now repeatedly pop up regardless of whether or not you have messages suppressed<br>" +
"-Various bugfixes",
}
export {CONSTANTS};

@ -134,7 +134,12 @@ function getNumAvailableCreateProgram() {
if (!Player.hasProgram(Programs.AutoLink) && Player.hacking_skill >= 25) {
++count;
}
if (count > 0) {Player.firstProgramAvailable = true;}
if (Player.firstProgramAvailable === false && count > 0) {
Player.firstProgramAvailable = true;
document.getElementById("create-program-tab").style.display = "list-item";
document.getElementById("hacking-menu-header").click();
document.getElementById("hacking-menu-header").click();
}
return count;
}

@ -110,99 +110,113 @@ function determineCrimeSuccess(crime, moneyGained) {
}
}
let intWgt = CONSTANTS.IntelligenceCrimeWeight;
let maxLvl = CONSTANTS.MaxSkillLevel;
function determineCrimeChanceShoplift() {
var chance = ((Player.dexterity / CONSTANTS.MaxSkillLevel +
Player.agility / CONSTANTS.MaxSkillLevel)) * 20;
var chance = (Player.dexterity / maxLvl +
Player.agility / maxLvl +
intWgt * Player.intelligence / maxLvl) * 20;
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
function determineCrimeChanceRobStore() {
var chance = ((0.5 * Player.hacking_skill / CONSTANTS.MaxSkillLevel +
2 * Player.dexterity / CONSTANTS.MaxSkillLevel +
1 * Player.agility / CONSTANTS.MaxSkillLevel)) * 5;
var chance = (0.5 * Player.hacking_skill / maxLvl +
2 * Player.dexterity / maxLvl +
1 * Player.agility / maxLvl +
intWgt * Player.intelligence / maxLvl) * 5;
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
function determineCrimeChanceMug() {
var chance = ((1.5 * Player.strength / CONSTANTS.MaxSkillLevel +
0.5 * Player.defense / CONSTANTS.MaxSkillLevel +
1.5 * Player.dexterity / CONSTANTS.MaxSkillLevel +
0.5 * Player.agility / CONSTANTS.MaxSkillLevel)) * 5;
var chance = (1.5 * Player.strength / maxLvl +
0.5 * Player.defense / maxLvl +
1.5 * Player.dexterity / maxLvl +
0.5 * Player.agility / maxLvl +
intWgt * Player.intelligence / maxLvl) * 5;
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
function determineCrimeChanceLarceny() {
var chance = ((0.5 * Player.hacking_skill / CONSTANTS.MaxSkillLevel +
Player.dexterity / CONSTANTS.MaxSkillLevel +
Player.agility / CONSTANTS.MaxSkillLevel)) * 3;
var chance = (0.5 * Player.hacking_skill / maxLvl +
Player.dexterity / maxLvl +
Player.agility / maxLvl +
intWgt * Player.intelligence / maxLvl) * 3;
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
function determineCrimeChanceDealDrugs() {
var chance = ((3*Player.charisma / CONSTANTS.MaxSkillLevel +
2*Player.dexterity / CONSTANTS.MaxSkillLevel +
Player.agility / CONSTANTS.MaxSkillLevel));
var chance = (3*Player.charisma / maxLvl +
2*Player.dexterity / maxLvl +
Player.agility / maxLvl +
intWgt * Player.intelligence / maxLvl);
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
function determineCrimeChanceTraffickArms() {
var chance = ((Player.charisma / CONSTANTS.MaxSkillLevel +
Player.strength / CONSTANTS.MaxSkillLevel +
Player.defense / CONSTANTS.MaxSkillLevel +
Player.dexterity / CONSTANTS.MaxSkillLevel +
Player.agility / CONSTANTS.MaxSkillLevel)) / 2;
var chance = (Player.charisma / maxLvl +
Player.strength / maxLvl +
Player.defense / maxLvl +
Player.dexterity / maxLvl +
Player.agility / maxLvl +
intWgt * Player.intelligence / maxLvl) / 2;
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
function determineCrimeChanceHomicide() {
var chance = ((2 * Player.strength / CONSTANTS.MaxSkillLevel +
2 * Player.defense / CONSTANTS.MaxSkillLevel +
0.5 * Player.dexterity / CONSTANTS.MaxSkillLevel +
0.5 * Player.agility / CONSTANTS.MaxSkillLevel));
var chance = (2 * Player.strength / maxLvl +
2 * Player.defense / maxLvl +
0.5 * Player.dexterity / maxLvl +
0.5 * Player.agility / maxLvl +
intWgt * Player.intelligence / maxLvl);
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
function determineCrimeChanceGrandTheftAuto() {
var chance = ((Player.hacking_skill / CONSTANTS.MaxSkillLevel +
Player.strength / CONSTANTS.MaxSkillLevel +
4 * Player.dexterity / CONSTANTS.MaxSkillLevel +
2 * Player.agility / CONSTANTS.MaxSkillLevel +
2 * Player.charisma / CONSTANTS.MaxSkillLevel)) / 8;
var chance = (Player.hacking_skill / maxLvl +
Player.strength / maxLvl +
4 * Player.dexterity / maxLvl +
2 * Player.agility / maxLvl +
2 * Player.charisma / maxLvl +
intWgt * Player.intelligence / maxLvl) / 8;
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
function determineCrimeChanceKidnap() {
var chance = ((Player.charisma / CONSTANTS.MaxSkillLevel +
Player.strength / CONSTANTS.MaxSkillLevel +
Player.dexterity / CONSTANTS.MaxSkillLevel +
Player.agility / CONSTANTS.MaxSkillLevel)) / 5;
var chance = (Player.charisma / maxLvl +
Player.strength / maxLvl +
Player.dexterity / maxLvl +
Player.agility / maxLvl +
intWgt * Player.intelligence / maxLvl) / 5;
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
function determineCrimeChanceAssassination() {
var chance = ((Player.strength / CONSTANTS.MaxSkillLevel +
2 * Player.dexterity / CONSTANTS.MaxSkillLevel +
Player.agility / CONSTANTS.MaxSkillLevel)) / 8;
var chance = (Player.strength / maxLvl +
2 * Player.dexterity / maxLvl +
Player.agility / maxLvl +
intWgt * Player.intelligence / maxLvl) / 8;
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}
function determineCrimeChanceHeist() {
var chance = ((Player.hacking_skill / CONSTANTS.MaxSkillLevel +
Player.strength / CONSTANTS.MaxSkillLevel +
Player.defense / CONSTANTS.MaxSkillLevel +
Player.dexterity / CONSTANTS.MaxSkillLevel +
Player.agility / CONSTANTS.MaxSkillLevel +
Player.charisma / CONSTANTS.MaxSkillLevel)) / 18;
var chance = (Player.hacking_skill / maxLvl +
Player.strength / maxLvl +
Player.defense / maxLvl +
Player.dexterity / maxLvl +
Player.agility / maxLvl +
Player.charisma / maxLvl +
intWgt * Player.intelligence / maxLvl) / 18;
chance *= Player.crime_success_mult;
return Math.min(chance, 1);
}

@ -3,6 +3,7 @@ import {Player} from "./Player.js";
import {SpecialServerIps} from "./SpecialServerIps.js";
import {post} from "./Terminal.js";
import {isValidIPAddress} from "../utils/IPAddress.js";
import {formatNumber} from "../utils/StringHelperFunctions.js";

@ -766,7 +766,10 @@ function displayFactionContent(factionName) {
}
function displayFactionAugmentations(factionName) {
document.getElementById("faction-augmentations-page-desc").innerHTML = "Lists all augmentations that are available to purchase from " + factionName;
document.getElementById("faction-augmentations-page-desc").innerHTML =
"Lists all Augmentations that are available to purchase from " + factionName + "<br><br>" +
"Augmentations are powerful upgrades that will enhance your abilities.";
var faction = Factions[factionName];
var augmentationsList = document.getElementById("faction-augmentations-list");
@ -849,7 +852,7 @@ function purchaseAugmentationBoxCreate(aug, fac) {
yesNoBoxClose();
});
yesNoBoxCreate("<h2>aug.name</h2><br>" +
yesNoBoxCreate("<h2>" + aug.name + "</h2><br>" +
aug.info + "<br><br>" +
"<br>Would you like to purchase the " + aug.name + " Augmentation for $" +
formatNumber(aug.baseCost * fac.augmentationPriceMult, 2) + "?");
@ -908,7 +911,12 @@ function purchaseAugmentation(aug, fac, sing=false) {
var txt = "You must first install the Bionic Arms augmentation before installing this upgrade";
if (sing) {return txt;} else {dialogBoxCreate(txt);}
} else if (Player.money.gte(aug.baseCost * fac.augmentationPriceMult)) {
Player.firstAugPurchased = true;
if (Player.firstAugPurchased === false) {
Player.firstAugPurchased = true;
document.getElementById("augmentations-tab").style.display = "list-item";
document.getElementById("character-menu-header").click();
document.getElementById("character-menu-header").click();
}
var queuedAugmentation = new PlayerOwnedAugmentation(aug.name);
if (aug.name == AugmentationNames.NeuroFluxGovernor) {

@ -130,7 +130,7 @@ function processAllGangPowerGains(numCycles=1) {
if (name == playerGangName) {
AllGangs[name].power += Player.gang.calculatePower();
} else {
var gain = Math.random() * 0.01; //TODO Adjust as necessary
var gain = Math.random() * 0.02; //TODO Adjust as necessary
AllGangs[name].power += (gain);
}
}
@ -235,8 +235,12 @@ Gang.prototype.processGains = function(numCycles=1) {
console.log("ERROR: respectGains is NaN");
}
if (!isNaN(wantedLevelGains)) {
this.wanted += (wantedLevelGains * this.storedCycles);
if (this.wanted < 1) {this.wanted = 1;}
if (this.wanted === 1 && wantedLevelGains < 0) {
//Do nothing
} else {
this.wanted += (wantedLevelGains * this.storedCycles);
if (this.wanted < 1) {this.wanted = 1;}
}
} else {
console.log("ERROR: wantedLevelGains is NaN");
}

@ -92,7 +92,7 @@ HacknetNode.prototype.getLevelUpgradeCost = function(levels=1) {
HacknetNode.prototype.purchaseLevelUpgrade = function(levels=1) {
var cost = this.calculateLevelUpgradeCost(levels);
if (isNaN(cost)) {return false;}
if (isNaN(cost) || levels < 0) {return false;}
if (this.level + levels > CONSTANTS.HacknetNodeMaxLevel) {
var diff = Math.max(0, CONSTANTS.HacknetNodeMaxLevel - this.level);
return this.purchaseLevelUpgrade(diff);
@ -442,7 +442,7 @@ function updateHacknetNodeDomElement(nodeObj) {
upgradeRamButton.setAttribute("class", "a-link-button-inactive");
} else {
var upgradeRamCost = nodeObj.calculateRamUpgradeCost();
upgradeRamButton.innerHTML = "Upgrade Hacknet Node RAM -$" + formatNumber(upgradeRamCost, 2);
upgradeRamButton.innerHTML = "Upgrade Hacknet Node RAM - $" + formatNumber(upgradeRamCost, 2);
if (Player.money.lt(upgradeRamCost)) {
upgradeRamButton.setAttribute("class", "a-link-button-inactive");
} else {

@ -24,7 +24,7 @@ let TerminalHelpText =
"rm [file] Delete a file from the server<br>" +
"run [name] [-t] [n] [args...] Execute a program or script<br>" +
"scan Prints all immediately-available network connections<br>" +
"scan-analyze [d] Prints info for all servers up to <i>d</i> nodes away<br>" +
"scan-analyze [d] [-a] Prints info for all servers up to <i>d</i> nodes away<br>" +
"scp [file] [server] Copies a script or .lit file to a destination server<br>" +
"sudov Shows whether you have root access on this computer<br>" +
"tail [script] [args...] Displays dynamic logs for the specified script<br>" +
@ -153,7 +153,7 @@ let HelpTexts = {
scan: "scan<br>" +
"Prints all immediately-available network connection. This will print a list of all servers that you can currently connect " +
"to using the 'connect' Terminal command.",
"scan-analyze": "scan-analyze [depth]<br>" +
"scan-analyze": "scan-analyze [depth] [-a]<br>" +
"Prints detailed information about all servers up to [depth] nodes away on the network. Calling " +
"'scan-analyze 1' will display information for the same servers that are shown by the 'scan' Terminal " +
"command. This command also shows the relative paths to reach each server.<br><br>" +
@ -162,7 +162,9 @@ let HelpTexts = {
"5 and 10, respectively.<br><br>" +
"The information 'scan-analyze' displays about each server includes whether or not you have root access to it, " +
"its required hacking level, the number of open ports required to run NUKE.exe on it, and how much RAM " +
"it has",
"it has.<br><br>" +
"By default, this command will not display servers that you have purchased. However, you can pass in the " +
"-a flag at the end of the command if you would like to enable that.",
scp: "scp [filename] [target server]<br>" +
"Copies the specified file from the current server to the target server. " +
"This command only works for script files (.script extension) and literature files (.lit extension). " +

@ -441,7 +441,7 @@ function updateInfiltrationLevelText(inst) {
var totalValue = 0;
var totalMoneyValue = 0;
for (var i = 0; i < inst.secretsStolen.length; ++i) {
totalValue += inst.secretsStolen[i];
totalValue += (inst.secretsStolen[i] * Player.faction_rep_mult * 1.25);
totalMoneyValue += inst.secretsStolen[i] * CONSTANTS.InfiltrationMoneyValue;
}
document.getElementById("infiltration-level-text").innerHTML =
@ -577,6 +577,7 @@ function updateInfiltrationButtons(inst, scenario) {
}
}
let intWgt = CONSTANTS.IntelligenceInfiltrationWeight;
//Kill
//Success: 5%, Failure 10%, -Karma
@ -649,7 +650,8 @@ function getInfiltrationStealthKnockoutChance(inst) {
return Math.min(0.95,
(0.5 * Player.strength +
2 * Player.dexterity +
2 * Player.agility) / (3 * lvl));
2 * Player.agility +
intWgt * Player.intelligence) / (3 * lvl));
}
//Assassination
@ -671,7 +673,8 @@ function getInfiltrationAssassinateChance(inst) {
var lvl = inst.securityLevel;
return Math.min(0.95,
(Player.dexterity +
0.5 * Player.agility) / (2 * lvl));
0.5 * Player.agility +
intWgt * Player.intelligence) / (2 * lvl));
}
@ -720,7 +723,8 @@ function attemptInfiltrationHack(inst) {
function getInfiltrationHackChance(inst) {
var lvl = inst.securityLevel;
return Math.min(0.95,
(Player.hacking_skill) / lvl);
(Player.hacking_skill +
(intWgt * Player.intelligence)) / lvl);
}
//Sneak past security
@ -740,7 +744,8 @@ function getInfiltrationSneakChance(inst) {
var lvl = inst.securityLevel;
return Math.min(0.95,
(Player.agility +
0.5 * Player.dexterity) / (2 * lvl));
0.5 * Player.dexterity +
intWgt * Player.intelligence) / (2 * lvl));
}
//Pick locked door
@ -760,7 +765,8 @@ function attemptInfiltrationPickLockedDoor(inst) {
function getInfiltrationPickLockedDoorChance(inst) {
var lvl = inst.securityLevel;
return Math.min(0.95,
(Player.dexterity) / lvl);
(Player.dexterity +
intWgt * Player.intelligence) / lvl);
}
//Bribe
@ -800,7 +806,8 @@ function getInfiltrationEscapeChance(inst) {
var lvl = inst.securityLevel;
return Math.min(0.95,
(2 * Player.agility +
Player.dexterity) / lvl);
Player.dexterity +
intWgt * Player.intelligence) / lvl);
}
export {beginInfiltration};

@ -73,7 +73,7 @@ function iTutorialEvaluateStep() {
iTutorialSetText("Welcome to Bitburner, a cyberpunk-themed incremental RPG! " +
"The game takes place in a dark, dystopian future...The year is 2077...<br><br>" +
"This tutorial will show you the basics of the game to help you get started. " +
"This tutorial will show you the basics of the game. " +
"You may skip the tutorial at any time.");
var next = clearEventListeners("interactive-tutorial-next");
next.style.display = "inline-block";
@ -114,7 +114,7 @@ function iTutorialEvaluateStep() {
break;
case iTutorialSteps.CharacterGoToTerminalPage:
iTutorialSetText("Let's head to your computer's terminal by clicking the 'Terminal' tab on the " +
"main navigation menu");
"main navigation menu.");
//No next button
var next = clearEventListeners("interactive-tutorial-next");
next.style.display = "none";
@ -132,8 +132,7 @@ function iTutorialEvaluateStep() {
break;
case iTutorialSteps.TerminalIntro:
iTutorialSetText("The Terminal is used to interface with your home computer as well as " +
"all of the other machines around the world. A lot of content in the game is " +
"accessible only through the Terminal, and is necessary for progressing. ");
"all of the other machines around the world.");
var next = clearEventListeners("interactive-tutorial-next");
next.style.display = "inline-block";
next.addEventListener("click", function() {
@ -149,14 +148,14 @@ function iTutorialEvaluateStep() {
//next step triggered by terminal command
break;
case iTutorialSteps.TerminalLs:
iTutorialSetText("The 'help' command displays a list of all available commands, how to use them, " +
iTutorialSetText("The 'help' command displays a list of all available Terminal commands, how to use them, " +
"and a description of what they do. <br><br>Let's try another command. Enter the 'ls' command");
//next step triggered by terminal command
break;
case iTutorialSteps.TerminalScan:
iTutorialSetText("'ls' is a basic command that shows all of the contents (programs/scripts) " +
"on the computer. Right now, it shows that you have a program called 'NUKE.exe' on your computer. " +
"We'll get to what this does later. <br><br> Through your home computer's terminal, you can connect " +
"We'll get to what this does later. <br><br>Using your home computer's terminal, you can connect " +
"to other machines throughout the world. Let's do that now by first entering " +
"the 'scan' command. ");
//next step triggered by terminal command
@ -197,7 +196,7 @@ function iTutorialEvaluateStep() {
case iTutorialSteps.TerminalNuke:
iTutorialSetText("When the 'analyze' command finishes running it will show useful information " +
"about hacking the server. <br><br> For this server, the required hacking skill is only 1, " +
"which means you are able to hack it right now. However, in order to hack a server " +
"which means you can hack it right now. However, in order to hack a server " +
"you must first gain root access. The 'NUKE.exe' program that we saw earlier on your " +
"home computer is a virus that will grant you root access to a machine if there are enough " +
"open ports.<br><br> The 'analyze' results shows that there do not need to be any open ports " +
@ -207,19 +206,19 @@ function iTutorialEvaluateStep() {
break;
case iTutorialSteps.TerminalManualHack:
iTutorialSetText("You now have root access! You can hack the server using the 'hack' command. " +
"Try doing that now. ");
"Try doing that now.");
//next step triggered by terminal command
break;
case iTutorialSteps.TerminalHackingMechanics:
iTutorialSetText("You are now attempting to hack the server. Note that performing a hack takes time and " +
"only has a certain percentage chance " +
"of success. This time and success chance is determined by a variety of factors, including " +
"your hacking skill and the server's security level. <br><br>" +
"your hacking skill and the server's security level.<br><br>" +
"If your attempt to hack the server is successful, you will steal a certain percentage " +
"of the server's total money. This percentage is affected by your hacking skill and " +
"the server's security level. <br><br> The amount of money on a server is not limitless. So, if " +
"the server's security level.<br><br>The amount of money on a server is not limitless. So, if " +
"you constantly hack a server and deplete its money, then you will encounter " +
"diminishing returns in your hacking.<br>");
"diminishing returns in your hacking.");
var next = clearEventListeners("interactive-tutorial-next");
next.style.display = "inline-block";
next.addEventListener("click", function() {
@ -230,7 +229,7 @@ function iTutorialEvaluateStep() {
case iTutorialSteps.TerminalCreateScript:
iTutorialSetText("Hacking is the core mechanic of the game and is necessary for progressing. However, " +
"you don't want to be hacking manually the entire time. You can automate your hacking " +
"by writing scripts! <br><br>To create a new script or edit an existing one, you can use the 'nano' " +
"by writing scripts!<br><br>To create a new script or edit an existing one, you can use the 'nano' " +
"command. Scripts must end with the '.script' extension. Let's make a script now by " +
"entering 'nano foodnstuff.script' after the hack command finishes running (Sidenote: Pressing ctrl + c" +
" will end a command like hack early)");
@ -249,14 +248,14 @@ function iTutorialEvaluateStep() {
"&nbsp;&nbsp;hack('foodnstuff'); <br>" +
"}<br><br> " +
"For anyone with basic programming experience, this code should be straightforward. " +
"This script will continuously hack the 'foodnstuff' server. <br><br>" +
"This script will continuously hack the 'foodnstuff' server.<br><br>" +
"To save and close the script editor, press the button in the bottom left, or press ctrl + b.");
//next step triggered in saveAndCloseScriptEditor() (Script.js)
break;
case iTutorialSteps.TerminalFree:
iTutorialSetText("Now we'll run the script. Scripts require a certain amount of RAM to run, and can be " +
"run on any machine which you have root access to. Different servers have different " +
"amounts of RAM. You can also purchase more RAM for your home server. <br><br> To check how much " +
"amounts of RAM. You can also purchase more RAM for your home server.<br><br>To check how much " +
"RAM is available on this machine, enter the 'free' command.");
//next step triggered by terminal commmand
break;
@ -272,8 +271,8 @@ function iTutorialEvaluateStep() {
"runs an infinite loop). <br><br>These scripts can passively earn you income and hacking experience. " +
"Your scripts will also earn money and experience while you are offline, although at a " +
"much slower rate. <br><br> " +
"Let's check out some statistics of our active, running scripts by clicking the " +
"'Active Scripts' link in the main navigation menu. ");
"Let's check out some statistics for our running scripts by clicking the " +
"'Active Scripts' link in the main navigation menu.");
document.getElementById("active-scripts-menu-link").setAttribute("class", "flashing-button");
var activeScriptsMainMenuButton = document.getElementById("active-scripts-menu-link");
activeScriptsMainMenuButton.addEventListener("click", function() {
@ -342,7 +341,7 @@ function iTutorialEvaluateStep() {
iTutorialSetText("You just purchased a Hacknet Node! This Hacknet Node will passively " +
"earn you money over time, both online and offline. When you get enough " +
" money, you can upgrade " +
"your newly-purchased Hacknet Node below. <br><br>" +
"your newly-purchased Hacknet Node below.<br><br>" +
"Let's go to the 'City' page through the main navigation menu.");
document.getElementById("city-menu-link").setAttribute("class", "flashing-button");
var worldButton = clearEventListeners("city-menu-link");

@ -120,7 +120,7 @@ function displayLocationContent() {
console.log("displayLocationContent() called with location " + Player.location)
}
var returnToWorld = document.getElementById("location-return-to-world-button");
var returnToWorld = document.getElementById("location-return-to-world-button");
var locationName = document.getElementById("location-name");
@ -304,7 +304,7 @@ function displayLocationContent() {
//Check if the player is employed at this Location. If he is, display the "Work" button,
//update the job title, etc.
if (loc == Player.companyName) {
if (loc != "" && loc === Player.companyName) {
var company = Companies[loc];
jobTitle.style.display = "block";
@ -420,7 +420,7 @@ function displayLocationContent() {
purchaseTor.style.display = "block";
purchaseHomeRam.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumECorp,
6000, 116, 150, 9.5);
6000, 116, 150, 8.5);
break;
case Locations.AevumBachmanAndAssociates:
@ -433,7 +433,7 @@ function displayLocationContent() {
businessJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumBachmanAndAssociates,
1500, 42, 60, 6.5);
1500, 42, 60, 5.75);
break;
case Locations.AevumClarkeIncorporated:
@ -446,7 +446,7 @@ function displayLocationContent() {
businessJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumClarkeIncorporated,
2400, 34, 75, 6);
2400, 34, 75, 5.4);
break;
case Locations.AevumFulcrumTechnologies:
@ -465,7 +465,7 @@ function displayLocationContent() {
purchaseTor.style.display = "block";
purchaseHomeRam.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumFulcrumTechnologies,
6000, 96, 100, 10);
6000, 96, 100, 9);
break;
case Locations.AevumAeroCorp:
@ -477,7 +477,7 @@ function displayLocationContent() {
networkEngineerJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumAeroCorp,
2000, 32, 50, 7);
2000, 32, 50, 6.3);
break;
case Locations.AevumGalacticCybersystems:
@ -490,7 +490,7 @@ function displayLocationContent() {
networkEngineerJob.style.display = "block";
businessJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumGalacticCybersystems,
1400, 30, 50, 6);
1400, 30, 50, 5.3);
break;
case Locations.AevumWatchdogSecurity:
@ -504,7 +504,7 @@ function displayLocationContent() {
securityJob.style.display = "block";
agentJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumWatchdogSecurity,
850, 16, 30, 5);
850, 16, 30, 4.5);
break;
case Locations.AevumRhoConstruction:
@ -513,7 +513,7 @@ function displayLocationContent() {
softwareJob.style.display = "block";
businessJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumRhoConstruction,
600, 12, 20, 3);
600, 12, 20, 2.7);
break;
case Locations.AevumPolice:
@ -522,7 +522,7 @@ function displayLocationContent() {
softwareJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumPolice,
700, 14, 25, 3.5);
700, 14, 25, 3.2);
break;
case Locations.AevumNetLinkTechnologies:
@ -540,7 +540,7 @@ function displayLocationContent() {
purchaseTor.style.display = "block";
purchaseHomeRam.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumNetLinkTechnologies,
160, 10, 15, 2);
160, 10, 15, 1.8);
break;
case Locations.AevumCrushFitnessGym:
@ -574,7 +574,7 @@ function displayLocationContent() {
businessJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.ChongqingKuaiGongInternational,
5500, 48, 100, 10);
5500, 48, 100, 9);
break;
case Locations.ChongqingSolarisSpaceSystems:
@ -586,7 +586,7 @@ function displayLocationContent() {
networkEngineerJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.ChongqingSolarisSpaceSystems,
3600, 26, 75, 9.5);
3600, 26, 75, 8.6);
break;
@ -615,7 +615,7 @@ function displayLocationContent() {
businessJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12MegaCorp,
6000, 114, 125, 11);
6000, 114, 125, 9.8);
break;
case Locations.Sector12BladeIndustries:
@ -628,7 +628,7 @@ function displayLocationContent() {
businessJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12BladeIndustries,
3000, 46, 100, 7.5);
3000, 46, 100, 6.7);
break;
case Locations.Sector12FourSigma:
@ -641,7 +641,7 @@ function displayLocationContent() {
businessJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12FourSigma,
1500, 58, 100, 11.5);
1500, 58, 100, 10.2);
break;
case Locations.Sector12IcarusMicrosystems:
@ -654,7 +654,7 @@ function displayLocationContent() {
networkEngineerJob.style.display = "block";
businessJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12IcarusMicrosystems,
900, 32, 70, 8.5);
900, 32, 70, 7.8);
break;
case Locations.Sector12UniversalEnergy:
@ -667,7 +667,7 @@ function displayLocationContent() {
networkEngineerJob.style.display = "block";
businessJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12UniversalEnergy,
775, 24, 50, 7);
775, 24, 50, 6.3);
break;
case Locations.Sector12DeltaOne:
@ -679,7 +679,7 @@ function displayLocationContent() {
networkEngineerJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12DeltaOne,
1200, 38, 75, 7);
1200, 38, 75, 6.3);
break;
case Locations.Sector12CIA:
@ -692,7 +692,7 @@ function displayLocationContent() {
securityJob.style.display = "block";
agentJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12CIA,
1450, 44, 80, 8.5);
1450, 44, 80, 7.6);
break;
case Locations.Sector12NSA:
@ -705,7 +705,7 @@ function displayLocationContent() {
securityJob.style.display = "block";
agentJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12NSA,
1400, 40, 80, 8);
1400, 40, 80, 7.2);
break;
case Locations.Sector12AlphaEnterprises:
@ -719,7 +719,7 @@ function displayLocationContent() {
purchaseTor.style.display = "block";
purchaseHomeRam.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12AlphaEnterprises,
250, 14, 40, 3);
250, 14, 40, 2.7);
break;
case Locations.Sector12CarmichaelSecurity:
@ -733,7 +733,7 @@ function displayLocationContent() {
securityJob.style.display = "block";
agentJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12CarmichaelSecurity,
500, 18, 60, 3);
500, 18, 60, 2.7);
break;
case Locations.Sector12FoodNStuff:
@ -749,7 +749,7 @@ function displayLocationContent() {
employeeJob.style.display = "block";
employeePartTimeJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12JoesGuns,
120, 8, 20, 2.5);
120, 8, 20, 2.2);
break;
case Locations.Sector12IronGym:
@ -782,7 +782,7 @@ function displayLocationContent() {
securityEngineerJob.style.display = "block";
networkEngineerJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.NewTokyoDefComm,
1300, 28, 70, 6);
1300, 28, 70, 5.4);
break;
case Locations.NewTokyoVitaLife:
@ -795,7 +795,7 @@ function displayLocationContent() {
networkEngineerJob.style.display = "block";
businessJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.NewTokyoVitaLife,
750, 22, 100, 5.5);
750, 22, 100, 5);
break;
case Locations.NewTokyoGlobalPharmaceuticals:
@ -809,7 +809,7 @@ function displayLocationContent() {
businessJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.NewTokyoGlobalPharmaceuticals,
900, 24, 80, 6);
900, 24, 80, 5.4);
break;
case Locations.NewTokyoNoodleBar:
@ -848,7 +848,7 @@ function displayLocationContent() {
purchase256gb.style.display = "block";
purchaseHomeRam.style.display = "block";
setInfiltrateButton(infiltrate, Locations.IshimaStormTechnologies,
700, 24, 100, 6.5);
700, 24, 100, 5.9);
break;
case Locations.IshimaNovaMedical:
@ -861,7 +861,7 @@ function displayLocationContent() {
networkEngineerJob.style.display = "block";
businessJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.IshimaNovaMedical,
600, 20, 50, 5);
600, 20, 50, 4.5);
break;
case Locations.IshimaOmegaSoftware:
@ -879,7 +879,7 @@ function displayLocationContent() {
purchaseTor.style.display = "block";
purchaseHomeRam.style.display = "block";
setInfiltrateButton(infiltrate, Locations.IshimaOmegaSoftware,
200, 10, 40, 2.5);
200, 10, 40, 2.3);
break;
case Locations.VolhavenTravelAgency:
@ -912,7 +912,7 @@ function displayLocationContent() {
purchase512gb.style.display = "block";
purchase1tb.style.display = "block";
setInfiltrateButton(infiltrate, Locations.VolhavenOmniTekIncorporated,
1500, 44, 100, 7);
1500, 44, 100, 6.3);
break;
case Locations.VolhavenNWO:
@ -925,7 +925,7 @@ function displayLocationContent() {
businessJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.VolhavenNWO,
1800, 56, 200, 8);
1800, 56, 200, 7.2);
break;
case Locations.VolhavenHeliosLabs:
@ -937,7 +937,7 @@ function displayLocationContent() {
securityEngineerJob.style.display = "block";
networkEngineerJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.VolhavenHeliosLabs,
1200, 28, 75, 6);
1200, 28, 75, 5.4);
break;
case Locations.VolhavenOmniaCybersystems:
@ -949,7 +949,7 @@ function displayLocationContent() {
networkEngineerJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.VolhavenOmniaCybersystems,
900, 28, 90, 6.5);
900, 28, 90, 5.8);
break;
case Locations.VolhavenLexoCorp:
@ -963,7 +963,7 @@ function displayLocationContent() {
businessJob.style.display = "block";
securityJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.VolhavenLexoCorp,
500, 14, 40, 3.5);
500, 14, 40, 3.1);
break;
case Locations.VolhavenSysCoreSecurities:
@ -974,7 +974,7 @@ function displayLocationContent() {
securityEngineerJob.style.display = "block";
networkEngineerJob.style.display = "block";
setInfiltrateButton(infiltrate, Locations.VolhavenSysCoreSecurities,
600, 16, 50, 4);
600, 16, 50, 3.6);
break;
case Locations.VolhavenCompuTek:
@ -995,7 +995,7 @@ function displayLocationContent() {
purchaseTor.style.display = "block";
purchaseHomeRam.style.display = "block";
setInfiltrateButton(infiltrate, Locations.VolhavenCompuTek,
300, 12, 35, 3.5);
300, 12, 35, 3.1);
break;
case Locations.VolhavenMilleniumFitnessGym:
@ -1840,7 +1840,13 @@ function initLocationButtons() {
}
function travelToCity(destCityName, cost) {
Player.firstTimeTraveled = true;
if (Player.firstTimeTraveled === false) {
Player.firstTimeTraveled = true;
document.getElementById("travel-tab").style.display = "list-item";
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
}
if (Player.money.lt(cost)) {
dialogBoxCreate("You cannot afford to travel to " + destCityName);
return;

@ -4,7 +4,7 @@ import {Programs} from "./CreateProgram.js";
import {Player} from "./Player.js";
import {GetServerByHostname} from "./Server.js";
import {Settings} from "./Settings.js";
import {dialogBoxCreate} from "../utils/DialogBox.js";
import {dialogBoxCreate, dialogBoxOpened} from "../utils/DialogBox.js";
import {Reviver, Generic_toJSON,
Generic_fromJSON} from "../utils/JSONReviver.js";
@ -27,10 +27,10 @@ Message.fromJSON = function(value) {
Reviver.constructors.Message = Message;
//Sends message to player, including a pop up
function sendMessage(msg) {
function sendMessage(msg, forced=false) {
console.log("sending message: " + msg.filename);
msg.recvd = true;
if (!Settings.SuppressMessages) {
if (forced || !Settings.SuppressMessages) {
showMessage(msg);
}
addMessageToServer(msg, "home");
@ -50,6 +50,11 @@ function addMessageToServer(msg, serverHostname) {
console.log("WARNING: Did not locate " + serverHostname);
return;
}
for (var i = 0; i < server.messages.length; ++i) {
if (server.messages[i].filename === msg.filename) {
return; //Already exists
}
}
server.messages.push(msg);
}
@ -60,7 +65,6 @@ function checkForMessagesToSend() {
var jumper2 = Messages[MessageFilenames.Jumper2];
var jumper3 = Messages[MessageFilenames.Jumper3];
var jumper4 = Messages[MessageFilenames.Jumper4];
var jumper5 = Messages[MessageFilenames.Jumper5];
var cybersecTest = Messages[MessageFilenames.CyberSecTest];
var nitesecTest = Messages[MessageFilenames.NiteSecTest];
var bitrunnersTest = Messages[MessageFilenames.BitRunnersTest];
@ -71,8 +75,13 @@ function checkForMessagesToSend() {
redpillOwned = true;
}
if (jumper0 && !jumper0.recvd && Player.hacking_skill >= 25) {
if (redpill && redpillOwned) {
if (!dialogBoxOpened) {
sendMessage(redpill, true);
}
} else if (jumper0 && !jumper0.recvd && Player.hacking_skill >= 25) {
sendMessage(jumper0);
Player.getHomeComputer().programs.push(Programs.Flight);
} else if (jumper1 && !jumper1.recvd && Player.hacking_skill >= 40) {
sendMessage(jumper1);
} else if (cybersecTest && !cybersecTest.recvd && Player.hacking_skill >= 50) {
@ -87,11 +96,6 @@ function checkForMessagesToSend() {
sendMessage(jumper4);
} else if (bitrunnersTest && !bitrunnersTest.recvd && Player.hacking_skill >= 500) {
sendMessage(bitrunnersTest);
} else if (jumper5 && !jumper5.recvd && Player.hacking_skill >= 1000) {
sendMessage(jumper5);
Player.getHomeComputer().programs.push(Programs.Flight);
} else if (redpill && !redpill.recvd && Player.hacking_skill >= 2000 && redpillOwned) {
sendMessage(redpill);
}
}
@ -111,7 +115,6 @@ let MessageFilenames = {
Jumper2: "j2.msg",
Jumper3: "j3.msg",
Jumper4: "j4.msg",
Jumper5: "j5.msg",
CyberSecTest: "csec-test.msg",
NiteSecTest: "nitesec-test.msg",
BitRunnersTest: "19dfj3l1nd.msg",
@ -127,7 +130,10 @@ function initMessages() {
"I know you can sense it. I know you're searching for it. " +
"It's why you spend night after " +
"night at your computer. <br><br>It's real, I've seen it. And I can " +
"help you find it. But not right now. You're not ready yet.<br><br>-jump3R"));
"help you find it. But not right now. You're not ready yet.<br><br>" +
"Use this program to track your progress<br><br>" +
"The fl1ght.exe program was added to your home computer<br><br>" +
"-jump3R"));
AddToAllMessages(new Message(MessageFilenames.Jumper1,
"Soon you will be contacted by a hacking group known as CyberSec. " +
"They can help you with your search. <br><br>" +
@ -148,9 +154,6 @@ function initMessages() {
"To find what you are searching for, you must understand the bits. " +
"The bits are all around us. The runners will help you.<br><br>" +
"-jump3R"));
AddToAllMessages(new Message(MessageFilenames.Jumper5,
"Build your wings and fly<br><br>-jump3R<br><br> " +
"The fl1ght.exe program was added to your home computer"));
//Messages from hacking factions
AddToAllMessages(new Message(MessageFilenames.CyberSecTest,

@ -50,6 +50,30 @@ Environment.prototype = {
return (scope || this).vars[name] = value;
},
setArrayElement: function(name, idx, value) {
if (!(idx instanceof Array)) {
throw new Error("idx parameter is not an Array");
}
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);
}
var res = arr;
for (var iterator = 0; iterator < idx.length-1; ++iterator) {
var i = idx[iterator];
if (!(res instanceof Array) || i >= res.length) {
throw new Error("Out-of-bounds array access");
}
res = res[i];
}
return res[idx[idx.length-1]] = value;
},
/*
setArrayElement: function(name, idx, value) {
var scope = this.lookup(name);
if (!scope && this.parent) {
@ -61,7 +85,7 @@ Environment.prototype = {
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) {

@ -13,11 +13,10 @@ import {isValidIPAddress} from "../utils/IPAddress.js";
import {isString} from "../utils/StringHelperFunctions.js";
/* Evaluator
* Evaluates the Abstract Syntax Tree for Netscript
* generated by the Parser class
* Evaluates/Interprets the Abstract Syntax Tree generated by Acorns parser
*
* Returns a promise
*/
// Evaluator should return a Promise, so that any call to evaluate() can just
//wait for that promise to finish before continuing
function evaluate(exp, workerScript) {
return new Promise(function(resolve, reject) {
var env = workerScript.env;
@ -179,7 +178,7 @@ function evaluate(exp, workerScript) {
env.set(exp.argument.name,env.get(exp.argument.name)-1);
break;
default:
reject(makeRuntimeRejectMsg(workerScript, "Unrecognized token: " + exp.type + ". This is a bug please report to game developer"));
reject(makeRuntimeRejectMsg(workerScript, "Unrecognized token: " + exp.type + ". You are trying to use code that is currently unsupported"));
}
if (env.prefix){
return;
@ -196,11 +195,11 @@ function evaluate(exp, workerScript) {
resolve(false);
break;
case "ReturnStatement":
reject(makeRuntimeRejectMsg(workerScript, "Not implemented ReturnStatement"));
var lineNum = getErrorLineNumber(exp, workerScript);
reject(makeRuntimeRejectMsg(workerScript, "Return statements are not yet implemented in Netscript (line " + (lineNum+1) + ")"));
break;
case "BreakStatement":
reject("BREAKSTATEMENT");
//reject(makeRuntimeRejectMsg(workerScript, "Not implemented BreakStatement"));
break;
case "IfStatement":
evaluateIf(exp, workerScript).then(function(forLoopRes) {
@ -210,7 +209,8 @@ function evaluate(exp, workerScript) {
});
break;
case "SwitchStatement":
reject(makeRuntimeRejectMsg(workerScript, "Not implemented SwitchStatement"));
var lineNum = getErrorLineNumber(exp, workerScript);
reject(makeRuntimeRejectMsg(workerScript, "Switch statements are not yet implemented in Netscript (line " + (lineNum+1) + ")"));
break;e
case "WhileStatement":
evaluateWhile(exp, workerScript).then(function(forLoopRes) {
@ -239,7 +239,8 @@ function evaluate(exp, workerScript) {
});
break;
default:
reject(makeRuntimeRejectMsg(workerScript, "Unrecognized token: " + exp.type + ". This is a bug please report to game developer"));
var lineNum = getErrorLineNumber(exp, workerScript);
reject(makeRuntimeRejectMsg(workerScript, "Unrecognized token: " + exp.type + " (line " + (lineNum+1) + "). This is currently unsupported in Netscript"));
break;
} //End switch
}, Settings.CodeInstructionRunTime); //End setTimeout, the Netscript operation run time
@ -251,6 +252,12 @@ function evalBinary(exp, workerScript){
return new Promise(function(resolve, reject) {
var expLeftPromise = evaluate(exp.left, workerScript);
expLeftPromise.then(function(expLeft) {
if (expLeft == true && exp.operator === "||") {
return resolve(true);
}
if (expLeft == false && exp.operator === "&&") {
return resolve(false);
}
var expRightPromise = evaluate(exp.right, workerScript);
expRightPromise.then(function(expRight) {
switch (exp.operator){
@ -306,7 +313,7 @@ function evalBinary(exp, workerScript){
resolve(expLeft && expRight);
break;
default:
reject(makeRuntimeRejectMsg(workerScript, "Bitwise operators are not implemented"));
reject(makeRuntimeRejectMsg(workerScript, "Unsupported operator: " + exp.operator));
}
}, function(e) {
reject(e);
@ -340,6 +347,40 @@ function evalUnary(exp, workerScript){
});
}
//Takes in a MemberExpression that should represent a Netscript array (possible multidimensional)
//The return value is an array of the form:
// [0th index (leftmost), array name, 1st index, 2nd index, ...]
function getArrayElement(exp, workerScript) {
return new Promise(function(resolve, reject) {
var indices = [];
var iPromise = evaluate(exp.property, workerScript);
iPromise.then(function(idx) {
if (isNaN(idx)) {
return reject(makeRuntimeRejectMsg(workerScript, "Invalid access to array. Index is not a number: " + idx));
} else {
if (exp.object.name === undefined && exp.object.object) {
var recursePromise = getArrayElement(exp.object, workerScript);
recursePromise.then(function(res) {
res.push(idx);
indices = res;
return resolve(indices);
}).catch(function(e) {
return reject(e);
});
} else {
indices.push(idx);
indices.push(exp.object.name);
return resolve(indices);
}
}
}).catch(function(e) {
console.log(e);
console.log("Error getting index in getArrayElement: " + e.toString());
return reject(e);
});
});
}
function evalAssignment(exp, workerScript) {
var env = workerScript.env;
return new Promise(function(resolve, reject) {
@ -359,6 +400,22 @@ function evalAssignment(exp, workerScript) {
//Assign to array element
//Array object designed by exp.left.object.name
//Index designated by exp.left.property
var getArrayElementPromise = getArrayElement(exp.left, workerScript);
getArrayElementPromise.then(function(res) {
if (!(res instanceof Array) || res.length < 2) {
return reject(makeRuntimeRejectMsg(workerScript, "Error evaluating array assignment. This is (probably) a bug please report to game dev"));
}
//The array name is the second value
var arrName = res.splice(1, 1);
arrName = arrName[0];
env.setArrayElement(arrName, res, expRight);
return resolve(false);
}).catch(function(e) {
return reject(e);
});
/*
var name = exp.left.object.name;
if (!(name in env.vars)){
reject(makeRuntimeRejectMsg(workerScript, "variable " + name + " not defined"));
@ -379,7 +436,7 @@ function evalAssignment(exp, workerScript) {
});
} else {
return reject(makeRuntimeRejectMsg(workerScript, "Trying to access a non-array variable using the [] operator"));
}
}*/
} else {
//Other assignments
try {
@ -405,19 +462,18 @@ function evalAssignment(exp, workerScript) {
default:
reject(makeRuntimeRejectMsg(workerScript, "Bitwise assignment is not implemented"));
}
resolve(false);
} catch (e) {
return reject(makeRuntimeRejectMsg(workerScript, "Failed to set environment variable: " + e.toString()));
}
}
resolve(false); //Return false so this doesnt cause conditionals to evaluate
//resolve(false); //Return false so this doesnt cause conditionals to evaluate
}, function(e) {
reject(e);
});
});
}
//Returns true if any of the if statements evaluated, false otherwise. Therefore, the else statement
//should evaluate if this returns false
function evaluateIf(exp, workerScript, i) {
var env = workerScript.env;
return new Promise(function(resolve, reject) {
@ -566,9 +622,13 @@ function evaluateProg(exp, workerScript, index) {
});
}
function netscriptDelay(time) {
function netscriptDelay(time, workerScript) {
return new Promise(function(resolve) {
setTimeout(resolve, time);
var delay = setTimeout(resolve, time);
workerScript.killTrigger = function() {
clearTimeout(delay);
resolve();
};
});
}
@ -576,6 +636,7 @@ function makeRuntimeRejectMsg(workerScript, msg) {
return "|"+workerScript.serverIp+"|"+workerScript.name+"|" + msg;
}
/*
function apply_op(op, a, b) {
function num(x) {
if (typeof x != "number")
@ -604,6 +665,7 @@ function apply_op(op, a, b) {
}
throw new Error("Can't apply operator " + op);
}
*/
//Run a script from inside a script using run() command
function runScriptFromScript(server, scriptname, args, workerScript, threads=1) {
@ -620,6 +682,7 @@ function runScriptFromScript(server, scriptname, args, workerScript, threads=1)
//Check for admin rights and that there is enough RAM availble to run
var script = server.scripts[i];
var ramUsage = script.ramUsage;
threads = Math.round(Number(threads)); //Convert to number and round
ramUsage = ramUsage * threads * Math.pow(CONSTANTS.MultithreadingRAMCost, threads-1);
var ramAvailable = server.maxRam - server.ramUsed;
@ -644,6 +707,15 @@ function runScriptFromScript(server, scriptname, args, workerScript, threads=1)
return Promise.resolve(false);
}
//Takes in a
function getErrorLineNumber(exp, workerScript) {
var code = workerScript.scriptRef.scriptRef.code;
//Split code up to the start of the node
code = code.substring(0, exp.start);
return (code.match(/\n/g) || []).length;
}
function isScriptErrorMessage(msg) {
if (!isString(msg)) {return false;}
let splitMsg = msg.split("|");
@ -660,7 +732,7 @@ function isScriptErrorMessage(msg) {
//The same as Player's calculateHackingChance() function but takes in the server as an argument
function scriptCalculateHackingChance(server) {
var difficultyMult = (100 - server.hackDifficulty) / 100;
var skillMult = (1.75 * Player.hacking_skill);
var skillMult = (1.75 * Player.hacking_skill) + (0.2 * Player.intelligence);
var skillChance = (skillMult - server.requiredHackingSkill) / skillMult;
var chance = skillChance * difficultyMult * Player.hacking_chance_mult;
if (chance > 1) {return 1;}
@ -671,7 +743,7 @@ function scriptCalculateHackingChance(server) {
//The same as Player's calculateHackingTime() function but takes in the server as an argument
function scriptCalculateHackingTime(server) {
var difficultyMult = server.requiredHackingSkill * server.hackDifficulty;
var skillFactor = (2.5 * difficultyMult + 500) / (Player.hacking_skill + 50);
var skillFactor = (2.5 * difficultyMult + 500) / (Player.hacking_skill + 50 + (0.1 * Player.intelligence));
var hackingTime = 5 * skillFactor / Player.hacking_speed_mult; //This is in seconds
return hackingTime;
}
@ -697,7 +769,7 @@ function scriptCalculatePercentMoneyHacked(server) {
//Amount of time to execute grow() in milliseconds
function scriptCalculateGrowTime(server) {
var difficultyMult = server.requiredHackingSkill * server.hackDifficulty;
var skillFactor = (2.5 * difficultyMult + 500) / (Player.hacking_skill + 50);
var skillFactor = (2.5 * difficultyMult + 500) / (Player.hacking_skill + 50 + (0.1 * Player.intelligence));
var growTime = 16 * skillFactor / Player.hacking_speed_mult; //This is in seconds
return growTime * 1000;
}
@ -705,7 +777,7 @@ function scriptCalculateGrowTime(server) {
//Amount of time to execute weaken() in milliseconds
function scriptCalculateWeakenTime(server) {
var difficultyMult = server.requiredHackingSkill * server.hackDifficulty;
var skillFactor = (2.5 * difficultyMult + 500) / (Player.hacking_skill + 50);
var skillFactor = (2.5 * difficultyMult + 500) / (Player.hacking_skill + 50 + (0.1 * Player.intelligence));
var weakenTime = 20 * skillFactor / Player.hacking_speed_mult; //This is in seconds
return weakenTime * 1000;
}

@ -1,5 +1,8 @@
import {updateActiveScriptsItems} from "./ActiveScriptsUI.js";
import {Augmentations, Augmentation,
augmentationExists, installAugmentations} from "./Augmentations.js";
augmentationExists, installAugmentations,
AugmentationNames} from "./Augmentations.js";
import {BitNodeMultipliers} from "./BitNode.js";
import {Companies, Company, CompanyPosition,
CompanyPositions, companyExists} from "./Company.js";
import {CONSTANTS} from "./Constants.js";
@ -11,6 +14,7 @@ import {Factions, Faction, joinFaction,
import {getCostOfNextHacknetNode,
purchaseHacknet} from "./HacknetNode.js";
import {Locations} from "./Location.js";
import {Message, Messages} from "./Message.js";
import {Player} from "./Player.js";
import {Script, findRunningScript, RunningScript} from "./Script.js";
import {Server, getServer, AddToAllServers,
@ -34,33 +38,46 @@ import {makeRuntimeRejectMsg, netscriptDelay, runScriptFromScript,
import {Environment} from "./NetscriptEnvironment.js";
import Decimal from '../utils/decimal.js';
import {dialogBoxCreate} from "../utils/DialogBox.js";
import {printArray, powerOfTwo} from "../utils/HelperFunctions.js";
import {createRandomIp} from "../utils/IPAddress.js";
import {formatNumber, isString} from "../utils/StringHelperFunctions.js";
import {formatNumber, isString, isHTML} from "../utils/StringHelperFunctions.js";
var hasSingularitySF = false;
var hasAISF = false;
var singularitySFLvl = 1;
//Also used to check for Artificial Intelligence Source File, don't want to change
//name though
function initSingularitySFFlags() {
for (var i = 0; i < Player.sourceFiles.length; ++i) {
if (Player.sourceFiles[i].n === 4) {
hasSingularitySF = true;
singularitySFLvl = Player.sourceFiles[i].lvl;
}
if (Player.sourceFiles[i].n === 5) {
hasAISF = true;
}
}
}
function NetscriptFunctions(workerScript) {
return {
Math : Math,
hacknetnodes : Player.hacknetNodes,
scan : function(ip=workerScript.serverIp){
scan : function(ip=workerScript.serverIp, hostnames=true){
var server = getServer(ip);
if (server == null) {
throw makeRuntimeRejectMsg(workerScript, 'Invalid IP or hostname passed into scan() command');
}
var out = [];
for (var i = 0; i < server.serversOnNetwork.length; i++) {
var entry = server.getServerOnNetwork(i).hostname;
var entry;
if (hostnames) {
entry = server.getServerOnNetwork(i).hostname;
} else {
entry = server.getServerOnNetwork(i).ip;
}
if (entry == null) {
continue;
}
@ -97,7 +114,7 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("Attempting to hack " + ip + " in " + hackingTime.toFixed(3) + " seconds (t=" + threads + ")");
//console.log("Hacking " + server.hostname + " after " + hackingTime.toString() + " seconds (t=" + threads + ")");
return netscriptDelay(hackingTime* 1000).then(function() {
return netscriptDelay(hackingTime* 1000, workerScript).then(function() {
if (workerScript.env.stopFlag) {return Promise.reject(workerScript);}
var hackChance = scriptCalculateHackingChance(server);
var rand = Math.random();
@ -142,7 +159,7 @@ function NetscriptFunctions(workerScript) {
if (log) {
workerScript.scriptRef.log("Sleeping for " + time + " milliseconds");
}
return netscriptDelay(time).then(function() {
return netscriptDelay(time, workerScript).then(function() {
return Promise.resolve(true);
});
},
@ -167,7 +184,7 @@ function NetscriptFunctions(workerScript) {
var growTime = scriptCalculateGrowTime(server);
//console.log("Executing grow() on server " + server.hostname + " in " + formatNumber(growTime/1000, 3) + " seconds")
workerScript.scriptRef.log("Executing grow() on server " + server.hostname + " in " + formatNumber(growTime/1000, 3) + " seconds (t=" + threads + ")");
return netscriptDelay(growTime).then(function() {
return netscriptDelay(growTime, workerScript).then(function() {
if (workerScript.env.stopFlag) {return Promise.reject(workerScript);}
server.moneyAvailable += (1 * threads); //It can be grown even if it has no money
var growthPercentage = processSingleServerGrowth(server, 450 * threads);
@ -203,10 +220,9 @@ function NetscriptFunctions(workerScript) {
}
var weakenTime = scriptCalculateWeakenTime(server);
//console.log("Executing weaken() on server " + server.hostname + " in " + formatNumber(weakenTime/1000, 3) + " seconds")
workerScript.scriptRef.log("Executing weaken() on server " + server.hostname + " in " +
formatNumber(weakenTime/1000, 3) + " seconds (t=" + threads + ")");
return netscriptDelay(weakenTime).then(function() {
return netscriptDelay(weakenTime, workerScript).then(function() {
if (workerScript.env.stopFlag) {return Promise.reject(workerScript);}
server.weaken(CONSTANTS.ServerWeakenAmount * threads);
workerScript.scriptRef.recordWeaken(server.ip, threads);
@ -228,6 +244,14 @@ function NetscriptFunctions(workerScript) {
if (args === undefined || args === null) {
throw makeRuntimeRejectMsg(workerScript, "tprint() call has incorrect number of arguments. Takes 1 argument");
}
var x = args.toString();
if (isHTML(x)) {
Player.takeDamage(1);
dialogBoxCreate("You suddenly feel a sharp shooting pain through your body as an angry voice in your head exclaims: <br><br>" +
"DON'T USE TPRINT() TO OUTPUT HTML ELEMENTS TO YOUR TERMINAL!!!!<br><br>" +
"(You lost 1 HP)");
return;
}
post(workerScript.scriptRef.filename + ": " + args.toString());
},
clearLog : function() {
@ -439,20 +463,70 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("killall(): Killing all scripts on " + server.hostname + ". May take a few minutes for the scripts to die");
return true;
},
scp : function(scriptname,ip){
if (scriptname === undefined || ip === undefined) {
throw makeRuntimeRejectMsg(workerScript, "scp() call has incorrect number of arguments. Takes 2 arguments");
scp : function(scriptname, ip1, ip2){
if (arguments.length !== 2 && arguments.length !== 3) {
throw makeRuntimeRejectMsg(workerScript, "Error: scp() call has incorrect number of arguments. Takes 2 or 3 arguments");
}
var destServer = getServer(ip);
if (destServer == null) {
throw makeRuntimeRejectMsg(workerScript, "Invalid hostname/ip passed into scp() command: " + ip);
if (!scriptname.endsWith(".lit") && !scriptname.endsWith(".script")) {
throw makeRuntimeRejectMsg(workerScript, "Error: scp() only works for .script and .lit files");
}
var currServ = getServer(workerScript.serverIp);
if (currServ == null) {
throw makeRuntimeRejectMsg(workerScript, "Could not find server ip for this script. This is a bug please contact game developer");
var destServer, currServ;
if (arguments.length === 3) { //scriptname, source, destination
if (scriptname === undefined || ip1 === undefined || ip2 === undefined) {
throw makeRuntimeRejectMsg(workerScript, "Error: scp() call has incorrect number of arguments. Takes 2 or 3 arguments");
}
destServer = getServer(ip2);
if (destServer == null) {
throw makeRuntimeRejectMsg(workerScript, "Error: Invalid hostname/ip passed into scp() command: " + ip);
}
currServ = getServer(ip1);
if (currServ == null) {
throw makeRuntimeRejectMsg(workerScript, "Could not find server ip for this script. This is a bug please contact game developer");
}
} else if (arguments.length === 2) { //scriptname, destination
if (scriptname === undefined || ip1 === undefined) {
throw makeRuntimeRejectMsg(workerScript, "Error: scp() call has incorrect number of arguments. Takes 2 or 3 arguments");
}
destServer = getServer(ip1);
if (destServer == null) {
throw makeRuntimeRejectMsg(workerScript, "Error: Invalid hostname/ip passed into scp() command: " + ip);
}
currServ = getServer(workerScript.serverIp);
if (currServ == null) {
throw makeRuntimeRejectMsg(workerScript, "Could not find server ip for this script. This is a bug please contact game developer");
}
}
//Scp for lit files
if (scriptname.endsWith(".lit")) {
var found = false;
for (var i = 0; i < currServ.messages.length; ++i) {
if (!(currServ.messages[i] instanceof Message) && currServ.messages[i] == scriptname) {
found = true;
}
}
if (!found) {
workerScript.scriptRef.log(scriptname + " does not exist. scp() failed");
return false;
}
for (var i = 0; i < destServer.messages.length; ++i) {
if (destServer.messages[i] === scriptname) {
workerScript.scriptRef.log(scriptname + " copied over to " + destServer.hostname);
return true; //Already exists
}
}
destServer.messages.push(scriptname);
workerScript.scriptRef.log(scriptname + " copied over to " + destServer.hostname);
return true;
}
//Scp for script files
var sourceScript = null;
for (var i = 0; i < currServ.scripts.length; ++i) {
if (scriptname == currServ.scripts[i].filename) {
@ -487,6 +561,64 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log(scriptname + " copied over to " + destServer.hostname);
return true;
},
ls : function(ip, grep) {
if (ip === undefined) {
throw makeRuntimeRejectMsg(workerScript, "ls() failed because of invalid arguments. Usage: ls(ip/hostname, [grep filter])");
}
var server = getServer(ip);
if (server === null) {
workerScript.scriptRef.log("ls() failed. Invalid IP or hostname passed in: " + ip);
throw makeRuntimeRejectMsg(workerScript, "ls() failed. Invalid IP or hostname passed in: " + ip);
}
//Get the grep filter, if one exists
var filter = false;
if (arguments.length >= 2) {
filter = grep.toString();
}
var allFiles = [];
for (var i = 0; i < server.programs.length; i++) {
if (filter) {
if (server.programs[i].includes(filter)) {
allFiles.push(server.programs[i]);
}
} else {
allFiles.push(server.programs[i]);
}
}
for (var i = 0; i < server.scripts.length; i++) {
if (filter) {
if (server.scripts[i].filename.includes(filter)) {
allFiles.push(server.scripts[i].filename);
}
} else {
allFiles.push(server.scripts[i].filename);
}
}
for (var i = 0; i < server.messages.length; i++) {
if (filter) {
if (server.messages[i] instanceof Message) {
if (server.messages[i].filename.includes(filter)) {
allFiles.push(server.messages[i].filename);
}
} else if (server.messages[i].includes(filter)) {
allFiles.push(server.messages[i]);
}
} else {
if (server.messages[i] instanceof Message) {
allFiles.push(server.messages[i].filename);
} else {
allFiles.push(server.messages[i]);
}
}
}
//Sort the files alphabetically then print each
allFiles.sort();
return allFiles;
},
hasRootAccess : function(ip){
if (ip===undefined){
throw makeRuntimeRejectMsg(workerScript, "hasRootAccess() call has incorrect number of arguments. Takes 1 argument");
@ -498,6 +630,13 @@ function NetscriptFunctions(workerScript) {
}
return server.hasAdminRights;
},
getIp : function() {
var scriptServer = getServer(workerScript.serverIp);
if (scriptServer == null) {
throw makeRuntimeRejectMsg(workerScript, "Could not find server. This is a bug in the game. Report to game dev");
}
return scriptServer.ip;
},
getHostname : function(){
var scriptServer = getServer(workerScript.serverIp);
if (scriptServer == null) {
@ -510,11 +649,33 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("getHackingLevel() returned " + Player.hacking_skill);
return Player.hacking_skill;
},
getIntelligence : function () {
if (!hasAISF) {
throw makeRuntimeRejectMsg(workerScript, "Cannot run getIntelligence(). It requires Source-File 5 to run.");
}
Player.updateSkillLevels();
workerScript.scriptRef.log("getHackingLevel() returned " + Player.intelligence);
return Player.intelligence;
},
getHackingMultipliers : function() {
return {
chance: Player.hacking_chance_mult,
speed: Player.hacking_speed_mult,
money: Player.hacking_money_mult,
growth: Player.hacking_grow_mult,
};
},
getBitNodeMultipliers: function() {
if (!hasAISF) {
throw makeRuntimeRejectMsg(workerScript, "Cannot run getBitNodeMultipliers(). It requires Source-File 5 to run.");
}
return BitNodeMultipliers;
},
getServerMoneyAvailable : function(ip){
var server = getServer(ip);
if (server == null) {
workerScript.scriptRef.log("Cannot getServerMoneyAvailable(). Invalid IP or hostname passed in: " + ip);
throw makeRuntimeRejectMsg(workerScript, "Cannot getServerMoneyAvailable(). Invalid IP or hostname passed in: " + ip);
workerScript.scriptRef.log("getServerMoneyAvailable() failed. Invalid IP or hostname passed in: " + ip);
throw makeRuntimeRejectMsg(workerScript, "getServerMoneyAvailable() failed. Invalid IP or hostname passed in: " + ip);
}
if (server.hostname == "home") {
//Return player's money
@ -587,6 +748,9 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("getServerRam() returned [" + formatNumber(server.maxRam, 2) + "GB, " + formatNumber(server.ramUsed, 2) + "GB]");
return [server.maxRam, server.ramUsed];
},
serverExists : function(ip) {
return (getServer(ip) !== null);
},
fileExists : function(filename,ip=workerScript.serverIp){
if (filename === undefined) {
throw makeRuntimeRejectMsg(workerScript, "fileExists() call has incorrect number of arguments. Usage: fileExists(scriptname, [server])");
@ -924,6 +1088,55 @@ function NetscriptFunctions(workerScript) {
}
return scriptCalculateWeakenTime(server) / 1000; //Returns seconds
},
getScriptIncome : function(scriptname, ip) {
if (arguments.length === 0) {
//Get total script income
return updateActiveScriptsItems();
} else {
//Get income for a particular script
var server = getServer(ip);
if (server === null) {
workerScript.scriptRef.log("getScriptIncome() failed. Invalid IP or hostnamed passed in: " + ip);
throw makeRuntimeRejectMsg(workerScript, "getScriptIncome() failed. Invalid IP or hostnamed passed in: " + ip);
}
var argsForScript = [];
for (var i = 2; i < arguments.length; ++i) {
argsForScript.push(arguments[i]);
}
var runningScriptObj = findRunningScript(scriptname, argsForScript, server);
if (runningScriptObj == null) {
workerScript.scriptRef.log("getScriptIncome() failed. No such script "+ scriptname + " on " + server.hostname + " with args: " + printArray(argsForScript));
return -1;
}
return runningScriptObj.onlineMoneyMade / runningScriptObj.onlineRunningTime;
}
},
getScriptExpGain : function(scriptname, ip) {
if (arguments.length === 0) {
var total = 0;
for (var i = 0; i < workerScripts.length; ++i) {
total += (workerScripts[i].scriptRef.onlineExpGained / workerScripts[i].scriptRef.onlineRunningTime);
}
return total;
} else {
//Get income for a particular script
var server = getServer(ip);
if (server === null) {
workerScript.scriptRef.log("getScriptExpGain() failed. Invalid IP or hostnamed passed in: " + ip);
throw makeRuntimeRejectMsg(workerScript, "getScriptExpGain() failed. Invalid IP or hostnamed passed in: " + ip);
}
var argsForScript = [];
for (var i = 2; i < arguments.length; ++i) {
argsForScript.push(arguments[i]);
}
var runningScriptObj = findRunningScript(scriptname, argsForScript, server);
if (runningScriptObj == null) {
workerScript.scriptRef.log("getScriptExpGain() failed. No such script "+ scriptname + " on " + server.hostname + " with args: " + printArray(argsForScript));
return -1;
}
return runningScriptObj.onlineExpGained / runningScriptObj.onlineRunningTime;
}
},
/* Singularity Functions */
universityCourse(universityName, className) {
@ -945,6 +1158,7 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("ERROR: You cannot study at Summit University because you are not in Aevum. universityCourse() failed");
return false;
}
Player.location = Locations.AevumSummitUniversity;
costMult = 4;
expMult = 3;
break;
@ -953,6 +1167,7 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("ERROR: You cannot study at Rothman University because you are not in Sector-12. universityCourse() failed");
return false;
}
Player.location = Locations.Sector12RothmanUniversity;
costMult = 3;
expMult = 2;
break;
@ -961,6 +1176,7 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("ERROR: You cannot study at ZB Institute of Technology because you are not in Volhaven. universityCourse() failed");
return false;
}
Player.location = Locations.VolhavenZBInstituteOfTechnology;
costMult = 5;
expMult = 4;
break;
@ -1016,6 +1232,7 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("ERROR: You cannot workout at Crush Fitness because you are not in Aevum. gymWorkout() failed");
return false;
}
Player.location = Locations.AevumCrushFitnessGym;
costMult = 2;
expMult = 1.5;
break;
@ -1024,6 +1241,7 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("ERROR: You cannot workout at Snap Fitness because you are not in Aevum. gymWorkout() failed");
return false;
}
Player.location = Locations.AevumSnapFitnessGym;
costMult = 6;
expMult = 4;
break;
@ -1032,6 +1250,7 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("ERROR: You cannot workout at Iron Gym because you are not in Sector-12. gymWorkout() failed");
return false;
}
Player.location = Locations.Sector12IronGym;
costMult = 1;
expMult = 1;
break;
@ -1040,6 +1259,7 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("ERROR: You cannot workout at Powerhouse Gym because you are not in Sector-12. gymWorkout() failed");
return false;
}
Player.location = Locations.Sector12PowerhouseGym;
costMult = 10;
expMult = 7.5;
break;
@ -1048,6 +1268,7 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("ERROR: You cannot workout at Millenium Fitness Gym because you are not in Volhaven. gymWorkout() failed");
return false;
}
Player.location = Locations.VolhavenMilleniumFitnessGym;
costMult = 3;
expMult = 2.5;
break;
@ -1098,6 +1319,7 @@ function NetscriptFunctions(workerScript) {
case Locations.Volhaven:
Player.loseMoney(200000);
Player.city = cityname;
Player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain);
workerScript.scriptRef.log("Traveled to " + cityname);
return true;
default:
@ -1133,6 +1355,7 @@ function NetscriptFunctions(workerScript) {
Player.getHomeComputer().serversOnNetwork.push(darkweb.ip);
darkweb.serversOnNetwork.push(Player.getHomeComputer().ip);
Player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain);
workerScript.scriptRef.log("You have purchased a Tor router!");
return true;
},
@ -1159,6 +1382,7 @@ function NetscriptFunctions(workerScript) {
"can be found on your home computer.");
} else {
workerScript.scriptRef.log("Not enough money to purchase " + programName);
return false;
}
return true;
case Programs.FTPCrackProgram.toLowerCase():
@ -1169,7 +1393,8 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("You have purchased the FTPCrack.exe program. The new program " +
"can be found on your home computer.");
} else {
workerScript.scriptRef.log("Not enough money to purchase " + itemName);
workerScript.scriptRef.log("Not enough money to purchase " + programName);
return false;
}
return true;
case Programs.RelaySMTPProgram.toLowerCase():
@ -1180,7 +1405,8 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("You have purchased the relaySMTP.exe program. The new program " +
"can be found on your home computer.");
} else {
workerScript.scriptRef.log("Not enough money to purchase " + itemName);
workerScript.scriptRef.log("Not enough money to purchase " + programName);
return false;
}
return true;
case Programs.HTTPWormProgram.toLowerCase():
@ -1191,7 +1417,8 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("You have purchased the HTTPWorm.exe program. The new program " +
"can be found on your home computer.");
} else {
workerScript.scriptRef.log("Not enough money to purchase " + itemName);
workerScript.scriptRef.log("Not enough money to purchase " + programName);
return false;
}
return true;
case Programs.SQLInjectProgram.toLowerCase():
@ -1202,7 +1429,8 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("You have purchased the SQLInject.exe program. The new program " +
"can be found on your home computer.");
} else {
workerScript.scriptRef.log("Not enough money to purchase " + itemName);
workerScript.scriptRef.log("Not enough money to purchase " + programName);
return false;
}
return true;
case Programs.DeepscanV1.toLowerCase():
@ -1213,7 +1441,8 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("You have purchased the DeepscanV1.exe program. The new program " +
"can be found on your home computer.");
} else {
workerScript.scriptRef.log("Not enough money to purchase " + itemName);
workerScript.scriptRef.log("Not enough money to purchase " + programName);
return false;
}
return true;
case Programs.DeepscanV2.toLowerCase():
@ -1224,7 +1453,8 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("You have purchased the DeepscanV2.exe program. The new program " +
"can be found on your home computer.");
} else {
workerScript.scriptRef.log("Not enough money to purchase " + itemName);
workerScript.scriptRef.log("Not enough money to purchase " + programName);
return false;
}
return true;
default:
@ -1261,6 +1491,7 @@ function NetscriptFunctions(workerScript) {
Player.loseMoney(cost);
Player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain);
workerScript.scriptRef.log("Purchased additional RAM for home computer! It now has " + homeComputer.maxRam + "GB of RAM.");
return true;
},
@ -1431,6 +1662,7 @@ function NetscriptFunctions(workerScript) {
Player.factionInvitations.splice(index, 1);
var fac = Factions[name];
joinFaction(fac);
Player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain);
workerScript.scriptRef.log("Joined the " + name + " faction.");
return true;
},
@ -1658,16 +1890,23 @@ function NetscriptFunctions(workerScript) {
return false;
}
for (var j = 0; j < Player.queuedAugmentations.length; ++j) {
if (Player.queuedAugmentations[j].name === aug.name) {
workerScript.scriptRef.log("ERROR: purchaseAugmentation() failed because you already have " + name);
return false;
}
var isNeuroflux = false;
if (aug.name === AugmentationNames.NeuroFluxGovernor) {
isNeuroflux = true;
}
for (var j = 0; j < Player.augmentations.length; ++j) {
if (Player.augmentations[j].name === aug.name) {
workerScript.scriptRef.log("ERROR: purchaseAugmentation() failed because you already have " + name);
return false;
if (!isNeuroflux) {
for (var j = 0; j < Player.queuedAugmentations.length; ++j) {
if (Player.queuedAugmentations[j].name === aug.name) {
workerScript.scriptRef.log("ERROR: purchaseAugmentation() failed because you already have " + name);
return false;
}
}
for (var j = 0; j < Player.augmentations.length; ++j) {
if (Player.augmentations[j].name === aug.name) {
workerScript.scriptRef.log("ERROR: purchaseAugmentation() failed because you already have " + name);
return false;
}
}
}
@ -1679,6 +1918,7 @@ function NetscriptFunctions(workerScript) {
var res = purchaseAugmentation(aug, fac, true);
workerScript.scriptRef.log(res);
if (isString(res) && res.startsWith("You purchased")) {
Player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain);
return true;
} else {
return false;
@ -1696,6 +1936,7 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("ERROR: installAugmentations() failed because you do not have any Augmentations to be installed");
return false;
}
Player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain);
workerScript.scriptRef.log("Installing Augmentations. This will cause this script to be killed");
installAugmentations();
return true;

@ -25,6 +25,7 @@ function WorkerScript(runningScriptObj) {
this.scriptRef = runningScriptObj;
this.errorMessage = "";
this.args = runningScriptObj.args;
this.killTrigger = function() {}; //CB func used to clear any delays (netscriptDelay())
}
//Returns the server on which the workerScript is running
@ -58,6 +59,34 @@ function prestigeWorkerScripts() {
//Loop through workerScripts and run every script that is not currently running
function runScriptsLoop() {
//Delete any scripts that finished or have been killed. Loop backwards bc removing
//items fucks up the indexing
for (var i = workerScripts.length - 1; i >= 0; i--) {
if (workerScripts[i].running == false && workerScripts[i].env.stopFlag == true) {
console.log("Deleting script: " + workerScripts[i].name);
//Delete script from the runningScripts array on its host serverIp
var ip = workerScripts[i].serverIp;
var name = workerScripts[i].name;
for (var j = 0; j < AllServers[ip].runningScripts.length; j++) {
if (AllServers[ip].runningScripts[j].filename == name &&
compareArrays(AllServers[ip].runningScripts[j].args, workerScripts[i].args)) {
AllServers[ip].runningScripts.splice(j, 1);
break;
}
}
//Free RAM
AllServers[ip].ramUsed -= workerScripts[i].ramUsage;
//Delete script from Active Scripts
deleteActiveScriptsItem(workerScripts[i]);
//Delete script from workerScripts
workerScripts.splice(i, 1);
}
}
//Run any scripts that haven't been started
for (var i = 0; i < workerScripts.length; i++) {
//If it isn't running, start the script
@ -120,35 +149,7 @@ function runScriptsLoop() {
}
}
//Delete any scripts that finished or have been killed. Loop backwards bc removing
//items fucks up the indexing
for (var i = workerScripts.length - 1; i >= 0; i--) {
if (workerScripts[i].running == false && workerScripts[i].env.stopFlag == true) {
console.log("Deleting script: " + workerScripts[i].name);
//Delete script from the runningScripts array on its host serverIp
var ip = workerScripts[i].serverIp;
var name = workerScripts[i].name;
for (var j = 0; j < AllServers[ip].runningScripts.length; j++) {
if (AllServers[ip].runningScripts[j].filename == name &&
compareArrays(AllServers[ip].runningScripts[j].args, workerScripts[i].args)) {
AllServers[ip].runningScripts.splice(j, 1);
break;
}
}
//Free RAM
AllServers[ip].ramUsed -= workerScripts[i].ramUsage;
//Delete script from Active Scripts
deleteActiveScriptsItem(workerScripts[i]);
//Delete script from workerScripts
workerScripts.splice(i, 1);
}
}
setTimeout(runScriptsLoop, 10000);
setTimeout(runScriptsLoop, 6000);
}
//Queues a script to be killed by settings its stop flag to true. Then, the code will reject
@ -159,6 +160,7 @@ function killWorkerScript(runningScriptObj, serverIp) {
if (workerScripts[i].name == runningScriptObj.filename && workerScripts[i].serverIp == serverIp &&
compareArrays(workerScripts[i].args, runningScriptObj.args)) {
workerScripts[i].env.stopFlag = true;
workerScripts[i].killTrigger();
return true;
}
}

@ -8,7 +8,8 @@ import {CONSTANTS} from "./Constants.js";
import {Programs} from "./CreateProgram.js";
import {determineCrimeSuccess} from "./Crimes.js";
import {Engine} from "./engine.js";
import {Factions, Faction} from "./Faction.js";
import {Factions, Faction,
displayFactionContent} from "./Faction.js";
import {Gang, resetGangs} from "./Gang.js";
import {Locations} from "./Location.js";
import {AllServers, Server, AddToAllServers} from "./Server.js";
@ -26,19 +27,21 @@ import {formatNumber,
function PlayerObject() {
//Skills and stats
this.hacking_skill = 1;
this.hacking_skill = 1;
//Fighting
this.hp = 10;
this.max_hp = 10;
this.strength = 1; //Damage dealt
this.defense = 1; //Damage received
this.dexterity = 1; //Accuracy
this.agility = 1; //Dodge %
//Combat stats
this.hp = 10;
this.max_hp = 10;
this.strength = 1; //Damage dealt
this.defense = 1; //Damage received
this.dexterity = 1; //Accuracy
this.agility = 1; //Dodge %
//Labor stats
this.charisma = 1;
//Intelligence, perhaps?
this.charisma = 1;
//Special stats
this.intelligence = 0;
//Hacking multipliers
this.hacking_chance_mult = 1; //Increase through ascensions/augmentations
@ -53,6 +56,7 @@ function PlayerObject() {
this.dexterity_exp = 0;
this.agility_exp = 0;
this.charisma_exp = 0;
this.intelligence_exp= 0;
this.hacking_mult = 1;
this.strength_mult = 1;
@ -143,12 +147,14 @@ function PlayerObject() {
this.workMoneyGained = 0;
this.createProgramName = "";
this.createProgramReqLvl = 0;
this.className = "";
this.crimeType = "";
this.timeWorked = 0; //in ms
this.timeWorkedCreateProgram = 0;
this.timeNeededToCompleteWork = 0;
this.work_money_mult = 1;
@ -193,15 +199,6 @@ PlayerObject.prototype.init = function() {
this.getHomeComputer().programs.push(Programs.NukeProgram);
}
PlayerObject.prototype.increaseMultiplier = function(name, val) {
let mult = this[name];
if (mult === null || mult === undefined) {
console.log("ERROR: Could not find this multiplier " + name);
return;
}
mult *= val;
}
PlayerObject.prototype.prestigeAugmentation = function() {
var homeComp = this.getHomeComputer();
this.currentServer = homeComp.ip;
@ -392,6 +389,12 @@ PlayerObject.prototype.updateSkillLevels = function() {
this.agility = Math.floor(this.calculateSkill(this.agility_exp) * this.agility_mult);
this.charisma = Math.floor(this.calculateSkill(this.charisma_exp) * this.charisma_mult);
if (this.intelligence > 0) {
this.intelligence = Math.floor(this.calculateSkill(this.intelligence_exp));
} else {
this.intelligence = 0;
}
var ratio = this.hp / this.max_hp;
this.max_hp = Math.floor(10 + this.defense / 10);
Player.hp = Math.round(this.max_hp * ratio);
@ -439,7 +442,7 @@ PlayerObject.prototype.resetMultipliers = function() {
// (2 * hacking_chance_multiplier * hacking_skill) 100
PlayerObject.prototype.calculateHackingChance = function() {
var difficultyMult = (100 - this.getCurrentServer().hackDifficulty) / 100;
var skillMult = (1.75 * this.hacking_skill);
var skillMult = (1.75 * this.hacking_skill) + (0.2 * this.intelligence);
var skillChance = (skillMult - this.getCurrentServer().requiredHackingSkill) / skillMult;
var chance = skillChance * difficultyMult * this.hacking_chance_mult;
if (chance > 1) {return 1;}
@ -454,7 +457,7 @@ PlayerObject.prototype.calculateHackingChance = function() {
// hacking_skill + 100
PlayerObject.prototype.calculateHackingTime = function() {
var difficultyMult = this.getCurrentServer().requiredHackingSkill * this.getCurrentServer().hackDifficulty;
var skillFactor = (2.5 * difficultyMult + 200) / (this.hacking_skill + 100);
var skillFactor = (2.5 * difficultyMult + 200) / (this.hacking_skill + 100 + (0.1 * this.intelligence));
return 5 * skillFactor / this.hacking_speed_mult;
}
@ -571,6 +574,24 @@ PlayerObject.prototype.gainCharismaExp = function(exp) {
this.charisma_exp += exp;
}
PlayerObject.prototype.gainIntelligenceExp = function(exp) {
if (isNaN(exp)) {
console.log("ERROR: NaN passed into Player.gainIntelligenceExp()"); return;
}
var hasBn = false;
for (var i = 0; i < this.sourceFiles.length; ++i) {
if (this.sourceFiles[i].n === 5) {
hasBn = true;
break;
}
}
if (hasBn || this.intelligence > 0) {
this.intelligence_exp += exp;
} else {
console.log("Not gaining intelligence experience bc it hasn't been unlocked yet");
}
}
/******* Working functions *******/
PlayerObject.prototype.resetWorkStatus = function() {
this.workHackExpGainRate = 0;
@ -592,6 +613,7 @@ PlayerObject.prototype.resetWorkStatus = function() {
this.workMoneyGained = 0;
this.timeWorked = 0;
this.timeWorkedCreateProgram = 0;
this.currentWorkFactionName = "";
this.currentWorkFactionDescription = "";
@ -648,7 +670,8 @@ PlayerObject.prototype.finishWork = function(cancelled, sing=false) {
var mainMenu = document.getElementById("mainmenu-container");
mainMenu.style.visibility = "visible";
this.isWorking = false;
Engine.loadTerminalContent();
//Engine.loadTerminalContent();
Engine.loadLocationContent();
if (sing) {
return "You worked a short shift of " + convertTimeMsToTimeElapsedString(this.timeWorked) + " and " +
@ -724,7 +747,7 @@ PlayerObject.prototype.work = function(numCycles) {
var txt = document.getElementById("work-in-progress-text");
txt.innerHTML = "You are currently working as a " + this.companyPosition.positionName +
" at " + Player.companyName + "<br><br>" +
" at " + this.companyName + "<br><br>" +
"You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "<br><br>" +
"You have earned: <br><br>" +
"$" + formatNumber(this.workMoneyGained, 2) + " ($" + formatNumber(this.workMoneyGainRate * cyclesPerSec, 2) + " / sec) <br><br>" +
@ -841,7 +864,8 @@ PlayerObject.prototype.finishWorkPartTime = function(sing=false) {
var mainMenu = document.getElementById("mainmenu-container");
mainMenu.style.visibility = "visible";
this.isWorking = false;
Engine.loadTerminalContent();
//Engine.loadTerminalContent();
Engine.loadLocationContent();
if (sing) {
return "You worked for " + convertTimeMsToTimeElapsedString(this.timeWorked) + " and " +
"earned a total of " +
@ -884,7 +908,9 @@ PlayerObject.prototype.finishFactionWork = function(cancelled, sing=false) {
this.isWorking = false;
Engine.loadTerminalContent();
//Engine.loadTerminalContent();
Engine.loadFactionContent();
displayFactionContent(faction.name);
if (sing) {
return "You worked for your faction " + faction.name + " for a total of " + convertTimeMsToTimeElapsedString(this.timeWorked) + ". " +
"You earned " +
@ -926,7 +952,7 @@ PlayerObject.prototype.startFactionHackWork = function(faction) {
this.resetWorkStatus();
this.workHackExpGainRate = .15 * this.hacking_exp_mult * BitNodeMultipliers.FactionWorkExpGain;
this.workRepGainRate = this.hacking_skill / CONSTANTS.MaxSkillLevel * this.faction_rep_mult;
this.workRepGainRate = this.workRepGainRate = (this.hacking_skill + this.intelligence) / CONSTANTS.MaxSkillLevel * this.faction_rep_mult;
this.factionWorkType = CONSTANTS.FactionWorkHacking;
this.currentWorkFactionDescription = "carrying out hacking contracts";
@ -974,7 +1000,7 @@ PlayerObject.prototype.workForFaction = function(numCycles) {
//Constantly update the rep gain rate
switch (this.factionWorkType) {
case CONSTANTS.FactionWorkHacking:
this.workRepGainRate = this.hacking_skill / CONSTANTS.MaxSkillLevel * this.faction_rep_mult;
this.workRepGainRate = (this.hacking_skill + this.intelligence) / CONSTANTS.MaxSkillLevel * this.faction_rep_mult;
break;
case CONSTANTS.FactionWorkField:
this.workRepGainRate = this.getFactionFieldWorkRepGain();
@ -1008,6 +1034,7 @@ PlayerObject.prototype.workForFaction = function(numCycles) {
//If timeWorked == 20 hours, then finish. You can only work for the faction for 20 hours
if (this.timeWorked >= CONSTANTS.MillisecondsPer20Hours) {
var maxCycles = CONSTANTS.GameCyclesPer20Hours;
this.timeWorked = CONSTANTS.MillisecondsPer20Hours;
this.workHackExpGained = this.workHackExpGainRate * maxCycles;
this.workStrExpGained = this.workStrExpGainRate * maxCycles;
this.workDefExpGained = this.workDefExpGainRate * maxCycles;
@ -1092,6 +1119,10 @@ PlayerObject.prototype.getWorkRepGain = function() {
var jobPerformance = this.companyPosition.calculateJobPerformance(this.hacking_skill, this.strength,
this.defense, this.dexterity,
this.agility, this.charisma);
//Intelligence provides a flat bonus to job performance
jobPerformance += (this.intelligence / CONSTANTS.MaxSkillLevel);
//Update reputation gain rate to account for company favor
var favorMult = 1 + (company.favor / 100);
if (isNaN(favorMult)) {favorMult = 1;}
@ -1113,7 +1144,8 @@ PlayerObject.prototype.getFactionFieldWorkRepGain = function() {
this.defense / CONSTANTS.MaxSkillLevel +
this.dexterity / CONSTANTS.MaxSkillLevel +
this.agility / CONSTANTS.MaxSkillLevel +
this.charisma / CONSTANTS.MaxSkillLevel) / 6;
this.charisma / CONSTANTS.MaxSkillLevel +
this.intelligence / CONSTANTS.MaxSkillLevel) / 6;
return t * this.faction_rep_mult;
}
@ -1125,21 +1157,22 @@ PlayerObject.prototype.startCreateProgramWork = function(programName, time, reqL
//Time needed to complete work affected by hacking skill (linearly based on
//ratio of (your skill - required level) to MAX skill)
var timeMultiplier = (CONSTANTS.MaxSkillLevel - (this.hacking_skill - reqLevel)) / CONSTANTS.MaxSkillLevel;
if (timeMultiplier > 1) {timeMultiplier = 1;}
if (timeMultiplier < 0.01) {timeMultiplier = 0.01;}
//var timeMultiplier = (CONSTANTS.MaxSkillLevel - (this.hacking_skill - reqLevel)) / CONSTANTS.MaxSkillLevel;
//if (timeMultiplier > 1) {timeMultiplier = 1;}
//if (timeMultiplier < 0.01) {timeMultiplier = 0.01;}
this.createProgramReqLvl = reqLevel;
this.timeNeededToCompleteWork = timeMultiplier * time;
this.timeNeededToCompleteWork = time;
//Check for incomplete program
for (var i = 0; i < Player.getHomeComputer().programs.length; ++i) {
var programFile = Player.getHomeComputer().programs[i];
for (var i = 0; i < this.getHomeComputer().programs.length; ++i) {
var programFile = this.getHomeComputer().programs[i];
if (programFile.startsWith(programName) && programFile.endsWith("%-INC")) {
var res = programFile.split("-");
if (res.length != 3) {break;}
var percComplete = Number(res[1].slice(0, -1));
if (isNaN(percComplete) || percComplete < 0 || percComplete >= 100) {break;}
this.timeWorked = percComplete / 100 * this.timeNeededToCompleteWork;
Player.getHomeComputer().programs.splice(i, 1);
this.timeWorkedCreateProgram = percComplete / 100 * this.timeNeededToCompleteWork;
this.getHomeComputer().programs.splice(i, 1);
}
}
@ -1157,17 +1190,24 @@ PlayerObject.prototype.startCreateProgramWork = function(programName, time, reqL
}
PlayerObject.prototype.createProgramWork = function(numCycles) {
this.timeWorked += Engine._idleSpeed * numCycles;
//Higher hacking skill will allow you to create programs faster
var reqLvl = this.createProgramReqLvl;
var skillMult = (this.hacking_skill / reqLvl); //This should always be greater than 1;
skillMult = 1 + ((skillMult - 1) / 5); //The divider constant can be adjusted as necessary
//Skill multiplier directly applied to "time worked"
this.timeWorked += (Engine._idleSpeed * numCycles);
this.timeWorkedCreateProgram += (Engine._idleSpeed * numCycles * skillMult);
var programName = this.createProgramName;
if (this.timeWorked >= this.timeNeededToCompleteWork) {
if (this.timeWorkedCreateProgram >= this.timeNeededToCompleteWork) {
this.finishCreateProgramWork(false);
}
var txt = document.getElementById("work-in-progress-text");
txt.innerHTML = "You are currently working on coding " + programName + ".<br><br> " +
"You have been working for " + convertTimeMsToTimeElapsedString(this.timeWorked) + "<br><br>" +
"The program is " + (this.timeWorked / this.timeNeededToCompleteWork * 100).toFixed(2) + "% complete. <br>" +
"The program is " + (this.timeWorkedCreateProgram / this.timeNeededToCompleteWork * 100).toFixed(2) + "% complete. <br>" +
"If you cancel, your work will be saved and you can come back to complete the program later.";
}
@ -1177,17 +1217,19 @@ PlayerObject.prototype.finishCreateProgramWork = function(cancelled, sing=false)
dialogBoxCreate("You've finished creating " + programName + "!<br>" +
"The new program can be found on your home computer.");
Player.getHomeComputer().programs.push(programName);
this.getHomeComputer().programs.push(programName);
} else {
var perc = Math.floor(this.timeWorked / this.timeNeededToCompleteWork * 100).toString();
var perc = Math.floor(this.timeWorkedCreateProgram / this.timeNeededToCompleteWork * 100).toString();
var incompleteName = programName + "-" + perc + "%-INC";
Player.getHomeComputer().programs.push(incompleteName);
this.getHomeComputer().programs.push(incompleteName);
}
this.gainIntelligenceExp(this.createProgramReqLvl / CONSTANTS.IntelligenceProgramBaseExpGain);
var mainMenu = document.getElementById("mainmenu-container");
mainMenu.style.visibility = "visible";
Player.isWorking = false;
this.isWorking = false;
Engine.loadTerminalContent();
}
@ -1255,7 +1297,7 @@ PlayerObject.prototype.startClass = function(costMult, expMult, className) {
agiExp = baseGymExp * expMult / gameCPS;
break;
default:
throw new Error("ERR: Invalid/unregocnized class name");
throw new Error("ERR: Invalid/unrecognized class name");
return;
}
@ -1386,16 +1428,16 @@ PlayerObject.prototype.startCrime = function(hackExp, strExp, defExp, dexExp, ag
PlayerObject.prototype.commitCrime = function (numCycles) {
this.timeWorked += Engine._idleSpeed * numCycles;
if (this.timeWorked >= this.timeNeededToCompleteWork) {Player.finishCrime(false); return;}
if (this.timeWorked >= this.timeNeededToCompleteWork) {this.finishCrime(false); return;}
var percent = Math.round(Player.timeWorked / Player.timeNeededToCompleteWork * 100);
var percent = Math.round(this.timeWorked / this.timeNeededToCompleteWork * 100);
var numBars = Math.round(percent / 5);
if (numBars < 0) {numBars = 0;}
if (numBars > 20) {numBars = 20;}
var progressBar = "[" + Array(numBars+1).join("|") + Array(20 - numBars + 1).join(" ") + "]";
var txt = document.getElementById("work-in-progress-text");
txt.innerHTML = "You are attempting to " + Player.crimeType + ".<br>" +
txt.innerHTML = "You are attempting to " + this.crimeType + ".<br>" +
"Time remaining: " + convertTimeMsToTimeElapsedString(this.timeNeededToCompleteWork - this.timeWorked) + "<br>" +
progressBar.replace( / /g, "&nbsp;" );
}
@ -1431,6 +1473,7 @@ PlayerObject.prototype.finishCrime = function(cancelled) {
break;
case CONSTANTS.CrimeGrandTheftAuto:
this.karma -= 5;
this.gainIntelligenceExp(CONSTANTS.IntelligenceCrimeBaseExpGain);
break;
case CONSTANTS.CrimeKidnap:
this.karma -= 6;
@ -1438,9 +1481,11 @@ PlayerObject.prototype.finishCrime = function(cancelled) {
case CONSTANTS.CrimeAssassination:
++this.numPeopleKilled;
this.karma -= 10;
this.gainIntelligenceExp(CONSTANTS.IntelligenceCrimeBaseExpGain);
break;
case CONSTANTS.CrimeHeist:
this.karma -= 15;
this.gainIntelligenceExp(5 * CONSTANTS.IntelligenceCrimeBaseExpGain);
break;
default:
console.log(this.crimeType);
@ -1531,7 +1576,7 @@ PlayerObject.prototype.hospitalize = function() {
dialogBoxCreate("You were in critical condition! You were taken to the hospital where " +
"luckily they were able to save your life. You were charged $" +
formatNumber(this.max_hp * CONSTANTS.HospitalCostPerHp, 2));
Player.loseMoney(this.max_hp * CONSTANTS.HospitalCostPerHp);
this.loseMoney(this.max_hp * CONSTANTS.HospitalCostPerHp);
this.hp = this.max_hp;
}
@ -1615,7 +1660,12 @@ PlayerObject.prototype.applyForJob = function(entryPosType, sing=false) {
this.companyName = company.companyName;
this.companyPosition = pos;
Player.firstJobRecvd = true;
if (this.firstJobRecvd === false) {
this.firstJobRecvd = true;
document.getElementById("job-tab").style.display = "list-item";
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
}
if (leaveCompany) {
if (sing) {return true;}
@ -1719,7 +1769,12 @@ PlayerObject.prototype.applyForAgentJob = function(sing=false) {
PlayerObject.prototype.applyForEmployeeJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions.Employee)) {
Player.firstJobRecvd = true;
if (this.firstJobRecvd === false) {
this.firstJobRecvd = true;
document.getElementById("job-tab").style.display = "list-item";
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
}
this.companyName = company.companyName;
this.companyPosition = CompanyPositions.Employee;
if (sing) {return true;}
@ -1734,7 +1789,12 @@ PlayerObject.prototype.applyForEmployeeJob = function(sing=false) {
PlayerObject.prototype.applyForPartTimeEmployeeJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions.PartTimeEmployee)) {
Player.firstJobRecvd = true;
if (this.firstJobRecvd === false) {
this.firstJobRecvd = true;
document.getElementById("job-tab").style.display = "list-item";
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
}
this.companyName = company.companyName;
this.companyPosition = CompanyPositions.PartTimeEmployee;
if (sing) {return true;}
@ -1749,7 +1809,12 @@ PlayerObject.prototype.applyForPartTimeEmployeeJob = function(sing=false) {
PlayerObject.prototype.applyForWaiterJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions.Waiter)) {
Player.firstJobRecvd = true;
if (this.firstJobRecvd === false) {
this.firstJobRecvd = true;
document.getElementById("job-tab").style.display = "list-item";
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
}
this.companyName = company.companyName;
this.companyPosition = CompanyPositions.Waiter;
if (sing) {return true;}
@ -1764,7 +1829,12 @@ PlayerObject.prototype.applyForWaiterJob = function(sing=false) {
PlayerObject.prototype.applyForPartTimeWaiterJob = function(sing=false) {
var company = Companies[this.location]; //Company being applied to
if (this.isQualified(company, CompanyPositions.PartTimeWaiter)) {
Player.firstJobRecvd = true;
if (this.firstJobRecvd === false) {
this.firstJobRecvd = true;
document.getElementById("job-tab").style.display = "list-item";
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();
}
this.companyName = company.companyName;
this.companyPosition = CompanyPositions.PartTimeWaiter;
if (sing) {return true;}
@ -2113,10 +2183,10 @@ PlayerObject.prototype.checkForFactionInvitations = function() {
var totalHacknetRam = 0;
var totalHacknetCores = 0;
var totalHacknetLevels = 0;
for (var i = 0; i < Player.hacknetNodes.length; ++i) {
totalHacknetLevels += Player.hacknetNodes[i].level;
totalHacknetRam += Player.hacknetNodes[i].ram;
totalHacknetCores += Player.hacknetNodes[i].cores;
for (var i = 0; i < this.hacknetNodes.length; ++i) {
totalHacknetLevels += this.hacknetNodes[i].level;
totalHacknetRam += this.hacknetNodes[i].ram;
totalHacknetCores += this.hacknetNodes[i].cores;
}
if (!netburnersFac.isBanned && !netburnersFac.isMember && !netburnersFac.alreadyInvited &&
this.hacking_skill >= 80 && totalHacknetRam >= 8 &&

@ -9,6 +9,7 @@ import {Factions, Faction, initFactions,
joinFaction} from "./Faction.js";
import {Locations} from "./Location.js";
import {initMessages, Messages, Message} from "./Message.js";
import {initSingularitySFFlags} from "./NetscriptFunctions.js";
import {WorkerScript, workerScripts,
prestigeWorkerScripts} from "./NetscriptWorker.js";
import {Player} from "./Player.js";
@ -117,6 +118,7 @@ function prestigeAugmentation() {
var mainMenu = document.getElementById("mainmenu-container");
mainMenu.style.visibility = "visible";
Terminal.resetTerminalInput();
Engine.loadTerminalContent();
//Red Pill
@ -215,7 +217,14 @@ function prestigeSourceFile() {
var mainMenu = document.getElementById("mainmenu-container");
mainMenu.style.visibility = "visible";
Terminal.resetTerminalInput();
Engine.loadTerminalContent();
//Reinitialize flags in case you just finished BN-4
initSingularitySFFlags();
//Gain int exp
Player.gainIntelligenceExp(5);
}
export {prestigeAugmentation, prestigeSourceFile};

@ -123,6 +123,9 @@ function giveSourceFile(bitNodeNumber) {
} else {
var playerSrcFile = new PlayerOwnedSourceFile(bitNodeNumber, 1);
Player.sourceFiles.push(playerSrcFile);
if (bitNodeNumber === 5) { //Artificial Intelligence
Player.intelligence = 1;
}
dialogBoxCreate("You received a Source-File for destroying a Bit Node!<br><br>" +
sourceFile.name + "<br><br>" + sourceFile.info);
}
@ -206,7 +209,7 @@ function loadBitVerse(destroyedBitNodeNum) {
var elemId = "bitnode-" + i.toString();
var elem = clearEventListeners(elemId);
if (elem == null) {return;}
if (i === 1 || i === 2 || i === 4 || i === 11) {
if (i === 1 || i === 2 || i === 4 || i === 5 || i === 11) {
elem.addEventListener("click", function() {
var bitNodeKey = "BitNode" + i;
var bitNode = BitNodes[bitNodeKey];

@ -73,7 +73,16 @@ BitburnerSaveObject.prototype.saveGame = function() {
this.AllGangsSave = JSON.stringify(AllGangs);
}
var saveString = btoa(unescape(encodeURIComponent(JSON.stringify(this))));
window.localStorage.setItem("bitburnerSave", saveString);
try {
window.localStorage.setItem("bitburnerSave", saveString);
} catch(e) {
if (e.code == 22) {
dialogBoxCreate("Failed to save game because the size of the save file " +
"is too large. Consider killing several of your scripts to " +
"fix this, or increasing the size of your browsers localStorage");
}
}
console.log("Game saved!");
Engine.createStatusText("Game saved!");
@ -466,7 +475,7 @@ BitburnerSaveObject.prototype.exportGame = function() {
this.VersionSave = JSON.stringify(CONSTANTS.Version);
var saveString = btoa(unescape(encodeURIComponent(JSON.stringify(this))));
var filename = "bitburnerSave.json";
var file = new Blob([saveString], {type: 'text/plain'});
if (window.navigator.msSaveOrOpenBlob) {// IE10+
window.navigator.msSaveOrOpenBlob(file, filename);

@ -1,6 +1,18 @@
var ace = require('brace');
require('brace/mode/javascript');
require('brace/mode/netscript');
require('brace/theme/chaos');
require('brace/theme/chrome');
require('brace/theme/monokai');
require('brace/theme/solarized_dark');
require('brace/theme/solarized_light');
require('brace/theme/terminal');
require('brace/theme/twilight');
require('brace/theme/xcode');
require("brace/keybinding/vim");
require("brace/keybinding/emacs");
import {CONSTANTS} from "./Constants.js";
import {Engine} from "./engine.js";
@ -18,6 +30,12 @@ import {compareArrays} from "../utils/HelperFunctions.j
import {formatNumber, numOccurrences,
numNetscriptOperators} from "../utils/StringHelperFunctions.js";
var keybindings = {
ace: null,
vim: "ace/keyboard/vim",
emacs: "ace/keyboard/emacs",
};
function scriptEditorInit() {
//Initialize save and close button
var closeButton = document.getElementById("script-editor-save-and-close-button");
@ -27,26 +45,59 @@ function scriptEditorInit() {
return false;
});
//Allow tabs (four spaces) in all textareas
var textareas = document.getElementsByTagName('textarea');
var count = textareas.length;
for(var i=0;i<count;i++){
textareas[i].onkeydown = function(e){
if(e.keyCode==9 || e.which==9){
e.preventDefault();
var start = this.selectionStart;
var end = this.selectionEnd;
//Initialize ACE Script editor
var editor = ace.edit('javascript-editor');
editor.getSession().setMode('ace/mode/netscript');
editor.setTheme('ace/theme/monokai');
document.getElementById('javascript-editor').style.fontSize='16px';
editor.setOption("showPrintMargin", false);
//Set textarea value to: text before caret + four spaces + text after caret
let spaces = " ";
this.value = this.value.substring(0, start) + spaces + this.value.substring(end);
/* Script editor options */
//Theme
var themeDropdown = document.getElementById("script-editor-option-theme");
themeDropdown.selectedIndex = 2;
themeDropdown.onchange = function() {
var val = themeDropdown.value;
var themePath = "ace/theme/" + val.toLowerCase();
editor.setTheme(themePath);
};
//Put caret at after the four spaces
this.selectionStart = this.selectionEnd = start + spaces.length;
}
}
}
};
//Keybinding
var keybindingDropdown = document.getElementById("script-editor-option-keybinding");
keybindingDropdown.onchange = function() {
var val = keybindingDropdown.value;
editor.setKeyboardHandler(keybindings[val.toLowerCase()]);
};
//Highlight Active line
var highlightActiveChkBox = document.getElementById("script-editor-option-highlightactiveline");
highlightActiveChkBox.onchange = function() {
editor.setHighlightActiveLine(highlightActiveChkBox.checked);
};
//Show Invisibles
var showInvisiblesChkBox = document.getElementById("script-editor-option-showinvisibles");
showInvisiblesChkBox.onchange = function() {
editor.setShowInvisibles(showInvisiblesChkBox.checked);
};
//Use Soft Tab
var softTabChkBox = document.getElementById("script-editor-option-usesofttab");
softTabChkBox.onchange = function() {
editor.getSession().setUseSoftTabs(softTabChkBox.checked);
};
//Configure some of the VIM keybindings
ace.config.loadModule('ace/keyboard/vim', function(module) {
var VimApi = module.CodeMirror.Vim;
VimApi.defineEx('write', 'w', function(cm, input) {
saveAndCloseScriptEditor();
});
VimApi.defineEx('quit', 'q', function(cm, input) {
Engine.loadTerminalContent();
});
});
}
document.addEventListener("DOMContentLoaded", scriptEditorInit, false);
//Updates line number and RAM usage in script
@ -163,6 +214,7 @@ Script.prototype.updateRamUsage = function() {
}
function calculateRamUsage(codeCopy) {
codeCopy = codeCopy.replace(/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm, '$1'); //Delete comments
codeCopy = codeCopy.replace(/\s/g,''); //Remove all whitespace
var baseRam = 1.4;
var whileCount = numOccurrences(codeCopy, "while(");
@ -183,8 +235,12 @@ function calculateRamUsage(codeCopy) {
var killCount = numOccurrences(codeCopy, "kill(") + numOccurrences(codeCopy, "killall(");
var scpCount = numOccurrences(codeCopy, "scp(");
var hasRootAccessCount = numOccurrences(codeCopy, "hasRootAccess(");
var getHostnameCount = numOccurrences(codeCopy, "getHostname(");
var getHackingLevelCount = numOccurrences(codeCopy, "getHackingLevel(");
var getHostnameCount = numOccurrences(codeCopy, "getHostname(") +
numOccurrences(codeCopy, "getIp(");
var getHackingLevelCount = numOccurrences(codeCopy, "getHackingLevel(") +
numOccurrences(codeCopy, "getIntelligence(");
var getMultipliersCount = numOccurrences(codeCopy, "getHackingMultipliers(") +
numOccurrences(codeCopy, "getBitNodeMultipliers(");
var getServerCount = numOccurrences(codeCopy, "getServerMoneyAvailable(") +
numOccurrences(codeCopy, "getServerMaxMoney(") +
numOccurrences(codeCopy, "getServerSecurityLevel(") +
@ -192,10 +248,10 @@ function calculateRamUsage(codeCopy) {
numOccurrences(codeCopy, "getServerGrowth(") +
numOccurrences(codeCopy, "getServerRequiredHackingLevel(") +
numOccurrences(codeCopy, "getServerNumPortsRequired(") +
numOccurrences(codeCopy, "getServerRam(");
numOccurrences(codeCopy, "getServerRam(") +
numOccurrences(codeCopy, "serverExists(");
var fileExistsCount = numOccurrences(codeCopy, "fileExists(");
var isRunningCount = numOccurrences(codeCopy, "isRunning(");
var numOperators = numNetscriptOperators(codeCopy);
var purchaseHacknetCount = numOccurrences(codeCopy, "purchaseHacknetNode(");
var hacknetnodesArrayCount = numOccurrences(codeCopy, "hacknetnodes[");
var hnUpgLevelCount = numOccurrences(codeCopy, ".upgradeLevel(");
@ -212,7 +268,9 @@ function calculateRamUsage(codeCopy) {
var scriptReadCount = numOccurrences(codeCopy, "read(");
var arbScriptCount = numOccurrences(codeCopy, "scriptRunning(") +
numOccurrences(codeCopy, "scriptKill(");
var getScriptCount = numOccurrences(codeCopy, "getScriptRam(");
var getScriptCount = numOccurrences(codeCopy, "getScriptRam(") +
numOccurrences(codeCopy, "getScriptIncome(") +
numOccurrences(codeCopy, "getScriptExpGain(");
var getHackTimeCount = numOccurrences(codeCopy, "getHackTime(") +
numOccurrences(codeCopy, "getGrowTime(") +
numOccurrences(codeCopy, "getWeakenTime(");
@ -262,10 +320,10 @@ function calculateRamUsage(codeCopy) {
(hasRootAccessCount * CONSTANTS.ScriptHasRootAccessRamCost) +
(getHostnameCount * CONSTANTS.ScriptGetHostnameRamCost) +
(getHackingLevelCount * CONSTANTS.ScriptGetHackingLevelRamCost) +
(getMultipliersCount * CONSTANTS.ScriptGetMultipliersRamCost) +
(getServerCount * CONSTANTS.ScriptGetServerCost) +
(fileExistsCount * CONSTANTS.ScriptFileExistsRamCost) +
(isRunningCount * CONSTANTS.ScriptIsRunningRamCost) +
(numOperators * CONSTANTS.ScriptOperatorRamCost) +
(purchaseHacknetCount * CONSTANTS.ScriptPurchaseHacknetRamCost) +
(hacknetnodesArrayCount * CONSTANTS.ScriptHacknetNodesRamCost) +
(hnUpgLevelCount * CONSTANTS.ScriptHNUpgLevelRamCost) +
@ -444,19 +502,7 @@ function RunningScript(script, args) {
this.threads = 1;
//[MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
this.dataMap = new AllServersMap([0, 0, 0, 0]);
}
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 = [];
this.dataMap = new AllServersMap([0, 0, 0, 0], true);
}
RunningScript.prototype.log = function(txt) {
@ -483,7 +529,7 @@ RunningScript.prototype.clearLog = function() {
RunningScript.prototype.recordHack = function(serverIp, moneyGained, n=1) {
if (this.dataMap == null) {
//[MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
this.dataMap = new AllServersMap([0, 0, 0, 0]);
this.dataMap = new AllServersMap([0, 0, 0, 0], true);
}
this.dataMap[serverIp][0] += moneyGained;
this.dataMap[serverIp][1] += n;
@ -493,7 +539,7 @@ RunningScript.prototype.recordHack = function(serverIp, moneyGained, n=1) {
RunningScript.prototype.recordGrow = function(serverIp, n=1) {
if (this.dataMap == null) {
//[MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
this.dataMap = new AllServersMap([0, 0, 0, 0]);
this.dataMap = new AllServersMap([0, 0, 0, 0], true);
}
this.dataMap[serverIp][2] += n;
}
@ -502,7 +548,7 @@ RunningScript.prototype.recordGrow = function(serverIp, n=1) {
RunningScript.prototype.recordWeaken = function(serverIp, n=1) {
if (this.dataMap == null) {
//[MoneyStolen, NumTimesHacked, NumTimesGrown, NumTimesWeaken]
this.dataMap = new AllServersMap([0, 0, 0, 0]);
this.dataMap = new AllServersMap([0, 0, 0, 0], true);
}
this.dataMap[serverIp][3] += n;
}
@ -520,9 +566,12 @@ Reviver.constructors.RunningScript = RunningScript;
//Creates an object that creates a map/dictionary with the IP of each existing server as
//a key. Initializes every key with a specified value that can either by a number or an array
function AllServersMap(arr=false) {
function AllServersMap(arr=false, filterOwned=false) {
for (var ip in AllServers) {
if (AllServers.hasOwnProperty(ip)) {
if (filterOwned && (AllServers[ip].purchasedByPlayer || AllServers[ip].hostname === "home")) {
continue;
}
if (arr) {
this[ip] = [0, 0, 0, 0];
} else {
@ -532,14 +581,6 @@ function AllServersMap(arr=false) {
}
}
AllServersMap.prototype.reset = function() {
for (var ip in this) {
if (this.hasOwnProperty(ip)) {
this[ip] = 0;
}
}
}
AllServersMap.prototype.printConsole = function() {
for (var ip in this) {
if (this.hasOwnProperty(ip)) {

@ -32,7 +32,7 @@ function Server(ip=createRandomIp(), hostname="", organizationName="",
//RAM, CPU speed and Scripts
this.maxRam = maxRam; //GB
this.ramUsed = 0;
this.cpuSpeed = 1; //MHz
this.cpuCores = 1; //Max of 8, affects hacking times and Hacking MIssion starting Cores
this.scripts = [];
this.runningScripts = []; //Stores RunningScript objects
@ -78,8 +78,8 @@ Server.prototype.setHackingParameters = function(requiredHackingSkill, moneyAvai
this.moneyAvailable = moneyAvailable * BitNodeMultipliers.ServerStartingMoney;
}
this.moneyMax = 25 * this.moneyAvailable * BitNodeMultipliers.ServerMaxMoney;
this.hackDifficulty = hackDifficulty;
this.baseDifficulty = hackDifficulty;
this.hackDifficulty = hackDifficulty * BitNodeMultipliers.ServerStartingSecurity;
this.baseDifficulty = hackDifficulty * BitNodeMultipliers.ServerStartingSecurity;
this.minDifficulty = Math.max(1, Math.round(hackDifficulty / 3));
this.serverGrowth = serverGrowth;
}
@ -118,7 +118,9 @@ Server.prototype.getScript = function(scriptName) {
//Strengthens a server's security level (difficulty) by the specified amount
Server.prototype.fortify = function(amt) {
this.hackDifficulty += amt;
if (this.hackDifficulty > 99) {this.hackDifficulty = 99;}
//Place some arbitrarily limit that realistically should never happen unless someone is
//screwing around with the game
if (this.hackDifficulty > 1000000) {this.hackDifficulty = 1000000;}
}
Server.prototype.weaken = function(amt) {
@ -155,26 +157,26 @@ function initForeignServers() {
BachmanAndAssociatesServer.setPortProperties(5);
AddToAllServers(BachmanAndAssociatesServer);
var BladeIndustriesServer = new Server(createRandomIp(), "blade", "Blade Industries", false, false, false, 0);
var BladeIndustriesServer = new Server(createRandomIp(), "blade", "Blade Industries", false, false, false, 2);
BladeIndustriesServer.setHackingParameters(getRandomInt(1000, 1100), getRandomInt(12000000000, 20000000000), getRandomInt(90, 95), getRandomInt(60, 75));
BladeIndustriesServer.setPortProperties(5);
BladeIndustriesServer.messages.push("beyond-man.lit");
AddToAllServers(BladeIndustriesServer);
var NWOServer = new Server(createRandomIp(), "nwo", "New World Order", false, false, false, 0);
var NWOServer = new Server(createRandomIp(), "nwo", "New World Order", false, false, false, 2);
NWOServer.setHackingParameters(getRandomInt(1000, 1200), getRandomInt(25000000000, 35000000000), 99, getRandomInt(75, 85));
NWOServer.setPortProperties(5);
NWOServer.messages.push("the-hidden-world.lit");
AddToAllServers(NWOServer);
var ClarkeIncorporatedServer = new Server(createRandomIp(), "clarkeinc", "Clarke Incorporated", false, false, false, 0);
var ClarkeIncorporatedServer = new Server(createRandomIp(), "clarkeinc", "Clarke Incorporated", false, false, false, 2);
ClarkeIncorporatedServer.setHackingParameters(getRandomInt(1000, 1200), getRandomInt(15000000000, 25000000000), getRandomInt(50, 60), getRandomInt(50, 70));
ClarkeIncorporatedServer.setPortProperties(5);
ClarkeIncorporatedServer.messages.push("beyond-man.lit");
ClarkeIncorporatedServer.messages.push("cost-of-immortality.lit");
AddToAllServers(ClarkeIncorporatedServer);
var OmniTekIncorporatedServer = new Server(createRandomIp(), "omnitek", "OmniTek Incorporated", false, false, false, 0);
var OmniTekIncorporatedServer = new Server(createRandomIp(), "omnitek", "OmniTek Incorporated", false, false, false, 2);
OmniTekIncorporatedServer.setHackingParameters(getRandomInt(900, 1100), getRandomInt(15000000000, 20000000000), getRandomInt(90, 99), getRandomInt(95, 99));
OmniTekIncorporatedServer.setPortProperties(5);
OmniTekIncorporatedServer.messages.push("coded-intelligence.lit");
@ -218,7 +220,7 @@ function initForeignServers() {
InfoCommServer.setPortProperties(5);
AddToAllServers(InfoCommServer);
var HeliosLabsServer = new Server(createRandomIp(), "helios", "Helios Labs", false, false, false, 0);
var HeliosLabsServer = new Server(createRandomIp(), "helios", "Helios Labs", false, false, false, 2);
HeliosLabsServer.setHackingParameters(getRandomInt(800, 900), getRandomInt(550000000, 750000000), getRandomInt(85, 95), getRandomInt(70, 80));
HeliosLabsServer.setPortProperties(5);
HeliosLabsServer.messages.push("beyond-man.lit");
@ -252,7 +254,7 @@ function initForeignServers() {
MicrodyneTechnologiesServer.messages.push("synthetic-muscles.lit");
AddToAllServers(MicrodyneTechnologiesServer);
var TaiYangDigitalServer = new Server(createRandomIp(), "taiyang-digital", "Taiyang Digital", false, false, false, 0);
var TaiYangDigitalServer = new Server(createRandomIp(), "taiyang-digital", "Taiyang Digital", false, false, false, 2);
TaiYangDigitalServer.setHackingParameters(getRandomInt(850, 950), getRandomInt(800000000, 900000000), getRandomInt(70, 80), getRandomInt(70, 80));
TaiYangDigitalServer.setPortProperties(5);
TaiYangDigitalServer.messages.push("A-Green-Tomorrow.lit");
@ -265,7 +267,7 @@ function initForeignServers() {
AddToAllServers(GalacticCyberSystemsServer);
//Defense Companies ("Large" Companies)
var AeroCorpServer = new Server(createRandomIp(), "aerocorp", "AeroCorp", false, false, false, 0);
var AeroCorpServer = new Server(createRandomIp(), "aerocorp", "AeroCorp", false, false, false, 2);
AeroCorpServer.setHackingParameters(getRandomInt(850, 925), getRandomInt(1000000000, 1200000000), getRandomInt(80, 90), getRandomInt(55, 65));
AeroCorpServer.setPortProperties(5);
AeroCorpServer.messages.push("man-and-machine.lit");
@ -276,7 +278,7 @@ function initForeignServers() {
OmniaCybersystemsServer.setPortProperties(5);
AddToAllServers(OmniaCybersystemsServer);
var ZBDefenseServer = new Server(createRandomIp(), "zb-def", "ZB Defense Industries", false, false, false, 0);
var ZBDefenseServer = new Server(createRandomIp(), "zb-def", "ZB Defense Industries", false, false, false, 2);
ZBDefenseServer.setHackingParameters(getRandomInt(775, 825), getRandomInt(900000000, 1100000000), getRandomInt(55, 65), getRandomInt(65, 75));
ZBDefenseServer.setPortProperties(4);
ZBDefenseServer.messages.push("synthetic-muscles.lit");
@ -287,7 +289,7 @@ function initForeignServers() {
AppliedEnergeticsServer.setPortProperties(4);
AddToAllServers(AppliedEnergeticsServer);
var SolarisSpaceSystemsServer = new Server(createRandomIp(), "solaris", "Solaris Space Systems", false, false, false, 0);
var SolarisSpaceSystemsServer = new Server(createRandomIp(), "solaris", "Solaris Space Systems", false, false, false, 2);
SolarisSpaceSystemsServer.setHackingParameters(getRandomInt(750, 850), getRandomInt(700000000, 900000000), getRandomInt(70, 80), getRandomInt(70, 80));
SolarisSpaceSystemsServer.setPortProperties(5);
SolarisSpaceSystemsServer.messages.push("A-Green-Tomorrow.lit");
@ -332,7 +334,7 @@ function initForeignServers() {
RhoConstructionServer.setPortProperties(3);
AddToAllServers(RhoConstructionServer);
var AlphaEnterprisesServer = new Server(createRandomIp(), "alpha-ent", "Alpha Enterprises", false, false, false, 0);
var AlphaEnterprisesServer = new Server(createRandomIp(), "alpha-ent", "Alpha Enterprises", false, false, false, 2);
AlphaEnterprisesServer.setHackingParameters(getRandomInt(500, 600), getRandomInt(600000000, 750000000), getRandomInt(50, 70), getRandomInt(50, 60));
AlphaEnterprisesServer.setPortProperties(4);
AlphaEnterprisesServer.messages.push("sector-12-crime.lit");
@ -369,7 +371,7 @@ function initForeignServers() {
SysCoreSecuritiesServer.setPortProperties(4);
AddToAllServers(SysCoreSecuritiesServer);
var CatalystVenturesServer = new Server(createRandomIp(), "catalyst", "Catalyst Ventures", false, false, false, 0);
var CatalystVenturesServer = new Server(createRandomIp(), "catalyst", "Catalyst Ventures", false, false, false, 2);
CatalystVenturesServer.setHackingParameters(getRandomInt(400, 450), getRandomInt(300000000, 550000000), getRandomInt(60, 70), getRandomInt(25, 55));
CatalystVenturesServer.setPortProperties(3);
CatalystVenturesServer.messages.push("tensions-in-tech-race.lit");
@ -386,7 +388,7 @@ function initForeignServers() {
CompuTekServer.messages.push("man-and-machine.lit");
AddToAllServers(CompuTekServer);
var NetLinkTechnologiesServer = new Server(createRandomIp(), "netlink", "NetLink Technologies", false, false, false, 0);
var NetLinkTechnologiesServer = new Server(createRandomIp(), "netlink", "NetLink Technologies", false, false, false, 2);
NetLinkTechnologiesServer.setHackingParameters(getRandomInt(375, 425), 275000000, getRandomInt(60, 80), getRandomInt(45, 75));
NetLinkTechnologiesServer.setPortProperties(3);
NetLinkTechnologiesServer.messages.push("simulated-reality.lit");
@ -414,7 +416,7 @@ function initForeignServers() {
JoesGunsServer.setPortProperties(0);
AddToAllServers(JoesGunsServer);
var Zer0NightclubServer = new Server(createRandomIp(), "zer0", "ZER0 Nightclub", false, false, false, 4);
var Zer0NightclubServer = new Server(createRandomIp(), "zer0", "ZER0 Nightclub", false, false, false, 16);
Zer0NightclubServer.setHackingParameters(75, 7500000, 25, 40);
Zer0NightclubServer.setPortProperties(1);
AddToAllServers(Zer0NightclubServer);
@ -424,13 +426,13 @@ function initForeignServers() {
NectarNightclubServer.setPortProperties(0);
AddToAllServers(NectarNightclubServer);
var NeoNightclubServer = new Server(createRandomIp(), "neo-net", "Neo Nightclub Network", false, false, false, 4);
var NeoNightclubServer = new Server(createRandomIp(), "neo-net", "Neo Nightclub Network", false, false, false, 16);
NeoNightclubServer.setHackingParameters(50, 5000000, 25, 25);
NeoNightclubServer.setPortProperties(1);
NeoNightclubServer.messages.push("the-hidden-world.lit");
AddToAllServers(NeoNightclubServer);
var SilverHelixServer = new Server(createRandomIp(), "silver-helix", "Silver Helix", false, false, false, 2);
var SilverHelixServer = new Server(createRandomIp(), "silver-helix", "Silver Helix", false, false, false, 32);
SilverHelixServer.setHackingParameters(150, 45000000, 30, 30);
SilverHelixServer.setPortProperties(2);
SilverHelixServer.messages.push("new-triads.lit");
@ -447,17 +449,17 @@ function initForeignServers() {
HaraKiriSushiBarServer.setPortProperties(0);
AddToAllServers(HaraKiriSushiBarServer);
var PhantasyServer = new Server(createRandomIp(), "phantasy", "Phantasy Club", false, false, false, 0);
var PhantasyServer = new Server(createRandomIp(), "phantasy", "Phantasy Club", false, false, false, 16);
PhantasyServer.setHackingParameters(100, 24000000, 20, 35);
PhantasyServer.setPortProperties(2);
AddToAllServers(PhantasyServer);
var MaxHardwareServer = new Server(createRandomIp(), "max-hardware", "Max Hardware Store", false, false, false, 4);
var MaxHardwareServer = new Server(createRandomIp(), "max-hardware", "Max Hardware Store", false, false, false, 16);
MaxHardwareServer.setHackingParameters(80, 10000000, 15, 30);
MaxHardwareServer.setPortProperties(1);
AddToAllServers(MaxHardwareServer);
var OmegaSoftwareServer = new Server(createRandomIp(), "omega-net", "Omega Software", false, false, false, 8);
var OmegaSoftwareServer = new Server(createRandomIp(), "omega-net", "Omega Software", false, false, false, 16);
OmegaSoftwareServer.setHackingParameters(getRandomInt(180, 220), getRandomInt(60000000, 70000000), getRandomInt(25, 35), getRandomInt(30, 40));
OmegaSoftwareServer.setPortProperties(2);
OmegaSoftwareServer.messages.push("the-new-god.lit");
@ -469,7 +471,7 @@ function initForeignServers() {
CrushFitnessGymServer.setPortProperties(2);
AddToAllServers(CrushFitnessGymServer);
var IronGymServer = new Server(createRandomIp(), "iron-gym", "Iron Gym Network", false, false, false, 4);
var IronGymServer = new Server(createRandomIp(), "iron-gym", "Iron Gym Network", false, false, false, 16);
IronGymServer.setHackingParameters(100, 20000000, 30, 20);
IronGymServer.setPortProperties(1);
AddToAllServers(IronGymServer);
@ -490,7 +492,7 @@ function initForeignServers() {
AddToAllServers(SnapFitnessGymServer);
//Faction servers, cannot hack money from these
var BitRunnersServer = new Server(createRandomIp(), "run4theh111z", "The Runners", false, false, false, 0);
var BitRunnersServer = new Server(createRandomIp(), "run4theh111z", "The Runners", false, false, false, 2);
BitRunnersServer.setHackingParameters(getRandomInt(505, 550), 0, 0, 0);
BitRunnersServer.setPortProperties(4);
BitRunnersServer.messages.push("simulated-reality.lit");
@ -498,14 +500,14 @@ function initForeignServers() {
AddToAllServers(BitRunnersServer);
SpecialServerIps.addIp(SpecialServerNames.BitRunnersServer, BitRunnersServer.ip);
var TheBlackHandServer = new Server(createRandomIp(), "I.I.I.I", "I.I.I.I", false, false, false, 0);
var TheBlackHandServer = new Server(createRandomIp(), "I.I.I.I", "I.I.I.I", false, false, false, 2);
TheBlackHandServer.setHackingParameters(getRandomInt(340, 365), 0, 0, 0);
TheBlackHandServer.setPortProperties(3);
TheBlackHandServer.messages.push("democracy-is-dead.lit");
AddToAllServers(TheBlackHandServer);
SpecialServerIps.addIp(SpecialServerNames.TheBlackHandServer, TheBlackHandServer.ip);
var NiteSecServer = new Server(createRandomIp(), "avmnite-02h", "NiteSec", false, false, false, 0);
var NiteSecServer = new Server(createRandomIp(), "avmnite-02h", "NiteSec", false, false, false, 2);
NiteSecServer.setHackingParameters(getRandomInt(202, 220), 0, 0, 0);
NiteSecServer.setPortProperties(2);
NiteSecServer.messages.push("democracy-is-dead.lit");
@ -518,14 +520,14 @@ function initForeignServers() {
AddToAllServers(DarkArmyServer);
SpecialServerIps.addIp(SpecialServerNames.TheDarkArmyServer, DarkArmyServer.ip);
var CyberSecServer = new Server(createRandomIp(), "CSEC", "CyberSec", false, false, false, 0);
var CyberSecServer = new Server(createRandomIp(), "CSEC", "CyberSec", false, false, false, 2);
CyberSecServer.setHackingParameters(getRandomInt(51, 60), 0, 0, 0);
CyberSecServer.setPortProperties(1);
CyberSecServer.messages.push("democracy-is-dead.lit");
AddToAllServers(CyberSecServer);
SpecialServerIps.addIp(SpecialServerNames.CyberSecServer, CyberSecServer.ip);
var DaedalusServer = new Server(createRandomIp(), "The-Cave", "Helios", false, false, false, 0);
var DaedalusServer = new Server(createRandomIp(), "The-Cave", "Helios", false, false, false, 2);
DaedalusServer.setHackingParameters(925, 0, 0, 0);
DaedalusServer.setPortProperties(5);
DaedalusServer.messages.push("alpha-omega.lit");
@ -669,13 +671,14 @@ function processSingleServerGrowth(server, numCycles) {
serverGrowth = 1;
}
var oldMoneyAvailable = server.moneyAvailable;
server.moneyAvailable *= serverGrowth;
if (server.moneyMax && isNaN(server.moneyAvailable)) {
server.moneyAvailable = server.moneyMax;
}
if (server.moneyMax && server.moneyAvailable > server.moneyMax) {
server.moneyAvailable = server.moneyMax;
return 1;
return server.moneyAvailable / oldMoneyAvailable;
}
//Growing increases server security twice as much as hacking

@ -1,9 +1,11 @@
import {CONSTANTS} from "./Constants.js";
import {Player} from "./Player.js";
import {AllServers} from "./Server.js";
import {Server, AllServers, AddToAllServers} from "./Server.js";
import {dialogBoxCreate} from "../utils/DialogBox.js";
import {createRandomIp} from "../utils/IPAddress.js";
import {yesNoTxtInpBoxGetInput} from "../utils/YesNoBox.js";
/* Functions to handle any server-related purchasing:
* Purchasing new servers
* Purchasing more RAM for home computer

@ -1,6 +1,6 @@
/* Settings.js */
let Settings = {
CodeInstructionRunTime: 100,
CodeInstructionRunTime: 50,
MaxLogCapacity: 50,
MaxPortCapacity: 50,
SuppressMessages: false,
@ -12,7 +12,7 @@ function loadSettings(saveString) {
}
function initSettings() {
Settings.CodeInstructionRunTime = 100;
Settings.CodeInstructionRunTime = 50;
Settings.MaxLogCapacity = 50;
Settings.MaxPortCapacity = 50;
Settings.SuppressMessages = false;

@ -13,6 +13,9 @@ import {iTutorialNextStep, iTutorialSteps,
currITutorialStep} from "./InteractiveTutorial.js";
import {showLiterature} from "./Literature.js";
import {showMessage, Message} from "./Message.js";
import {scriptCalculateHackingTime,
scriptCalculateGrowTime,
scriptCalculateWeakenTime} from "./NetscriptEvaluator.js";
import {killWorkerScript, addWorkerScript} from "./NetscriptWorker.js";
import {Player} from "./Player.js";
import {hackWorldDaemon} from "./RedPill.js";
@ -24,18 +27,18 @@ import {SpecialServerIps,
SpecialServerNames} from "./SpecialServerIps.js";
import {containsAllStrings, longestCommonStart,
formatNumber} from "../utils/StringHelperFunctions.js";
formatNumber, isString} from "../utils/StringHelperFunctions.js";
import {addOffset, printArray} from "../utils/HelperFunctions.js";
import {logBoxCreate} from "../utils/LogBox.js";
/* Write text to terminal */
//If replace is true then spaces are replaced with "&nbsp;"
function post(input, replace=true) {
if (replace) {
$("#terminal-input").before('<tr class="posted"><td class="terminal-line" style="color: var(--my-font-color); background-color: var(--my-background-color);">' + input.replace( / /g, "&nbsp;" ) + '</td></tr>');
} else {
$("#terminal-input").before('<tr class="posted"><td class="terminal-line" style="color: var(--my-font-color); background-color: var(--my-background-color);">' + input + '</td></tr>');
}
updateTerminalScroll();
}
@ -72,10 +75,10 @@ $(document).keydown(function(event) {
event.preventDefault(); //Prevent newline from being entered in Script Editor
var command = $('input[class=terminal-input]').val();
if (command.length > 0) {
post("> " + command);
post("[" + Player.getCurrentServer().hostname + " ~]> " + command);
Terminal.resetTerminalInput(); //Clear input first
Terminal.executeCommand(command);
$('input[class=terminal-input]').val("");
}
}
@ -211,13 +214,13 @@ function tabCompletion(command, arg, allPossibilities, index=0) {
//that we are attempting to autocomplete
if (arg == "") {
for (var i = allPossibilities.length-1; i >= 0; --i) {
if (!allPossibilities[i].startsWith(command)) {
if (!allPossibilities[i].toLowerCase().startsWith(command.toLowerCase())) {
allPossibilities.splice(i, 1);
}
}
} else {
for (var i = allPossibilities.length-1; i >= 0; --i) {
if (!allPossibilities[i].startsWith(arg)) {
if (!allPossibilities[i].toLowerCase().startsWith(arg.toLowerCase())) {
allPossibilities.splice(i, 1);
}
}
@ -337,7 +340,7 @@ function determineAllPossibilitiesForTabCompletion(input, index=0) {
}
if (input.startsWith("kill ") || input.startsWith("nano ") ||
input.startsWith("tail ") || input.startsWith("rm ") ||
input.startsWith("tail ") ||
input.startsWith("mem ") || input.startsWith("check ")) {
//All Scripts
for (var i = 0; i < currServ.scripts.length; ++i) {
@ -346,6 +349,22 @@ function determineAllPossibilitiesForTabCompletion(input, index=0) {
return allPos;
}
if (input.startsWith("rm ")) {
for (var i = 0; i < currServ.scripts.length; ++i) {
allPos.push(currServ.scripts[i].filename);
}
for (var i = 0; i < currServ.programs.length; ++i) {
allPos.push(currServ.programs[i]);
}
for (var i = 0; i < currServ.messages.length; ++i) {
if (!(currServ.messages[i] instanceof Message) && isString(currServ.messages[i]) &&
currServ.messages[i].endsWith(".lit")) {
allPos.push(currServ.messages[i]);
}
}
return allPos;
}
if (input.startsWith("run ")) {
//All programs and scripts
for (var i = 0; i < currServ.scripts.length; ++i) {
@ -390,6 +409,17 @@ let Terminal = {
}
},
resetTerminalInput: function() {
document.getElementById("terminal-input-td").innerHTML =
"<div id='terminal-input-header'>[" + Player.getCurrentServer().hostname + " ~]" + "$ </div>" +
'<input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1"/>';
var hdr = document.getElementById("terminal-input-header");
hdr.style.display = "inline";
var lineWidth = document.getElementById("terminal-input-td").offsetWidth;
var width = lineWidth - hdr.offsetWidth - 10;
document.getElementById("terminal-input-text-box").style.width = width + "px";
},
//Complete the hack/analyze command
finishHack: function(cancelled = false) {
if (cancelled == false) {
@ -414,13 +444,12 @@ let Terminal = {
var moneyGained = Player.calculatePercentMoneyHacked();
moneyGained = Math.floor(server.moneyAvailable * moneyGained);
//Safety check
if (moneyGained <= 0) {moneyGained = 0;}
if (moneyGained <= 0) {moneyGained = 0;} //Safety check
server.moneyAvailable -= moneyGained;
Player.gainMoney(moneyGained);
Player.gainHackingExp(expGainedOnSuccess)
Player.gainIntelligenceExp(expGainedOnSuccess / CONSTANTS.IntelligenceTerminalHackBaseExpGain);
server.fortify(CONSTANTS.ServerFortifyAmount);
@ -435,7 +464,8 @@ let Terminal = {
//Rename the progress bar so that the next hacks dont trigger it. Re-enable terminal
$("#hack-progress-bar").attr('id', "old-hack-progress-bar");
$("#hack-progress").attr('id', "old-hack-progress");
document.getElementById("terminal-input-td").innerHTML = '$ <input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1"/>';
Terminal.resetTerminalInput();
//document.getElementById("terminal-input-td").innerHTML = '$ <input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1"/>';
$('input[class=terminal-input]').prop('disabled', false);
Terminal.hackFlag = false;
@ -490,7 +520,8 @@ let Terminal = {
//Rename the progress bar so that the next hacks dont trigger it. Re-enable terminal
$("#hack-progress-bar").attr('id', "old-hack-progress-bar");
$("#hack-progress").attr('id', "old-hack-progress");
document.getElementById("terminal-input-td").innerHTML = '$ <input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1"/>';
Terminal.resetTerminalInput();
//document.getElementById("terminal-input-td").innerHTML = '$ <input type="text" id="terminal-input-text-box" class="terminal-input" tabindex="1"/>';
$('input[class=terminal-input]').prop('disabled', false);
},
@ -587,6 +618,7 @@ let Terminal = {
Player.analyze();
//Disable terminal
//Terminal.resetTerminalInput();
document.getElementById("terminal-input-td").innerHTML = '<input type="text" class="terminal-input"/>';
$('input[class=terminal-input]').prop('disabled', true);
iTutorialNextStep();
@ -610,6 +642,7 @@ let Terminal = {
Player.hack();
//Disable terminal
//Terminal.resetTerminalInput();
document.getElementById("terminal-input-td").innerHTML = '<input type="text" class="terminal-input"/>';
$('input[class=terminal-input]').prop('disabled', true);
iTutorialNextStep();
@ -690,6 +723,7 @@ let Terminal = {
Player.analyze();
//Disable terminal
//Terminal.resetTerminalInput();
document.getElementById("terminal-input-td").innerHTML = '<input type="text" class="terminal-input"/>';
$('input[class=terminal-input]').prop('disabled', true);
break;
@ -793,6 +827,7 @@ let Terminal = {
Player.hack();
//Disable terminal
//Terminal.resetTerminalInput();
document.getElementById("terminal-input-td").innerHTML = '<input type="text" class="terminal-input"/>';
$('input[class=terminal-input]').prop('disabled', true);
}
@ -821,6 +856,7 @@ let Terminal = {
Player.currentServer = Player.getHomeComputer().ip;
Player.getCurrentServer().isConnectedTo = true;
post("Connected to home");
Terminal.resetTerminalInput();
break;
case "hostname":
if (commandArray.length != 1) {
@ -961,6 +997,15 @@ let Terminal = {
}
}
//Check literature files
for (var i = 0; i < s.messages.length; ++i) {
var f = s.messages[i];
if (!(f instanceof Message) && isString(f) && f === delTarget) {
s.messages.splice(i, 1);
return;
}
}
post("No such file exists");
break;
case "run":
@ -986,7 +1031,17 @@ let Terminal = {
if (commandArray.length == 1) {
Terminal.executeScanAnalyzeCommand(1);
} else if (commandArray.length == 2) {
var depth = Number(commandArray[1]);
var all = false;
if (commandArray[1].endsWith("-a")) {
all = true;
commandArray[1] = commandArray[1].replace("-a", "");
}
var depth;
if (commandArray[1].length === 0) {
depth = 1;
} else {
depth = Number(commandArray[1]);
}
if (isNaN(depth) || depth < 0) {
post("Incorrect usage of scan-analyze command. depth argument must be positive numeric");
return;
@ -1002,7 +1057,7 @@ let Terminal = {
post("You cannot scan-analyze with that high of a depth. Maximum depth is 10");
return;
}
Terminal.executeScanAnalyzeCommand(depth);
Terminal.executeScanAnalyzeCommand(depth, all);
} else {
post("Incorrect usage of scan-analyze command. usage: scan-analyze [depth]");
}
@ -1033,7 +1088,6 @@ let Terminal = {
//Scp for lit files
if (scriptname.endsWith(".lit")) {
var found = false;
var curr
for (var i = 0; i < currServ.messages.length; ++i) {
if (!(currServ.messages[i] instanceof Message) && currServ.messages[i] == scriptname) {
found = true;
@ -1227,6 +1281,7 @@ let Terminal = {
if (Player.getCurrentServer().hostname == "darkweb") {
checkIfConnectedToDarkweb(); //Posts a 'help' message if connecting to dark web
}
Terminal.resetTerminalInput();
},
executeListCommand: function(commandArray) {
@ -1330,12 +1385,13 @@ let Terminal = {
}
},
executeScanAnalyzeCommand: function(depth=1) {
executeScanAnalyzeCommand: function(depth=1, all=false) {
//We'll use the AllServersMap as a visited() array
//TODO Using array as stack for now, can make more efficient
post("~~~~~~~~~~ Beginning scan-analyze ~~~~~~~~~~");
post(" ");
var visited = new AllServersMap();
var stack = [];
var depthQueue = [0];
var currServ = Player.getCurrentServer();
@ -1343,8 +1399,10 @@ let Terminal = {
while(stack.length != 0) {
var s = stack.pop();
var d = depthQueue.pop();
if (visited[s.ip] || d > depth) {
continue;
if (!all && s.purchasedByPlayer && s.hostname != "home") {
continue; //Purchased server
} else if (visited[s.ip] || d > depth) {
continue; //Already visited or out-of-depth
} else {
visited[s.ip] = 1;
}
@ -1375,6 +1433,7 @@ let Terminal = {
(function() {
var hostname = links[i].innerHTML.toString();
links[i].onclick = function() {
if (Terminal.analyzeFlag || Terminal.hackFlag) {return;}
Terminal.connectToServer(hostname);
}
}());//Immediate invocation

@ -1,9 +1,3 @@
var ace = require('brace');
require('brace/mode/javascript');
require('brace/theme/monokai');
require('brace/theme/terminal');
require('brace/theme/twilight');
import {dialogBoxCreate} from "../utils/DialogBox.js";
import {gameOptionsBoxOpen, gameOptionsBoxClose}from "../utils/GameOptions.js";
import {clearEventListeners} from "../utils/HelperFunctions.js";
@ -441,16 +435,30 @@ let Engine = {
displayCharacterOverviewInfo: function() {
if (Player.hp == null) {Player.hp = Player.max_hp;}
document.getElementById("character-overview-text").innerHTML =
("Hp: " + Player.hp + " / " + Player.max_hp + "<br>" +
"Money: " + numeral(Player.money.toNumber()).format('($0.000a)') + "<br>" +
"Hack: " + (Player.hacking_skill).toLocaleString() + "<br>" +
"Str: " + (Player.strength).toLocaleString() + "<br>" +
"Def: " + (Player.defense).toLocaleString() + "<br>" +
"Dex: " + (Player.dexterity).toLocaleString() + "<br>" +
"Agi: " + (Player.agility).toLocaleString() + "<br>" +
"Cha: " + (Player.charisma).toLocaleString()
).replace( / /g, "&nbsp;" );
if (Player.intelligence >= 1) {
document.getElementById("character-overview-text").innerHTML =
("Hp: " + Player.hp + " / " + Player.max_hp + "<br>" +
"Money: " + numeral(Player.money.toNumber()).format('($0.000a)') + "<br>" +
"Hack: " + (Player.hacking_skill).toLocaleString() + "<br>" +
"Str: " + (Player.strength).toLocaleString() + "<br>" +
"Def: " + (Player.defense).toLocaleString() + "<br>" +
"Dex: " + (Player.dexterity).toLocaleString() + "<br>" +
"Agi: " + (Player.agility).toLocaleString() + "<br>" +
"Cha: " + (Player.charisma).toLocaleString() + "<br>" +
"Int: " + (Player.intelligence).toLocaleString()
).replace( / /g, "&nbsp;" );
} else {
document.getElementById("character-overview-text").innerHTML =
("Hp: " + Player.hp + " / " + Player.max_hp + "<br>" +
"Money: " + numeral(Player.money.toNumber()).format('($0.000a)') + "<br>" +
"Hack: " + (Player.hacking_skill).toLocaleString() + "<br>" +
"Str: " + (Player.strength).toLocaleString() + "<br>" +
"Def: " + (Player.defense).toLocaleString() + "<br>" +
"Dex: " + (Player.dexterity).toLocaleString() + "<br>" +
"Agi: " + (Player.agility).toLocaleString() + "<br>" +
"Cha: " + (Player.charisma).toLocaleString()
).replace( / /g, "&nbsp;" );
}
},
/* Display character info */
@ -915,7 +923,13 @@ let Engine = {
if (Engine.Counters.checkFactionInvitations <= 0) {
var invitedFactions = Player.checkForFactionInvitations();
if (invitedFactions.length > 0) {
Player.firstFacInvRecvd = true;
if (Player.firstFacInvRecvd === false) {
Player.firstFacInvRecvd = true;
document.getElementById("factions-tab").style.display = "list-item";
document.getElementById("character-menu-header").click();
document.getElementById("character-menu-header").click();
}
var randFaction = invitedFactions[Math.floor(Math.random() * invitedFactions.length)];
inviteToFaction(randFaction);
}
@ -930,7 +944,11 @@ let Engine = {
if (Engine.Counters.messages <= 0) {
checkForMessagesToSend();
Engine.Counters.messages = 150;
if (Augmentations[AugmentationNames.TheRedPill].owned) {
Engine.Counters.messages = 600; //2 minutes for Red pill message
} else {
Engine.Counters.messages = 150;
}
}
if (Engine.Counters.stockTick <= 0) {
@ -1018,14 +1036,54 @@ let Engine = {
document.getElementById("entire-game-container").style.visibility = "visible";
},
load: function() {
//Load script editor
var editor = ace.edit('javascript-editor');
editor.getSession().setMode('ace/mode/javascript');
editor.setTheme('ace/theme/monokai');
document.getElementById('javascript-editor').style.fontSize='16px';
editor.setOption("showPrintMargin", false);
//Used when initializing a game
//elems should be an array of all DOM elements under the header
closeMainMenuHeader: function(elems) {
for (var i = 0; i < elems.length; ++i) {
elems[i].style.maxHeight = null;
elems[i].style.opacity = 0;
elems[i].style.pointerEvents = "none";
}
},
//Used when initializing the game
//elems should be an array of all DOM elements under the header
openMainMenuHeader: function(elems) {
for (var i = 0; i < elems.length; ++i) {
elems[i].style.maxHeight = elems[i].scrollHeight + "px";
elems[i].style.display = "block";
}
},
//Used in game when clicking on a main menu header (NOT FOR INITIALIZATION)
//open is a boolean specifying whether its being opened or closed
//elems is an array of DOM elements for main menu tabs (li)
//links is an array of DOM elements for main menu links (a)
toggleMainMenuHeader: function(open, elems, links) {
for (var i = 0; i < elems.length; ++i) {
if (open) {
elems[i].style.opacity = 1;
elems[i].style.maxHeight = elems[i].scrollHeight + "px";
} else {
elems[i].style.opacity = 0;
elems[i].style.maxHeight = null;
}
}
for (var i = 0; i < links.length; ++i) {
if (open) {
links[i].style.opacity = 1;
links[i].style.maxHeight = links[i].scrollHeight + "px";
links[i].style.pointerEvents = "auto";
} else {
links[i].style.opacity = 0;
links[i].style.maxHeight = null;
links[i].style.pointerEvents = "none";
}
}
},
load: function() {
//Initialize main menu accordion panels to all start as "open"
var terminal = document.getElementById("terminal-tab");
var createScript = document.getElementById("create-script-tab");
@ -1090,7 +1148,7 @@ let Engine = {
processPassiveFactionRepGain(numCyclesOffline);
//Gang progress for BitNode 2
if (Player.bitNodeN != null && Player.bitNodeN == 2 && Player.inGang()) {
if (Player.bitNodeN != null && Player.bitNodeN === 2 && Player.inGang()) {
Player.gang.process(numCyclesOffline);
}
@ -1108,45 +1166,20 @@ let Engine = {
formatNumber(offlineProductionFromScripts, 2) + " and your Hacknet Nodes generated $" +
formatNumber(offlineProductionFromHacknetNodes, 2));
//Close main menu accordions for loaded game
terminal.style.maxHeight = null;
terminal.style.opacity = 0;
terminal.style.pointerEvents = "none";
createScript.style.maxHeight = null;
createScript.style.opacity = 0;
createScript.style.pointerEvents = "none";
activeScripts.style.maxHeight = null;
activeScripts.style.opacity = 0;
activeScripts.style.pointerEvents = "none";
createProgram.style.maxHeight = null;
createProgram.style.opacity = 0;
createProgram.style.pointerEvents = "none";
stats.style.maxHeight = null;
stats.style.opacity = 0;
stats.style.pointerEvents = "none";
factions.style.maxHeight = null;
factions.style.opacity = 0;
factions.style.pointerEvents = "none";
augmentations.style.maxHeight = null;
augmentations.style.opacity = 0;
augmentations.style.pointerEvents = "none";
hacknetnodes.style.maxHeight = null;
hacknetnodes.style.opacity = 0;
hacknetnodes.style.pointerEvents = "none";
city.style.maxHeight = null;
city.style.opacity = 0;
city.style.pointerEvents = "none";
travel.style.maxHeight = null;
travel.style.opacity = 0;
travel.style.pointerEvents = "none";
job.style.maxHeight = null;
job.style.opacity = 0;
job.style.pointerEvents = "none";
tutorial.style.maxHeight = null;
tutorial.style.opacity = 0;
tutorial.style.pointerEvents = "none";
options.style.maxHeight = null;
options.style.opacity = 0;
options.style.pointerEvents = "none";
var visibleMenuTabs = [terminal, createScript, activeScripts, stats,
hacknetnodes, city, tutorial, options];
if (Player.firstFacInvRecvd) {visibleMenuTabs.push(factions);}
else {factions.style.display = "none";}
if (Player.firstAugPurchased) {visibleMenuTabs.push(augmentations);}
else {augmentations.style.display = "none";}
if (Player.firstJobRecvd) {visibleMenuTabs.push(job);}
else {job.style.display = "none";}
if (Player.firstTimeTraveled) {visibleMenuTabs.push(travel);}
else {travel.style.display = "none";}
if (Player.firstProgramAvailable) {visibleMenuTabs.push(createProgram);}
else {createProgram.style.display = "none";}
Engine.closeMainMenuHeader(visibleMenuTabs);
} else {
//No save found, start new game
console.log("Initializing new game");
@ -1177,32 +1210,19 @@ let Engine = {
worldHdr.classList.toggle("opened");
var helpHdr = document.getElementById("help-menu-header");
helpHdr.classList.toggle("opened");
terminal.style.maxHeight = terminal.scrollHeight + "px";
terminal.style.display = "block";
createScript.style.maxHeight = createScript.scrollHeight + "px";
createScript.style.display = "block";
activeScripts.style.maxHeight = activeScripts.scrollHeight + "px";
activeScripts.style.display = "block";
createProgram.style.maxHeight = createProgram.scrollHeight + "px";
createProgram.style.display = "block";
stats.style.maxHeight = stats.scrollHeight + "px";
stats.style.display = "block";
factions.style.maxHeight = factions.scrollHeight + "px";
factions.style.display = "block";
augmentations.style.maxHeight = augmentations.scrollHeight + "px";
augmentations.style.display = "block";
hacknetnodes.style.maxHeight = hacknetnodes.scrollHeight + "px";
hacknetnodes.style.display = "block";
city.style.maxHeight = city.scrollHeight + "px";
city.style.display = "block";
travel.style.maxHeight = travel.scrollHeight + "px";
travel.style.display = "block";
job.style.maxHeight = job.scrollHeight + "px";
job.style.display = "block";
tutorial.style.maxHeight = tutorial.scrollHeight + "px";
tutorial.style.display = "block";
options.style.maxHeight = options.scrollHeight + "px";
options.style.display = "block";
//Hide tabs that wont be revealed until later
factions.style.display = "none";
augmentations.style.display = "none";
job.style.display = "none";
travel.style.display = "none";
createProgram.style.display = "none";
Engine.openMainMenuHeader(
[terminal, createScript, activeScripts, stats,
hacknetnodes, city,
tutorial, options]
);
//Start interactive tutorial
iTutorialStart();
@ -1210,6 +1230,7 @@ let Engine = {
}
//Initialize labels on game settings
setSettingsLabels();
Terminal.resetTerminalInput();
},
setDisplayElements: function() {
@ -1350,13 +1371,9 @@ let Engine = {
//Main menu accordions
var hackingHdr = document.getElementById("hacking-menu-header");
//hackingHdr.classList.toggle("opened");
var characterHdr = document.getElementById("character-menu-header");
//characterHdr.classList.toggle("opened");
var worldHdr = document.getElementById("world-menu-header");
//worldHdr.classList.toggle("opened");
var helpHdr = document.getElementById("help-menu-header");
//helpHdr.classList.toggle("opened");
hackingHdr.onclick = function() {
var terminal = document.getElementById("terminal-tab");
@ -1370,55 +1387,18 @@ let Engine = {
var createProgramNot = document.getElementById("create-program-notification");
this.classList.toggle("opened");
if (terminal.style.maxHeight) {
terminal.style.opacity = 0;
terminal.style.maxHeight = null;
terminalLink.style.opacity = 0;
terminalLink.style.maxHeight = null;
terminalLink.style.pointerEvents = "none";
createScript.style.opacity = 0;
createScript.style.maxHeight = null;
createScriptLink.style.opacity = 0;
createScriptLink.style.maxHeight = null;
createScriptLink.style.pointerEvents = "none";
activeScripts.style.opacity = 0;
activeScripts.style.maxHeight = null;
activeScriptsLink.style.opacity = 0;
activeScriptsLink.style.maxHeight = null;
activeScriptsLink.style.pointerEvents = "none";
createProgram.style.opacity = 0;
createProgram.style.maxHeight = null;
createProgramLink.style.opacity = 0;
createProgramLink.style.maxHeight = null;
createProgramLink.style.pointerEvents = "none";
Engine.toggleMainMenuHeader(false,
[terminal, createScript, activeScripts, createProgram],
[terminalLink, createScriptLink, activeScriptsLink, createProgramLink]
);
createProgramNot.style.display = "none";
} else {
terminal.style.maxHeight = terminal.scrollHeight + "px";
terminal.style.opacity = 1;
terminalLink.style.maxHeight = terminalLink.scrollHeight + "px";
terminalLink.style.opacity = 1;
terminalLink.style.pointerEvents = "auto";
Engine.toggleMainMenuHeader(true,
[terminal, createScript, activeScripts, createProgram],
[terminalLink, createScriptLink, activeScriptsLink, createProgramLink]
);
createScript.style.maxHeight = createScript.scrollHeight + "px";
createScript.style.opacity = 1;
createScriptLink.style.maxHeight = createScriptLink.scrollHeight + "px";
createScriptLink.style.opacity = 1;
createScriptLink.style.pointerEvents = "auto";
activeScripts.style.maxHeight = activeScripts.scrollHeight + "px";
activeScripts.style.opacity = 1;
activeScriptsLink.style.maxHeight = activeScriptsLink.scrollHeight + "px";
activeScriptsLink.style.opacity = 1;
activeScriptsLink.style.pointerEvents = "auto";
createProgram.style.maxHeight = createProgram.scrollHeight + "px";
createProgram.style.opacity = 1;
createProgramLink.style.maxHeight = createProgramLink.scrollHeight + "px";
createProgramLink.style.opacity = 1;
createProgramLink.style.pointerEvents = "auto";
createProgramNot.style.display = "block"
}
}
@ -1434,53 +1414,15 @@ let Engine = {
var hacknetnodesLink = document.getElementById("hacknet-nodes-menu-link");
this.classList.toggle("opened");
if (stats.style.maxHeight) {
stats.style.opacity = 0;
stats.style.maxHeight = null;
statsLink.style.opacity = 0;
statsLink.style.maxHeight = null;
statsLink.style.pointerEvents = "none";
factions.style.opacity = 0;
factions.style.maxHeight = null;
factionsLink.style.opacity = 0;
factionsLink.style.maxHeight = null;
factionsLink.style.pointerEvents = "none";
augmentations.style.opacity = 0;
augmentations.style.maxHeight = null;
augmentationsLink.style.opacity = 0;
augmentationsLink.style.maxHeight = null;
augmentationsLink.style.pointerEvents = "none";
hacknetnodes.style.opacity = 0;
hacknetnodes.style.maxHeight = null;
hacknetnodesLink.style.opacity = 0;
hacknetnodesLink.style.maxHeight = null;
hacknetnodesLink.style.pointerEvents = "none";
Engine.toggleMainMenuHeader(false,
[stats, factions, augmentations, hacknetnodes],
[statsLink, factionsLink, augmentationsLink, hacknetnodesLink]
);
} else {
stats.style.maxHeight = stats.scrollHeight + "px";
stats.style.opacity = 1;
statsLink.style.maxHeight = statsLink.scrollHeight + "px";
statsLink.style.opacity = 1;
statsLink.style.pointerEvents = "auto";
factions.style.maxHeight = factions.scrollHeight + "px";
factions.style.opacity = 1;
factionsLink.style.maxHeight = factionsLink.scrollHeight + "px";
factionsLink.style.opacity = 1;
factionsLink.style.pointerEvents = "auto";
augmentations.style.maxHeight = augmentations.scrollHeight + "px";
augmentations.style.opacity = 1;
augmentationsLink.style.maxHeight = augmentationsLink.scrollHeight + "px";
augmentationsLink.style.opacity = 1;
augmentationsLink.style.pointerEvents = "auto";
hacknetnodes.style.maxHeight = hacknetnodes.scrollHeight + "px";
hacknetnodes.style.opacity = 1;
hacknetnodesLink.style.maxHeight = hacknetnodesLink.scrollHeight + "px";
hacknetnodesLink.style.opacity = 1;
hacknetnodesLink.style.pointerEvents = "auto";
Engine.toggleMainMenuHeader(true,
[stats, factions, augmentations, hacknetnodes],
[statsLink, factionsLink, augmentationsLink, hacknetnodesLink]
);
}
}
@ -1493,41 +1435,15 @@ let Engine = {
var jobLink = document.getElementById("job-menu-link");
this.classList.toggle("opened");
if (city.style.maxHeight) {
city.style.opacity = 0;
city.style.maxHeight = null;
cityLink.style.opacity = 0;
cityLink.style.maxHeight = null;
cityLink.style.pointerEvents = "none";
travel.style.opacity = 0;
travel.style.maxHeight = null;
travelLink.style.opacity = 0;
travelLink.style.maxHeight = null;
travelLink.style.pointerEvents = "none";
job.style.opacity = 0;
job.style.maxHeight = null;
jobLink.style.opacity = 0;
jobLink.style.maxHeight = null;
jobLink.style.pointerEvents = "none";
Engine.toggleMainMenuHeader(false,
[city, travel, job],
[cityLink, travelLink, jobLink]
);
} else {
city.style.maxHeight = city.scrollHeight + "px";
city.style.opacity = 1;
cityLink.style.maxHeight = cityLink.scrollHeight + "px";
cityLink.style.opacity = 1;
cityLink.style.pointerEvents = "auto";
travel.style.maxHeight = travel.scrollHeight + "px";
travel.style.opacity = 1;
travelLink.style.maxHeight = travelLink.scrollHeight + "px";
travelLink.style.opacity = 1;
travelLink.style.pointerEvents = "auto";
job.style.maxHeight = job.scrollHeight + "px";
job.style.opacity = 1;
jobLink.style.maxHeight = jobLink.scrollHeight + "px";
jobLink.style.opacity = 1;
jobLink.style.pointerEvents = "auto";
Engine.toggleMainMenuHeader(true,
[city, travel, job],
[cityLink, travelLink, jobLink]
);
}
}
@ -1538,29 +1454,15 @@ let Engine = {
var optionsLink = document.getElementById("options-menu-link");
this.classList.toggle("opened");
if (tutorial.style.maxHeight) {
tutorial.style.opacity = 0;
tutorial.style.maxHeight = null;
tutorialLink.style.opacity = 0;
tutorialLink.style.maxHeight = null;
tutorialLink.style.pointerEvents = "none";
options.style.opacity = 0;
options.style.maxHeight = null;
optionsLink.style.opacity = 0;
optionsLink.style.maxHeight = null;
optionsLink.style.pointerEvents = "none";
Engine.toggleMainMenuHeader(false,
[tutorial, options],
[tutorialLink, optionsLink]
);
} else {
tutorial.style.maxHeight = tutorial.scrollHeight + "px";
tutorial.style.opacity = 1;
tutorialLink.style.maxHeight = tutorialLink.scrollHeight + "px";
tutorialLink.style.opacity = 1;
tutorialLink.style.pointerEvents = "auto";
options.style.maxHeight = options.scrollHeight + "px";
options.style.opacity = 1;
optionsLink.style.maxHeight = optionsLink.scrollHeight + "px";
optionsLink.style.opacity = 1;
optionsLink.style.pointerEvents = "auto";
Engine.toggleMainMenuHeader(true,
[tutorial, options],
[tutorialLink, optionsLink]
);
}
}

@ -61,4 +61,4 @@ function dialogBoxCreate(txt) {
}, 400);
}
export {dialogBoxCreate};
export {dialogBoxCreate, dialogBoxOpened};

@ -23,6 +23,14 @@ function infiltrationSetText(txt) {
//ram argument is in GB
function infiltrationBoxCreate(inst) {
//Gain exp
Player.gainHackingExp(inst.hackingExpGained);
Player.gainStrengthExp(inst.strExpGained);
Player.gainDefenseExp(inst.defExpGained);
Player.gainDexterityExp(inst.dexExpGained);
Player.gainAgilityExp(inst.agiExpGained);
Player.gainCharismaExp(inst.chaExpGained);
var totalValue = 0;
for (var i = 0; i < inst.secretsStolen.length; ++i) {
totalValue += inst.secretsStolen[i];
@ -39,7 +47,7 @@ function infiltrationBoxCreate(inst) {
formatNumber(inst.chaExpGained, 3) + " cha exp<br>");
return;
}
var facValue = totalValue * Player.faction_rep_mult * 1.2
var facValue = totalValue * Player.faction_rep_mult * 1.25
var moneyValue = totalValue * CONSTANTS.InfiltrationMoneyValue;
infiltrationSetText("You can sell the classified documents and secrets " +
"you stole from " + inst.companyName + " for $" +

@ -39,13 +39,15 @@ var logBoxCurrentScript = null;
function logBoxCreate(script) {
logBoxCurrentScript = script;
logBoxOpen();
document.getElementById("log-box-text-header").innerHTML =
logBoxCurrentScript.filename + " " + printArray(logBoxCurrentScript.args) + ":<br><br>";
logBoxUpdateText();
}
function logBoxUpdateText() {
var txt = document.getElementById("log-box-text");
if (logBoxCurrentScript && logBoxOpened && txt) {
txt.innerHTML = logBoxCurrentScript.filename + printArray(logBoxCurrentScript.args) + ":<br><br>";
txt.innerHTML = "";
for (var i = 0; i < logBoxCurrentScript.logs.length; ++i) {
txt.innerHTML += logBoxCurrentScript.logs[i];
txt.innerHTML += "<br>";

@ -60,7 +60,7 @@ function longestCommonStart(strings) {
var A = strings.concat().sort(),
a1= A[0], a2= A[A.length-1], L= a1.length, i= 0;
while(i<L && a1.charAt(i)=== a2.charAt(i)) i++;
while(i<L && a1.charAt(i).toLowerCase() === a2.charAt(i).toLowerCase()) i++;
return a1.substring(0, i);
}
@ -129,6 +129,16 @@ function numNetscriptOperators(string) {
return total;
}
//Checks if a string contains HTML elements
function isHTML(str) {
var a = document.createElement('div');
a.innerHTML = str;
for (var c = a.childNodes, i = c.length; i--; ) {
if (c[i].nodeType == 1) return true;
}
return false;
}
export {getIndicesOf, convertTimeMsToTimeElapsedString, longestCommonStart,
isString, isPositiveNumber, containsAllStrings, formatNumber,
numOccurrences, numNetscriptOperators};
numOccurrences, numNetscriptOperators, isHTML};