Merge branch 'dev' of github.com:danielyxie/bitburner into dev

This commit is contained in:
Olivier Gagnon 2021-05-03 12:20:54 -04:00
commit ee759a8dd6
35 changed files with 282 additions and 145 deletions

@ -0,0 +1,15 @@
getServerMaxRam() Netscript Function
====================================
.. js:function:: getServerMaxRam(hostname)
:RAM cost: 0.05 GB
:param string hostname: Hostname of target server.
:returns: Total ram available on that server. In GB.
Example:
.. code-block:: javascript
maxRam = getServerMaxRam("helios"); // returns: 16
print("helios has "+maxRam + "GB");

@ -3,6 +3,8 @@ getServerRam() Netscript Function
.. js:function:: getServerRam(hostname)
.. warning:: This function is deprecated.
:RAM cost: 0.1 GB
:param string hostname: Hostname of target server.
:returns: An array of 2 number, first number is the total RAM, second the

@ -0,0 +1,15 @@
getServerUsedRam() Netscript Function
=====================================
.. js:function:: getServerUsedRam(hostname)
:RAM cost: 0.05 GB
:param string hostname: Hostname of target server.
:returns: Used ram on that server. In GB.
Example:
.. code-block:: javascript
usedRam = getServerUsedRam("harakiri-sushi"); // returns: 5.6
print("harakiri-sushi uses "+usedRam + "GB");

@ -54,7 +54,8 @@ This includes information such as function signatures, what they do, and their r
getServerMinSecurityLevel() <basicfunctions/getServerMinSecurityLevel>
getServerRequiredHackingLevel() <basicfunctions/getServerRequiredHackingLevel>
getServerNumPortsRequired() <basicfunctions/getServerNumPortsRequired>
getServerRam() <basicfunctions/getServerRam>
getServerMaxRam() <basicfunctions/getServerMaxRam>
getServerUsedRam() <basicfunctions/getServerUsedRam>
serverExists() <basicfunctions/serverExists>
fileExists() <basicfunctions/fileExists>
isRunning() <basicfunctions/isRunning>
@ -90,3 +91,8 @@ This includes information such as function signatures, what they do, and their r
wget() <basicfunctions/wget>
getFavorToDonate() <basicfunctions/getFavorToDonate>
flags() <basicfunctions/flags>
.. toctree::
:caption: Deprecated:
getServerRam() <basicfunctions/getServerRam>

@ -86,7 +86,7 @@ The following is an example of one way a script can be used to automate the
purchasing and upgrading of Hacknet Nodes.
This script attempts to purchase Hacknet Nodes until the player has a total of 8. Then
it gradually upgrades those Node's to a minimum of level 140, 64 GB RAM, and 8 cores
it gradually upgrades those Node's to a minimum of level 80, 16 GB RAM, and 8 cores
.. code:: javascript
@ -129,3 +129,16 @@ it gradually upgrades those Node's to a minimum of level 140, 64 GB RAM, and 8 c
};
print("All nodes upgraded to 16GB RAM");
for (var i = 0; i < cnt; i++) {
while (hacknet.getNodeStats(i).cores < 8) {
var cost = hacknet.getCoreUpgradeCost(i, 1);
while (myMoney() < cost) {
print("Need $" + cost + " . Have $" + myMoney());
sleep(3000);
}
res = hacknet.upgradeCore(i, 1);
};
};
print("All nodes upgraded to 8 cores");

@ -327,8 +327,8 @@
Would you like to join? <br/> <br/>
Warning: Joining this faction may prevent you from joining other factions during this run!
</p>
<button id="faction-invitation-box-yes" class="popup-box-button"> Yes </button>
<button id="faction-invitation-box-no" class="popup-box-button"> No </button>
<button id="faction-invitation-box-yes" class="popup-box-button"> Join! </button>
<button id="faction-invitation-box-no" class="popup-box-button"> Decide later. </button>
</div>
</div>

