Merge pull request from danielyxie/dev

Buncha fix
This commit is contained in:
hydroflame
2021-11-27 11:45:06 -05:00
committed by GitHub
36 changed files with 503 additions and 453 deletions

24
dist/vendor.bundle.js vendored

File diff suppressed because one or more lines are too long

@ -151,7 +151,7 @@ You may have noticed that every new ns2 file will contains the following comment
* @param {NS} ns * @param {NS} ns
**/ **/
This command is used to help the text editor autocomplete functions in the Netscript API. You can enabling it by pressing ctrl+space after `ns.` This comment is used to help the text editor autocomplete functions in the Netscript API. You can enabling it by pressing ctrl+space after `ns.`
.. image:: autocomplete.png .. image:: autocomplete.png

@ -34,7 +34,7 @@ Let's assume Port 1 starts out empty (no data inside). We'll represent the port
Now assume we ran the following simple script:: Now assume we ran the following simple script::
for (i = 0; i < 10; ++i) { for (i = 0; i < 10; ++i) {
write(1, i); //Writes the value of i to port 1 writePort(1, i); //Writes the value of i to port 1
} }
After this script executes, our script will contain every number from 0 through 9, as so:: After this script executes, our script will contain every number from 0 through 9, as so::
@ -44,7 +44,7 @@ After this script executes, our script will contain every number from 0 through
Then, assume we run the following script:: Then, assume we run the following script::
for (i = 0; i < 3; ++i) { for (i = 0; i < 3; ++i) {
print(read(1)); //Reads a value from port 1 and then prints it print(readPort(1)); //Reads a value from port 1 and then prints it
} }
This script above will read the first three values from port 1 and then print them to the script's log. The log will end up looking like:: This script above will read the first three values from port 1 and then print them to the script's log. The log will end up looking like::
@ -69,7 +69,7 @@ The :js:func:`getPortHandle` Netscript function can be used to get a handle to a
This handle allows you to access several new port-related functions and the This handle allows you to access several new port-related functions and the
port's underlying data structure, which is just a JavaScript array. The functions are: port's underlying data structure, which is just a JavaScript array. The functions are:
.. js:method:: NetscriptPort.write(data) .. js:method:: NetscriptPort.writePort(data)
:param data: Data to write to the port :param data: Data to write to the port
:returns: If the port is full, the item that is removed from the port is returned. :returns: If the port is full, the item that is removed from the port is returned.
@ -77,7 +77,7 @@ port's underlying data structure, which is just a JavaScript array. The function
Writes `data` to the port. Works the same as the Netscript function `write`. Writes `data` to the port. Works the same as the Netscript function `write`.
.. js:method:: NetscriptPort.tryWrite(data) .. js:method:: NetscriptPort.tryWritePort(data)
:param data: Data to try to write to the port :param data: Data to try to write to the port
:returns: True if the data is successfully written to the port, and false otherwise. :returns: True if the data is successfully written to the port, and false otherwise.
@ -85,7 +85,7 @@ port's underlying data structure, which is just a JavaScript array. The function
Attempts to write `data` to the Netscript port. If the port is full, the data will Attempts to write `data` to the Netscript port. If the port is full, the data will
not be written. Otherwise, the data will be written normally. not be written. Otherwise, the data will be written normally.
.. js::method:: NetscriptPort.read() .. js::method:: NetscriptPort.readPort()
:returns: The data read from the port. If the port is empty, "NULL PORT DATA" is returned :returns: The data read from the port. If the port is empty, "NULL PORT DATA" is returned

