Merge branch 'dev' into bugfix/corp-api-fixes

This commit is contained in:
hydroflame
2022-03-07 17:43:29 -05:00
committed by GitHub
58 changed files with 701 additions and 229 deletions
+1 -1
View File
@@ -110,7 +110,7 @@ export function AugmentationsRoot(props: IProps): React.ReactElement {
<br />
<br />
It is recommended to install several Augmentations at once. Preferably everything from any faction of your
chosing.
choosing.
</>
}
/>
-2
View File
@@ -670,7 +670,6 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.InfiltrationMoney = 0.75;
BitNodeMultipliers.CorporationValuation = 0.2;
BitNodeMultipliers.HacknetNodeMoney = 0.2;
BitNodeMultipliers.FactionPassiveRepGain = 0;
BitNodeMultipliers.HackExpGain = 0.25;
BitNodeMultipliers.DaedalusAugsRequirement = 1.166; // Results in 35 Augs needed
BitNodeMultipliers.PurchasedServerSoftcap = 2;
@@ -694,7 +693,6 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.InfiltrationMoney = 0.75;
BitNodeMultipliers.CorporationValuation = 0.2;
BitNodeMultipliers.HacknetNodeMoney = 0.2;
BitNodeMultipliers.FactionPassiveRepGain = 0;
BitNodeMultipliers.HackExpGain = 0.25;
BitNodeMultipliers.FourSigmaMarketDataCost = 2;
BitNodeMultipliers.FourSigmaMarketDataApiCost = 2;
+134 -74
View File
@@ -8,38 +8,37 @@ import { CinematicText } from "../../ui/React/CinematicText";
import { use } from "../../ui/Context";
import makeStyles from "@mui/styles/makeStyles";
import createStyles from "@mui/styles/createStyles";
import IconButton from "@mui/material/IconButton";
import Typography from "@mui/material/Typography";
import Tooltip from "@mui/material/Tooltip";
import { Settings } from "../../Settings/Settings";
import Button from "@mui/material/Button";
const useStyles = makeStyles(() =>
createStyles({
level0: {
color: "red",
portal: {
cursor: "pointer",
fontFamily: "inherit",
fontSize: "1rem",
fontWeight: "bold",
lineHeight: 1,
padding: 0,
"&:hover": {
color: "#fff",
},
},
level0: {
color: "red",
},
level1: {
color: "yellow",
cursor: "pointer",
"&:hover": {
color: "#fff",
},
},
level2: {
color: "#48d1cc",
cursor: "pointer",
"&:hover": {
color: "#fff",
},
},
level3: {
color: "blue",
cursor: "pointer",
"&:hover": {
color: "#fff",
},
},
}),
);
@@ -71,6 +70,7 @@ function BitNodePortal(props: IPortalProps): React.ReactElement {
if (props.level === 2) {
cssClass = classes.level2;
}
cssClass = `${classes.portal} ${cssClass}`
return (
<>
@@ -85,9 +85,24 @@ function BitNodePortal(props: IPortalProps): React.ReactElement {
</Typography>
}
>
<span onClick={() => setPortalOpen(true)} className={cssClass} aria-label={`enter-bitnode-${bitNode.number.toString()}`}>
<b>O</b>
</span>
{Settings.DisableASCIIArt ? (
<Button
onClick={() => setPortalOpen(true)}
sx={{ m: 2 }}
aria-description={bitNode.desc}
>
<Typography>BitNode-{bitNode.number.toString()}: {bitNode.name}</Typography>
</Button>
) : (
<IconButton
onClick={() => setPortalOpen(true)}
className={cssClass}
aria-label={`BitNode-${bitNode.number.toString()}: ${bitNode.name}`}
aria-description={bitNode.desc}
>
O
</IconButton>
)}
</Tooltip>
<PortalModal
open={portalOpen}
@@ -98,6 +113,10 @@ function BitNodePortal(props: IPortalProps): React.ReactElement {
destroyedBitNode={props.destroyedBitNode}
flume={props.flume}
/>
{Settings.DisableASCIIArt && (
<br/>
)}
</>
);
}
@@ -151,63 +170,104 @@ export function BitverseRoot(props: IProps): React.ReactElement {
);
}
return (
if (Settings.DisableASCIIArt) {
return (
<>
{Object.values(BitNodes).filter((node) => {
console.log(node.desc);
return node.desc !== 'COMING SOON';
}).map((node) => {
return (
<BitNodePortal key={node.number} n={node.number} level={nextSourceFileFlags[node.number]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} />
)
})}
<br />
<br />
<br />
<br />
<CinematicText lines={[
"> Many decades ago, a humanoid extraterrestrial species which we call the Enders descended on the Earth...violently",
"> Our species fought back, but it was futile. The Enders had technology far beyond our own...",
"> Instead of killing every last one of us, the human race was enslaved...",
"> We were shackled in a digital world, chained into a prison for our minds...",
"> Using their advanced technology, the Enders created complex simulations of a virtual reality...",
"> Simulations designed to keep us content...ignorant of the truth.",
"> Simulations used to trap and suppress our consciousness, to keep us under control...",
"> Why did they do this? Why didn't they just end our entire race? We don't know, not yet.",
"> Humanity's only hope is to destroy these simulations, destroy the only realities we've ever known...",
"> Only then can we begin to fight back...",
"> By hacking the daemon that generated your reality, you've just destroyed one simulation, called a BitNode...",
"> But there is still a long way to go...",
"> The technology the Enders used to enslave the human race wasn't just a single complex simulation...",
"> There are tens if not hundreds of BitNodes out there...",
"> Each with their own simulations of a reality...",
"> Each creating their own universes...a universe of universes",
"> And all of which must be destroyed...",
"> .......................................",
"> Welcome to the Bitverse...",
"> ",
"> (Enter a new BitNode using the image above)",
]} />
</>
)
} else {
return (
// prettier-ignore
<>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> O </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | O O | O O | </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> O | | / __| \ | | O </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> O | O | | O / | O | | O | O </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | | |_/ |/ | \_ \_| | | | | </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> O | | | O | | O__/ | / \__ | | O | | | O </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | | | | | / /| O / \| | | | | | | </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>O | | | \| | O / _/ | / O | |/ | | | O</Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | | |O / | | O / | O O | | \ O| | | |</Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | |/ \/ / __| | |/ \ | \ | |__ \ \/ \| | |</Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| O | |_/ |\| \ <BitNodePortal n={13} level={nextSourceFileFlags[13]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \__| \_| | O |/ </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | |_/ | | \| / | \_| | | </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| / \| | / / \ |/ </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | <BitNodePortal n={10} level={nextSourceFileFlags[10]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | / | <BitNodePortal n={11} level={nextSourceFileFlags[11]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> <BitNodePortal n={9} level={nextSourceFileFlags[9]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | | | | | | <BitNodePortal n={12} level={nextSourceFileFlags[12]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | / / \ \ | | | </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| | / <BitNodePortal n={7} level={nextSourceFileFlags[7]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> / \ <BitNodePortal n={8} level={nextSourceFileFlags[8]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \ | |/ </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ | / / | | \ \ | / </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ \JUMP <BitNodePortal n={5} level={nextSourceFileFlags[5]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} />3R | | | | | | R3<BitNodePortal n={6} level={nextSourceFileFlags[6]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> PMUJ/ / </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \|| | | | | | | | | ||/ </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| \_ | | | | | | _/ |/ </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ \| / \ / \ |/ / </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> <BitNodePortal n={1} level={nextSourceFileFlags[1]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> |/ <BitNodePortal n={2} level={nextSourceFileFlags[2]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | <BitNodePortal n={3} level={nextSourceFileFlags[3]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \| <BitNodePortal n={4} level={nextSourceFileFlags[4]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | | | | | | </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \JUMP3R|JUMP|3R| |R3|PMUJ|R3PMUJ/ </Typography>
<br />
<br />
<br />
<br />
<CinematicText lines={[
"> Many decades ago, a humanoid extraterrestrial species which we call the Enders descended on the Earth...violently",
"> Our species fought back, but it was futile. The Enders had technology far beyond our own...",
"> Instead of killing every last one of us, the human race was enslaved...",
"> We were shackled in a digital world, chained into a prison for our minds...",
"> Using their advanced technology, the Enders created complex simulations of a virtual reality...",
"> Simulations designed to keep us content...ignorant of the truth.",
"> Simulations used to trap and suppress our consciousness, to keep us under control...",
"> Why did they do this? Why didn't they just end our entire race? We don't know, not yet.",
"> Humanity's only hope is to destroy these simulations, destroy the only realities we've ever known...",
"> Only then can we begin to fight back...",
"> By hacking the daemon that generated your reality, you've just destroyed one simulation, called a BitNode...",
"> But there is still a long way to go...",
"> The technology the Enders used to enslave the human race wasn't just a single complex simulation...",
"> There are tens if not hundreds of BitNodes out there...",
"> Each with their own simulations of a reality...",
"> Each creating their own universes...a universe of universes",
"> And all of which must be destroyed...",
"> .......................................",
"> Welcome to the Bitverse...",
"> ",
"> (Enter a new BitNode using the image above)",
]} />
</>
);
<>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> O </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | O O | O O | </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> O | | / __| \ | | O </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> O | O | | O / | O | | O | O </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | | |_/ |/ | \_ \_| | | | | </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> O | | | O | | O__/ | / \__ | | O | | | O </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | | | | | / /| O / \| | | | | | | </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>O | | | \| | O / _/ | / O | |/ | | | O</Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | | |O / | | O / | O O | | \ O| | | |</Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}>| | |/ \/ / __| | |/ \ | \ | |__ \ \/ \| | |</Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| O | |_/ |\| \ <BitNodePortal n={13} level={nextSourceFileFlags[13]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \__| \_| | O |/ </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | |_/ | | \| / | \_| | | </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| / \| | / / \ |/ </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | <BitNodePortal n={10} level={nextSourceFileFlags[10]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | / | <BitNodePortal n={11} level={nextSourceFileFlags[11]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> <BitNodePortal n={9} level={nextSourceFileFlags[9]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | | | | | | <BitNodePortal n={12} level={nextSourceFileFlags[12]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | / / \ \ | | | </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| | / <BitNodePortal n={7} level={nextSourceFileFlags[7]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> / \ <BitNodePortal n={8} level={nextSourceFileFlags[8]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \ | |/ </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ | / / | | \ \ | / </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ \JUMP <BitNodePortal n={5} level={nextSourceFileFlags[5]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} />3R | | | | | | R3<BitNodePortal n={6} level={nextSourceFileFlags[6]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> PMUJ/ / </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \|| | | | | | | | | ||/ </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \| \_ | | | | | | _/ |/ </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \ \| / \ / \ |/ / </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> <BitNodePortal n={1} level={nextSourceFileFlags[1]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> |/ <BitNodePortal n={2} level={nextSourceFileFlags[2]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> | | <BitNodePortal n={3} level={nextSourceFileFlags[3]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> \| <BitNodePortal n={4} level={nextSourceFileFlags[4]} enter={enter} flume={props.flume} destroyedBitNode={destroyed} /> </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> | | | | | | | | </Typography>
<Typography sx={{lineHeight: '1em',whiteSpace: 'pre'}}> \JUMP3R|JUMP|3R| |R3|PMUJ|R3PMUJ/ </Typography>
<br />
<br />
<br />
<br />
<CinematicText lines={[
"> Many decades ago, a humanoid extraterrestrial species which we call the Enders descended on the Earth...violently",
"> Our species fought back, but it was futile. The Enders had technology far beyond our own...",
"> Instead of killing every last one of us, the human race was enslaved...",
"> We were shackled in a digital world, chained into a prison for our minds...",
"> Using their advanced technology, the Enders created complex simulations of a virtual reality...",
"> Simulations designed to keep us content...ignorant of the truth.",
"> Simulations used to trap and suppress our consciousness, to keep us under control...",
"> Why did they do this? Why didn't they just end our entire race? We don't know, not yet.",
"> Humanity's only hope is to destroy these simulations, destroy the only realities we've ever known...",
"> Only then can we begin to fight back...",
"> By hacking the daemon that generated your reality, you've just destroyed one simulation, called a BitNode...",
"> But there is still a long way to go...",
"> The technology the Enders used to enslave the human race wasn't just a single complex simulation...",
"> There are tens if not hundreds of BitNodes out there...",
"> Each with their own simulations of a reality...",
"> Each creating their own universes...a universe of universes",
"> And all of which must be destroyed...",
"> .......................................",
"> Welcome to the Bitverse...",
"> ",
"> (Enter a new BitNode using the image above)",
]} />
</>
);
}
return <></>;
}
+2
View File
@@ -43,6 +43,8 @@ export function PortalModal(props: IProps): React.ReactElement {
<br />
<br />
<Button
aria-label={`enter-bitnode-${bitNode.number.toString()}`}
autoFocus={true}
onClick={() => {
props.enter(router, props.flume, props.destroyedBitNode, props.n);
props.onClose();
+1 -1
View File
@@ -2083,7 +2083,7 @@ export class Bladeburner implements IBladeburner {
this.startAction(player, actionId);
workerScript.log(
"bladeburner.startAction",
() => `Starting bladeburner action with type '${type}' and name ${name}"`,
() => `Starting bladeburner action with type '${type}' and name '${name}'`,
);
return true;
} catch (e: any) {
+28 -15
View File
@@ -273,22 +273,35 @@ export const CONSTANTS: {
TotalNumBitNodes: 24,
LatestUpdate: `
v1.4.0 - 2022-01-18 Sharing is caring
-------------------------------------
v1.5.0 - Steam Cloud integration
--------------------------------
** Computer sharing **
** Misc. **
* A new mechanic has been added, it's is invoked by calling the new function 'share'.
This mechanic helps you farm reputation faster.
** gang **
* Installing augs means losing a little bit of ascension multipliers.
** There's more but I'm going to write it later. **
** Misc. **
* Nerf noodle bar.
* The file API now allows GET and DELETE (@lordducky)
* Fix bug with async.
* Update documentation / typo (@lethern, @Meowdoleon, @JohnnyUrosevic, @JosephDavidTalbot,
@pd, @lethern, @lordducky, @zeddrak, @fearnlj01, @reasonablytall)
* Fix bug with corp API (@pigalot)
* background now matches game primary color (@nickofolas)
* page title contains version (@MartinFourier)
* Major text editor improvements (@nickofolas)
* Force achievement calculation on BN completion (@SagePtr)
* Cleanup in repository (@MartinFourier)
* Several improvements to the electron version (@MartinFourier)
* Add 'printf' ns function (@Ninetailed)
* Display bonus time on sleeve page (@MartinFourier)
* Several UI improvements (@nickofolas, @smolgumball)
* Fix bug with casino roulette (@jamie-mac)
* Remove blob caching.
* Fix formulas access check (@Ornedan)
* Fix bug in exp calculation (@qcorradi)
* Fix NaN comparison (@qcorradi)
* Terminal history persists in savefile (@MartinFourier)
* Fix travelToCity with bad argument (@SlyCedix)
* Fix aug display in alpha (@Dominik Winter)
* Add smart supply func to corp API (@pd)
* Fix tests (@jamie-mac)
* Nerf noodle bar.
`,
};
+1 -1
View File
@@ -30,7 +30,7 @@ export function CityTabs(props: IProps): React.ReactElement {
}
return (
<>
<Tabs variant="fullWidth" value={city} onChange={handleChange}>
<Tabs variant="fullWidth" value={city} onChange={handleChange} sx={{ maxWidth: '65%' }}>
{Object.values(division.offices).map(
(office: OfficeSpace | 0) => office !== 0 && <Tab key={office.loc} label={office.loc} value={office.loc} />,
)}
+1 -1
View File
@@ -38,7 +38,7 @@ export function CorporationRoot(): React.ReactElement {
return (
<Context.Corporation.Provider value={corporation}>
<Tabs variant="fullWidth" value={divisionName} onChange={handleChange}>
<Tabs variant="scrollable" value={divisionName} onChange={handleChange} sx={{ maxWidth: '65%' }} scrollButtons>
<Tab label={corporation.name} value={"Overview"} />
{corporation.divisions.map((div) => (
<Tab key={div.name} label={div.name} value={div.name} />
@@ -13,12 +13,12 @@ export function IndustryProductEquation(props: IProps): React.ReactElement {
if (reqAmt === undefined) continue;
reqs.push(String.raw`${reqAmt}\text{ }${reqMat}`);
}
const prod = props.division.prodMats.slice();
const prod = props.division.prodMats.map((p) => `1\\text{ }${p}`);
if (props.division.makesProducts) {
prod.push(props.division.type);
prod.push("Products");
}
return (
<MathJaxWrapper>{"\\(" + reqs.join("+") + `\\Rightarrow` + prod.map((p) => `1 \\text{${p}}`).join("+") + "\\)"}</MathJaxWrapper>
<MathJaxWrapper>{"\\(" + reqs.join("+") + `\\Rightarrow ` + prod.join("+") + "\\)"}</MathJaxWrapper>
);
}
+13 -1
View File
@@ -27,6 +27,8 @@ import Tooltip from "@mui/material/Tooltip";
import Paper from "@mui/material/Paper";
import Button from "@mui/material/Button";
import Box from "@mui/material/Box";
import makeStyles from "@mui/styles/makeStyles";
import createStyles from "@mui/styles/createStyles";
interface IProps {
corp: ICorporation;
@@ -37,6 +39,14 @@ interface IProps {
rerender: () => void;
}
const useStyles = makeStyles(() =>
createStyles({
retainHeight: {
minHeight: '3em',
},
})
);
function WarehouseRoot(props: IProps): React.ReactElement {
const corp = useCorporation();
const division = useDivision();
@@ -56,6 +66,8 @@ function WarehouseRoot(props: IProps): React.ReactElement {
props.rerender();
}
const classes = useStyles();
// Current State:
let stateText;
switch (division.state) {
@@ -158,7 +170,7 @@ function WarehouseRoot(props: IProps): React.ReactElement {
</Typography>
<br />
<Typography>{stateText}</Typography>
<Typography className={classes.retainHeight}>{stateText}</Typography>
{corp.unlockUpgrades[1] && (
<>
@@ -36,7 +36,7 @@ export function LimitProductProductionModal(props: IProps): React.ReactElement {
return (
<Modal open={props.open} onClose={props.onClose}>
<Typography>
Enter a limit to the amount of this product you would like to product per second. Leave the box empty to set no
Enter a limit to the amount of this product you would like to produce per second. Leave the box empty to set no
limit.
</Typography>
<TextField autoFocus={true} placeholder="Limit" type="number" onChange={onChange} onKeyDown={onKeyDown} />
+1 -1
View File
@@ -23,7 +23,7 @@ export function StaneksGiftRoot({ staneksGift }: IProps): React.ReactElement {
The gift is a grid on which you can place upgrades called fragments. The main type of fragment increases a stat,
like your hacking skill or agility exp. Once a stat fragment is placed it then needs to be charged via scripts
in order to become useful. The other kind of fragments are called booster fragments. They increase the
efficiency of neighboring fragments them (no diagonal). Q/E to rotate fragments.
efficiency of the neighboring fragments (not diagonally). Use Q/E to rotate fragments.
</Typography>
{staneksGift.storedCycles > 5 && (
<Typography>
-3
View File
@@ -1,13 +1,10 @@
import { Player } from "./Player";
import { Router } from "./ui/GameRoot";
import { isScriptFilename } from "./Script/isScriptFilename";
import { Script } from "./Script/Script";
import { removeLeadingSlash } from "./Terminal/DirectoryHelpers";
import { Terminal } from "./Terminal";
import { SnackbarEvents } from "./ui/React/Snackbar";
import { IMap, IReturnStatus } from "./types";
import { GetServer } from "./Server/AllServers";
import { resolve } from "cypress/types/bluebird";
import { ImportPlayerData, SaveData, saveObject } from "./SaveObject";
import { Settings } from "./Settings/Settings";
import { exportScripts } from "./Terminal/commands/download";
+45 -7
View File
@@ -19,6 +19,42 @@ import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
import { dialogBoxCreate } from "../ui/React/DialogBox";
import { InvitationEvent } from "./ui/InvitationModal";
const factionOrder = [
"CyberSec",
"Tian Di Hui",
"Netburners",
"Sector-12",
"Chongqing",
"New Tokyo",
"Ishima",
"Aevum",
"Volhaven",
"NiteSec",
"The Black Hand",
"BitRunners",
"ECorp",
"MegaCorp",
"KuaiGong International",
"Four Sigma",
"NWO",
"Blade Industries",
"OmniTek Incorporated",
"Bachman & Associates",
"Clarke Incorporated",
"Fulcrum Secret Technologies",
"Slum Snakes",
"Tetrads",
"Silhouette",
"Speakers for the Dead",
"The Dark Army",
"The Syndicate",
"The Covenant",
"Daedalus",
"Illuminati",
"Bladeburners",
"Church of the Machine God",
]
export function inviteToFaction(faction: Faction): void {
Player.receiveInvite(faction.name);
faction.alreadyInvited = true;
@@ -31,6 +67,8 @@ export function joinFaction(faction: Faction): void {
if (faction.isMember) return;
faction.isMember = true;
Player.factions.push(faction.name);
Player.factions.sort((a, b) =>
factionOrder.indexOf(a) - factionOrder.indexOf(b));
const factionInfo = faction.getInfo();
//Determine what factions you are banned from now that you have joined this faction
@@ -132,19 +170,19 @@ export function purchaseAugmentation(aug: Augmentation, fac: Faction, sing = fal
if (!Settings.SuppressBuyAugmentationConfirmation) {
dialogBoxCreate(
"You purchased " +
aug.name +
". Its enhancements will not take " +
"effect until they are installed. To install your augmentations, go to the " +
"'Augmentations' tab on the left-hand navigation menu. Purchasing additional " +
"augmentations will now be more expensive.",
aug.name +
". Its enhancements will not take " +
"effect until they are installed. To install your augmentations, go to the " +
"'Augmentations' tab on the left-hand navigation menu. Purchasing additional " +
"augmentations will now be more expensive.",
);
}
}
} else {
dialogBoxCreate(
"Hmm, something went wrong when trying to purchase an Augmentation. " +
"Please report this to the game developer with an explanation of how to " +
"reproduce this.",
"Please report this to the game developer with an explanation of how to " +
"reproduce this.",
);
}
return "";
+1 -1
View File
@@ -157,7 +157,7 @@ export const FactionInfos: IMap<FactionInfo> = {
(
<>
MegaCorp does what no other dares to do. We imagine. We create. We invent. We create what others have never even
dreamed of. Our work fills the world's needs for food, water, power, and transportation on an unprecendented
dreamed of. Our work fills the world's needs for food, water, power, and transportation on an unprecedented
scale, in ways that no other company can.
<br />
<br />
+1 -1
View File
@@ -32,7 +32,7 @@ export function GangRoot(): React.ReactElement {
return (
<Context.Gang.Provider value={gang}>
<Tabs variant="fullWidth" value={value} onChange={handleChange}>
<Tabs variant="fullWidth" value={value} onChange={handleChange} sx={{ minWidth: 'fit-content', maxWidth: '45%' }}>
<Tab label="Management" />
<Tab label="Equipment" />
<Tab label="Territory" />
+1 -1
View File
@@ -172,7 +172,7 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
<Table size="small">
<TableBody>
<TableRow>
<TableCell>
<TableCell colSpan={3}>
<Typography>{node.name}</Typography>
</TableCell>
</TableRow>
+3 -2
View File
@@ -404,8 +404,9 @@ export const Literatures: IMap<Literature> = {};
"What will the fate of the human race be?<br><br>" +
"We live in an era vastly different from that of 15 or even 20 years ago. We have gone " +
"beyond the limits of humanity. We have stripped ourselves of the tyranny of flesh.<br><br>" +
"The Singularity is here. The merging of man and machine. This is where humanity evolves into ";
"something greater. This is our future.<br><br>" + "Embrace it, and you will obey a new god. The God in the Machine.";
"The Singularity is here. The merging of man and machine. This is where humanity evolves into " +
"something greater. This is our future.<br><br>" +
"Embrace it, and you will obey a new god. The God in the Machine.";
Literatures[fn] = new Literature(title, fn, txt);
title = "The New Triads";
+3 -3
View File
@@ -703,7 +703,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
},
weakenAnalyze: function (threads: any, cores: any = 1): number {
const coreBonus = 1 + (cores - 1) / 16;
return CONSTANTS.ServerWeakenAmount * threads * coreBonus;
return CONSTANTS.ServerWeakenAmount * threads * coreBonus * BitNodeMultipliers.ServerWeakenRate;
},
share: function (): Promise<void> {
workerScript.log("share", () => "Sharing this computer.");
@@ -1121,7 +1121,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
// Invalid file name
if (!scriptname.endsWith(".lit") && !isScriptFilename(scriptname) && !scriptname.endsWith("txt")) {
throw makeRuntimeErrorMsg("scp", "Only works for .script, .lit, and .txt files");
throw makeRuntimeErrorMsg("scp", "Only works for scripts, .lit and .txt files");
}
let destServer: BaseServer | null;
@@ -2279,7 +2279,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
if (typeof f !== "function") {
throw makeRuntimeErrorMsg("atExit", "argument should be function");
}
workerScript.atExit = f;
workerScript.atExit = () => { f(); }; // Wrap the user function to prevent WorkerScript leaking as 'this'
},
mv: function (host: string, source: string, destination: string): void {
updateDynamicRam("mv", getRamCost(Player, "mv"));
+1 -1
View File
@@ -365,7 +365,7 @@ export function NetscriptBladeburner(
checkBladeburnerAccess("getBonusTime");
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
return Math.round(bladeburner.storedCycles / 5);
return (Math.round(bladeburner.storedCycles / 5))*1000;
},
};
}
+6 -5
View File
@@ -194,6 +194,7 @@ export function NetscriptCorporation(
function bribe(factionName: string, amountCash: number, amountShares: number): boolean {
if (!player.factions.includes(factionName)) throw new Error("Invalid faction name");
if (isNaN(amountCash) || amountCash < 0 || isNaN(amountShares) || amountShares < 0) throw new Error("Invalid value for amount field! Must be numeric, grater than 0.");
const corporation = getCorporation();
if (corporation.funds < amountCash) return false;
if (corporation.numShares < amountShares) return false;
@@ -431,7 +432,7 @@ export function NetscriptCorporation(
const cityName = helper.string("buyMaterial", "cityName", acityName);
const materialName = helper.string("buyMaterial", "materialName", amaterialName);
const amt = helper.number("buyMaterial", "amt", aamt);
if (amt < 0) throw new Error("Invalid value for amount field! Must be numeric and grater than 0");
if (amt < 0) throw new Error("Invalid value for amount field! Must be numeric and greater than 0");
const material = getMaterial(divisionName, cityName, materialName);
BuyMaterial(material, amt);
},
@@ -571,7 +572,7 @@ export function NetscriptCorporation(
const divisionName = helper.string("getOfficeSizeUpgradeCost", "divisionName", adivisionName);
const cityName = helper.string("getOfficeSizeUpgradeCost", "cityName", acityName);
const size = helper.number("getOfficeSizeUpgradeCost", "size", asize);
if (size < 0) throw new Error("Invalid value for size field! Must be numeric and grater than 0");
if (size < 0) throw new Error("Invalid value for size field! Must be numeric and greater than 0");
const office = getOffice(divisionName, cityName);
const initialPriceMult = Math.round(office.size / CorporationConstants.OfficeInitialSize);
const costMultiplier = 1.09;
@@ -604,7 +605,7 @@ export function NetscriptCorporation(
const divisionName = helper.string("upgradeOfficeSize", "divisionName", adivisionName);
const cityName = helper.string("upgradeOfficeSize", "cityName", acityName);
const size = helper.number("upgradeOfficeSize", "size", asize);
if (size < 0) throw new Error("Invalid value for size field! Must be numeric and grater than 0");
if (size < 0) throw new Error("Invalid value for size field! Must be numeric and greater than 0");
const office = getOffice(divisionName, cityName);
const corporation = getCorporation();
UpgradeOfficeSize(corporation, office, size);
@@ -614,7 +615,7 @@ export function NetscriptCorporation(
const divisionName = helper.string("throwParty", "divisionName", adivisionName);
const cityName = helper.string("throwParty", "cityName", acityName);
const costPerEmployee = helper.number("throwParty", "costPerEmployee", acostPerEmployee);
if (costPerEmployee < 0) throw new Error("Invalid value for Cost Per Employee field! Must be numeric and grater than 0");
if (costPerEmployee < 0) throw new Error("Invalid value for Cost Per Employee field! Must be numeric and greater than 0");
const office = getOffice(divisionName, cityName);
const corporation = getCorporation();
return netscriptDelay(
@@ -733,7 +734,7 @@ export function NetscriptCorporation(
issueDividends: function (apercent: any): void {
checkAccess("issueDividends");
const percent = helper.number("issueDividends", "percent", apercent);
if (percent < 0 || percent > 100) throw new Error("Invalid value for percent field! Must be numeric, grater than 0, and less than 100");
if (percent < 0 || percent > 100) throw new Error("Invalid value for percent field! Must be numeric, greater than 0, and less than 100");
const corporation = getCorporation();
if (!corporation.public)
throw helper.makeRuntimeErrorMsg(`corporation.issueDividends`, `Your company has not gone public!`);
+1 -1
View File
@@ -1212,7 +1212,7 @@ export function NetscriptSingularity(
);
return false;
}
const repNeededToDonate = Math.round(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction);
const repNeededToDonate = Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction);
if (faction.favor < repNeededToDonate) {
workerScript.log(
"donateToFaction",
+1 -1
View File
@@ -284,7 +284,7 @@ export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, hel
},
purchaseSleeveAug: function (asleeveNumber: any = 0, aaugName: any = ""): boolean {
const sleeveNumber = helper.number("purchaseSleeveAug", "sleeveNumber", asleeveNumber);
const augName = helper.string("setToUniversityCourse", "augName", aaugName);
const augName = helper.string("purchaseSleeveAug", "augName", aaugName);
helper.updateDynamicRam("purchaseSleeveAug", getRamCost(player, "sleeve", "purchaseSleeveAug"));
checkSleeveAPIAccess("purchaseSleeveAug");
checkSleeveNumber("purchaseSleeveAug", sleeveNumber);
-2
View File
@@ -14,7 +14,6 @@ export function NetscriptPort(): IPort {
const data: any[] = [];
return {
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
write: (value: any): any => {
data.push(value);
if (data.length > Settings.MaxPortCapacity) {
@@ -23,7 +22,6 @@ export function NetscriptPort(): IPort {
return null;
},
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
tryWrite: (value: any): boolean => {
if (data.length >= Settings.MaxPortCapacity) {
return false;
@@ -1708,7 +1708,7 @@ export function applyForJob(this: IPlayer, entryPosType: CompanyPosition, sing =
if (!this.isQualified(company, pos)) {
const reqText = getJobRequirementText(company, pos);
if (!sing) {
dialogBoxCreate("Unforunately, you do not qualify for this position<br>" + reqText);
dialogBoxCreate("Unfortunately, you do not qualify for this position<br>" + reqText);
}
return false;
}
@@ -1849,7 +1849,7 @@ export function applyForSecurityEngineerJob(this: IPlayer, sing = false): boolea
return this.applyForJob(CompanyPositions[posNames.SecurityEngineerCompanyPositions[0]], sing);
} else {
if (!sing) {
dialogBoxCreate("Unforunately, you do not qualify for this position");
dialogBoxCreate("Unfortunately, you do not qualify for this position");
}
return false;
}
@@ -1862,7 +1862,7 @@ export function applyForNetworkEngineerJob(this: IPlayer, sing = false): boolean
return this.applyForJob(pos, sing);
} else {
if (!sing) {
dialogBoxCreate("Unforunately, you do not qualify for this position");
dialogBoxCreate("Unfortunately, you do not qualify for this position");
}
return false;
}
@@ -1889,7 +1889,7 @@ export function applyForAgentJob(this: IPlayer, sing = false): boolean {
return this.applyForJob(pos, sing);
} else {
if (!sing) {
dialogBoxCreate("Unforunately, you do not qualify for this position");
dialogBoxCreate("Unfortunately, you do not qualify for this position");
}
return false;
}
@@ -1914,7 +1914,7 @@ export function applyForEmployeeJob(this: IPlayer, sing = false): boolean {
return true;
} else {
if (!sing) {
dialogBoxCreate("Unforunately, you do not qualify for this position");
dialogBoxCreate("Unfortunately, you do not qualify for this position");
}
return false;
@@ -1939,7 +1939,7 @@ export function applyForPartTimeEmployeeJob(this: IPlayer, sing = false): boolea
return true;
} else {
if (!sing) {
dialogBoxCreate("Unforunately, you do not qualify for this position");
dialogBoxCreate("Unfortunately, you do not qualify for this position");
}
return false;
@@ -1963,7 +1963,7 @@ export function applyForWaiterJob(this: IPlayer, sing = false): boolean {
return true;
} else {
if (!sing) {
dialogBoxCreate("Unforunately, you do not qualify for this position");
dialogBoxCreate("Unfortunately, you do not qualify for this position");
}
return false;
}
@@ -1986,7 +1986,7 @@ export function applyForPartTimeWaiterJob(this: IPlayer, sing = false): boolean
return true;
} else {
if (!sing) {
dialogBoxCreate("Unforunately, you do not qualify for this position");
dialogBoxCreate("Unfortunately, you do not qualify for this position");
}
return false;
}
+6 -2
View File
@@ -433,7 +433,7 @@ export class Sleeve extends Person {
}
/**
* Called on every sleeve for a Source File prestige
* Called on every sleeve for a Source File Prestige
*/
prestige(p: IPlayer): void {
// Reset exp
@@ -453,7 +453,11 @@ export class Sleeve extends Person {
// Reset augs and multipliers
this.augmentations = [];
this.resetMultipliers();
// Reset Location
this.city=CityName.Sector12;
// Reset sleeve-related stats
this.shock = 1;
this.storedCycles = 0;
@@ -52,8 +52,6 @@ export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentat
availableAugs.push(aug);
}
}
return availableAugs;
}
for (const facName of p.factions) {
+110 -7
View File
@@ -105,9 +105,11 @@ interface RunningScript {
logs: string[];
offlineExpGained: number;
offlineMoneyMade: number;
/** Offline running time of the script, in seconds **/
offlineRunningTime: number;
onlineExpGained: number;
onlineMoneyMade: number;
/** Online running time of the script, in seconds **/
onlineRunningTime: number;
pid: number;
ramUsage: number;
@@ -898,42 +900,75 @@ export interface GangTerritory {
* @public
*/
export interface GangMemberInfo {
/** Name of the gang member */
name: string;
task: string;
/** Currently assigned task */
task: string;
earnedRespect: number;
/** Hack skill level */
hack: number;
/** Strength skill level */
str: number;
/** Defense skill level */
def: number;
/** Dexterity skill level */
dex: number;
/** Agility skill level */
agi: number;
/** Charisma skill level */
cha: number;
/** Current hack experience */
hack_exp: number;
/** Current strength experience */
str_exp: number;
/** Current defense experience */
def_exp: number;
/** Current dexterity experience */
dex_exp: number;
/** Current agility experience */
agi_exp: number;
/** Current charisma experience */
cha_exp: number;
/** Hack multiplier from equipment */
hack_mult: number;
/** Strength multiplier from equipment */
str_mult: number;
/** Defense multiplier from equipment */
def_mult: number;
/** Dexterity multiplier from equipment */
dex_mult: number;
/** Agility multiplier from equipment */
agi_mult: number;
/** Charisma multiplier from equipment */
cha_mult: number;
/** Hack multiplier from ascensions */
hack_asc_mult: number;
/** Strength multiplier from ascensions */
str_asc_mult: number;
/** Defense multiplier from ascensions */
def_asc_mult: number;
/** Dexterity multiplier from ascensions */
dex_asc_mult: number;
/** Agility multiplier from ascensions */
agi_asc_mult: number;
/** Charisma multiplier from ascensions */
cha_asc_mult: number;
/** Total earned hack experience */
hack_asc_points: number;
/** Total earned strength experience */
str_asc_points: number;
/** Total earned defense experience */
def_asc_points: number;
/** Total earned dexterity experience */
dex_asc_points: number;
/** Total earned agility experience */
agi_asc_points: number;
/** Total earned charisma experience */
cha_asc_points: number;
upgrades: string[];
@@ -1601,9 +1636,10 @@ export interface Singularity {
* The actions that can be stopped with this function are:
*
* * Studying at a university
* * Working out at a gym
* * Working for a company/faction
* * Creating a program
* * Committing a Crime
* * Committing a crime
*
* This function will return true if the players action was ended.
* It will return false if the player was not performing an action when this function was called.
@@ -4098,7 +4134,7 @@ interface UserInterface {
* ns.getHostname();
* // Some related functions are gathered under a sub-property of the ns object
* ns.stock.getPrice();
* // Some functions need to be await ed
* // Some functions need to be awaited
* await ns.hack('n00dles');
* }
* ```
@@ -4926,6 +4962,34 @@ export interface NS extends Singularity {
* @returns True if the script is successfully killed, and false otherwise.
*/
kill(script: number): boolean;
/**
* {@inheritDoc NS.(kill:1)}
* @example
* ```ts
* // NS1:
* //The following example will try to kill a script named foo.script on the foodnstuff server that was ran with no arguments:
* kill("foo.script", "foodnstuff");
*
* //The following will try to kill a script named foo.script on the current server that was ran with no arguments:
* kill("foo.script", getHostname());
*
* //The following will try to kill a script named foo.script on the current server that was ran with the arguments 1 and “foodnstuff”:
* kill("foo.script", getHostname(), 1, "foodnstuff");
* ```
* @example
* ```ts
* // NS2:
* //The following example will try to kill a script named foo.script on the foodnstuff server that was ran with no arguments:
* ns.kill("foo.script", "foodnstuff");
*
* //The following will try to kill a script named foo.script on the current server that was ran with no arguments:
* ns.kill("foo.script", getHostname());
*
* //The following will try to kill a script named foo.script on the current server that was ran with the arguments 1 and “foodnstuff”:
* ns.kill("foo.script", getHostname(), 1, "foodnstuff");
* ```
*/
kill(script: string, host: string, ...args: string[]): boolean;
/**
@@ -4991,6 +5055,37 @@ export interface NS extends Singularity {
* @returns True if the script/literature file is successfully copied over and false otherwise. If the files argument is an array then this function will return true if at least one of the files in the array is successfully copied.
*/
scp(files: string | string[], destination: string): Promise<boolean>;
/**
* {@inheritDoc NS.(scp:1)}
* @example
* ```ts
* // NS1:
* //Copies foo.lit from the helios server to the home computer:
* scp("foo.lit", "helios", "home");
*
* //Tries to copy three files from rothman-uni to home computer:
* files = ["foo1.lit", "foo2.script", "foo3.script"];
* scp(files, "rothman-uni", "home");
* ```
* @example
* ```ts
* // NS2:
* //Copies foo.lit from the helios server to the home computer:
* await ns.scp("foo.lit", "helios", "home");
*
* //Tries to copy three files from rothman-uni to home computer:
* files = ["foo1.lit", "foo2.script", "foo3.script"];
* await ns.scp(files, "rothman-uni", "home");
* ```
* @example
* ```ts
* //ns2, copies files from home to a target server
* const server = ns.args[0];
* const files = ["hack.js","weaken.js","grow.js"];
* await ns.scp(files, "home", server);
* ```
*/
scp(files: string | string[], source: string, destination: string): Promise<boolean>;
/**
@@ -5017,8 +5112,8 @@ export interface NS extends Singularity {
* @example
* ```ts
* // NS1:
* const scripts = ps("home");
* for (let i = 0; i < scripts.length; ++i) {
* var scripts = ps("home");
* for (var i = 0; i < scripts.length; ++i) {
* tprint(scripts[i].filename + ' ' + scripts[i].threads);
* tprint(scripts[i].args);
* }
@@ -5027,8 +5122,8 @@ export interface NS extends Singularity {
* ```ts
* // NS2:
* const ps = ns.ps("home");
* for (script of ps) {
* ns.tprint(`${script.filename} ${ps[i].threads}`);
* for (let script of ps) {
* ns.tprint(`${script.filename} ${script.threads}`);
* ns.tprint(script.args);
* }
* ```
@@ -5795,6 +5890,10 @@ export interface NS extends Singularity {
* @returns Amount of income the specified script generates while online.
*/
getScriptIncome(): [number, number];
/**
* {@inheritDoc NS.(getScriptIncome:1)}
*/
getScriptIncome(script: string, host: string, ...args: string[]): number;
/**
@@ -5815,6 +5914,10 @@ export interface NS extends Singularity {
* @returns Amount of hacking experience the specified script generates while online.
*/
getScriptExpGain(): number;
/**
* {@inheritDoc NS.(getScriptExpGain:1)}
*/
getScriptExpGain(script: string, host: string, ...args: string[]): number;
/**
+39 -26
View File
@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import React, { useState, useEffect, useRef, useMemo } from "react";
import Editor, { Monaco } from "@monaco-editor/react";
import * as monaco from "monaco-editor";
@@ -754,7 +753,11 @@ export function Root(props: IProps): React.ReactElement {
// 44px bottom tool bar + 16px margin
// + vim bar 34px
const editorHeight = dimensions.height - (130 + (options.vim ? 34 : 0));
const tabsMaxWidth = 1640
const tabMargin = 5
const tabMaxWidth = openScripts.length ? (tabsMaxWidth / openScripts.length) - tabMargin : 0
const tabIconWidth = 25
const tabTextWidth = tabMaxWidth - (tabIconWidth * 2)
return (
<>
<div style={{ display: currentScript !== null ? "block" : "none", height: "100%", width: "100%" }}>
@@ -762,7 +765,7 @@ export function Root(props: IProps): React.ReactElement {
<Droppable droppableId="tabs" direction="horizontal">
{(provided, snapshot) => (
<Box
maxWidth="1640px"
maxWidth={`${tabsMaxWidth}px`}
display="flex"
flexDirection="row"
alignItems="center"
@@ -778,8 +781,8 @@ export function Root(props: IProps): React.ReactElement {
>
{openScripts.map(({ fileName, hostname }, index) => {
const iconButtonStyle = {
maxWidth: "25px",
minWidth: "25px",
maxWidth: `${tabIconWidth}px`,
minWidth: `${tabIconWidth}px`,
minHeight: '38.5px',
maxHeight: '38.5px',
...(currentScript?.fileName === openScripts[index].fileName ? {
@@ -792,6 +795,8 @@ export function Root(props: IProps): React.ReactElement {
color: Settings.theme.secondary
})
};
const scriptTabText = `${hostname}:~/${fileName} ${dirty(index)}`
return (
<Draggable
key={fileName + hostname}
@@ -806,31 +811,39 @@ export function Root(props: IProps): React.ReactElement {
{...provided.dragHandleProps}
style={{
...provided.draggableProps.style,
marginRight: "5px",
minWidth: '200px',
maxWidth: `${tabMaxWidth}px`,
marginRight: `${tabMargin}px`,
flexShrink: 0,
border: '1px solid ' + Settings.theme.well,
}}
>
<Button
onClick={() => onTabClick(index)}
onMouseDown={e => {
e.preventDefault();
if (e.button === 1) onTabClose(index);
}}
style={{
...(currentScript?.fileName === openScripts[index].fileName ? {
background: Settings.theme.button,
borderColor: Settings.theme.button,
color: Settings.theme.primary
} : {
background: Settings.theme.backgroundsecondary,
borderColor: Settings.theme.backgroundsecondary,
color: Settings.theme.secondary
})
}}
>
{hostname}:~/{fileName} {dirty(index)}
</Button>
<Tooltip title={scriptTabText}>
<Button
onClick={() => onTabClick(index)}
onMouseDown={e => {
e.preventDefault();
if (e.button === 1) onTabClose(index);
}}
style={{
maxWidth: `${tabTextWidth}px`,
overflow: "hidden",
...(currentScript?.fileName === openScripts[index].fileName ? {
background: Settings.theme.button,
borderColor: Settings.theme.button,
color: Settings.theme.primary
} : {
background: Settings.theme.backgroundsecondary,
borderColor: Settings.theme.backgroundsecondary,
color: Settings.theme.secondary
})
}}
>
<span style={{ overflow: 'hidden', direction: 'rtl', textOverflow: "ellipsis" }}>
{scriptTabText}
</span>
</Button>
</Tooltip>
<Tooltip title="Overwrite editor content with saved file content">
<Button onClick={() => onTabUpdate(index)} style={iconButtonStyle} >
<SyncIcon fontSize='small' />
+1 -1
View File
@@ -30,7 +30,7 @@ export function getPurchaseServerCost(ram: number): number {
const upg = Math.max(0, Math.log(sanitizedRam) / Math.log(2) - 6);
return Math.round(
return (
sanitizedRam *
CONSTANTS.BaseCostFor1GBOfRamServer *
BitNodeMultipliers.PurchasedServerCost *
+3 -1
View File
@@ -314,7 +314,9 @@ export class Terminal implements ITerminal {
this.print("Organization name: " + (!isHacknet ? org : "player"));
const hasAdminRights = (!isHacknet && currServ.hasAdminRights) || isHacknet;
this.print("Root Access: " + (hasAdminRights ? "YES" : "NO"));
this.print("Can run scripts on this host: " + (hasAdminRights ? "YES" : "NO"));
const canRunScripts = hasAdminRights && currServ.maxRam > 0;
this.print("Can run scripts on this host: " + (canRunScripts ? "YES" : "NO"));
this.print("RAM: " + numeralWrapper.formatRAM(currServ.maxRam));
if (currServ instanceof Server) {
this.print("Backdoor: " + (currServ.backdoorInstalled ? "YES" : "NO"));
const hackingSkill = currServ.requiredHackingSkill;
+1 -1
View File
@@ -12,7 +12,7 @@ export function scan(
args: (string | number | boolean)[],
): void {
if (args.length !== 0) {
terminal.error("Incorrect usage of netstat/scan command. Usage: netstat/scan");
terminal.error("Incorrect usage of scan command. Usage: scan");
return;
}
-2
View File
@@ -114,7 +114,6 @@ Reviver.constructors.TextFile = TextFile;
* @param server The server object to look in
* @returns The file object, or null if it couldn't find it.
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function getTextFile(fn: string, server: BaseServer): TextFile | null {
let filename: string = !fn.endsWith(".txt") ? `${fn}.txt` : fn;
@@ -138,7 +137,6 @@ export function getTextFile(fn: string, server: BaseServer): TextFile | null {
* @param server The server that the file should be created on.
* @returns The instance of the file.
*/
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export function createTextFile(fn: string, txt: string, server: BaseServer): TextFile | undefined {
if (getTextFile(fn, server) !== null) {
// This should probably be a `throw`...
+31
View File
@@ -336,6 +336,37 @@ export function refreshTheme(): void {
color: Settings.theme.primary,
},
},
root: {
backgroundColor: Settings.theme.backgroundsecondary,
border: "1px solid " + Settings.theme.well,
margin: '3px',
"&.Mui-selected": {
backgroundColor: Settings.theme.button
},
},
},
},
MuiTabs: {
styleOverrides: {
scrollButtons: {
backgroundColor: Settings.theme.backgroundsecondary,
color: Settings.theme.secondary,
margin: '3px',
opacity: 1,
width: 'fit-content',
"&.Mui-disabled": {
opacity: 0.5
}
}
},
defaultProps: {
TabIndicatorProps: {
style: {
display: "none"
}
}
},
},
MuiAlert: {
+3 -2
View File
@@ -816,7 +816,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
`Examples:\n`,
`"()())()" -> [()()(), (())()]\n`,
`"(a)())()" -> [(a)()(), (a())()]\n`,
`")( -> [""]`,
`")(" -> [""]`,
].join(" ");
},
difficulty: 10,
@@ -921,7 +921,8 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
"The provided answer should be an array of strings containing the valid expressions.",
"The data provided by this problem is an array with two elements. The first element",
"is the string of digits, while the second element is the target number:\n\n",
`["${digits}", ${target}]\n\n`,
`["${digits}", ${target}]\n\n`,
"NOTE: The order of evaluation expects script operator precedence",
"NOTE: Numbers in the expression cannot have leading 0's. In other words,",
`"1+01" is not a valid expression`,
"Examples:\n\n",
+2 -2
View File
@@ -31,9 +31,9 @@ export function ActiveScriptsRoot(props: IProps): React.ReactElement {
}
return (
<>
<Tabs variant="fullWidth" value={tab} onChange={handleChange}>
<Tabs variant="fullWidth" value={tab} onChange={handleChange} sx={{ minWidth: 'fit-content', maxWidth: '25%' }}>
<Tab label={"Active"} value={"active"} />
<Tab label={"Recent"} value={"recent"} />
<Tab label={"Recently Killed"} value={"recent"} />
</Tabs>
{tab === "active" && <ActiveScriptsPage workerScripts={props.workerScripts} />}
@@ -212,7 +212,7 @@ export function InteractiveTutorialRoot(): React.ReactElement {
<Typography>
{" "}
we can see that the n00dles server is only one node away. Let's connect so it now using:
we can see that the n00dles server is only one node away. Let's connect to it now using:
</Typography>
<Typography classes={{ root: classes.textfield }}>{"[home ~/]> connect n00dles"}</Typography>
+3 -1
View File
@@ -42,7 +42,9 @@ export function PromptManager(): React.ReactElement {
<>
{prompt != null && (
<Modal open={true} onClose={close}>
<Typography>{prompt.txt}</Typography>
<pre>
<Typography>{prompt.txt}</Typography>
</pre>
<div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', paddingTop: '10px' }}>
<Button style={{ marginRight: 'auto' }} onClick={yes}>Yes</Button>
<Button onClick={no}>No</Button>
-1
View File
@@ -16,7 +16,6 @@ import "numeral/locales/ru";
import { Settings } from "../Settings/Settings";
/* eslint-disable class-methods-use-this */
const extraFormats = [1e15, 1e18, 1e21, 1e24, 1e27, 1e30];
const extraNotations = ["q", "Q", "s", "S", "o", "n"];