Merge pull request #150 from danielyxie/dev

All v0.30.0 Changes
This commit is contained in:
danielyxie 2017-10-10 00:08:28 -05:00 committed by GitHub
commit cc6575ddb6
16 changed files with 1490 additions and 1100 deletions

@ -37,6 +37,10 @@
font-size:12px;
margin-top: 8px;
text-align:center;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.hack-mission-player-node {

2175
dist/bundle.js vendored

File diff suppressed because one or more lines are too long

@ -424,7 +424,7 @@
<ul id="generic-locations-list">
<li id="generic-location-wse-li">
<a id="generic-location-wse" class="a-link-button">World Stock Exchange </a>
<a id="generic-location-wse" class="a-link-button">World Stock Exchange</a>
</li>
</ul>
</div>
@ -515,7 +515,7 @@
<a id="faction-hack-mission-button" class="a-link-button">Hacking Mission</a>
<p id="faction-hack-mission-text">
Attempt a hacking mission for your faction.
A mission is a mini game that, if won, earns you significant reputation with this faction.
A mission is a mini game that, if won, earns you significant reputation with this faction. (Recommended hacking level: 200+)
</p>
</div>
<div class="faction-clear"></div>
@ -606,7 +606,7 @@
Faction/Company reputation <br>
Stocks<br><br>
Installing Augmentations lets you start over with the perks and benefits granted by all
of the Augmentations you have ever installed. Also, you will keep any scripts and RAM upgrades
of the Augmentations you have ever installed. Also, you will keep any scripts and RAM/Core upgrades
on your home computer (but you will lose all programs besides NUKE.exe).
</p>
<br><br>
@ -696,7 +696,7 @@
<a id="location-purchase-1tb" class="a-link-button"> Purchase 1TB Server - $75,000,000</a>
<a id="location-purchase-tor" class="a-link-button"> Purchase TOR Router - $100,000</a>
<a id="location-purchase-home-ram" class="a-link-button"> Purchase additional RAM for Home computer </a>
<!--<a id="location-purchase-home-cores" class="a-link-button"> Purchase additional Core for Home computer </a>-->
<a id="location-purchase-home-cores" class="a-link-button"> Purchase additional Core for Home computer </a>
<!-- Infiltrate -->
<a id="location-infiltrate" class="a-link-button tooltip"> Infiltrate Company

@ -79,7 +79,7 @@ function initBitNodes() {
BitNodes["BitNode8"] = new BitNode(8, "Ghost of Wall Street", "COMING SOON"); //Trading only viable strategy
BitNodes["BitNode9"] = new BitNode(9, "MegaCorp", "COMING SOON"); //Single corp/server with increasing difficulty
BitNodes["BitNode10"] = new BitNode(10, "Wasteland", "COMING SOON"); //Postapocalyptic
BitNodes["BitNode11"] = new BitNode(11, "The Big Crash", "Okay. Sell it all.", //Crashing economy
BitNodes["BitNode11"] = new BitNode(11, "The Big Crash", "Okay. Sell it all.",
"The 2050s was defined by the massive amounts of violent civil unrest and anarchic rebellion that rose all around the world. It was this period " +
"of disorder that eventually lead to the governmental reformation of many global superpowers, most notably " +
"the USA and China. But just as the world was slowly beginning to recover from these dark times, financial catastrophe hit.<br><br>" +
@ -94,12 +94,35 @@ function initBitNodes() {
"Hacknet Node production is significantly decreased<br>" +
"Augmentations are twice as expensive<br><br>" +
"Destroying this BitNode will give you Source-File 11, or if you already have this Source-File it will " +
"upgrade its level up to a maximum of 3. This Source-File increases the player's company salary and reputation gain multipliers by:<br><br>" +
"Level 1: 60%<br>" +
"Level 2: 90%<br>" +
"Level 3: 105%");
"upgrade its level up to a maximum of 3. This Source-File makes it so that company favor increases BOTH " +
"the player's salary and reputation gain rate at that company by 1% per favor (rather than just the reputation gain). " +
"This Source-File also increases the player's company salary and reputation gain multipliers by:<br><br>" +
"Level 1: 24%<br>" +
"Level 2: 36%<br>" +
"Level 3: 42%");
//Books: Frontera, Shiner
BitNodes["BitNode12"] = new BitNode(12, "Eye of the World", "COMING SOON"); //Become AI
BitNodes["BitNode13"] = new BitNode(13, "", "COMING SOON");
BitNodes["BitNode14"] = new BitNode(14, "", "COMING SOON");
BitNodes["BitNode15"] = new BitNode(15, "", "COMING SOON");
BitNodes["BitNode16"] = new BitNode(16, "fOS", "COMING SOON"); //Unlocks the new game mode and the rest of the BitNodes
BitNodes["BitNode17"] = new BitNode(17, "", "COMING SOON");
BitNodes["BitNode18"] = new BitNode(18, "", "COMING SOON");
BitNodes["BitNode19"] = new BitNode(19, "", "COMING SOON");
BitNodes["BitNode20"] = new BitNode(20, "", "COMING SOON");
BitNodes["BitNode21"] = new BitNode(21, "", "COMING SOON");
BitNodes["BitNode22"] = new BitNode(22, "", "COMING SOON");
BitNodes["BitNode23"] = new BitNode(23, "", "COMING SOON");
BitNodes["BitNode24"] = new BitNode(24, "", "COMING SOON");
BitNodes["BitNode25"] = new BitNode(25, "", "COMING SOON");
BitNodes["BitNode26"] = new BitNode(26, "", "COMING SOON");
BitNodes["BitNode27"] = new BitNode(27, "", "COMING SOON");
BitNodes["BitNode28"] = new BitNode(28, "", "COMING SOON");
BitNodes["BitNode29"] = new BitNode(29, "", "COMING SOON");
BitNodes["BitNode30"] = new BitNode(30, "", "COMING SOON");
BitNodes["BitNode31"] = new BitNode(31, "", "COMING SOON");
BitNodes["BitNode32"] = new BitNode(32, "", "COMING SOON");
}
let BitNodeMultipliers = {
@ -172,7 +195,7 @@ function initBitNodeMultipliers() {
break;
case 11: //The Big Crash
BitNodeMultipliers.ServerMaxMoney = 0.1;
BitNodeMultipliers.ServerStartingMoney = 0.25;
BitNodeMultipliers.ServerStartingMoney = 0.1;
BitNodeMultipliers.ServerGrowthRate = 0.5;
BitNodeMultipliers.ServerWeakenRate = 2;
BitNodeMultipliers.CompanyWorkMoney = 0.5;

@ -1,5 +1,5 @@
let CONSTANTS = {
Version: "0.29.3",
Version: "0.30.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
@ -118,16 +118,17 @@ let CONSTANTS = {
IntelligenceCrimeBaseExpGain: 0.001,
IntelligenceProgramBaseExpGain: 500, //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,
IntelligenceClassBaseExpGain: 0.0000005,
IntelligenceSingFnBaseExpGain: 0.001,
IntelligenceClassBaseExpGain: 0.000001,
IntelligenceHackingMissionBaseExpGain: 0.03, //Hacking Mission difficulty multiplied by this to get exp gain
//Hacking Missions
HackingMissionRepToDiffConversion: 10000, //Faction rep is divided by this to get mission difficulty
HackingMissionRepToRewardConversion: 10, //Faction rep divided byt his to get mission rep reward
HackingMissionRepToRewardConversion: 7, //Faction rep divided byt his to get mission rep reward
HackingMissionSpamTimeIncrease: 15000, //How much time limit increase is gained when conquering a Spam Node (ms)
HackingMissionTransferAttackIncrease: 1.05, //Multiplier by which the attack for all Core Nodes is increased when conquering a Transfer Node
HackingMissionMiscDefenseIncrease: 1.12, //The amount by which every misc node's defense is multiplied when one is conquered
HackingMissionDifficultyToHacking: 120, //Difficulty is multiplied by this to determine enemy's "hacking" level (to determine effects of scan/attack, etc)
HackingMissionMiscDefenseIncrease: 1.05, //The amount by which every misc node's defense is multiplied when one is conquered
HackingMissionDifficultyToHacking: 150, //Difficulty is multiplied by this to determine enemy's "hacking" level (to determine effects of scan/attack, etc)
HackingMissionHowToPlay: "Hacking missions are a minigame that, if won, will reward you with faction reputation.<br><br>" +
"In this game you control a set of Nodes and use them to try and defeat an enemy. Your Nodes " +
"are colored blue, while the enemy's are red. There are also other nodes on the map colored gray " +
@ -168,8 +169,11 @@ let CONSTANTS = {
"the connection between one of your Nodes and its target. Alternatively, you can select the 'source' Node and click the 'Drop Connection' button, " +
"or press 'd'.<br><br>" +
"Other Notes:<br><br>" +
"-Whenever you conquer a miscellenaous Node (not owned by the enemy), the defense of all remaining miscellaneous Nodes will increase " +
"by a fixed percentage.",
"-Whenever a miscellenaous Node (not owned by the player or enemy) is conquered, the defense of all remaining miscellaneous Nodes that " +
"are not actively being targeted will increase by a fixed percentage.<br><br>" +
"-Whenever a Node is conquered, its stats are significantly reduced<br><br>" +
"-Miscellaneous Nodes slowly raise their defense over time<br><br>" +
"-Nodes slowly regenerate health and raise over time.",
//Gang constants
@ -1016,44 +1020,28 @@ let CONSTANTS = {
"Here is everything you will KEEP when you install an Augmentation: <br><br>" +
"Every Augmentation you have installed<br>" +
"Scripts on your home computer<br>" +
"RAM Upgrades on your home computer<br>" +
"RAM and CPU Core Upgrades on your home computer<br>" +
"World Stock Exchange account and TIX API Access<br>",
LatestUpdate:
"v0.30.0<br>" +
"-Added getAugmentations() and getAugmentationsFromFaction() Netscript Singularity Functions<br>" +
"-Increased the rate of Intelligence exp gain<br>" +
"-Added a new upgrade for home computers: CPU Cores. Each CPU core on the home computer " +
"grants an additional starting Core Node in Hacking Missions. I may add in other benefits later. Like RAM upgrades, upgrading " +
"the CPU Core on your home computer persists until you enter a new BitNode.<br>" +
"-Added lscpu Terminal command to check number of CPU Cores<br>" +
"-Changed the effect of Source-File 5 and made BitNode-5 a little bit harder<br>" +
"-Fixed a bug with Netscript functions (the ones you create yourself)<br>" +
"-Hacking Missions officially released (they give reputation now). Notable changes in the last few updates:<br><br>" +
"---Misc Nodes slowly gain hp/defense over time<br>" +
"---Conquering a Misc Node will increase the defense of all remaining Misc Nodes that are not being targeted by a certain percentage<br>" +
"---Reputation reward for winning a Mission is now affected by faction favor and Player's faction rep multiplier<br>" +
"---Whenever a Node is conquered, its stats are reduced<br><br>" +
"v0.29.3<br>" +
"-Fixed bug for killing scripts and showing error messages when there are errors in a player-defined function<br>" +
"-Added function name autocompletion in Script Editor. Press Ctrl+space on a prefix to show autocompletion options.<br>" +
"-Minor rebalancing and bug fixes for Infiltration<br><br>" +
"v0.29.2<br>" +
"-installAugmentations() Singularity Function now takes a callback script as an argument. This is a script " +
"that gets ran automatically after Augmentations are installed. The script is run with no arguments and only a single thread, " +
"and must be found on your home computer.<br>" +
"-Added the ability to create your own functions in Netscript. See <a href='http://bitburner.wikia.com/wiki/Netscript_Functions' target='_blank'>this link</a> for details<br>" +
"-Added :q, :x, and :wq Vim Ex Commands when using the Vim script editor keybindings. :w, :x, and :wq will all save the script and return to Terminal. " +
":q will quit (return to Terminal) WITHOUT saving. If anyone thinks theres an issue with this please let me know, I don't use Vim<br>" +
"-Added a new Augmentation: ADR-V2 Pheromone Gene<br>" +
"-In Hacking Missions, enemy nodes will now automatically target Nodes and perform actions.<br>" +
"-Re-balanced Hacking Missions through minor tweaking of many numbers<br>" +
"-The faction reputation reward for Hacking Missions was slightly increased<br><br>" +
"v0.29.1<br>" +
"-New gameplay feature that is currently in BETA: Hacking Missions. Hacking Missions is an active gameplay mechanic (its a minigame) " +
"that is meant to be used to earn faction reputation. However, since this is currently in beta, hacking missions will NOT grant reputation " +
"for the time being, since the feature likely has many bugs, balance problems, and other issues. If you have any feedback " +
"regarding the new feature, feel free to let me know<br>" +
"-CHANGED THE RETURN VALUE OF getScriptIncome() WHEN RAN WITH NO ARGUMENTS. It will now return an array of " +
"two values rather than a single value. This may break your scripts, so make sure to update them!<br>" +
"-Added continue statement for for/while loops<br>" +
"-Added getServerMinSecurityLevel(), getPurchasedServers(), and getTimeSinceLastAug() Netscript functions<br>" +
"-Netscript scp() function can now take an array as the first argument, and will try to copy " +
"every file specified in the array (it will just call scp() normally for every element in the array). " +
"If an array is passed in, then the scp() function returns true if at least one element from the array is successfully copied<br>" +
"-Added Javascript's Date module to Netscript. Since 'new' is not supported in Netscript yet, only the Date module's " +
"static methods will work (now(), UTC(), parse(), etc.).<br>" +
"-Failing a crime now gives half the experience it did before<br>" +
"-The forced repeated 'Find The-Cave' message after installing The Red Pill Augmentation now only happens " +
"if you've never destroyed a BitNode before, and will only popup every 15 minutes. If you have already destroyed a BitNode, " +
"the message will not pop up if you have messages suppressed (if you don't have messages suppressed it WILL still repeatedly popup)<br>" +
"-fileExists() function now works on literature files<br><br>",
"-Minor rebalancing and bug fixes for Infiltration and Hacking Missions<br><br>"
}
export {CONSTANTS};

@ -18,6 +18,7 @@ let TerminalHelpText =
"kill [script] [args...] Stops the specified script on the current server <br>" +
"killall Stops all running scripts on the current machine<br>" +
"ls [| grep pattern] Displays all files on the machine<br>" +
"lscpu Displays the number of CPU cores on the machine<br>" +
"mem [script] [-t] [n] Displays the amount of RAM required to run the script<br>" +
"nano [script] Script editor - Open up and edit a script<br>" +
"ps Display all scripts that are currently running<br>" +

@ -22,6 +22,7 @@ import {SpecialServerNames, SpecialServerIps} from "./SpecialServerIps.js";
import {dialogBoxCreate} from "../utils/DialogBox.js";
import {clearEventListeners} from "../utils/HelperFunctions.js";
import {createRandomIp} from "../utils/IPAddress.js";
import numeral from "../utils/numeral.min.js";
import {formatNumber} from "../utils/StringHelperFunctions.js";
import {yesNoBoxCreate, yesNoTxtInpBoxCreate,
yesNoBoxGetYesButton, yesNoBoxGetNoButton,
@ -173,6 +174,7 @@ function displayLocationContent() {
var purchase1tb = document.getElementById("location-purchase-1tb");
var purchaseTor = document.getElementById("location-purchase-tor");
var purchaseHomeRam = document.getElementById("location-purchase-home-ram");
var purchaseHomeCores = document.getElementById("location-purchase-home-cores");
var travelAgencyText = document.getElementById("location-travel-agency-text");
var travelToAevum = document.getElementById("location-travel-to-aevum");
@ -264,6 +266,7 @@ function displayLocationContent() {
purchase1tb.style.display = "none";
purchaseTor.style.display = "none";
purchaseHomeRam.style.display = "none";
purchaseHomeCores.style.display = "none";
purchase2gb.innerHTML = "Purchase 2GB Server - $" + formatNumber(2*CONSTANTS.BaseCostFor1GBOfRamServer, 2);
purchase4gb.innerHTML = "Purchase 4GB Server - $" + formatNumber(4*CONSTANTS.BaseCostFor1GBOfRamServer, 2);
@ -419,6 +422,7 @@ function displayLocationContent() {
purchase1tb.style.display = "block";
purchaseTor.style.display = "block";
purchaseHomeRam.style.display = "block";
purchaseHomeCores.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumECorp,
6000, 116, 150, 8.5);
break;
@ -464,6 +468,7 @@ function displayLocationContent() {
purchase1tb.style.display = "block";
purchaseTor.style.display = "block";
purchaseHomeRam.style.display = "block";
purchaseHomeCores.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumFulcrumTechnologies,
6000, 96, 100, 9);
break;
@ -539,6 +544,7 @@ function displayLocationContent() {
purchase8gb.style.display = "block";
purchaseTor.style.display = "block";
purchaseHomeRam.style.display = "block";
purchaseHomeCores.style.display = "block";
setInfiltrateButton(infiltrate, Locations.AevumNetLinkTechnologies,
160, 10, 15, 1.8);
break;
@ -718,6 +724,7 @@ function displayLocationContent() {
purchase4gb.style.display = "block";
purchaseTor.style.display = "block";
purchaseHomeRam.style.display = "block";
purchaseHomeCores.style.display = "block";
setInfiltrateButton(infiltrate, Locations.Sector12AlphaEnterprises,
250, 14, 40, 2.7);
break;
@ -847,6 +854,7 @@ function displayLocationContent() {
purchase128gb.style.display = "block";
purchase256gb.style.display = "block";
purchaseHomeRam.style.display = "block";
purchaseHomeCores.style.display = "block";
setInfiltrateButton(infiltrate, Locations.IshimaStormTechnologies,
700, 24, 100, 5.9);
break;
@ -878,6 +886,7 @@ function displayLocationContent() {
purchase32gb.style.display = "block";
purchaseTor.style.display = "block";
purchaseHomeRam.style.display = "block";
purchaseHomeCores.style.display = "block";
setInfiltrateButton(infiltrate, Locations.IshimaOmegaSoftware,
200, 10, 40, 2.3);
break;
@ -994,6 +1003,7 @@ function displayLocationContent() {
purchase256gb.style.display = "block";
purchaseTor.style.display = "block";
purchaseHomeRam.style.display = "block";
purchaseHomeCores.style.display = "block";
setInfiltrateButton(infiltrate, Locations.VolhavenCompuTek,
300, 12, 35, 3.1);
break;
@ -1574,6 +1584,7 @@ function initLocationButtons() {
var purchase1tb = document.getElementById("location-purchase-1tb");
var purchaseTor = document.getElementById("location-purchase-tor");
var purchaseHomeRam = document.getElementById("location-purchase-home-ram");
var purchaseHomeCores = document.getElementById("location-purchase-home-cores");
var travelToAevum = document.getElementById("location-travel-to-aevum");
var travelToChongqing = document.getElementById("location-travel-to-chongqing");
@ -1742,6 +1753,42 @@ function initLocationButtons() {
"This will cost $" + formatNumber(cost, 2));
});
purchaseHomeCores.addEventListener("click", function() {
var currentCores = Player.getHomeComputer().cpuCores;
if (currentCores >= 8) {return;} //Max of 8 cores
//Cost of purchasing another cost is found by indexing this array with number of current cores
var cost = [0,
10000000000, //1->2 Cores - 10 bn
250000000000, //2->3 Cores - 250 bn
5000000000000, //3->4 Cores - 5 trillion
100000000000000, //4->5 Cores - 100 trillion
1000000000000000, //5->6 Cores - 1 quadrillion
20000000000000000, //6->7 Cores - 20 quadrillion
200000000000000000]; //7->8 Cores - 200 quadrillion
cost = cost[currentCores];
var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton();
yesBtn.innerHTML = "Purchase"; noBtn.innerHTML = "Cancel";
yesBtn.addEventListener("click", ()=>{
if (Player.money.lt(cost)) {
dialogBoxCreate("You do not have enough mone to purchase an additional CPU Core for your home computer!");
} else {
Player.loseMoney(cost);
Player.getHomeComputer().cpuCores++;
dialogBoxCreate("You purchased an additional CPU Core for your home computer! It now has " +
Player.getHomeComputer().cpuCores + " cores.");
}
yesNoBoxClose();
});
noBtn.addEventListener("click", ()=>{
yesNoBoxClose();
});
yesNoBoxCreate("Would you like to purchase an additional CPU Core for your home computer? Each CPU Core " +
"lets you start with an additional Core Node in Hacking Missions.<br><br>" +
"Purchasing an additional core (for a total of " + (Player.getHomeComputer().cpuCores + 1) + ") will " +
"cost " + numeral(cost).format('$0.000a'));
});
travelToAevum.addEventListener("click", function() {
travelBoxCreate(Locations.Aevum, 200000);
return false;

@ -76,6 +76,7 @@ function Node(type, stats) {
this.pos = [0, 0]; //x, y
this.el = null; //Holds the Node's DOM element
this.action = null;
this.targetedCount = 0; //Count of how many connections this node is the target of
//Holds the JsPlumb Connection object for this Node,
//where this Node is the Source (since each Node
@ -149,6 +150,15 @@ Node.prototype.deselect = function(actionButtons) {
}
}
Node.prototype.untarget = function() {
if (this.targetedCount === 0) {
console.log("WARN: Node " + this.el.id + " is being 'untargeted' when it has no target count");
return;
}
--this.targetedCount;
}
//Hacking mission instance
//Takes in the reputation of the Faction for which the mission is
//being conducted
@ -189,8 +199,7 @@ function HackingMission(rep, fac) {
this.jsplumbinstance = null;
//difficulty capped at 16
this.difficulty = Math.min(16, Math.round(rep / CONSTANTS.HackingMissionRepToDiffConversion) + 1);
this.difficulty = rep / CONSTANTS.HackingMissionRepToDiffConversion + 1;
console.log("difficulty: " + this.difficulty);
this.reward = 250 + (rep / CONSTANTS.HackingMissionRepToRewardConversion);
}
@ -203,20 +212,21 @@ HackingMission.prototype.init = function() {
var home = Player.getHomeComputer()
for (var i = 0; i < home.cpuCores; ++i) {
var stats = {
atk: (Player.hacking_skill / 5),
atk: (Player.hacking_skill / 7.5) + 30,
def: (Player.hacking_skill / 20),
hp: (Player.hacking_skill / 5),
hp: (Player.hacking_skill / 4),
};
this.playerCores.push(new Node(NodeTypes.Core, stats));
this.playerCores[i].setControlledByPlayer();
this.setNodePosition(this.playerCores[i], 0, i);
this.removeAvailablePosition(0, i);
this.setNodePosition(this.playerCores[i], i, 0);
this.removeAvailablePosition(i, 0);
}
//Randomly generate enemy nodes (CPU and Firewall) based on difficulty
var numNodes = Math.max(1, Math.round(this.difficulty / 3));
var numFirewalls = getRandomInt(this.difficulty, this.difficulty + 1);
var numDatabases = getRandomInt(this.difficulty, this.difficulty + 1);
var numNodes = Math.min(8, Math.max(1, Math.round(this.difficulty / 4)));
var numFirewalls = Math.min(20,
getRandomInt(Math.round(this.difficulty/2), Math.round(this.difficulty/2) + 1));
var numDatabases = Math.min(10, getRandomInt(1, Math.round(this.difficulty / 3) + 1));
var totalNodes = numNodes + numFirewalls + numDatabases;
var xlimit = 7 - Math.floor(totalNodes / 8);
console.log("numNodes: " + numNodes);
@ -224,12 +234,12 @@ HackingMission.prototype.init = function() {
console.log("numDatabases: " + numDatabases);
console.log("totalNodes: " + totalNodes);
console.log("xlimit: " + xlimit);
var randMult = addOffset(0.85 + (this.difficulty / 6), 10);
var randMult = addOffset(0.8 + (this.difficulty / 5), 10);
for (var i = 0; i < numNodes; ++i) {
var stats = {
atk: randMult * getRandomInt(50, 75),
atk: randMult * getRandomInt(75, 85),
def: randMult * getRandomInt(20, 40),
hp: randMult * getRandomInt(100, 120)
hp: randMult * getRandomInt(200, 220)
}
this.enemyCores.push(new Node(NodeTypes.Core, stats));
this.enemyCores[i].setControlledByEnemy();
@ -238,8 +248,8 @@ HackingMission.prototype.init = function() {
for (var i = 0; i < numFirewalls; ++i) {
var stats = {
atk: 0,
def: randMult * getRandomInt(50, 75),
hp: randMult * getRandomInt(150, 200)
def: randMult * getRandomInt(80, 100),
hp: randMult * getRandomInt(250, 275)
}
this.enemyNodes.push(new Node(NodeTypes.Firewall, stats));
this.enemyNodes[i].setControlledByEnemy();
@ -248,8 +258,8 @@ HackingMission.prototype.init = function() {
for (var i = 0; i < numDatabases; ++i) {
var stats = {
atk: 0,
def: randMult * getRandomInt(20, 30),
hp: randMult * getRandomInt(120, 150)
def: randMult * getRandomInt(75, 100),
hp: randMult * getRandomInt(200, 250)
}
var node = new Node(NodeTypes.Database, stats);
node.setControlledByEnemy();
@ -264,8 +274,12 @@ HackingMission.prototype.init = function() {
HackingMission.prototype.createPageDom = function() {
var container = document.getElementById("mission-container");
var favorMult = 1 + (this.faction.favor / 100);
var gain = this.reward * Player.faction_rep_mult * favorMult;
var headerText = document.createElement("p");
headerText.innerHTML = "You are about to start a hacking mission! For more information " +
headerText.innerHTML = "You are about to start a hacking mission! You will gain " +
formatNumber(gain, 3) + " faction reputation with " + this.faction.name +
" if you win. For more information " +
"about how hacking missions work, click one of the guide links " +
"below (one opens up an in-game guide and the other opens up " +
"the guide from the wiki). Click the 'Start' button to begin.";
@ -604,26 +618,28 @@ HackingMission.prototype.createMap = function() {
document.getElementById("mission-container").appendChild(map);
//Create random Nodes for every space in the map that
//hasn't been filled yet
//hasn't been filled yet. The stats of each Node will be based on
//the player/enemy attack
var averageAttack = (this.playerAtk + this.enemyAtk) / 2;
for (var x = 0; x < 8; ++x) {
for (var y = 0; y < 8; ++y) {
if (!(this.map[x][y] instanceof Node)) {
var node, type = getRandomInt(0, 2);
var randMult = addOffset(0.75 + (this.difficulty / 3), 20);
var randMult = addOffset(0.85 + (this.difficulty / 2), 15);
switch (type) {
case 0: //Spam
var stats = {
atk: 0,
def: randMult * getRandomInt(30, 50),
hp: randMult * getRandomInt(125, 150)
def: averageAttack * 1.2 + getRandomInt(10, 50),
hp: randMult * getRandomInt(160, 180)
}
node = new Node(NodeTypes.Spam, stats);
break;
case 1: //Transfer
var stats = {
atk: 0,
def: randMult * getRandomInt(40, 60),
hp: randMult * getRandomInt(150, 175)
def: averageAttack * 1.2 + getRandomInt(10, 50),
hp: randMult * getRandomInt(210, 230)
}
node = new Node(NodeTypes.Transfer, stats);
break;
@ -631,8 +647,8 @@ HackingMission.prototype.createMap = function() {
default:
var stats = {
atk: 0,
def: randMult * getRandomInt(50, 75),
hp: randMult * getRandomInt(200, 250)
def: averageAttack * 1.2 + getRandomInt(25, 75),
hp: randMult * getRandomInt(275, 300)
}
node = new Node(NodeTypes.Shield, stats);
break;
@ -927,12 +943,16 @@ HackingMission.prototype.initJsPlumb = function() {
var sourceNode = this.getNodeFromElement(info.source);
sourceNode.conn = info.connection;
var targetNode = this.getNodeFromElement(info.target);
++targetNode.targetedCount;
});
//Detach Connection events
instance.bind("connectionDetached", (info, originalEvent)=>{
var sourceNode = this.getNodeFromElement(info.source);
sourceNode.conn = null;
var targetNode = this.getNodeFromElement(info.target);
targetNode.untarget();
});
}
@ -955,13 +975,14 @@ HackingMission.prototype.dropAllConnectionsToNode = function(node) {
allConns[i].endpoints[0].detachFrom(allConns[i].endpoints[1]);
}
}
node.beingTargeted = false;
}
var storedCycles = 0;
HackingMission.prototype.process = function(numCycles=1) {
if (!this.started) {return;}
storedCycles += numCycles;
if (storedCycles < 3) {return;} //Only process every 2 cycles minimum
if (storedCycles < 2) {return;} //Only process every 3 cycles minimum
var res = false;
//Process actions of all player nodes
@ -988,6 +1009,12 @@ HackingMission.prototype.process = function(numCycles=1) {
}
});
//The hp of enemy databases increases slowly
this.enemyDatabases.forEach((node)=>{
node.maxhp += (0.1 * storedCycles);
node.hp += (0.1 * storedCycles);
});
if (res) {
this.calculateAttacks();
this.calculateDefenses();
@ -1005,9 +1032,12 @@ HackingMission.prototype.process = function(numCycles=1) {
return;
}
//Defense of every misc Node increase by 0.5 per second
//Defense/hp of misc nodes increases slowly over time
this.miscNodes.forEach((node)=>{
node.def += (0.1 * storedCycles);
node.maxhp += (0.05 * storedCycles);
node.hp += (0.1 * storedCycles);
if (node.hp > node.maxhp) {node.hp = node.maxhp;}
this.updateNodeDomElement(node);
});
@ -1103,6 +1133,10 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
targetNode.deselect(this.actionButtons);
}
//The conquered node has its stats reduced
targetNode.atk /= 3;
targetNode.def /= 3;
//Flag for whether the target node was a misc node
var isMiscNode = !targetNode.plyrCtrl && !targetNode.enmyCtrl;
@ -1205,9 +1239,11 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
}
//If a misc node was conquered, the defense for all misc nodes increases by some fixed amount
if (isMiscNode && conqueredByPlayer) {
if (isMiscNode) { //&& conqueredByPlayer) {
this.miscNodes.forEach((node)=>{
node.def *= CONSTANTS.HackingMissionMiscDefenseIncrease;
if (node.targetedCount === 0) {
node.def *= CONSTANTS.HackingMissionMiscDefenseIncrease;
}
});
}
}
@ -1218,7 +1254,7 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
return calcStats;
}
//Enemy "AI" for CPU Cor eand Transfer Nodes
//Enemy "AI" for CPU Core and Transfer Nodes
HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
if (nodeObj === null) {return;}
switch(nodeObj.type) {
@ -1238,11 +1274,11 @@ HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
}
if (this.nodeReachableByEnemy(node)) {
//Create connection
console.log("Enemy core selected a Player Node as target");
nodeObj.conn = this.jsplumbinstance.connect({
source:nodeObj.el,
target:node.el
});
++node.targetedCount;
} else {
//Randomly pick a player core and attack it if its reachable
rand = getRandomInt(0, this.playerCores.length-1);
@ -1254,11 +1290,11 @@ HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
if (this.nodeReachableByEnemy(node)) {
//Create connection
console.log("Enemy core selected a Player Core as target");
nodeObj.conn = this.jsplumbinstance.connect({
source:nodeObj.el,
target:node.el
});
++node.targetedCount;
}
}
} else {
@ -1266,11 +1302,11 @@ HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
var rand = getRandomInt(0, this.miscNodes.length-1);
var node = this.miscNodes[rand];
if (this.nodeReachableByEnemy(node)) {
console.log("Enemy core selected a Misc Node as target: " + node.el.id);
nodeObj.conn = this.jsplumbinstance.connect({
source:nodeObj.el,
target:node.el,
});
++node.targetedCount;
}
}
@ -1288,13 +1324,13 @@ HackingMission.prototype.enemyAISelectAction = function(nodeObj) {
console.log("Error getting Target node Object in enemyAISelectAction()");
}
if (targetNode.def > this.enemyAtk + 25) {
if (targetNode.def > this.enemyAtk + 15) {
if (nodeObj.def < 50) {
nodeObj.action = NodeActions.Fortify;
} else {
nodeObj.action = NodeActions.Overflow;
}
} else if (Math.abs(targetNode.def - this.enemyAtk) <= 25) {
} else if (Math.abs(targetNode.def - this.enemyAtk) <= 15) {
nodeObj.action = NodeActions.Scan;
} else {
nodeObj.action = NodeActions.Attack;
@ -1324,11 +1360,11 @@ HackingMission.prototype.calculateAttackDamage = function(atk, def, hacking = 0)
}
HackingMission.prototype.calculateScanEffect = function(atk, def, hacking=0) {
return Math.max((atk) + hacking / hackEffWeightTarget - def, 1);
return Math.max(0.85 * ((atk) + hacking / hackEffWeightTarget - (def * 0.95)), 2);
}
HackingMission.prototype.calculateWeakenEffect = function(atk, def, hacking=0) {
return Math.max((atk) + hacking / hackEffWeightTarget - def, 1);
return Math.max((atk) + hacking / hackEffWeightTarget - (def * 0.95), 2);
}
HackingMission.prototype.calculateFortifyEffect = function(hacking=0) {
@ -1343,7 +1379,7 @@ HackingMission.prototype.calculateOverflowEffect = function(hacking=0) {
HackingMission.prototype.updateTimer = function() {
var timer = document.getElementById("hacking-mission-timer");
//Convert time remaining to a string of the form m:ss
//Convert time remaining to a string of the form mm:ss
var seconds = Math.round(this.time / 1000);
var minutes = Math.trunc(seconds / 60);
seconds %= 60;
@ -1357,11 +1393,17 @@ HackingMission.prototype.finishMission = function(win) {
currMission = null;
if (win) {
dialogBoxCreate("Mission won! This feature is currently in " +
"beta so you did not earn anything, but normally you would have won " +
this.reward + " reputation with " + this.faction.name);
var favorMult = 1 + (this.faction.favor / 100);
console.log("Hacking mission base reward: " + this.reward);
console.log("favorMult: " + favorMult);
console.log("rep mult: " + Player.faction_rep_mult);
var gain = this.reward * Player.faction_rep_mult * favorMult;
dialogBoxCreate("Mission won! You earned " +
formatNumber(gain, 3) + " reputation with " + this.faction.name);
Player.gainIntelligenceExp(this.difficulty * CONSTANTS.IntelligenceHackingMissionBaseExpGain);
this.faction.playerReputation += gain;
} else {
dialogBoxCreate("Mission lost/forfeited!");
dialogBoxCreate("Mission lost/forfeited! You did not gain any faction reputation.");
}
//Clear mission container

@ -35,8 +35,7 @@ function evaluate(exp, workerScript) {
resolve(workerScript);
}, function(e) {
if (e.constructor === Array && e.length === 2 && e[0] === "RETURNSTATEMENT") {
//Returning from a Player-defined function
resolve(e[1]);
reject(e);
} else if (isString(e)) {
workerScript.errorMessage = e;
reject(workerScript);
@ -101,16 +100,19 @@ function evaluate(exp, workerScript) {
funcWorkerScript.env = funcEnv;
evaluate(func.body, funcWorkerScript).then(function(res) {
resolve(res);
//If the function finished successfuly, that means there
//was no return statement since a return statement rejects. So resolve to null
resolve(null);
}).catch(function(e) {
if (isString(e)) {
if (e.constructor === Array && e.length === 2 && e[0] === "RETURNSTATEMENT") {
//Return statement from function
resolve(e[1]);
} else if (isString(e)) {
reject(makeRuntimeRejectMsg(workerScript, e));
} else if (e instanceof WorkerScript) {
//Parse out the err message from the WorkerScript and re-reject
var errorMsg = e.errorMessage;
var errorTextArray = errorMsg.split("|");
console.log("Printing error message from Function:");
console.log(errorMsg);
if (errorTextArray.length === 4) {
errorMsg = errorTextArray[3];
reject(makeRuntimeRejectMsg(workerScript, errorMsg));

@ -43,12 +43,10 @@ import {printArray, powerOfTwo} from "../utils/HelperFunctio
import {createRandomIp} from "../utils/IPAddress.js";
import {formatNumber, isString, isHTML} from "../utils/StringHelperFunctions.js";
var hasSingularitySF = false;
var hasAISF = false;
var hasSingularitySF = false, hasAISF = false, hasBn11SF = false;
var singularitySFLvl = 1;
//Also used to check for Artificial Intelligence Source File, don't want to change
//name though
//Used to check and set flags for every Source File, despite the name of the function
function initSingularitySFFlags() {
for (var i = 0; i < Player.sourceFiles.length; ++i) {
if (Player.sourceFiles[i].n === 4) {
@ -58,6 +56,9 @@ function initSingularitySFFlags() {
if (Player.sourceFiles[i].n === 5) {
hasAISF = true;
}
if (Player.sourceFiles[i].n === 11) {
hasBn11SF = true;
}
}
}
@ -1898,6 +1899,44 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("Began creating program: " + name);
return true;
},
getOwnedAugmentations(purchased=false) {
if (Player.bitNodeN != 4) {
if (!(hasSingularitySF && singularitySFLvl >= 3)) {
throw makeRuntimeRejectMsg(workerScript, "Cannot run getOwnedAugmentations(). It is a Singularity Function and requires SourceFile-4 (level 3) to run.");
return [];
}
}
var res = [];
for (var i = 0; i < Player.augmentations.length; ++i) {
res.push(Player.augmentations[i].name);
}
if (purchased) {
for (var i = 0; i < Player.queuedAugmentations.length; ++i) {
res.push(Player.queuedAugmentations[i].name);
}
}
return res;
},
getAugmentationsFromFaction(facname) {
if (Player.bitNodeN != 4) {
if (!(hasSingularitySF && singularitySFLvl >= 3)) {
throw makeRuntimeRejectMsg(workerScript, "Cannot run getAugmentationsFromFaction(). It is a Singularity Function and requires SourceFile-4 (level 3) to run.");
return [];
}
}
if (!factionExists(facname)) {
workerScript.scriptRef.log("ERROR: getAugmentationsFromFaction() failed. Invalid faction name passed in (this is case-sensitive): " + facname);
return [];
}
var fac = Factions[facname];
var res = [];
for (var i = 0; i < fac.augmentations.length; ++i) {
res.push(fac.augmentations[i]);
}
return res;
},
getAugmentationCost(name) {
if (Player.bitNodeN != 4) {
if (!(hasSingularitySF && singularitySFLvl >= 3)) {
@ -1993,4 +2032,4 @@ function NetscriptFunctions(workerScript) {
}
}
export {NetscriptFunctions, initSingularitySFFlags, hasSingularitySF};
export {NetscriptFunctions, initSingularitySFFlags, hasSingularitySF, hasBn11SF};

@ -115,6 +115,11 @@ function runScriptsLoop() {
dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer");
console.log("ERROR: Evaluating workerscript returns an Error. THIS SHOULDN'T HAPPEN: " + w.toString());
return;
} else if (w.constructor === Array && w.length === 2 && w[0] === "RETURNSTATEMENT") {
//Script ends with a return statement
console.log("Script returning with value: " + w[1]);
//TODO maybe do something with this in the future
return;
} else if (w instanceof WorkerScript) {
if (isScriptErrorMessage(w.errorMessage)) {
var errorTextArray = w.errorMessage.split("|");

@ -13,6 +13,7 @@ import {Factions, Faction,
displayFactionContent} from "./Faction.js";
import {Gang, resetGangs} from "./Gang.js";
import {Locations} from "./Location.js";
import {hasBn11SF} from "./NetscriptFunctions.js";
import {AllServers, Server, AddToAllServers} from "./Server.js";
import {SpecialServerIps, SpecialServerNames} from "./SpecialServerIps.js";
import {SourceFiles, applySourceFile} from "./SourceFile.js";
@ -1068,9 +1069,13 @@ PlayerObject.prototype.workForFaction = function(numCycles) {
//Money gained per game cycle
PlayerObject.prototype.getWorkMoneyGain = function() {
var bn11Mult = 1;
var company = Companies[this.companyName];
if (hasBn11SF) {
bn11Mult = 1 + (company.favor / 100);
}
return this.companyPosition.baseSalary * company.salaryMultiplier *
this.work_money_mult * BitNodeMultipliers.CompanyWorkMoney;
this.work_money_mult * BitNodeMultipliers.CompanyWorkMoney * bn11Mult;
}
//Hack exp gained per game cycle
@ -1459,12 +1464,14 @@ PlayerObject.prototype.finishCrime = function(cancelled) {
break;
case CONSTANTS.CrimeRobStore:
this.karma -= 0.5;
this.gainIntelligenceExp(0.25 * CONSTANTS.IntelligenceCrimeBaseExpGain);
break;
case CONSTANTS.CrimeMug:
this.karma -= 0.25;
break;
case CONSTANTS.CrimeLarceny:
this.karma -= 1.5;
this.gainIntelligenceExp(0.5 * CONSTANTS.IntelligenceCrimeBaseExpGain);
break;
case CONSTANTS.CrimeDrugs:
this.karma -= 0.5;

@ -166,6 +166,7 @@ function prestigeSourceFile() {
} else {
homeComp.setMaxRam(8);
}
homeComp.cpuCores = 1;
AddToAllServers(homeComp);

@ -38,6 +38,7 @@ function Server(ip=createRandomIp(), hostname="", organizationName="",
this.runningScripts = []; //Stores RunningScript objects
this.programs = [];
this.messages = [];
this.dir = 0; //new Directory(this, null, "");
/* Hacking information (only valid for "foreign" aka non-purchased servers) */
//Skill required to attempt a hack. Whether a hack is successful will be determined
@ -763,6 +764,34 @@ function PrintAllServers() {
}
}
// Directory object (folders)
function Directory(server, parent, name) {
this.s = server; //Ref to server
this.p = parent; //Ref to parent directory
this.c = []; //Subdirs
this.n = name;
this.d = parent.d + 1; //We'll only have a maximum depth of 3 or something
this.scrs = []; //Holds references to the scripts in server.scripts
this.pgms = [];
this.msgs = [];
}
Directory.prototype.createSubdir = function(name) {
var subdir = new Directory(this.s, this, name);
}
Directory.prototype.getPath = function(name) {
var res = [];
var i = this;
while (i !== null) {
res.unshift(i.n, "/");
i = i.parent;
}
res.unshift("/");
return res.join("");
}
export {Server, AllServers, getServer, GetServerByHostname, loadAllServers,
AddToAllServers, processSingleServerGrowth, initForeignServers,
prestigeAllServers, prestigeHomeComputer};

@ -47,10 +47,12 @@ function initSourceFiles() {
SourceFiles["SourceFile8"] = new SourceFile(8);
SourceFiles["SourceFile9"] = new SourceFile(9);
SourceFiles["SourceFile10"] = new SourceFile(10);
SourceFiles["SourceFile11"] = new SourceFile(11, "This Source-File increases the player's company salary and reputation gain multipliers by:<br><br>" +
"Level 1: 60%<br>" +
"Level 2: 90%<br>" +
"Level 3: 105%<br>");
SourceFiles["SourceFile11"] = new SourceFile(11, "This Source-File makes it so that company favor increases BOTH the player's salary and reputation gain rate " +
"at that company by 1% per favor (rather than just the reputation gain). This Source-File also " +
" increases the player's company salary and reputation gain multipliers by:<br><br>" +
"Level 1: 24%<br>" +
"Level 2: 36%<br>" +
"Level 3: 42%<br>");
SourceFiles["SourceFile12"] = new SourceFile(12);
}
@ -126,11 +128,13 @@ function applySourceFile(srcFile) {
Player.hacking_speed_mult *= incMult;
Player.hacking_money_mult *= incMult;
Player.hacking_grow_mult *= incMult;
Player.hacking_mult *= incMult;
Player.hacking_exp_mult *= incMult;
break;
case 11: //The Big Crash
var mult = 0;
for (var i = 0; i < srcFile.lvl; ++i) {
mult += (60 / (Math.pow(2, i)));
mult += (24 / (Math.pow(2, i)));
}
var incMult = 1 + (mult / 100);
Player.work_money_mult *= incMult;

@ -297,7 +297,7 @@ function determineAllPossibilitiesForTabCompletion(input, index=0) {
if (index == -1) {
return ["alias", "analyze", "cat", "check", "clear", "cls", "connect", "free",
"hack", "help", "home", "hostname", "ifconfig", "kill", "killall",
"ls", "mem", "nano", "ps", "rm", "run", "scan", "scan-analyze",
"ls", "lscpu", "mem", "nano", "ps", "rm", "run", "scan", "scan-analyze",
"scp", "sudov", "tail", "theme", "top"].concat(Object.keys(Aliases)).concat(Object.keys(GlobalAliases));
}
@ -899,6 +899,9 @@ let Terminal = {
case "ls":
Terminal.executeListCommand(commandArray);
break;
case "lscpu":
post(Player.getCurrentServer().cpuCores + " Core(s)");
break;
case "mem":
if (commandArray.length != 2) {
post("Incorrect usage of mem command. usage: mem [scriptname] [-t] [number threads]"); return;