v0.34.0 changes

This commit is contained in:
danielyxie 2017-12-06 21:45:47 -06:00
parent 9e5db4b644
commit 3f61ec1cab
13 changed files with 1026 additions and 262 deletions

@ -1,5 +1,6 @@
#cmpy-mgmt-container p,
#cmpy-mgmt-container a {
#cmpy-mgmt-container a,
#cmpy-mgmt-container div {
font-size: 14px;
}
@ -98,3 +99,36 @@
padding:2px;
border:1px solid white;
}
/* Exporting materials/products */
.cmpy-mgmt-existing-export {
border:1px solid white;
border-radius:25px;
margin:4px;
padding:4px;
}
.cmpy-mgmt-existing-export:hover {
background-color:#333333;
}
/* Upgrades */
.cmpy-mgmt-upgrade-container {
border:1px solid white;
width: 60%;
margin:4px;
}
.cmpy-mgmt-upgrade-div {
border:1px solid white;
margin:4px;
padding:12px;
border-radius:25px;
width:95%;
color:var(--my-font-color);
}
.cmpy-mgmt-upgrade-div:hover {
background-color:#333333;
}

655
dist/bundle.js vendored

File diff suppressed because it is too large Load Diff

@ -905,7 +905,7 @@
<span class="tooltiptext">
The minimum number of milliseconds it takes to execute an operation in Netscript.
Setting this too low can result in poor performance if you have many scripts running.
The default value is 100ms.
The default value is 50ms.
</span>
</label>

