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) .. js:function:: getServerRam(hostname)
.. warning:: This function is deprecated.
:RAM cost: 0.1 GB :RAM cost: 0.1 GB
:param string hostname: Hostname of target server. :param string hostname: Hostname of target server.
:returns: An array of 2 number, first number is the total RAM, second the :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> getServerMinSecurityLevel() <basicfunctions/getServerMinSecurityLevel>
getServerRequiredHackingLevel() <basicfunctions/getServerRequiredHackingLevel> getServerRequiredHackingLevel() <basicfunctions/getServerRequiredHackingLevel>
getServerNumPortsRequired() <basicfunctions/getServerNumPortsRequired> getServerNumPortsRequired() <basicfunctions/getServerNumPortsRequired>
getServerRam() <basicfunctions/getServerRam> getServerMaxRam() <basicfunctions/getServerMaxRam>
getServerUsedRam() <basicfunctions/getServerUsedRam>
serverExists() <basicfunctions/serverExists> serverExists() <basicfunctions/serverExists>
fileExists() <basicfunctions/fileExists> fileExists() <basicfunctions/fileExists>
isRunning() <basicfunctions/isRunning> isRunning() <basicfunctions/isRunning>
@ -90,3 +91,8 @@ This includes information such as function signatures, what they do, and their r
wget() <basicfunctions/wget> wget() <basicfunctions/wget>
getFavorToDonate() <basicfunctions/getFavorToDonate> getFavorToDonate() <basicfunctions/getFavorToDonate>
flags() <basicfunctions/flags> 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. purchasing and upgrading of Hacknet Nodes.
This script attempts to purchase Hacknet Nodes until the player has a total of 8. Then 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 .. 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"); 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/> Would you like to join? <br/> <br/>
Warning: Joining this faction may prevent you from joining other factions during this run! Warning: Joining this faction may prevent you from joining other factions during this run!
</p> </p>
<button id="faction-invitation-box-yes" class="popup-box-button"> Yes </button> <button id="faction-invitation-box-yes" class="popup-box-button"> Join! </button>
<button id="faction-invitation-box-no" class="popup-box-button"> No </button> <button id="faction-invitation-box-no" class="popup-box-button"> Decide later. </button>
</div> </div>
</div> </div>

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

