merge base

This commit is contained in:
phyzical
2022-04-13 18:50:42 +08:00
172 changed files with 5885 additions and 3696 deletions
+3 -4
View File
@@ -2,7 +2,6 @@
import * as React from "react";
import { IMap } from "../types";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { Faction } from "../Faction/Faction";
import { Factions } from "../Faction/Factions";
import { numeralWrapper } from "../ui/numeralFormat";
@@ -141,7 +140,7 @@ function generateStatsDescription(mults: IMap<number>, programs?: string[], star
desc = (
<>
{desc}
<br />+{f(mults.charisma_mult - 1)} Charisma skill
<br />+{f(mults.charisma_mult - 1)} charisma skill
</>
);
}
@@ -464,8 +463,8 @@ export class Augmentation {
this.info = params.info;
this.prereqs = params.prereqs ? params.prereqs : [];
this.baseRepRequirement = params.repCost * BitNodeMultipliers.AugmentationRepCost;
this.baseCost = params.moneyCost * BitNodeMultipliers.AugmentationMoneyCost;
this.baseRepRequirement = params.repCost;
this.baseCost = params.moneyCost;
this.startingCost = this.baseCost;
this.startingRepRequirement = this.baseRepRequirement;
this.factions = params.factions;
+18 -8
View File
@@ -22,6 +22,7 @@ import {
initUnstableCircadianModulator,
} from "./data/AugmentationCreator";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { Router } from "../ui/GameRoot";
export function AddToAugmentations(aug: Augmentation): void {
const name = aug.name;
@@ -157,6 +158,12 @@ function applyAugmentation(aug: IPlayerOwnedAugmentation, reapply = false): void
}
}
// Special logic for Congruity Implant
if (aug.name === AugmentationNames.CongruityImplant && !reapply) {
Player.entropy = 0;
Player.applyEntropy(Player.entropy);
}
// Push onto Player's Augmentation list
if (!reapply) {
const ownedAug = new PlayerOwnedAugmentation(aug.name);
@@ -164,8 +171,8 @@ function applyAugmentation(aug: IPlayerOwnedAugmentation, reapply = false): void
}
}
function installAugmentations(): boolean {
if (Player.queuedAugmentations.length == 0) {
function installAugmentations(force?: boolean): boolean {
if (Player.queuedAugmentations.length == 0 && !force) {
dialogBoxCreate("You have not purchased any Augmentations to install!");
return false;
}
@@ -195,13 +202,16 @@ function installAugmentations(): boolean {
augmentationList += aug.name + level + "<br>";
}
Player.queuedAugmentations = [];
dialogBoxCreate(
"You slowly drift to sleep as scientists put you under in order " +
"to install the following Augmentations:<br>" +
augmentationList +
"<br>You wake up in your home...you feel different...",
);
if (!force) {
dialogBoxCreate(
"You slowly drift to sleep as scientists put you under in order " +
"to install the following Augmentations:<br>" +
augmentationList +
"<br>You wake up in your home...you feel different...",
);
}
prestigeAugmentation();
Router.toTerminal();
return true;
}
@@ -1641,6 +1641,25 @@ export const initGeneralAugmentations = (): Augmentation[] => [
),
factions: [FactionNames.TianDiHui],
}),
// Grafting-exclusive Augmentation
new Augmentation({
name: AugmentationNames.CongruityImplant,
repCost: Infinity,
moneyCost: 50e12,
info: (
<>
Developed by a pioneer in Grafting research, this implant generates pulses of stability which seem to have a
nullifying effect versus the Entropy virus.
<br />
<br />
<b>Note:</b> For unknown reasons, the lowercase <code>n</code> appears to be an integral component to its
functionality.
</>
),
stats: <>This Augmentation removes the Entropy virus, and prevents it from affecting you again.</>,
factions: [],
}),
];
export const initBladeburnerAugmentations = (): Augmentation[] => [
@@ -91,6 +91,7 @@ export enum AugmentationNames {
BionicArms = "Bionic Arms",
SNA = "Social Negotiation Assistant (S.N.A)",
HydroflameLeftArm = "Hydroflame Left Arm",
CongruityImplant = "nickofolas Congruity Implant",
EsperEyewear = "EsperTech Bladeburner Eyewear",
EMS4Recombination = "EMS-4 Recombination",
OrionShoulder = "ORION-MKIV Shoulder",
+151 -72
View File
@@ -7,7 +7,7 @@ import React, { useState, useEffect } from "react";
import { InstalledAugmentations } from "./InstalledAugmentations";
import { PlayerMultipliers } from "./PlayerMultipliers";
import { PurchasedAugmentations } from "./PurchasedAugmentations";
import { SourceFiles } from "./SourceFiles";
import { SourceFilesElement } from "./SourceFiles";
import { canGetBonus } from "../../ExportBonus";
import { use } from "../../ui/Context";
@@ -16,8 +16,55 @@ import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import Tooltip from "@mui/material/Tooltip";
import Box from "@mui/material/Box";
import Paper from "@mui/material/Paper";
import Container from "@mui/material/Container";
import { Settings } from "../../Settings/Settings";
import { ConfirmationModal } from "../../ui/React/ConfirmationModal";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { AugmentationNames } from "../data/AugmentationNames";
import { Augmentations } from "../Augmentations";
import { CONSTANTS } from "../../Constants";
import { formatNumber } from "../../utils/StringHelperFunctions";
import { Info } from "@mui/icons-material";
interface NFGDisplayProps {
player: IPlayer;
}
const NeuroFluxDisplay = ({ player }: NFGDisplayProps): React.ReactElement => {
const level = player.augmentations.find((e) => e.name === AugmentationNames.NeuroFluxGovernor)?.level ?? 0;
return level > 0 ? (
<Paper sx={{ p: 1 }}>
<Typography variant="h5" color={Settings.theme.info}>
NeuroFlux Governor - Level {level}
</Typography>
<Typography color={Settings.theme.info}>{Augmentations[AugmentationNames.NeuroFluxGovernor].stats}</Typography>
</Paper>
) : (
<></>
);
};
interface EntropyDisplayProps {
player: IPlayer;
}
const EntropyDisplay = ({ player }: EntropyDisplayProps): React.ReactElement => {
return player.entropy > 0 ? (
<Paper sx={{ p: 1 }}>
<Typography variant="h5" color={Settings.theme.error}>
Entropy Virus - Level {player.entropy}
</Typography>
<Typography color={Settings.theme.error}>
<b>All multipliers decreased by:</b> {formatNumber((1 - CONSTANTS.EntropyEffect ** player.entropy) * 100, 3)}%
(multiplicative)
</Typography>
</Paper>
) : (
<></>
);
};
interface IProps {
exportGameFn: () => void;
@@ -55,81 +102,113 @@ export function AugmentationsRoot(props: IProps): React.ReactElement {
}
return (
<>
<Container disableGutters maxWidth="lg" sx={{ mx: 0 }}>
<Typography variant="h4">Augmentations</Typography>
<Box mx={2}>
<Typography>
Below is a list of all Augmentations you have purchased but not yet installed. Click the button below to
install them.
</Typography>
<Typography>WARNING: Installing your Augmentations resets most of your progress, including:</Typography>
<br />
<Typography>- Stats/Skill levels and Experience</Typography>
<Typography>- Money</Typography>
<Typography>- Scripts on every computer but your home computer</Typography>
<Typography>- Purchased servers</Typography>
<Typography>- Hacknet Nodes</Typography>
<Typography>- Faction/Company reputation</Typography>
<Typography>- Stocks</Typography>
<br />
<Typography>
Installing Augmentations lets you start over with the perks and benefits granted by all of the Augmentations
you have ever installed. Also, you will keep any scripts and RAM/Core upgrades on your home computer (but you
will lose all programs besides NUKE.exe)
</Typography>
<Box sx={{ mb: 1 }}>
<Paper sx={{ p: 1 }}>
<Typography variant="h5" color="primary" sx={{ display: "flex", alignItems: "center", flexWrap: "wrap" }}>
Purchased Augmentations
<Tooltip
title={
<>
<Typography>
Below is a list of all Augmentations you have purchased but not yet installed. Click the button
below to install them.
</Typography>
<Typography>
WARNING: Installing your Augmentations resets most of your progress, including:
</Typography>
<br />
<Typography>- Stats/Skill levels and Experience</Typography>
<Typography>- Money</Typography>
<Typography>- Scripts on every computer but your home computer</Typography>
<Typography>- Purchased servers</Typography>
<Typography>- Hacknet Nodes</Typography>
<Typography>- Faction/Company reputation</Typography>
<Typography>- Stocks</Typography>
<br />
<Typography>
Installing Augmentations lets you start over with the perks and benefits granted by all of the
Augmentations you have ever installed. Also, you will keep any scripts and RAM/Core upgrades on your
home computer (but you will lose all programs besides NUKE.exe)
</Typography>
</>
}
>
<Info sx={{ ml: 1, mb: 0.5 }} color="info" />
</Tooltip>
</Typography>
<ConfirmationModal
open={installOpen}
onClose={() => setInstallOpen(false)}
onConfirm={props.installAugmentationsFn}
confirmationText={
<>
Installing will reset
<br />
<br />- money
<br />- skill / experience
<br />- every server except home
<br />- factions and reputation
<br />
<br />
You will keep:
<br />
<br />- All scripts on home
<br />- home ram and cores
<br />
<br />
It is recommended to install several Augmentations at once. Preferably everything from any faction of
your choosing.
</>
}
/>
<Box sx={{ display: "grid", width: "100%", gridTemplateColumns: "1fr 1fr" }}>
<Tooltip title={<Typography>'I never asked for this'</Typography>}>
<span>
<Button sx={{ width: "100%" }} disabled={player.queuedAugmentations.length === 0} onClick={doInstall}>
Install Augmentations
</Button>
</span>
</Tooltip>
<Tooltip title={<Typography>It's always a good idea to backup/export your save!</Typography>}>
<Button sx={{ width: "100%" }} onClick={doExport} color="error">
Backup Save {exportBonusStr()}
</Button>
</Tooltip>
</Box>
</Paper>
{player.queuedAugmentations.length > 0 ? (
<Box sx={{ display: "grid", gridTemplateColumns: "1fr 3fr" }}>
<PurchasedAugmentations />
<PlayerMultipliers />
</Box>
) : (
<Paper sx={{ p: 1 }}>
<Typography>No Augmentations have been purchased yet</Typography>
</Paper>
)}
</Box>
<Typography variant="h4" color="primary">
Purchased Augmentations
</Typography>
<Box mx={2}>
<Tooltip title={<Typography>'I never asked for this'</Typography>}>
<span>
<Button disabled={player.queuedAugmentations.length === 0} onClick={doInstall}>
Install Augmentations
</Button>
</span>
</Tooltip>
<ConfirmationModal
open={installOpen}
onClose={() => setInstallOpen(false)}
onConfirm={props.installAugmentationsFn}
confirmationText={
<>
Installing will reset
<br />
<br />- money
<br />- skill / experience
<br />- every server except home
<br />- factions and reputation
<br />
<br />
You will keep:
<br />
<br />- All scripts on home
<br />- home ram and cores
<br />
<br />
It is recommended to install several Augmentations at once. Preferably everything from any faction of your
choosing.
</>
}
/>
<Tooltip title={<Typography>It's always a good idea to backup/export your save!</Typography>}>
<Button sx={{ mx: 2 }} onClick={doExport} color="error">
Backup Save {exportBonusStr()}
</Button>
</Tooltip>
<PurchasedAugmentations />
<Box
sx={{
my: 1,
display: "grid",
gridTemplateColumns: `repeat(${
+!!((player.augmentations.find((e) => e.name === AugmentationNames.NeuroFluxGovernor)?.level ?? 0) > 0) +
+!!(player.entropy > 0)
}, 1fr)`,
gap: 1,
}}
>
<NeuroFluxDisplay player={player} />
<EntropyDisplay player={player} />
</Box>
<Typography variant="h4">Installed Augmentations</Typography>
<Box mx={2}>
<Typography>
List of all Augmentations that have been installed. You have gained the effects of these.
</Typography>
<Box>
<InstalledAugmentations />
</Box>
<PlayerMultipliers />
<SourceFiles />
</>
<SourceFilesElement />
</Container>
);
}
+62 -66
View File
@@ -5,28 +5,23 @@
* It also contains 'configuration' buttons that allow you to change how the
* Augs/SF's are displayed
*/
import { Box, ListItemButton, Paper, Typography } from "@mui/material";
import Button from "@mui/material/Button";
import List from "@mui/material/List";
import Tooltip from "@mui/material/Tooltip";
import React, { useState } from "react";
import { AugmentationAccordion } from "../../ui/React/AugmentationAccordion";
import { Augmentations } from "../Augmentations";
import { AugmentationNames } from "../data/AugmentationNames";
import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums";
import { Settings } from "../../Settings/Settings";
import { use } from "../../ui/Context";
import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums";
import Button from "@mui/material/Button";
import Tooltip from "@mui/material/Tooltip";
import List from "@mui/material/List";
import { ExpandLess, ExpandMore } from "@mui/icons-material";
import { Box, Paper, ListItemButton, ListItemText, Typography, Collapse } from "@mui/material";
import { CONSTANTS } from "../../Constants";
import { formatNumber } from "../../utils/StringHelperFunctions";
import { Augmentations } from "../Augmentations";
import { AugmentationNames } from "../data/AugmentationNames";
export function InstalledAugmentations(): React.ReactElement {
const setRerender = useState(true)[1];
const player = use.Player();
const sourceAugs = player.augmentations.slice().filter((aug) => aug.name !== AugmentationNames.NeuroFluxGovernor);
const sourceAugs = player.augmentations.slice();
const [selectedAug, setSelectedAug] = useState(sourceAugs[0]);
if (Settings.OwnedAugmentationsOrder === OwnedAugmentationsOrderSetting.Alphabetically) {
sourceAugs.sort((aug1, aug2) => {
@@ -49,59 +44,60 @@ export function InstalledAugmentations(): React.ReactElement {
}
return (
<>
<Tooltip title={"Sorts the Augmentations alphabetically in numeral order"}>
<Button onClick={sortInOrder}>Sort in Order</Button>
</Tooltip>
<Tooltip title={"Sorts the Augmentations based on when you acquired them (same as default)"}>
<Button sx={{ mx: 2 }} onClick={sortByAcquirementTime}>
Sort by Acquirement Time
</Button>
</Tooltip>
<List dense>
{player.entropy > 0 &&
(() => {
const [open, setOpen] = useState(false);
return (
<Box component={Paper}>
<ListItemButton onClick={() => setOpen((old) => !old)}>
<ListItemText
primary={
<Typography color={Settings.theme.hp} style={{ whiteSpace: "pre-wrap" }}>
Entropy Virus - Level {player.entropy}
</Typography>
}
/>
{open ? (
<ExpandLess sx={{ color: Settings.theme.hp }} />
) : (
<ExpandMore sx={{ color: Settings.theme.hp }} />
)}
<Box sx={{ width: "100%" }}>
<Paper sx={{ p: 1 }}>
<Typography variant="h5">Installed Augmentations</Typography>
<Box sx={{ display: "grid", gridTemplateColumns: "1fr 1fr" }}>
<Tooltip title={"Sorts the Augmentations alphabetically in numeral order"}>
<Button sx={{ width: "100%" }} onClick={sortInOrder}>
Sort in Order
</Button>
</Tooltip>
<Tooltip title={"Sorts the Augmentations based on when you acquired them (same as default)"}>
<Button sx={{ width: "100%" }} onClick={sortByAcquirementTime}>
Sort by Time of Acquirement
</Button>
</Tooltip>
</Box>
</Paper>
{sourceAugs.length > 0 ? (
<Paper sx={{ display: "grid", gridTemplateColumns: "1fr 3fr" }}>
<Box>
<List sx={{ height: 400, overflowY: "scroll", borderRight: `1px solid ${Settings.theme.welllight}` }}>
{sourceAugs.map((k, i) => (
<ListItemButton key={i + 1} onClick={() => setSelectedAug(k)} selected={selectedAug === k}>
<Typography>{k.name}</Typography>
</ListItemButton>
<Collapse in={open} unmountOnExit>
<Box m={4}>
<Typography color={Settings.theme.hp}>
<b>All multipliers decreased by:</b>{" "}
{formatNumber((1 - CONSTANTS.EntropyEffect ** player.entropy) * 100, 3)}% (multiplicative)
</Typography>
</Box>
</Collapse>
</Box>
);
})()}
))}
</List>
</Box>
<Box sx={{ m: 1 }}>
<Typography variant="h6" sx={{ display: "flex", alignItems: "center", flexWrap: "wrap" }}>
{selectedAug.name}
</Typography>
<Typography sx={{ maxHeight: 350, overflowY: "scroll" }}>
{(() => {
const aug = Augmentations[selectedAug.name];
{sourceAugs.map((e) => {
const aug = Augmentations[e.name];
let level = null;
if (e.name === AugmentationNames.NeuroFluxGovernor) {
level = e.level;
}
return <AugmentationAccordion key={aug.name} aug={aug} level={level} />;
})}
</List>
</>
const info = typeof aug.info === "string" ? <span>{aug.info}</span> : aug.info;
const tooltip = (
<>
{info}
<br />
<br />
{aug.stats}
</>
);
return tooltip;
})()}
</Typography>
</Box>
</Paper>
) : (
<Paper sx={{ p: 1 }}>
<Typography>No Augmentations have been installed yet</Typography>
</Paper>
)}
</Box>
);
}
+273 -298
View File
@@ -1,20 +1,22 @@
/**
* React component for displaying the player's multipliers on the Augmentation UI page
*/
import { DoubleArrow } from "@mui/icons-material";
import { List, ListItem, ListItemText, Paper, Typography } from "@mui/material";
import * as React from "react";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { Player } from "../../Player";
import { Settings } from "../../Settings/Settings";
import { SourceFileFlags } from "../../SourceFile/SourceFileFlags";
import { numeralWrapper } from "../../ui/numeralFormat";
import { Augmentations } from "../Augmentations";
import { Table, TableCell } from "../../ui/React/Table";
import TableBody from "@mui/material/TableBody";
import TableRow from "@mui/material/TableRow";
import Typography from "@mui/material/Typography";
import Box from "@mui/material/Box";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
function calculateAugmentedStats(): any {
const augP: any = {};
interface IAugmentedStats {
[index: string]: number;
}
function calculateAugmentedStats(): IAugmentedStats {
const augP: IAugmentedStats = {};
for (const aug of Player.queuedAugmentations) {
const augObj = Augmentations[aug.name];
for (const mult of Object.keys(augObj.mults)) {
@@ -25,311 +27,284 @@ function calculateAugmentedStats(): any {
return augP;
}
function Improvements({ r, m }: { r: number; m: number }): React.ReactElement {
if (r) {
return (
<>
<TableCell key="2">
<Typography>&nbsp;{"=>"}&nbsp;</Typography>
</TableCell>
<TableCell key="3">
<Typography>
{numeralWrapper.formatPercentage(r)} <BN5Stat base={r} mult={m} />
</Typography>
</TableCell>
</>
);
}
return <></>;
}
interface IBN5StatsProps {
interface IBitNodeModifiedStatsProps {
base: number;
mult: number;
color: string;
}
function BN5Stat(props: IBN5StatsProps): React.ReactElement {
if (props.mult === 1) return <></>;
return <>({numeralWrapper.formatPercentage(props.base * props.mult)})</>;
}
function BitNodeModifiedStats(props: IBitNodeModifiedStatsProps): React.ReactElement {
// If player doesn't have SF5 or if the property isn't affected by BitNode mults
if (props.mult === 1 || SourceFileFlags[5] === 0)
return <Typography color={props.color}>{numeralWrapper.formatPercentage(props.base)}</Typography>;
function MultiplierTable({ rows }: { rows: [string, number, number, number][] }): React.ReactElement {
return (
<Table size="small" padding="none">
<TableBody>
{rows.map((r: any) => (
<TableRow key={r[0]}>
<TableCell key="0">
<Typography noWrap>{r[0]} multiplier:&nbsp;</Typography>
</TableCell>
<TableCell key="1" style={{ textAlign: "right" }}>
<Typography noWrap>
{numeralWrapper.formatPercentage(r[1])} <BN5Stat base={r[1]} mult={r[3]} />
</Typography>
</TableCell>
<Improvements r={r[2]} m={r[3]} />
</TableRow>
))}
</TableBody>
</Table>
<Typography color={props.color}>
<span style={{ opacity: 0.5 }}>{numeralWrapper.formatPercentage(props.base)}</span>{" "}
{numeralWrapper.formatPercentage(props.base * props.mult)}
</Typography>
);
}
type MultiplierListItemData = [
multiplier: string,
currentValue: number,
augmentedValue: number,
bitNodeMultiplier: number,
color: string,
];
interface IMultiplierListProps {
rows: MultiplierListItemData[];
}
function MultiplierList(props: IMultiplierListProps): React.ReactElement {
const listItems = props.rows
.map((data) => {
const [multiplier, currentValue, augmentedValue, bitNodeMultiplier, color] = data;
if (!isNaN(augmentedValue)) {
return (
<ListItem key={multiplier} disableGutters sx={{ py: 0 }}>
<ListItemText
sx={{ my: 0.1 }}
primary={
<Typography color={color}>
<b>{multiplier}</b>
</Typography>
}
secondary={
<span style={{ display: "flex", alignItems: "center", flexWrap: "wrap" }}>
<BitNodeModifiedStats base={currentValue} mult={bitNodeMultiplier} color={color} />
<DoubleArrow fontSize="small" color="success" sx={{ mb: 0.5, mx: 1 }} />
<BitNodeModifiedStats base={augmentedValue} mult={bitNodeMultiplier} color={Settings.theme.success} />
</span>
}
disableTypography
/>
</ListItem>
);
}
return;
})
.filter((i) => i !== undefined);
return listItems.length > 0 ? <List disablePadding>{listItems}</List> : <></>;
}
export function PlayerMultipliers(): React.ReactElement {
const mults = calculateAugmentedStats();
function BladeburnerMults(): React.ReactElement {
if (!Player.canAccessBladeburner()) return <></>;
return (
<>
<MultiplierTable
rows={[
[
"Bladeburner Success Chance",
Player.bladeburner_success_chance_mult,
Player.bladeburner_success_chance_mult * mults.bladeburner_success_chance_mult,
1,
],
[
"Bladeburner Max Stamina",
Player.bladeburner_max_stamina_mult,
Player.bladeburner_max_stamina_mult * mults.bladeburner_max_stamina_mult,
1,
],
[
"Bladeburner Stamina Gain",
Player.bladeburner_stamina_gain_mult,
Player.bladeburner_stamina_gain_mult * mults.bladeburner_stamina_gain_mult,
1,
],
[
"Bladeburner Field Analysis",
Player.bladeburner_analysis_mult,
Player.bladeburner_analysis_mult * mults.bladeburner_analysis_mult,
1,
],
]}
/>
<br />
</>
// Column data is a bit janky, so it's set up here to allow for
// easier logic in setting up the layout
const leftColData: MultiplierListItemData[] = [
...[
["Hacking Chance ", Player.hacking_chance_mult, Player.hacking_chance_mult * mults.hacking_chance_mult, 1],
["Hacking Speed ", Player.hacking_speed_mult, Player.hacking_speed_mult * mults.hacking_speed_mult, 1],
["Hacking Money ", Player.hacking_money_mult, Player.hacking_money_mult * mults.hacking_money_mult, 1],
["Hacking Growth ", Player.hacking_grow_mult, Player.hacking_grow_mult * mults.hacking_grow_mult, 1],
[
"Hacking Level ",
Player.hacking_mult,
Player.hacking_mult * mults.hacking_mult,
BitNodeMultipliers.HackingLevelMultiplier,
],
[
"Hacking Experience ",
Player.hacking_exp_mult,
Player.hacking_exp_mult * mults.hacking_exp_mult,
BitNodeMultipliers.HackExpGain,
],
].map((data): MultiplierListItemData => (data as any).concat([Settings.theme.hack])),
...[
[
"Strength Level ",
Player.strength_mult,
Player.strength_mult * mults.strength_mult,
BitNodeMultipliers.StrengthLevelMultiplier,
],
["Strength Experience ", Player.strength_exp_mult, Player.strength_exp_mult * mults.strength_exp_mult, 1],
[
"Defense Level ",
Player.defense_mult,
Player.defense_mult * mults.defense_mult,
BitNodeMultipliers.DefenseLevelMultiplier,
],
["Defense Experience ", Player.defense_exp_mult, Player.defense_exp_mult * mults.defense_exp_mult, 1],
[
"Dexterity Level ",
Player.dexterity_mult,
Player.dexterity_mult * mults.dexterity_mult,
BitNodeMultipliers.DexterityLevelMultiplier,
],
["Dexterity Experience ", Player.dexterity_exp_mult, Player.dexterity_exp_mult * mults.dexterity_exp_mult, 1],
[
"Agility Level ",
Player.agility_mult,
Player.agility_mult * mults.agility_mult,
BitNodeMultipliers.AgilityLevelMultiplier,
],
["Agility Experience ", Player.agility_exp_mult, Player.agility_exp_mult * mults.agility_exp_mult, 1],
].map((data): MultiplierListItemData => (data as any).concat([Settings.theme.combat])),
[
"Charisma Level ",
Player.charisma_mult,
Player.charisma_mult * mults.charisma_mult,
BitNodeMultipliers.CharismaLevelMultiplier,
Settings.theme.cha,
],
[
"Charisma Experience ",
Player.charisma_exp_mult,
Player.charisma_exp_mult * mults.charisma_exp_mult,
1,
Settings.theme.cha,
],
];
const rightColData: MultiplierListItemData[] = [
...[
[
"Hacknet Node production ",
Player.hacknet_node_money_mult,
Player.hacknet_node_money_mult * mults.hacknet_node_money_mult,
BitNodeMultipliers.HacknetNodeMoney,
],
[
"Hacknet Node purchase cost ",
Player.hacknet_node_purchase_cost_mult,
Player.hacknet_node_purchase_cost_mult * mults.hacknet_node_purchase_cost_mult,
1,
],
[
"Hacknet Node RAM upgrade cost ",
Player.hacknet_node_ram_cost_mult,
Player.hacknet_node_ram_cost_mult * mults.hacknet_node_ram_cost_mult,
1,
],
[
"Hacknet Node Core purchase cost ",
Player.hacknet_node_core_cost_mult,
Player.hacknet_node_core_cost_mult * mults.hacknet_node_core_cost_mult,
1,
],
[
"Hacknet Node level upgrade cost ",
Player.hacknet_node_level_cost_mult,
Player.hacknet_node_level_cost_mult * mults.hacknet_node_level_cost_mult,
1,
],
["Company reputation gain ", Player.company_rep_mult, Player.company_rep_mult * mults.company_rep_mult, 1],
[
"Faction reputation gain ",
Player.faction_rep_mult,
Player.faction_rep_mult * mults.faction_rep_mult,
BitNodeMultipliers.FactionWorkRepGain,
],
].map((data): MultiplierListItemData => (data as any).concat([Settings.theme.primary])),
[
"Salary ",
Player.work_money_mult,
Player.work_money_mult * mults.work_money_mult,
BitNodeMultipliers.CompanyWorkMoney,
Settings.theme.money,
],
[
"Crime success ",
Player.crime_success_mult,
Player.crime_success_mult * mults.crime_success_mult,
1,
Settings.theme.combat,
],
[
"Crime money ",
Player.crime_money_mult,
Player.crime_money_mult * mults.crime_money_mult,
BitNodeMultipliers.CrimeMoney,
Settings.theme.money,
],
];
if (Player.canAccessBladeburner()) {
rightColData.push(
...[
[
"Bladeburner Success Chance",
Player.bladeburner_success_chance_mult,
Player.bladeburner_success_chance_mult * mults.bladeburner_success_chance_mult,
1,
],
[
"Bladeburner Max Stamina",
Player.bladeburner_max_stamina_mult,
Player.bladeburner_max_stamina_mult * mults.bladeburner_max_stamina_mult,
1,
],
[
"Bladeburner Stamina Gain",
Player.bladeburner_stamina_gain_mult,
Player.bladeburner_stamina_gain_mult * mults.bladeburner_stamina_gain_mult,
1,
],
[
"Bladeburner Field Analysis",
Player.bladeburner_analysis_mult,
Player.bladeburner_analysis_mult * mults.bladeburner_analysis_mult,
1,
],
].map((data): MultiplierListItemData => (data as any).concat([Settings.theme.primary])),
);
}
function InfiltrationMults(): React.ReactElement {
return (
<>
<MultiplierTable
rows={[
[
"Infiltrator Rep reward",
Player.infiltration_rep_mult,
Player.infiltration_rep_mult * mults.infiltration_rep_mult,
1,
],
[
"Infiltration sell",
Player.infiltration_sell_mult,
Player.infiltration_sell_mult * mults.infiltration_sell_mult,
1,
],
[
"Infiltration trade",
Player.infiltration_trade_mult,
Player.infiltration_trade_mult * mults.infiltration_trade_mult,
1,
],
[
"Infiltration minigame timer",
Player.infiltration_timer_mult,
Player.infiltration_timer_mult * mults.infiltration_timer_mult,
1,
],
[
"Infiltration minigame health reduction",
Player.infiltration_health_reduction_mult,
-1 * (1 - Player.infiltration_health_reduction_mult * mults.infiltration_health_reduction_mult),
1,
],
]}
/>
<br />
</>
);
}
rightColData.push(
...[
[
"Infiltrator Rep reward",
Player.infiltration_rep_mult,
Player.infiltration_rep_mult * mults.infiltration_rep_mult,
1,
],
[
"Infiltration sell",
Player.infiltration_sell_mult,
Player.infiltration_sell_mult * mults.infiltration_sell_mult,
1,
],
[
"Infiltration trade",
Player.infiltration_trade_mult,
Player.infiltration_trade_mult * mults.infiltration_trade_mult,
1,
],
[
"Infiltration minigame timer",
Player.infiltration_timer_mult,
Player.infiltration_timer_mult * mults.infiltration_timer_mult,
1,
],
[
"Infiltration minigame health reduction",
Player.infiltration_health_reduction_mult,
-1 * (1 - Player.infiltration_health_reduction_mult * mults.infiltration_health_reduction_mult),
1,
],
].map((data): MultiplierListItemData => (data as any).concat([Settings.theme.primary])),
);
const hasLeftImprovements = +!!(leftColData.filter((item) => item[2] !== 0).length > 0),
hasRightImprovements = +!!(rightColData.filter((item) => item[2] !== 0).length > 0);
return (
<>
<Typography variant="h4">Multipliers</Typography>
<Box mx={2}>
<MultiplierTable
rows={[
["Hacking Chance ", Player.hacking_chance_mult, Player.hacking_chance_mult * mults.hacking_chance_mult, 1],
["Hacking Speed ", Player.hacking_speed_mult, Player.hacking_speed_mult * mults.hacking_speed_mult, 1],
["Hacking Money ", Player.hacking_money_mult, Player.hacking_money_mult * mults.hacking_money_mult, 1],
["Hacking Growth ", Player.hacking_grow_mult, Player.hacking_grow_mult * mults.hacking_grow_mult, 1],
]}
/>
<br />
<MultiplierTable
rows={[
[
"Hacking Level ",
Player.hacking_mult,
Player.hacking_mult * mults.hacking_mult,
BitNodeMultipliers.HackingLevelMultiplier,
],
[
"Hacking Experience ",
Player.hacking_exp_mult,
Player.hacking_exp_mult * mults.hacking_exp_mult,
BitNodeMultipliers.HackExpGain,
],
]}
/>
<br />
<MultiplierTable
rows={[
[
"Strength Level ",
Player.strength_mult,
Player.strength_mult * mults.strength_mult,
BitNodeMultipliers.StrengthLevelMultiplier,
],
["Strength Experience ", Player.strength_exp_mult, Player.strength_exp_mult * mults.strength_exp_mult, 1],
]}
/>
<br />
<MultiplierTable
rows={[
[
"Defense Level ",
Player.defense_mult,
Player.defense_mult * mults.defense_mult,
BitNodeMultipliers.DefenseLevelMultiplier,
],
["Defense Experience ", Player.defense_exp_mult, Player.defense_exp_mult * mults.defense_exp_mult, 1],
]}
/>
<br />
<MultiplierTable
rows={[
[
"Dexterity Level ",
Player.dexterity_mult,
Player.dexterity_mult * mults.dexterity_mult,
BitNodeMultipliers.DexterityLevelMultiplier,
],
[
"Dexterity Experience ",
Player.dexterity_exp_mult,
Player.dexterity_exp_mult * mults.dexterity_exp_mult,
1,
],
]}
/>
<br />
<MultiplierTable
rows={[
[
"Agility Level ",
Player.agility_mult,
Player.agility_mult * mults.agility_mult,
BitNodeMultipliers.AgilityLevelMultiplier,
],
["Agility Experience ", Player.agility_exp_mult, Player.agility_exp_mult * mults.agility_exp_mult, 1],
]}
/>
<br />
<MultiplierTable
rows={[
[
"Charisma Level ",
Player.charisma_mult,
Player.charisma_mult * mults.charisma_mult,
BitNodeMultipliers.CharismaLevelMultiplier,
],
["Charisma Experience ", Player.charisma_exp_mult, Player.charisma_exp_mult * mults.charisma_exp_mult, 1],
]}
/>
<br />
<MultiplierTable
rows={[
[
"Hacknet Node production ",
Player.hacknet_node_money_mult,
Player.hacknet_node_money_mult * mults.hacknet_node_money_mult,
BitNodeMultipliers.HacknetNodeMoney,
],
[
"Hacknet Node purchase cost ",
Player.hacknet_node_purchase_cost_mult,
Player.hacknet_node_purchase_cost_mult * mults.hacknet_node_purchase_cost_mult,
1,
],
[
"Hacknet Node RAM upgrade cost ",
Player.hacknet_node_ram_cost_mult,
Player.hacknet_node_ram_cost_mult * mults.hacknet_node_ram_cost_mult,
1,
],
[
"Hacknet Node Core purchase cost ",
Player.hacknet_node_core_cost_mult,
Player.hacknet_node_core_cost_mult * mults.hacknet_node_core_cost_mult,
1,
],
[
"Hacknet Node level upgrade cost ",
Player.hacknet_node_level_cost_mult,
Player.hacknet_node_level_cost_mult * mults.hacknet_node_level_cost_mult,
1,
],
]}
/>
<br />
<MultiplierTable
rows={[
["Company reputation gain ", Player.company_rep_mult, Player.company_rep_mult * mults.company_rep_mult, 1],
[
"Faction reputation gain ",
Player.faction_rep_mult,
Player.faction_rep_mult * mults.faction_rep_mult,
BitNodeMultipliers.FactionWorkRepGain,
],
[
"Salary ",
Player.work_money_mult,
Player.work_money_mult * mults.work_money_mult,
BitNodeMultipliers.CompanyWorkMoney,
],
]}
/>
<br />
<MultiplierTable
rows={[
["Crime success ", Player.crime_success_mult, Player.crime_success_mult * mults.crime_success_mult, 1],
[
"Crime money ",
Player.crime_money_mult,
Player.crime_money_mult * mults.crime_money_mult,
BitNodeMultipliers.CrimeMoney,
],
]}
/>
<br />
<BladeburnerMults />
<InfiltrationMults />
</Box>
</>
<Paper
sx={{
p: 1,
maxHeight: 400,
overflowY: "scroll",
display: "grid",
gridTemplateColumns: `repeat(${hasLeftImprovements + hasRightImprovements}, 1fr)`,
}}
>
<MultiplierList rows={leftColData} />
<MultiplierList rows={rightColData} />
</Paper>
);
}
+38 -7
View File
@@ -2,14 +2,11 @@
* React component for displaying all of the player's purchased (but not installed)
* Augmentations on the Augmentations UI.
*/
import { List, ListItemText, Paper, Tooltip, Typography } from "@mui/material";
import * as React from "react";
import { Player } from "../../Player";
import { Augmentations } from "../Augmentations";
import { AugmentationNames } from "../data/AugmentationNames";
import { Player } from "../../Player";
import { AugmentationAccordion } from "../../ui/React/AugmentationAccordion";
import List from "@mui/material/List";
export function PurchasedAugmentations(): React.ReactElement {
const augs: React.ReactElement[] = [];
@@ -23,14 +20,48 @@ export function PurchasedAugmentations(): React.ReactElement {
}
for (let i = 0; i < Player.queuedAugmentations.length; i++) {
const ownedAug = Player.queuedAugmentations[i];
let displayName = ownedAug.name;
if (ownedAug.name === AugmentationNames.NeuroFluxGovernor && i !== nfgIndex) continue;
const aug = Augmentations[ownedAug.name];
let level = null;
if (ownedAug.name === AugmentationNames.NeuroFluxGovernor) {
level = ownedAug.level;
displayName += ` - Level ${level}`;
}
augs.push(<AugmentationAccordion key={aug.name} aug={aug} level={level} />);
augs.push(
<Tooltip
title={
<Typography>
{(() => {
const info = typeof aug.info === "string" ? <span>{aug.info}</span> : aug.info;
const tooltip = (
<>
{info}
<br />
<br />
{aug.stats}
</>
);
return tooltip;
})()}
</Typography>
}
enterNextDelay={500}
key={displayName}
>
<ListItemText sx={{ px: 2, py: 1 }} primary={displayName} />
</Tooltip>,
);
}
return <List dense>{augs}</List>;
return (
<Paper sx={{ py: 1, maxHeight: 400, overflowY: "scroll" }}>
<List sx={{ height: 400, overflowY: "scroll" }} disablePadding>
{augs}
</List>
</Paper>
);
}
+154 -16
View File
@@ -1,21 +1,159 @@
import React from "react";
import { SourceFileMinus1 } from "./SourceFileMinus1";
import { OwnedSourceFiles } from "./OwnedSourceFiles";
import List from "@mui/material/List";
import Typography from "@mui/material/Typography";
import { ListItemButton, ListItemText, Paper } from "@mui/material";
import Box from "@mui/material/Box";
import List from "@mui/material/List";
import Typography from "@mui/material/Typography";
import React, { useState } from "react";
import { Exploit, ExploitName } from "../../Exploits/Exploit";
import { Player } from "../../Player";
import { OwnedAugmentationsOrderSetting } from "../../Settings/SettingEnums";
import { Settings } from "../../Settings/Settings";
import { SourceFile } from "../../SourceFile/SourceFile";
import { SourceFiles } from "../../SourceFile/SourceFiles";
interface SfMinus1 {
info: React.ReactElement;
n: number;
name: string;
lvl: number;
}
const safeGetSf = (sfNum: number): SourceFile | SfMinus1 | null => {
if (sfNum === -1) {
const sfMinus1: SfMinus1 = {
info: (
<>
This Source-File can only be acquired with obscure knowledge of the game, javascript, and the web ecosystem.
<br />
<br />
It increases all of the player's multipliers by 0.1%
<br />
<br />
You have found the following exploits:
<br />
<br />
{Player.exploits.map((c: Exploit) => (
<React.Fragment key={c}>
* {ExploitName(c)}
<br />
</React.Fragment>
))}
</>
),
lvl: Player.exploits.length,
n: -1,
name: "Source-File -1: Exploits in the BitNodes",
};
return sfMinus1;
}
const srcFileKey = "SourceFile" + sfNum;
const sfObj = SourceFiles[srcFileKey];
if (sfObj == null) {
console.error(`Invalid source file number: ${sfNum}`);
return null;
}
return sfObj;
};
const getMaxLevel = (sfObj: SourceFile | SfMinus1): string | number => {
let maxLevel;
switch (sfObj.n) {
case 12:
maxLevel = "∞";
break;
case -1:
maxLevel = Object.keys(Exploit).length;
break;
default:
maxLevel = "3";
}
return maxLevel;
};
export function SourceFilesElement(): React.ReactElement {
const sourceSfs = Player.sourceFiles.slice();
const exploits = Player.exploits;
// Create a fake SF for -1, if "owned"
if (exploits.length > 0) {
sourceSfs.unshift({
n: -1,
lvl: exploits.length,
});
}
if (Settings.OwnedAugmentationsOrder === OwnedAugmentationsOrderSetting.Alphabetically) {
sourceSfs.sort((sf1, sf2) => {
return sf1.n - sf2.n;
});
}
if (sourceSfs.length === 0) {
return <></>;
}
const [selectedSf, setSelectedSf] = useState(sourceSfs[0]);
export function SourceFiles(): React.ReactElement {
return (
<>
<Typography variant="h4">Source Files</Typography>
<Box mx={2}>
<List dense>
<SourceFileMinus1 />
<OwnedSourceFiles />
</List>
</Box>
</>
<Box sx={{ width: "100%", mt: 1 }}>
<Paper sx={{ p: 1 }}>
<Typography variant="h5">Source Files</Typography>
</Paper>
<Paper sx={{ display: "grid", gridTemplateColumns: "1fr 3fr" }}>
<Box>
<List
sx={{ height: 400, overflowY: "scroll", borderRight: `1px solid ${Settings.theme.welllight}` }}
disablePadding
>
{sourceSfs.map((e, i) => {
const sfObj = safeGetSf(e.n);
if (!sfObj) return;
const maxLevel = getMaxLevel(sfObj);
return (
<ListItemButton
key={i + 1}
onClick={() => setSelectedSf(e)}
selected={selectedSf.n === e.n}
sx={{ py: 0 }}
>
<ListItemText
disableTypography
primary={<Typography>{sfObj.name}</Typography>}
secondary={
<Typography>
Level {e.lvl} / {maxLevel}
</Typography>
}
/>
</ListItemButton>
);
})}
</List>
</Box>
<Box sx={{ m: 1 }}>
<Typography variant="h6" sx={{ display: "flex", alignItems: "center", flexWrap: "wrap" }}>
{safeGetSf(selectedSf.n)?.name}
</Typography>
<Typography sx={{ maxHeight: 350, overflowY: "scroll" }}>
{(() => {
const sfObj = safeGetSf(selectedSf.n);
if (!sfObj) return;
const maxLevel = getMaxLevel(sfObj);
return (
<>
Level {selectedSf.lvl} / {maxLevel}
<br />
<br />
{sfObj.info}
</>
);
})()}
</Typography>
</Box>
</Paper>
</Box>
);
}