@ -13,12 +13,6 @@
<meta name="msapplication-TileColor" content="#000000"/> <meta name="msapplication-TileColor" content="#000000"/>
<meta name="msapplication-config" content="dist/browserconfig.xml"/> <meta name="msapplication-config" content="dist/browserconfig.xml"/>
<meta name="theme-color" content="#ffffff"/> <meta name="theme-color" content="#ffffff"/>
<script>
// Give a warning if you go back in browser history.
window.onbeforeunload = function () {
return "Your work will be lost.";
};
</script>
<!-- Google Analytics --> <!-- Google Analytics -->
<script> <script>
(function (i, s, o, g, r, a, m) { (function (i, s, o, g, r, a, m) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -2026,7 +2026,7 @@ export class Bladeburner implements IBladeburner {
const errorLogText = `Invalid action: type='${type}' name='${name}'`; const errorLogText = `Invalid action: type='${type}' name='${name}'`;
const actionId = this.getActionIdFromTypeAndName(type, name); const actionId = this.getActionIdFromTypeAndName(type, name);
if (actionId == null) { if (actionId == null) {
workerScript.log("bladeburner.startAction", errorLogText); workerScript.log("bladeburner.startAction", () => errorLogText);
return false; return false;
} }
@ -2038,13 +2038,13 @@ export class Bladeburner implements IBladeburner {
if (!(action instanceof BlackOperation)) throw new Error(`Action should be BlackOperation but isn't`); if (!(action instanceof BlackOperation)) throw new Error(`Action should be BlackOperation but isn't`);
//const blackOp = (action as BlackOperation); //const blackOp = (action as BlackOperation);
if (action.reqdRank > this.rank) { if (action.reqdRank > this.rank) {
workerScript.log("bladeburner.startAction", `Insufficient rank to start Black Op '${actionId.name}'.`); workerScript.log("bladeburner.startAction", () => `Insufficient rank to start Black Op '${actionId.name}'.`);
return false; return false;
} }
// Can't start a BlackOp if its already been done // Can't start a BlackOp if its already been done
if (this.blackops[actionId.name] != null) { if (this.blackops[actionId.name] != null) {
workerScript.log("bladeburner.startAction", `Black Op ${actionId.name} has already been completed.`); workerScript.log("bladeburner.startAction", () => `Black Op ${actionId.name} has already been completed.`);
return false; return false;
} }
@ -2061,14 +2061,14 @@ export class Bladeburner implements IBladeburner {
const i = blackops.indexOf(actionId.name); const i = blackops.indexOf(actionId.name);
if (i === -1) { if (i === -1) {
workerScript.log("bladeburner.startAction", `Invalid Black Op: '${name}'`); workerScript.log("bladeburner.startAction", () => `Invalid Black Op: '${name}'`);
return false; return false;
} }
if (i > 0 && this.blackops[blackops[i - 1]] == null) { if (i > 0 && this.blackops[blackops[i - 1]] == null) {
workerScript.log( workerScript.log(
"bladeburner.startAction", "bladeburner.startAction",
`Preceding Black Op must be completed before starting '${actionId.name}'.`, () => `Preceding Black Op must be completed before starting '${actionId.name}'.`,
); );
return false; return false;
} }
@ -2076,11 +2076,14 @@ export class Bladeburner implements IBladeburner {
try { try {
this.startAction(player, actionId); this.startAction(player, actionId);
workerScript.log("bladeburner.startAction", `Starting bladeburner action with type '${type}' and name ${name}"`); workerScript.log(
"bladeburner.startAction",
() => `Starting bladeburner action with type '${type}' and name ${name}"`,
);
return true; return true;
} catch (e: any) { } catch (e: any) {
this.resetAction(); this.resetAction();
workerScript.log("bladeburner.startAction", errorLogText); workerScript.log("bladeburner.startAction", () => errorLogText);
return false; return false;
} }
} }
@ -2089,13 +2092,13 @@ export class Bladeburner implements IBladeburner {
const errorLogText = `Invalid action: type='${type}' name='${name}'`; const errorLogText = `Invalid action: type='${type}' name='${name}'`;
const actionId = this.getActionIdFromTypeAndName(type, name); const actionId = this.getActionIdFromTypeAndName(type, name);
if (actionId == null) { if (actionId == null) {
workerScript.log("bladeburner.getActionTime", errorLogText); workerScript.log("bladeburner.getActionTime", () => errorLogText);
return -1; return -1;
} }
const actionObj = this.getActionObject(actionId); const actionObj = this.getActionObject(actionId);
if (actionObj == null) { if (actionObj == null) {
workerScript.log("bladeburner.getActionTime", errorLogText); workerScript.log("bladeburner.getActionTime", () => errorLogText);
return -1; return -1;
} }
@ -2116,7 +2119,7 @@ export class Bladeburner implements IBladeburner {
case ActionTypes["Incite Violence"]: case ActionTypes["Incite Violence"]:
return 60000; return 60000;
default: default:
workerScript.log("bladeburner.getActionTime", errorLogText); workerScript.log("bladeburner.getActionTime", () => errorLogText);
return -1; return -1;
} }
} }
@ -2130,13 +2133,13 @@ export class Bladeburner implements IBladeburner {
const errorLogText = `Invalid action: type='${type}' name='${name}'`; const errorLogText = `Invalid action: type='${type}' name='${name}'`;
const actionId = this.getActionIdFromTypeAndName(type, name); const actionId = this.getActionIdFromTypeAndName(type, name);
if (actionId == null) { if (actionId == null) {
workerScript.log("bladeburner.getActionEstimatedSuccessChance", errorLogText); workerScript.log("bladeburner.getActionEstimatedSuccessChance", () => errorLogText);
return [-1, -1]; return [-1, -1];
} }
const actionObj = this.getActionObject(actionId); const actionObj = this.getActionObject(actionId);
if (actionObj == null) { if (actionObj == null) {
workerScript.log("bladeburner.getActionEstimatedSuccessChance", errorLogText); workerScript.log("bladeburner.getActionEstimatedSuccessChance", () => errorLogText);
return [-1, -1]; return [-1, -1];
} }
@ -2158,7 +2161,7 @@ export class Bladeburner implements IBladeburner {
return [recChance, recChance]; return [recChance, recChance];
} }
default: default:
workerScript.log("bladeburner.getActionEstimatedSuccessChance", errorLogText); workerScript.log("bladeburner.getActionEstimatedSuccessChance", () => errorLogText);
return [-1, -1]; return [-1, -1];
} }
} }
@ -2167,13 +2170,13 @@ export class Bladeburner implements IBladeburner {
const errorLogText = `Invalid action: type='${type}' name='${name}'`; const errorLogText = `Invalid action: type='${type}' name='${name}'`;
const actionId = this.getActionIdFromTypeAndName(type, name); const actionId = this.getActionIdFromTypeAndName(type, name);
if (actionId == null) { if (actionId == null) {
workerScript.log("bladeburner.getActionCountRemaining", errorLogText); workerScript.log("bladeburner.getActionCountRemaining", () => errorLogText);
return -1; return -1;
} }
const actionObj = this.getActionObject(actionId); const actionObj = this.getActionObject(actionId);
if (actionObj == null) { if (actionObj == null) {
workerScript.log("bladeburner.getActionCountRemaining", errorLogText); workerScript.log("bladeburner.getActionCountRemaining", () => errorLogText);
return -1; return -1;
} }
@ -2197,14 +2200,14 @@ export class Bladeburner implements IBladeburner {
case ActionTypes["Incite Violence"]: case ActionTypes["Incite Violence"]:
return Infinity; return Infinity;
default: default:
workerScript.log("bladeburner.getActionCountRemaining", errorLogText); workerScript.log("bladeburner.getActionCountRemaining", () => errorLogText);
return -1; return -1;
} }
} }
getSkillLevelNetscriptFn(skillName: string, workerScript: WorkerScript): number { getSkillLevelNetscriptFn(skillName: string, workerScript: WorkerScript): number {
if (skillName === "" || !Skills.hasOwnProperty(skillName)) { if (skillName === "" || !Skills.hasOwnProperty(skillName)) {
workerScript.log("bladeburner.getSkillLevel", `Invalid skill: '${skillName}'`); workerScript.log("bladeburner.getSkillLevel", () => `Invalid skill: '${skillName}'`);
return -1; return -1;
} }
@ -2217,7 +2220,7 @@ export class Bladeburner implements IBladeburner {
getSkillUpgradeCostNetscriptFn(skillName: string, workerScript: WorkerScript): number { getSkillUpgradeCostNetscriptFn(skillName: string, workerScript: WorkerScript): number {
if (skillName === "" || !Skills.hasOwnProperty(skillName)) { if (skillName === "" || !Skills.hasOwnProperty(skillName)) {
workerScript.log("bladeburner.getSkillUpgradeCost", `Invalid skill: '${skillName}'`); workerScript.log("bladeburner.getSkillUpgradeCost", () => `Invalid skill: '${skillName}'`);
return -1; return -1;
} }
@ -2232,7 +2235,7 @@ export class Bladeburner implements IBladeburner {
upgradeSkillNetscriptFn(skillName: string, workerScript: WorkerScript): boolean { upgradeSkillNetscriptFn(skillName: string, workerScript: WorkerScript): boolean {
const errorLogText = `Invalid skill: '${skillName}'`; const errorLogText = `Invalid skill: '${skillName}'`;
if (!Skills.hasOwnProperty(skillName)) { if (!Skills.hasOwnProperty(skillName)) {
workerScript.log("bladeburner.upgradeSkill", errorLogText); workerScript.log("bladeburner.upgradeSkill", () => errorLogText);
return false; return false;
} }
@ -2244,13 +2247,14 @@ export class Bladeburner implements IBladeburner {
const cost = skill.calculateCost(currentLevel); const cost = skill.calculateCost(currentLevel);
if (skill.maxLvl && currentLevel >= skill.maxLvl) { if (skill.maxLvl && currentLevel >= skill.maxLvl) {
workerScript.log("bladeburner.upgradeSkill", `Skill '${skillName}' is already maxed.`); workerScript.log("bladeburner.upgradeSkill", () => `Skill '${skillName}' is already maxed.`);
return false; return false;
} }
if (this.skillPoints < cost) { if (this.skillPoints < cost) {
workerScript.log( workerScript.log(
"bladeburner.upgradeSkill", "bladeburner.upgradeSkill",
() =>
`You do not have enough skill points to upgrade ${skillName} (You have ${this.skillPoints}, you need ${cost})`, `You do not have enough skill points to upgrade ${skillName} (You have ${this.skillPoints}, you need ${cost})`,
); );
return false; return false;
@ -2258,7 +2262,7 @@ export class Bladeburner implements IBladeburner {
this.skillPoints -= cost; this.skillPoints -= cost;
this.upgradeSkill(skill); this.upgradeSkill(skill);
workerScript.log("bladeburner.upgradeSkill", `'${skillName}' upgraded to level ${this.skills[skillName]}`); workerScript.log("bladeburner.upgradeSkill", () => `'${skillName}' upgraded to level ${this.skills[skillName]}`);
return true; return true;
} }
@ -2270,13 +2274,13 @@ export class Bladeburner implements IBladeburner {
const errorLogText = `Invalid action: type='${type}' name='${name}'`; const errorLogText = `Invalid action: type='${type}' name='${name}'`;
const actionId = this.getActionIdFromTypeAndName(type, name); const actionId = this.getActionIdFromTypeAndName(type, name);
if (actionId == null) { if (actionId == null) {
workerScript.log("bladeburner.getTeamSize", errorLogText); workerScript.log("bladeburner.getTeamSize", () => errorLogText);
return -1; return -1;
} }
const actionObj = this.getActionObject(actionId); const actionObj = this.getActionObject(actionId);
if (actionObj == null) { if (actionObj == null) {
workerScript.log("bladeburner.getTeamSize", errorLogText); workerScript.log("bladeburner.getTeamSize", () => errorLogText);
return -1; return -1;
} }
@ -2295,7 +2299,7 @@ export class Bladeburner implements IBladeburner {
const errorLogText = `Invalid action: type='${type}' name='${name}'`; const errorLogText = `Invalid action: type='${type}' name='${name}'`;
const actionId = this.getActionIdFromTypeAndName(type, name); const actionId = this.getActionIdFromTypeAndName(type, name);
if (actionId == null) { if (actionId == null) {
workerScript.log("bladeburner.setTeamSize", errorLogText); workerScript.log("bladeburner.setTeamSize", () => errorLogText);
return -1; return -1;
} }
@ -2304,26 +2308,26 @@ export class Bladeburner implements IBladeburner {
actionId.type !== ActionTypes["BlackOp"] && actionId.type !== ActionTypes["BlackOp"] &&
actionId.type !== ActionTypes["BlackOperation"] actionId.type !== ActionTypes["BlackOperation"]
) { ) {
workerScript.log("bladeburner.setTeamSize", "Only valid for 'Operations' and 'BlackOps'"); workerScript.log("bladeburner.setTeamSize", () => "Only valid for 'Operations' and 'BlackOps'");
return -1; return -1;
} }
const actionObj = this.getActionObject(actionId); const actionObj = this.getActionObject(actionId);
if (actionObj == null) { if (actionObj == null) {
workerScript.log("bladeburner.setTeamSize", errorLogText); workerScript.log("bladeburner.setTeamSize", () => errorLogText);
return -1; return -1;
} }
let sanitizedSize = Math.round(size); let sanitizedSize = Math.round(size);
if (isNaN(sanitizedSize) || sanitizedSize < 0) { if (isNaN(sanitizedSize) || sanitizedSize < 0) {
workerScript.log("bladeburner.setTeamSize", `Invalid size: ${size}`); workerScript.log("bladeburner.setTeamSize", () => `Invalid size: ${size}`);
return -1; return -1;
} }
if (this.teamSize < sanitizedSize) { if (this.teamSize < sanitizedSize) {
sanitizedSize = this.teamSize; sanitizedSize = this.teamSize;
} }
actionObj.teamCount = sanitizedSize; actionObj.teamCount = sanitizedSize;
workerScript.log("bladeburner.setTeamSize", `Team size for '${name}' set to ${sanitizedSize}.`); workerScript.log("bladeburner.setTeamSize", () => `Team size for '${name}' set to ${sanitizedSize}.`);
return sanitizedSize; return sanitizedSize;
} }
@ -2333,12 +2337,12 @@ export class Bladeburner implements IBladeburner {
return true; return true;
} else if (this.rank >= BladeburnerConstants.RankNeededForFaction) { } else if (this.rank >= BladeburnerConstants.RankNeededForFaction) {
joinFaction(bladeburnerFac); joinFaction(bladeburnerFac);
workerScript.log("bladeburner.joinBladeburnerFaction", "Joined Bladeburners faction."); workerScript.log("bladeburner.joinBladeburnerFaction", () => "Joined Bladeburners faction.");
return true; return true;
} else { } else {
workerScript.log( workerScript.log(
"bladeburner.joinBladeburnerFaction", "bladeburner.joinBladeburnerFaction",
`You do not have the required rank (${this.rank}/${BladeburnerConstants.RankNeededForFaction}).`, () => `You do not have the required rank (${this.rank}/${BladeburnerConstants.RankNeededForFaction}).`,
); );
return false; return false;
} }

@ -2,7 +2,7 @@ import * as React from "react";
import { IPlayer } from "../PersonObjects/IPlayer"; import { IPlayer } from "../PersonObjects/IPlayer";
import { Money } from "../ui/React/Money"; import { Money } from "../ui/React/Money";
import { Game } from "./Game"; import { Game, reachedLimit } from "./Game";
import { Deck } from "./CardDeck/Deck"; import { Deck } from "./CardDeck/Deck";
import { Hand } from "./CardDeck/Hand"; import { Hand } from "./CardDeck/Hand";
import { InputAdornment } from "@mui/material"; import { InputAdornment } from "@mui/material";
@ -70,12 +70,12 @@ export class Blackjack extends Game<Props, State> {
}; };
startGame = (): void => { startGame = (): void => {
if (!this.canStartGame()) { if (!this.canStartGame() || reachedLimit(this.props.p)) {
return; return;
} }
// Take money from player right away so that player's dont just "leave" to avoid the loss (I mean they could // Take money from player right away so that player's dont just "leave" to avoid the loss (I mean they could
// always reload without saving but w.e) // always reload without saving but w.e) TODO: Save/Restore the RNG state to limit the value of save-scumming.
this.props.p.loseMoney(this.state.bet, "casino"); this.props.p.loseMoney(this.state.bet, "casino");
const playerHand = new Hand([this.deck.safeDrawCard(), this.deck.safeDrawCard()]); const playerHand = new Hand([this.deck.safeDrawCard(), this.deck.safeDrawCard()]);
@ -217,31 +217,26 @@ export class Blackjack extends Game<Props, State> {
}; };
finishGame = (result: Result): void => { finishGame = (result: Result): void => {
let gains = 0; const gains =
if (this.isPlayerWinResult(result)) { result === Result.DealerWon
gains = this.state.bet; ? 0 // We took away the bet at the start, don't need to take more
: result === Result.Tie
// We 2x the gains because we took away money at the start, so we need to give the original bet back. ? this.state.bet // We took away the bet at the start, give it back
this.win(this.props.p, 2 * gains); : result === Result.PlayerWon
} else if (result === Result.DealerWon) { ? 2 * this.state.bet // Give back their bet plus their winnings
gains = -1 * this.state.bet; : result === Result.PlayerWonByBlackjack
this.win(this.props.p, -this.state.bet); // Get the original bet back ? 2.5 * this.state.bet // Blackjack pays out 1.5x bet!
// Dont need to take money here since we already did it at the start : (() => {
} else if (result === Result.Tie) { throw new Error(`Unexpected result: ${result}`);
this.win(this.props.p, this.state.bet); // Get the original bet back })(); // This can't happen, right?
} this.win(this.props.p, gains);
this.setState({ this.setState({
gameInProgress: false, gameInProgress: false,
result, result,
gains: this.state.gains + gains, gains: this.state.gains + gains - this.state.bet, // Not updated upfront - only tracks the final outcome
}); });
}; };
isPlayerWinResult = (result: Result): boolean => {
return result === Result.PlayerWon || result === Result.PlayerWonByBlackjack;
};
wagerOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => { wagerOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
const { p } = this.props; const { p } = this.props;
const betInput = event.target.value; const betInput = event.target.value;
@ -362,15 +357,17 @@ export class Blackjack extends Game<Props, State> {
<> <>
<Box display="flex"> <Box display="flex">
<Paper elevation={2}> <Paper elevation={2}>
<pre>Player</pre> <Typography>Player</Typography>
{playerHand.cards.map((card, i) => ( {playerHand.cards.map((card, i) => (
<ReactCard card={card} key={i} /> <ReactCard card={card} key={i} />
))} ))}
<pre>Value(s): </pre> <Typography>
{playerHandValues.map((value, i) => ( Count:{" "}
<pre key={i}>{value}</pre> {playerHandValues
))} .map<React.ReactNode>((value, i) => <span key={i}>{value}</span>)
.reduce((prev, curr) => [prev, " or ", curr])}
</Typography>
</Paper> </Paper>
</Box> </Box>
@ -378,7 +375,7 @@ export class Blackjack extends Game<Props, State> {
<Box display="flex"> <Box display="flex">
<Paper elevation={2}> <Paper elevation={2}>
<pre>Dealer</pre> <Typography>Dealer</Typography>
{dealerHand.cards.map((card, i) => ( {dealerHand.cards.map((card, i) => (
// Hide every card except the first while game is in progress // Hide every card except the first while game is in progress
<ReactCard card={card} hidden={gameInProgress && i !== 0} key={i} /> <ReactCard card={card} hidden={gameInProgress && i !== 0} key={i} />
@ -386,10 +383,12 @@ export class Blackjack extends Game<Props, State> {
{!gameInProgress && ( {!gameInProgress && (
<> <>
<pre>Value(s): </pre> <Typography>
{dealerHandValues.map((value, i) => ( Count:{" "}
<pre key={i}>{value}</pre> {dealerHandValues
))} .map<React.ReactNode>((value, i) => <span key={i}>{value}</span>)
.reduce((prev, curr) => [prev, " or ", curr])}
</Typography>
</> </>
)} )}
</Paper> </Paper>
@ -400,9 +399,10 @@ export class Blackjack extends Game<Props, State> {
{/* Results from previous round */} {/* Results from previous round */}
{result !== Result.Pending && ( {result !== Result.Pending && (
<Typography> <Typography>
{result} {result}&nbsp;
{this.isPlayerWinResult(result) && <Money money={this.state.bet} />} {result === Result.PlayerWon && <Money money={this.state.bet} />}
{result === Result.DealerWon && <Money money={this.state.bet} />} {result === Result.PlayerWonByBlackjack && <Money money={this.state.bet * 1.5} />}
{result === Result.DealerWon && <Money money={-this.state.bet} />}
</Typography> </Typography>
)} )}
</> </>

@ -349,13 +349,13 @@ export const FactionInfos: IMap<FactionInfo> = {
{" ; d' o `b ; "}<br /> {" ; d' o `b ; "}<br />
{" / d; `b| "}<br /> {" / d; `b| "}<br />
{" /, $; @ `: "}<br /> {" /, $; @ `: "}<br />
{" /' $$ ; "}<br /> {" /' $/ ; "}<br />
{" .' $$b o | "}<br /> {" .' $/b o | "}<br />
{" .' d$$$; : "}<br /> {" .' d$/$; : "}<br />
{" / .d$$$$; , ; "}<br /> {" / .d/$/$; , ; "}<br />
{" d .dNITESEC $ | "}<br /> {" d .dNITESEC $ | "}<br />
{" :bp.__.gNITESEC$$ :$ ; "}<br /> {" :bp.__.gNITESEC/$ :$ ; "}<br />
{" NITESECNITESECNIT $$b : "}<br /></>, {" NITESECNITESECNIT /$b : "}<br /></>,
[], [],
true, true,
true, true,

@ -349,7 +349,7 @@ export class Gang {
const res = member.ascend(); const res = member.ascend();
this.respect = Math.max(1, this.respect - res.respect); this.respect = Math.max(1, this.respect - res.respect);
if (workerScript) { if (workerScript) {
workerScript.log("ascend", `Ascended Gang member ${member.name}`); workerScript.log("ascend", () => `Ascended Gang member ${member.name}`);
} }
return res; return res;
} catch (e: any) { } catch (e: any) {

@ -47,7 +47,7 @@ export function purchaseHacknet(player: IPlayer): number {
throw new Error(`Calculated cost of purchasing HacknetServer is NaN`); throw new Error(`Calculated cost of purchasing HacknetServer is NaN`);
} }
if (!player.canAfford(cost)) { if (!player.canAfford(cost) || numOwned >= HacknetServerConstants.MaxServers) {
return -1; return -1;
} }
player.loseMoney(cost, "hacknet_expenses"); player.loseMoney(cost, "hacknet_expenses");

@ -5,7 +5,7 @@ export const recentScripts: RecentScript[] = [];
export function AddRecentScript(workerScript: WorkerScript): void { export function AddRecentScript(workerScript: WorkerScript): void {
if (recentScripts.find((r) => r.pid === workerScript.pid)) return; if (recentScripts.find((r) => r.pid === workerScript.pid)) return;
recentScripts.push({ recentScripts.unshift({
filename: workerScript.name, filename: workerScript.name,
args: workerScript.args, args: workerScript.args,
pid: workerScript.pid, pid: workerScript.pid,

@ -195,14 +195,14 @@ export class WorkerScript {
return this.disableLogs[fn] == null; return this.disableLogs[fn] == null;
} }
log(func: string, txt: string): void { log(func: string, txt: () => string): void {
if (this.shouldLog(func)) { if (this.shouldLog(func)) {
if (func && txt) { if (func && txt) {
this.scriptRef.log(`${func}: ${txt}`); this.scriptRef.log(`${func}: ${txt()}`);
} else if (func) { } else if (func) {
this.scriptRef.log(func); this.scriptRef.log(func);
} else { } else {
this.scriptRef.log(txt); this.scriptRef.log(txt());
} }
} }
} }

@ -213,7 +213,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
*/ */
const failOnHacknetServer = function (server: any, callingFn: any = ""): boolean { const failOnHacknetServer = function (server: any, callingFn: any = ""): boolean {
if (server instanceof HacknetServer) { if (server instanceof HacknetServer) {
workerScript.log(callingFn, `Does not work on Hacknet Servers`); workerScript.log(callingFn, () => `Does not work on Hacknet Servers`);
return true; return true;
} else { } else {
return false; return false;
@ -282,7 +282,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
userstack.push(`${filename}:L${call.line}@${call.func}`); userstack.push(`${filename}:L${call.line}@${call.func}`);
} }
workerScript.log(caller, msg); workerScript.log(caller, () => msg);
let rejectMsg = `${caller}: ${msg}`; let rejectMsg = `${caller}: ${msg}`;
if (userstack.length !== 0) rejectMsg += `<br><br>Stack:<br>${userstack.join("<br>")}`; if (userstack.length !== 0) rejectMsg += `<br><br>Stack:<br>${userstack.join("<br>")}`;
return makeRuntimeRejectMsg(workerScript, rejectMsg); return makeRuntimeRejectMsg(workerScript, rejectMsg);
@ -317,6 +317,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
workerScript.log( workerScript.log(
"hack", "hack",
() =>
`Executing ${hostname} in ${convertTimeMsToTimeElapsedString( `Executing ${hostname} in ${convertTimeMsToTimeElapsedString(
hackingTime * 1000, hackingTime * 1000,
true, true,
@ -366,6 +367,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
workerScript.scriptRef.onlineExpGained += expGainedOnSuccess; workerScript.scriptRef.onlineExpGained += expGainedOnSuccess;
workerScript.log( workerScript.log(
"hack", "hack",
() =>
`Successfully hacked '${server.hostname}' for ${numeralWrapper.formatMoney( `Successfully hacked '${server.hostname}' for ${numeralWrapper.formatMoney(
moneyGained, moneyGained,
)} and ${numeralWrapper.formatExp(expGainedOnSuccess)} exp (t=${numeralWrapper.formatThreads(threads)})`, )} and ${numeralWrapper.formatExp(expGainedOnSuccess)} exp (t=${numeralWrapper.formatThreads(threads)})`,
@ -384,6 +386,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
workerScript.scriptRef.onlineExpGained += expGainedOnFailure; workerScript.scriptRef.onlineExpGained += expGainedOnFailure;
workerScript.log( workerScript.log(
"hack", "hack",
() =>
`Failed to hack '${server.hostname}'. Gained ${numeralWrapper.formatExp( `Failed to hack '${server.hostname}'. Gained ${numeralWrapper.formatExp(
expGainedOnFailure, expGainedOnFailure,
)} exp (t=${numeralWrapper.formatThreads(threads)})`, )} exp (t=${numeralWrapper.formatThreads(threads)})`,
@ -460,7 +463,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
if (entry === null) continue; if (entry === null) continue;
out.push(entry); out.push(entry);
} }
workerScript.log("scan", `returned ${server.serversOnNetwork.length} connections for ${server.hostname}`); workerScript.log("scan", () => `returned ${server.serversOnNetwork.length} connections for ${server.hostname}`);
return out; return out;
}, },
hack: function (hostname: any, { threads: requestedThreads, stock }: any = {}): any { hack: function (hostname: any, { threads: requestedThreads, stock }: any = {}): any {
@ -473,7 +476,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
// Check argument validity // Check argument validity
const server = safeGetServer(hostname, "hackAnalyzeThreads"); const server = safeGetServer(hostname, "hackAnalyzeThreads");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("hackAnalyzeThreads", "Cannot be executed on this server."); workerScript.log("hackAnalyzeThreads", () => "Cannot be executed on this server.");
return -1; return -1;
} }
if (isNaN(hackAmount)) { if (isNaN(hackAmount)) {
@ -496,7 +499,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
const server = safeGetServer(hostname, "hackAnalyze"); const server = safeGetServer(hostname, "hackAnalyze");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("hackAnalyze", "Cannot be executed on this server."); workerScript.log("hackAnalyze", () => "Cannot be executed on this server.");
return false; return false;
} }
@ -510,7 +513,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
const server = safeGetServer(hostname, "hackAnalyzeChance"); const server = safeGetServer(hostname, "hackAnalyzeChance");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("hackAnalyzeChance", "Cannot be executed on this server."); workerScript.log("hackAnalyzeChance", () => "Cannot be executed on this server.");
return false; return false;
} }
@ -520,7 +523,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
if (time === undefined) { if (time === undefined) {
throw makeRuntimeErrorMsg("sleep", "Takes 1 argument."); throw makeRuntimeErrorMsg("sleep", "Takes 1 argument.");
} }
workerScript.log("sleep", `Sleeping for ${time} milliseconds`); workerScript.log("sleep", () => `Sleeping for ${time} milliseconds`);
return netscriptDelay(time, workerScript).then(function () { return netscriptDelay(time, workerScript).then(function () {
return Promise.resolve(true); return Promise.resolve(true);
}); });
@ -529,7 +532,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
if (time === undefined) { if (time === undefined) {
throw makeRuntimeErrorMsg("asleep", "Takes 1 argument."); throw makeRuntimeErrorMsg("asleep", "Takes 1 argument.");
} }
workerScript.log("asleep", `Sleeping for ${time} milliseconds`); workerScript.log("asleep", () => `Sleeping for ${time} milliseconds`);
return netscriptDelay(time, workerScript).then(function () { return netscriptDelay(time, workerScript).then(function () {
return Promise.resolve(true); return Promise.resolve(true);
}); });
@ -542,7 +545,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
} }
const server = safeGetServer(hostname, "grow"); const server = safeGetServer(hostname, "grow");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("grow", "Cannot be executed on this server."); workerScript.log("grow", () => "Cannot be executed on this server.");
return false; return false;
} }
@ -560,6 +563,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
const growTime = calculateGrowTime(server, Player); const growTime = calculateGrowTime(server, Player);
workerScript.log( workerScript.log(
"grow", "grow",
() =>
`Executing on '${server.hostname}' in ${convertTimeMsToTimeElapsedString( `Executing on '${server.hostname}' in ${convertTimeMsToTimeElapsedString(
growTime * 1000, growTime * 1000,
true, true,
@ -577,6 +581,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
const logGrowPercent = moneyAfter / moneyBefore - 1; const logGrowPercent = moneyAfter / moneyBefore - 1;
workerScript.log( workerScript.log(
"grow", "grow",
() =>
`Available money on '${server.hostname}' grown by ${numeralWrapper.formatPercentage( `Available money on '${server.hostname}' grown by ${numeralWrapper.formatPercentage(
logGrowPercent, logGrowPercent,
6, 6,
@ -596,7 +601,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
// Check argument validity // Check argument validity
const server = safeGetServer(hostname, "growthAnalyze"); const server = safeGetServer(hostname, "growthAnalyze");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("growthAnalyze", "Cannot be executed on this server."); workerScript.log("growthAnalyze", () => "Cannot be executed on this server.");
return false; return false;
} }
if (typeof growth !== "number" || isNaN(growth) || growth < 1 || !isFinite(growth)) { if (typeof growth !== "number" || isNaN(growth) || growth < 1 || !isFinite(growth)) {
@ -616,7 +621,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
} }
const server = safeGetServer(hostname, "weaken"); const server = safeGetServer(hostname, "weaken");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("weaken", "Cannot be executed on this server."); workerScript.log("weaken", () => "Cannot be executed on this server.");
return false; return false;
} }
@ -629,6 +634,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
const weakenTime = calculateWeakenTime(server, Player); const weakenTime = calculateWeakenTime(server, Player);
workerScript.log( workerScript.log(
"weaken", "weaken",
() =>
`Executing on '${server.hostname}' in ${convertTimeMsToTimeElapsedString( `Executing on '${server.hostname}' in ${convertTimeMsToTimeElapsedString(
weakenTime * 1000, weakenTime * 1000,
true, true,
@ -638,7 +644,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
if (workerScript.env.stopFlag) return Promise.reject(workerScript); if (workerScript.env.stopFlag) return Promise.reject(workerScript);
const host = GetServer(workerScript.hostname); const host = GetServer(workerScript.hostname);
if (host === null) { if (host === null) {
workerScript.log("weaken", "Server is null, did it die?"); workerScript.log("weaken", () => "Server is null, did it die?");
return Promise.resolve(0); return Promise.resolve(0);
} }
const coreBonus = 1 + (host.cpuCores - 1) / 16; const coreBonus = 1 + (host.cpuCores - 1) / 16;
@ -647,9 +653,10 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
const expGain = calculateHackingExpGain(server, Player) * threads; const expGain = calculateHackingExpGain(server, Player) * threads;
workerScript.log( workerScript.log(
"weaken", "weaken",
`'${server.hostname}' security level weakened to ${server.hackDifficulty}. Gained ${numeralWrapper.formatExp( () =>
expGain, `'${server.hostname}' security level weakened to ${
)} hacking exp (t=${numeralWrapper.formatThreads(threads)})`, 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);
@ -721,12 +728,12 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
for (fn in possibleLogs) { for (fn in possibleLogs) {
workerScript.disableLogs[fn] = true; workerScript.disableLogs[fn] = true;
} }
workerScript.log("disableLog", `Disabled logging for all functions`); workerScript.log("disableLog", () => `Disabled logging for all functions`);
} else if (possibleLogs[fn] === undefined) { } else if (possibleLogs[fn] === undefined) {
throw makeRuntimeErrorMsg("disableLog", `Invalid argument: ${fn}.`); throw makeRuntimeErrorMsg("disableLog", `Invalid argument: ${fn}.`);
} else { } else {
workerScript.disableLogs[fn] = true; workerScript.disableLogs[fn] = true;
workerScript.log("disableLog", `Disabled logging for ${fn}`); workerScript.log("disableLog", () => `Disabled logging for ${fn}`);
} }
}, },
enableLog: function (fn: any): any { enableLog: function (fn: any): any {
@ -734,7 +741,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
throw makeRuntimeErrorMsg("enableLog", `Invalid argument: ${fn}.`); throw makeRuntimeErrorMsg("enableLog", `Invalid argument: ${fn}.`);
} }
delete workerScript.disableLogs[fn]; delete workerScript.disableLogs[fn];
workerScript.log("enableLog", `Enabled logging for ${fn}`); workerScript.log("enableLog", () => `Enabled logging for ${fn}`);
}, },
isLogEnabled: function (fn: any): any { isLogEnabled: function (fn: any): any {
if (possibleLogs[fn] === undefined) { if (possibleLogs[fn] === undefined) {
@ -745,7 +752,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
getScriptLogs: function (fn: any, hostname: any, ...scriptArgs: any): any { getScriptLogs: function (fn: any, hostname: any, ...scriptArgs: any): any {
const runningScriptObj = getRunningScript(fn, hostname, "getScriptLogs", scriptArgs); const runningScriptObj = getRunningScript(fn, hostname, "getScriptLogs", scriptArgs);
if (runningScriptObj == null) { if (runningScriptObj == null) {
workerScript.log("getScriptLogs", getCannotFindRunningScriptErrorMessage(fn, hostname, scriptArgs)); workerScript.log("getScriptLogs", () => getCannotFindRunningScriptErrorMessage(fn, hostname, scriptArgs));
return ""; return "";
} }
@ -761,7 +768,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
runningScriptObj = getRunningScript(fn, hostname, "tail", scriptArgs); runningScriptObj = getRunningScript(fn, hostname, "tail", scriptArgs);
} }
if (runningScriptObj == null) { if (runningScriptObj == null) {
workerScript.log("tail", getCannotFindRunningScriptErrorMessage(fn, hostname, scriptArgs)); workerScript.log("tail", () => getCannotFindRunningScriptErrorMessage(fn, hostname, scriptArgs));
return; return;
} }
@ -774,7 +781,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
} }
const server = safeGetServer(hostname, "nuke"); const server = safeGetServer(hostname, "nuke");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("nuke", "Cannot be executed on this server."); workerScript.log("nuke", () => "Cannot be executed on this server.");
return false; return false;
} }
if (!Player.hasProgram(Programs.NukeProgram.name)) { if (!Player.hasProgram(Programs.NukeProgram.name)) {
@ -784,10 +791,10 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
throw makeRuntimeErrorMsg("nuke", "Not enough ports opened to use NUKE.exe virus."); throw makeRuntimeErrorMsg("nuke", "Not enough ports opened to use NUKE.exe virus.");
} }
if (server.hasAdminRights) { if (server.hasAdminRights) {
workerScript.log("nuke", `Already have root access to '${server.hostname}'.`); workerScript.log("nuke", () => `Already have root access to '${server.hostname}'.`);
} else { } else {
server.hasAdminRights = true; server.hasAdminRights = true;
workerScript.log("nuke", `Executed NUKE.exe virus on '${server.hostname}' to gain root access.`); workerScript.log("nuke", () => `Executed NUKE.exe virus on '${server.hostname}' to gain root access.`);
} }
return true; return true;
}, },
@ -798,18 +805,18 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
} }
const server = safeGetServer(hostname, "brutessh"); const server = safeGetServer(hostname, "brutessh");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("brutessh", "Cannot be executed on this server."); workerScript.log("brutessh", () => "Cannot be executed on this server.");
return false; return false;
} }
if (!Player.hasProgram(Programs.BruteSSHProgram.name)) { if (!Player.hasProgram(Programs.BruteSSHProgram.name)) {
throw makeRuntimeErrorMsg("brutessh", "You do not have the BruteSSH.exe program!"); throw makeRuntimeErrorMsg("brutessh", "You do not have the BruteSSH.exe program!");
} }
if (!server.sshPortOpen) { if (!server.sshPortOpen) {
workerScript.log("brutessh", `Executed BruteSSH.exe on '${server.hostname}' to open SSH port (22).`); workerScript.log("brutessh", () => `Executed BruteSSH.exe on '${server.hostname}' to open SSH port (22).`);
server.sshPortOpen = true; server.sshPortOpen = true;
++server.openPortCount; ++server.openPortCount;
} else { } else {
workerScript.log("brutessh", `SSH Port (22) already opened on '${server.hostname}'.`); workerScript.log("brutessh", () => `SSH Port (22) already opened on '${server.hostname}'.`);
} }
return true; return true;
}, },
@ -820,18 +827,18 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
} }
const server = safeGetServer(hostname, "ftpcrack"); const server = safeGetServer(hostname, "ftpcrack");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("ftpcrack", "Cannot be executed on this server."); workerScript.log("ftpcrack", () => "Cannot be executed on this server.");
return false; return false;
} }
if (!Player.hasProgram(Programs.FTPCrackProgram.name)) { if (!Player.hasProgram(Programs.FTPCrackProgram.name)) {
throw makeRuntimeErrorMsg("ftpcrack", "You do not have the FTPCrack.exe program!"); throw makeRuntimeErrorMsg("ftpcrack", "You do not have the FTPCrack.exe program!");
} }
if (!server.ftpPortOpen) { if (!server.ftpPortOpen) {
workerScript.log("ftpcrack", `Executed FTPCrack.exe on '${server.hostname}' to open FTP port (21).`); workerScript.log("ftpcrack", () => `Executed FTPCrack.exe on '${server.hostname}' to open FTP port (21).`);
server.ftpPortOpen = true; server.ftpPortOpen = true;
++server.openPortCount; ++server.openPortCount;
} else { } else {
workerScript.log("ftpcrack", `FTP Port (21) already opened on '${server.hostname}'.`); workerScript.log("ftpcrack", () => `FTP Port (21) already opened on '${server.hostname}'.`);
} }
return true; return true;
}, },
@ -842,18 +849,18 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
} }
const server = safeGetServer(hostname, "relaysmtp"); const server = safeGetServer(hostname, "relaysmtp");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("relaysmtp", "Cannot be executed on this server."); workerScript.log("relaysmtp", () => "Cannot be executed on this server.");
return false; return false;
} }
if (!Player.hasProgram(Programs.RelaySMTPProgram.name)) { if (!Player.hasProgram(Programs.RelaySMTPProgram.name)) {
throw makeRuntimeErrorMsg("relaysmtp", "You do not have the relaySMTP.exe program!"); throw makeRuntimeErrorMsg("relaysmtp", "You do not have the relaySMTP.exe program!");
} }
if (!server.smtpPortOpen) { if (!server.smtpPortOpen) {
workerScript.log("relaysmtp", `Executed relaySMTP.exe on '${server.hostname}' to open SMTP port (25).`); workerScript.log("relaysmtp", () => `Executed relaySMTP.exe on '${server.hostname}' to open SMTP port (25).`);
server.smtpPortOpen = true; server.smtpPortOpen = true;
++server.openPortCount; ++server.openPortCount;
} else { } else {
workerScript.log("relaysmtp", `SMTP Port (25) already opened on '${server.hostname}'.`); workerScript.log("relaysmtp", () => `SMTP Port (25) already opened on '${server.hostname}'.`);
} }
return true; return true;
}, },
@ -864,18 +871,18 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
} }
const server = safeGetServer(hostname, "httpworm"); const server = safeGetServer(hostname, "httpworm");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("httpworm", "Cannot be executed on this server."); workerScript.log("httpworm", () => "Cannot be executed on this server.");
return false; return false;
} }
if (!Player.hasProgram(Programs.HTTPWormProgram.name)) { if (!Player.hasProgram(Programs.HTTPWormProgram.name)) {
throw makeRuntimeErrorMsg("httpworm", "You do not have the HTTPWorm.exe program!"); throw makeRuntimeErrorMsg("httpworm", "You do not have the HTTPWorm.exe program!");
} }
if (!server.httpPortOpen) { if (!server.httpPortOpen) {
workerScript.log("httpworm", `Executed HTTPWorm.exe on '${server.hostname}' to open HTTP port (80).`); workerScript.log("httpworm", () => `Executed HTTPWorm.exe on '${server.hostname}' to open HTTP port (80).`);
server.httpPortOpen = true; server.httpPortOpen = true;
++server.openPortCount; ++server.openPortCount;
} else { } else {
workerScript.log("httpworm", `HTTP Port (80) already opened on '${server.hostname}'.`); workerScript.log("httpworm", () => `HTTP Port (80) already opened on '${server.hostname}'.`);
} }
return true; return true;
}, },
@ -886,18 +893,18 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
} }
const server = safeGetServer(hostname, "sqlinject"); const server = safeGetServer(hostname, "sqlinject");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("sqlinject", "Cannot be executed on this server."); workerScript.log("sqlinject", () => "Cannot be executed on this server.");
return false; return false;
} }
if (!Player.hasProgram(Programs.SQLInjectProgram.name)) { if (!Player.hasProgram(Programs.SQLInjectProgram.name)) {
throw makeRuntimeErrorMsg("sqlinject", "You do not have the SQLInject.exe program!"); throw makeRuntimeErrorMsg("sqlinject", "You do not have the SQLInject.exe program!");
} }
if (!server.sqlPortOpen) { if (!server.sqlPortOpen) {
workerScript.log("sqlinject", `Executed SQLInject.exe on '${server.hostname}' to open SQL port (1433).`); workerScript.log("sqlinject", () => `Executed SQLInject.exe on '${server.hostname}' to open SQL port (1433).`);
server.sqlPortOpen = true; server.sqlPortOpen = true;
++server.openPortCount; ++server.openPortCount;
} else { } else {
workerScript.log("sqlinject", `SQL Port (1433) already opened on '${server.hostname}'.`); workerScript.log("sqlinject", () => `SQL Port (1433) already opened on '${server.hostname}'.`);
} }
return true; return true;
}, },
@ -946,11 +953,11 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
return runScriptFromScript("spawn", scriptServer, scriptname, args, workerScript, threads); return runScriptFromScript("spawn", scriptServer, scriptname, args, workerScript, threads);
}, spawnDelay * 1e3); }, spawnDelay * 1e3);
workerScript.log("spawn", `Will execute '${scriptname}' in ${spawnDelay} seconds`); workerScript.log("spawn", () => `Will execute '${scriptname}' in ${spawnDelay} seconds`);
workerScript.running = false; // Prevent workerScript from "finishing execution naturally" workerScript.running = false; // Prevent workerScript from "finishing execution naturally"
if (killWorkerScript(workerScript)) { if (killWorkerScript(workerScript)) {
workerScript.log("spawn", "Exiting..."); workerScript.log("spawn", () => "Exiting...");
} }
}, },
kill: function (filename: any, hostname: any, ...scriptArgs: any): any { kill: function (filename: any, hostname: any, ...scriptArgs: any): any {
@ -970,7 +977,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
const server = safeGetServer(hostname, "kill"); const server = safeGetServer(hostname, "kill");
const runningScriptObj = getRunningScript(filename, hostname, "kill", scriptArgs); const runningScriptObj = getRunningScript(filename, hostname, "kill", scriptArgs);
if (runningScriptObj == null) { if (runningScriptObj == null) {
workerScript.log("kill", getCannotFindRunningScriptErrorMessage(filename, hostname, scriptArgs)); workerScript.log("kill", () => getCannotFindRunningScriptErrorMessage(filename, hostname, scriptArgs));
return false; return false;
} }
@ -979,18 +986,21 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
if (res) { if (res) {
if (killByPid) { if (killByPid) {
workerScript.log("kill", `Killing script with PID ${filename}`); workerScript.log("kill", () => `Killing script with PID ${filename}`);
} else { } else {
workerScript.log("kill", `Killing '${filename}' on '${hostname}' with args: ${arrayToString(scriptArgs)}.`); workerScript.log(
"kill",
() => `Killing '${filename}' on '${hostname}' with args: ${arrayToString(scriptArgs)}.`,
);
} }
return true; return true;
} else { } else {
if (killByPid) { if (killByPid) {
workerScript.log("kill", `No script with PID ${filename}`); workerScript.log("kill", () => `No script with PID ${filename}`);
} else { } else {
workerScript.log( workerScript.log(
"kill", "kill",
`No such script '${filename}' on '${hostname}' with args: ${arrayToString(scriptArgs)}`, () => `No such script '${filename}' on '${hostname}' with args: ${arrayToString(scriptArgs)}`,
); );
} }
return false; return false;
@ -1009,7 +1019,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
WorkerScriptStartStopEventEmitter.emit(); WorkerScriptStartStopEventEmitter.emit();
workerScript.log( workerScript.log(
"killall", "killall",
`Killing all scripts on '${server.hostname}'. May take a few minutes for the scripts to die.`, () => `Killing all scripts on '${server.hostname}'. May take a few minutes for the scripts to die.`,
); );
return scriptsRunning; return scriptsRunning;
@ -1017,9 +1027,9 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
exit: function (): any { exit: function (): any {
workerScript.running = false; // Prevent workerScript from "finishing execution naturally" workerScript.running = false; // Prevent workerScript from "finishing execution naturally"
if (killWorkerScript(workerScript)) { if (killWorkerScript(workerScript)) {
workerScript.log("exit", "Exiting..."); workerScript.log("exit", () => "Exiting...");
} else { } else {
workerScript.log("exit", "Failed. This is a bug. Report to dev."); workerScript.log("exit", () => "Failed. This is a bug. Report to dev.");
} }
}, },
scp: async function (scriptname: any, hostname1: any, hostname2: any): Promise<boolean> { scp: async function (scriptname: any, hostname1: any, hostname2: any): Promise<boolean> {
@ -1086,18 +1096,18 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
} }
if (!found) { if (!found) {
workerScript.log("scp", `File '${scriptname}' does not exist.`); workerScript.log("scp", () => `File '${scriptname}' does not exist.`);
return Promise.resolve(false); return Promise.resolve(false);
} }
for (let i = 0; i < destServer.messages.length; ++i) { for (let i = 0; i < destServer.messages.length; ++i) {
if (destServer.messages[i] === scriptname) { if (destServer.messages[i] === scriptname) {
workerScript.log("scp", `File '${scriptname}' copied over to '${destServer.hostname}'.`); workerScript.log("scp", () => `File '${scriptname}' copied over to '${destServer?.hostname}'.`);
return Promise.resolve(true); // Already exists return Promise.resolve(true); // Already exists
} }
} }
destServer.messages.push(scriptname); destServer.messages.push(scriptname);
workerScript.log("scp", `File '${scriptname}' copied over to '${destServer.hostname}'.`); workerScript.log("scp", () => `File '${scriptname}' copied over to '${destServer?.hostname}'.`);
return Promise.resolve(true); return Promise.resolve(true);
} }
@ -1111,7 +1121,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
} }
} }
if (txtFile === undefined) { if (txtFile === undefined) {
workerScript.log("scp", `File '${scriptname}' does not exist.`); workerScript.log("scp", () => `File '${scriptname}' does not exist.`);
return Promise.resolve(false); return Promise.resolve(false);
} }
@ -1119,13 +1129,13 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
if (destServer.textFiles[i].fn === scriptname) { if (destServer.textFiles[i].fn === scriptname) {
// Overwrite // Overwrite
destServer.textFiles[i].text = txtFile.text; destServer.textFiles[i].text = txtFile.text;
workerScript.log("scp", `File '${scriptname}' copied over to '${destServer.hostname}'.`); workerScript.log("scp", () => `File '${scriptname}' copied over to '${destServer?.hostname}'.`);
return Promise.resolve(true); return Promise.resolve(true);
} }
} }
const newFile = new TextFile(txtFile.fn, txtFile.text); const newFile = new TextFile(txtFile.fn, txtFile.text);
destServer.textFiles.push(newFile); destServer.textFiles.push(newFile);
workerScript.log("scp", `File '${scriptname}' copied over to '${destServer.hostname}'.`); workerScript.log("scp", () => `File '${scriptname}' copied over to '${destServer?.hostname}'.`);
return Promise.resolve(true); return Promise.resolve(true);
} }
@ -1138,14 +1148,14 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
} }
} }
if (sourceScript == null) { if (sourceScript == null) {
workerScript.log("scp", `File '${scriptname}' does not exist.`); workerScript.log("scp", () => `File '${scriptname}' does not exist.`);
return Promise.resolve(false); return Promise.resolve(false);
} }
// Overwrite script if it already exists // Overwrite script if it already exists
for (let i = 0; i < destServer.scripts.length; ++i) { for (let i = 0; i < destServer.scripts.length; ++i) {
if (scriptname == destServer.scripts[i].filename) { if (scriptname == destServer.scripts[i].filename) {
workerScript.log("scp", `WARNING: File '${scriptname}' overwritten on '${destServer.hostname}'`); workerScript.log("scp", () => `WARNING: File '${scriptname}' overwritten on '${destServer?.hostname}'`);
const oldScript = destServer.scripts[i]; const oldScript = destServer.scripts[i];
// If it's the exact same file don't actually perform the // If it's the exact same file don't actually perform the
// copy to avoid recompiling uselessly. Players tend to scp // copy to avoid recompiling uselessly. Players tend to scp
@ -1164,7 +1174,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
newScript.ramUsage = sourceScript.ramUsage; newScript.ramUsage = sourceScript.ramUsage;
newScript.server = destServer.hostname; newScript.server = destServer.hostname;
destServer.scripts.push(newScript); destServer.scripts.push(newScript);
workerScript.log("scp", `File '${scriptname}' copied over to '${destServer.hostname}'.`); workerScript.log("scp", () => `File '${scriptname}' copied over to '${destServer?.hostname}'.`);
return new Promise((resolve) => { return new Promise((resolve) => {
if (destServer === null) { if (destServer === null) {
resolve(false); resolve(false);
@ -1274,7 +1284,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
getHackingLevel: function (): any { getHackingLevel: function (): any {
updateDynamicRam("getHackingLevel", getRamCost("getHackingLevel")); updateDynamicRam("getHackingLevel", getRamCost("getHackingLevel"));
Player.updateSkillLevels(); Player.updateSkillLevels();
workerScript.log("getHackingLevel", `returned ${Player.hacking}`); workerScript.log("getHackingLevel", () => `returned ${Player.hacking}`);
return Player.hacking; return Player.hacking;
}, },
getHackingMultipliers: function (): any { getHackingMultipliers: function (): any {
@ -1322,7 +1332,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
updateDynamicRam("getServerMoneyAvailable", getRamCost("getServerMoneyAvailable")); updateDynamicRam("getServerMoneyAvailable", getRamCost("getServerMoneyAvailable"));
const server = safeGetServer(hostname, "getServerMoneyAvailable"); const server = safeGetServer(hostname, "getServerMoneyAvailable");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("getServerMoneyAvailable", "Cannot be executed on this server."); workerScript.log("getServerMoneyAvailable", () => "Cannot be executed on this server.");
return 0; return 0;
} }
if (failOnHacknetServer(server, "getServerMoneyAvailable")) { if (failOnHacknetServer(server, "getServerMoneyAvailable")) {
@ -1332,13 +1342,13 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
// Return player's money // Return player's money
workerScript.log( workerScript.log(
"getServerMoneyAvailable", "getServerMoneyAvailable",
`returned player's money: ${numeralWrapper.formatMoney(Player.money)}`, () => `returned player's money: ${numeralWrapper.formatMoney(Player.money)}`,
); );
return Player.money; return Player.money;
} }
workerScript.log( workerScript.log(
"getServerMoneyAvailable", "getServerMoneyAvailable",
`returned ${numeralWrapper.formatMoney(server.moneyAvailable)} for '${server.hostname}'`, () => `returned ${numeralWrapper.formatMoney(server.moneyAvailable)} for '${server.hostname}'`,
); );
return server.moneyAvailable; return server.moneyAvailable;
}, },
@ -1346,7 +1356,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
updateDynamicRam("getServerSecurityLevel", getRamCost("getServerSecurityLevel")); updateDynamicRam("getServerSecurityLevel", getRamCost("getServerSecurityLevel"));
const server = safeGetServer(hostname, "getServerSecurityLevel"); const server = safeGetServer(hostname, "getServerSecurityLevel");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("getServerSecurityLevel", "Cannot be executed on this server."); workerScript.log("getServerSecurityLevel", () => "Cannot be executed on this server.");
return 1; return 1;
} }
if (failOnHacknetServer(server, "getServerSecurityLevel")) { if (failOnHacknetServer(server, "getServerSecurityLevel")) {
@ -1354,7 +1364,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
} }
workerScript.log( workerScript.log(
"getServerSecurityLevel", "getServerSecurityLevel",
`returned ${numeralWrapper.formatServerSecurity(server.hackDifficulty)} for '${server.hostname}'`, () => `returned ${numeralWrapper.formatServerSecurity(server.hackDifficulty)} for '${server.hostname}'`,
); );
return server.hackDifficulty; return server.hackDifficulty;
}, },
@ -1362,11 +1372,11 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
updateDynamicRam("getServerBaseSecurityLevel", getRamCost("getServerBaseSecurityLevel")); updateDynamicRam("getServerBaseSecurityLevel", getRamCost("getServerBaseSecurityLevel"));
workerScript.log( workerScript.log(
"getServerBaseSecurityLevel", "getServerBaseSecurityLevel",
`getServerBaseSecurityLevel is deprecated because it's not useful.`, () => `getServerBaseSecurityLevel is deprecated because it's not useful.`,
); );
const server = safeGetServer(hostname, "getServerBaseSecurityLevel"); const server = safeGetServer(hostname, "getServerBaseSecurityLevel");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("getServerBaseSecurityLevel", "Cannot be executed on this server."); workerScript.log("getServerBaseSecurityLevel", () => "Cannot be executed on this server.");
return 1; return 1;
} }
if (failOnHacknetServer(server, "getServerBaseSecurityLevel")) { if (failOnHacknetServer(server, "getServerBaseSecurityLevel")) {
@ -1374,7 +1384,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
} }
workerScript.log( workerScript.log(
"getServerBaseSecurityLevel", "getServerBaseSecurityLevel",
`returned ${numeralWrapper.formatServerSecurity(server.baseDifficulty)} for '${server.hostname}'`, () => `returned ${numeralWrapper.formatServerSecurity(server.baseDifficulty)} for '${server.hostname}'`,
); );
return server.baseDifficulty; return server.baseDifficulty;
}, },
@ -1382,7 +1392,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
updateDynamicRam("getServerMinSecurityLevel", getRamCost("getServerMinSecurityLevel")); updateDynamicRam("getServerMinSecurityLevel", getRamCost("getServerMinSecurityLevel"));
const server = safeGetServer(hostname, "getServerMinSecurityLevel"); const server = safeGetServer(hostname, "getServerMinSecurityLevel");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("getServerMinSecurityLevel", "Cannot be executed on this server."); workerScript.log("getServerMinSecurityLevel", () => "Cannot be executed on this server.");
return 1; return 1;
} }
if (failOnHacknetServer(server, "getServerMinSecurityLevel")) { if (failOnHacknetServer(server, "getServerMinSecurityLevel")) {
@ -1390,7 +1400,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
} }
workerScript.log( workerScript.log(
"getServerMinSecurityLevel", "getServerMinSecurityLevel",
`returned ${numeralWrapper.formatServerSecurity(server.minDifficulty)} for ${server.hostname}`, () => `returned ${numeralWrapper.formatServerSecurity(server.minDifficulty)} for ${server.hostname}`,
); );
return server.minDifficulty; return server.minDifficulty;
}, },
@ -1398,7 +1408,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
updateDynamicRam("getServerRequiredHackingLevel", getRamCost("getServerRequiredHackingLevel")); updateDynamicRam("getServerRequiredHackingLevel", getRamCost("getServerRequiredHackingLevel"));
const server = safeGetServer(hostname, "getServerRequiredHackingLevel"); const server = safeGetServer(hostname, "getServerRequiredHackingLevel");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("getServerRequiredHackingLevel", "Cannot be executed on this server."); workerScript.log("getServerRequiredHackingLevel", () => "Cannot be executed on this server.");
return 1; return 1;
} }
if (failOnHacknetServer(server, "getServerRequiredHackingLevel")) { if (failOnHacknetServer(server, "getServerRequiredHackingLevel")) {
@ -1406,7 +1416,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
} }
workerScript.log( workerScript.log(
"getServerRequiredHackingLevel", "getServerRequiredHackingLevel",
`returned ${numeralWrapper.formatSkill(server.requiredHackingSkill)} for '${server.hostname}'`, () => `returned ${numeralWrapper.formatSkill(server.requiredHackingSkill)} for '${server.hostname}'`,
); );
return server.requiredHackingSkill; return server.requiredHackingSkill;
}, },
@ -1414,7 +1424,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
updateDynamicRam("getServerMaxMoney", getRamCost("getServerMaxMoney")); updateDynamicRam("getServerMaxMoney", getRamCost("getServerMaxMoney"));
const server = safeGetServer(hostname, "getServerMaxMoney"); const server = safeGetServer(hostname, "getServerMaxMoney");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("getServerMaxMoney", "Cannot be executed on this server."); workerScript.log("getServerMaxMoney", () => "Cannot be executed on this server.");
return 0; return 0;
} }
if (failOnHacknetServer(server, "getServerMaxMoney")) { if (failOnHacknetServer(server, "getServerMaxMoney")) {
@ -1422,7 +1432,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
} }
workerScript.log( workerScript.log(
"getServerMaxMoney", "getServerMaxMoney",
`returned ${numeralWrapper.formatMoney(server.moneyMax)} for '${server.hostname}'`, () => `returned ${numeralWrapper.formatMoney(server.moneyMax)} for '${server.hostname}'`,
); );
return server.moneyMax; return server.moneyMax;
}, },
@ -1430,48 +1440,54 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
updateDynamicRam("getServerGrowth", getRamCost("getServerGrowth")); updateDynamicRam("getServerGrowth", getRamCost("getServerGrowth"));
const server = safeGetServer(hostname, "getServerGrowth"); const server = safeGetServer(hostname, "getServerGrowth");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("getServerGrowth", "Cannot be executed on this server."); workerScript.log("getServerGrowth", () => "Cannot be executed on this server.");
return 1; return 1;
} }
if (failOnHacknetServer(server, "getServerGrowth")) { if (failOnHacknetServer(server, "getServerGrowth")) {
return 1; return 1;
} }
workerScript.log("getServerGrowth", `returned ${server.serverGrowth} for '${server.hostname}'`); workerScript.log("getServerGrowth", () => `returned ${server.serverGrowth} for '${server.hostname}'`);
return server.serverGrowth; return server.serverGrowth;
}, },
getServerNumPortsRequired: function (hostname: any): any { getServerNumPortsRequired: function (hostname: any): any {
updateDynamicRam("getServerNumPortsRequired", getRamCost("getServerNumPortsRequired")); updateDynamicRam("getServerNumPortsRequired", getRamCost("getServerNumPortsRequired"));
const server = safeGetServer(hostname, "getServerNumPortsRequired"); const server = safeGetServer(hostname, "getServerNumPortsRequired");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("getServerNumPortsRequired", "Cannot be executed on this server."); workerScript.log("getServerNumPortsRequired", () => "Cannot be executed on this server.");
return 5; return 5;
} }
if (failOnHacknetServer(server, "getServerNumPortsRequired")) { if (failOnHacknetServer(server, "getServerNumPortsRequired")) {
return 5; return 5;
} }
workerScript.log("getServerNumPortsRequired", `returned ${server.numOpenPortsRequired} for '${server.hostname}'`); workerScript.log(
"getServerNumPortsRequired",
() => `returned ${server.numOpenPortsRequired} for '${server.hostname}'`,
);
return server.numOpenPortsRequired; return server.numOpenPortsRequired;
}, },
getServerRam: function (hostname: any): any { getServerRam: function (hostname: any): any {
updateDynamicRam("getServerRam", getRamCost("getServerRam")); updateDynamicRam("getServerRam", getRamCost("getServerRam"));
workerScript.log("getServerRam", `getServerRam is deprecated in favor of getServerMaxRam / getServerUsedRam`); workerScript.log(
"getServerRam",
() => `getServerRam is deprecated in favor of getServerMaxRam / getServerUsedRam`,
);
const server = safeGetServer(hostname, "getServerRam"); const server = safeGetServer(hostname, "getServerRam");
workerScript.log( workerScript.log(
"getServerRam", "getServerRam",
`returned [${numeralWrapper.formatRAM(server.maxRam)}, ${numeralWrapper.formatRAM(server.ramUsed)}]`, () => `returned [${numeralWrapper.formatRAM(server.maxRam)}, ${numeralWrapper.formatRAM(server.ramUsed)}]`,
); );
return [server.maxRam, server.ramUsed]; return [server.maxRam, server.ramUsed];
}, },
getServerMaxRam: function (hostname: any): any { getServerMaxRam: function (hostname: any): any {
updateDynamicRam("getServerMaxRam", getRamCost("getServerMaxRam")); updateDynamicRam("getServerMaxRam", getRamCost("getServerMaxRam"));
const server = safeGetServer(hostname, "getServerMaxRam"); const server = safeGetServer(hostname, "getServerMaxRam");
workerScript.log("getServerMaxRam", `returned ${numeralWrapper.formatRAM(server.maxRam)}`); workerScript.log("getServerMaxRam", () => `returned ${numeralWrapper.formatRAM(server.maxRam)}`);
return server.maxRam; return server.maxRam;
}, },
getServerUsedRam: function (hostname: any): any { getServerUsedRam: function (hostname: any): any {
updateDynamicRam("getServerUsedRam", getRamCost("getServerUsedRam")); updateDynamicRam("getServerUsedRam", getRamCost("getServerUsedRam"));
const server = safeGetServer(hostname, "getServerUsedRam"); const server = safeGetServer(hostname, "getServerUsedRam");
workerScript.log("getServerUsedRam", `returned ${numeralWrapper.formatRAM(server.ramUsed)}`); workerScript.log("getServerUsedRam", () => `returned ${numeralWrapper.formatRAM(server.ramUsed)}`);
return server.ramUsed; return server.ramUsed;
}, },
serverExists: function (hostname: any): any { serverExists: function (hostname: any): any {
@ -1531,7 +1547,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
const cost = getPurchaseServerCost(ram); const cost = getPurchaseServerCost(ram);
if (cost === Infinity) { if (cost === Infinity) {
workerScript.log("getPurchasedServerCost", `Invalid argument: ram='${ram}'`); workerScript.log("getPurchasedServerCost", () => `Invalid argument: ram='${ram}'`);
return Infinity; return Infinity;
} }
@ -1542,13 +1558,14 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
let hostnameStr = String(name); let hostnameStr = String(name);
hostnameStr = hostnameStr.replace(/\s+/g, ""); hostnameStr = hostnameStr.replace(/\s+/g, "");
if (hostnameStr == "") { if (hostnameStr == "") {
workerScript.log("purchaseServer", `Invalid argument: hostname='${hostnameStr}'`); workerScript.log("purchaseServer", () => `Invalid argument: hostname='${hostnameStr}'`);
return ""; return "";
} }
if (Player.purchasedServers.length >= getPurchaseServerLimit()) { if (Player.purchasedServers.length >= getPurchaseServerLimit()) {
workerScript.log( workerScript.log(
"purchaseServer", "purchaseServer",
() =>
`You have reached the maximum limit of ${getPurchaseServerLimit()} servers. You cannot purchase any more.`, `You have reached the maximum limit of ${getPurchaseServerLimit()} servers. You cannot purchase any more.`,
); );
return ""; return "";
@ -1556,14 +1573,14 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
const cost = getPurchaseServerCost(ram); const cost = getPurchaseServerCost(ram);
if (cost === Infinity) { if (cost === Infinity) {
workerScript.log("purchaseServer", `Invalid argument: ram='${ram}'`); workerScript.log("purchaseServer", () => `Invalid argument: ram='${ram}'`);
return ""; return "";
} }
if (Player.money < cost) { if (Player.money < cost) {
workerScript.log( workerScript.log(
"purchaseServer", "purchaseServer",
`Not enough money to purchase server. Need ${numeralWrapper.formatMoney(cost)}`, () => `Not enough money to purchase server. Need ${numeralWrapper.formatMoney(cost)}`,
); );
return ""; return "";
} }
@ -1585,7 +1602,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
Player.loseMoney(cost, "servers"); Player.loseMoney(cost, "servers");
workerScript.log( workerScript.log(
"purchaseServer", "purchaseServer",
`Purchased new server with hostname '${newServ.hostname}' for ${numeralWrapper.formatMoney(cost)}`, () => `Purchased new server with hostname '${newServ.hostname}' for ${numeralWrapper.formatMoney(cost)}`,
); );
return newServ.hostname; return newServ.hostname;
}, },
@ -1595,12 +1612,12 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
hostnameStr = hostnameStr.replace(/\s\s+/g, ""); hostnameStr = hostnameStr.replace(/\s\s+/g, "");
const server = GetServer(hostnameStr); const server = GetServer(hostnameStr);
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("deleteServer", `Invalid argument: hostname='${hostnameStr}'`); workerScript.log("deleteServer", () => `Invalid argument: hostname='${hostnameStr}'`);
return false; return false;
} }
if (!server.purchasedByPlayer || server.hostname === "home") { if (!server.purchasedByPlayer || server.hostname === "home") {
workerScript.log("deleteServer", "Cannot delete non-purchased server."); workerScript.log("deleteServer", () => "Cannot delete non-purchased server.");
return false; return false;
} }
@ -1608,19 +1625,22 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
// Can't delete server you're currently connected to // Can't delete server you're currently connected to
if (server.isConnectedTo) { if (server.isConnectedTo) {
workerScript.log("deleteServer", "You are currently connected to the server you are trying to delete."); workerScript.log("deleteServer", () => "You are currently connected to the server you are trying to delete.");
return false; return false;
} }
// A server cannot delete itself // A server cannot delete itself
if (hostname === workerScript.hostname) { if (hostname === workerScript.hostname) {
workerScript.log("deleteServer", "Cannot delete the server this script is running on."); workerScript.log("deleteServer", () => "Cannot delete the server this script is running on.");
return false; return false;
} }
// Delete all scripts running on server // Delete all scripts running on server
if (server.runningScripts.length > 0) { if (server.runningScripts.length > 0) {
workerScript.log("deleteServer", `Cannot delete server '${hostname}' because it still has scripts running.`); workerScript.log(
"deleteServer",
() => `Cannot delete server '${hostname}' because it still has scripts running.`,
);
return false; return false;
} }
@ -1637,7 +1657,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
if (!found) { if (!found) {
workerScript.log( workerScript.log(
"deleteServer", "deleteServer",
`Could not identify server ${hostname} as a purchased server. This is a bug. Report to dev.`, () => `Could not identify server ${hostname} as a purchased server. This is a bug. Report to dev.`,
); );
return false; return false;
} }
@ -1651,14 +1671,14 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
for (let i = 0; i < homeComputer.serversOnNetwork.length; ++i) { for (let i = 0; i < homeComputer.serversOnNetwork.length; ++i) {
if (hostname == homeComputer.serversOnNetwork[i]) { if (hostname == homeComputer.serversOnNetwork[i]) {
homeComputer.serversOnNetwork.splice(i, 1); homeComputer.serversOnNetwork.splice(i, 1);
workerScript.log("deleteServer", `Deleted server '${hostnameStr}`); workerScript.log("deleteServer", () => `Deleted server '${hostnameStr}`);
return true; return true;
} }
} }
// Wasn't found on home computer // Wasn't found on home computer
workerScript.log( workerScript.log(
"deleteServer", "deleteServer",
`Could not find server ${hostname} as a purchased server. This is a bug. Report to dev.`, () => `Could not find server ${hostname} as a purchased server. This is a bug. Report to dev.`,
); );
return false; return false;
}, },
@ -1896,7 +1916,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
const status = s.removeFile(fn); const status = s.removeFile(fn);
if (!status.res) { if (!status.res) {
workerScript.log("rm", status.msg + ""); workerScript.log("rm", () => status.msg + "");
} }
return status.res; return status.res;
@ -1941,16 +1961,12 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
updateDynamicRam("getRunningScript", getRamCost("getRunningScript")); updateDynamicRam("getRunningScript", getRamCost("getRunningScript"));
let runningScript; let runningScript;
if (args.length === 0) { if (fn === undefined && hostname === undefined && args.length === 0) {
runningScript = workerScript.scriptRef; runningScript = workerScript.scriptRef;
} else if (typeof fn === "number") { } else if (typeof fn === "number") {
runningScript = getRunningScriptByPid(fn, "getRunningScript"); runningScript = getRunningScriptByPid(fn, "getRunningScript");
} else { } else {
const scriptArgs = []; runningScript = getRunningScript(fn, hostname, "getRunningScript", args);
for (let i = 2; i < args.length; ++i) {
scriptArgs.push(args[i]);
}
runningScript = getRunningScript(fn, hostname, "getRunningScript", scriptArgs);
} }
if (runningScript === null) return null; if (runningScript === null) return null;
return { return {
@ -1973,7 +1989,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
updateDynamicRam("getHackTime", getRamCost("getHackTime")); updateDynamicRam("getHackTime", getRamCost("getHackTime"));
const server = safeGetServer(hostname, "getHackTime"); const server = safeGetServer(hostname, "getHackTime");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("getHackTime", "invalid for this kind of server"); workerScript.log("getHackTime", () => "invalid for this kind of server");
return Infinity; return Infinity;
} }
if (failOnHacknetServer(server, "getHackTime")) { if (failOnHacknetServer(server, "getHackTime")) {
@ -1986,7 +2002,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
updateDynamicRam("getGrowTime", getRamCost("getGrowTime")); updateDynamicRam("getGrowTime", getRamCost("getGrowTime"));
const server = safeGetServer(hostname, "getGrowTime"); const server = safeGetServer(hostname, "getGrowTime");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("getGrowTime", "invalid for this kind of server"); workerScript.log("getGrowTime", () => "invalid for this kind of server");
return Infinity; return Infinity;
} }
if (failOnHacknetServer(server, "getGrowTime")) { if (failOnHacknetServer(server, "getGrowTime")) {
@ -1999,7 +2015,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
updateDynamicRam("getWeakenTime", getRamCost("getWeakenTime")); updateDynamicRam("getWeakenTime", getRamCost("getWeakenTime"));
const server = safeGetServer(hostname, "getWeakenTime"); const server = safeGetServer(hostname, "getWeakenTime");
if (!(server instanceof Server)) { if (!(server instanceof Server)) {
workerScript.log("getWeakenTime", "invalid for this kind of server"); workerScript.log("getWeakenTime", () => "invalid for this kind of server");
return Infinity; return Infinity;
} }
if (failOnHacknetServer(server, "getWeakenTime")) { if (failOnHacknetServer(server, "getWeakenTime")) {
@ -2030,7 +2046,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
if (runningScriptObj == null) { if (runningScriptObj == null) {
workerScript.log( workerScript.log(
"getScriptIncome", "getScriptIncome",
`No such script '${scriptname}' on '${server.hostname}' with args: ${arrayToString(args)}`, () => `No such script '${scriptname}' on '${server.hostname}' with args: ${arrayToString(args)}`,
); );
return -1; return -1;
} }
@ -2052,7 +2068,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
if (runningScriptObj == null) { if (runningScriptObj == null) {
workerScript.log( workerScript.log(
"getScriptExpGain", "getScriptExpGain",
`No such script '${scriptname}' on '${server.hostname}' with args: ${arrayToString(args)}`, () => `No such script '${scriptname}' on '${server.hostname}' with args: ${arrayToString(args)}`,
); );
return -1; return -1;
} }
@ -2095,7 +2111,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
}, },
wget: async function (url: any, target: any, hostname: any = workerScript.hostname): Promise<boolean> { wget: async function (url: any, target: any, hostname: any = workerScript.hostname): Promise<boolean> {
if (!isScriptFilename(target) && !target.endsWith(".txt")) { if (!isScriptFilename(target) && !target.endsWith(".txt")) {
workerScript.log("wget", `Invalid target file: '${target}'. Must be a script or text file.`); workerScript.log("wget", () => `Invalid target file: '${target}'. Must be a script or text file.`);
return Promise.resolve(false); return Promise.resolve(false);
} }
const s = safeGetServer(hostname, "wget"); const s = safeGetServer(hostname, "wget");
@ -2110,19 +2126,22 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
res = s.writeToTextFile(target, data); res = s.writeToTextFile(target, data);
} }
if (!res.success) { if (!res.success) {
workerScript.log("wget", "Failed."); workerScript.log("wget", () => "Failed.");
return resolve(false); return resolve(false);
} }
if (res.overwritten) { if (res.overwritten) {
workerScript.log("wget", `Successfully retrieved content and overwrote '${target}' on '${hostname}'`); workerScript.log(
"wget",
() => `Successfully retrieved content and overwrote '${target}' on '${hostname}'`,
);
return resolve(true); return resolve(true);
} }
workerScript.log("wget", `Successfully retrieved content to new file '${target}' on '${hostname}'`); workerScript.log("wget", () => `Successfully retrieved content to new file '${target}' on '${hostname}'`);
return resolve(true); return resolve(true);
}, },
"text", "text",
).fail(function (e) { ).fail(function (e) {
workerScript.log("wget", JSON.stringify(e)); workerScript.log("wget", () => JSON.stringify(e));
return resolve(false); return resolve(false);
}); });
}); });

@ -344,13 +344,13 @@ export function NetscriptBladeburner(
player.agility >= 100 player.agility >= 100
) { ) {
player.bladeburner = new Bladeburner(player); player.bladeburner = new Bladeburner(player);
workerScript.log("joinBladeburnerDivision", "You have been accepted into the Bladeburner division"); workerScript.log("joinBladeburnerDivision", () => "You have been accepted into the Bladeburner division");
return true; return true;
} else { } else {
workerScript.log( workerScript.log(
"joinBladeburnerDivision", "joinBladeburnerDivision",
"You do not meet the requirements for joining the Bladeburner division", () => "You do not meet the requirements for joining the Bladeburner division",
); );
return false; return false;
} }

@ -53,17 +53,21 @@ export function NetscriptCodingContract(
const serv = helper.getServer(hostname, "codingcontract.attempt"); const serv = helper.getServer(hostname, "codingcontract.attempt");
if (contract.isSolution(answer)) { if (contract.isSolution(answer)) {
const reward = player.gainCodingContractReward(creward, contract.getDifficulty()); const reward = player.gainCodingContractReward(creward, contract.getDifficulty());
workerScript.log("attempt", `Successfully completed Coding Contract '${filename}'. Reward: ${reward}`); workerScript.log("attempt", () => `Successfully completed Coding Contract '${filename}'. Reward: ${reward}`);
serv.removeContract(filename); serv.removeContract(filename);
return returnReward ? reward : true; return returnReward ? reward : true;
} else { } else {
++contract.tries; ++contract.tries;
if (contract.tries >= contract.getMaxNumTries()) { if (contract.tries >= contract.getMaxNumTries()) {
workerScript.log("attempt", `Coding Contract attempt '${filename}' failed. Contract is now self-destructing`); workerScript.log(
"attempt",
() => `Coding Contract attempt '${filename}' failed. Contract is now self-destructing`,
);
serv.removeContract(filename); serv.removeContract(filename);
} else { } else {
workerScript.log( workerScript.log(
"attempt", "attempt",
() =>
`Coding Contract attempt '${filename}' failed. ${ `Coding Contract attempt '${filename}' failed. ${
contract.getMaxNumTries() - contract.tries contract.getMaxNumTries() - contract.tries
} attempts remaining.`, } attempts remaining.`,

@ -167,9 +167,9 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
if (gang === null) throw new Error("Should not be called without Gang"); if (gang === null) throw new Error("Should not be called without Gang");
const recruited = gang.recruitMember(name); const recruited = gang.recruitMember(name);
if (recruited) { if (recruited) {
workerScript.log("recruitMember", `Successfully recruited Gang Member '${name}'`); workerScript.log("recruitMember", () => `Successfully recruited Gang Member '${name}'`);
} else { } else {
workerScript.log("recruitMember", `Failed to recruit Gang Member '${name}'`); workerScript.log("recruitMember", () => `Failed to recruit Gang Member '${name}'`);
} }
return recruited; return recruited;
@ -189,11 +189,14 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
const member = getGangMember("setMemberTask", memberName); const member = getGangMember("setMemberTask", memberName);
const success = member.assignToTask(taskName); const success = member.assignToTask(taskName);
if (success) { if (success) {
workerScript.log("setMemberTask", `Successfully assigned Gang Member '${memberName}' to '${taskName}' task`); workerScript.log(
"setMemberTask",
() => `Successfully assigned Gang Member '${memberName}' to '${taskName}' task`,
);
} else { } else {
workerScript.log( workerScript.log(
"setMemberTask", "setMemberTask",
`Failed to assign Gang Member '${memberName}' to '${taskName}' task. '${memberName}' is now Unassigned`, () => `Failed to assign Gang Member '${memberName}' to '${taskName}' task. '${memberName}' is now Unassigned`,
); );
} }
@ -248,9 +251,12 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
if (!equipment) return false; if (!equipment) return false;
const res = member.buyUpgrade(equipment, player, gang); const res = member.buyUpgrade(equipment, player, gang);
if (res) { if (res) {
workerScript.log("purchaseEquipment", `Purchased '${equipName}' for Gang member '${memberName}'`); workerScript.log("purchaseEquipment", () => `Purchased '${equipName}' for Gang member '${memberName}'`);
} else { } else {
workerScript.log("purchaseEquipment", `Failed to purchase '${equipName}' for Gang member '${memberName}'`); workerScript.log(
"purchaseEquipment",
() => `Failed to purchase '${equipName}' for Gang member '${memberName}'`,
);
} }
return res; return res;
@ -271,10 +277,10 @@ export function NetscriptGang(player: IPlayer, workerScript: WorkerScript, helpe
if (gang === null) throw new Error("Should not be called without Gang"); if (gang === null) throw new Error("Should not be called without Gang");
if (engage) { if (engage) {
gang.territoryWarfareEngaged = true; gang.territoryWarfareEngaged = true;
workerScript.log("setTerritoryWarfare", "Engaging in Gang Territory Warfare"); workerScript.log("setTerritoryWarfare", () => "Engaging in Gang Territory Warfare");
} else { } else {
gang.territoryWarfareEngaged = false; gang.territoryWarfareEngaged = false;
workerScript.log("setTerritoryWarfare", "Disengaging in Gang Territory Warfare"); workerScript.log("setTerritoryWarfare", () => "Disengaging in Gang Territory Warfare");
} }
}, },
getChanceToWinClash: function (otherGang: any): number { getChanceToWinClash: function (otherGang: any): number {

@ -109,7 +109,7 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript, he
} }
const node = getHacknetNode(i, "upgradeCache"); const node = getHacknetNode(i, "upgradeCache");
if (!(node instanceof HacknetServer)) { if (!(node instanceof HacknetServer)) {
workerScript.log("upgradeCache", "Can only be called on hacknet servers"); workerScript.log("upgradeCache", () => "Can only be called on hacknet servers");
return false; return false;
} }
const res = purchaseCacheUpgrade(player, node, n); const res = purchaseCacheUpgrade(player, node, n);
@ -136,7 +136,7 @@ export function NetscriptHacknet(player: IPlayer, workerScript: WorkerScript, he
} }
const node = getHacknetNode(i, "upgradeCache"); const node = getHacknetNode(i, "upgradeCache");
if (!(node instanceof HacknetServer)) { if (!(node instanceof HacknetServer)) {
workerScript.log("getCacheUpgradeCost", "Can only be called on hacknet servers"); workerScript.log("getCacheUpgradeCost", () => "Can only be called on hacknet servers");
return -1; return -1;
} }
return node.calculateCacheUpgradeCost(n); return node.calculateCacheUpgradeCost(n);

@ -186,7 +186,10 @@ export function NetscriptSingularity(
} }
if (!augs.includes(name)) { if (!augs.includes(name)) {
workerScript.log("purchaseAugmentation", `Faction '${faction}' does not have the '${name}' augmentation.`); workerScript.log(
"purchaseAugmentation",
() => `Faction '${faction}' does not have the '${name}' augmentation.`,
);
return false; return false;
} }
@ -194,25 +197,25 @@ export function NetscriptSingularity(
if (!isNeuroflux) { if (!isNeuroflux) {
for (let j = 0; j < player.queuedAugmentations.length; ++j) { for (let j = 0; j < player.queuedAugmentations.length; ++j) {
if (player.queuedAugmentations[j].name === aug.name) { if (player.queuedAugmentations[j].name === aug.name) {
workerScript.log("purchaseAugmentation", `You already have the '${name}' augmentation.`); workerScript.log("purchaseAugmentation", () => `You already have the '${name}' augmentation.`);
return false; return false;
} }
} }
for (let j = 0; j < player.augmentations.length; ++j) { for (let j = 0; j < player.augmentations.length; ++j) {
if (player.augmentations[j].name === aug.name) { if (player.augmentations[j].name === aug.name) {
workerScript.log("purchaseAugmentation", `You already have the '${name}' augmentation.`); workerScript.log("purchaseAugmentation", () => `You already have the '${name}' augmentation.`);
return false; return false;
} }
} }
} }
if (fac.playerReputation < aug.baseRepRequirement) { if (fac.playerReputation < aug.baseRepRequirement) {
workerScript.log("purchaseAugmentation", `You do not have enough reputation with '${fac.name}'.`); workerScript.log("purchaseAugmentation", () => `You do not have enough reputation with '${fac.name}'.`);
return false; return false;
} }
const res = purchaseAugmentation(aug, fac, true); const res = purchaseAugmentation(aug, fac, true);
workerScript.log("purchaseAugmentation", res); workerScript.log("purchaseAugmentation", () => res);
if (isString(res) && res.startsWith("You purchased")) { if (isString(res) && res.startsWith("You purchased")) {
player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain); player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain);
return true; return true;
@ -224,7 +227,7 @@ export function NetscriptSingularity(
helper.updateDynamicRam("softReset", getRamCost("softReset")); helper.updateDynamicRam("softReset", getRamCost("softReset"));
helper.checkSingularityAccess("softReset", 3); helper.checkSingularityAccess("softReset", 3);
workerScript.log("softReset", "Soft resetting. This will cause this script to be killed"); workerScript.log("softReset", () => "Soft resetting. This will cause this script to be killed");
setTimeout(() => { setTimeout(() => {
prestigeAugmentation(); prestigeAugmentation();
runAfterReset(cbScript); runAfterReset(cbScript);
@ -239,11 +242,14 @@ export function NetscriptSingularity(
helper.checkSingularityAccess("installAugmentations", 3); helper.checkSingularityAccess("installAugmentations", 3);
if (player.queuedAugmentations.length === 0) { if (player.queuedAugmentations.length === 0) {
workerScript.log("installAugmentations", "You do not have any Augmentations to be installed."); workerScript.log("installAugmentations", () => "You do not have any Augmentations to be installed.");
return false; return false;
} }
player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain); player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain);
workerScript.log("installAugmentations", "Installing Augmentations. This will cause this script to be killed"); workerScript.log(
"installAugmentations",
() => "Installing Augmentations. This will cause this script to be killed",
);
setTimeout(() => { setTimeout(() => {
installAugmentations(); installAugmentations();
runAfterReset(cbScript); runAfterReset(cbScript);
@ -258,11 +264,11 @@ export function NetscriptSingularity(
helper.checkSingularityAccess("goToLocation", 1); helper.checkSingularityAccess("goToLocation", 1);
const location = Object.values(Locations).find((l) => l.name === locationName); const location = Object.values(Locations).find((l) => l.name === locationName);
if (!location) { if (!location) {
workerScript.log("goToLocation", `No location named ${locationName}`); workerScript.log("goToLocation", () => `No location named ${locationName}`);
return false; return false;
} }
if (player.city !== location.city) { if (player.city !== location.city) {
workerScript.log("goToLocation", `No location named ${locationName} in ${player.city}`); workerScript.log("goToLocation", () => `No location named ${locationName} in ${player.city}`);
return false; return false;
} }
Router.toLocation(location); Router.toLocation(location);
@ -274,7 +280,7 @@ export function NetscriptSingularity(
helper.checkSingularityAccess("universityCourse", 1); helper.checkSingularityAccess("universityCourse", 1);
if (player.isWorking) { if (player.isWorking) {
const txt = player.singularityStopWork(); const txt = player.singularityStopWork();
workerScript.log("universityCourse", txt); workerScript.log("universityCourse", () => txt);
} }
let costMult, expMult; let costMult, expMult;
@ -283,7 +289,7 @@ export function NetscriptSingularity(
if (player.city != CityName.Aevum) { if (player.city != CityName.Aevum) {
workerScript.log( workerScript.log(
"universityCourse", "universityCourse",
"You cannot study at 'Summit University' because you are not in 'Aevum'.", () => "You cannot study at 'Summit University' because you are not in 'Aevum'.",
); );
return false; return false;
} }
@ -295,7 +301,7 @@ export function NetscriptSingularity(
if (player.city != CityName.Sector12) { if (player.city != CityName.Sector12) {
workerScript.log( workerScript.log(
"universityCourse", "universityCourse",
"You cannot study at 'Rothman University' because you are not in 'Sector-12'.", () => "You cannot study at 'Rothman University' because you are not in 'Sector-12'.",
); );
return false; return false;
} }
@ -307,7 +313,7 @@ export function NetscriptSingularity(
if (player.city != CityName.Volhaven) { if (player.city != CityName.Volhaven) {
workerScript.log( workerScript.log(
"universityCourse", "universityCourse",
"You cannot study at 'ZB Institute of Technology' because you are not in 'Volhaven'.", () => "You cannot study at 'ZB Institute of Technology' because you are not in 'Volhaven'.",
); );
return false; return false;
} }
@ -316,11 +322,11 @@ export function NetscriptSingularity(
expMult = 4; expMult = 4;
break; break;
default: default:
workerScript.log("universityCourse", `Invalid university name: '${universityName}'.`); workerScript.log("universityCourse", () => `Invalid university name: '${universityName}'.`);
return false; return false;
} }
let task; let task = "";
switch (className.toLowerCase()) { switch (className.toLowerCase()) {
case "Study Computer Science".toLowerCase(): case "Study Computer Science".toLowerCase():
task = CONSTANTS.ClassStudyComputerScience; task = CONSTANTS.ClassStudyComputerScience;
@ -341,11 +347,11 @@ export function NetscriptSingularity(
task = CONSTANTS.ClassLeadership; task = CONSTANTS.ClassLeadership;
break; break;
default: default:
workerScript.log("universityCourse", `Invalid class name: ${className}.`); workerScript.log("universityCourse", () => `Invalid class name: ${className}.`);
return false; return false;
} }
player.startClass(Router, costMult, expMult, task); player.startClass(Router, costMult, expMult, task);
workerScript.log("universityCourse", `Started ${task} at ${universityName}`); workerScript.log("universityCourse", () => `Started ${task} at ${universityName}`);
return true; return true;
}, },
@ -354,13 +360,16 @@ export function NetscriptSingularity(
helper.checkSingularityAccess("gymWorkout", 1); helper.checkSingularityAccess("gymWorkout", 1);
if (player.isWorking) { if (player.isWorking) {
const txt = player.singularityStopWork(); const txt = player.singularityStopWork();
workerScript.log("gymWorkout", txt); workerScript.log("gymWorkout", () => txt);
} }
let costMult, expMult; let costMult, expMult;
switch (gymName.toLowerCase()) { switch (gymName.toLowerCase()) {
case LocationName.AevumCrushFitnessGym.toLowerCase(): case LocationName.AevumCrushFitnessGym.toLowerCase():
if (player.city != CityName.Aevum) { if (player.city != CityName.Aevum) {
workerScript.log("gymWorkout", "You cannot workout at 'Crush Fitness' because you are not in 'Aevum'."); workerScript.log(
"gymWorkout",
() => "You cannot workout at 'Crush Fitness' because you are not in 'Aevum'.",
);
return false; return false;
} }
player.location = LocationName.AevumCrushFitnessGym; player.location = LocationName.AevumCrushFitnessGym;
@ -369,7 +378,10 @@ export function NetscriptSingularity(
break; break;
case LocationName.AevumSnapFitnessGym.toLowerCase(): case LocationName.AevumSnapFitnessGym.toLowerCase():
if (player.city != CityName.Aevum) { if (player.city != CityName.Aevum) {
workerScript.log("gymWorkout", "You cannot workout at 'Snap Fitness' because you are not in 'Aevum'."); workerScript.log(
"gymWorkout",
() => "You cannot workout at 'Snap Fitness' because you are not in 'Aevum'.",
);
return false; return false;
} }
player.location = LocationName.AevumSnapFitnessGym; player.location = LocationName.AevumSnapFitnessGym;
@ -378,7 +390,10 @@ export function NetscriptSingularity(
break; break;
case LocationName.Sector12IronGym.toLowerCase(): case LocationName.Sector12IronGym.toLowerCase():
if (player.city != CityName.Sector12) { if (player.city != CityName.Sector12) {
workerScript.log("gymWorkout", "You cannot workout at 'Iron Gym' because you are not in 'Sector-12'."); workerScript.log(
"gymWorkout",
() => "You cannot workout at 'Iron Gym' because you are not in 'Sector-12'.",
);
return false; return false;
} }
player.location = LocationName.Sector12IronGym; player.location = LocationName.Sector12IronGym;
@ -389,7 +404,7 @@ export function NetscriptSingularity(
if (player.city != CityName.Sector12) { if (player.city != CityName.Sector12) {
workerScript.log( workerScript.log(
"gymWorkout", "gymWorkout",
"You cannot workout at 'Powerhouse Gym' because you are not in 'Sector-12'.", () => "You cannot workout at 'Powerhouse Gym' because you are not in 'Sector-12'.",
); );
return false; return false;
} }
@ -401,7 +416,7 @@ export function NetscriptSingularity(
if (player.city != CityName.Volhaven) { if (player.city != CityName.Volhaven) {
workerScript.log( workerScript.log(
"gymWorkout", "gymWorkout",
"You cannot workout at 'Millenium Fitness Gym' because you are not in 'Volhaven'.", () => "You cannot workout at 'Millenium Fitness Gym' because you are not in 'Volhaven'.",
); );
return false; return false;
} }
@ -410,7 +425,7 @@ export function NetscriptSingularity(
expMult = 4; expMult = 4;
break; break;
default: default:
workerScript.log("gymWorkout", `Invalid gym name: ${gymName}. gymWorkout() failed`); workerScript.log("gymWorkout", () => `Invalid gym name: ${gymName}. gymWorkout() failed`);
return false; return false;
} }
@ -432,10 +447,10 @@ export function NetscriptSingularity(
player.startClass(Router, costMult, expMult, CONSTANTS.ClassGymAgility); player.startClass(Router, costMult, expMult, CONSTANTS.ClassGymAgility);
break; break;
default: default:
workerScript.log("gymWorkout", `Invalid stat: ${stat}.`); workerScript.log("gymWorkout", () => `Invalid stat: ${stat}.`);
return false; return false;
} }
workerScript.log("gymWorkout", `Started training ${stat} at ${gymName}`); workerScript.log("gymWorkout", () => `Started training ${stat} at ${gymName}`);
return true; return true;
}, },
@ -455,11 +470,11 @@ export function NetscriptSingularity(
} }
player.loseMoney(CONSTANTS.TravelCost, "other"); player.loseMoney(CONSTANTS.TravelCost, "other");
player.city = cityname; player.city = cityname;
workerScript.log("travelToCity", `Traveled to ${cityname}`); workerScript.log("travelToCity", () => `Traveled to ${cityname}`);
player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain / 50); player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain / 50);
return true; return true;
default: default:
workerScript.log("travelToCity", `Invalid city name: '${cityname}'.`); workerScript.log("travelToCity", () => `Invalid city name: '${cityname}'.`);
return false; return false;
} }
}, },
@ -469,12 +484,12 @@ export function NetscriptSingularity(
helper.checkSingularityAccess("purchaseTor", 1); helper.checkSingularityAccess("purchaseTor", 1);
if (player.hasTorRouter()) { if (player.hasTorRouter()) {
workerScript.log("purchaseTor", "You already have a TOR router!"); workerScript.log("purchaseTor", () => "You already have a TOR router!");
return false; return false;
} }
if (player.money < CONSTANTS.TorRouterCost) { if (player.money < CONSTANTS.TorRouterCost) {
workerScript.log("purchaseTor", "You cannot afford to purchase a Tor router."); workerScript.log("purchaseTor", () => "You cannot afford to purchase a Tor router.");
return false; return false;
} }
player.loseMoney(CONSTANTS.TorRouterCost, "other"); player.loseMoney(CONSTANTS.TorRouterCost, "other");
@ -493,7 +508,7 @@ export function NetscriptSingularity(
player.getHomeComputer().serversOnNetwork.push(darkweb.hostname); player.getHomeComputer().serversOnNetwork.push(darkweb.hostname);
darkweb.serversOnNetwork.push(player.getHomeComputer().hostname); darkweb.serversOnNetwork.push(player.getHomeComputer().hostname);
player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain); player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain);
workerScript.log("purchaseTor", "You have purchased a Tor router!"); workerScript.log("purchaseTor", () => "You have purchased a Tor router!");
return true; return true;
}, },
purchaseProgram: function (programName: any): any { purchaseProgram: function (programName: any): any {
@ -501,35 +516,28 @@ export function NetscriptSingularity(
helper.checkSingularityAccess("purchaseProgram", 1); helper.checkSingularityAccess("purchaseProgram", 1);
if (!player.hasTorRouter()) { if (!player.hasTorRouter()) {
workerScript.log("purchaseProgram", "You do not have the TOR router."); workerScript.log("purchaseProgram", () => "You do not have the TOR router.");
return false; return false;
} }
programName = programName.toLowerCase(); programName = programName.toLowerCase();
let item = null; const item = Object.values(DarkWebItems).find((i) => i.program.toLowerCase() === programName);
for (const key in DarkWebItems) {
const i = DarkWebItems[key];
if (i.program.toLowerCase() == programName) {
item = i;
}
}
if (item == null) { if (item == null) {
workerScript.log("purchaseProgram", `Invalid program name: '${programName}.`); workerScript.log("purchaseProgram", () => `Invalid program name: '${programName}.`);
return false; return false;
} }
if (player.money < item.price) { if (player.money < item.price) {
workerScript.log( workerScript.log(
"purchaseProgram", "purchaseProgram",
`Not enough money to purchase '${item.program}'. Need ${numeralWrapper.formatMoney(item.price)}`, () => `Not enough money to purchase '${item.program}'. Need ${numeralWrapper.formatMoney(item.price)}`,
); );
return false; return false;
} }
if (player.hasProgram(item.program)) { if (player.hasProgram(item.program)) {
workerScript.log("purchaseProgram", `You already have the '${item.program}' program`); workerScript.log("purchaseProgram", () => `You already have the '${item.program}' program`);
return true; return true;
} }
@ -537,7 +545,7 @@ export function NetscriptSingularity(
player.getHomeComputer().programs.push(item.program); player.getHomeComputer().programs.push(item.program);
workerScript.log( workerScript.log(
"purchaseProgram", "purchaseProgram",
`You have purchased the '${item.program}' program. The new program can be found on your home computer.`, () => `You have purchased the '${item.program}' program. The new program can be found on your home computer.`,
); );
player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain / 50); player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain / 50);
return true; return true;
@ -593,7 +601,7 @@ export function NetscriptSingularity(
helper.checkSingularityAccess("installBackdoor", 1); helper.checkSingularityAccess("installBackdoor", 1);
const baseserver = player.getCurrentServer(); const baseserver = player.getCurrentServer();
if (!(baseserver instanceof Server)) { if (!(baseserver instanceof Server)) {
workerScript.log("installBackdoor", "cannot backdoor this kind of server"); workerScript.log("installBackdoor", () => "cannot backdoor this kind of server");
return Promise.resolve(); return Promise.resolve();
} }
const server = baseserver as Server; const server = baseserver as Server;
@ -607,14 +615,14 @@ export function NetscriptSingularity(
workerScript.log( workerScript.log(
"installBackdoor", "installBackdoor",
`Installing backdoor on '${server.hostname}' in ${convertTimeMsToTimeElapsedString(installTime, true)}`, () => `Installing backdoor on '${server.hostname}' in ${convertTimeMsToTimeElapsedString(installTime, true)}`,
); );
return netscriptDelay(installTime, workerScript).then(function () { return netscriptDelay(installTime, workerScript).then(function () {
if (workerScript.env.stopFlag) { if (workerScript.env.stopFlag) {
return Promise.reject(workerScript); return Promise.reject(workerScript);
} }
workerScript.log("installBackdoor", `Successfully installed backdoor on '${server.hostname}'`); workerScript.log("installBackdoor", () => `Successfully installed backdoor on '${server.hostname}'`);
server.backdoorInstalled = true; server.backdoorInstalled = true;
@ -627,7 +635,7 @@ export function NetscriptSingularity(
getStats: function (): any { getStats: function (): any {
helper.updateDynamicRam("getStats", getRamCost("getStats")); helper.updateDynamicRam("getStats", getRamCost("getStats"));
helper.checkSingularityAccess("getStats", 1); helper.checkSingularityAccess("getStats", 1);
workerScript.log("getStats", `getStats is deprecated, please use getplayer`); workerScript.log("getStats", () => `getStats is deprecated, please use getplayer`);
return { return {
hacking: player.hacking, hacking: player.hacking,
@ -642,7 +650,7 @@ export function NetscriptSingularity(
getCharacterInformation: function (): any { getCharacterInformation: function (): any {
helper.updateDynamicRam("getCharacterInformation", getRamCost("getCharacterInformation")); helper.updateDynamicRam("getCharacterInformation", getRamCost("getCharacterInformation"));
helper.checkSingularityAccess("getCharacterInformation", 1); helper.checkSingularityAccess("getCharacterInformation", 1);
workerScript.log("getCharacterInformation", `getCharacterInformation is deprecated, please use getplayer`); workerScript.log("getCharacterInformation", () => `getCharacterInformation is deprecated, please use getplayer`);
return { return {
bitnode: player.bitNodeN, bitnode: player.bitNodeN,
@ -691,7 +699,7 @@ export function NetscriptSingularity(
helper.updateDynamicRam("hospitalize", getRamCost("hospitalize")); helper.updateDynamicRam("hospitalize", getRamCost("hospitalize"));
helper.checkSingularityAccess("hospitalize", 1); helper.checkSingularityAccess("hospitalize", 1);
if (player.isWorking || Router.page() === Page.Infiltration || Router.page() === Page.BitVerse) { if (player.isWorking || Router.page() === Page.Infiltration || Router.page() === Page.BitVerse) {
workerScript.log("hospitalize", "Cannot go to the hospital because the player is busy."); workerScript.log("hospitalize", () => "Cannot go to the hospital because the player is busy.");
return; return;
} }
return player.hospitalize(); return player.hospitalize();
@ -707,7 +715,7 @@ export function NetscriptSingularity(
if (player.isWorking) { if (player.isWorking) {
Router.toTerminal(); Router.toTerminal();
const txt = player.singularityStopWork(); const txt = player.singularityStopWork();
workerScript.log("stopAction", txt); workerScript.log("stopAction", () => txt);
return true; return true;
} }
return false; return false;
@ -719,13 +727,16 @@ export function NetscriptSingularity(
// Check if we're at max cores // Check if we're at max cores
const homeComputer = player.getHomeComputer(); const homeComputer = player.getHomeComputer();
if (homeComputer.cpuCores >= 8) { if (homeComputer.cpuCores >= 8) {
workerScript.log("upgradeHomeCores", `Your home computer is at max cores.`); workerScript.log("upgradeHomeCores", () => `Your home computer is at max cores.`);
return false; return false;
} }
const cost = player.getUpgradeHomeCoresCost(); const cost = player.getUpgradeHomeCoresCost();
if (player.money < cost) { if (player.money < cost) {
workerScript.log("upgradeHomeCores", `You don't have enough money. Need ${numeralWrapper.formatMoney(cost)}`); workerScript.log(
"upgradeHomeCores",
() => `You don't have enough money. Need ${numeralWrapper.formatMoney(cost)}`,
);
return false; return false;
} }
@ -735,7 +746,7 @@ export function NetscriptSingularity(
player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain); player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain);
workerScript.log( workerScript.log(
"upgradeHomeCores", "upgradeHomeCores",
`Purchased an additional core for home computer! It now has ${homeComputer.cpuCores} cores.`, () => `Purchased an additional core for home computer! It now has ${homeComputer.cpuCores} cores.`,
); );
return true; return true;
}, },
@ -752,13 +763,16 @@ export function NetscriptSingularity(
// Check if we're at max RAM // Check if we're at max RAM
const homeComputer = player.getHomeComputer(); const homeComputer = player.getHomeComputer();
if (homeComputer.maxRam >= CONSTANTS.HomeComputerMaxRam) { if (homeComputer.maxRam >= CONSTANTS.HomeComputerMaxRam) {
workerScript.log("upgradeHomeRam", `Your home computer is at max RAM.`); workerScript.log("upgradeHomeRam", () => `Your home computer is at max RAM.`);
return false; return false;
} }
const cost = player.getUpgradeHomeRamCost(); const cost = player.getUpgradeHomeRamCost();
if (player.money < cost) { if (player.money < cost) {
workerScript.log("upgradeHomeRam", `You don't have enough money. Need ${numeralWrapper.formatMoney(cost)}`); workerScript.log(
"upgradeHomeRam",
() => `You don't have enough money. Need ${numeralWrapper.formatMoney(cost)}`,
);
return false; return false;
} }
@ -768,6 +782,7 @@ export function NetscriptSingularity(
player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain); player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain);
workerScript.log( workerScript.log(
"upgradeHomeRam", "upgradeHomeRam",
() =>
`Purchased additional RAM for home computer! It now has ${numeralWrapper.formatRAM( `Purchased additional RAM for home computer! It now has ${numeralWrapper.formatRAM(
homeComputer.maxRam, homeComputer.maxRam,
)} of RAM.`, )} of RAM.`,
@ -791,13 +806,13 @@ export function NetscriptSingularity(
// Make sure its a valid company // Make sure its a valid company
if (companyName == null || companyName === "" || !(Companies[companyName] instanceof Company)) { if (companyName == null || companyName === "" || !(Companies[companyName] instanceof Company)) {
workerScript.log("workForCompany", `Invalid company: '${companyName}'`); workerScript.log("workForCompany", () => `Invalid company: '${companyName}'`);
return false; return false;
} }
// Make sure player is actually employed at the comapny // Make sure player is actually employed at the comapny
if (!Object.keys(player.jobs).includes(companyName)) { if (!Object.keys(player.jobs).includes(companyName)) {
workerScript.log("workForCompany", `You do not have a job at '${companyName}'`); workerScript.log("workForCompany", () => `You do not have a job at '${companyName}'`);
return false; return false;
} }
@ -805,13 +820,13 @@ export function NetscriptSingularity(
const companyPositionName = player.jobs[companyName]; const companyPositionName = player.jobs[companyName];
const companyPosition = CompanyPositions[companyPositionName]; const companyPosition = CompanyPositions[companyPositionName];
if (companyPositionName === "" || !(companyPosition instanceof CompanyPosition)) { if (companyPositionName === "" || !(companyPosition instanceof CompanyPosition)) {
workerScript.log("workForCompany", "You do not have a job"); workerScript.log("workForCompany", () => "You do not have a job");
return false; return false;
} }
if (player.isWorking) { if (player.isWorking) {
const txt = player.singularityStopWork(); const txt = player.singularityStopWork();
workerScript.log("workForCompany", txt); workerScript.log("workForCompany", () => txt);
} }
if (companyPosition.isPartTimeJob()) { if (companyPosition.isPartTimeJob()) {
@ -819,7 +834,10 @@ export function NetscriptSingularity(
} else { } else {
player.startWork(Router, companyName); player.startWork(Router, companyName);
} }
workerScript.log("workForCompany", `Began working at '${player.companyName}' as a '${companyPositionName}'`); workerScript.log(
"workForCompany",
() => `Began working at '${player.companyName}' as a '${companyPositionName}'`,
);
return true; return true;
}, },
applyToCompany: function (companyName: any, field: any): any { applyToCompany: function (companyName: any, field: any): any {
@ -870,24 +888,24 @@ export function NetscriptSingularity(
res = player.applyForPartTimeWaiterJob(true); res = player.applyForPartTimeWaiterJob(true);
break; break;
default: default:
workerScript.log("applyToCompany", `Invalid job: '${field}'.`); workerScript.log("applyToCompany", () => `Invalid job: '${field}'.`);
return false; return false;
} }
// TODO https://github.com/danielyxie/bitburner/issues/1378 // TODO https://github.com/danielyxie/bitburner/issues/1378
// The player object's applyForJob function can return string with special error messages // The player object's applyForJob function can return string with special error messages
// if (isString(res)) { // if (isString(res)) {
// workerScript.log("applyToCompany", res); // workerScript.log("applyToCompany",()=> res);
// return false; // return false;
// } // }
if (res) { if (res) {
workerScript.log( workerScript.log(
"applyToCompany", "applyToCompany",
`You were offered a new job at '${companyName}' as a '${player.jobs[companyName]}'`, () => `You were offered a new job at '${companyName}' as a '${player.jobs[companyName]}'`,
); );
} else { } else {
workerScript.log( workerScript.log(
"applyToCompany", "applyToCompany",
`You failed to get a new job/promotion at '${companyName}' in the '${field}' field.`, () => `You failed to get a new job/promotion at '${companyName}' in the '${field}' field.`,
); );
} }
return res; return res;
@ -922,7 +940,7 @@ export function NetscriptSingularity(
getFaction("joinFaction", name); getFaction("joinFaction", name);
if (!player.factionInvitations.includes(name)) { if (!player.factionInvitations.includes(name)) {
workerScript.log("joinFaction", `You have not been invited by faction '${name}'`); workerScript.log("joinFaction", () => `You have not been invited by faction '${name}'`);
return false; return false;
} }
const fac = Factions[name]; const fac = Factions[name];
@ -936,7 +954,7 @@ export function NetscriptSingularity(
} }
} }
player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain); player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain);
workerScript.log("joinFaction", `Joined the '${name}' faction.`); workerScript.log("joinFaction", () => `Joined the '${name}' faction.`);
return true; return true;
}, },
workForFaction: function (name: any, type: any): any { workForFaction: function (name: any, type: any): any {
@ -946,18 +964,18 @@ export function NetscriptSingularity(
// if the player is in a gang and the target faction is any of the gang faction, fail // if the player is in a gang and the target faction is any of the gang faction, fail
if (player.inGang() && AllGangs[name] !== undefined) { if (player.inGang() && AllGangs[name] !== undefined) {
workerScript.log("workForFaction", `Faction '${name}' does not offer work at the moment.`); workerScript.log("workForFaction", () => `Faction '${name}' does not offer work at the moment.`);
return; return;
} }
if (!player.factions.includes(name)) { if (!player.factions.includes(name)) {
workerScript.log("workForFaction", `You are not a member of '${name}'`); workerScript.log("workForFaction", () => `You are not a member of '${name}'`);
return false; return false;
} }
if (player.isWorking) { if (player.isWorking) {
const txt = player.singularityStopWork(); const txt = player.singularityStopWork();
workerScript.log("workForFaction", txt); workerScript.log("workForFaction", () => txt);
} }
const fac = Factions[name]; const fac = Factions[name];
@ -1049,34 +1067,34 @@ export function NetscriptSingularity(
case "hacking contracts": case "hacking contracts":
case "hackingcontracts": case "hackingcontracts":
if (!hackAvailable.includes(fac.name)) { if (!hackAvailable.includes(fac.name)) {
workerScript.log("workForFaction", `Faction '${fac.name}' do not need help with hacking contracts.`); workerScript.log("workForFaction", () => `Faction '${fac.name}' do not need help with hacking contracts.`);
return false; return false;
} }
player.startFactionHackWork(Router, fac); player.startFactionHackWork(Router, fac);
workerScript.log("workForFaction", `Started carrying out hacking contracts for '${fac.name}'`); workerScript.log("workForFaction", () => `Started carrying out hacking contracts for '${fac.name}'`);
return true; return true;
case "field": case "field":
case "fieldwork": case "fieldwork":
case "field work": case "field work":
if (!fdWkAvailable.includes(fac.name)) { if (!fdWkAvailable.includes(fac.name)) {
workerScript.log("workForFaction", `Faction '${fac.name}' do not need help with field missions.`); workerScript.log("workForFaction", () => `Faction '${fac.name}' do not need help with field missions.`);
return false; return false;
} }
player.startFactionFieldWork(Router, fac); player.startFactionFieldWork(Router, fac);
workerScript.log("workForFaction", `Started carrying out field missions for '${fac.name}'`); workerScript.log("workForFaction", () => `Started carrying out field missions for '${fac.name}'`);
return true; return true;
case "security": case "security":
case "securitywork": case "securitywork":
case "security work": case "security work":
if (!scWkAvailable.includes(fac.name)) { if (!scWkAvailable.includes(fac.name)) {
workerScript.log("workForFaction", `Faction '${fac.name}' do not need help with security work.`); workerScript.log("workForFaction", () => `Faction '${fac.name}' do not need help with security work.`);
return false; return false;
} }
player.startFactionSecurityWork(Router, fac); player.startFactionSecurityWork(Router, fac);
workerScript.log("workForFaction", `Started carrying out security work for '${fac.name}'`); workerScript.log("workForFaction", () => `Started carrying out security work for '${fac.name}'`);
return true; return true;
default: default:
workerScript.log("workForFaction", `Invalid work type: '${type}`); workerScript.log("workForFaction", () => `Invalid work type: '${type}`);
} }
return true; return true;
}, },
@ -1104,13 +1122,13 @@ export function NetscriptSingularity(
const faction = getFaction("donateToFaction", name); const faction = getFaction("donateToFaction", name);
if (typeof amt !== "number" || amt <= 0) { if (typeof amt !== "number" || amt <= 0) {
workerScript.log("donateToFaction", `Invalid donation amount: '${amt}'.`); workerScript.log("donateToFaction", () => `Invalid donation amount: '${amt}'.`);
return false; return false;
} }
if (player.money < amt) { if (player.money < amt) {
workerScript.log( workerScript.log(
"donateToFaction", "donateToFaction",
`You do not have enough money to donate ${numeralWrapper.formatMoney(amt)} to '${name}'`, () => `You do not have enough money to donate ${numeralWrapper.formatMoney(amt)} to '${name}'`,
); );
return false; return false;
} }
@ -1118,6 +1136,7 @@ export function NetscriptSingularity(
if (faction.favor < repNeededToDonate) { if (faction.favor < repNeededToDonate) {
workerScript.log( workerScript.log(
"donateToFaction", "donateToFaction",
() =>
`You do not have enough favor to donate to this faction. Have ${faction.favor}, need ${repNeededToDonate}`, `You do not have enough favor to donate to this faction. Have ${faction.favor}, need ${repNeededToDonate}`,
); );
return false; return false;
@ -1127,6 +1146,7 @@ export function NetscriptSingularity(
player.loseMoney(amt, "other"); player.loseMoney(amt, "other");
workerScript.log( workerScript.log(
"donateToFaction", "donateToFaction",
() =>
`${numeralWrapper.formatMoney(amt)} donated to '${name}' for ${numeralWrapper.formatReputation( `${numeralWrapper.formatMoney(amt)} donated to '${name}' for ${numeralWrapper.formatReputation(
repGain, repGain,
)} reputation`, )} reputation`,
@ -1139,41 +1159,39 @@ export function NetscriptSingularity(
if (player.isWorking) { if (player.isWorking) {
const txt = player.singularityStopWork(); const txt = player.singularityStopWork();
workerScript.log("createProgram", txt); workerScript.log("createProgram", () => txt);
} }
name = name.toLowerCase(); name = name.toLowerCase();
let p = null; const p = Object.values(Programs).find((p) => p.name.toLowerCase() === name);
for (const key in Programs) {
if (Programs[key].name.toLowerCase() == name) {
p = Programs[key];
}
}
if (p == null) { if (p == null) {
workerScript.log("createProgram", `The specified program does not exist: '${name}`); workerScript.log("createProgram", () => `The specified program does not exist: '${name}`);
return false; return false;
} }
if (player.hasProgram(p.name)) { if (player.hasProgram(p.name)) {
workerScript.log("createProgram", `You already have the '${p.name}' program`); workerScript.log("createProgram", () => `You already have the '${p.name}' program`);
return false; return false;
} }
const create = p.create; const create = p.create;
if (create === null) { if (create === null) {
workerScript.log("createProgram", `You cannot create the '${p.name}' program`); workerScript.log("createProgram", () => `You cannot create the '${p.name}' program`);
return false; return false;
} }
if (!create.req(player)) { if (!create.req(player)) {
workerScript.log("createProgram", `Hacking level is too low to create '${p.name}' (level ${create.level} req)`); workerScript.log(
"createProgram",
() => `Hacking level is too low to create '${p.name}' (level ${create.level} req)`,
);
return false; return false;
} }
player.startCreateProgramWork(Router, p.name, create.time, create.level); player.startCreateProgramWork(Router, p.name, create.time, create.level);
workerScript.log("createProgram", `Began creating program: '${name}'`); workerScript.log("createProgram", () => `Began creating program: '${name}'`);
return true; return true;
}, },
commitCrime: function (crimeRoughName: any): any { commitCrime: function (crimeRoughName: any): any {
@ -1182,7 +1200,7 @@ export function NetscriptSingularity(
if (player.isWorking) { if (player.isWorking) {
const txt = player.singularityStopWork(); const txt = player.singularityStopWork();
workerScript.log("commitCrime", txt); workerScript.log("commitCrime", () => txt);
} }
// Set Location to slums // Set Location to slums
@ -1193,7 +1211,7 @@ export function NetscriptSingularity(
// couldn't find crime // couldn't find crime
throw helper.makeRuntimeErrorMsg("commitCrime", `Invalid crime: '${crimeRoughName}'`); throw helper.makeRuntimeErrorMsg("commitCrime", `Invalid crime: '${crimeRoughName}'`);
} }
workerScript.log("commitCrime", `Attempting to commit ${crime.name}...`); workerScript.log("commitCrime", () => `Attempting to commit ${crime.name}...`);
return crime.commit(Router, player, 1, workerScript); return crime.commit(Router, player, 1, workerScript);
}, },
getCrimeChance: function (crimeRoughName: any): any { getCrimeChance: function (crimeRoughName: any): any {

@ -25,7 +25,7 @@ export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, hel
const checkSleeveNumber = function (func: any, sleeveNumber: any): void { const checkSleeveNumber = function (func: any, sleeveNumber: any): void {
if (sleeveNumber >= player.sleeves.length || sleeveNumber < 0) { if (sleeveNumber >= player.sleeves.length || sleeveNumber < 0) {
const msg = `Invalid sleeve number: ${sleeveNumber}`; const msg = `Invalid sleeve number: ${sleeveNumber}`;
workerScript.log(func, msg); workerScript.log(func, () => msg);
throw helper.makeRuntimeErrorMsg(`sleeve.${func}`, msg); throw helper.makeRuntimeErrorMsg(`sleeve.${func}`, msg);
} }
}; };

@ -315,18 +315,18 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
checkTixApiAccess("purchase4SMarketData"); checkTixApiAccess("purchase4SMarketData");
if (player.has4SData) { if (player.has4SData) {
workerScript.log("purchase4SMarketData", "Already purchased 4S Market Data."); workerScript.log("stock.purchase4SMarketData", () => "Already purchased 4S Market Data.");
return true; return true;
} }
if (player.money < getStockMarket4SDataCost()) { if (player.money < getStockMarket4SDataCost()) {
workerScript.log("purchase4SMarketData", "Not enough money to purchase 4S Market Data."); workerScript.log("stock.purchase4SMarketData", () => "Not enough money to purchase 4S Market Data.");
return false; return false;
} }
player.has4SData = true; player.has4SData = true;
player.loseMoney(getStockMarket4SDataCost(), "stock"); player.loseMoney(getStockMarket4SDataCost(), "stock");
workerScript.log("purchase4SMarketData", "Purchased 4S Market Data"); workerScript.log("stock.purchase4SMarketData", () => "Purchased 4S Market Data");
return true; return true;
}, },
purchase4SMarketDataTixApi: function () { purchase4SMarketDataTixApi: function () {
@ -334,18 +334,21 @@ export function NetscriptStockMarket(player: IPlayer, workerScript: WorkerScript
checkTixApiAccess("purchase4SMarketDataTixApi"); checkTixApiAccess("purchase4SMarketDataTixApi");
if (player.has4SDataTixApi) { if (player.has4SDataTixApi) {
workerScript.log("purchase4SMarketDataTixApi", "Already purchased 4S Market Data TIX API"); workerScript.log("stock.purchase4SMarketDataTixApi", () => "Already purchased 4S Market Data TIX API");
return true; return true;
} }
if (player.money < getStockMarket4STixApiCost()) { if (player.money < getStockMarket4STixApiCost()) {
workerScript.log("purchase4SMarketDataTixApi", "Not enough money to purchase 4S Market Data TIX API"); workerScript.log(
"stock.purchase4SMarketDataTixApi",
() => "Not enough money to purchase 4S Market Data TIX API",
);
return false; return false;
} }
player.has4SDataTixApi = true; player.has4SDataTixApi = true;
player.loseMoney(getStockMarket4STixApiCost(), "stock"); player.loseMoney(getStockMarket4STixApiCost(), "stock");
workerScript.log("purchase4SMarketDataTixApi", "Purchased 4S Market Data TIX API"); workerScript.log("stock.purchase4SMarketDataTixApi", () => "Purchased 4S Market Data TIX API");
return true; return true;
}, },
}; };

@ -535,7 +535,7 @@ function createAndAddWorkerScript(runningScriptObj: RunningScript, server: BaseS
} }
killWorkerScript(s); killWorkerScript(s);
w.log("", "Script finished running"); w.log("", () => "Script finished running");
}).catch(function (w) { }).catch(function (w) {
if (w instanceof Error) { if (w instanceof Error) {
dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer"); dialogBoxCreate("Script runtime unknown error. This is a bug please contact game developer");
@ -561,9 +561,9 @@ function createAndAddWorkerScript(runningScriptObj: RunningScript, server: BaseS
msg += errorMsg; msg += errorMsg;
dialogBoxCreate(msg); dialogBoxCreate(msg);
w.log("", "Script crashed with runtime error"); w.log("", () => "Script crashed with runtime error");
} else { } else {
w.log("", "Script killed"); w.log("", () => "Script killed");
return; // Already killed, so stop here return; // Already killed, so stop here
} }
w.running = false; w.running = false;
@ -645,7 +645,7 @@ export function runScriptFromScript(
} }
if (typeof scriptname !== "string" || !Array.isArray(args)) { if (typeof scriptname !== "string" || !Array.isArray(args)) {
workerScript.log(caller, `Invalid arguments: scriptname='${scriptname} args='${args}'`); workerScript.log(caller, () => `Invalid arguments: scriptname='${scriptname} args='${args}'`);
console.error(`runScriptFromScript() failed due to invalid arguments`); console.error(`runScriptFromScript() failed due to invalid arguments`);
return 0; return 0;
} }
@ -658,14 +658,14 @@ export function runScriptFromScript(
// Check if the script is already running // Check if the script is already running
const runningScriptObj = server.getRunningScript(scriptname, args); const runningScriptObj = server.getRunningScript(scriptname, args);
if (runningScriptObj != null) { if (runningScriptObj != null) {
workerScript.log(caller, `'${scriptname}' is already running on '${server.hostname}'`); workerScript.log(caller, () => `'${scriptname}' is already running on '${server.hostname}'`);
return 0; return 0;
} }
// 'null/undefined' arguments are not allowed // 'null/undefined' arguments are not allowed
for (let i = 0; i < args.length; ++i) { for (let i = 0; i < args.length; ++i) {
if (args[i] == null) { if (args[i] == null) {
workerScript.log(caller, "Cannot execute a script with null/undefined as an argument"); workerScript.log(caller, () => "Cannot execute a script with null/undefined as an argument");
return 0; return 0;
} }
} }
@ -684,11 +684,12 @@ export function runScriptFromScript(
const ramAvailable = server.maxRam - server.ramUsed; const ramAvailable = server.maxRam - server.ramUsed;
if (server.hasAdminRights == false) { if (server.hasAdminRights == false) {
workerScript.log(caller, `You do not have root access on '${server.hostname}'`); workerScript.log(caller, () => `You do not have root access on '${server.hostname}'`);
return 0; return 0;
} else if (ramUsage > ramAvailable) { } else if (ramUsage > ramAvailable) {
workerScript.log( workerScript.log(
caller, caller,
() =>
`Cannot run script '${scriptname}' (t=${threads}) on '${server.hostname}' because there is not enough available RAM!`, `Cannot run script '${scriptname}' (t=${threads}) on '${server.hostname}' because there is not enough available RAM!`,
); );
return 0; return 0;
@ -696,7 +697,7 @@ export function runScriptFromScript(
// Able to run script // Able to run script
workerScript.log( workerScript.log(
caller, caller,
`'${scriptname}' on '${server.hostname}' with ${threads} threads and args: ${arrayToString(args)}.`, () => `'${scriptname}' on '${server.hostname}' with ${threads} threads and args: ${arrayToString(args)}.`,
); );
const runningScriptObj = new RunningScript(script, args); const runningScriptObj = new RunningScript(script, args);
runningScriptObj.threads = threads; runningScriptObj.threads = threads;
@ -706,6 +707,6 @@ export function runScriptFromScript(
break; break;
} }
workerScript.log(caller, `Could not find script '${scriptname}' on '${server.hostname}'`); workerScript.log(caller, () => `Could not find script '${scriptname}' on '${server.hostname}'`);
return 0; return 0;
} }

@ -28,6 +28,7 @@ import { dialogBoxCreate } from "./ui/React/DialogBox";
import { ProgramsSeen } from "./Programs/ui/ProgramsRoot"; import { ProgramsSeen } from "./Programs/ui/ProgramsRoot";
import { InvitationsSeen } from "./Faction/ui/FactionsRoot"; import { InvitationsSeen } from "./Faction/ui/FactionsRoot";
import { LogBoxClearEvents } from "./ui/React/LogBoxManager";
const BitNode8StartingMoney = 250e6; const BitNode8StartingMoney = 250e6;
@ -85,17 +86,17 @@ export function prestigeAugmentation(): void {
} }
} }
// Stop a Terminal action if there is onerror // Stop a Terminal action if there is one.
if (Terminal.action !== null) { if (Terminal.action !== null) {
Terminal.finishAction(Router, Player, true); Terminal.finishAction(Router, Player, true);
} }
Terminal.clear(); Terminal.clear();
LogBoxClearEvents.emit();
// Re-initialize things - This will update any changes // Re-initialize things - This will update any changes
initFactions(); // Factions must be initialized before augmentations initFactions(); // Factions must be initialized before augmentations
Player.factions = Player.factions.concat(maintainMembership); Player.factionInvitations = Player.factionInvitations.concat(maintainMembership);
Player.factions.map((f) => (Factions[f].isMember = true));
initAugmentations(); // Calls reapplyAllAugmentations() and resets Player multipliers initAugmentations(); // Calls reapplyAllAugmentations() and resets Player multipliers
Player.reapplyAllSourceFiles(); Player.reapplyAllSourceFiles();
initCompanies(); initCompanies();

@ -56,7 +56,7 @@ export class Script {
* Download the script as a file * Download the script as a file
*/ */
download(): void { download(): void {
const filename = this.filename + ".js"; const filename = this.filename;
const file = new Blob([this.code], { type: "text/plain" }); const file = new Blob([this.code], { type: "text/plain" });
const navigator = window.navigator as any; const navigator = window.navigator as any;
if (navigator.msSaveOrOpenBlob) { if (navigator.msSaveOrOpenBlob) {

@ -51,7 +51,7 @@ export function buyStock(
} }
if (stock == null || isNaN(shares)) { if (stock == null || isNaN(shares)) {
if (workerScript) { if (workerScript) {
workerScript.log("buyStock", `Invalid arguments: stock='${stock}' shares='${shares}'`); workerScript.log("stock.buy", () => `Invalid arguments: stock='${stock}' shares='${shares}'`);
} else if (opts.suppressDialog !== true) { } else if (opts.suppressDialog !== true) {
dialogBoxCreate("Failed to buy stock. This may be a bug, contact developer"); dialogBoxCreate("Failed to buy stock. This may be a bug, contact developer");
} }
@ -67,7 +67,8 @@ export function buyStock(
if (Player.money < totalPrice) { if (Player.money < totalPrice) {
if (workerScript) { if (workerScript) {
workerScript.log( workerScript.log(
"buyStock", "stock.buy",
() =>
`You do not have enough money to purchase this position. You need ${numeralWrapper.formatMoney(totalPrice)}.`, `You do not have enough money to purchase this position. You need ${numeralWrapper.formatMoney(totalPrice)}.`,
); );
} else if (opts.suppressDialog !== true) { } else if (opts.suppressDialog !== true) {
@ -85,7 +86,8 @@ export function buyStock(
if (shares + stock.playerShares + stock.playerShortShares > stock.maxShares) { if (shares + stock.playerShares + stock.playerShortShares > stock.maxShares) {
if (workerScript) { if (workerScript) {
workerScript.log( workerScript.log(
"buyStock", "stock.buy",
() =>
`Purchasing '${shares + stock.playerShares + stock.playerShortShares}' shares would exceed ${ `Purchasing '${shares + stock.playerShares + stock.playerShortShares}' shares would exceed ${
stock.symbol stock.symbol
}'s maximum (${stock.maxShares}) number of shares`, }'s maximum (${stock.maxShares}) number of shares`,
@ -116,7 +118,7 @@ export function buyStock(
`Bought ${numeralWrapper.formatShares(shares)} shares of ${stock.symbol} for ${numeralWrapper.formatMoney( `Bought ${numeralWrapper.formatShares(shares)} shares of ${stock.symbol} for ${numeralWrapper.formatMoney(
totalPrice, totalPrice,
)}. ` + `Paid ${numeralWrapper.formatMoney(CONSTANTS.StockMarketCommission)} in commission fees.`; )}. ` + `Paid ${numeralWrapper.formatMoney(CONSTANTS.StockMarketCommission)} in commission fees.`;
workerScript.log("buyStock", resultTxt); workerScript.log("stock.buy", () => resultTxt);
} else if (opts.suppressDialog !== true) { } else if (opts.suppressDialog !== true) {
dialogBoxCreate( dialogBoxCreate(
<> <>
@ -146,7 +148,7 @@ export function sellStock(
// Sanitize/Validate arguments // Sanitize/Validate arguments
if (stock == null || shares < 0 || isNaN(shares)) { if (stock == null || shares < 0 || isNaN(shares)) {
if (workerScript) { if (workerScript) {
workerScript.log("sellStock", `Invalid arguments: stock='${stock}' shares='${shares}'`); workerScript.log("stock.sell", () => `Invalid arguments: stock='${stock}' shares='${shares}'`);
} else if (opts.suppressDialog !== true) { } else if (opts.suppressDialog !== true) {
dialogBoxCreate( dialogBoxCreate(
"Failed to sell stock. This is probably due to an invalid quantity. Otherwise, this may be a bug, contact developer", "Failed to sell stock. This is probably due to an invalid quantity. Otherwise, this may be a bug, contact developer",
@ -192,7 +194,7 @@ export function sellStock(
const resultTxt = const resultTxt =
`Sold ${numeralWrapper.formatShares(shares)} shares of ${stock.symbol}. ` + `Sold ${numeralWrapper.formatShares(shares)} shares of ${stock.symbol}. ` +
`After commissions, you gained a total of ${numeralWrapper.formatMoney(gains)}.`; `After commissions, you gained a total of ${numeralWrapper.formatMoney(gains)}.`;
workerScript.log("sellStock", resultTxt); workerScript.log("stock.sell", () => resultTxt);
} else if (opts.suppressDialog !== true) { } else if (opts.suppressDialog !== true) {
dialogBoxCreate( dialogBoxCreate(
<> <>
@ -226,7 +228,7 @@ export function shortStock(
} }
if (stock == null || isNaN(shares)) { if (stock == null || isNaN(shares)) {
if (workerScript) { if (workerScript) {
workerScript.log("shortStock", `Invalid arguments: stock='${stock}' shares='${shares}'`); workerScript.log("stock.short", () => `Invalid arguments: stock='${stock}' shares='${shares}'`);
} else if (opts.suppressDialog !== true) { } else if (opts.suppressDialog !== true) {
dialogBoxCreate( dialogBoxCreate(
"Failed to initiate a short position in a stock. This is probably " + "Failed to initiate a short position in a stock. This is probably " +
@ -244,7 +246,8 @@ export function shortStock(
if (Player.money < totalPrice) { if (Player.money < totalPrice) {
if (workerScript) { if (workerScript) {
workerScript.log( workerScript.log(
"shortStock", "stock.short",
() =>
"You do not have enough " + "You do not have enough " +
"money to purchase this short position. You need " + "money to purchase this short position. You need " +
numeralWrapper.formatMoney(totalPrice), numeralWrapper.formatMoney(totalPrice),
@ -264,7 +267,8 @@ export function shortStock(
if (shares + stock.playerShares + stock.playerShortShares > stock.maxShares) { if (shares + stock.playerShares + stock.playerShortShares > stock.maxShares) {
if (workerScript) { if (workerScript) {
workerScript.log( workerScript.log(
"shortStock", "stock.short",
() =>
`This '${shares + stock.playerShares + stock.playerShortShares}' short shares would exceed ${ `This '${shares + stock.playerShares + stock.playerShortShares}' short shares would exceed ${
stock.symbol stock.symbol
}'s maximum (${stock.maxShares}) number of shares.`, }'s maximum (${stock.maxShares}) number of shares.`,
@ -296,7 +300,7 @@ export function shortStock(
CONSTANTS.StockMarketCommission, CONSTANTS.StockMarketCommission,
)} ` + )} ` +
`in commission fees.`; `in commission fees.`;
workerScript.log("shortStock", resultTxt); workerScript.log("stock.short", () => resultTxt);
} else if (!opts.suppressDialog) { } else if (!opts.suppressDialog) {
dialogBoxCreate( dialogBoxCreate(
<> <>
@ -325,7 +329,7 @@ export function sellShort(
): boolean { ): boolean {
if (stock == null || isNaN(shares) || shares < 0) { if (stock == null || isNaN(shares) || shares < 0) {
if (workerScript) { if (workerScript) {
workerScript.log("sellShort", `Invalid arguments: stock='${stock}' shares='${shares}'`); workerScript.log("stock.sellShort", () => `Invalid arguments: stock='${stock}' shares='${shares}'`);
} else if (!opts.suppressDialog) { } else if (!opts.suppressDialog) {
dialogBoxCreate( dialogBoxCreate(
"Failed to sell a short position in a stock. This is probably " + "Failed to sell a short position in a stock. This is probably " +
@ -348,8 +352,8 @@ export function sellShort(
if (totalGain == null || isNaN(totalGain) || origCost == null) { if (totalGain == null || isNaN(totalGain) || origCost == null) {
if (workerScript) { if (workerScript) {
workerScript.log( workerScript.log(
"sellShort", "stock.sellShort",
`Failed to sell short position in a stock. This is probably either due to invalid arguments, or a bug`, () => `Failed to sell short position in a stock. This is probably either due to invalid arguments, or a bug`,
); );
} else if (!opts.suppressDialog) { } else if (!opts.suppressDialog) {
dialogBoxCreate( dialogBoxCreate(
@ -383,7 +387,7 @@ export function sellShort(
const resultTxt = const resultTxt =
`Sold your short position of ${numeralWrapper.formatShares(shares)} shares of ${stock.symbol}. ` + `Sold your short position of ${numeralWrapper.formatShares(shares)} shares of ${stock.symbol}. ` +
`After commissions, you gained a total of ${numeralWrapper.formatMoney(totalGain)}`; `After commissions, you gained a total of ${numeralWrapper.formatMoney(totalGain)}`;
workerScript.log("sellShort", resultTxt); workerScript.log("stock.sellShort", () => resultTxt);
} else if (!opts.suppressDialog) { } else if (!opts.suppressDialog) {
dialogBoxCreate( dialogBoxCreate(
<> <>

@ -37,7 +37,7 @@ export function placeOrder(
): boolean { ): boolean {
if (!(stock instanceof Stock)) { if (!(stock instanceof Stock)) {
if (workerScript) { if (workerScript) {
workerScript.log("placeOrder", `Invalid stock: '${stock}'`); workerScript.log("stock.placeOrder", () => `Invalid stock: '${stock}'`);
} else { } else {
dialogBoxCreate(`ERROR: Invalid stock passed to placeOrder() function`); dialogBoxCreate(`ERROR: Invalid stock passed to placeOrder() function`);
} }
@ -45,7 +45,7 @@ export function placeOrder(
} }
if (typeof shares !== "number" || typeof price !== "number") { if (typeof shares !== "number" || typeof price !== "number") {
if (workerScript) { if (workerScript) {
workerScript.log("placeOrder", `Invalid arguments: shares='${shares}' price='${price}'`); workerScript.log("stock.placeOrder", () => `Invalid arguments: shares='${shares}' price='${price}'`);
} else { } else {
dialogBoxCreate("ERROR: Invalid numeric value provided for either 'shares' or 'price' argument"); dialogBoxCreate("ERROR: Invalid numeric value provided for either 'shares' or 'price' argument");
} }

@ -19,43 +19,29 @@ export function download(
return; return;
} }
const fn = args[0] + ""; const fn = args[0] + "";
if (fn === "*" || fn === "*.script" || fn === "*.txt") { // If the parameter starts with *, download all files that match the wildcard pattern
// Download all scripts as a zip if (fn.startsWith("*")) {
const matchEnding = fn.length == 1 || fn === "*.*" ? null : fn.slice(1); // Treat *.* the same as *
const zip = new JSZip(); const zip = new JSZip();
if (fn === "*" || fn === "*.script") { // Helper function to zip any file contents whose name matches the pattern
for (let i = 0; i < server.scripts.length; ++i) { let zipFiles = (fileNames: string[], fileContents: string[]) => {
const file = new Blob([server.scripts[i].code], { for (let i = 0; i < fileContents.length; ++i) {
type: "text/plain", let name = fileNames[i];
}); if (name.startsWith("/")) name = name.slice(1);
let name = server.scripts[i].filename; if (!matchEnding || name.endsWith(matchEnding))
if (name.startsWith("/")) { zip.file(name, new Blob([fileContents[i]], { type: "text/plain" }));
name = name.slice(1);
} }
zip.file(name + ".js", file); };
} // In the case of script files, we pull from the server.scripts array
} if (!matchEnding || isScriptFilename(matchEnding))
if (fn === "*" || fn === "*.txt") { zipFiles(server.scripts.map(s => s.filename), server.scripts.map(s => s.code));
for (let i = 0; i < server.textFiles.length; ++i) { // In the case of text files, we pull from the server.scripts array
const file = new Blob([server.textFiles[i].text], { if (!matchEnding || matchEnding.endsWith(".txt"))
type: "text/plain", zipFiles(server.textFiles.map(s => s.fn), server.textFiles.map(s => s.text));
}); // Return an error if no files matched, rather than an empty zip folder
zip.file(server.textFiles[i].fn, file); if (Object.keys(zip.files).length == 0)
} return terminal.error(`No files match the pattern ${fn}`);
} const zipFn = `bitburner${isScriptFilename(fn) ? "Scripts" : fn === "*.txt" ? "Texts" : "Files"}.zip`;
let zipFn = "";
switch (fn) {
case "*.script":
zipFn = "bitburnerScripts.zip";
break;
case "*.txt":
zipFn = "bitburnerTexts.zip";
break;
default:
zipFn = "bitburnerFiles.zip";
break;
}
zip.generateAsync({ type: "blob" }).then((content: any) => FileSaver.saveAs(content, zipFn)); zip.generateAsync({ type: "blob" }).then((content: any) => FileSaver.saveAs(content, zipFn));
return; return;
} else if (isScriptFilename(fn)) { } else if (isScriptFilename(fn)) {

@ -47,9 +47,7 @@ export async function main(ns) {
router.toScriptEditor(filepath, txt.text); router.toScriptEditor(filepath, txt.text);
} }
} else { } else {
terminal.error( terminal.error("Invalid file. Only scripts (.script, .ns, .js), or text files (.txt) can be edited with nano");
"Invalid file. Only scripts (.script, .ns, .js), text files (.txt), or .fconf can be edited with nano",
);
return; return;
} }
} catch (e) { } catch (e) {

@ -275,7 +275,6 @@ export async function determineAllPossibilitiesForTabCompletion(
if (isCommand("nano")) { if (isCommand("nano")) {
addAllScripts(); addAllScripts();
addAllTextFiles(); addAllTextFiles();
allPos.push(".fconf");
addAllDirectories(); addAllDirectories();
return allPos; return allPos;

@ -283,7 +283,7 @@ export function TerminalInput({ terminal, router, player }: IProps): React.React
} }
} }
// Extra Bash Emulation Hotkeys, must be enabled through .fconf // Extra Bash Emulation Hotkeys, must be enabled through options
if (Settings.EnableBashHotkeys) { if (Settings.EnableBashHotkeys) {
if (event.keyCode === KEY.A && event.ctrlKey) { if (event.keyCode === KEY.A && event.ctrlKey) {
event.preventDefault(); event.preventDefault();

@ -13,12 +13,6 @@
<meta name="msapplication-TileColor" content="#000000" /> <meta name="msapplication-TileColor" content="#000000" />
<meta name="msapplication-config" content="dist/browserconfig.xml" /> <meta name="msapplication-config" content="dist/browserconfig.xml" />
<meta name="theme-color" content="#ffffff" /> <meta name="theme-color" content="#ffffff" />
<script>
// Give a warning if you go back in browser history.
window.onbeforeunload = function () {
return "Your work will be lost.";
};
</script>
<!-- Google Analytics --> <!-- Google Analytics -->
<script> <script>
(function (i, s, o, g, r, a, m) { (function (i, s, o, g, r, a, m) {

@ -24,3 +24,10 @@ function rerender(): void {
(function () { (function () {
ThemeEvents.subscribe(rerender); ThemeEvents.subscribe(rerender);
})(); })();
(function () {
if (process.env.NODE_ENV === "development") return;
window.onbeforeunload = function () {
return "Your work will be lost.";
};
})();

@ -72,7 +72,11 @@ export function ServerAccordions(props: IProps): React.ReactElement {
if (data !== undefined) data.workerScripts.push(ws); if (data !== undefined) data.workerScripts.push(ws);
} }
const filtered = Object.values(serverToScriptMap).filter((data) => data && data.server.hostname.includes(filter)); const filtered = Object.values(serverToScriptMap).filter(
(data) =>
data &&
(data.server.hostname.includes(filter) || data.server.runningScripts.find((s) => s.filename.includes(filter))),
);
function rerender(): void { function rerender(): void {
setRerender((old) => !old); setRerender((old) => !old);

@ -40,6 +40,7 @@ export function CodingContractModal(): React.ReactElement {
if (event.keyCode === KEY.ENTER && value !== "") { if (event.keyCode === KEY.ENTER && value !== "") {
event.preventDefault(); event.preventDefault();
props.onAttempt(answer); props.onAttempt(answer);
close();
} }
} }

@ -19,6 +19,7 @@ import { Theme } from "@mui/material";
let layerCounter = 0; let layerCounter = 0;
export const LogBoxEvents = new EventEmitter<[RunningScript]>(); export const LogBoxEvents = new EventEmitter<[RunningScript]>();
export const LogBoxClearEvents = new EventEmitter<[]>();
interface Log { interface Log {
id: string; id: string;
@ -46,6 +47,13 @@ export function LogBoxManager(): React.ReactElement {
[], [],
); );
useEffect(() =>
LogBoxClearEvents.subscribe(() => {
logs = [];
rerender();
}),
);
function close(id: string): void { function close(id: string): void {
logs = logs.filter((l) => l.id !== id); logs = logs.filter((l) => l.id !== id);
rerender(); rerender();
@ -134,16 +142,16 @@ function LogWindow(props: IProps): React.ReactElement {
} }
function lineClass(s: string): string { function lineClass(s: string): string {
if (s.match(/\[[^\]]+\] ERROR/) || s.match(/\[[^\]]+\] FAIL/)) { if (s.match(/(^\[[^\]]+\] )?ERROR/) || s.match(/(^\[[^\]]+\] )?FAIL/)) {
return classes.error; return classes.error;
} }
if (s.match(/\[[^\]]+\] SUCCESS/)) { if (s.match(/(^\[[^\]]+\] )?SUCCESS/)) {
return classes.success; return classes.success;
} }
if (s.match(/\[[^\]]+\] WARN/)) { if (s.match(/(^\[[^\]]+\] )?WARN/)) {
return classes.warning; return classes.warning;
} }
if (s.match(/\[[^\]]+\] INFO/)) { if (s.match(/(^\[[^\]]+\] )?INFO/)) {
return classes.info; return classes.info;
} }
return classes.primary; return classes.primary;

@ -112,7 +112,6 @@ export function ThemeEditorModal(props: IProps): React.ReactElement {
<TextField value={"Text field"} /> <TextField value={"Text field"} />
</Paper> </Paper>
<br /> <br />
<Typography>Warning: Editing the theme is very slow.</Typography>
<ColorEditor <ColorEditor
name="primarylight" name="primarylight"
onColorChange={onColorChange} onColorChange={onColorChange}