@ -352,7 +352,6 @@ Product.prototype.finishProduct = function(employeeProd, industry) {
var advMult = 1 + (Math.pow(this.advCost, 0.1) / 100);
console.log("advMult: " + advMult);
this.mku = 100 / (advMult * this.qlt * (busRatio + mgmtRatio));
console.log("product mku: " + this.mku);
this.dmd = industry.awareness === 0 ? 100 : Math.min(100, advMult * (100 * (industry.popularity / industry.awareness)));
this.cmp = getRandomInt(0, 70);
@ -848,7 +847,7 @@ Industry.prototype.updateWarehouseSizeUsed = function(warehouse) {
}
}
Industry.prototype.process = function(marketCycles=1, state) {
Industry.prototype.process = function(marketCycles=1, state, company) {
this.state = state;
//At the start of a cycle, store and reset revenue/expenses
@ -876,7 +875,7 @@ Industry.prototype.process = function(marketCycles=1, state) {
}
//Process production, purchase, and import/export of materials
var res = this.processMaterials(marketCycles);
var res = this.processMaterials(marketCycles, company);
this.thisCycleRevenue = this.thisCycleRevenue.plus(res[0]);
this.thisCycleExpenses = this.thisCycleExpenses.plus(res[1]);
@ -936,7 +935,7 @@ Industry.prototype.processProductMarket = function(marketCycles=1) {
}
//Process production, purchase, and import/export of materials
Industry.prototype.processMaterials = function(marketCycles=1) {
Industry.prototype.processMaterials = function(marketCycles=1, company) {
var revenue = 0, expenses = 0;
for (var i = 0; i < Cities.length; ++i) {
var city = Cities[i], office = this.offices[city];
@ -1113,9 +1112,39 @@ Industry.prototype.processMaterials = function(marketCycles=1) {
break;
/* TODO Process Export of materials */
case "EXPORT":
for (var matName in warehouse.materials) {
if (warehouse.materials.hasOwnProperty(matName)) {
var mat = warehouse.materials[matName];
for (var expI = 0; expI < mat.exp.length; ++expI) {
var exp = mat.exp[expI];
var amt = exp.amt * SecsPerMarketCycle * marketCycles;
if (mat.qty <= amt) {
amt = mat.qty;
}
if (amt === 0) {
break; //None left
}
for (var foo = 0; foo < company.divisions.length; ++foo) {
if (company.divisions[foo].name === exp.ind) {
var expIndustry = company.divisions[foo];
var expWarehouse = expIndustry.warehouses[exp.city];
if (!(expWarehouse instanceof Warehouse)) {
console.log("ERROR: Invalid export!");
break;
}
expWarehouse.materials[mat.name].qty += amt;
mat.qty -= amt;
break;
}
}
}
}
}
break;
case "START":
case "EXPORT":
break;
default:
console.log("ERROR: Invalid state: " + this.state);
@ -1257,7 +1286,6 @@ Industry.prototype.processProduct = function(marketCycles=1, product) {
//Since its a product, its production cost is increased for labor
product.pCost *= 3;
console.log("Product pCost:" + product.pCost);
var markup = 1, markupLimit = product.rat / product.mku;
if (product.sCost > product.pCost) {
@ -1826,21 +1854,31 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) {
totalExport += mat.exp[i].amt;
}
var totalGain = mat.buy + mat.prd + mat.imp - mat.sll - totalExport;
div.appendChild(createElement("p", {
innerHTML: "<p class='tooltip'>" + mat.name + ": " + formatNumber(mat.qty, 3) +
//If Market Research upgrades are unlocked, add competition and demand info
var cmpAndDmdText = "";
if (company.unlockUpgrades[2] === 1) {
cmpAndDmdText += "<br>Competition: " + formatNumber(mat.cmp, 3);
}
if (company.unlockUpgrades[3] === 1) {
cmpAndDmdText += "<br>Demand: " + formatNumber(mat.dmd, 3);
}
var innerTxt = "<p class='tooltip'>" + mat.name + ": " + formatNumber(mat.qty, 3) +
"(" + formatNumber(totalGain, 3) + "/s)" +
"<span class='tooltiptext'>Buy: " + formatNumber(mat.buy, 3) +
"/s<br>Prod: " + formatNumber(mat.prd, 3) + "/s<br>Sell: " + formatNumber(mat.sll, 3) +
"/s<br>Export: " + formatNumber(totalExport, 3) + "/s<br>Import: " +
formatNumber(mat.imp, 3) + "/s</span></p><br>" +
formatNumber(mat.imp, 3) + "/s" + cmpAndDmdText + "</span></p><br>" +
"<p class='tooltip'>MP: $" + formatNumber(mat.bCost, 2) +
"<span class='tooltiptext'>Market Price: The price you would pay if " +
"you were to buy this material on the market</span></p><br>" +
"<p class='tooltip'>Quality: " + formatNumber(mat.qlt, 2) +
"<span class='tooltiptext'>The quality of your material. Higher quality " +
"will lead to more sales</span></p>",
id: "cmpy-mgmt-warehouse-" + matName + "-text",
display:"inline-block",
"will lead to more sales</span></p>";
div.appendChild(createElement("p", {
innerHTML: innerTxt,
id: "cmpy-mgmt-warehouse-" + matName + "-text", display:"inline-block",
}));
var buttonPanel = createElement("div", {
@ -1885,9 +1923,8 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) {
}));
//Button to manage exports
buttonPanel.appendChild(createElement("a", {
innerText:"Export", display:"inline-block", class:"a-link-button",
clickListener:()=>{
if (company.unlockUpgrades[0] === 1) { //Export unlock upgrade
function createExportPopup() {
var popupId = "cmpy-mgmt-export-popup";
var exportTxt = createElement("p", {
innerText:"Select the industry and city to export this material to, as well as " +
@ -1922,7 +1959,6 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) {
} //End for
var currIndustry = industrySelector.options[industrySelector.selectedIndex].value;
console.log(currIndustry);
for (var i = 0; i < company.divisions.length; ++i) {
if (company.divisions[i].name == currIndustry) {
for (var cityName in company.divisions[i].warehouses) {
@ -1990,24 +2026,25 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) {
for (var i = 0; i < mat.exp.length; ++i) {
(function(i, mat, currExports){
currExports.push(createElement("div", {
class:"cmpy-mgmt-existing-export",
innerHTML: "Industry: " + mat.exp[i].ind + "<br>" +
"City: " + mat.exp[i].city + "<br>" +
"Amount/s: " + mat.exp[i].amt,
clickListener:()=>{
mat.exp[i].splice(i, 1);
//Go to the target city and decrease the mat.imp attribute for the corresponding material
for (var i = 0; i < company.divisions.length; ++i) {
if (company.divisions[i].name === mat.exp[i].ind) {
var warehouse = company.divisions[i].warehouses[mat.exp[i].city];
for (var j = 0; j < company.divisions.length; ++j) {
if (company.divisions[j].name === mat.exp[i].ind) {
var warehouse = company.divisions[j].warehouses[mat.exp[i].city];
if (warehouse instanceof Warehouse) {
warehouse.materials[matName].imp -= mat.exp[i].amt;
return false;
} else {
console.log("ERROR: Target city for export does not have warehouse in specified city");
}
}
}
mat.exp.splice(i, 1); //Remove export object
removeElementById(popupId);
createExportPopup();
}
}));
})(i, mat, currExports);
@ -2015,8 +2052,11 @@ Warehouse.prototype.createMaterialUI = function(mat, matName, parentRefs) {
createPopup(popupId, [exportTxt, industrySelector, citySelector, exportAmount,
exportBtn, cancelBtn, currExportsText].concat(currExports));
}
}));
buttonPanel.appendChild(createElement("a", {
innerText:"Export", display:"inline-block", class:"a-link-button",
clickListener:()=>{createExportPopup();}
}));
}
buttonPanel.appendChild(createElement("br", {})); // Force line break
@ -2318,6 +2358,81 @@ Warehouse.fromJSON = function(value) {
Reviver.constructors.Warehouse = Warehouse;
//Corporation Unlock Upgrades
//Upgrades for entire corporation, unlocks features, either you have it or you dont
//The structure is [index in Corporation feature upgrades array, price ]
var CorporationUnlockUpgrades = {
//Lets you export goods
"0": [0, 20e9, "Export",
"Develop infrastructure to export your materials to your other facilities. " +
"This allows you to move materials around between different divisions and cities."],
//Lets you buy exactly however many required materials you need for production
"1": [1, 999999e9, "Smart Supply", "NOT YET IMPLEMENTED!!!!!! - Use advanced AI to anticipate your supply needs. " +
"This allows you to purchase exactly however many materials you need for production."],
//Displays each material/product's demand
"2": [2, 25e9, "Market Research - Demand",
"Mine and analyze market data to determine the demand of all resources. " +
"The demand attribute, which affects sales, will be displayed for every material and product."],
//Display's each material/product's competition
"3": [3, 25e9, "Market Data - Competition",
"Mine and analyze market data to determine how much competition there is on the market " +
"for all resources. The competition attribute, which affects sales, will be displayed for " +
"for every material and product."],
}
//Corporation Upgrades
//Upgrades for entire corporation, levelable upgrades
//The structure is [index in Corporation upgrades array, base price, price mult, benefit mult (additive),
// name, desc]
var CorporationUpgrades = {
//Smart factories, increases production
"0": [0, 10e9, 1.07, 0.02,
"Smart Factories", "Advanced AI automatically optimizes the operation and productivity " +
"of factories. Each level of this upgrade increases your global production by 2% (additive)."],
//Smart warehouses, increases storage size
"1": [1, 20e9, 1.07, .1,
"Smart Storage", "Advanced AI automatically optimizes your warehouse storage methods. " +
"Each level of this upgrade increases your global warehouse storage size by 10% (additive)."],
//Advertise through dreams, passive popularity/ awareness gain
"2": [2, 100e9, 1.08, .001,
"DreamSense", "Use DreamSense LCC Technologies to advertise your corporation " +
"to consumers through their dreams. Each level of this upgrade provides a passive " +
"increase in awareness of your company by 0.001 / second."],
//Makes advertising more effective
"3": [3, 5e9, 1.11, 0.1,
"Wilson Analytics", "Purchase data and analysis from Wilson, a marketing research " +
"firm. Each level of this upgrades increases the effectiveness of your " +
"advertising by 10% (additive)."],
//Augmentation for employees, increases cre
"4": [4, 10e9, 1.05, 0.1,
"Nuoptimal Nootropic Injector Implants", "Purchase the Nuoptimal Nootropic " +
"Injector augmentation for your employees. Each level of this upgrade " +
"globally increases the creativity of your employees by 10% (additive)."],
//Augmentation for employees, increases cha
"5": [5, 10e9, 1.05, 0.1,
"Speech Processor Implants", "Purchase the Speech Processor augmentation for your employees. " +
"Each level of this upgrade globally increases the charisma of your employees by 10% (additive)."],
//Augmentation for employees, increases int
"6": [6, 10e9, 1.05, 0.1,
"Neural Acelerators", "Purchase the Neural Accelerator augmentation for your employees. " +
"Each level of this upgrade globally increases the intelligence of your employees " +
"by 10% (additive)."],
//Augmentation for employees, increases eff
"7": [7, 10e9, 1.05, 0.1,
"FocusWires", "Purchase the FocusWire augmentation for your employees. Each level " +
"of this upgrade globally increases the efficiency of your employees by 10% (additive)."],
}
function Corporation(params={}) {
this.name = params.name ? params.name : "The Corporation";
@ -2335,6 +2450,13 @@ function Corporation(params={}) {
this.sharePrice = 0;
this.storedCycles = 0;
var numUnlockUpgrades = Object.keys(CorporationUnlockUpgrades).length,
numUpgrades = Object.keys(CorporationUpgrades).length;
this.unlockUpgrades = Array(numUnlockUpgrades).fill(0);
this.upgrades = Array(numUpgrades).fill(0);
this.upgradeMultipliers = Array(numUpgrades).fill(1);
this.state = new CorporationState();
}
@ -2343,12 +2465,13 @@ Corporation.prototype.getState = function() {
}
Corporation.prototype.process = function(numCycles=1) {
var corp = this;
this.storedCycles += numCycles;
if (this.storedCycles >= CyclesPerIndustryStateCycle) {
var state = this.getState(), marketCycles = 1;
this.storedCycles -= (marketCycles * CyclesPerIndustryStateCycle);
this.divisions.forEach(function(ind) {
ind.process(marketCycles, state);
ind.process(marketCycles, state, corp);
});
//At the start of a new cycle, calculate profits from previous cycle
@ -2369,13 +2492,13 @@ Corporation.prototype.process = function(numCycles=1) {
}
Corporation.prototype.determineValuation = function() {
var val, profit = (this.revenue - this.expenses);
var val, profit = (this.revenue.minus(this.expenses)).toNumber();
if (this.public) {
val = 50e9 + this.funds + (profit * getRandomInt(7000, 8500));
val = 25e9 + this.funds.toNumber() + (profit * getRandomInt(7000, 8500));
val *= (Math.pow(1.1, this.divisions.length));
val = Math.max(val, 0);
} else {
val = 10e9 + Math.max(this.funds, 0); //Base valuation
val = 10e9 + Math.max(this.funds.toNumber(), 0); //Base valuation
if (profit > 0) {
val += (profit * getRandomInt(12e3, 14e3));
val *= (Math.pow(1.1, this.divisions.length));
@ -2483,12 +2606,46 @@ Corporation.prototype.updateSharePrice = function() {
} else {
this.sharePrice *= (1 - (Math.random() * 0.01));
}
if (this.sharePrice <= 0.01) {this.sharePrice = 0.01;}
}
//One time upgrades that unlock new features
Corporation.prototype.unlock = function(upgrade) {
var upgN = upgrade[0], price = upgrade[1];
while (this.unlockUpgrades.length <= upgN) {
this.unlockUpgrades.push(0);
}
if (this.funds.lt(price)) {
dialogBoxCreate("You don't have enough funds to unlock this!");
return;
}
this.unlockUpgrades[upgN] = 1;
this.funds = this.funds.minus(price);
}
//Levelable upgrades
Corporation.prototype.upgrade = function(upgrade) {
var upgN = upgrade[0], basePrice = upgrade[1], priceMult = upgrade[2],
upgradeAmt = upgrade[3]; //Amount by which the upgrade multiplier gets increased (additive)
while (this.upgrades.length <= upgN) {this.upgrades.push(0);}
while (this.upgradeMultipliers.length <= upgN) {this.upgradeMultipliers.push(1);}
var totalCost = basePrice * Math.pow(this.upgrades[upgN], priceMult);
if (this.funds.lt(totalCost)) {
dialogBoxCreate("You don't have enough funds to purchase this!");
return;
}
++this.upgrades[upgN];
this.funds = this.funds.minus(totalCost);
//Increase upgrade multiplier
this.upgradeMultipliers[upgN] = 1 + (this.upgrades[upgN] * upgradeAmt);
}
//Keep 'global' variables for DOM elements so we don't have to search
//through the DOM tree repeatedly when updating UI
var companyManagementDiv, companyManagementHeaderTabs, companyManagementPanel,
currentCityUi,
corporationUnlockUpgrades, corporationUpgrades,
industryOverviewPanel, industryOverviewText,
industryEmployeePanel, industryEmployeeText, industryEmployeeHireButton, industryEmployeeList,
industryOfficeUpgradeSizeButton,
@ -2756,7 +2913,7 @@ Corporation.prototype.displayCorporationOverviewContent = function() {
} else {
this.numShares -= shares;
this.issuedShares += shares;
//TODO ADD TO PLAYER MONEY
Player.gainMoney(shares * this.sharePrice);
removeElementById(popupId);
return false;
}
@ -2890,7 +3047,81 @@ Corporation.prototype.displayCorporationOverviewContent = function() {
companyManagementPanel.appendChild(goPublic);
}
//Update overview text
this.updateCorporationOverviewContent();
//Don't show upgrades if player hasn't opened any divisions
if (this.divisions.length <= 0) {return; }
//Corporation Upgrades
var upgradeContainer = createElement("div", {
class:"cmpy-mgmt-upgrade-container",
});
upgradeContainer.appendChild(createElement("h1", {
innerText:"Upgrades", margin:"6px", padding:"6px",
}));
//Unlock upgrades
var corp = this;
if (this.unlockUpgrades == null || this.upgrades == null) { //Backwards compatibility
var numUnlockUpgrades = Object.keys(CorporationUnlockUpgrades).length,
numUpgrades = Object.keys(CorporationUpgrades).length;
this.unlockUpgrades = Array(numUnlockUpgrades).fill(0);
this.upgrades = Array(numUpgrades).fill(0);
}
for (var i = 0; i < this.unlockUpgrades.length; ++i) {
(function(i, corp) {
if (corp.unlockUpgrades[i] === 0) {
var upgrade = CorporationUnlockUpgrades[i.toString()];
if (upgrade == null) {
console.log("ERROR: Could not find upgrade index " + i);
return;
}
upgradeContainer.appendChild(createElement("div", {
class:"cmpy-mgmt-upgrade-div",
innerHTML:upgrade[2] + " - " + numeral(upgrade[1]).format("$0.000a") + "<br><br>" + upgrade[3],
clickListener:()=>{
if (corp.funds.lt(upgrade[1])) {
dialogBoxCreate("Insufficient funds");
} else {
corp.unlock(upgrade);
corp.displayCorporationOverviewContent();
}
}
}));
}
})(i, corp);
}
//Levelable upgrades
/*
for (var i = 0; i < this.upgrades.length; ++i) {
(function(i, corp) {
var upgrade = CorporationUpgrades[i.toString()];
if (upgrade == null) {
console.log("ERROR: Could not find levelable upgrade index " + i);
return;
}
var baseCost = upgrade[1], priceMult = upgrade[2];
var cost = baseCost * Math.pow(corp.upgrades[i], priceMult);
upgradeContainer.appendChild(createElement("div", {
class:"cmpy-mgmt-upgrade-div",
innerHTML:upgrade[4] + " - " + numeral(cost).format("$0.000a") + "<br><br>" + upgrade[5],
clickListener:()=>{
if (corp.funds.lt(cost)) {
dialogBoxCreate("Insufficient funds");
} else {
corp.upgrade(upgrade);
corp.displayCorporationOverviewContent();
}
}
}));
})(i, corp);
}*/
companyManagementPanel.appendChild(upgradeContainer);
}
Corporation.prototype.updateCorporationOverviewContent = function() {
@ -3429,6 +3660,9 @@ Corporation.prototype.clearUI = function() {
companyManagementPanel = null;
currentCityUi = null;
corporationUnlockUpgrades = null;
corporationUpgrades = null;
industryOverviewPanel = null;
industryOverviewText = null;

@ -1,5 +1,5 @@
let CONSTANTS = {
Version: "0.33.0",
Version: "0.34.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
@ -129,44 +129,45 @@ let CONSTANTS = {
HackingMissionSpamTimeIncrease: 25000, //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.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)
HackingMissionDifficultyToHacking: 135, //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 " +
"that initially belong to neither you nor the enemy. The goal of the game is " +
"to capture all of the enemy's database nodes within the time limit. " +
"If you cannot capture all of the enemy's database nodes in the time limit, you will lose.<br><br>" +
"to capture all of the enemy's Database nodes within the time limit. " +
"If you fail to do this, you will lose.<br><br>" +
"Each Node has three stats: Attack, Defense, and HP. There are five different actions that " +
"a Node can take:<br><br> " +
"Attack - Targets an enemy Node and lowers its HP. The effectiveness is determined by the owner's Attack, the Player's " +
"hacking level, and the enemy's defense.<br>" +
"hacking level, and the enemy's defense.<br><br>" +
"Scan - Targets an enemy Node and lowers its Defense. The effectiveness is determined by the owner's Attack, the Player's hacking level, and the " +
"enemy's defense.<br>" +
"enemy's defense.<br><br>" +
"Weaken - Targets an enemy Node and lowers its Attack. The effectiveness is determined by the owner's Attack, the Player's hacking level, and the enemy's " +
"defense.<br>" +
"Fortify - Raises the Node's Defense. The effectiveness is determined by your hacking level.<br>" +
"defense.<br><br>" +
"Fortify - Raises the Node's Defense. The effectiveness is determined by your hacking level.<br><br>" +
"Overflow - Raises the Node's Attack but lowers its Defense. The effectiveness is determined by your hacking level.<br><br>" +
"Note that when determining the effectiveness of the above actions, the TOTAL Attack or Defense of the team is used, not just the " +
"Attack/Defense of the individual Node that is performing the action.<br><br>" +
"To capture a Node, you must lower its HP down to 0.<br><br>" +
"There are six different types of Nodes:<br><br>" +
"CPU Core - These are your main Nodes that are used to perform actions. Capable of performing every action<br>" +
"Firewall - Nodes with high defense. These Nodes cannot perform any actions<br>" +
"CPU Core - These are your main Nodes that are used to perform actions. Capable of performing every action<br><br>" +
"Firewall - Nodes with high defense. These Nodes can 'Fortify'<br><br>" +
"Database - A special type of Node. The player's objective is to conquer all of the enemy's Database Nodes within " +
"the time limit. These Nodes cannot perform any actions<br>" +
"the time limit. These Nodes cannot perform any actions<br><br>" +
"Spam - Conquering one of these Nodes will slow the enemy's trace, giving the player additional time to complete " +
"the mission. These Nodes cannot perform any actions<br>" +
"the mission. These Nodes cannot perform any actions<br><br>" +
"Transfer - Conquering one of these nodes will increase the Attack of all of your CPU Cores by a small fixed percentage. " +
"These Nodes are capable of performing every action except the 'Attack' action<br>" +
"Shield - Nodes with high defense. These Nodes cannot perform any actions<br><br>" +
"To assign an action to a Node, you must first select one of your Nodes. This can be done by simply clicking on it. Only " +
"one Node can be selected at a time, and it will be denoted with a white highlight. After selecting the Node, " +
"These Nodes are capable of performing every action except the 'Attack' action<br><br>" +
"Shield - Nodes with high defense. These Nodes can 'Fortify'<br><br>" +
"To assign an action to a Node, you must first select one of your Nodes. This can be done by simply clicking on it. Double-clicking " +
"a node will select all of your Nodes of the same type (e.g. select all CPU Core Nodes or all Transfer Nodes). Note that only Nodes " +
"that can perform actions (CPU Core, Transfer, Shield, Firewall) can be selected. Selected Nodes will be denoted with a white highlight. After selecting a Node or multiple Nodes, " +
"select its action using the Action Buttons near the top of the screen. Every action also has a corresponding keyboard " +
"shortcut.<br><br>" +
"For certain actions such as attacking, scanning, and weakening, the Node performing the action must have a target. To target " +
"another node, simply click-and-drag from the 'source' Node to a target. A Node can only have one target, and you can target " +
"any Node that is adjacent to one of your Nodes (immediately above, below, or to the side. NOT diagonal). Furthermore, only CPU Cores and Transfer Nodes " +
"can target, since they are the only ones that can perform actions. To remove a target, you can simply click on the line that represents " +
"can target, since they are the only ones that can perform the related actions. To remove a target, you can simply click on the line that represents " +
"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>" +
@ -1113,17 +1114,26 @@ let CONSTANTS = {
LatestUpdate:
"v0.34.0<br>" +
"-Added clear() and exit() Netscript functions<br>" +
"-When starting out or prestiging, you will now receive a 'Hacking Starter Guide'. It provides tips/pointers for new players<br>" +
"-Doubled the amount of RAM on low-level servers (up to required hacking level 150)<br>" +
"-Slightly increased experience gain from Infiltration<br>" +
"-buyStock(), sellStock(), shortStock(), and sellShort() Netscript function now return the stock price at which the transaction occurred, rather than a boolean. " +
"If the function fails for some reason, 0 will be returned.<br>" +
"-Hacking Mission Changes:<br>" +
"---You can now select multiple Nodes of the same type by double clicking. This allows you to set the " +
"action of all of selected nodes at once (e.g. set all Transfer Nodes to Fortify). Creating connections " +
"does not work with this multi-select functionality yet<br>" +
"---Shield and Firewall Nodes can now fortify<br>" +
"---The effects of Fortifying are now ~30% lower<br>" +
"---Conquering a Spam Node now increases your time limit by 25 secs instead of 15<br>" +
"---The effects of Fortifying are now ~5% lower<br>" +
"---Conquering a Spam Node now increases your time limit by 25 seconds instead of 15<br>" +
"---Damage dealt by Attacking was slightly reduced<br>" +
"---The effect of Scanning was slightly reduced<br>" +
""
"---Enemy CPU Core Nodes start with slightly more attack. Misc Nodes start with slightly less defense<br>" +
"-Corporation Management changes:<br>" +
"---Added several upgrades that unlock new features<br>" +
"---Implemented Exporting mechanic<br>" +
"---Fixed many bugs<br>"
}
export {CONSTANTS};

@ -1,6 +1,7 @@
import {Engine} from "./engine.js";
import {dialogBoxCreate} from "../utils/DialogBox.js";
import {clearEventListeners} from "../utils/HelperFunctions.js";
import {Engine} from "./engine.js";
import {Player} from "./Player.js";
import {dialogBoxCreate} from "../utils/DialogBox.js";
import {clearEventListeners} from "../utils/HelperFunctions.js";
/* InteractiveTutorial.js */
let iTutorialSteps = {
@ -646,7 +647,10 @@ function iTutorialEnd() {
document.getElementById("interactive-tutorial-container").style.display = "none";
dialogBoxCreate("If you are new to the game, the following links may be useful for you!<br><br>" +
"<a class='a-link-button' href='http://bitburner.wikia.com/wiki/Chapt3rs_Guide_to_Getting_Started_with_Bitburner' target='_blank'>Getting Started Guide</a>" +
"<a class='a-link-button' href='http://bitburner.wikia.com/wiki/Bitburner_Wiki' target='_blank'>Wiki</a>");
"<a class='a-link-button' href='http://bitburner.wikia.com/wiki/Bitburner_Wiki' target='_blank'>Wiki</a><br><br>" +
"The Beginner's Guide to Hacking was added to your home computer! It contains stop tips/pointers for starting out with the game. " +
"To read it, go to Terminal and enter<br><br>cat hackers-starting-handbook.lit");
Player.getHomeComputer().messages.push("hackers-starting-handbook.lit");
}
function iTutorialSetText(txt) {

@ -12,8 +12,8 @@ function Literature(title, filename, txt) {
function showLiterature(fn) {
var litObj = Literatures[fn];
if (litObj == null) {return;}
var txt = litObj.title + "<br><br>" +
"<i>" + litObj.txt + "</i>";
var txt = "<i>" + litObj.title + "</i><br><br>" +
litObj.txt;
dialogBoxCreate(txt);
}
@ -21,6 +21,24 @@ let Literatures = {}
function initLiterature() {
var title, fn, txt;
title = "The Beginner's Guide to Hacking";
fn = "hackers-starting-handbook.lit";
txt = "When starting out, hacking is the most profitable way to earn money and progress. This " +
"is a brief collection of tips/pointers on how to make the most out of your hacking scripts.<br><br>" +
"-hack() and grow() both work by percentages. hack() steals a certain percentage of the " +
"money on a server, and grow() increases the amount of money on a server by some percentage (multiplicatively)<br><br>" +
"-Because hack() and grow() work by percentages, they are more effective if the target server has a high amount of money. " +
"Therefore, you should try to increase the amount of money on a server (using grow()) to a certain amount before hacking it. Two " +
"import Netscript functions for this are getServerMoneyAvailable() and getServerMaxMoney()<br><br>" +
"-Keep security level low. Security level affects everything when hacking. Two important Netscript functions " +
"for this are getServerSecurityLevel() and getServerMinSecurityLevel()<br><br>" +
"-Purchase additional servers by visiting 'Alpha Enterprises' in the city. They are relatively cheap " +
"and give you valuable RAM to run more scripts early in the game<br><br>" +
"-Prioritize upgrading the RAM on your home computer. This can also be done at 'Alpha Enterprises'<br><br>" +
"-Many low level servers have free RAM. You can use this RAM to run your scripts. Use the scp Terminal or " +
"Netscript command to copy your scripts onto these servers and then run them.";
Literatures[fn] = new Literature(title, fn, txt);
title = "A Green Tomorrow";
fn = "A-Green-Tomorrow.lit";
txt = "Starting a few decades ago, there was a massive global movement towards the generation of renewable energy in an effort to " +

@ -22,7 +22,7 @@ function setInMission(bool, mission) {
//Keyboard shortcuts
$(document).keydown(function(e) {
if (inMission && currMission && currMission.selectedNode != null) {
if (inMission && currMission && currMission.selectedNode.length != 0) {
switch (e.keyCode) {
case 65: //a for Attack
currMission.actionButtons[0].click();
@ -186,7 +186,7 @@ function HackingMission(rep, fac) {
this.miscNodes = [];
this.selectedNode = null; //Which of the player's nodes is currently selected
this.selectedNode = []; //Which of the player's nodes are currently selected
this.actionButtons = []; //DOM buttons for actions
@ -230,15 +230,15 @@ HackingMission.prototype.init = function() {
//Randomly generate enemy nodes (CPU and Firewall) based on difficulty
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));
getRandomInt(Math.round(this.difficulty/3), Math.round(this.difficulty/3) + 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);
var randMult = addOffset(0.8 + (this.difficulty / 5), 10);
for (var i = 0; i < numNodes; ++i) {
var stats = {
atk: randMult * getRandomInt(75, 85),
def: randMult * getRandomInt(25, 35),
atk: randMult * getRandomInt(80, 86),
def: randMult * getRandomInt(5, 10),
hp: randMult * getRandomInt(210, 230)
}
this.enemyCores.push(new Node(NodeTypes.Core, stats));
@ -248,7 +248,7 @@ HackingMission.prototype.init = function() {
for (var i = 0; i < numFirewalls; ++i) {
var stats = {
atk: 0,
def: randMult * getRandomInt(80, 90),
def: randMult * getRandomInt(10, 20),
hp: randMult * getRandomInt(275, 300)
}
this.enemyNodes.push(new Node(NodeTypes.Firewall, stats));
@ -258,7 +258,7 @@ HackingMission.prototype.init = function() {
for (var i = 0; i < numDatabases; ++i) {
var stats = {
atk: 0,
def: randMult * getRandomInt(70, 85),
def: randMult * getRandomInt(30, 55),
hp: randMult * getRandomInt(210, 275)
}
var node = new Node(NodeTypes.Database, stats);
@ -398,71 +398,88 @@ HackingMission.prototype.createPageDom = function() {
//Set Action Button event listeners
this.actionButtons[0].addEventListener("click", ()=>{
if (!(this.selectedNode instanceof Node)) {
if (!(this.selectedNode.length > 0)) {
console.log("ERR: Pressing Action button without selected node");
return;
}
if (this.selectedNode.type !== NodeTypes.Core) {return;}
this.setActionButtonsActive(this.selectedNode.type);
if (this.selectedNode[0].type !== NodeTypes.Core) {return;}
this.setActionButtonsActive(this.selectedNode[0].type);
this.setActionButton(NodeActions.Attack, false); //Set attack button inactive
this.selectedNode.action = NodeActions.Attack;
this.selectedNode.forEach(function(node){
node.action = NodeActions.Attack;
});
});
this.actionButtons[1].addEventListener("click", ()=>{
if (!(this.selectedNode instanceof Node)) {
if (!(this.selectedNode.length > 0)) {
console.log("ERR: Pressing Action button without selected node");
return;
}
var nodeType = this.selectedNode.type;
var nodeType = this.selectedNode[0].type; //In a multiselect, every Node will have the same type
if (nodeType !== NodeTypes.Core && nodeType !== NodeTypes.Transfer) {return;}
this.setActionButtonsActive(nodeType);
this.setActionButton(NodeActions.Scan, false); //Set scan button inactive
this.selectedNode.action = NodeActions.Scan;
this.selectedNode.forEach(function(node){
node.action = NodeActions.Scan;
});
});
this.actionButtons[2].addEventListener("click", ()=>{
if (!(this.selectedNode instanceof Node)) {
if (!(this.selectedNode.length > 0)) {
console.log("ERR: Pressing Action button without selected node");
return;
}
var nodeType = this.selectedNode.type;
var nodeType = this.selectedNode[0].type; //In a multiselect, every Node will have the same type
if (nodeType !== NodeTypes.Core && nodeType !== NodeTypes.Transfer) {return;}
this.setActionButtonsActive(nodeType);
this.setActionButton(NodeActions.Weaken, false); //Set Weaken button inactive
this.selectedNode.action = NodeActions.Weaken;
this.selectedNode.forEach(function(node){
node.action = NodeActions.Weaken;
});
});
this.actionButtons[3].addEventListener("click", ()=>{
if (!(this.selectedNode instanceof Node)) {
if (!(this.selectedNode.length > 0)) {
console.log("ERR: Pressing Action button without selected node");
return;
}
this.setActionButtonsActive(this.selectedNode.type);
this.setActionButtonsActive(this.selectedNode[0].type);
this.setActionButton(NodeActions.Fortify, false); //Set Fortify button inactive
this.selectedNode.action = NodeActions.Fortify;
this.selectedNode.forEach(function(node){
node.action = NodeActions.Fortify;
});
});
this.actionButtons[4].addEventListener("click", ()=>{
if (!(this.selectedNode instanceof Node)) {
if (!(this.selectedNode.length > 0)) {
console.log("ERR: Pressing Action button without selected node");
return;
}
var nodeType = this.selectedNode.type;
var nodeType = this.selectedNode[0].type;
if (nodeType !== NodeTypes.Core && nodeType !== NodeTypes.Transfer) {return;}
this.setActionButtonsActive(this.selectedNode.type);
this.setActionButtonsActive(nodeType);
this.setActionButton(NodeActions.Overflow, false); //Set Overflow button inactive
this.selectedNode.action = NodeActions.Overflow;
this.selectedNode.forEach(function(node){
node.action = NodeActions.Overflow;
});
});
this.actionButtons[5].addEventListener("click", ()=>{
if (!(this.selectedNode instanceof Node)) {
if (!(this.selectedNode.length > 0)) {
console.log("ERR: Pressing Action button without selected node");
return;
}
if (this.selectedNode.conn) {
var endpoints = this.selectedNode.conn.endpoints;
endpoints[0].detachFrom(endpoints[1]);
}
this.selectedNode.forEach(function(node){
if (node.conn) {
var endpoints = node.conn.endpoints;
endpoints[0].detachFrom(endpoints[1]);
}
node.action = NodeActions.Fortify;
});
// if (this.selectedNode.conn) {
// var endpoints = this.selectedNode.conn.endpoints;
// endpoints[0].detachFrom(endpoints[1]);
// }
})
var timeDisplay = document.createElement("p");
@ -662,7 +679,7 @@ HackingMission.prototype.createMap = function() {
case 0: //Spam
var stats = {
atk: 0,
def: averageAttack * 1.15 + getRandomInt(10, 50),
def: averageAttack * 1.1 + getRandomInt(15, 45),
hp: randMult * getRandomInt(200, 225)
}
node = new Node(NodeTypes.Spam, stats);
@ -670,7 +687,7 @@ HackingMission.prototype.createMap = function() {
case 1: //Transfer
var stats = {
atk: 0,
def: averageAttack * 1.15 + getRandomInt(10, 50),
def: averageAttack * 1.1 + getRandomInt(15, 45),
hp: randMult * getRandomInt(250, 275)
}
node = new Node(NodeTypes.Transfer, stats);
@ -679,7 +696,7 @@ HackingMission.prototype.createMap = function() {
default:
var stats = {
atk: 0,
def: averageAttack * 1.15 + getRandomInt(25, 75),
def: averageAttack * 1.1 + getRandomInt(30, 70),
hp: randMult * getRandomInt(300, 320)
}
node = new Node(NodeTypes.Shield, stats);
@ -843,12 +860,40 @@ function selectNode(hackMissionInst, el) {
if (nodeObj == null) {console.log("Error getting Node object");}
if (!nodeObj.plyrCtrl) {return;}
if (hackMissionInst.selectedNode instanceof Node) {
hackMissionInst.selectedNode.deselect(hackMissionInst.actionButtons);
hackMissionInst.selectedNode = null;
}
clearAllSelectedNodes(hackMissionInst);
nodeObj.select(hackMissionInst.actionButtons);
hackMissionInst.selectedNode = nodeObj;
hackMissionInst.selectedNode.push(nodeObj);
}
function multiselectNode(hackMissionInst, el) {
var nodeObj = hackMissionInst.getNodeFromElement(el);
if (nodeObj == null) {console.log("ERROR: Getting Node Object in multiselectNode()");}
if (!nodeObj.plyrCtrl) {return;}
clearAllSelectedNodes(hackMissionInst);
var type = nodeObj.type;
if (type === NodeTypes.Core) {
hackMissionInst.playerCores.forEach(function(node) {
node.select(hackMissionInst.actionButtons);
hackMissionInst.selectedNode.push(node);
});
} else {
hackMissionInst.playerNodes.forEach(function(node) {
if (node.type === type) {
node.select(hackMissionInst.actionButtons);
hackMissionInst.selectedNode.push(node);
}
});
}
}
function clearAllSelectedNodes(hackMissionInst) {
if (hackMissionInst.selectedNode.length > 0) {
hackMissionInst.selectedNode.forEach(function(node){
node.deselect(hackMissionInst.actionButtons);
});
hackMissionInst.selectedNode.length = 0;
}
}
//Configures a DOM element representing a player-owned node to
@ -865,6 +910,12 @@ HackingMission.prototype.configurePlayerNodeElement = function(el) {
}
el.addEventListener("click", selectNodeWrapper);
function multiselectNodeWrapper() {
multiselectNode(self, el);
}
el.addEventListener("dblclick", multiselectNodeWrapper);
if (el.firstChild) {
el.firstChild.addEventListener("click", selectNodeWrapper);
}
@ -875,8 +926,12 @@ HackingMission.prototype.configurePlayerNodeElement = function(el) {
HackingMission.prototype.configureEnemyNodeElement = function(el) {
//Deselect node if it was the selected node
var nodeObj = this.getNodeFromElement(el);
if (this.selectedNode == nodeObj) {
nodeObj.deselect(this.actionButtons);
for (var i = 0; i < this.selectedNode.length; ++i) {
if (this.selectedNode[i] == nodeObj) {
nodeObj.deselect(this.actionButtons);
this.selectedNode.splice(i, 1);
break;
}
}
}
@ -1241,6 +1296,7 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
swapNodes(this.enemyNodes, this.playerNodes, targetNode);
} else {
swapNodes(this.playerNodes, this.enemyNodes, targetNode);
this.configureEnemyNodeElement(targetNode.el);
}
break;
case NodeTypes.Database:
@ -1282,6 +1338,7 @@ HackingMission.prototype.processNode = function(nodeObj, numCycles=1) {
this.configurePlayerNodeElement(targetNode.el);
} else {
swapNodes(isMiscNode ? this.miscNodes : this.playerNodes, this.enemyNodes, targetNode);
this.configureEnemyNodeElement(targetNode.el);
}
break;
}
@ -1420,7 +1477,7 @@ HackingMission.prototype.calculateWeakenEffect = function(atk, def, hacking=0) {
}
HackingMission.prototype.calculateFortifyEffect = function(hacking=0) {
return 0.6 * hacking / hackEffWeightSelf;
return 0.9 * hacking / hackEffWeightSelf;
}
HackingMission.prototype.calculateOverflowEffect = function(hacking=0) {

@ -493,6 +493,17 @@ 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;
},
exit : function() {
var server = getServer(workerScript.serverIp);
if (server == null) {
throw makeRuntimeRejectMsg(workerScript, "Error getting Server for this script in exit(). This is a bug please contact game dev");
}
if (killWorkerScript(workerScript.scriptRef, server.ip)) {
workerScript.scriptRef.log("Exiting...");
} else {
workerScript.scriptRef.log("Exit failed(). This is a bug please contact game developer");
}
},
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");
@ -1166,7 +1177,7 @@ function NetscriptFunctions(workerScript) {
if (!isNaN(port)) { //Write to port
//Port 1-10
if (port < 1 || port > 10) {
throw makeRuntimeRejectMsg(workerScript, "Trying to write to invalid port: " + port + ". Only ports 1-10 are valid.");
throw makeRuntimeRejectMsg(workerScript, "ERR: Trying to write to invalid port: " + port + ". Only ports 1-10 are valid.");
}
var portName = "Port" + String(port);
var port = NetscriptPorts[portName];
@ -1197,19 +1208,19 @@ function NetscriptFunctions(workerScript) {
}
return true;
} else {
throw makeRuntimeRejectMsg(workerScript, "Invalid argument passed in for port: " + port + ". Must be a number between 1 and 10");
throw makeRuntimeRejectMsg(workerScript, "Invalid argument passed in for write: " + port);
}
},
read : function(port) {
if (!isNaN(port)) { //Read from port
//Port 1-10
if (port < 1 || port > 10) {
throw makeRuntimeRejectMsg(workerScript, "Trying to write to invalid port: " + port + ". Only ports 1-10 are valid.");
throw makeRuntimeRejectMsg(workerScript, "ERR: Trying to read from invalid port: " + port + ". Only ports 1-10 are valid.");
}
var portName = "Port" + String(port);
var port = NetscriptPorts[portName];
if (port == null) {
throw makeRuntimeRejectMsg(workerScript, "Could not find port: " + port + ". This is a bug contact the game developer");
throw makeRuntimeRejectMsg(workerScript, "ERR: Could not find port: " + port + ". This is a bug contact the game developer");
}
if (port.length == 0) {
return "NULL PORT DATA";
@ -1229,9 +1240,35 @@ function NetscriptFunctions(workerScript) {
return "";
}
} else {
throw makeRuntimeRejectMsg(workerScript, "Invalid argument passed in for port: " + port + ". Must be a number between 1 and 10");
throw makeRuntimeRejectMsg(workerScript, "Invalid argument passed in for read(): " + port);
}
},
clear : function(port) {
if (!isNaN(port)) { //Clear port
if (port < 1 || port > 10) {
throw makeRuntimeRejectMsg(workerScript, "ERR: Trying to read from invalid port: " + port + ". Only ports 1-10 are valid");
}
var portName = "Port" + String(port);
var port = NetscriptPorts[portName];
if (port == null) {
throw makeRuntimeRejectMsg(workerScript, "ERR: Could not find port: " + port + ". This is a bug contact the game developer");
}
port.length = 0;
} else if (isString(port)) { //Clear text file
var fn = port;
var server = getServer(workerScript.serverIp);
if (server == null) {
throw makeRuntimeRejectMsg(workerScript, "Error getting Server for this script in clear(). This is a bug please contact game dev");
}
var txtFile = getTextFile(fn, server);
if (txtFile != null) {
txtFile.write("");
}
} else {
throw makeRuntimeRejectMsg(workerScript, "Invalid argument passed in for clear(): " + port);
}
return 0;
},
scriptRunning : function(scriptname, ip) {
var server = getServer(ip);
if (server == null) {

@ -376,6 +376,7 @@ PlayerObject.prototype.prestigeSourceFile = function() {
//BitNode 3: Corporatocracy
if (this.bitNodeN === 3) {this.money = new Decimal(150e9);}
this.corporation = 0;
//BitNode 8: Ghost of Wall Street
if (this.bitNodeN === 8) {this.money = new Decimal(100000000);}

@ -258,7 +258,8 @@ function calculateRamUsage(codeCopy) {
var sqlinjectCount = numOccurrences(codeCopy, "sqlinject(");
var runCount = numOccurrences(codeCopy, "run(");
var execCount = numOccurrences(codeCopy, "exec(");
var killCount = numOccurrences(codeCopy, "kill(") + numOccurrences(codeCopy, "killall(");
var killCount = numOccurrences(codeCopy, "kill(") + numOccurrences(codeCopy, "killall(") +
numOccurrences(codeCopy, "exit(");
var scpCount = numOccurrences(codeCopy, "scp(");
var hasRootAccessCount = numOccurrences(codeCopy, "hasRootAccess(");
var getHostnameCount = numOccurrences(codeCopy, "getHostname(") +
@ -295,7 +296,7 @@ function calculateRamUsage(codeCopy) {
numOccurrences(codeCopy, "deleteServer(") +
numOccurrences(codeCopy, "getPurchasedServers(");
var scriptRoundCount = numOccurrences(codeCopy, "round(");
var scriptWriteCount = numOccurrences(codeCopy, "write(");
var scriptWriteCount = numOccurrences(codeCopy, "write(") + numOccurrences(codeCopy, "clear(");
var scriptReadCount = numOccurrences(codeCopy, "read(");
var arbScriptCount = numOccurrences(codeCopy, "scriptRunning(") +
numOccurrences(codeCopy, "scriptKill(");

@ -402,23 +402,23 @@ function initForeignServers() {
AddToAllServers(JohnsonOrthopedicsServer);
//"Low level" targets
var FoodNStuffServer = new Server(createRandomIp(), "foodnstuff", "Food N Stuff Supermarket", false, false, false, 8);
var FoodNStuffServer = new Server(createRandomIp(), "foodnstuff", "Food N Stuff Supermarket", false, false, false, 16);
FoodNStuffServer.setHackingParameters(1, 2000000, 10, 5);
FoodNStuffServer.setPortProperties(0);
FoodNStuffServer.messages.push("sector-12-crime.lit");
AddToAllServers(FoodNStuffServer);
var SigmaCosmeticsServer = new Server(createRandomIp(), "sigma-cosmetics", "Sigma Cosmetics", false, false, false, 8);
var SigmaCosmeticsServer = new Server(createRandomIp(), "sigma-cosmetics", "Sigma Cosmetics", false, false, false, 16);
SigmaCosmeticsServer.setHackingParameters(5, 2300000, 10, 10);
SigmaCosmeticsServer.setPortProperties(0);
AddToAllServers(SigmaCosmeticsServer);
var JoesGunsServer = new Server(createRandomIp(), "joesguns", "Joe's Guns", false, false, false, 8);
var JoesGunsServer = new Server(createRandomIp(), "joesguns", "Joe's Guns", false, false, false, 16);
JoesGunsServer.setHackingParameters(10, 2500000, 15, 20);
JoesGunsServer.setPortProperties(0);
AddToAllServers(JoesGunsServer);
var Zer0NightclubServer = new Server(createRandomIp(), "zer0", "ZER0 Nightclub", false, false, false, 16);
var Zer0NightclubServer = new Server(createRandomIp(), "zer0", "ZER0 Nightclub", false, false, false, 32);
Zer0NightclubServer.setHackingParameters(75, 7500000, 25, 40);
Zer0NightclubServer.setPortProperties(1);
AddToAllServers(Zer0NightclubServer);
@ -428,40 +428,40 @@ function initForeignServers() {
NectarNightclubServer.setPortProperties(0);
AddToAllServers(NectarNightclubServer);
var NeoNightclubServer = new Server(createRandomIp(), "neo-net", "Neo Nightclub Network", false, false, false, 16);
var NeoNightclubServer = new Server(createRandomIp(), "neo-net", "Neo Nightclub Network", false, false, false, 32);
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, 32);
var SilverHelixServer = new Server(createRandomIp(), "silver-helix", "Silver Helix", false, false, false, 64);
SilverHelixServer.setHackingParameters(150, 45000000, 30, 30);
SilverHelixServer.setPortProperties(2);
SilverHelixServer.messages.push("new-triads.lit");
AddToAllServers(SilverHelixServer);
var HongFangTeaHouseServer = new Server(createRandomIp(), "hong-fang-tea", "HongFang Teahouse", false, false, false, 8);
var HongFangTeaHouseServer = new Server(createRandomIp(), "hong-fang-tea", "HongFang Teahouse", false, false, false, 16);
HongFangTeaHouseServer.setHackingParameters(30, 3000000, 15, 20);
HongFangTeaHouseServer.setPortProperties(0);
HongFangTeaHouseServer.messages.push("brighter-than-the-sun.lit");
AddToAllServers(HongFangTeaHouseServer);
var HaraKiriSushiBarServer = new Server(createRandomIp(), "harakiri-sushi", "HaraKiri Sushi Bar Network", false, false, false, 8);
var HaraKiriSushiBarServer = new Server(createRandomIp(), "harakiri-sushi", "HaraKiri Sushi Bar Network", false, false, false, 16);
HaraKiriSushiBarServer.setHackingParameters(40, 4000000, 15, 40);
HaraKiriSushiBarServer.setPortProperties(0);
AddToAllServers(HaraKiriSushiBarServer);
var PhantasyServer = new Server(createRandomIp(), "phantasy", "Phantasy Club", false, false, false, 16);
var PhantasyServer = new Server(createRandomIp(), "phantasy", "Phantasy Club", false, false, false, 32);
PhantasyServer.setHackingParameters(100, 24000000, 20, 35);
PhantasyServer.setPortProperties(2);
AddToAllServers(PhantasyServer);
var MaxHardwareServer = new Server(createRandomIp(), "max-hardware", "Max Hardware Store", false, false, false, 16);
var MaxHardwareServer = new Server(createRandomIp(), "max-hardware", "Max Hardware Store", false, false, false, 32);
MaxHardwareServer.setHackingParameters(80, 10000000, 15, 30);
MaxHardwareServer.setPortProperties(1);
AddToAllServers(MaxHardwareServer);
var OmegaSoftwareServer = new Server(createRandomIp(), "omega-net", "Omega Software", false, false, false, 16);
var OmegaSoftwareServer = new Server(createRandomIp(), "omega-net", "Omega Software", false, false, false, 32);
OmegaSoftwareServer.setHackingParameters(getRandomInt(180, 220), getRandomInt(60000000, 70000000), getRandomInt(25, 35), getRandomInt(30, 40));
OmegaSoftwareServer.setPortProperties(2);
OmegaSoftwareServer.messages.push("the-new-god.lit");
@ -473,7 +473,7 @@ function initForeignServers() {
CrushFitnessGymServer.setPortProperties(2);
AddToAllServers(CrushFitnessGymServer);
var IronGymServer = new Server(createRandomIp(), "iron-gym", "Iron Gym Network", false, false, false, 16);
var IronGymServer = new Server(createRandomIp(), "iron-gym", "Iron Gym Network", false, false, false, 32);
IronGymServer.setHackingParameters(100, 20000000, 30, 20);
IronGymServer.setPortProperties(1);
AddToAllServers(IronGymServer);
@ -697,6 +697,7 @@ function prestigeHomeComputer(homeComp) {
homeComp.programs.push(Programs.NukeProgram);
homeComp.messages.length = 0;
homeComp.messages.push("hackers-starting-handbook.lit");
}
//List of all servers that exist in the game, indexed by their ip

@ -1010,7 +1010,7 @@ let Terminal = {
//Check programs
var delTarget = commandArray[1];
if (delTarget.endsWith(".exe")) {
if (delTarget.includes(".exe")) {
for (var i = 0; i < s.programs.length; ++i) {
if (s.programs[i] == delTarget) {
s.programs.splice(i, 1);