@ -9,7 +9,7 @@ import { Factions } from "../Faction/Factions";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../../utils/JSONReviver";
interface IConstructorParams {
info: string;
info: string | JSX.Element;
isSpecial?: boolean;
moneyCost: number;
name: string;
@ -57,7 +57,7 @@ export class Augmentation {
baseRepRequirement = 0;
// Description of what this Aug is and what it does
info = "";
info: string | JSX.Element;
// Any Augmentation not immediately available in BitNode-1 is special (e.g. Bladeburner augs)
isSpecial = false;

@ -60,7 +60,7 @@ function initAugmentations() {
"This augmentation increases the player's dexterity by 10%.",
dexterity_mult: 1.1,
});
Targeting1.addToFactions(["Slum Snakes", "The Dark Army", "The Syndicate", "Sector-12", "Volhaven", "Ishima",
Targeting1.addToFactions(["Slum Snakes", "The Dark Army", "The Syndicate", "Sector-12", "Ishima",
"OmniTek Incorporated", "KuaiGong International", "Blade Industries"]);
if (augmentationExists(AugmentationNames.Targeting1)) {
delete Augmentations[AugmentationNames.Targeting1];
@ -75,7 +75,7 @@ function initAugmentations() {
prereqs:[AugmentationNames.Targeting1],
dexterity_mult: 1.2,
});
Targeting2.addToFactions(["The Dark Army", "The Syndicate", "Sector-12", "Volhaven", "Ishima",
Targeting2.addToFactions(["The Dark Army", "The Syndicate", "Sector-12",
"OmniTek Incorporated", "KuaiGong International", "Blade Industries"]);
if (augmentationExists(AugmentationNames.Targeting2)) {
delete Augmentations[AugmentationNames.Targeting2];
@ -136,7 +136,7 @@ function initAugmentations() {
strength_mult: 1.1,
defense_mult: 1.1,
});
CombatRib1.addToFactions(["Slum Snakes", "The Dark Army", "The Syndicate", "Sector-12", "Volhaven", "Ishima",
CombatRib1.addToFactions(["Slum Snakes", "The Dark Army", "The Syndicate", "Volhaven", "Ishima",
"OmniTek Incorporated", "KuaiGong International", "Blade Industries"]);
if (augmentationExists(AugmentationNames.CombatRib1)) {
delete Augmentations[AugmentationNames.CombatRib1];
@ -152,7 +152,7 @@ function initAugmentations() {
strength_mult: 1.14,
defense_mult: 1.14,
});
CombatRib2.addToFactions(["The Dark Army", "The Syndicate", "Sector-12", "Volhaven", "Ishima",
CombatRib2.addToFactions(["The Dark Army", "The Syndicate", "Volhaven",
"OmniTek Incorporated", "KuaiGong International", "Blade Industries"]);
if (augmentationExists(AugmentationNames.CombatRib2)) {
delete Augmentations[AugmentationNames.CombatRib2];
@ -428,7 +428,7 @@ function initAugmentations() {
"This augmentation increases the player's hacking speed by 3%.",
hacking_speed_mult: 1.03,
});
SynapticEnhancement.addToFactions(["CyberSec"]);
SynapticEnhancement.addToFactions(["CyberSec", "Aevum"]);
if (augmentationExists(AugmentationNames.SynapticEnhancement)) {
delete Augmentations[AugmentationNames.SynapticEnhancement];
}
@ -756,7 +756,7 @@ function initAugmentations() {
"when working for a company by 20%.",
company_rep_mult: 1.2,
});
NuoptimalInjectorImplant.addToFactions(["Tian Di Hui", "Volhaven", "New Tokyo", "Chongqing", "Ishima",
NuoptimalInjectorImplant.addToFactions(["Tian Di Hui", "Volhaven", "New Tokyo", "Chongqing",
"Clarke Incorporated", "Four Sigma", "Bachman & Associates"]);
if (augmentationExists(AugmentationNames.NuoptimalInjectorImplant)) {
delete Augmentations[AugmentationNames.NuoptimalInjectorImplant];
@ -1064,7 +1064,7 @@ function initAugmentations() {
agility_exp_mult: 1.1,
charisma_exp_mult: 1.1,
});
Neurotrainer1.addToFactions(["CyberSec"]);
Neurotrainer1.addToFactions(["CyberSec", "Aevum"]);
if (augmentationExists(AugmentationNames.Neurotrainer1)) {
delete Augmentations[AugmentationNames.Neurotrainer1];
}

@ -236,8 +236,7 @@ BitNodes["BitNode12"] = new BitNode(12, "The Recursion", "Repeat.",
"To iterate is human, to recurse divine.<br><br>" +
"Every time this BitNode is destroyed, it becomes slightly harder. Destroying this BitNode will give you Source-File 12, or " +
"if you already have this Source-File it will upgrade its level. There is no maximum level for Source-File 12. Each level " +
"of Source-File 12 will increase all of your multipliers by 1%. This effect is multiplicative with itself. " +
"In other words, level N of this Source-File will result in a multiplier of 1.01^N (or 0.99^N for multipliers that decrease)");
"of Source-File 12 lets you start any BitNodes with NeuroFlux Governor equal to the level of this source file.");
// Books: Frontera, Shiner
BitNodes["BitNode13"] = new BitNode(13, "fOS", "COMING SOON"); //Unlocks the new game mode and the rest of the BitNodes
BitNodes["BitNode14"] = new BitNode(14, "", "COMING SOON");

@ -160,7 +160,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
"technology in Operation K, we've discovered that a small group of " +
"MK-VI Synthoids were able to make off with the schematics and design " +
"of the technology before the Operation. It is almost a certainty that " +
"these Synthoids are some of the rogue MK-VI ones from the Synthoid Uprising." +
"these Synthoids are some of the rogue MK-VI ones from the Synthoid Uprising.<br><br>" +
"The goal of Operation Deckard is to hunt down these Synthoids and retire " +
"them. I don't need to tell you how critical this mission is.",
baseDifficulty:20e3, reqdRank:40e3,
@ -231,7 +231,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
"means that the supercomputer may be able to reason abstractly " +
"and become self-aware.<br><br>" +
"I do not need to remind you why sentient-level AIs pose a serious " +
"thread to all of mankind.<br><br>" +
"threat to all of mankind.<br><br>" +
"The research for this project is being conducted at one of Fulcrum " +
"Technologies secret facilities in Aevum, codenamed 'Alpha Ranch'. " +
"Infiltrate the compound, delete and destroy the work, and then find and kill the " +
@ -342,4 +342,4 @@ export const BlackOperations: IMap<BlackOperation> = {};
weights:{hack:0.1,str:0.2,def:0.2,dex:0.2,agi:0.2,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.75},
});
})()
})()

@ -135,6 +135,10 @@ class DevMenuComponent extends Component {
Player.getHomeComputer().maxRam *= 2;
}
quickB1tFlum3() {
hackWorldDaemon(Player.bitNodeN, true, true);
}
b1tflum3() {
hackWorldDaemon(Player.bitNodeN, true);
}
@ -705,7 +709,8 @@ class DevMenuComponent extends Component {
<button className="std-button" onClick={this.upgradeRam}>Upgrade Home Computer's RAM</button>
</div>
<div className="row">
<button className="std-button" onClick={this.b1tflum3}>Run bit_flum3.exe</button>
<button className="std-button" onClick={this.quickB1tFlum3}>Quick b1t_flum3.exe</button>
<button className="std-button" onClick={this.b1tflum3}>Run b1t_flum3.exe</button>
<button className="std-button" onClick={this.hackW0r1dD43m0n}>Hack w0rld_d34m0n</button>
</div>
<div className="row">

@ -4,8 +4,8 @@ export function applyExploit(): void {
if (Player.exploits && Player.exploits.length === 0) {
return;
}
const inc = Math.pow(1.0001, Player.exploits.length);
const dec = Math.pow(0.9999, Player.exploits.length);
const inc = Math.pow(1.001, Player.exploits.length);
const dec = Math.pow(0.999, Player.exploits.length);
Player.hacking_chance_mult *= inc;
Player.hacking_speed_mult *= inc;

@ -16,6 +16,8 @@ import { dialogBoxCreate } from "../../../utils/DialogBox";
type IProps = {
faction: Faction;
disabled: boolean;
favorToDonate: number;
p: IPlayer;
rerender: () => void;
}
@ -36,9 +38,10 @@ export class DonateOption extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
donateAmt: 0,
status: <></>,
status: props.disabled ? <>Unlocked at {props.favorToDonate} favor with {props.faction.name}</> : <></>,
}
this.calculateRepGain = this.calculateRepGain.bind(this);
@ -90,10 +93,17 @@ export class DonateOption extends React.Component<IProps, IState> {
return (
<div className={"faction-work-div"}>
<div className={"faction-work-div-wrapper"}>
<input className="text-input" onChange={this.handleChange} placeholder={"Donation amount"} style={inputStyleMarkup} />
<input
className="text-input"
onChange={this.handleChange}
placeholder={"Donation amount"}
style={inputStyleMarkup}
disabled={this.props.disabled}
/>
<StdButton
onClick={this.donate}
text={"Donate Money"}
disabled={this.props.disabled}
/>
<p style={this.blockStyle}>{this.state.status}</p>
</div>

@ -264,11 +264,13 @@ export class FactionRoot extends React.Component<IProps, IState> {
/>
}
{
(!isPlayersGang && canDonate) &&
!isPlayersGang &&
<DonateOption
faction={this.props.faction}
p={this.props.p}
rerender={this.rerender}
favorToDonate={favorToDonate}
disabled={!canDonate}
/>
}
<Option

@ -23,6 +23,8 @@ export const RamCostConstants: IMap<number> = {
ScriptGetHackingLevelRamCost: 0.05,
ScriptGetMultipliersRamCost: 4.0,
ScriptGetServerRamCost: 0.1,
ScriptGetServerMaxRam: 0.05,
ScriptGetServerUsedRam: 0.05,
ScriptFileExistsRamCost: 0.1,
ScriptIsRunningRamCost: 0.1,
ScriptHacknetNodesRamCost: 4.0,
@ -122,6 +124,8 @@ export const RamCosts: IMap<any> = {
getServerGrowth: () => RamCostConstants.ScriptGetServerRamCost,
getServerNumPortsRequired: () => RamCostConstants.ScriptGetServerRamCost,
getServerRam: () => RamCostConstants.ScriptGetServerRamCost,
getServerMaxRam: () => RamCostConstants.ScriptGetServerMaxRam,
getServerUsedRam: () => RamCostConstants.ScriptGetServerUsedRam,
serverExists: () => RamCostConstants.ScriptGetServerRamCost,
fileExists: () => RamCostConstants.ScriptFileExistsRamCost,
isRunning: () => RamCostConstants.ScriptIsRunningRamCost,

@ -670,7 +670,7 @@ function NetscriptFunctions(workerScript) {
throw makeRuntimeErrorMsg('hack', canHack.msg);
}
workerScript.log("hack", `Executing ${ip} in ${hackingTime.toFixed(3)} seconds (t=${threads})`);
workerScript.log("hack", `Executing ${ip} in ${convertTimeMsToTimeElapsedString(hackingTime*1000, true)} (t=${numeralWrapper.formatThreads(threads)})`);
return netscriptDelay(hackingTime * 1000, workerScript).then(function() {
if (workerScript.env.stopFlag) {return Promise.reject(workerScript);}
@ -706,7 +706,7 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.recordHack(server.ip, moneyGained, threads);
Player.gainHackingExp(expGainedOnSuccess);
workerScript.scriptRef.onlineExpGained += expGainedOnSuccess;
workerScript.log("hack", `Successfully hacked '${server.hostname}' for ${numeralWrapper.formatMoney(moneyGained)} and ${numeralWrapper.formatExp(expGainedOnSuccess)} exp (t=${threads})`);
workerScript.log("hack", `Successfully hacked '${server.hostname}' for ${numeralWrapper.formatMoney(moneyGained)} and ${numeralWrapper.formatExp(expGainedOnSuccess)} exp (t=${numeralWrapper.formatThreads(threads)})`);
server.fortify(CONSTANTS.ServerFortifyAmount * Math.min(threads, maxThreadNeeded));
if (stock) {
influenceStockThroughServerHack(server, moneyGained);
@ -719,7 +719,7 @@ function NetscriptFunctions(workerScript) {
// Player only gains 25% exp for failure?
Player.gainHackingExp(expGainedOnFailure);
workerScript.scriptRef.onlineExpGained += expGainedOnFailure;
workerScript.log("hack", `Failed to hack '${server.hostname}'. Gained ${numeralWrapper.formatExp(expGainedOnFailure)} exp (t=${threads})`);
workerScript.log("hack", `Failed to hack '${server.hostname}'. Gained ${numeralWrapper.formatExp(expGainedOnFailure)} exp (t=${numeralWrapper.formatThreads(threads)})`);
return Promise.resolve(0);
}
});
@ -937,7 +937,7 @@ function NetscriptFunctions(workerScript) {
}
var growTime = calculateGrowTime(server, Player);
workerScript.log("grow", `Executing on '${server.hostname}' in ${formatNumber(growTime, 3)} seconds (t=${threads}).`);
workerScript.log("grow", `Executing on '${server.hostname}' in ${convertTimeMsToTimeElapsedString(growTime*1000, true)} (t=${numeralWrapper.formatThreads(threads)}).`);
return netscriptDelay(growTime * 1000, workerScript).then(function() {
if (workerScript.env.stopFlag) {return Promise.reject(workerScript);}
const moneyBefore = server.moneyAvailable <= 0 ? 1 : server.moneyAvailable;
@ -950,7 +950,7 @@ function NetscriptFunctions(workerScript) {
expGain = 0;
}
const logGrowPercent = (moneyAfter/moneyBefore)*100 - 100;
workerScript.log("grow", `Available money on '${server.hostname}' grown by ${formatNumber(logGrowPercent, 6)}%. Gained ${numeralWrapper.formatExp(expGain)} hacking exp (t=${threads}).`);
workerScript.log("grow", `Available money on '${server.hostname}' grown by ${formatNumber(logGrowPercent, 6)}%. Gained ${numeralWrapper.formatExp(expGain)} hacking exp (t=${numeralWrapper.formatThreads(threads)}).`);
workerScript.scriptRef.onlineExpGained += expGain;
Player.gainHackingExp(expGain);
if (stock) {
@ -988,13 +988,13 @@ function NetscriptFunctions(workerScript) {
}
var weakenTime = calculateWeakenTime(server, Player);
workerScript.log("weaken", `Executing on '${server.hostname}' in ${formatNumber(weakenTime, 3)} seconds (t=${threads})`);
workerScript.log("weaken", `Executing on '${server.hostname}' in ${convertTimeMsToTimeElapsedString(weakenTime*1000, true)} (t=${numeralWrapper.formatThreads(threads)})`);
return netscriptDelay(weakenTime * 1000, workerScript).then(function() {
if (workerScript.env.stopFlag) {return Promise.reject(workerScript);}
server.weaken(CONSTANTS.ServerWeakenAmount * threads);
workerScript.scriptRef.recordWeaken(server.ip, threads);
var expGain = calculateHackingExpGain(server, Player) * threads;
workerScript.log("weaken", `'${server.hostname}' security level weakened to ${server.hackDifficulty}. Gained ${numeralWrapper.formatExp(expGain)} hacking exp (t=${threads})`);
workerScript.log("weaken", `'${server.hostname}' security level weakened to ${server.hackDifficulty}. Gained ${numeralWrapper.formatExp(expGain)} hacking exp (t=${numeralWrapper.formatThreads(threads)})`);
workerScript.scriptRef.onlineExpGained += expGain;
Player.gainHackingExp(expGain);
return Promise.resolve(CONSTANTS.ServerWeakenAmount * threads);
@ -1619,7 +1619,7 @@ function NetscriptFunctions(workerScript) {
},
getBitNodeMultipliers: function() {
updateDynamicRam("getBitNodeMultipliers", getRamCost("getBitNodeMultipliers"));
if (SourceFileFlags[5] <= 0) {
if (SourceFileFlags[5] <= 0 && Player.bitNodeN !== 5) {
throw makeRuntimeErrorMsg("getBitNodeMultipliers", "Requires Source-File 5 to run.");
}
let copy = Object.assign({}, BitNodeMultipliers);
@ -1709,6 +1709,18 @@ function NetscriptFunctions(workerScript) {
workerScript.log("getServerRam", `returned [${formatNumber(server.maxRam, 2)}GB, ${formatNumber(server.ramUsed, 2)}GB]`);
return [server.maxRam, server.ramUsed];
},
getServerMaxRam: function(ip) {
updateDynamicRam("getServerMaxRam", getRamCost("getServerMaxRam"));
const server = safeGetServer(ip, "getServerMaxRam");
workerScript.log("getServerMaxRam", `returned ${formatNumber(server.maxRam, 2)}GB`);
return server.maxRam;
},
getServerUsedRam: function(ip) {
updateDynamicRam("getServerUsedRam", getRamCost("getServerUsedRam"));
const server = safeGetServer(ip, "getServerUsedRam");
workerScript.log("getServerUsedRam", `returned ${formatNumber(server.ramUsed, 2)}GB`);
return server.ramUsed;
},
serverExists: function(ip) {
updateDynamicRam("serverExists", getRamCost("serverExists"));
return (getServer(ip) !== null);

@ -368,5 +368,10 @@ function updateAugDescription(elems: IResleeveUIElems): void {
return;
}
elems.augDescription.innerHTML = aug.info;
let innerHTML = aug.info;
if(typeof innerHTML !== 'string') {
innerHTML = renderToStaticMarkup(innerHTML);
}
elems.augDescription.innerHTML = innerHTML;
}

@ -907,7 +907,7 @@ export class Sleeve extends Person {
this.currentTaskLocation = LocationName.Sector12PowerhouseGym;
costMult = 20;
break;
case LocationName.VolhavenMilleniumFitnessGym:
case LocationName.VolhavenMilleniumFitnessGym.toLowerCase():
if (this.city != CityName.Volhaven) { return false; }
this.currentTaskLocation = LocationName.VolhavenMilleniumFitnessGym;
costMult = 7;

@ -55,10 +55,15 @@ export function createSleevePurchaseAugsPopup(sleeve: Sleeve, p: IPlayer): void
continue;
}
let tooltip = aug.info;
if(typeof tooltip !== 'string') {
tooltip = renderToStaticMarkup(tooltip);
}
ownedAugsDiv.appendChild(createElement("div", {
class: "gang-owned-upgrade", // Reusing a class from the Gang UI
innerText: ownedAug,
tooltip: aug.info,
tooltip: tooltip,
}))
}
popupElems.push(ownedAugsDiv);
@ -83,13 +88,18 @@ export function createSleevePurchaseAugsPopup(sleeve: Sleeve, p: IPlayer): void
class: "cmpy-mgmt-upgrade-div", // We'll reuse this CSS class
});
let info = aug.info;
if(typeof info !== 'string') {
info = renderToStaticMarkup(info);
}
div.appendChild(createElement("p", {
fontSize: "12px",
innerHTML:
[
`<h2>${aug.name}</h2><br>`,
`Cost: ${renderToStaticMarkup(Money(aug.startingCost))}<br><br>`,
`${aug.info}`,
`${info}`,
].join(" "),
padding: "2px",
clickListener: () => {

@ -340,6 +340,11 @@ function prestigeSourceFile() {
updateHashManagerCapacity();
}
if(SourceFileFlags[12] > 0) {
Player.augmentations.push({name: AugmentationNames.NeuroFluxGovernor, level: SourceFileFlags[12]})
Player.reapplyAllAugmentations(true);
}
// Refresh Main Menu (the 'World' menu, specifically)
document.getElementById("world-menu-header").click();
document.getElementById("world-menu-header").click();

@ -58,13 +58,17 @@ function writeRedPillLetter(pElem, line, i=0) {
}
let redPillFlag = false;
function hackWorldDaemon(currentNodeNumber, flume=false) {
function hackWorldDaemon(currentNodeNumber, flume=false, quick=false) {
// Clear Red Pill screen first
var container = document.getElementById("red-pill-content");
removeChildrenFromElement(container);
redPillFlag = true;
Engine.loadRedPillContent();
if(quick) {
return loadBitVerse(currentNodeNumber, flume, quick);
}
return writeRedPillLine("[ERROR] SEMPOOL INVALID").then(function() {
return writeRedPillLine("[ERROR] Segmentation Fault");
}).then(function() {
@ -143,7 +147,7 @@ function giveSourceFile(bitNodeNumber) {
// is destroyed. Updated every time loadBitVerse() is called
let nextSourceFileFlags = [];
function loadBitVerse(destroyedBitNodeNum, flume=false) {
function loadBitVerse(destroyedBitNodeNum, flume=false, quick=false) {
// Clear the screen
const container = document.getElementById("red-pill-content");
removeChildrenFromElement(container);
@ -151,7 +155,7 @@ function loadBitVerse(destroyedBitNodeNum, flume=false) {
// Update NextSourceFileFlags
nextSourceFileFlags = SourceFileFlags.slice();
if (!flume) {
if (nextSourceFileFlags[destroyedBitNodeNum] < 3 && destroyedBitNodeNum !== 12)
if (nextSourceFileFlags[destroyedBitNodeNum] < 3)
++nextSourceFileFlags[destroyedBitNodeNum];
}
@ -221,6 +225,10 @@ function loadBitVerse(destroyedBitNodeNum, flume=false) {
}(i)); // Immediate invocation closure
}
if(quick) {
return Promise.resolve(true);
}
// Create lore text
return writeRedPillLine("Many decades ago, a humanoid extraterrestial species which we call the Enders descended on the Earth...violently").then(function() {
return writeRedPillLine("Our species fought back, but it was futile. The Enders had technology far beyond our own...");

@ -1203,10 +1203,10 @@ export const serverMetadata: IServerMetadata[] = [
},
{
hackDifficulty: 1,
hostname: "foodnstuff",
hostname: "n00dles",
literature: [LiteratureNames.Sector12Crime],
maxRamExponent: 4,
moneyAvailable: 40000,
maxRamExponent: 2,
moneyAvailable: 70000,
networkLayer: 1,
numOpenPortsRequired: 0,
organizationName: LocationName.Sector12FoodNStuff,
@ -1215,26 +1215,39 @@ export const serverMetadata: IServerMetadata[] = [
specialName: LocationName.Sector12FoodNStuff,
},
{
hackDifficulty: 3,
hackDifficulty: 10,
hostname: "foodnstuff",
literature: [LiteratureNames.Sector12Crime],
maxRamExponent: 4,
moneyAvailable: 2000000,
networkLayer: 1,
numOpenPortsRequired: 0,
organizationName: LocationName.Sector12FoodNStuff,
requiredHackingSkill: 1,
serverGrowth: 5,
specialName: LocationName.Sector12FoodNStuff,
},
{
hackDifficulty: 10,
hostname: "sigma-cosmetics",
maxRamExponent: 4,
moneyAvailable: 70000,
moneyAvailable: 2300000,
networkLayer: 1,
numOpenPortsRequired: 0,
organizationName: "Sigma Cosmetics",
requiredHackingSkill: 5,
serverGrowth: 3000,
serverGrowth: 10,
},
{
hackDifficulty: 9,
hackDifficulty: 15,
hostname: "joesguns",
maxRamExponent: 4,
moneyAvailable: 600000,
moneyAvailable: 2500000,
networkLayer: 1,
numOpenPortsRequired: 0,
organizationName: LocationName.Sector12JoesGuns,
requiredHackingSkill: 10,
serverGrowth: 500,
serverGrowth: 20,
specialName: LocationName.Sector12JoesGuns,
},
{
@ -1569,4 +1582,4 @@ export const serverMetadata: IServerMetadata[] = [
serverGrowth: 0,
specialName: "w0r1d_d43m0n",
},
];
];

@ -60,5 +60,4 @@ SourceFiles["SourceFile11"] = new SourceFile(11, "This Source-File makes it so t
"Level 1: 32%<br>" +
"Level 2: 48%<br>" +
"Level 3: 56%<br>");
SourceFiles["SourceFile12"] = new SourceFile(12, "This Source-File increases all your multipliers by 1% per level. This effect is multiplicative with itself. " +
"In other words, level N of this Source-File will result in a multiplier of 1.01^N (or 0.99^N for multipliers that decrease)");
SourceFiles["SourceFile12"] = new SourceFile(12, "This Source-File lets the player start with Neuroflux Governor equal to the level of this Source-File.");

@ -141,44 +141,9 @@ export function applySourceFile(srcFile: PlayerOwnedSourceFile): void {
Player.company_rep_mult *= incMult;
break;
}
case 12: { // The Recursion
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;
case 12: // The Recursion
// No effects, grants neuroflux.
break;
}
default:
console.error(`Invalid source file number: ${srcFile.n}`);
break;

@ -53,7 +53,11 @@ import { Player } from "./Player";
import { hackWorldDaemon } from "./RedPill";
import { RunningScript } from "./Script/RunningScript";
import { getRamUsageFromRunningScript } from "./Script/RunningScriptHelpers";
import { getCurrentEditor, findRunningScript } from "./Script/ScriptHelpers";
import {
getCurrentEditor,
findRunningScript,
findRunningScriptByPid,
} from "./Script/ScriptHelpers";
import { isScriptFilename } from "./Script/ScriptHelpersTS";
import { AllServers } from "./Server/AllServers";
import {
@ -571,47 +575,26 @@ let Terminal = {
let currServ = Player.getCurrentServer();
const isHacknet = currServ instanceof HacknetServer;
post(currServ.hostname + ": ");
post("Organization name: " + currServ.organizationName);
var rootAccess = "";
if (currServ.hasAdminRights) {rootAccess = "YES";}
else {rootAccess = "NO";}
post("Root Access: " + rootAccess);
if (!isHacknet) { post("Required hacking skill: " + currServ.requiredHackingSkill); }
post("Server security level: " + numeralWrapper.formatServerSecurity(currServ.hackDifficulty));
post("Chance to hack: " + numeralWrapper.formatPercentage(calculateHackingChance(currServ, Player)));
post("Time to hack: " + convertTimeMsToTimeElapsedString(calculateHackingTime(currServ, Player)*1000));
postElement(<>Total money available on server: {Money(currServ.moneyAvailable)}</>);
if (!isHacknet) { post("Required number of open ports for NUKE: " + currServ.numOpenPortsRequired); }
if (currServ.sshPortOpen) {
post("SSH port: Open")
} else {
post("SSH port: Closed")
}
if (currServ.ftpPortOpen) {
post("FTP port: Open")
} else {
post("FTP port: Closed")
}
if (currServ.smtpPortOpen) {
post("SMTP port: Open")
} else {
post("SMTP port: Closed")
}
if (currServ.httpPortOpen) {
post("HTTP port: Open")
} else {
post("HTTP port: Closed")
}
if (currServ.sqlPortOpen) {
post("SQL port: Open")
} else {
post("SQL port: Closed")
}
const org = currServ.organizationName
post("Organization name: " + (!isHacknet ? org : "Player"));
const admin = currServ.hasAdminRights;
post("Root Access: " + (!isHacknet ? "YES" : "NO"));
const hackingSkill = currServ.requiredHackingSkill
post("Required hacking skill: " + (!isHacknet ? hackingSkill : "N/A"));
const security = currServ.hackDifficulty;
post("Server security level: " + (!isHacknet ? numeralWrapper.formatServerSecurity(security) : "N/A"));
const hackingChance = calculateHackingChance(currServ, Player)
post("Chance to hack: " + (!isHacknet ? numeralWrapper.formatPercentage(hackingChance) : "N/A"));
const hackingTime = calculateHackingTime(currServ, Player)*1000;
post("Time to hack: " + (!isHacknet ? convertTimeMsToTimeElapsedString(hackingTime, true) : "N/A"));
postElement(<>Total money available on server: {!isHacknet ? Money(currServ.moneyAvailable) : "N/A"}</>);
const numPort = currServ.numOpenPortsRequired;
post("Required number of open ports for NUKE: " + (!isHacknet ? numPort : "N/A"));
post("SSH port: "+ (currServ.sshPortOpen ? "Open" : "Closed"))
post("FTP port: "+ (currServ.ftpPortOpen ? "Open" : "Closed"))
post("SMTP port: "+ (currServ.smtpPortOpen ? "Open" : "Closed"))
post("HTTP port: "+ (currServ.httpPortOpen ? "Open" : "Closed"))
post("SQL port: "+ (currServ.sqlPortOpen ? "Open" : "Closed"))
}
Terminal.analyzeFlag = false;
},
@ -1405,10 +1388,10 @@ let Terminal = {
try {
if (commandArray.length < 2) {
postError("Incorrect number of arguments. Usage: tail [script] [arg1] [arg2]...");
} else {
} else if(typeof commandArray[1] === 'string') {
const scriptName = Terminal.getFilepath(commandArray[1]);
if (!isScriptFilename(scriptName)) {
postError("tail can only be called on .script files (filename must end with .script)");
postError("tail can only be called on .script, .ns, .js files, or by pid");
return;
}
@ -1425,6 +1408,13 @@ let Terminal = {
return;
}
logBoxCreate(runningScript);
} else {
const runningScript = findRunningScriptByPid(commandArray[1], Player.getCurrentServer());
if (runningScript == null) {
postError("No such script exists");
return;
}
logBoxCreate(runningScript);
}
} catch(e) {
Terminal.postThrownError(e);
@ -2136,13 +2126,19 @@ let Terminal = {
post("Invalid server IP/hostname");
return;
}
if(targetServer instanceof HacknetServer) {
post(`${Programs.ServerProfiler.name} cannot be run on a Hacknet Server.`);
return
}
post(targetServer.hostname + ":");
post("Server base security level: " + targetServer.baseDifficulty);
post("Server current security level: " + targetServer.hackDifficulty);
post("Server growth rate: " + targetServer.serverGrowth);
post(`Netscript hack() execution time: ${convertTimeMsToTimeElapsedString(calculateHackingTime(targetServer, Player)*1000)}`);
post(`Netscript grow() execution time: ${convertTimeMsToTimeElapsedString(calculateGrowTime(targetServer, Player)*1000)}`);
post(`Netscript weaken() execution time: ${convertTimeMsToTimeElapsedString(calculateWeakenTime(targetServer, Player)*1000)}`);
post(`Netscript hack() execution time: ${convertTimeMsToTimeElapsedString(calculateHackingTime(targetServer, Player)*1000, true)}`);
post(`Netscript grow() execution time: ${convertTimeMsToTimeElapsedString(calculateGrowTime(targetServer, Player)*1000, true)}`);
post(`Netscript weaken() execution time: ${convertTimeMsToTimeElapsedString(calculateWeakenTime(targetServer, Player)*1000, true)}`);
};
programHandlers[Programs.AutoLink.name] = () => {
post("This executable cannot be run.");

@ -340,8 +340,8 @@ if (htmlWebpackPlugin.options.googleAnalytics.trackingId) { %>
Would you like to join? <br /> <br />
Warning: Joining this faction may prevent you from joining other factions during this run!
</p>
<button id="faction-invitation-box-yes" class="popup-box-button"> Yes </button>
<button id="faction-invitation-box-no" class="popup-box-button"> No </button>
<button id="faction-invitation-box-yes" class="popup-box-button"> Join! </button>
<button id="faction-invitation-box-no" class="popup-box-button"> Decide later </button>
</div>
</div>

@ -49,7 +49,7 @@ export function WorkerScriptAccordion(props: IProps): React.ReactElement {
panelClass="active-scripts-script-panel"
panelContent={
<>
<pre>Threads: {props.workerScript.scriptRef.threads}</pre>
<pre>Threads: {numeralWrapper.formatThreads(props.workerScript.scriptRef.threads)}</pre>
<pre>Args: {arrayToString(props.workerScript.args)}</pre>
<pre>Online Time: {convertTimeMsToTimeElapsedString(scriptRef.onlineRunningTime * 1e3)}</pre>
<pre>Offline Time: {convertTimeMsToTimeElapsedString(scriptRef.offlineRunningTime * 1e3)}</pre>

@ -24,10 +24,19 @@ export function AugmentationAccordion(props: IProps): React.ReactElement {
}
}
if(typeof props.aug.info === 'string') {
return (
<Accordion
headerContent={<>{displayName}</>}
panelContent={<p dangerouslySetInnerHTML={{__html: props.aug.info}}></p>}
/>
)
}
return (
<Accordion
headerContent={<>{displayName}</>}
panelContent={<p dangerouslySetInnerHTML={{__html: props.aug.info}}></p>}
panelContent={<p>{props.aug.info}</p>}
/>
)
}

@ -15,8 +15,7 @@ export class CharacterOverviewComponent extends Component {
);
return (
<div id="character-overview-text">
<table>
<table>
<tbody>
<tr id="character-hp-wrapper">
<td className="character-hp-cell">Hp:</td><td id="character-hp-text" className="character-hp-cell character-stat-cell">{numeralWrapper.formatHp(Player.hp) + " / " + numeralWrapper.formatHp(Player.max_hp)}</td>
@ -47,8 +46,7 @@ export class CharacterOverviewComponent extends Component {
intelligence
}
</tbody>
</table>
</div>
</table>
)
}
}

@ -53,6 +53,9 @@ class NumeralFormatter {
}
formatMoney(n: number): string {
if(n < 1000) {
return this.format(n, "$0.00");
}
return this.format(n, "$0.000a");
}
@ -131,6 +134,10 @@ class NumeralFormatter {
formatInfiltrationSecurity(n: number): string {
return this.format(n, "0.000a");
}
formatThreads(n: number): string {
return this.format(n, "0,0");
}
}
export const numeralWrapper = new NumeralFormatter();

@ -394,6 +394,16 @@ describe("Netscript Dynamic RAM Calculation/Generation Tests", function() {
await testNonzeroDynamicRamCost(f);
});
it("getServerMaxRam()", async function() {
const f = ["getServerMaxRam"];
await testNonzeroDynamicRamCost(f);
});
it("getServerUsedRam()", async function() {
const f = ["getServerUsedRam"];
await testNonzeroDynamicRamCost(f);
});
it("serverExists()", async function() {
const f = ["serverExists"];
await testNonzeroDynamicRamCost(f);

@ -284,6 +284,16 @@ describe("Netscript Static RAM Calculation/Generation Tests", function() {
await expectNonZeroRamCost(f);
});
it("getServerMaxRam()", async function() {
const f = ["getServerMaxRam"];
await expectNonZeroRamCost(f);
});
it("getServerUsedRam()", async function() {
const f = ["getServerUsedRam"];
await expectNonZeroRamCost(f);
});
it("serverExists()", async function() {
const f = ["serverExists"];
await expectNonZeroRamCost(f);

@ -0,0 +1,11 @@
import { expect } from "chai";
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
describe("StringHelperFunctions Tests", function() {
expect(convertTimeMsToTimeElapsedString(1000)).to.equal("1 seconds");
expect(convertTimeMsToTimeElapsedString(5*60*1000+34*1000)).to.equal("5 minutes 34 seconds");
expect(convertTimeMsToTimeElapsedString(2*60*60*24*1000+5*60*1000+34*1000)).to.equal("2 days 5 minutes 34 seconds");
expect(convertTimeMsToTimeElapsedString(2*60*60*24*1000+5*60*1000+34*1000, true)).to.equal("2 days 5 minutes 34.000 seconds");
expect(convertTimeMsToTimeElapsedString(2*60*60*24*1000+5*60*1000+34*1000+123, true)).to.equal("2 days 5 minutes 34.123 seconds");
expect(convertTimeMsToTimeElapsedString(2*60*60*24*1000+5*60*1000+34*1000+123.888, true)).to.equal("2 days 5 minutes 34.123 seconds");
})

@ -1,4 +1,5 @@
export * from "./Netscript/DynamicRamCalculationTests";
export * from "./Netscript/StaticRamCalculationTests";
export * from "./StockMarketTests";
export * from "./StringHelperFunctionsTests";
export * from "./Terminal/DirectoryTests";

@ -13,7 +13,8 @@ Converts a date representing time in milliseconds to a string with the format H
e.g. 10000 -> "10 seconds"
120000 -> "2 minutes and 0 seconds"
*/
function convertTimeMsToTimeElapsedString(time: number): string {
function convertTimeMsToTimeElapsedString(time: number, showMilli=false): string {
time = Math.floor(time);
const millisecondsPerSecond = 1000;
const secondPerMinute = 60;
const minutesPerHours = 60;
@ -33,7 +34,13 @@ function convertTimeMsToTimeElapsedString(time: number): string {
const minutes: number = Math.floor(secTruncHours / secondPerMinute);
const secTruncMinutes: number = secTruncHours % secondPerMinute;
const seconds: number = secTruncMinutes;
const milliTruncSec: string = (() => {
let str: string = `${time % millisecondsPerSecond}`;
while(str.length < 3) str = "0"+str;
return str;
})()
const seconds: string = showMilli ? `${secTruncMinutes}.${milliTruncSec}` : `${secTruncMinutes}`;
let res = "";
if (days > 0) {res += `${days} days `; }