This commit is contained in:
danielyxie 2018-06-06 11:13:38 -05:00
commit 6e6f5ce3d0
10 changed files with 358 additions and 152 deletions

@ -288,30 +288,44 @@
} }
#hacknet-nodes-text, #hacknet-nodes-text,
#hacknet-nodes-money,
#hacknet-nodes-container li { #hacknet-nodes-container li {
width: 70%;
margin: 10px; margin: 10px;
padding: 10px; padding: 10px;
} }
#hacknet-nodes-purchase-button { #hacknet-nodes-container li {
display: inline-block; float: left;
overflow: hidden;
white-space: nowrap;
}
#hacknet-nodes-list {
list-style: none;
width: 82vw;
}
#hacknet-nodes-money {
margin: 10px;
float: left;
} }
#hacknet-nodes-money-multipliers-div { #hacknet-nodes-money-multipliers-div {
display: inline-block; display: inline-block;
width: 70%; width: 70vw;
} }
#hacknet-nodes-multipliers { #hacknet-nodes-multipliers {
float: right; float: right;
} }
#hacknet-nodes-purchase-button {
display: inline-block;
}
.hacknet-node { .hacknet-node {
margin: 6px; margin: 6px;
padding: 6px; padding: 6px;
width: 85%; width: 34vw;
border: 2px solid var(--my-highlight-color); border: 2px solid var(--my-highlight-color);
-webkit-box-shadow: -webkit-box-shadow:
inset 0 0 8px rgba(0,0,0,0.1), inset 0 0 8px rgba(0,0,0,0.1),
@ -324,12 +338,28 @@
0 0 16px rgba(0,0,0,0.1); 0 0 16px rgba(0,0,0,0.1);
} }
.hacknet-node-button-div a { .hacknet-node-container {
display: block; display: inline-table;
} }
.hacknet-node-button-div:not(:last-child) { .hacknet-node-container .row {
border-bottom: none; display: table-row;
height: 30px;
}
.hacknet-node-container .row p {
display: table-cell;
}
.hacknet-node-container .upgradable-info {
display: inline-block;
margin: 0 4px; /* Don't want the vertical margin/padding, just left & right */
padding: 0 4px;
width: 48px; /* Four times font-size */
}
.menu-page-text {
width: 70vw;
} }
/* World */ /* World */

@ -15,7 +15,10 @@ body {
background-color: var(--my-background-color); background-color: var(--my-background-color);
} }
p, pre, h2 { p,
pre,
h2,
.text {
color: var(--my-font-color); color: var(--my-font-color);
} }

@ -185,7 +185,7 @@
<!-- Hacknet Nodes --> <!-- Hacknet Nodes -->
<div id="hacknet-nodes-container" class="generic-menupage-container"> <div id="hacknet-nodes-container" class="generic-menupage-container">
<h1 id="hacknet-nodes-title"> Hacknet Nodes </h1> <h1 id="hacknet-nodes-title"> Hacknet Nodes </h1>
<p id="hacknet-nodes-text"> <p id="hacknet-nodes-text" class="menu-page-text">
The Hacknet is a global, decentralized network of machines. It is used by hackers all around The Hacknet is a global, decentralized network of machines. It is used by hackers all around
the world to anonymously share computing power and perform distributed cyberattacks without the the world to anonymously share computing power and perform distributed cyberattacks without the
fear of being traced. fear of being traced.
@ -199,8 +199,11 @@
</p> </p>
<a id="hacknet-nodes-purchase-button" class="a-link-button"> Purchase Hacknet Node </a> <a id="hacknet-nodes-purchase-button" class="a-link-button"> Purchase Hacknet Node </a>
<br> <br>
<div id="hacknet-nodes-money-multipliers-div">" <div id="hacknet-nodes-money-multipliers-div">
<p id="hacknet-nodes-money"> </p> <p id="hacknet-nodes-money">
<span>Money:</span><span id="hacknet-nodes-player-money" ></span><br />
<span>Total Hacknet Node Prodution:</span><span id="hacknet-nodes-total-production"></span>
</p>
<span id="hacknet-nodes-multipliers"> <span id="hacknet-nodes-multipliers">
<a id="hacknet-nodes-1x-multiplier" class="a-link-button-inactive"> x1 </a> <a id="hacknet-nodes-1x-multiplier" class="a-link-button-inactive"> x1 </a>
<a id="hacknet-nodes-5x-multiplier" class="a-link-button"> x5 </a> <a id="hacknet-nodes-5x-multiplier" class="a-link-button"> x5 </a>
@ -208,7 +211,7 @@
<a id="hacknet-nodes-max-multiplier" class="a-link-button"> MAX </a> <a id="hacknet-nodes-max-multiplier" class="a-link-button"> MAX </a>
</span> </span>
</div> </div>
<ul id="hacknet-nodes-list" style="list-style : none;"> <ul id="hacknet-nodes-list">
</ul> </ul>
</div> </div>

@ -2594,8 +2594,9 @@ function displaySourceFiles(listElement, sourceFiles) {
console.log("ERROR: Invalid source file number: " + sourceFiles[i].n); console.log("ERROR: Invalid source file number: " + sourceFiles[i].n);
continue; continue;
} }
const maxLevel = sourceFiles[i].n == 12 ? "∞" : "3";
var accordion = createAccordionElement({ var accordion = createAccordionElement({
hdrText:sourceFileObject.name + "<br>" + "Level " + (sourceFiles[i].lvl) + " / 3", hdrText:sourceFileObject.name + "<br>" + "Level " + (sourceFiles[i].lvl) + " / "+maxLevel,
panelText:sourceFileObject.info panelText:sourceFileObject.info
}); });