@ -60,7 +60,7 @@ function initAugmentations() {
"This augmentation increases the player's dexterity by 10%.", "This augmentation increases the player's dexterity by 10%.",
dexterity_mult: 1.1, 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"]); "OmniTek Incorporated", "KuaiGong International", "Blade Industries"]);
if (augmentationExists(AugmentationNames.Targeting1)) { if (augmentationExists(AugmentationNames.Targeting1)) {
delete Augmentations[AugmentationNames.Targeting1]; delete Augmentations[AugmentationNames.Targeting1];
@ -75,7 +75,7 @@ function initAugmentations() {
prereqs:[AugmentationNames.Targeting1], prereqs:[AugmentationNames.Targeting1],
dexterity_mult: 1.2, 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"]); "OmniTek Incorporated", "KuaiGong International", "Blade Industries"]);
if (augmentationExists(AugmentationNames.Targeting2)) { if (augmentationExists(AugmentationNames.Targeting2)) {
delete Augmentations[AugmentationNames.Targeting2]; delete Augmentations[AugmentationNames.Targeting2];
@ -136,7 +136,7 @@ function initAugmentations() {
strength_mult: 1.1, strength_mult: 1.1,
defense_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"]); "OmniTek Incorporated", "KuaiGong International", "Blade Industries"]);
if (augmentationExists(AugmentationNames.CombatRib1)) { if (augmentationExists(AugmentationNames.CombatRib1)) {
delete Augmentations[AugmentationNames.CombatRib1]; delete Augmentations[AugmentationNames.CombatRib1];
@ -152,7 +152,7 @@ function initAugmentations() {
strength_mult: 1.14, strength_mult: 1.14,
defense_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"]); "OmniTek Incorporated", "KuaiGong International", "Blade Industries"]);
if (augmentationExists(AugmentationNames.CombatRib2)) { if (augmentationExists(AugmentationNames.CombatRib2)) {
delete Augmentations[AugmentationNames.CombatRib2]; delete Augmentations[AugmentationNames.CombatRib2];
@ -428,7 +428,7 @@ function initAugmentations() {
"This augmentation increases the player's hacking speed by 3%.", "This augmentation increases the player's hacking speed by 3%.",
hacking_speed_mult: 1.03, hacking_speed_mult: 1.03,
}); });
SynapticEnhancement.addToFactions(["CyberSec"]); SynapticEnhancement.addToFactions(["CyberSec", "Aevum"]);
if (augmentationExists(AugmentationNames.SynapticEnhancement)) { if (augmentationExists(AugmentationNames.SynapticEnhancement)) {
delete Augmentations[AugmentationNames.SynapticEnhancement]; delete Augmentations[AugmentationNames.SynapticEnhancement];
} }
@ -756,7 +756,7 @@ function initAugmentations() {
"when working for a company by 20%.", "when working for a company by 20%.",
company_rep_mult: 1.2, 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"]); "Clarke Incorporated", "Four Sigma", "Bachman & Associates"]);
if (augmentationExists(AugmentationNames.NuoptimalInjectorImplant)) { if (augmentationExists(AugmentationNames.NuoptimalInjectorImplant)) {
delete Augmentations[AugmentationNames.NuoptimalInjectorImplant]; delete Augmentations[AugmentationNames.NuoptimalInjectorImplant];
@ -1064,7 +1064,7 @@ function initAugmentations() {
agility_exp_mult: 1.1, agility_exp_mult: 1.1,
charisma_exp_mult: 1.1, charisma_exp_mult: 1.1,
}); });
Neurotrainer1.addToFactions(["CyberSec"]); Neurotrainer1.addToFactions(["CyberSec", "Aevum"]);
if (augmentationExists(AugmentationNames.Neurotrainer1)) { if (augmentationExists(AugmentationNames.Neurotrainer1)) {
delete Augmentations[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>" + "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 " + "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 " + "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. " + "of Source-File 12 lets you start any BitNodes with NeuroFlux Governor equal to the level of this source file.");
"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)");
// Books: Frontera, Shiner // Books: Frontera, Shiner
BitNodes["BitNode13"] = new BitNode(13, "fOS", "COMING SOON"); //Unlocks the new game mode and the rest of the BitNodes BitNodes["BitNode13"] = new BitNode(13, "fOS", "COMING SOON"); //Unlocks the new game mode and the rest of the BitNodes
BitNodes["BitNode14"] = new BitNode(14, "", "COMING SOON"); 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 " + "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 " + "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 " + "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 " + "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.", "them. I don't need to tell you how critical this mission is.",
baseDifficulty:20e3, reqdRank:40e3, baseDifficulty:20e3, reqdRank:40e3,
@ -231,7 +231,7 @@ export const BlackOperations: IMap<BlackOperation> = {};
"means that the supercomputer may be able to reason abstractly " + "means that the supercomputer may be able to reason abstractly " +
"and become self-aware.<br><br>" + "and become self-aware.<br><br>" +
"I do not need to remind you why sentient-level AIs pose a serious " + "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 " + "The research for this project is being conducted at one of Fulcrum " +
"Technologies secret facilities in Aevum, codenamed 'Alpha Ranch'. " + "Technologies secret facilities in Aevum, codenamed 'Alpha Ranch'. " +
"Infiltrate the compound, delete and destroy the work, and then find and kill the " + "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}, 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}, 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; Player.getHomeComputer().maxRam *= 2;
} }
quickB1tFlum3() {
hackWorldDaemon(Player.bitNodeN, true, true);
}
b1tflum3() { b1tflum3() {
hackWorldDaemon(Player.bitNodeN, true); 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> <button className="std-button" onClick={this.upgradeRam}>Upgrade Home Computer's RAM</button>
</div> </div>
<div className="row"> <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> <button className="std-button" onClick={this.hackW0r1dD43m0n}>Hack w0rld_d34m0n</button>
</div> </div>
<div className="row"> <div className="row">

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

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

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

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

@ -670,7 +670,7 @@ function NetscriptFunctions(workerScript) {
throw makeRuntimeErrorMsg('hack', canHack.msg); 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() { return netscriptDelay(hackingTime * 1000, workerScript).then(function() {
if (workerScript.env.stopFlag) {return Promise.reject(workerScript);} if (workerScript.env.stopFlag) {return Promise.reject(workerScript);}
@ -706,7 +706,7 @@ function NetscriptFunctions(workerScript) {
workerScript.scriptRef.recordHack(server.ip, moneyGained, threads); workerScript.scriptRef.recordHack(server.ip, moneyGained, threads);
Player.gainHackingExp(expGainedOnSuccess); Player.gainHackingExp(expGainedOnSuccess);
workerScript.scriptRef.onlineExpGained += 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)); server.fortify(CONSTANTS.ServerFortifyAmount * Math.min(threads, maxThreadNeeded));
if (stock) { if (stock) {
influenceStockThroughServerHack(server, moneyGained); influenceStockThroughServerHack(server, moneyGained);
@ -719,7 +719,7 @@ function NetscriptFunctions(workerScript) {
// Player only gains 25% exp for failure? // Player only gains 25% exp for failure?
Player.gainHackingExp(expGainedOnFailure); Player.gainHackingExp(expGainedOnFailure);
workerScript.scriptRef.onlineExpGained += 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); return Promise.resolve(0);
} }
}); });
@ -937,7 +937,7 @@ function NetscriptFunctions(workerScript) {
} }
var growTime = calculateGrowTime(server, Player); 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() { return netscriptDelay(growTime * 1000, workerScript).then(function() {
if (workerScript.env.stopFlag) {return Promise.reject(workerScript);} if (workerScript.env.stopFlag) {return Promise.reject(workerScript);}
const moneyBefore = server.moneyAvailable <= 0 ? 1 : server.moneyAvailable; const moneyBefore = server.moneyAvailable <= 0 ? 1 : server.moneyAvailable;
@ -950,7 +950,7 @@ function NetscriptFunctions(workerScript) {
expGain = 0; expGain = 0;
} }
const logGrowPercent = (moneyAfter/moneyBefore)*100 - 100; 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; workerScript.scriptRef.onlineExpGained += expGain;
Player.gainHackingExp(expGain); Player.gainHackingExp(expGain);
if (stock) { if (stock) {
@ -988,13 +988,13 @@ function NetscriptFunctions(workerScript) {
} }
var weakenTime = calculateWeakenTime(server, Player); 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() { return netscriptDelay(weakenTime * 1000, workerScript).then(function() {
if (workerScript.env.stopFlag) {return Promise.reject(workerScript);} if (workerScript.env.stopFlag) {return Promise.reject(workerScript);}
server.weaken(CONSTANTS.ServerWeakenAmount * threads); server.weaken(CONSTANTS.ServerWeakenAmount * threads);
workerScript.scriptRef.recordWeaken(server.ip, threads); workerScript.scriptRef.recordWeaken(server.ip, threads);
var expGain = calculateHackingExpGain(server, Player) * 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; workerScript.scriptRef.onlineExpGained += expGain;
Player.gainHackingExp(expGain); Player.gainHackingExp(expGain);
return Promise.resolve(CONSTANTS.ServerWeakenAmount * threads); return Promise.resolve(CONSTANTS.ServerWeakenAmount * threads);
@ -1619,7 +1619,7 @@ function NetscriptFunctions(workerScript) {
}, },
getBitNodeMultipliers: function() { getBitNodeMultipliers: function() {
updateDynamicRam("getBitNodeMultipliers", getRamCost("getBitNodeMultipliers")); updateDynamicRam("getBitNodeMultipliers", getRamCost("getBitNodeMultipliers"));
if (SourceFileFlags[5] <= 0) { if (SourceFileFlags[5] <= 0 && Player.bitNodeN !== 5) {
throw makeRuntimeErrorMsg("getBitNodeMultipliers", "Requires Source-File 5 to run."); throw makeRuntimeErrorMsg("getBitNodeMultipliers", "Requires Source-File 5 to run.");
} }
let copy = Object.assign({}, BitNodeMultipliers); 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]`); workerScript.log("getServerRam", `returned [${formatNumber(server.maxRam, 2)}GB, ${formatNumber(server.ramUsed, 2)}GB]`);
return [server.maxRam, server.ramUsed]; 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) { serverExists: function(ip) {
updateDynamicRam("serverExists", getRamCost("serverExists")); updateDynamicRam("serverExists", getRamCost("serverExists"));
return (getServer(ip) !== null); return (getServer(ip) !== null);

@ -368,5 +368,10 @@ function updateAugDescription(elems: IResleeveUIElems): void {
return; 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; this.currentTaskLocation = LocationName.Sector12PowerhouseGym;
costMult = 20; costMult = 20;
break; break;
case LocationName.VolhavenMilleniumFitnessGym: case LocationName.VolhavenMilleniumFitnessGym.toLowerCase():
if (this.city != CityName.Volhaven) { return false; } if (this.city != CityName.Volhaven) { return false; }
this.currentTaskLocation = LocationName.VolhavenMilleniumFitnessGym; this.currentTaskLocation = LocationName.VolhavenMilleniumFitnessGym;
costMult = 7; costMult = 7;

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

@ -340,6 +340,11 @@ function prestigeSourceFile() {
updateHashManagerCapacity(); updateHashManagerCapacity();
} }
if(SourceFileFlags[12] > 0) {
Player.augmentations.push({name: AugmentationNames.NeuroFluxGovernor, level: SourceFileFlags[12]})
Player.reapplyAllAugmentations(true);
}
// Refresh Main Menu (the 'World' menu, specifically) // Refresh Main Menu (the 'World' menu, specifically)
document.getElementById("world-menu-header").click(); document.getElementById("world-menu-header").click();
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; let redPillFlag = false;
function hackWorldDaemon(currentNodeNumber, flume=false) { function hackWorldDaemon(currentNodeNumber, flume=false, quick=false) {
// Clear Red Pill screen first // Clear Red Pill screen first
var container = document.getElementById("red-pill-content"); var container = document.getElementById("red-pill-content");
removeChildrenFromElement(container); removeChildrenFromElement(container);
redPillFlag = true; redPillFlag = true;
Engine.loadRedPillContent(); Engine.loadRedPillContent();
if(quick) {
return loadBitVerse(currentNodeNumber, flume, quick);
}
return writeRedPillLine("[ERROR] SEMPOOL INVALID").then(function() { return writeRedPillLine("[ERROR] SEMPOOL INVALID").then(function() {
return writeRedPillLine("[ERROR] Segmentation Fault"); return writeRedPillLine("[ERROR] Segmentation Fault");
}).then(function() { }).then(function() {
@ -143,7 +147,7 @@ function giveSourceFile(bitNodeNumber) {
// is destroyed. Updated every time loadBitVerse() is called // is destroyed. Updated every time loadBitVerse() is called
let nextSourceFileFlags = []; let nextSourceFileFlags = [];
function loadBitVerse(destroyedBitNodeNum, flume=false) { function loadBitVerse(destroyedBitNodeNum, flume=false, quick=false) {
// Clear the screen // Clear the screen
const container = document.getElementById("red-pill-content"); const container = document.getElementById("red-pill-content");
removeChildrenFromElement(container); removeChildrenFromElement(container);
@ -151,7 +155,7 @@ function loadBitVerse(destroyedBitNodeNum, flume=false) {
// Update NextSourceFileFlags // Update NextSourceFileFlags
nextSourceFileFlags = SourceFileFlags.slice(); nextSourceFileFlags = SourceFileFlags.slice();
if (!flume) { if (!flume) {
if (nextSourceFileFlags[destroyedBitNodeNum] < 3 && destroyedBitNodeNum !== 12) if (nextSourceFileFlags[destroyedBitNodeNum] < 3)
++nextSourceFileFlags[destroyedBitNodeNum]; ++nextSourceFileFlags[destroyedBitNodeNum];
} }
@ -221,6 +225,10 @@ function loadBitVerse(destroyedBitNodeNum, flume=false) {
}(i)); // Immediate invocation closure }(i)); // Immediate invocation closure
} }
if(quick) {
return Promise.resolve(true);
}
// Create lore text // 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("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..."); 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, hackDifficulty: 1,
hostname: "foodnstuff", hostname: "n00dles",
literature: [LiteratureNames.Sector12Crime], literature: [LiteratureNames.Sector12Crime],
maxRamExponent: 4, maxRamExponent: 2,
moneyAvailable: 40000, moneyAvailable: 70000,
networkLayer: 1, networkLayer: 1,
numOpenPortsRequired: 0, numOpenPortsRequired: 0,
organizationName: LocationName.Sector12FoodNStuff, organizationName: LocationName.Sector12FoodNStuff,
@ -1215,26 +1215,39 @@ export const serverMetadata: IServerMetadata[] = [
specialName: LocationName.Sector12FoodNStuff, 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", hostname: "sigma-cosmetics",
maxRamExponent: 4, maxRamExponent: 4,
moneyAvailable: 70000, moneyAvailable: 2300000,
networkLayer: 1, networkLayer: 1,
numOpenPortsRequired: 0, numOpenPortsRequired: 0,
organizationName: "Sigma Cosmetics", organizationName: "Sigma Cosmetics",
requiredHackingSkill: 5, requiredHackingSkill: 5,
serverGrowth: 3000, serverGrowth: 10,
}, },
{ {
hackDifficulty: 9, hackDifficulty: 15,
hostname: "joesguns", hostname: "joesguns",
maxRamExponent: 4, maxRamExponent: 4,
moneyAvailable: 600000, moneyAvailable: 2500000,
networkLayer: 1, networkLayer: 1,
numOpenPortsRequired: 0, numOpenPortsRequired: 0,
organizationName: LocationName.Sector12JoesGuns, organizationName: LocationName.Sector12JoesGuns,
requiredHackingSkill: 10, requiredHackingSkill: 10,
serverGrowth: 500, serverGrowth: 20,
specialName: LocationName.Sector12JoesGuns, specialName: LocationName.Sector12JoesGuns,
}, },
{ {
@ -1569,4 +1582,4 @@ export const serverMetadata: IServerMetadata[] = [
serverGrowth: 0, serverGrowth: 0,
specialName: "w0r1d_d43m0n", specialName: "w0r1d_d43m0n",
}, },
]; ];

@ -60,5 +60,4 @@ SourceFiles["SourceFile11"] = new SourceFile(11, "This Source-File makes it so t
"Level 1: 32%<br>" + "Level 1: 32%<br>" +
"Level 2: 48%<br>" + "Level 2: 48%<br>" +
"Level 3: 56%<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. " + SourceFiles["SourceFile12"] = new SourceFile(12, "This Source-File lets the player start with Neuroflux Governor equal to the level of this Source-File.");
"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)");

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

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

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

@ -49,7 +49,7 @@ export function WorkerScriptAccordion(props: IProps): React.ReactElement {
panelClass="active-scripts-script-panel" panelClass="active-scripts-script-panel"
panelContent={ 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>Args: {arrayToString(props.workerScript.args)}</pre>
<pre>Online Time: {convertTimeMsToTimeElapsedString(scriptRef.onlineRunningTime * 1e3)}</pre> <pre>Online Time: {convertTimeMsToTimeElapsedString(scriptRef.onlineRunningTime * 1e3)}</pre>
<pre>Offline Time: {convertTimeMsToTimeElapsedString(scriptRef.offlineRunningTime * 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 ( return (
<Accordion <Accordion
headerContent={<>{displayName}</>} 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 ( return (
<div id="character-overview-text"> <table>
<table>
<tbody> <tbody>
<tr id="character-hp-wrapper"> <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> <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 intelligence
} }
</tbody> </tbody>
</table> </table>
</div>
) )
} }
} }

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

@ -394,6 +394,16 @@ describe("Netscript Dynamic RAM Calculation/Generation Tests", function() {
await testNonzeroDynamicRamCost(f); 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() { it("serverExists()", async function() {
const f = ["serverExists"]; const f = ["serverExists"];
await testNonzeroDynamicRamCost(f); await testNonzeroDynamicRamCost(f);

@ -284,6 +284,16 @@ describe("Netscript Static RAM Calculation/Generation Tests", function() {
await expectNonZeroRamCost(f); 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() { it("serverExists()", async function() {
const f = ["serverExists"]; const f = ["serverExists"];
await expectNonZeroRamCost(f); 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/DynamicRamCalculationTests";
export * from "./Netscript/StaticRamCalculationTests"; export * from "./Netscript/StaticRamCalculationTests";
export * from "./StockMarketTests"; export * from "./StockMarketTests";
export * from "./StringHelperFunctionsTests";
export * from "./Terminal/DirectoryTests"; 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" e.g. 10000 -> "10 seconds"
120000 -> "2 minutes and 0 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 millisecondsPerSecond = 1000;
const secondPerMinute = 60; const secondPerMinute = 60;
const minutesPerHours = 60; const minutesPerHours = 60;
@ -33,7 +34,13 @@ function convertTimeMsToTimeElapsedString(time: number): string {
const minutes: number = Math.floor(secTruncHours / secondPerMinute); const minutes: number = Math.floor(secTruncHours / secondPerMinute);
const secTruncMinutes: number = 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 = ""; let res = "";
if (days > 0) {res += `${days} days `; } if (days > 0) {res += `${days} days `; }