mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-22 23:53:48 +01:00
Merge pull request #3545 from nickofolas/improvement/purchase-augs-ui
UI: Redesign purchasable Augmentations
This commit is contained in:
commit
d0d700077a
@ -251,7 +251,7 @@ export const initGeneralAugmentations = (): Augmentation[] => [
|
||||
moneyCost: 1.15e8,
|
||||
repCost: 2.75e4,
|
||||
info: "The latest version of the 'Augmented Targeting' implant adds the ability to lock-on and track threats.",
|
||||
prereqs: [AugmentationNames.Targeting2],
|
||||
prereqs: [AugmentationNames.Targeting2, AugmentationNames.Targeting1],
|
||||
dexterity_mult: 1.3,
|
||||
factions: [
|
||||
FactionNames.TheDarkArmy,
|
||||
@ -348,7 +348,7 @@ export const initGeneralAugmentations = (): Augmentation[] => [
|
||||
info:
|
||||
"The latest version of the 'Combat Rib' augmentation releases advanced anabolic steroids that " +
|
||||
"improve muscle mass and physical performance while being safe and free of side effects.",
|
||||
prereqs: [AugmentationNames.CombatRib2],
|
||||
prereqs: [AugmentationNames.CombatRib2, AugmentationNames.CombatRib1],
|
||||
strength_mult: 1.18,
|
||||
defense_mult: 1.18,
|
||||
factions: [
|
||||
@ -682,7 +682,7 @@ export const initGeneralAugmentations = (): Augmentation[] => [
|
||||
"This upgraded firmware allows the Embedded Netburner Module to control information on " +
|
||||
"a network by re-routing traffic, spoofing IP addresses, and altering the data inside network " +
|
||||
"packets.",
|
||||
prereqs: [AugmentationNames.ENMCore],
|
||||
prereqs: [AugmentationNames.ENMCore, AugmentationNames.ENM],
|
||||
hacking_speed_mult: 1.05,
|
||||
hacking_money_mult: 1.3,
|
||||
hacking_chance_mult: 1.05,
|
||||
@ -707,7 +707,7 @@ export const initGeneralAugmentations = (): Augmentation[] => [
|
||||
"The Core V3 library is an implant that upgrades the firmware of the Embedded Netburner Module. " +
|
||||
"This upgraded firmware allows the Embedded Netburner Module to seamlessly inject code into " +
|
||||
"any device on a network.",
|
||||
prereqs: [AugmentationNames.ENMCoreV2],
|
||||
prereqs: [AugmentationNames.ENMCoreV2, AugmentationNames.ENMCore, AugmentationNames.ENM],
|
||||
hacking_speed_mult: 1.05,
|
||||
hacking_money_mult: 1.4,
|
||||
hacking_chance_mult: 1.1,
|
||||
@ -835,7 +835,7 @@ export const initGeneralAugmentations = (): Augmentation[] => [
|
||||
"are a set of specialized microprocessors that are attached to " +
|
||||
"neurons in the brain. These chips process neural signals to quickly and automatically perform specific computations " +
|
||||
"so that the brain doesn't have to.",
|
||||
prereqs: [AugmentationNames.CranialSignalProcessorsG2],
|
||||
prereqs: [AugmentationNames.CranialSignalProcessorsG2, AugmentationNames.CranialSignalProcessorsG1],
|
||||
hacking_speed_mult: 1.02,
|
||||
hacking_money_mult: 1.15,
|
||||
hacking_mult: 1.09,
|
||||
@ -850,7 +850,11 @@ export const initGeneralAugmentations = (): Augmentation[] => [
|
||||
"are a set of specialized microprocessors that are attached to " +
|
||||
"neurons in the brain. These chips process neural signals to quickly and automatically perform specific computations " +
|
||||
"so that the brain doesn't have to.",
|
||||
prereqs: [AugmentationNames.CranialSignalProcessorsG3],
|
||||
prereqs: [
|
||||
AugmentationNames.CranialSignalProcessorsG3,
|
||||
AugmentationNames.CranialSignalProcessorsG2,
|
||||
AugmentationNames.CranialSignalProcessorsG1,
|
||||
],
|
||||
hacking_speed_mult: 1.02,
|
||||
hacking_money_mult: 1.2,
|
||||
hacking_grow_mult: 1.25,
|
||||
@ -865,7 +869,12 @@ export const initGeneralAugmentations = (): Augmentation[] => [
|
||||
"are a set of specialized microprocessors that are attached to " +
|
||||
"neurons in the brain. These chips process neural signals to quickly and automatically perform specific computations " +
|
||||
"so that the brain doesn't have to.",
|
||||
prereqs: [AugmentationNames.CranialSignalProcessorsG4],
|
||||
prereqs: [
|
||||
AugmentationNames.CranialSignalProcessorsG4,
|
||||
AugmentationNames.CranialSignalProcessorsG3,
|
||||
AugmentationNames.CranialSignalProcessorsG2,
|
||||
AugmentationNames.CranialSignalProcessorsG1,
|
||||
],
|
||||
hacking_mult: 1.3,
|
||||
hacking_money_mult: 1.25,
|
||||
hacking_grow_mult: 1.75,
|
||||
@ -1962,7 +1971,7 @@ export const initChurchOfTheMachineGodAugmentations = (): Augmentation[] => [
|
||||
"You will become greater than the sum of our parts. As One. Embrace your gift " +
|
||||
"fully and wholly free of it's accursed toll. Serenity brings tranquility the form " +
|
||||
"of no longer suffering a stat penalty. ",
|
||||
prereqs: [AugmentationNames.StaneksGift2],
|
||||
prereqs: [AugmentationNames.StaneksGift2, AugmentationNames.StaneksGift1],
|
||||
isSpecial: true,
|
||||
hacking_chance_mult: 1 / 0.95,
|
||||
hacking_speed_mult: 1 / 0.95,
|
||||
|
264
src/Augmentation/ui/PurchasableAugmentations.tsx
Normal file
264
src/Augmentation/ui/PurchasableAugmentations.tsx
Normal file
@ -0,0 +1,264 @@
|
||||
/**
|
||||
* React component for displaying a single augmentation for purchase through
|
||||
* the faction UI
|
||||
*/
|
||||
import { CheckBox, CheckBoxOutlineBlank, CheckCircle, Info, NewReleases, Report } from "@mui/icons-material";
|
||||
import { Box, Button, Container, Paper, Tooltip, Typography } from "@mui/material";
|
||||
import React, { useState } from "react";
|
||||
import { getNextNeuroFluxLevel } from "../AugmentationHelpers";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
import { Augmentation } from "../Augmentation";
|
||||
import { Augmentations } from "../Augmentations";
|
||||
import { AugmentationNames } from "../data/AugmentationNames";
|
||||
import { PurchaseAugmentationModal } from "./PurchaseAugmentationModal";
|
||||
|
||||
interface IPreReqsProps {
|
||||
player: IPlayer;
|
||||
aug: Augmentation;
|
||||
}
|
||||
|
||||
const PreReqs = (props: IPreReqsProps): React.ReactElement => {
|
||||
const ownedPreReqs = props.aug.prereqs.filter((aug) => props.player.hasAugmentation(aug));
|
||||
const hasPreReqs = props.aug.prereqs.length > 0 && ownedPreReqs.length === props.aug.prereqs.length;
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
title={
|
||||
<>
|
||||
<Typography sx={{ color: Settings.theme.money }}>
|
||||
This Augmentation has the following pre-requisite(s):
|
||||
</Typography>
|
||||
{props.aug.prereqs.map((preAug) => (
|
||||
<Requirement
|
||||
fulfilled={props.player.hasAugmentation(preAug)}
|
||||
value={preAug}
|
||||
color={Settings.theme.money}
|
||||
key={preAug}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
color: hasPreReqs ? Settings.theme.successlight : Settings.theme.error,
|
||||
}}
|
||||
>
|
||||
{hasPreReqs ? (
|
||||
<>
|
||||
<CheckCircle fontSize="small" sx={{ mr: 1 }} />
|
||||
Pre-requisites Owned
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Report fontSize="small" sx={{ mr: 1 }} />
|
||||
Missing {props.aug.prereqs.length - ownedPreReqs.length} pre-requisite(s)
|
||||
</>
|
||||
)}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
interface IExclusiveProps {
|
||||
player: IPlayer;
|
||||
aug: Augmentation;
|
||||
}
|
||||
|
||||
const Exclusive = (props: IExclusiveProps): React.ReactElement => {
|
||||
return (
|
||||
<Tooltip
|
||||
title={
|
||||
<>
|
||||
<Typography sx={{ color: Settings.theme.money }}>
|
||||
This Augmentation can only be acquired from the following source(s):
|
||||
</Typography>
|
||||
<ul>
|
||||
<Typography sx={{ color: Settings.theme.money }}>
|
||||
<li>
|
||||
<b>{props.aug.factions[0]}</b> faction
|
||||
</li>
|
||||
{props.player.canAccessGang() && !props.aug.isSpecial && (
|
||||
<li>
|
||||
Certain <b>gangs</b>
|
||||
</li>
|
||||
)}
|
||||
{props.player.canAccessGrafting() &&
|
||||
!props.aug.isSpecial &&
|
||||
props.aug.name !== AugmentationNames.TheRedPill && (
|
||||
<li>
|
||||
<b>Grafting</b>
|
||||
</li>
|
||||
)}
|
||||
</Typography>
|
||||
</ul>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<NewReleases sx={{ ml: 1, color: Settings.theme.money, transform: "rotate(180deg)" }} />
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
interface IReqProps {
|
||||
value: string;
|
||||
color: string;
|
||||
fulfilled: boolean;
|
||||
}
|
||||
|
||||
const Requirement = (props: IReqProps): React.ReactElement => {
|
||||
return (
|
||||
<Typography sx={{ display: "flex", alignItems: "center", color: props.color }}>
|
||||
{props.fulfilled ? <CheckBox sx={{ mr: 1 }} /> : <CheckBoxOutlineBlank sx={{ mr: 1 }} />}
|
||||
{props.value}
|
||||
</Typography>
|
||||
);
|
||||
};
|
||||
|
||||
interface IPurchasableAugsProps {
|
||||
augNames: string[];
|
||||
ownedAugNames: string[];
|
||||
player: IPlayer;
|
||||
|
||||
canPurchase: (player: IPlayer, aug: Augmentation) => boolean;
|
||||
purchaseAugmentation: (player: IPlayer, aug: Augmentation, showModal: (open: boolean) => void) => void;
|
||||
|
||||
rep?: number;
|
||||
sleeveAugs?: boolean;
|
||||
faction?: Faction;
|
||||
}
|
||||
|
||||
export const PurchasableAugmentations = (props: IPurchasableAugsProps): React.ReactElement => {
|
||||
return (
|
||||
<Container
|
||||
maxWidth="lg"
|
||||
disableGutters
|
||||
sx={{ mx: 0, display: "grid", gridTemplateColumns: "repeat(1, 1fr)", gap: 1 }}
|
||||
>
|
||||
{props.augNames.map((augName: string) => (
|
||||
<PurchasableAugmentation key={augName} parent={props} augName={augName} owned={false} />
|
||||
))}
|
||||
{props.ownedAugNames.map((augName: string) => (
|
||||
<PurchasableAugmentation key={augName} parent={props} augName={augName} owned={true} />
|
||||
))}
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
interface IPurchasableAugProps {
|
||||
parent: IPurchasableAugsProps;
|
||||
augName: string;
|
||||
owned: boolean;
|
||||
}
|
||||
|
||||
export function PurchasableAugmentation(props: IPurchasableAugProps): React.ReactElement {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const aug = Augmentations[props.augName];
|
||||
|
||||
const cost = props.parent.sleeveAugs ? aug.startingCost : aug.baseCost;
|
||||
|
||||
const info = typeof aug.info === "string" ? <span>{aug.info}</span> : aug.info;
|
||||
const description = (
|
||||
<>
|
||||
{info}
|
||||
<br />
|
||||
<br />
|
||||
{aug.stats}
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<Paper
|
||||
sx={{
|
||||
p: 1,
|
||||
display: "grid",
|
||||
gridTemplateColumns: "minmax(0, 4fr) 1fr",
|
||||
gap: 1,
|
||||
opacity: props.owned ? 0.75 : 1,
|
||||
}}
|
||||
>
|
||||
<>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<Button
|
||||
onClick={() =>
|
||||
props.parent.purchaseAugmentation(props.parent.player, aug, (open): void => {
|
||||
setOpen(open);
|
||||
})
|
||||
}
|
||||
disabled={!props.parent.canPurchase(props.parent.player, aug) || props.owned}
|
||||
sx={{ width: "48px", height: "48px", float: "left", clear: "none", mr: 1 }}
|
||||
>
|
||||
{props.owned ? "Owned" : "Buy"}
|
||||
</Button>
|
||||
|
||||
<Box sx={{ maxWidth: props.owned ? "100%" : "85%" }}>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<Tooltip
|
||||
title={
|
||||
<>
|
||||
<Typography variant="h5">
|
||||
{props.augName}
|
||||
{props.augName === AugmentationNames.NeuroFluxGovernor && ` - Level ${getNextNeuroFluxLevel()}`}
|
||||
</Typography>
|
||||
<Typography>{description}</Typography>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Info sx={{ mr: 1 }} color="info" />
|
||||
</Tooltip>
|
||||
<Typography
|
||||
variant="h6"
|
||||
sx={{
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
{aug.name}
|
||||
{aug.name === AugmentationNames.NeuroFluxGovernor && ` - Level ${getNextNeuroFluxLevel()}`}
|
||||
</Typography>
|
||||
{aug.factions.length === 1 && !props.parent.sleeveAugs && (
|
||||
<Exclusive player={props.parent.player} aug={aug} />
|
||||
)}
|
||||
</Box>
|
||||
|
||||
{aug.prereqs.length > 0 && !props.parent.sleeveAugs && <PreReqs player={props.parent.player} aug={aug} />}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{props.owned || (
|
||||
<Box sx={{ display: "grid", alignItems: "center", justifyItems: "left" }}>
|
||||
<Requirement
|
||||
fulfilled={aug.baseCost === 0 || props.parent.player.money > cost}
|
||||
value={numeralWrapper.formatMoney(cost)}
|
||||
color={Settings.theme.money}
|
||||
/>
|
||||
{props.parent.rep !== undefined && (
|
||||
<Requirement
|
||||
fulfilled={props.parent.rep >= aug.baseRepRequirement}
|
||||
value={`${numeralWrapper.formatReputation(aug.baseRepRequirement)} rep`}
|
||||
color={Settings.theme.rep}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{Settings.SuppressBuyAugmentationConfirmation || (
|
||||
<PurchaseAugmentationModal
|
||||
open={open}
|
||||
onClose={() => setOpen(false)}
|
||||
faction={props.parent.faction}
|
||||
aug={aug}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
</Paper>
|
||||
);
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
import React from "react";
|
||||
|
||||
import { Augmentation } from "../../Augmentation/Augmentation";
|
||||
import { Faction } from "../Faction";
|
||||
import { purchaseAugmentation } from "../FactionHelpers";
|
||||
import { isRepeatableAug } from "../../Augmentation/AugmentationHelpers";
|
||||
import { Augmentation } from "../Augmentation";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
import { purchaseAugmentation } from "../../Faction/FactionHelpers";
|
||||
import { isRepeatableAug } from "../AugmentationHelpers";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { use } from "../../ui/Context";
|
||||
@ -13,21 +13,23 @@ import Button from "@mui/material/Button";
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
faction: Faction;
|
||||
aug: Augmentation;
|
||||
rerender: () => void;
|
||||
faction?: Faction;
|
||||
aug?: Augmentation;
|
||||
}
|
||||
|
||||
export function PurchaseAugmentationModal(props: IProps): React.ReactElement {
|
||||
if (typeof props.aug === "undefined" || typeof props.faction === "undefined") {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const player = use.Player();
|
||||
|
||||
function buy(): void {
|
||||
if (!isRepeatableAug(props.aug) && player.hasAugmentation(props.aug)) {
|
||||
if (!isRepeatableAug(props.aug as Augmentation) && player.hasAugmentation(props.aug as Augmentation)) {
|
||||
return;
|
||||
}
|
||||
|
||||
purchaseAugmentation(props.aug, props.faction);
|
||||
props.rerender();
|
||||
purchaseAugmentation(props.aug as Augmentation, props.faction as Faction);
|
||||
props.onClose();
|
||||
}
|
||||
|
@ -54,36 +54,15 @@ export function joinFaction(faction: Faction): void {
|
||||
//Returns a boolean indicating whether the player has the prerequisites for the
|
||||
//specified Augmentation
|
||||
export function hasAugmentationPrereqs(aug: Augmentation): boolean {
|
||||
let hasPrereqs = true;
|
||||
if (aug.prereqs && aug.prereqs.length > 0) {
|
||||
for (let i = 0; i < aug.prereqs.length; ++i) {
|
||||
const prereqAug = Augmentations[aug.prereqs[i]];
|
||||
if (prereqAug == null) {
|
||||
console.error(`Invalid prereq Augmentation ${aug.prereqs[i]}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Player.hasAugmentation(prereqAug, true) === false) {
|
||||
hasPrereqs = false;
|
||||
|
||||
// Check if the aug is purchased
|
||||
for (let j = 0; j < Player.queuedAugmentations.length; ++j) {
|
||||
if (Player.queuedAugmentations[j].name === prereqAug.name) {
|
||||
hasPrereqs = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hasPrereqs;
|
||||
return aug.prereqs.every((aug) => Player.hasAugmentation(aug));
|
||||
}
|
||||
|
||||
export function purchaseAugmentation(aug: Augmentation, fac: Faction, sing = false): string {
|
||||
const hasPrereqs = hasAugmentationPrereqs(aug);
|
||||
if (!hasPrereqs) {
|
||||
const txt = `You must first purchase or install ${aug.prereqs.join(",")} before you can purchase this one.`;
|
||||
const txt = `You must first purchase or install ${aug.prereqs
|
||||
.filter((req) => !Player.hasAugmentation(req))
|
||||
.join(",")} before you can purchase this one.`;
|
||||
if (sing) {
|
||||
return txt;
|
||||
} else {
|
||||
|
@ -1,30 +1,21 @@
|
||||
/**
|
||||
* Root React Component for displaying a faction's "Purchase Augmentations" page
|
||||
*/
|
||||
import { Box, Button, Tooltip, Typography, Paper, Container } from "@mui/material";
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { PurchaseableAugmentation } from "./PurchaseableAugmentation";
|
||||
|
||||
import { getGenericAugmentationPriceMultiplier } from "../../Augmentation/AugmentationHelpers";
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
import { Faction } from "../Faction";
|
||||
import { PurchasableAugmentations } from "../../Augmentation/ui/PurchasableAugmentations";
|
||||
import { PurchaseAugmentationsOrderSetting } from "../../Settings/SettingEnums";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { hasAugmentationPrereqs, getFactionAugmentationsFiltered } from "../FactionHelpers";
|
||||
|
||||
import { use } from "../../ui/Context";
|
||||
import { Reputation } from "../../ui/React/Reputation";
|
||||
import { Favor } from "../../ui/React/Favor";
|
||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||
|
||||
import Box from "@mui/material/Box";
|
||||
import Button from "@mui/material/Button";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import TableBody from "@mui/material/TableBody";
|
||||
import Table from "@mui/material/Table";
|
||||
import { getGenericAugmentationPriceMultiplier } from "../../Augmentation/AugmentationHelpers";
|
||||
import { Favor } from "../../ui/React/Favor";
|
||||
import { Reputation } from "../../ui/React/Reputation";
|
||||
import { FactionNames } from "../data/FactionNames";
|
||||
import { Faction } from "../Faction";
|
||||
import { getFactionAugmentationsFiltered, hasAugmentationPrereqs, purchaseAugmentation } from "../FactionHelpers";
|
||||
|
||||
type IProps = {
|
||||
faction: Faction;
|
||||
@ -137,38 +128,12 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
|
||||
aug === AugmentationNames.NeuroFluxGovernor ||
|
||||
(!player.augmentations.some((a) => a.name === aug) && !player.queuedAugmentations.some((a) => a.name === aug)),
|
||||
);
|
||||
|
||||
const purchaseableAugmentation = (aug: string, owned = false): React.ReactNode => {
|
||||
return (
|
||||
<PurchaseableAugmentation
|
||||
augName={aug}
|
||||
faction={props.faction}
|
||||
key={aug}
|
||||
p={player}
|
||||
rerender={rerender}
|
||||
owned={owned}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const augListElems = purchasable.map((aug) => purchaseableAugmentation(aug));
|
||||
|
||||
let ownedElem = <></>;
|
||||
const owned = augs.filter((aug: string) => !purchasable.includes(aug));
|
||||
if (owned.length !== 0) {
|
||||
ownedElem = (
|
||||
<>
|
||||
<br />
|
||||
<Typography variant="h4">Purchased Augmentations</Typography>
|
||||
<Typography>This faction also offers these augmentations but you already own them.</Typography>
|
||||
{owned.map((aug) => purchaseableAugmentation(aug, true))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const multiplierComponent =
|
||||
props.faction.name !== FactionNames.ShadowsOfAnarchy ? (
|
||||
<Typography>
|
||||
Price multiplier: x {numeralWrapper.formatMultiplier(getGenericAugmentationPriceMultiplier())}
|
||||
<b>Price multiplier:</b> x {numeralWrapper.formatReallyBigNumber(getGenericAugmentationPriceMultiplier())}
|
||||
</Typography>
|
||||
) : (
|
||||
<></>
|
||||
@ -176,42 +141,77 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button onClick={props.routeToMainPage}>Back</Button>
|
||||
<Typography variant="h4">Faction Augmentations</Typography>
|
||||
<Typography>
|
||||
These are all of the Augmentations that are available to purchase from {props.faction.name}. Augmentations are
|
||||
powerful upgrades that will enhance your abilities.
|
||||
<br />
|
||||
Reputation: <Reputation reputation={props.faction.playerReputation} /> Favor:{" "}
|
||||
<Favor favor={Math.floor(props.faction.favor)} />
|
||||
</Typography>
|
||||
<Box display="flex">
|
||||
<Tooltip
|
||||
title={
|
||||
<Container disableGutters maxWidth="lg" sx={{ mx: 0 }}>
|
||||
<Button onClick={props.routeToMainPage}>Back</Button>
|
||||
<Typography variant="h4">Faction Augmentations</Typography>
|
||||
<Paper sx={{ p: 1, mb: 1 }}>
|
||||
<Typography>
|
||||
These are all of the Augmentations that are available to purchase from <b>{props.faction.name}</b>.
|
||||
Augmentations are powerful upgrades that will enhance your abilities.
|
||||
<br />
|
||||
</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: `repeat(${props.faction.name === FactionNames.ShadowsOfAnarchy ? "2" : "3"}, 1fr)`,
|
||||
justifyItems: "center",
|
||||
my: 1,
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography>
|
||||
The price of every Augmentation increases for every queued Augmentation and it is reset when you
|
||||
install them.
|
||||
</Typography>
|
||||
}
|
||||
>
|
||||
{multiplierComponent}
|
||||
</Tooltip>
|
||||
<Typography>
|
||||
The price of every Augmentation increases for every queued Augmentation and it is reset when you install
|
||||
them.
|
||||
<b>Reputation:</b> <Reputation reputation={props.faction.playerReputation} />
|
||||
</Typography>
|
||||
<Typography>
|
||||
<b>Favor:</b> <Favor favor={Math.floor(props.faction.favor)} />
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box sx={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)" }}>
|
||||
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Cost)}>Sort by Cost</Button>
|
||||
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Reputation)}>
|
||||
Sort by Reputation
|
||||
</Button>
|
||||
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Default)}>
|
||||
Sort by Default Order
|
||||
</Button>
|
||||
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Purchasable)}>
|
||||
Sort by Purchasable
|
||||
</Button>
|
||||
</Box>
|
||||
</Paper>
|
||||
</Container>
|
||||
|
||||
<PurchasableAugmentations
|
||||
augNames={purchasable}
|
||||
ownedAugNames={owned}
|
||||
player={player}
|
||||
canPurchase={(player, aug) => {
|
||||
return (
|
||||
hasAugmentationPrereqs(aug) &&
|
||||
props.faction.playerReputation >= aug.baseRepRequirement &&
|
||||
(aug.baseCost === 0 || player.money > aug.baseCost)
|
||||
);
|
||||
}}
|
||||
purchaseAugmentation={(player, aug, showModal) => {
|
||||
if (!Settings.SuppressBuyAugmentationConfirmation) {
|
||||
showModal(true);
|
||||
} else {
|
||||
purchaseAugmentation(aug, props.faction);
|
||||
rerender();
|
||||
}
|
||||
>
|
||||
{multiplierComponent}
|
||||
</Tooltip>
|
||||
</Box>
|
||||
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Cost)}>Sort by Cost</Button>
|
||||
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Reputation)}>Sort by Reputation</Button>
|
||||
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Default)}>Sort by Default Order</Button>
|
||||
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Purchasable)}>
|
||||
Sort by Purchasable
|
||||
</Button>
|
||||
<br />
|
||||
|
||||
<Table size="small" padding="none">
|
||||
<TableBody>{augListElems}</TableBody>
|
||||
</Table>
|
||||
|
||||
<Table size="small" padding="none">
|
||||
<TableBody>{ownedElem}</TableBody>
|
||||
</Table>
|
||||
}}
|
||||
rep={props.faction.playerReputation}
|
||||
faction={props.faction}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,170 +0,0 @@
|
||||
/**
|
||||
* React component for displaying a single augmentation for purchase through
|
||||
* the faction UI
|
||||
*/
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { hasAugmentationPrereqs, purchaseAugmentation } from "../FactionHelpers";
|
||||
import { PurchaseAugmentationModal } from "./PurchaseAugmentationModal";
|
||||
|
||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||
import { Faction } from "../Faction";
|
||||
import { IPlayer } from "../../PersonObjects/IPlayer";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { Money } from "../../ui/React/Money";
|
||||
import { Reputation } from "../../ui/React/Reputation";
|
||||
|
||||
import { Augmentation as AugFormat } from "../../ui/React/Augmentation";
|
||||
import Button from "@mui/material/Button";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import Box from "@mui/material/Box";
|
||||
import { TableCell } from "../../ui/React/Table";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
import { getNextNeuroFluxLevel } from "../../Augmentation/AugmentationHelpers";
|
||||
|
||||
interface IReqProps {
|
||||
augName: string;
|
||||
p: IPlayer;
|
||||
hasReq: boolean;
|
||||
rep: number;
|
||||
hasRep: boolean;
|
||||
cost: number;
|
||||
hasCost: boolean;
|
||||
}
|
||||
|
||||
function Requirements(props: IReqProps): React.ReactElement {
|
||||
const aug = Augmentations[props.augName];
|
||||
if (!props.hasReq) {
|
||||
return (
|
||||
<TableCell key={1} colSpan={2}>
|
||||
<Typography color="error">
|
||||
Requires{" "}
|
||||
{aug.prereqs.map((aug, i) => (
|
||||
<AugFormat key={i} name={aug} />
|
||||
))}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment key="f">
|
||||
<TableCell key={1}>
|
||||
<Typography>
|
||||
<Money money={props.cost} player={props.p} />
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell key={2}>
|
||||
<Typography color={props.hasRep ? "primary" : "error"}>
|
||||
Requires <Reputation reputation={props.rep} /> faction reputation
|
||||
</Typography>
|
||||
</TableCell>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
augName: string;
|
||||
faction: Faction;
|
||||
p: IPlayer;
|
||||
rerender: () => void;
|
||||
owned?: boolean;
|
||||
}
|
||||
|
||||
export function PurchaseableAugmentation(props: IProps): React.ReactElement {
|
||||
const [open, setOpen] = useState(false);
|
||||
const aug = Augmentations[props.augName];
|
||||
if (aug == null) throw new Error(`aug ${props.augName} does not exists`);
|
||||
|
||||
if (aug == null) {
|
||||
console.error(
|
||||
`Invalid Augmentation when trying to create PurchaseableAugmentation display element: ${props.augName}`,
|
||||
);
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const moneyCost = aug.baseCost;
|
||||
const repCost = aug.baseRepRequirement;
|
||||
const hasReq = hasAugmentationPrereqs(aug);
|
||||
const hasRep = props.faction.playerReputation >= repCost;
|
||||
const hasCost = aug.baseCost === 0 || props.p.money > aug.baseCost;
|
||||
|
||||
// Determine UI properties
|
||||
const color: "error" | "primary" = !hasReq || !hasRep || !hasCost ? "error" : "primary";
|
||||
|
||||
// Determine button txt
|
||||
let btnTxt = aug.name;
|
||||
if (aug.name === AugmentationNames.NeuroFluxGovernor) {
|
||||
btnTxt += ` - Level ${getNextNeuroFluxLevel()}`;
|
||||
}
|
||||
|
||||
let tooltip = <></>;
|
||||
if (typeof aug.info === "string") {
|
||||
tooltip = (
|
||||
<>
|
||||
<span>{aug.info}</span>
|
||||
<br />
|
||||
<br />
|
||||
{aug.stats}
|
||||
</>
|
||||
);
|
||||
} else
|
||||
tooltip = (
|
||||
<>
|
||||
{aug.info}
|
||||
<br />
|
||||
<br />
|
||||
{aug.stats}
|
||||
</>
|
||||
);
|
||||
|
||||
function handleClick(): void {
|
||||
if (color === "error") return;
|
||||
if (!Settings.SuppressBuyAugmentationConfirmation) {
|
||||
setOpen(true);
|
||||
} else {
|
||||
purchaseAugmentation(aug, props.faction);
|
||||
props.rerender();
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<TableRow>
|
||||
{!props.owned && (
|
||||
<TableCell key={0}>
|
||||
<Button onClick={handleClick} color={color}>
|
||||
Buy
|
||||
</Button>
|
||||
<PurchaseAugmentationModal
|
||||
open={open}
|
||||
onClose={() => setOpen(false)}
|
||||
aug={aug}
|
||||
faction={props.faction}
|
||||
rerender={props.rerender}
|
||||
/>
|
||||
</TableCell>
|
||||
)}
|
||||
<TableCell key={1}>
|
||||
<Box display="flex">
|
||||
<Tooltip title={<Typography>{tooltip}</Typography>} placement="top">
|
||||
<Typography>{btnTxt}</Typography>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
</TableCell>
|
||||
{!props.owned && (
|
||||
<Requirements
|
||||
key={2}
|
||||
augName={props.augName}
|
||||
p={props.p}
|
||||
cost={moneyCost}
|
||||
rep={repCost}
|
||||
hasReq={hasReq}
|
||||
hasRep={hasRep}
|
||||
hasCost={hasCost}
|
||||
/>
|
||||
)}
|
||||
</TableRow>
|
||||
);
|
||||
}
|
@ -139,34 +139,37 @@ export const GraftingRoot = (): React.ReactElement => {
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<Typography color={Settings.theme.info}>
|
||||
<b>Time to Graft:</b>{" "}
|
||||
{convertTimeMsToTimeElapsedString(
|
||||
calculateGraftingTimeWithBonus(player, GraftableAugmentations[selectedAug]),
|
||||
<Box sx={{ maxHeight: 330, overflowY: "scroll" }}>
|
||||
<Typography color={Settings.theme.info}>
|
||||
<b>Time to Graft:</b>{" "}
|
||||
{convertTimeMsToTimeElapsedString(
|
||||
calculateGraftingTimeWithBonus(player, GraftableAugmentations[selectedAug]),
|
||||
)}
|
||||
{/* Use formula so the displayed creation time is accurate to player bonus */}
|
||||
</Typography>
|
||||
|
||||
{Augmentations[selectedAug].prereqs.length > 0 && (
|
||||
<AugPreReqsChecklist player={player} aug={Augmentations[selectedAug]} />
|
||||
)}
|
||||
{/* Use formula so the displayed creation time is accurate to player bonus */}
|
||||
</Typography>
|
||||
{Augmentations[selectedAug].prereqs.length > 0 && (
|
||||
<AugPreReqsChecklist player={player} aug={Augmentations[selectedAug]} />
|
||||
)}
|
||||
<br />
|
||||
|
||||
<br />
|
||||
<Typography sx={{ maxHeight: 305, overflowY: "scroll" }}>
|
||||
{(() => {
|
||||
const aug = Augmentations[selectedAug];
|
||||
<Typography>
|
||||
{(() => {
|
||||
const aug = Augmentations[selectedAug];
|
||||
|
||||
const info = typeof aug.info === "string" ? <span>{aug.info}</span> : aug.info;
|
||||
const tooltip = (
|
||||
<>
|
||||
{info}
|
||||
<br />
|
||||
<br />
|
||||
{aug.stats}
|
||||
</>
|
||||
);
|
||||
return tooltip;
|
||||
})()}
|
||||
</Typography>
|
||||
const info = typeof aug.info === "string" ? <span>{aug.info}</span> : aug.info;
|
||||
const tooltip = (
|
||||
<>
|
||||
{info}
|
||||
<br />
|
||||
<br />
|
||||
{aug.stats}
|
||||
</>
|
||||
);
|
||||
return tooltip;
|
||||
})()}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</Paper>
|
||||
) : (
|
||||
|
@ -1,20 +1,10 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { Container, Typography, Paper } from "@mui/material";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { PurchasableAugmentations } from "../../../Augmentation/ui/PurchasableAugmentations";
|
||||
import { use } from "../../../ui/Context";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { Sleeve } from "../Sleeve";
|
||||
import { findSleevePurchasableAugs } from "../SleeveHelpers";
|
||||
import { Augmentations } from "../../../Augmentation/Augmentations";
|
||||
import { Augmentation } from "../../../Augmentation/Augmentation";
|
||||
import { Money } from "../../../ui/React/Money";
|
||||
import { Modal } from "../../../ui/React/Modal";
|
||||
import { use } from "../../../ui/Context";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import Paper from "@mui/material/Paper";
|
||||
import Box from "@mui/material/Box";
|
||||
import Button from "@mui/material/Button";
|
||||
import TableBody from "@mui/material/TableBody";
|
||||
import Table from "@mui/material/Table";
|
||||
import { TableCell } from "../../../ui/React/Table";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
|
||||
interface IProps {
|
||||
open: boolean;
|
||||
@ -42,80 +32,34 @@ export function SleeveAugmentationsModal(props: IProps): React.ReactElement {
|
||||
// and you must also have enough rep in that faction in order to purchase it.
|
||||
const availableAugs = findSleevePurchasableAugs(props.sleeve, player);
|
||||
|
||||
function purchaseAugmentation(aug: Augmentation): void {
|
||||
props.sleeve.tryBuyAugmentation(player, aug);
|
||||
rerender();
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<>
|
||||
<Box sx={{ mx: 1 }}>
|
||||
<Typography>
|
||||
You can purchase Augmentations for your Duplicate Sleeves. These Augmentations have the same effect as they
|
||||
would for you. You can only purchase Augmentations that you have unlocked through Factions.
|
||||
<br />
|
||||
<br />
|
||||
When purchasing an Augmentation for a Duplicate Sleeve, they are immediately installed. This means that the
|
||||
Duplicate Sleeve will immediately lose all of its stat experience.
|
||||
</Typography>
|
||||
<Box component={Paper} sx={{ my: 1, p: 1 }}>
|
||||
<Table size="small" padding="none">
|
||||
<TableBody>
|
||||
{availableAugs.map((aug) => {
|
||||
return (
|
||||
<TableRow key={aug.name}>
|
||||
<TableCell>
|
||||
<Button onClick={() => purchaseAugmentation(aug)} disabled={player.money < aug.startingCost}>
|
||||
Buy
|
||||
</Button>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Box display="flex">
|
||||
<Tooltip title={aug.stats || ""}>
|
||||
<Typography>{aug.name}</Typography>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Money money={aug.startingCost} player={player} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{ownedAugNames.length > 0 && (
|
||||
<>
|
||||
<Typography sx={{ mx: 1 }}>Owned Augmentations:</Typography>
|
||||
<Box display="grid" sx={{ gridTemplateColumns: "repeat(5, 1fr)", m: 1 }}>
|
||||
{ownedAugNames.map((augName) => {
|
||||
const aug = Augmentations[augName];
|
||||
const info = typeof aug.info === "string" ? <span>{aug.info}</span> : aug.info;
|
||||
const tooltip = (
|
||||
<>
|
||||
{info}
|
||||
<br />
|
||||
<br />
|
||||
{aug.stats}
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<Tooltip key={augName} title={<Typography>{tooltip}</Typography>}>
|
||||
<Paper sx={{ p: 1 }}>
|
||||
<Typography>{augName}</Typography>
|
||||
</Paper>
|
||||
</Tooltip>
|
||||
);
|
||||
})}
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
<Container component={Paper} disableGutters maxWidth="lg" sx={{ mx: 0, mb: 1, p: 1 }}>
|
||||
<Typography>
|
||||
You can purchase Augmentations for your Duplicate Sleeves. These Augmentations have the same effect as they
|
||||
would for you. You can only purchase Augmentations that you have unlocked through Factions.
|
||||
<br />
|
||||
<br />
|
||||
When purchasing an Augmentation for a Duplicate Sleeve, they are immediately installed. This means that the
|
||||
Duplicate Sleeve will immediately lose all of its stat experience.
|
||||
<br />
|
||||
<br />
|
||||
Augmentations will appear below as they become available.
|
||||
</Typography>
|
||||
</Container>
|
||||
<PurchasableAugmentations
|
||||
augNames={availableAugs.map((aug) => aug.name)}
|
||||
ownedAugNames={ownedAugNames}
|
||||
player={player}
|
||||
canPurchase={(player, aug) => {
|
||||
return player.money > aug.startingCost;
|
||||
}}
|
||||
purchaseAugmentation={(player, aug, _showModal) => {
|
||||
props.sleeve.tryBuyAugmentation(player, aug);
|
||||
rerender();
|
||||
}}
|
||||
sleeveAugs
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user