@ -156,10 +156,9 @@ function initBitNodes() {
"Level 1: 24%<br>" + "Level 1: 24%<br>" +
"Level 2: 36%<br>" + "Level 2: 36%<br>" +
"Level 3: 42%"); "Level 3: 42%");
BitNodes["BitNode12"] = new BitNode(12, "The testing ground", "Ender improvement center", "Something about this bitnode being the testing ground for the enders security. This bitnode is infinitely repeatable but gets harder each time. This awards Source-File 12 which awards 1% to all stats each time this bitnode is destroyed.");
//Books: Frontera, Shiner //Books: Frontera, Shiner
BitNodes["BitNode12"] = new BitNode(12, "fOS", "COMING SOON"); //Unlocks the new game mode and the rest of the BitNodes BitNodes["BitNode13"] = new BitNode(13, "fOS", "COMING SOON"); //Unlocks the new game mode and the rest of the BitNodes
BitNodes["BitNode13"] = new BitNode(13, "", "COMING SOON");
BitNodes["BitNode14"] = new BitNode(14, "", "COMING SOON"); BitNodes["BitNode14"] = new BitNode(14, "", "COMING SOON");
BitNodes["BitNode15"] = new BitNode(15, "", "COMING SOON"); BitNodes["BitNode15"] = new BitNode(15, "", "COMING SOON");
BitNodes["BitNode16"] = new BitNode(16, "", "COMING SOON"); BitNodes["BitNode16"] = new BitNode(16, "", "COMING SOON");
@ -304,6 +303,51 @@ function initBitNodeMultipliers() {
BitNodeMultipliers.InfiltrationRep = 2.5; BitNodeMultipliers.InfiltrationRep = 2.5;
BitNodeMultipliers.CorporationValuation = 0.01; BitNodeMultipliers.CorporationValuation = 0.01;
break; break;
case 12: //The Testing Ground
let sf12Lvl = 0;
for(let i = 0; i < Player.sourceFiles.length; i++) {
if(Player.sourceFiles[i].n == 12) {
sf12Lvl = Player.sourceFiles[i].lvl;
}
}
const inc = Math.pow(1.01, sf12Lvl);
const dec = Math.pow(0.99, sf12Lvl);
BitNodeMultipliers.HackingLevelMultiplier = dec;
BitNodeMultipliers.ServerMaxMoney = dec;
BitNodeMultipliers.ServerStartingMoney = dec;
BitNodeMultipliers.ServerGrowthRate = dec;
BitNodeMultipliers.ServerWeakenRate = dec;
//this one is special because it can cause the min
//security to go over 100 and make it impossible to
//get money through hacking. This stat should not be
//BitNodeMultipliers.ServerStartingSecurity = inc;
BitNodeMultipliers.ManualHackMoney = dec;
BitNodeMultipliers.ScriptHackMoney = dec;
BitNodeMultipliers.CompanyWorkMoney = dec;
BitNodeMultipliers.CrimeMoney = dec;
BitNodeMultipliers.HacknetNodeMoney = dec;
BitNodeMultipliers.CompanyWorkExpGain = dec;
BitNodeMultipliers.ClassGymExpGain = dec;
BitNodeMultipliers.FactionWorkExpGain = dec;
BitNodeMultipliers.HackExpGain = dec;
BitNodeMultipliers.CrimeExpGain = dec;
BitNodeMultipliers.FactionWorkRepGain = dec;
BitNodeMultipliers.FactionPassiveRepGain = dec;
BitNodeMultipliers.RepToDonateToFaction = inc;
BitNodeMultipliers.AugmentationRepCost = inc;
BitNodeMultipliers.AugmentationMoneyCost = inc;
BitNodeMultipliers.InfiltrationMoney = dec;
BitNodeMultipliers.InfiltrationRep = dec;
BitNodeMultipliers.CorporationValuation = dec;
default: default:
console.log("WARNING: Player.bitNodeN invalid"); console.log("WARNING: Player.bitNodeN invalid");
break; break;

@ -599,7 +599,7 @@ function createFactionAugmentationDisplayElements(augmentationsList, augs, facti
var pElem = createElement("p", { var pElem = createElement("p", {
display:"inline", display:"inline",
}) })
var req = aug.baseRepRequirement * faction.augmentationRepRequirementMult; var req = aug.baseRepRequirement * factionInfo.augmentationRepRequirementMult;
var hasPrereqs = hasAugmentationPrereqs(aug); var hasPrereqs = hasAugmentationPrereqs(aug);
if (!hasPrereqs) { if (!hasPrereqs) {
aElem.setAttribute("class", "a-link-button-inactive"); aElem.setAttribute("class", "a-link-button-inactive");
@ -626,7 +626,7 @@ function createFactionAugmentationDisplayElements(augmentationsList, augs, facti
} }
function purchaseAugmentationBoxCreate(aug, fac) { function purchaseAugmentationBoxCreate(aug, fac) {
const factionInfo = fac.info(); const factionInfo = fac.getInfo();
var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton(); var yesBtn = yesNoBoxGetYesButton(), noBtn = yesNoBoxGetNoButton();
yesBtn.innerHTML = "Purchase"; yesBtn.innerHTML = "Purchase";
noBtn.innerHTML = "Cancel"; noBtn.innerHTML = "Cancel";
@ -671,12 +671,13 @@ function hasAugmentationPrereqs(aug) {
} }
function purchaseAugmentation(aug, fac, sing=false) { function purchaseAugmentation(aug, fac, sing=false) {
const factionInfo = fac.getInfo();
var hasPrereqs = hasAugmentationPrereqs(aug); var hasPrereqs = hasAugmentationPrereqs(aug);
if (!hasPrereqs) { if (!hasPrereqs) {
var txt = "You must first purchase or install " + aug.prereqs.join(",") + " before you can " + var txt = "You must first purchase or install " + aug.prereqs.join(",") + " before you can " +
"purchase this one."; "purchase this one.";
if (sing) {return txt;} else {dialogBoxCreate(txt);} if (sing) {return txt;} else {dialogBoxCreate(txt);}
} else if (Player.money.lt(aug.baseCost * fac.augmentationPriceMult)) { } else if (Player.money.lt(aug.baseCost * factionInfo.augmentationPriceMult)) {
let txt = "You don't have enough money to purchase " + aug.name; let txt = "You don't have enough money to purchase " + aug.name;
if (sing) {return txt;} if (sing) {return txt;}
dialogBoxCreate(txt); dialogBoxCreate(txt);
@ -684,7 +685,7 @@ function purchaseAugmentation(aug, fac, sing=false) {
let txt = "You don't have enough faction reputation to purchase " + aug.name; let txt = "You don't have enough faction reputation to purchase " + aug.name;
if (sing) {return txt;} if (sing) {return txt;}
dialogBoxCreate(txt); dialogBoxCreate(txt);
} else if (Player.money.gte(aug.baseCost * fac.augmentationPriceMult)) { } else if (Player.money.gte(aug.baseCost * factionInfo.augmentationPriceMult)) {
if (Player.firstAugPurchased === false) { if (Player.firstAugPurchased === false) {
Player.firstAugPurchased = true; Player.firstAugPurchased = true;
document.getElementById("augmentations-tab").style.display = "list-item"; document.getElementById("augmentations-tab").style.display = "list-item";
@ -698,7 +699,7 @@ function purchaseAugmentation(aug, fac, sing=false) {
} }
Player.queuedAugmentations.push(queuedAugmentation); Player.queuedAugmentations.push(queuedAugmentation);
Player.loseMoney((aug.baseCost * fac.augmentationPriceMult)); Player.loseMoney((aug.baseCost * factionInfo.augmentationPriceMult));
//If you just purchased Neuroflux Governor, recalculate the cost //If you just purchased Neuroflux Governor, recalculate the cost
if (aug.name == AugmentationNames.NeuroFluxGovernor) { if (aug.name == AugmentationNames.NeuroFluxGovernor) {

@ -5,42 +5,48 @@ import {iTutorialSteps, iTutorialNextStep,
iTutorialIsRunning, currITutorialStep} from "./InteractiveTutorial.js"; iTutorialIsRunning, currITutorialStep} from "./InteractiveTutorial.js";
import {Player} from "./Player.js"; import {Player} from "./Player.js";
import {dialogBoxCreate} from "../utils/DialogBox.js"; import {dialogBoxCreate} from "../utils/DialogBox.js";
import {clearEventListeners} from "../utils/HelperFunctions.js"; import {clearEventListeners, createElement,
getElementById} from "../utils/HelperFunctions.js";
import {Reviver, Generic_toJSON, import {Reviver, Generic_toJSON,
Generic_fromJSON} from "../utils/JSONReviver.js"; Generic_fromJSON} from "../utils/JSONReviver.js";
import {formatNumber} from "../utils/StringHelperFunctions.js"; import {formatNumber} from "../utils/StringHelperFunctions.js";
/**
* Overwrites the inner text of the specified HTML element if it is different from what currently exists.
* @param {string} elementId The HTML ID to find the first instance of.
* @param {string} text The inner text that should be set.
*/
function updateText(elementId, text) {
var el = getElementById(elementId);
if (el.innerText != text) {
el.innerText = text;
}
};
/* HacknetNode.js */ /* HacknetNode.js */
function hacknetNodesInit() { function hacknetNodesInit() {
var mult1x = document.getElementById("hacknet-nodes-1x-multiplier"); var performMapping = function(x) {
mult1x.addEventListener("click", function() { getElementById("hacknet-nodes-" + x.id + "-multiplier")
hacknetNodePurchaseMultiplier = 1; .addEventListener("click", function() {
updateHacknetNodesMultiplierButtons(); hacknetNodePurchaseMultiplier = x.multiplier;
updateHacknetNodesContent();
return false;
});
var mult5x = document.getElementById("hacknet-nodes-5x-multiplier");
mult5x.addEventListener("click", function() {
hacknetNodePurchaseMultiplier = 5;
updateHacknetNodesMultiplierButtons();
updateHacknetNodesContent();
return false;
});
var mult10x = document.getElementById("hacknet-nodes-10x-multiplier");
mult10x.addEventListener("click", function() {
hacknetNodePurchaseMultiplier = 10;
updateHacknetNodesMultiplierButtons();
updateHacknetNodesContent();
return false;
});
var multMax = document.getElementById("hacknet-nodes-max-multiplier");
multMax.addEventListener("click", function() {
hacknetNodePurchaseMultiplier = 0;
updateHacknetNodesMultiplierButtons(); updateHacknetNodesMultiplierButtons();
updateHacknetNodesContent(); updateHacknetNodesContent();
return false; return false;
}); });
};
var mappings = [
{ id: "1x", multiplier: 1 },
{ id: "5x", multiplier: 5 },
{ id: "10x", multiplier: 10 },
{ id: "max", multiplier: 0 }
];
for (var elem of mappings) {
// Encapsulate in a function so that the appropriate scope is kept in the click handler.
performMapping(elem);
} }
}
document.addEventListener("DOMContentLoaded", hacknetNodesInit, false); document.addEventListener("DOMContentLoaded", hacknetNodesInit, false);
function HacknetNode(name) { function HacknetNode(name) {
@ -76,7 +82,10 @@ HacknetNode.prototype.updateMoneyGainRate = function() {
HacknetNode.prototype.calculateLevelUpgradeCost = function(levels=1) { HacknetNode.prototype.calculateLevelUpgradeCost = function(levels=1) {
levels = Math.round(levels); levels = Math.round(levels);
if (isNaN(levels) || levels < 1) {return 0;} if (isNaN(levels) || levels < 1) {
return 0;
}
var mult = CONSTANTS.HacknetNodeUpgradeLevelMult; var mult = CONSTANTS.HacknetNodeUpgradeLevelMult;
var totalMultiplier = 0; //Summed var totalMultiplier = 0; //Summed
var currLevel = this.level; var currLevel = this.level;
@ -84,6 +93,7 @@ HacknetNode.prototype.calculateLevelUpgradeCost = function(levels=1) {
totalMultiplier += Math.pow(mult, currLevel); totalMultiplier += Math.pow(mult, currLevel);
++currLevel; ++currLevel;
} }
return CONSTANTS.BaseCostForHacknetNode / 2 * totalMultiplier * Player.hacknet_node_level_cost_mult; return CONSTANTS.BaseCostForHacknetNode / 2 * totalMultiplier * Player.hacknet_node_level_cost_mult;
} }
@ -95,12 +105,19 @@ HacknetNode.prototype.getLevelUpgradeCost = function(levels=1) {
HacknetNode.prototype.purchaseLevelUpgrade = function(levels=1) { HacknetNode.prototype.purchaseLevelUpgrade = function(levels=1) {
levels = Math.round(levels); levels = Math.round(levels);
var cost = this.calculateLevelUpgradeCost(levels); var cost = this.calculateLevelUpgradeCost(levels);
if (isNaN(cost) || levels < 0) {return false;} if (isNaN(cost) || levels < 0) {
return false;
}
if (this.level + levels > CONSTANTS.HacknetNodeMaxLevel) { if (this.level + levels > CONSTANTS.HacknetNodeMaxLevel) {
var diff = Math.max(0, CONSTANTS.HacknetNodeMaxLevel - this.level); var diff = Math.max(0, CONSTANTS.HacknetNodeMaxLevel - this.level);
return this.purchaseLevelUpgrade(diff); return this.purchaseLevelUpgrade(diff);
} }
if (Player.money.lt(cost)) {return false;}
if (Player.money.lt(cost)) {
return false;
}
Player.loseMoney(cost); Player.loseMoney(cost);
this.level += levels; this.level += levels;
this.updateMoneyGainRate(); this.updateMoneyGainRate();
@ -131,9 +148,18 @@ HacknetNode.prototype.getRamUpgradeCost = function() {
HacknetNode.prototype.purchaseRamUpgrade = function() { HacknetNode.prototype.purchaseRamUpgrade = function() {
var cost = this.calculateRamUpgradeCost(); var cost = this.calculateRamUpgradeCost();
if (isNaN(cost)) {return false;} if (isNaN(cost)) {
if (Player.money.lt(cost)) {return false;} return false;
if (this.ram >= CONSTANTS.HacknetNodeMaxRam) {return false;} }
if (Player.money.lt(cost)) {
return false;
}
if (this.ram >= CONSTANTS.HacknetNodeMaxRam) {
return false;
}
Player.loseMoney(cost); Player.loseMoney(cost);
this.ram *= 2; //Ram is always doubled this.ram *= 2; //Ram is always doubled
this.updateMoneyGainRate(); this.updateMoneyGainRate();
@ -162,9 +188,18 @@ HacknetNode.prototype.getCoreUpgradeCost = function() {
HacknetNode.prototype.purchaseCoreUpgrade = function() { HacknetNode.prototype.purchaseCoreUpgrade = function() {
var cost = this.calculateCoreUpgradeCost(); var cost = this.calculateCoreUpgradeCost();
if (isNaN(cost)) {return false;} if (isNaN(cost)) {
if (Player.money.lt(cost)) {return false;} return false;
if (this.cores >= CONSTANTS.HacknetNodeMaxCores) {return false;} }
if (Player.money.lt(cost)) {
return false;
}
if (this.cores >= CONSTANTS.HacknetNodeMaxCores) {
return false;
}
Player.loseMoney(cost); Player.loseMoney(cost);
++this.cores; ++this.cores;
this.updateMoneyGainRate(); this.updateMoneyGainRate();
@ -231,7 +266,10 @@ function purchaseHacknet() {
/* END INTERACTIVE TUTORIAL */ /* END INTERACTIVE TUTORIAL */
var cost = getCostOfNextHacknetNode(); var cost = getCostOfNextHacknetNode();
if (isNaN(cost)) {throw new Error("Cost is NaN"); return;} if (isNaN(cost)) {
throw new Error("Cost is NaN");
}
if (Player.money.lt(cost)) { if (Player.money.lt(cost)) {
//dialogBoxCreate("You cannot afford to purchase a Hacknet Node!"); //dialogBoxCreate("You cannot afford to purchase a Hacknet Node!");
return false; return false;
@ -299,7 +337,10 @@ function updateHacknetNodesMultiplierButtons() {
//Calculate the maximum number of times the Player can afford to upgrade //Calculate the maximum number of times the Player can afford to upgrade
//a Hacknet Node's level" //a Hacknet Node's level"
function getMaxNumberLevelUpgrades(nodeObj) { function getMaxNumberLevelUpgrades(nodeObj) {
if (Player.money.lt(nodeObj.calculateLevelUpgradeCost(1))) {return 0;} if (Player.money.lt(nodeObj.calculateLevelUpgradeCost(1))) {
return 0;
}
var min = 1; var min = 1;
var max = CONSTANTS.HacknetNodeMaxLevel - 1; var max = CONSTANTS.HacknetNodeMaxLevel - 1;
var levelsToMax = CONSTANTS.HacknetNodeMaxLevel - nodeObj.level; var levelsToMax = CONSTANTS.HacknetNodeMaxLevel - nodeObj.level;
@ -346,6 +387,7 @@ function displayHacknetNodesContent() {
for (var i = 0; i < Player.hacknetNodes.length; ++i) { for (var i = 0; i < Player.hacknetNodes.length; ++i) {
createHacknetNodeDomElement(Player.hacknetNodes[i]); createHacknetNodeDomElement(Player.hacknetNodes[i]);
} }
updateHacknetNodesContent(); updateHacknetNodesContent();
} }
@ -353,8 +395,11 @@ function displayHacknetNodesContent() {
function updateHacknetNodesContent() { function updateHacknetNodesContent() {
//Set purchase button to inactive if not enough money, and update its price display //Set purchase button to inactive if not enough money, and update its price display
var cost = getCostOfNextHacknetNode(); var cost = getCostOfNextHacknetNode();
var purchaseButton = document.getElementById("hacknet-nodes-purchase-button"); var purchaseButton = getElementById("hacknet-nodes-purchase-button");
purchaseButton.innerHTML = "Purchase Hacknet Node - $" + formatNumber(cost, 2); var formattedCost = formatNumber(cost, 2);
updateText("hacknet-nodes-purchase-button", "Purchase Hacknet Node - $" + formattedCost);
if (Player.money.lt(cost)) { if (Player.money.lt(cost)) {
purchaseButton.setAttribute("class", "a-link-button-inactive"); purchaseButton.setAttribute("class", "a-link-button-inactive");
} else { } else {
@ -362,9 +407,8 @@ function updateHacknetNodesContent() {
} }
//Update player's money //Update player's money
var moneyElem = document.getElementById("hacknet-nodes-money"); updateText("hacknet-nodes-player-money", "$" + formatNumber(Player.money.toNumber(), 2));
moneyElem.innerHTML = "Money: $" + formatNumber(Player.money.toNumber(), 2) + "<br>" + updateText("hacknet-nodes-total-production", "$" + formatNumber(Player.totalHacknetNodeProduction, 2) + " / second");
"Total production from all Hacknet Nodes: $" + formatNumber(Player.totalHacknetNodeProduction, 2) + " / second";
//Update information in each owned hacknet node //Update information in each owned hacknet node
for (var i = 0; i < Player.hacknetNodes.length; ++i) { for (var i = 0; i < Player.hacknetNodes.length; ++i) {
@ -376,29 +420,46 @@ function updateHacknetNodesContent() {
function createHacknetNodeDomElement(nodeObj) { function createHacknetNodeDomElement(nodeObj) {
var nodeName = nodeObj.name; var nodeName = nodeObj.name;
var listItem = document.createElement("li"); var nodeLevelContainer = createElement("div", {
listItem.setAttribute("class", "hacknet-node"); class: "hacknet-node-level-container row",
innerHTML: "<p>Level:</p><span class=\"text upgradable-info\" id=\"hacknet-node-level-" + nodeName + "\"></span>"
});
var span = document.createElement("span"); var nodeRamContainer = createElement("div", {
span.style.display = "inline"; class: "hacknet-node-ram-container row",
innerHTML: "<p>RAM:</p><span class=\"text upgradable-info\" id=\"hacknet-node-ram-" + nodeName + "\"></span>"
});
var buttonDiv = document.createElement("div"); var nodeCoresContainer = createElement("div", {
buttonDiv.setAttribute("class", "hacknet-node-button-div"); class: "hacknet-node-cores-container row",
innerHTML: "<p>Cores:</p><span class=\"text upgradable-info\" id=\"hacknet-node-cores-" + nodeName + "\"><span>"
})
var containingDiv = createElement("div", {
class: "hacknet-node-container",
innerHTML: "<div class=\"hacknet-node-name-container row\">" +
"<p>Node name:</p>" +
"<span class=\"text\" id=\"hacknet-node-name-" + nodeName + "\"></span>" +
"</div>" +
"<div class=\"hacknet-node-production-container row\">" +
"<p>Production:</p>" +
"<span class=\"text\" id=\"hacknet-node-total-production-" + nodeName + "\"></span>" +
"<span class=\"text\" id=\"hacknet-node-production-rate-" + nodeName + "\"></span>" +
"</div>"
});
containingDiv.appendChild(nodeLevelContainer);
containingDiv.appendChild(nodeRamContainer);
containingDiv.appendChild(nodeCoresContainer);
//Text var listItem = createElement("li", {
var txt = document.createElement("p"); class: "hacknet-node"
//txt.setAttribute("id", "hacknet-node-text-" + nodeName); });
txt.id = "hacknet-node-text-" + nodeName; listItem.appendChild(containingDiv);
//Upgrade buttons //Upgrade buttons
var upgradeLevelButton = document.createElement("a"); nodeLevelContainer.appendChild(createElement("a", {
var upgradeRamButton = document.createElement("a"); id: "hacknet-node-upgrade-level-" + nodeName,
var upgradeCoreButton = document.createElement("a"); class: "a-link-button-inactive",
clickListener: function() {
//upgradeLevelButton.setAttribute("id", "hacknet-node-upgrade-level-" + nodeName);
upgradeLevelButton.id = "hacknet-node-upgrade-level-" + nodeName;
upgradeLevelButton.setAttribute("class", "a-link-button-inactive");
upgradeLevelButton.addEventListener("click", function() {
var numUpgrades = hacknetNodePurchaseMultiplier; var numUpgrades = hacknetNodePurchaseMultiplier;
if (hacknetNodePurchaseMultiplier == 0) { if (hacknetNodePurchaseMultiplier == 0) {
numUpgrades = getMaxNumberLevelUpgrades(nodeObj); numUpgrades = getMaxNumberLevelUpgrades(nodeObj);
@ -406,31 +467,28 @@ function createHacknetNodeDomElement(nodeObj) {
nodeObj.purchaseLevelUpgrade(numUpgrades); nodeObj.purchaseLevelUpgrade(numUpgrades);
updateHacknetNodesContent(); updateHacknetNodesContent();
return false; return false;
}); }
//upgradeRamButton.setAttribute("id", "hacknet-node-upgrade-ram-" + nodeName); }));
upgradeRamButton.id = "hacknet-node-upgrade-ram-" + nodeName;
upgradeRamButton.setAttribute("class", "a-link-button-inactive"); nodeRamContainer.appendChild(createElement("a", {
upgradeRamButton.addEventListener("click", function() { id: "hacknet-node-upgrade-ram-" + nodeName,
class: "a-link-button-inactive",
clickListener: function() {
nodeObj.purchaseRamUpgrade(); nodeObj.purchaseRamUpgrade();
updateHacknetNodesContent(); updateHacknetNodesContent();
return false; return false;
}); }
//upgradeCoreButton.setAttribute("id", "hacknet-node-upgrade-core-" + nodeName); }));
upgradeCoreButton.id = "hacknet-node-upgrade-core-" + nodeName;
upgradeCoreButton.setAttribute("class", "a-link-button-inactive"); nodeCoresContainer.appendChild(createElement("a", {
upgradeCoreButton.addEventListener("click", function() { id: "hacknet-node-upgrade-core-" + nodeName,
class: "a-link-button-inactive",
clickListener: function() {
nodeObj.purchaseCoreUpgrade(); nodeObj.purchaseCoreUpgrade();
updateHacknetNodesContent(); updateHacknetNodesContent();
return false; return false;
}); }
}));
//Put all the components together in the li element
span.appendChild(txt);
buttonDiv.appendChild(upgradeLevelButton);
buttonDiv.appendChild(upgradeRamButton);
buttonDiv.appendChild(upgradeCoreButton);
span.appendChild(buttonDiv);
listItem.appendChild(span);
document.getElementById("hacknet-nodes-list").appendChild(listItem); document.getElementById("hacknet-nodes-list").appendChild(listItem);
@ -441,20 +499,19 @@ function createHacknetNodeDomElement(nodeObj) {
//Updates information on a single hacknet node DOM element //Updates information on a single hacknet node DOM element
function updateHacknetNodeDomElement(nodeObj) { function updateHacknetNodeDomElement(nodeObj) {
var nodeName = nodeObj.name; var nodeName = nodeObj.name;
var txt = document.getElementById("hacknet-node-text-" + nodeName);
if (txt == null) {throw new Error("Cannot find text element");} updateText("hacknet-node-name-" + nodeName, nodeName);
txt.innerHTML = "Node name: " + nodeName + "<br>" + updateText("hacknet-node-total-production-" + nodeName, "$" + formatNumber(nodeObj.totalMoneyGenerated, 2));
"Production: $" + formatNumber(nodeObj.totalMoneyGenerated, 2) + updateText("hacknet-node-production-rate-" + nodeName, "($" + formatNumber(nodeObj.moneyGainRatePerSecond, 2) + " / second)");
" ($" + formatNumber(nodeObj.moneyGainRatePerSecond, 2) + " / second) <br>" + updateText("hacknet-node-level-" + nodeName, nodeObj.level);
"Level: " + nodeObj.level + "<br>" + updateText("hacknet-node-ram-" + nodeName, nodeObj.ram + "GB");
"RAM: " + nodeObj.ram + "GB<br>" + updateText("hacknet-node-cores-" + nodeName, nodeObj.cores);
"Cores: " + nodeObj.cores;
//Upgrade level //Upgrade level
var upgradeLevelButton = document.getElementById("hacknet-node-upgrade-level-" + nodeName); var upgradeLevelButton = getElementById("hacknet-node-upgrade-level-" + nodeName);
if (upgradeLevelButton == null) {throw new Error("Cannot find upgrade level button element");}
if (nodeObj.level >= CONSTANTS.HacknetNodeMaxLevel) { if (nodeObj.level >= CONSTANTS.HacknetNodeMaxLevel) {
upgradeLevelButton.innerHTML = "MAX LEVEL"; updateText("hacknet-node-upgrade-level-" + nodeName, "MAX LEVEL");
upgradeLevelButton.setAttribute("class", "a-link-button-inactive"); upgradeLevelButton.setAttribute("class", "a-link-button-inactive");
} else { } else {
var multiplier = 0; var multiplier = 0;
@ -467,8 +524,7 @@ function updateHacknetNodeDomElement(nodeObj) {
} }
var upgradeLevelCost = nodeObj.calculateLevelUpgradeCost(multiplier); var upgradeLevelCost = nodeObj.calculateLevelUpgradeCost(multiplier);
upgradeLevelButton.innerHTML = "Upgrade Hacknet Node Level x" + multiplier + updateText("hacknet-node-upgrade-level-" + nodeName, "Upgrade x" + multiplier + " - $" + formatNumber(upgradeLevelCost, 2))
" - $" + formatNumber(upgradeLevelCost, 2);
if (Player.money.lt(upgradeLevelCost)) { if (Player.money.lt(upgradeLevelCost)) {
upgradeLevelButton.setAttribute("class", "a-link-button-inactive"); upgradeLevelButton.setAttribute("class", "a-link-button-inactive");
} else { } else {
@ -477,14 +533,14 @@ function updateHacknetNodeDomElement(nodeObj) {
} }
//Upgrade RAM //Upgrade RAM
var upgradeRamButton = document.getElementById("hacknet-node-upgrade-ram-" + nodeName); var upgradeRamButton = getElementById("hacknet-node-upgrade-ram-" + nodeName);
if (upgradeRamButton == null) {throw new Error("Cannot find upgrade ram button element");}
if (nodeObj.ram >= CONSTANTS.HacknetNodeMaxRam) { if (nodeObj.ram >= CONSTANTS.HacknetNodeMaxRam) {
upgradeRamButton.innerHTML = "MAX RAM"; updateText("hacknet-node-upgrade-ram-" + nodeName, "MAX RAM");
upgradeRamButton.setAttribute("class", "a-link-button-inactive"); upgradeRamButton.setAttribute("class", "a-link-button-inactive");
} else { } else {
var upgradeRamCost = nodeObj.calculateRamUpgradeCost(); var upgradeRamCost = nodeObj.calculateRamUpgradeCost();
upgradeRamButton.innerHTML = "Upgrade Hacknet Node RAM - $" + formatNumber(upgradeRamCost, 2); updateText("hacknet-node-upgrade-ram-" + nodeName, "Upgrade - $" + formatNumber(upgradeRamCost, 2));
if (Player.money.lt(upgradeRamCost)) { if (Player.money.lt(upgradeRamCost)) {
upgradeRamButton.setAttribute("class", "a-link-button-inactive"); upgradeRamButton.setAttribute("class", "a-link-button-inactive");
} else { } else {
@ -493,14 +549,14 @@ function updateHacknetNodeDomElement(nodeObj) {
} }
//Upgrade Cores //Upgrade Cores
var upgradeCoreButton = document.getElementById("hacknet-node-upgrade-core-" + nodeName); var upgradeCoreButton = getElementById("hacknet-node-upgrade-core-" + nodeName);
if (upgradeCoreButton == null) {throw new Error("Cannot find upgrade cores button element");}
if (nodeObj.cores >= CONSTANTS.HacknetNodeMaxCores) { if (nodeObj.cores >= CONSTANTS.HacknetNodeMaxCores) {
upgradeCoreButton.innerHTML = "MAX CORES"; updateText("hacknet-node-upgrade-core-" + nodeName, "MAX CORES");
upgradeCoreButton.setAttribute("class", "a-link-button-inactive"); upgradeCoreButton.setAttribute("class", "a-link-button-inactive");
} else { } else {
var upgradeCoreCost = nodeObj.calculateCoreUpgradeCost(); var upgradeCoreCost = nodeObj.calculateCoreUpgradeCost();
upgradeCoreButton.innerHTML = "Purchase additional CPU Core - $" + formatNumber(upgradeCoreCost, 2); updateText("hacknet-node-upgrade-core-" + nodeName, "Upgrade - $" + formatNumber(upgradeCoreCost, 2));
if (Player.money.lt(upgradeCoreCost)) { if (Player.money.lt(upgradeCoreCost)) {
upgradeCoreButton.setAttribute("class", "a-link-button-inactive"); upgradeCoreButton.setAttribute("class", "a-link-button-inactive");
} else { } else {
@ -520,8 +576,12 @@ function updatePlayerHacknetNodeWrappers() {
if (Player.hacknetNodeWrappers.length !== Player.hacknetNodes.length) { if (Player.hacknetNodeWrappers.length !== Player.hacknetNodes.length) {
return createPlayerHacknetNodeWrappers(); return createPlayerHacknetNodeWrappers();
} }
for (var i = 0; i < Player.hacknetNodeWrappers.length; ++i) { for (var i = 0; i < Player.hacknetNodeWrappers.length; ++i) {
if (!(Player.hacknetNodeWrappers[i] instanceof HacknetNodeWrapper)) {return createPlayerHacknetNodeWrappers();} if (!(Player.hacknetNodeWrappers[i] instanceof HacknetNodeWrapper)) {
return createPlayerHacknetNodeWrappers();
}
Player.hacknetNodeWrappers[i].level = Player.hacknetNodes[i].level; Player.hacknetNodeWrappers[i].level = Player.hacknetNodes[i].level;
Player.hacknetNodeWrappers[i].ram = Player.hacknetNodes[i].ram; Player.hacknetNodeWrappers[i].ram = Player.hacknetNodes[i].ram;
Player.hacknetNodeWrappers[i].cores = Player.hacknetNodes[i].cores; Player.hacknetNodeWrappers[i].cores = Player.hacknetNodes[i].cores;
@ -537,6 +597,7 @@ function processAllHacknetNodeEarnings(numCycles) {
for (var i = 0; i < Player.hacknetNodes.length; ++i) { for (var i = 0; i < Player.hacknetNodes.length; ++i) {
total += processSingleHacknetNodeEarnings(numCycles, Player.hacknetNodes[i]); total += processSingleHacknetNodeEarnings(numCycles, Player.hacknetNodes[i]);
} }
return total; return total;
} }
@ -544,9 +605,10 @@ function processSingleHacknetNodeEarnings(numCycles, nodeObj) {
var cyclesPerSecond = 1000 / Engine._idleSpeed; var cyclesPerSecond = 1000 / Engine._idleSpeed;
var earningPerCycle = nodeObj.moneyGainRatePerSecond / cyclesPerSecond; var earningPerCycle = nodeObj.moneyGainRatePerSecond / cyclesPerSecond;
if (isNaN(earningPerCycle)) { if (isNaN(earningPerCycle)) {
console.log("ERROR: Hacknet Node Calculated earnings is NaN"); console.error("Hacknet Node '" + nodeObj.name + "' Calculated earnings is NaN");
earningPerCycle = 0; earningPerCycle = 0;
} }
var totalEarnings = numCycles * earningPerCycle; var totalEarnings = numCycles * earningPerCycle;
nodeObj.totalMoneyGenerated += totalEarnings; nodeObj.totalMoneyGenerated += totalEarnings;
nodeObj.onlineTimeSeconds += (numCycles * (Engine._idleSpeed / 1000)); nodeObj.onlineTimeSeconds += (numCycles * (Engine._idleSpeed / 1000));
@ -560,10 +622,21 @@ function getHacknetNode(name) {
return Player.hacknetNodes[i]; return Player.hacknetNodes[i];
} }
} }
return null; return null;
} }
export {hacknetNodesInit, HacknetNode, purchaseHacknet, updateTotalHacknetProduction, export {
getCostOfNextHacknetNode, updateHacknetNodesMultiplierButtons, getMaxNumberLevelUpgrades, HacknetNode,
displayHacknetNodesContent, updateHacknetNodesContent, processAllHacknetNodeEarnings, createPlayerHacknetNodeWrappers,
getHacknetNode, createPlayerHacknetNodeWrappers}; displayHacknetNodesContent,
getCostOfNextHacknetNode,
getHacknetNode,
getMaxNumberLevelUpgrades,
hacknetNodesInit,
processAllHacknetNodeEarnings,
purchaseHacknet,
updateHacknetNodesContent,
updateHacknetNodesMultiplierButtons,
updateTotalHacknetProduction
};

@ -113,7 +113,7 @@ function giveSourceFile(bitNodeNumber) {
} }
if (alreadyOwned && ownedSourceFile) { if (alreadyOwned && ownedSourceFile) {
if (ownedSourceFile.lvl >= 3) { if (ownedSourceFile.lvl >= 3 && ownedSourceFile.n !== 12) {
dialogBoxCreate("The Source-File for the BitNode you just destroyed, " + sourceFile.name + ", " + dialogBoxCreate("The Source-File for the BitNode you just destroyed, " + sourceFile.name + ", " +
"is already at max level!"); "is already at max level!");
} else { } else {
@ -208,7 +208,7 @@ function loadBitVerse(destroyedBitNodeNum, flume=false) {
var elemId = "bitnode-" + i.toString(); var elemId = "bitnode-" + i.toString();
var elem = clearEventListeners(elemId); var elem = clearEventListeners(elemId);
if (elem == null) {return;} if (elem == null) {return;}
if (i === 1 || i === 2 || i === 3 || i === 4 || i === 5 || i === 6 || i === 8 || i === 11) { if (i === 1 || i === 2 || i === 3 || i === 4 || i === 5 || i === 6 || i === 8 || i === 11 || i === 12) {
elem.addEventListener("click", function() { elem.addEventListener("click", function() {
var bitNodeKey = "BitNode" + i; var bitNodeKey = "BitNode" + i;
var bitNode = BitNodes[bitNodeKey]; var bitNode = BitNodes[bitNodeKey];

@ -66,7 +66,7 @@ function initSourceFiles() {
"Level 1: 24%<br>" + "Level 1: 24%<br>" +
"Level 2: 36%<br>" + "Level 2: 36%<br>" +
"Level 3: 42%<br>"); "Level 3: 42%<br>");
SourceFiles["SourceFile12"] = new SourceFile(12); SourceFiles["SourceFile12"] = new SourceFile(12, "This Source-File increases all your multipliers by 1% per level");
} }
function PlayerOwnedSourceFile(number, level) { function PlayerOwnedSourceFile(number, level) {
@ -181,6 +181,42 @@ function applySourceFile(srcFile) {
Player.work_money_mult *= incMult; Player.work_money_mult *= incMult;
Player.company_rep_mult *= incMult; Player.company_rep_mult *= incMult;
break; break;
case 12: //The testing ground
const inc = Math.pow(1.01, srcFile.lvl);
const dec = Math.pow(0.99, srcFile.lvl);
Player.hacking_chance_mult *= inc;
Player.hacking_speed_mult *= inc;
Player.hacking_money_mult *= inc;
Player.hacking_grow_mult *= inc;
Player.hacking_mult *= inc;
Player.strength_mult *= inc;
Player.defense_mult *= inc;
Player.dexterity_mult *= inc;
Player.agility_mult *= inc;
Player.charisma_mult *= inc;
Player.hacking_exp_mult *= inc;
Player.strength_exp_mult *= inc;
Player.defense_exp_mult *= inc;
Player.dexterity_exp_mult *= inc;
Player.agility_exp_mult *= inc;
Player.charisma_exp_mult *= inc;
Player.company_rep_mult *= inc;
Player.faction_rep_mult *= inc;
Player.crime_money_mult *= inc;
Player.crime_success_mult *= inc;
Player.hacknet_node_money_mult *= inc;
Player.hacknet_node_purchase_cost_mult *= dec;
Player.hacknet_node_ram_cost_mult *= dec;
Player.hacknet_node_core_cost_mult *= dec;
Player.hacknet_node_level_cost_mult *= dec;
Player.work_money_mult *= inc;
default: default:
console.log("ERROR: Invalid source file number: " + srcFile.n); console.log("ERROR: Invalid source file number: " + srcFile.n);
break; break;

@ -74,6 +74,21 @@ function removeChildrenFromElement(el) {
} }
} }
/**
* Returns a reference to the first object with the specified value of the ID or NAME attribute, throwing an error if it is unable to find it.
* @param {string} elementId The HTML ID to retrieve the element by.
* @returns {HTMLElement} The single element.
* @throws {Error} When the 'idString' cannot be found.
*/
function getElementById(elementId) {
var el = document.getElementById(elementId);
if (el == null) {
throw new Error("Unable to find element with id '" + elementId + "'");
}
return el;
}
function createElement(type, params={}) { function createElement(type, params={}) {
var el = document.createElement(type); var el = document.createElement(type);
if (params.id) {el.id = params.id;} if (params.id) {el.id = params.id;}
@ -260,4 +275,4 @@ export {sizeOfObject, clearObject, addOffset, clearEventListeners, getRandomInt,
removeElementById, removeElement, createElement, createAccordionElement, removeElementById, removeElement, createElement, createAccordionElement,
appendLineBreaks, appendLineBreaks,
removeChildrenFromElement, createPopup, clearSelector, exceptionAlert, removeChildrenFromElement, createPopup, clearSelector, exceptionAlert,
createProgressBarText}; createProgressBarText, getElementById};