Merge pull request #3545 from nickofolas/improvement/purchase-augs-ui

UI: Redesign purchasable Augmentations
This commit is contained in:
hydroflame 2022-04-26 11:16:13 -04:00 committed by GitHub
commit d0d700077a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 433 additions and 402 deletions

@ -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,

@ -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 (
<>
<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 {props.faction.name}. Augmentations are
powerful upgrades that will enhance your abilities.
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 />
Reputation: <Reputation reputation={props.faction.playerReputation} /> Favor:{" "}
<Favor favor={Math.floor(props.faction.favor)} />
</Typography>
<Box display="flex">
<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.
The price of every Augmentation increases for every queued Augmentation and it is reset when you
install them.
</Typography>
}
>
{multiplierComponent}
</Tooltip>
<Typography>
<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.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 />
</Box>
</Paper>
</Container>
<Table size="small" padding="none">
<TableBody>{augListElems}</TableBody>
</Table>
<Table size="small" padding="none">
<TableBody>{ownedElem}</TableBody>
</Table>
<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();
}
}}
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,6 +139,7 @@ export const GraftingRoot = (): React.ReactElement => {
</>
}
/>
<Box sx={{ maxHeight: 330, overflowY: "scroll" }}>
<Typography color={Settings.theme.info}>
<b>Time to Graft:</b>{" "}
{convertTimeMsToTimeElapsedString(
@ -146,12 +147,13 @@ export const GraftingRoot = (): React.ReactElement => {
)}
{/* 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 />
<Typography sx={{ maxHeight: 305, overflowY: "scroll" }}>
<Typography>
{(() => {
const aug = Augmentations[selectedAug];
@ -168,6 +170,7 @@ export const GraftingRoot = (): React.ReactElement => {
})()}
</Typography>
</Box>
</Box>
</Paper>
) : (
<Typography>All Augmentations owned</Typography>

@ -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,15 +32,9 @@ 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 }}>
<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.
@ -58,64 +42,24 @@ export function SleeveAugmentationsModal(props: IProps): React.ReactElement {
<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>
<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>
<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>
);
}