Merge branch 'dev' into improve-get-script-ram

This commit is contained in:
Olivier Gagnon 2018-05-07 16:00:24 -04:00 committed by GitHub
commit dcc09d561e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 320 additions and 259 deletions

Binary file not shown.

Binary file not shown.

@ -779,6 +779,12 @@ scriptKill
Kills all scripts with the specified filename on the target server specified by *hostname/ip*, regardless of arguments. Returns
true if one or more scripts were successfully killed, and false if none were.
getScriptName
^^^^^^^^^^^^^
.. js:function:: getScriptName()
Returns the current script name
getScriptRam
^^^^^^^^^^^^

@ -17,6 +17,22 @@ hacknetnodes
accessed using *hacknetnodes[0]*. The fourth Hacknet Node you purchase will have the name
"hacknet-node-3" and can be accessed using *hacknetnodes[3]*.
Purchasing Hacknet Nodes
^^^^^^^^^^^^^^^^^^^^^^^^
The following is a list of supported functions for purchasing Hacknet Nodes.
.. js:function:: getNextHacknetNodeCost()
Returns the cost of purchasing a new Hacknet Node
.. js:function:: purchaseHacknetNode()
Purchases a new Hacknet Node. Returns a number with the index of the Hacknet Node. This index is equivalent to the number at the
end of the Hacknet Node's name (e.g The Hacknet Node named 'hacknet-node-4' will have an index of 4). If the player cannot afford
to purchase a new Hacknet Node then the function will return false.
Hacknet Node Member Variables
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -25,6 +41,11 @@ a value to these.
Note that these must be called on an element inside the *hacknetnodes* array, not the array itself.
.. js:attribute:: hacknetnodes[i].name
Returns the name of the corresponding Hacknet Node
.. js:attribute:: hacknetnodes[i].level
Returns the level of the corresponding Hacknet Node

@ -819,6 +819,18 @@
<input type="checkbox" name="settingsSuppressFactionInvites" id="settingsSuppressFactionInvites">
</fieldset>
<!-- Disable Terminal and Navigation Shortcuts -->
<fieldset>
<label for="settingsDisableHotkeys" class="tooltip">Disable Hotkeys:
<span class="tooltiptext">
If this is set, then most hotkeys (keyboard shortcuts) in the game are disabled.
This includes Terminal commands, hotkeys to navigate between different parts of the game,
and the "Save and Close (Ctrl + b)" hotkey in the Text Editor.
</span>
</label>
<input type="checkbox" name="settingsDisableHotkeys" id="settingsDisableHotkeys">
</fieldset>
<!-- Donate button -->
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank">
<input type="hidden" name="cmd" value="_s-xclick">

@ -4,156 +4,136 @@ import {workerScripts,
import {Player} from "./Player.js";
import {getServer} from "./Server.js";
import {dialogBoxCreate} from "../utils/DialogBox.js";
import {printArray} from "../utils/HelperFunctions.js";
import {printArray, createElement,
createAccordionElement, removeElement,
removeChildrenFromElement} from "../utils/HelperFunctions.js";
import {logBoxCreate} from "../utils/LogBox.js";
import numeral from "../utils/numeral.min.js";
import {formatNumber} from "../utils/StringHelperFunctions.js";
/* Active Scripts UI*/
function setActiveScriptsClickHandlers() {
//Server panel click handlers
var serverPanels = document.getElementsByClassName("active-scripts-server-header");
if (serverPanels == null) {
console.log("ERROR: Could not find Active Scripts server panels");
return;
}
for (i = 0; i < serverPanels.length; ++i) {
serverPanels[i].onclick = function() {
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
}
}
//Script Panel click handlers
var scriptPanels = document.getElementsByClassName("active-scripts-script-header");
if (scriptPanels == null) {
console.log("ERROR: Could not find Active Scripts panels for individual scripts");
return;
}
for (var i = 0; i < scriptPanels.length; ++i) {
scriptPanels[i].onclick = function() {
this.classList.toggle("active");
var panel = this.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
}
}
}
//Returns the ul element containins all script items for a specific server
function getActiveScriptsServerList(server) {
if (server == null) {return null;}
var panelname = "active-scripts-server-panel-" + server.hostname;
var item = document.getElementById(panelname + "-script-list");
if (item == null) {
console.log("ERROR: Cannot find list for: " + server.hostname);
}
return item;
}
/* {
* serverName: {
* header: Server Header Element
* panel: Server Panel List (ul) element
* scripts: {
* script id: Ref to Script information
* }
* }
* ...
*/
let ActiveScriptsUI = {};
function createActiveScriptsServerPanel(server) {
var panelname = "active-scripts-server-panel-" + server.hostname;
let hostname = server.hostname;
if (ActiveScriptsUI[hostname] != null) {
console.log("WARNING: Tried to create already-existing Active Scripts Server panel. Aborting");
return;
}
var activeScriptsList = document.getElementById("active-scripts-list");
//Div of entire Panel
var panelDiv = document.createElement("div");
panelDiv.setAttribute("id", panelname);
let res = createAccordionElement({hdrText:hostname});
let li = res[0];
var hdr = res[1];
let panel = res[2];
//Panel Header
var panelHdr = document.createElement("button");
panelHdr.setAttribute("class", "active-scripts-server-header")
panelHdr.setAttribute("id", panelname + "-hdr");
panelHdr.innerHTML = server.hostname;
var panelScriptList = createElement("ul");
panel.appendChild(panelScriptList);
activeScriptsList.appendChild(li);
//Panel content
var panelContentDiv = document.createElement("div");
panelContentDiv.setAttribute("class", "active-scripts-server-panel");
panelContentDiv.setAttribute("id", panelname + "-content");
ActiveScriptsUI[hostname] = {
header: hdr,
panel: panel,
panelList: panelScriptList,
scripts: {}, //Holds references to li elements for each active script
scriptHdrs: {}, //Holds references to header elements for each active script
scriptStats: {} //Holds references to the p elements containing text for each active script
};
//List of scripts
var panelScriptList = document.createElement("ul");
panelScriptList.setAttribute("id", panelname + "-script-list");
panelContentDiv.appendChild(panelScriptList);
panelDiv.appendChild(panelHdr);
panelDiv.appendChild(panelContentDiv);
activeScriptsList.appendChild(panelDiv);
setActiveScriptsClickHandlers() //Reset click handlers
return panelDiv;
return li;
}
//Deletes the info for a particular server (Dropdown header + Panel with all info)
//in the Active Scripts page if it exists
function deleteActiveScriptsServerPanel(server) {
var panelname = "active-scripts-server-panel-" + server.hostname;
var panel = document.getElementById(panelname);
if (panel == null) {
console.log("No such panel exists: " + panelname);
let hostname = server.hostname;
if (ActiveScriptsUI[hostname] == null) {
console.log("WARNING: Tried to delete non-existent Active Scripts Server panel. Aborting");
return;
}
//Remove the panel if it has no elements
var scriptList = document.getElementById(panelname + "-script-list");
if (scriptList.childNodes.length == 0) {
panel.parentNode.removeChild(panel);
//Make sure it's empty
if (Object.keys(ActiveScriptsUI[hostname].scripts).length > 0) {
console.log("WARNING: Tried to delete Active Scripts Server panel that still has scripts. Aborting");
return;
}
removeElement(ActiveScriptsUI[hostname].panel);
removeElement(ActiveScriptsUI[hostname].header);
delete ActiveScriptsUI[hostname];
}
function addActiveScriptsItem(workerscript) {
//Get server panel
var server = getServer(workerscript.serverIp);
if (server == null) {
console.log("ERROR: Invalid server IP for workerscript.");
console.log("ERROR: Invalid server IP for workerscript in addActiveScriptsItem()");
return;
}
var panelname = "active-scripts-server-panel-" + server.hostname;
var panel = document.getElementById(panelname);
if (panel == null) {
panel = createActiveScriptsServerPanel(server);
let hostname = server.hostname;
if (ActiveScriptsUI[hostname] == null) {
createActiveScriptsServerPanel(server);
}
//Create the element itself. Each element is an accordion collapsible
//Create the unique identifier (key) for this script
var itemNameArray = ["active", "scripts", server.hostname, workerscript.name];
for (var i = 0; i < workerscript.args.length; ++i) {
itemNameArray.push(String(workerscript.args[i]));
}
var itemName = itemNameArray.join("-");
var item = document.createElement("li");
item.setAttribute("id", itemName);
var btn = document.createElement("button");
btn.setAttribute("class", "active-scripts-script-header");
btn.setAttribute("id", itemName + "-header");
btn.innerHTML = workerscript.name;
let res = createAccordionElement({hdrText:workerscript.name});
let li = res[0];
let hdr = res[1];
let panel = res[2];
var itemContentDiv = document.createElement("div");
itemContentDiv.setAttribute("class", "active-scripts-script-panel");
itemContentDiv.setAttribute("id", itemName + "-content");
hdr.classList.remove("accordion-header");
hdr.classList.add("active-scripts-script-header");
panel.classList.remove("accordion-panel");
panel.classList.add("active-scripts-script-panel");
item.appendChild(btn);
item.appendChild(itemContentDiv);
createActiveScriptsText(workerscript, itemContentDiv);
//Handle the constant elements on the panel that don't change after creation
//Threads, args, kill/log button
panel.appendChild(createElement("p", {
innerHTML: "Threads: " + workerscript.scriptRef.threads + "<br>" +
"Args: " + printArray(workerscript.args)
}));
var panelText = createElement("p", {
innerText:"Loading...", fontSize:"14px",
});
updateActiveScriptsText(workerscript, panelText, itemName);
panel.appendChild(panelText);
panel.appendChild(createElement("br"));
panel.appendChild(createElement("span", {
innerText:"Log", class:"active-scripts-button", margin:"4px", padding:"4px",
clickListener:()=>{
logBoxCreate(workerscript.scriptRef);
return false;
}
}));
panel.appendChild(createElement("span", {
innerText:"Kill Script", class:"active-scripts-button", margin:"4px", padding:"4px",
clickListener:()=>{
killWorkerScript(workerscript.scriptRef, workerscript.scriptRef.scriptRef.server);
dialogBoxCreate("Killing script, may take a few minutes to complete...");
return false;
}
}));
//Append element to list
var list = getActiveScriptsServerList(server);
list.appendChild(item);
setActiveScriptsClickHandlers() //Reset click handlers
ActiveScriptsUI[hostname]["panelList"].appendChild(li);
ActiveScriptsUI[hostname].scripts[itemName] = li;
ActiveScriptsUI[hostname].scriptHdrs[itemName] = hdr;
ActiveScriptsUI[hostname].scriptStats[itemName] = panelText;
}
function deleteActiveScriptsItem(workerscript) {
@ -162,19 +142,32 @@ function deleteActiveScriptsItem(workerscript) {
console.log("ERROR: Invalid server IP for workerscript.");
return;
}
let hostname = server.hostname;
if (ActiveScriptsUI[hostname] == null) {
console.log("ERROR: Trying to delete Active Script UI Element with a hostname that cant be found in ActiveScriptsUI: " + hostname);
return;
}
var itemNameArray = ["active", "scripts", server.hostname, workerscript.name];
for (var i = 0; i < workerscript.args.length; ++i) {
itemNameArray.push(String(workerscript.args[i]));
}
var itemName = itemNameArray.join("-");
var li = document.getElementById(itemName);
let li = ActiveScriptsUI[hostname].scripts[itemName];
if (li == null) {
console.log("could not find Active scripts li element for: " + workerscript.name);
console.log("ERROR: Cannot find Active Script UI element for workerscript: ");
console.log(workerscript);
return;
}
li.parentNode.removeChild(li);
removeElement(li);
delete ActiveScriptsUI[hostname].scripts[itemName];
delete ActiveScriptsUI[hostname].scriptHdrs[itemName];
delete ActiveScriptsUI[hostname].scriptStats[itemName];
if (Object.keys(ActiveScriptsUI[hostname].scripts).length === 0) {
deleteActiveScriptsServerPanel(server);
}
}
//Update the ActiveScriptsItems array
function updateActiveScriptsItems() {
@ -197,69 +190,47 @@ function updateActiveScriptsItemContent(workerscript) {
console.log("ERROR: Invalid server IP for workerscript.");
return;
}
let hostname = server.hostname;
if (ActiveScriptsUI[hostname] == null) {
console.log("ERROR: Trying to update Active Script UI Element with a hostname that cant be found in ActiveScriptsUI: " + hostname);
return;
}
var itemNameArray = ["active", "scripts", server.hostname, workerscript.name];
for (var i = 0; i < workerscript.args.length; ++i) {
itemNameArray.push(String(workerscript.args[i]));
}
var itemName = itemNameArray.join("-");
var itemContent = document.getElementById(itemName + "-content")
var item = ActiveScriptsUI[hostname].scriptStats[itemName];
//Add the updated text back. Returns the total online production rate
return updateActiveScriptsText(workerscript, itemContent);
//Update the text if necessary. This fn returns the online $/s production
return updateActiveScriptsText(workerscript, item, itemName);
}
function createActiveScriptsText(workerscript, item) {
var itemTextHeader = document.createElement("p");
var itemTextStats = document.createElement("p");
var itemId = item.id;
itemTextStats.setAttribute("id", itemId + "-stats");
//Server ip/hostname
var threads = "Threads: " + workerscript.scriptRef.threads;
var args = "Args: " + printArray(workerscript.args);
itemTextHeader.innerHTML = threads + "<br>" + args + "<br>";
item.appendChild(itemTextHeader);
item.appendChild(itemTextStats);
var onlineMps = updateActiveScriptsText(workerscript, item, itemTextStats);
var logButton = document.createElement("span");
logButton.innerHTML = "Log";
var killButton = document.createElement("span");
killButton.innerHTML = "Kill script";
logButton.setAttribute("class", "active-scripts-button");
killButton.setAttribute("class", "active-scripts-button");
logButton.addEventListener("click", function() {
logBoxCreate(workerscript.scriptRef);
return false;
});
killButton.addEventListener("click", function() {
killWorkerScript(workerscript.scriptRef, workerscript.scriptRef.scriptRef.server);
dialogBoxCreate("Killing script, may take a few minutes to complete...");
return false;
});
item.appendChild(logButton);
item.appendChild(killButton);
//Return total online production rate
return onlineMps;
function updateActiveScriptsText(workerscript, item, itemName) {
var server = getServer(workerscript.serverIp);
if (server == null) {
console.log("ERROR: Invalid server IP for workerscript.");
return;
}
let hostname = server.hostname;
if (ActiveScriptsUI[hostname] == null) {
console.log("ERROR: Trying to update Active Script UI Element with a hostname that cant be found in ActiveScriptsUI: " + hostname);
return;
}
function updateActiveScriptsText(workerscript, item, statsEl=null) {
var itemId = item.id
var itemTextStats = document.getElementById(itemId + "-stats");
if (itemTextStats == null || itemTextStats === undefined) {
itemTextStats = statsEl;
}
var onlineMps = workerscript.scriptRef.onlineMoneyMade / workerscript.scriptRef.onlineRunningTime;
//Only update if the item is visible
if (ActiveScriptsUI[hostname].header.classList.contains("active") === false) {return onlineMps;}
if (ActiveScriptsUI[hostname].scriptHdrs[itemName].classList.contains("active") === false) {return onlineMps;}
removeChildrenFromElement(item);
//Updates statistics only
//Online
var onlineTotalMoneyMade = "Total online production: $" + formatNumber(workerscript.scriptRef.onlineMoneyMade, 2);
var onlineTotalExpEarned = (Array(26).join(" ") + formatNumber(workerscript.scriptRef.onlineExpGained, 2) + " hacking exp").replace( / /g, "&nbsp;");
var onlineMps = workerscript.scriptRef.onlineMoneyMade / workerscript.scriptRef.onlineRunningTime;
var onlineMpsText = "Online production rate: $" + formatNumber(onlineMps, 2) + "/second";
var onlineEps = workerscript.scriptRef.onlineExpGained / workerscript.scriptRef.onlineRunningTime;
var onlineEpsText = (Array(25).join(" ") + formatNumber(onlineEps, 4) + " hacking exp/second").replace( / /g, "&nbsp;");
@ -273,10 +244,10 @@ function updateActiveScriptsText(workerscript, item, statsEl=null) {
var offlineEps = workerscript.scriptRef.offlineExpGained / workerscript.scriptRef.offlineRunningTime;
var offlineEpsText = (Array(26).join(" ") + formatNumber(offlineEps, 4) + " hacking exp/second").replace( / /g, "&nbsp;");
itemTextStats.innerHTML = onlineTotalMoneyMade + "<br>" + onlineTotalExpEarned + "<br>" +
item.innerHTML = onlineTotalMoneyMade + "<br>" + onlineTotalExpEarned + "<br>" +
onlineMpsText + "<br>" + onlineEpsText + "<br>" + offlineTotalMoneyMade + "<br>" + offlineTotalExpEarned + "<br>" +
offlineMpsText + "<br>" + offlineEpsText + "<br>";
return onlineMps;
}
export {setActiveScriptsClickHandlers, addActiveScriptsItem, deleteActiveScriptsItem, updateActiveScriptsItems};
export {addActiveScriptsItem, deleteActiveScriptsItem, updateActiveScriptsItems};

@ -105,10 +105,10 @@ function initBitNodes() {
"for progression. Furthermore:<br><br>" +
"Hacking and Hacknet Nodes will be significantly less profitable<br>" +
"Your hacking level is reduced by 50%<br>" +
"Hacking experience gain from scripts is reduced by 80%<br>" +
"Hacking experience gain from scripts is reduced by 75%<br>" +
"Corporations have 80% lower valuations and are therefore less profitable<br>" +
"Working for companies is 50% less profitable<br>" +
"Crimes and Infiltration are 75% less profitable<br><br>" +
"Crimes and Infiltration are 50% less profitable<br><br>" +
"Destroying this BitNode will give you Source-File 6, or if you already have this Source-File it will upgrade " +
"its level up to a maximum of 3. This Source-File allows you to access the NSA's Bladeburner Division in other " +
"BitNodes. In addition, this Source-File will raise the experience gain rate of all your combat stats by:<br><br>" +
@ -274,12 +274,12 @@ function initBitNodeMultipliers() {
BitNodeMultipliers.ServerStartingSecurity = 1.5;
BitNodeMultipliers.ScriptHackMoney = 0.5;
BitNodeMultipliers.CompanyWorkMoney = 0.5;
BitNodeMultipliers.CrimeMoney = 0.25;
BitNodeMultipliers.InfiltrationMoney = 0.25;
BitNodeMultipliers.CrimeMoney = 0.5;
BitNodeMultipliers.InfiltrationMoney = 0.5;
BitNodeMultipliers.CorporationValuation = 0.2;
BitNodeMultipliers.HacknetNodeMoney = 0.2;
BitNodeMultipliers.FactionPassiveRepGain = 0;
BitNodeMultipliers.HackExpGain = 0.2;
BitNodeMultipliers.HackExpGain = 0.25;
break;
case 8: //Ghost of Wall Street
BitNodeMultipliers.ScriptHackMoney = 0;

@ -691,9 +691,9 @@ Bladeburner.prototype.create = function() {
"and information-gathering ONLY. Do NOT engage. Stealth is of the utmost importance.<br><br>" +
"Successfully completing Tracking contracts will slightly improve your Synthoid population estimate for " +
"whatever city you are currently in.",
baseDifficulty:150,difficultyFac:1.02,rewardFac:1.041,
baseDifficulty:125,difficultyFac:1.02,rewardFac:1.041,
rankGain:0.3, hpLoss:0.5,
count:getRandomInt(400, 800), countGrowth:getRandomInt(1, 5),
count:getRandomInt(300, 800), countGrowth:getRandomInt(1, 5),
weights:{hack:0,str:0.05,def:0.05,dex:0.35,agi:0.35,cha:0.1, int:0.05},
decays:{hack:0,str:0.91,def:0.91,dex:0.91,agi:0.91,cha:0.9, int:1},
isStealth:true
@ -705,7 +705,7 @@ Bladeburner.prototype.create = function() {
"current city, and will also increase its chaos level.",
baseDifficulty:250, difficultyFac:1.04,rewardFac:1.085,
rankGain:0.9, hpLoss:1,
count:getRandomInt(250, 500), countGrowth:getRandomInt(1, 3),
count:getRandomInt(200, 750), countGrowth:getRandomInt(1, 3),
weights:{hack:0,str:0.15,def:0.15,dex:0.25,agi:0.25,cha:0.1, int:0.1},
decays:{hack:0,str:0.91,def:0.91,dex:0.91,agi:0.91,cha:0.8, int:0.9},
isKill:true
@ -717,7 +717,7 @@ Bladeburner.prototype.create = function() {
"city, and will also increase its chaos level.",
baseDifficulty:200, difficultyFac:1.03, rewardFac:1.065,
rankGain:0.6, hpLoss:1,
count:getRandomInt(300, 600), countGrowth:getRandomInt(1,4),
count:getRandomInt(300, 900), countGrowth:getRandomInt(1,4),
weights:{hack:0,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0.1, int:0.1},
decays:{hack:0,str:0.91,def:0.91,dex:0.91,agi:0.91,cha:0.8, int:0.9},
isKill:true
@ -732,7 +732,7 @@ Bladeburner.prototype.create = function() {
"You will NOT lose HP from failed Investigation ops.",
baseDifficulty:400, difficultyFac:1.03,rewardFac:1.07,reqdRank:25,
rankGain:2, rankLoss:0.2,
count:getRandomInt(100, 300), countGrowth:1,
count:getRandomInt(50, 400), countGrowth:1,
weights:{hack:0.25,str:0.05,def:0.05,dex:0.2,agi:0.1,cha:0.25, int:0.1},
decays:{hack:0.85,str:0.9,def:0.9,dex:0.9,agi:0.9,cha:0.7, int:0.9},
isStealth:true
@ -745,7 +745,7 @@ Bladeburner.prototype.create = function() {
"data.",
baseDifficulty:500, difficultyFac:1.04, rewardFac:1.09, reqdRank:100,
rankGain:4, rankLoss:0.4, hpLoss:2,
count:getRandomInt(100, 250), countGrowth:1,
count:getRandomInt(50, 300), countGrowth:1,
weights:{hack:0.2,str:0.05,def:0.05,dex:0.2,agi:0.2,cha:0.2, int:0.1},
decays:{hack:0.8,str:0.9,def:0.9,dex:0.9,agi:0.9,cha:0.7, int:0.9},
isStealth:true
@ -756,7 +756,7 @@ Bladeburner.prototype.create = function() {
"notorious Synthoid criminals.",
baseDifficulty:650, difficultyFac:1.04, rewardFac:1.095, reqdRank:500,
rankGain:5, rankLoss:0.5, hpLoss:2.5,
count:getRandomInt(100,250), countGrowth:0.75,
count:getRandomInt(25,400), countGrowth:0.75,
weights:{hack:0.25,str:0.05,def:0.05,dex:0.25,agi:0.1,cha:0.2, int:0.1},
decays:{hack:0.8,str:0.85,def:0.85,dex:0.85,agi:0.85,cha:0.7, int:0.9},
isStealth:true
@ -768,7 +768,7 @@ Bladeburner.prototype.create = function() {
"in order for this Operation to be successful",
baseDifficulty:800, difficultyFac:1.045, rewardFac:1.1, reqdRank:3000,
rankGain:50,rankLoss:2.5,hpLoss:50,
count:getRandomInt(50, 100), countGrowth:0.2,
count:getRandomInt(25, 150), countGrowth:0.2,
weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,cha:0, int:0.1},
decays:{hack:0.7,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.9},
isKill:true
@ -780,7 +780,7 @@ Bladeburner.prototype.create = function() {
"drawing any attention. Stealth and discretion are key.",
baseDifficulty:1000, difficultyFac:1.05, rewardFac:1.11, reqdRank:20e3,
rankGain:20, rankLoss:2, hpLoss:10,
count:getRandomInt(50, 200), countGrowth:0.1,
count:getRandomInt(25, 250), countGrowth:0.1,
weights:{hack:0.1,str:0.1,def:0.1,dex:0.3,agi:0.3,cha:0, int:0.1},
decays:{hack:0.7,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.9},
isStealth:true, isKill:true
@ -792,7 +792,7 @@ Bladeburner.prototype.create = function() {
"in the Synthoid communities.",
baseDifficulty:1500, difficultyFac:1.06, rewardFac:1.14, reqdRank:50e3,
rankGain:40, rankLoss:4, hpLoss:5,
count:getRandomInt(50, 150), countGrowth:0.1,
count:getRandomInt(25, 200), countGrowth:0.1,
weights:{hack:0.1,str:0.1,def:0.1,dex:0.3,agi:0.3,cha:0, int:0.1},
decays:{hack:0.6,str:0.8,def:0.8,dex:0.8,agi:0.8,cha:0, int:0.8},
isStealth:true, isKill:true
@ -3202,11 +3202,11 @@ function initBladeburner() {
Skills[SkillNames.Datamancer] = new Skill({
name:SkillNames.Datamancer,
desc:"Each level of this skill increases your effectiveness in " +
"synthoid population analysis and investigation by 4%. " +
"synthoid population analysis and investigation by 5%. " +
"This affects all actions that can potentially increase " +
"the accuracy of your synthoid population/community estimates.",
baseCost:3,costInc:1,
successChanceEstimate:4
successChanceEstimate:5
});
Skills[SkillNames.Tracer] = new Skill({
name:SkillNames.Tracer,

@ -40,6 +40,7 @@ let CONSTANTS = {
/* Netscript Constants */
//RAM Costs for different commands
ScriptBaseRamCost: 1.4,
ScriptWhileRamCost: 0.2,
ScriptForRamCost: 0.2,
ScriptIfRamCost: 0.15,
@ -1139,7 +1140,14 @@ let CONSTANTS = {
LatestUpdate:
"v0.36.1<br>" +
"* Bladeburner Changes: <br>" +
"** Bug Fix: You can no longer get Bladeburner faction reputation through Infiltration<br>" +
"** Initial difficulty of Tracking contracts reduced<br>" +
"* Crime, Infiltration, and Hacking are now slightly more profitable in BN-6<br>" +
"* The ctrl+b hotkey in the text editor is now also triggered by command+b or winkey+b<br>" +
"* Many servers now have additional RAM<br>" +
"* Added an option to disable hotkeys/keyboard shortcuts<br>" +
"* Refactored 'Active Scripts' UI page to optimize its performance<br>" +
"v0.36.0<br>" +
"* Added BN-6: Bladeburners<br>" +
"* Rebalanced many combat Augmentations so that they are slightly less powerful<br>" +

@ -2013,7 +2013,10 @@ function purchaseTorRouter() {
}
Player.loseMoney(CONSTANTS.TorRouterCost);
var darkweb = new Server(createRandomIp(), "darkweb", "", false, false, false, 1);
var darkweb = new Server({
ip:createRandomIp(), hostname:"darkweb", organizationName:"",
isConnectedTo:false, adminRights:false, purchasedByPlayer:false, maxRam:1
});
AddToAllServers(darkweb);
SpecialServerIps.addIp("Darkweb Server", darkweb.ip);

@ -1633,7 +1633,15 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.log("Error: Not enough money to purchase server. Need $" + formatNumber(cost, 2));
return "";
}
var newServ = new Server(createRandomIp(), hostnameStr, "", false, true, true, ram);
var newServ = new Server({
ip: createRandomIp(),
hostname: hostnameStr,
organizationName: "",
isConnectedTo: false,
adminRights: true,
purchasedByPlayer: true,
maxRam: ram,
});
AddToAllServers(newServ);
Player.purchasedServers.push(newServ.ip);
@ -1994,7 +2002,11 @@ function NetscriptFunctions(workerScript) {
}
return suc;
},
getScriptRam : function (scriptname, ip=workerScript.serverIp) {
getScriptName : function() {
if (workerScript.checkingRam) {return 0;}
return workerScript.name;
},
getScriptRam : function (scriptname, ip=workerScript.serverIp)
if (workerScript.checkingRam) {
if (workerScript.loadedFns.getScriptRam) {
return 0;
@ -2432,7 +2444,10 @@ function NetscriptFunctions(workerScript) {
}
Player.loseMoney(CONSTANTS.TorRouterCost);
var darkweb = new Server(createRandomIp(), "darkweb", "", false, false, false, 1);
var darkweb = new Server({
ip:createRandomIp(), hostname:"darkweb", organizationName:"",
isConnectedTo:false, adminRights:false, purchasedByPlayer:false, maxRam:1
});
AddToAllServers(darkweb);
SpecialServerIps.addIp("Darkweb Server", darkweb.ip);

@ -62,29 +62,32 @@ function prestigeWorkerScripts() {
function startJsScript(workerScript) {
workerScript.running = true;
// The name of the currently running netscript function, to prevent concurrent
// calls to hack, grow, etc.
let runningFn = null;
// We need to go through the environment and wrap each function in such a way that it
// can be called at most once at a time. This will prevent situations where multiple
// hack promises are outstanding, for example.
function wrap(propName, f) {
let running = null; // The name of the currently running netscript function.
// This function unfortunately cannot be an async function, because we don't
// know if the original one was, and there's no way to tell.
return function (...args) {
const msg = "Concurrent calls to Netscript functions not allowed! " +
"Did you forget to await hack(), grow(), or some other " +
"promise-returning function? (Currently running: %s tried to run: %s)"
if (running) {
workerScript.errorMessage = makeRuntimeRejectMsg(workerScript, sprintf(msg, running, propName), null)
if (runningFn) {
workerScript.errorMessage = makeRuntimeRejectMsg(workerScript, sprintf(msg, runningFn, propName), null)
throw workerScript;
}
running = propName;
runningFn = propName;
let result = f(...args);
if (result && result.finally !== undefined) {
return result.finally(function () {
running = null;
runningFn = null;
});
} else {
running = null;
runningFn = null;
return result;
}
}
@ -104,7 +107,8 @@ function startJsScript(workerScript) {
return [mainReturnValue, workerScript];
}).catch(e => {
if (e instanceof Error) {
workerScript.errorMessage = makeRuntimeRejectMsg(workerScript, e.message + (e.stack && ("\nstack:\n" + e.stack.toString()) || ""));
workerScript.errorMessage = makeRuntimeRejectMsg(
workerScript, e.message + (e.stack && ("\nstack:\n" + e.stack.toString()) || ""));
throw workerScript;
} else if (isScriptErrorMessage(e)) {
workerScript.errorMessage = e;

@ -210,7 +210,10 @@ function PlayerObject() {
PlayerObject.prototype.init = function() {
/* Initialize Player's home computer */
var t_homeComp = new Server(createRandomIp(), "home", "Home PC", true, true, true, 8);
var t_homeComp = new Server({
ip:createRandomIp(), hostname:"home", organizationName:"Home PC",
isConnectedTo:true, adminRights:true, purchasedByPlayer:true, maxRam:8
});
this.homeComputer = t_homeComp.ip;
this.currentServer = t_homeComp.ip;
AddToAllServers(t_homeComp);

@ -233,6 +233,7 @@ function updateScriptEditorContent() {
//Define key commands in script editor (ctrl o to save + close, etc.)
$(document).keydown(function(e) {
if (Settings.DisableHotkeys === true) {return;}
if (Engine.currentPage == Engine.Page.ScriptEditor) {
//Ctrl + b
if (e.keyCode == 66 && (e.ctrlKey || e.metaKey)) {
@ -417,7 +418,7 @@ function parseOnlyRamCalculate(server, code, workerScript) {
// Finally, walk the reference map and generate a ram cost. The initial set of keys to scan
// are those that start with __SPECIAL_INITIAL_MODULE__.
let ram = 1.4;
let ram = CONSTANTS.ScriptBaseRamCost;
const unresolvedRefs = Object.keys(dependencyMap).filter(s => s.startsWith(initialModule));
const resolvedRefs = new Set();
while (unresolvedRefs.length > 0) {

@ -23,16 +23,16 @@ function Server(params={ip:createRandomIp(), hostname:""}) {
++i;
}
this.hostname = hostname + suffix;
this.organizationName = params.organizationName ? params.organizationName : "";
this.isConnectedTo = params.isConnectedTo ? params.isConnectedTo : false;
this.organizationName = params.organizationName != null ? params.organizationName : "";
this.isConnectedTo = params.isConnectedTo != null ? params.isConnectedTo : false;
//Access information
this.hasAdminRights = params.adminRights ? params.adminRights : false;
this.purchasedByPlayer = params.purchasedByPlayer ? params.purchasedByPlayer : false;
this.hasAdminRights = params.adminRights != null ? params.adminRights : false;
this.purchasedByPlayer = params.purchasedByPlayer != null ? params.purchasedByPlayer : false;
this.manuallyHacked = false; //Flag that tracks whether or not the server has been hacked at least once
//RAM, CPU speed and Scripts
this.maxRam = params.maxRam ? params.maxRam : 0; //GB
this.maxRam = params.maxRam != null ? params.maxRam : 0; //GB
this.ramUsed = 0;
this.cpuCores = 1; //Max of 8, affects hacking times and Hacking Mission starting Cores
@ -44,22 +44,22 @@ function Server(params={ip:createRandomIp(), hostname:""}) {
this.dir = 0; //new Directory(this, null, ""); TODO
/* Hacking information (only valid for "foreign" aka non-purchased servers) */
this.requiredHackingSkill = params.requiredHackingSkill ? params.requiredHackingSkill : 1;
this.moneyAvailable = params.moneyAvailable ? params.moneyAvailable * BitNodeMultipliers.ServerStartingMoney : 1e6;
this.requiredHackingSkill = params.requiredHackingSkill != null ? params.requiredHackingSkill : 1;
this.moneyAvailable = params.moneyAvailable != null ? params.moneyAvailable * BitNodeMultipliers.ServerStartingMoney : 0;
this.moneyMax = 25 * this.moneyAvailable * BitNodeMultipliers.ServerMaxMoney;
//Hack Difficulty is synonymous with server security. Base Difficulty = Starting difficulty
this.hackDifficulty = params.hackDifficulty ? params.hackDifficulty * BitNodeMultipliers.ServerStartingSecurity : 1;
this.hackDifficulty = params.hackDifficulty != null ? params.hackDifficulty * BitNodeMultipliers.ServerStartingSecurity : 1;
this.baseDifficulty = this.hackDifficulty;
this.minDifficulty = Math.max(1, Math.round(this.hackDifficulty / 3));
this.serverGrowth = params.serverGrowth ? params.serverGrowth : 1; //Integer from 0 to 100. Affects money increase from grow()
this.serverGrowth = params.serverGrowth != null ? params.serverGrowth : 1; //Integer from 0 to 100. Affects money increase from grow()
//The IP's of all servers reachable from this one (what shows up if you run scan/netstat)
// NOTE: Only contains IP and not the Server objects themselves
this.serversOnNetwork = [];
//Port information, required for porthacking servers to get admin rights
this.numOpenPortsRequired = params.numOpenPortsRequired ? params.numOpenPortsRequired : 5;
this.numOpenPortsRequired = params.numOpenPortsRequired != null ? params.numOpenPortsRequired : 5;
this.sshPortOpen = false; //Port 22
this.ftpPortOpen = false; //Port 21
this.smtpPortOpen = false; //Port 25
@ -527,7 +527,6 @@ function initForeignServers() {
requiredHackingSkill:20, moneyAvailable:2.75e6,
hackDifficulty:20, serverGrowth:25, numOpenPortsRequired:0
});
NectarNightclubServer.setPortProperties(0);
AddToAllServers(NectarNightclubServer);
var NeoNightclubServer = new Server({

@ -32,7 +32,10 @@ function purchaseServer(ram, cost) {
}
//Create server
var newServ = new Server(createRandomIp(), hostname, "", false, true, true, ram);
var newServ = new Server({
ip:createRandomIp(), hostname:hostname, organizationName:"",
isConnectedTo:false, adminRights:true, purchasedByPlayer:true, maxRam:ram
});
AddToAllServers(newServ);
//Add to Player's purchasedServers array

@ -8,6 +8,7 @@ let Settings = {
SuppressMessages: false,
SuppressFactionInvites: false,
AutosaveInterval: 60,
DisableHotkeys: false,
ThemeHighlightColor: "#ffffff",
ThemeFontColor: "#66ff33",
ThemeBackgroundColor: "#000000",
@ -26,6 +27,7 @@ function initSettings() {
Settings.SuppressMessages = false;
Settings.SuppressFactionInvites = false;
Settings.AutosaveInterval = 60;
Settings.DisableHotkeys = false;
}
function setSettingsLabels() {
@ -35,6 +37,7 @@ function setSettingsLabels() {
var suppressMsgs = document.getElementById("settingsSuppressMessages");
var suppressFactionInv = document.getElementById("settingsSuppressFactionInvites")
var autosaveInterval = document.getElementById("settingsAutosaveIntervalValLabel");
var disableHotkeys = document.getElementById("settingsDisableHotkeys");
//Initialize values on labels
nsExecTime.innerHTML = Settings.CodeInstructionRunTime + "ms";
@ -43,6 +46,7 @@ function setSettingsLabels() {
suppressMsgs.checked = Settings.SuppressMessages;
suppressFactionInv.checked = Settings.SuppressFactionInvites;
autosaveInterval.innerHTML = Settings.AutosaveInterval;
disableHotkeys.checked = Settings.DisableHotkeys;
//Set handlers for when input changes
var nsExecTimeInput = document.getElementById("settingsNSExecTimeRangeVal");
@ -79,14 +83,18 @@ function setSettingsLabels() {
}
};
document.getElementById("settingsSuppressMessages").onclick = function() {
suppressMsgs.onclick = function() {
Settings.SuppressMessages = this.checked;
};
document.getElementById("settingsSuppressFactionInvites").onclick = function() {
suppressFactionInv.onclick = function() {
Settings.SuppressFactionInvites = this.checked;
};
disableHotkeys.onclick = function() {
Settings.DisableHotkeys = this.checked;
}
//Theme
if (Settings.ThemeHighlightColor == null || Settings.ThemeFontColor == null || Settings.ThemeBackgroundColor == null) {
console.log("ERROR: Cannot find Theme Settings");

@ -86,11 +86,15 @@ var KEY = {
E: 69,
F: 70,
H: 72,
J: 74,
K: 75,
L: 76,
M: 77,
N: 78,
O: 79,
P: 80,
R: 82,
S: 83,
U: 85,
W: 87,
}
@ -259,9 +263,9 @@ $(document).keydown(function(event) {
});
//Keep terminal in focus
let terminalCtrlPressed = false;
let terminalCtrlPressed = false, shiftKeyPressed = false;
$(document).ready(function() {
if (Engine.currentPage == Engine.Page.Terminal) {
if (Engine.currentPage === Engine.Page.Terminal) {
$('.terminal-input').focus();
}
});
@ -269,15 +273,16 @@ $(document).keydown(function(e) {
if (Engine.currentPage == Engine.Page.Terminal) {
if (e.which == 17) {
terminalCtrlPressed = true;
} else if (terminalCtrlPressed == true) {
} else if (e.shiftKey) {
shiftKeyPressed = true;
} else if (terminalCtrlPressed || shiftKeyPressed) {
//Don't focus
} else {
var inputTextBox = document.getElementById("terminal-input-text-box");
if (inputTextBox != null) {
inputTextBox.focus();
}
if (inputTextBox != null) {inputTextBox.focus();}
terminalCtrlPressed = false;
shiftKeyPressed = false;
}
}
})
@ -286,6 +291,9 @@ $(document).keyup(function(e) {
if (e.which == 17) {
terminalCtrlPressed = false;
}
if (e.shiftKey) {
shiftKeyPressed = false;
}
}
})
@ -1304,12 +1312,11 @@ let Terminal = {
}
//Check if its a script or just a program/executable
if (isScriptFilename(executableName) == -1) {
// Not a script
Terminal.runProgram(executableName);
} else {
//Script
//if (isScriptFilename(executableName)) {
if (executableName.includes(".script") || executableName.includes(".js") || executableName.includes(".ns")) {
Terminal.runScript(executableName);
} else {
Terminal.runProgram(executableName);
}
}
break;

@ -9,8 +9,7 @@ import {formatNumber,
import {loxBoxCreate, logBoxUpdateText,
logBoxOpened} from "../utils/LogBox.js";
import {setActiveScriptsClickHandlers,
updateActiveScriptsItems} from "./ActiveScriptsUI.js";
import {updateActiveScriptsItems} from "./ActiveScriptsUI.js";
import {Augmentations, installAugmentations,
initAugmentations, AugmentationNames,
displayAugmentationsContent} from "./Augmentations.js";
@ -58,7 +57,7 @@ import {StockMarket, StockSymbols,
initSymbolToStockMap, stockMarketCycle,
updateStockPrices,
displayStockMarketContent} from "./StockMarket.js";
import {Terminal, postNetburnerText, post} from "./Terminal.js";
import {Terminal, postNetburnerText, post, KEY} from "./Terminal.js";
/* Shortcuts to navigate through the game
* Alt-t - Terminal
@ -76,51 +75,52 @@ import {Terminal, postNetburnerText, post} from "./Terminal.js";
* Alt-o - Options
*/
$(document).keydown(function(e) {
if (Settings.DisableHotkeys === true) {return;}
if (!Player.isWorking && !redPillFlag && !inMission && !cinematicTextFlag) {
if (e.keyCode == 84 && e.altKey) {
e.preventDefault();
Engine.loadTerminalContent();
} else if (e.keyCode == 67 && e.altKey) {
} else if (e.keyCode === KEY.C && e.altKey) {
e.preventDefault();
Engine.loadCharacterContent();
} else if (e.keyCode == 69 && e.altKey) {
} else if (e.keyCode === KEY.E && e.altKey) {
e.preventDefault();
Engine.loadScriptEditorContent();
} else if (e.keyCode == 83 && e.altKey) {
} else if (e.keyCode === KEY.S && e.altKey) {
e.preventDefault();
Engine.loadActiveScriptsContent();
} else if (e.keyCode == 72 && e.altKey) {
} else if (e.keyCode === KEY.H && e.altKey) {
e.preventDefault();
Engine.loadHacknetNodesContent();
} else if (e.keyCode == 87 && e.altKey) {
} else if (e.keyCode === KEY.W && e.altKey) {
e.preventDefault();
Engine.loadWorldContent();
} else if (e.keyCode == 74 && e.altKey) {
} else if (e.keyCode === KEY.J && e.altKey) {
e.preventDefault();
Engine.loadJobContent();
} else if (e.keyCode == 82 && e.altKey) {
} else if (e.keyCode === KEY.R && e.altKey) {
e.preventDefault();
Engine.loadTravelContent();
} else if (e.keyCode == 80 && e.altKey) {
} else if (e.keyCode === KEY.P && e.altKey) {
e.preventDefault();
Engine.loadCreateProgramContent();
} else if (e.keyCode == 70 && e.altKey) {
} else if (e.keyCode === KEY.F && e.altKey) {
//Overriden by Fconf
if (Engine.currentPage === Engine.Page.Terminal && FconfSettings.ENABLE_BASH_HOTKEYS) {
return;
}
e.preventDefault();
Engine.loadFactionsContent();
} else if (e.keyCode == 65 && e.altKey) {
} else if (e.keyCode === KEY.A && e.altKey) {
e.preventDefault();
Engine.loadAugmentationsContent();
} else if (e.keyCode == 85 && e.altKey) {
} else if (e.keyCode === KEY.U && e.altKey) {
e.preventDefault();
Engine.loadTutorialContent();
}
}
if (e.keyCode == 79 && e.altKey) {
if (e.keyCode === KEY.O && e.altKey) {
e.preventDefault();
gameOptionsBoxOpen();
}
@ -260,7 +260,6 @@ let Engine = {
loadActiveScriptsContent: function() {
Engine.hideAllContent();
Engine.Display.activeScriptsContent.style.display = "block";
setActiveScriptsClickHandlers();
updateActiveScriptsItems();
Engine.currentPage = Engine.Page.ActiveScripts;
document.getElementById("active-scripts-menu-link").classList.add("active");
@ -963,7 +962,7 @@ let Engine = {
} else if (Engine.currentPage === Engine.Page.Corporation) {
Player.corporation.updateUIContent();
}
Engine.Counters.updateDisplaysMed = 9;
Engine.Counters.updateDisplaysMed = 6;
}
if (Engine.Counters.updateDisplaysLong <= 0) {

@ -61,6 +61,7 @@ function infiltrationBoxCreate(inst) {
var selector = document.getElementById("infiltration-faction-select");
selector.innerHTML = "";
for (var i = 0; i < Player.factions.length; ++i) {
if (Player.factions[i] === "Bladeburners") {continue;}
selector.innerHTML += "<option value='" + Player.factions[i] +
"'>" + Player.factions[i] + "</option>";
}