mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-14 03:33:52 +01:00
Merge branch 'danielyxie:dev' into dev
This commit is contained in:
commit
2f320d00a2
7
src/@types/global.d.ts
vendored
7
src/@types/global.d.ts
vendored
@ -1,8 +1,13 @@
|
|||||||
// Defined by webpack on startup or compilation
|
// Defined by webpack on startup or compilation
|
||||||
declare let __COMMIT_HASH__: string;
|
declare const __COMMIT_HASH__: string;
|
||||||
|
|
||||||
// When using file-loader, we'll get a path to the resource
|
// When using file-loader, we'll get a path to the resource
|
||||||
declare module "*.png" {
|
declare module "*.png" {
|
||||||
const value: string;
|
const value: string;
|
||||||
export default value;
|
export default value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Achievements communicated back to Electron shell for Steam.
|
||||||
|
declare interface Document {
|
||||||
|
achievements: string[];
|
||||||
|
}
|
||||||
|
@ -799,5 +799,5 @@ export function calculateAchievements(): void {
|
|||||||
// Write all player's achievements to document for Steam/Electron
|
// Write all player's achievements to document for Steam/Electron
|
||||||
// This could be replaced by "availableAchievements"
|
// This could be replaced by "availableAchievements"
|
||||||
// if we don't want to grant the save game achievements to steam but only currently available
|
// if we don't want to grant the save game achievements to steam but only currently available
|
||||||
(document as any).achievements = [...Player.achievements.map((a) => a.ID)];
|
document.achievements = [...Player.achievements.map((a) => a.ID)];
|
||||||
}
|
}
|
||||||
|
@ -109,6 +109,7 @@ export const initSoAAugmentations = (): Augmentation[] => [
|
|||||||
rewards, reduced damage taken, etc.
|
rewards, reduced damage taken, etc.
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
|
isSpecial: true,
|
||||||
factions: [FactionNames.ShadowsOfAnarchy],
|
factions: [FactionNames.ShadowsOfAnarchy],
|
||||||
}),
|
}),
|
||||||
new Augmentation({
|
new Augmentation({
|
||||||
@ -121,6 +122,7 @@ export const initSoAAugmentations = (): Augmentation[] => [
|
|||||||
stats: (
|
stats: (
|
||||||
<>This augmentation makes the Slash minigame easier by showing you via an indictor when the slash in coming.</>
|
<>This augmentation makes the Slash minigame easier by showing you via an indictor when the slash in coming.</>
|
||||||
),
|
),
|
||||||
|
isSpecial: true,
|
||||||
factions: [FactionNames.ShadowsOfAnarchy],
|
factions: [FactionNames.ShadowsOfAnarchy],
|
||||||
}),
|
}),
|
||||||
new Augmentation({
|
new Augmentation({
|
||||||
@ -129,6 +131,7 @@ export const initSoAAugmentations = (): Augmentation[] => [
|
|||||||
moneyCost: 1e6,
|
moneyCost: 1e6,
|
||||||
info: "A connective brain implant to SASHA that focuses in pattern recognition and predictive templating.",
|
info: "A connective brain implant to SASHA that focuses in pattern recognition and predictive templating.",
|
||||||
stats: <>This augmentation makes the Bracket minigame easier by removing all '[' ']'.</>,
|
stats: <>This augmentation makes the Bracket minigame easier by removing all '[' ']'.</>,
|
||||||
|
isSpecial: true,
|
||||||
factions: [FactionNames.ShadowsOfAnarchy],
|
factions: [FactionNames.ShadowsOfAnarchy],
|
||||||
}),
|
}),
|
||||||
new Augmentation({
|
new Augmentation({
|
||||||
@ -137,6 +140,7 @@ export const initSoAAugmentations = (): Augmentation[] => [
|
|||||||
moneyCost: 1e6,
|
moneyCost: 1e6,
|
||||||
info: "Opto-occipito implant to process visual signal before brain interpretation.",
|
info: "Opto-occipito implant to process visual signal before brain interpretation.",
|
||||||
stats: <>This augmentation makes the Backwards minigame easier by flipping the words.</>,
|
stats: <>This augmentation makes the Backwards minigame easier by flipping the words.</>,
|
||||||
|
isSpecial: true,
|
||||||
factions: [FactionNames.ShadowsOfAnarchy],
|
factions: [FactionNames.ShadowsOfAnarchy],
|
||||||
}),
|
}),
|
||||||
new Augmentation({
|
new Augmentation({
|
||||||
@ -147,6 +151,7 @@ export const initSoAAugmentations = (): Augmentation[] => [
|
|||||||
"Pheromone extruder injected in the thoracodorsal nerve. Emits pleasing scent guaranteed to " +
|
"Pheromone extruder injected in the thoracodorsal nerve. Emits pleasing scent guaranteed to " +
|
||||||
"make conversational partners more agreeable.",
|
"make conversational partners more agreeable.",
|
||||||
stats: <>This augmentation makes the Bribe minigame easier by indicating the incorrect paths.</>,
|
stats: <>This augmentation makes the Bribe minigame easier by indicating the incorrect paths.</>,
|
||||||
|
isSpecial: true,
|
||||||
factions: [FactionNames.ShadowsOfAnarchy],
|
factions: [FactionNames.ShadowsOfAnarchy],
|
||||||
}),
|
}),
|
||||||
new Augmentation({
|
new Augmentation({
|
||||||
@ -155,6 +160,7 @@ export const initSoAAugmentations = (): Augmentation[] => [
|
|||||||
moneyCost: 1e6,
|
moneyCost: 1e6,
|
||||||
info: "Penta-dynamo-neurovascular-valve inserted in the carpal ligament, enhances dexterity.",
|
info: "Penta-dynamo-neurovascular-valve inserted in the carpal ligament, enhances dexterity.",
|
||||||
stats: <>This augmentation makes the Cheat Code minigame easier by allowing the opposite character.</>,
|
stats: <>This augmentation makes the Cheat Code minigame easier by allowing the opposite character.</>,
|
||||||
|
isSpecial: true,
|
||||||
factions: [FactionNames.ShadowsOfAnarchy],
|
factions: [FactionNames.ShadowsOfAnarchy],
|
||||||
}),
|
}),
|
||||||
new Augmentation({
|
new Augmentation({
|
||||||
@ -163,6 +169,7 @@ export const initSoAAugmentations = (): Augmentation[] => [
|
|||||||
moneyCost: 1e6,
|
moneyCost: 1e6,
|
||||||
info: "Transtinatium VVD reticulator used in optico-sterbing recognition.",
|
info: "Transtinatium VVD reticulator used in optico-sterbing recognition.",
|
||||||
stats: <>This augmentation makes the Symbol matching minigame easier by indicating the correct choice.</>,
|
stats: <>This augmentation makes the Symbol matching minigame easier by indicating the correct choice.</>,
|
||||||
|
isSpecial: true,
|
||||||
factions: [FactionNames.ShadowsOfAnarchy],
|
factions: [FactionNames.ShadowsOfAnarchy],
|
||||||
}),
|
}),
|
||||||
new Augmentation({
|
new Augmentation({
|
||||||
@ -176,6 +183,7 @@ export const initSoAAugmentations = (): Augmentation[] => [
|
|||||||
position.
|
position.
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
|
isSpecial: true,
|
||||||
factions: [FactionNames.ShadowsOfAnarchy],
|
factions: [FactionNames.ShadowsOfAnarchy],
|
||||||
}),
|
}),
|
||||||
new Augmentation({
|
new Augmentation({
|
||||||
@ -184,6 +192,7 @@ export const initSoAAugmentations = (): Augmentation[] => [
|
|||||||
moneyCost: 1e6,
|
moneyCost: 1e6,
|
||||||
info: "Neodynic retention fjengeln spoofer using -φ karmions, net positive effect on implantees delta wave.",
|
info: "Neodynic retention fjengeln spoofer using -φ karmions, net positive effect on implantees delta wave.",
|
||||||
stats: <>This augmentation makes the Wire Cutting minigame easier by indicating the incorrect wires.</>,
|
stats: <>This augmentation makes the Wire Cutting minigame easier by indicating the incorrect wires.</>,
|
||||||
|
isSpecial: true,
|
||||||
factions: [FactionNames.ShadowsOfAnarchy],
|
factions: [FactionNames.ShadowsOfAnarchy],
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
@ -242,7 +251,7 @@ export const initGeneralAugmentations = (): Augmentation[] => [
|
|||||||
moneyCost: 1.15e8,
|
moneyCost: 1.15e8,
|
||||||
repCost: 2.75e4,
|
repCost: 2.75e4,
|
||||||
info: "The latest version of the 'Augmented Targeting' implant adds the ability to lock-on and track threats.",
|
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,
|
dexterity_mult: 1.3,
|
||||||
factions: [
|
factions: [
|
||||||
FactionNames.TheDarkArmy,
|
FactionNames.TheDarkArmy,
|
||||||
@ -339,7 +348,7 @@ export const initGeneralAugmentations = (): Augmentation[] => [
|
|||||||
info:
|
info:
|
||||||
"The latest version of the 'Combat Rib' augmentation releases advanced anabolic steroids that " +
|
"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.",
|
"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,
|
strength_mult: 1.18,
|
||||||
defense_mult: 1.18,
|
defense_mult: 1.18,
|
||||||
factions: [
|
factions: [
|
||||||
@ -673,7 +682,7 @@ export const initGeneralAugmentations = (): Augmentation[] => [
|
|||||||
"This upgraded firmware allows the Embedded Netburner Module to control information on " +
|
"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 " +
|
"a network by re-routing traffic, spoofing IP addresses, and altering the data inside network " +
|
||||||
"packets.",
|
"packets.",
|
||||||
prereqs: [AugmentationNames.ENMCore],
|
prereqs: [AugmentationNames.ENMCore, AugmentationNames.ENM],
|
||||||
hacking_speed_mult: 1.05,
|
hacking_speed_mult: 1.05,
|
||||||
hacking_money_mult: 1.3,
|
hacking_money_mult: 1.3,
|
||||||
hacking_chance_mult: 1.05,
|
hacking_chance_mult: 1.05,
|
||||||
@ -698,7 +707,7 @@ export const initGeneralAugmentations = (): Augmentation[] => [
|
|||||||
"The Core V3 library is an implant that upgrades the firmware of the Embedded Netburner Module. " +
|
"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 " +
|
"This upgraded firmware allows the Embedded Netburner Module to seamlessly inject code into " +
|
||||||
"any device on a network.",
|
"any device on a network.",
|
||||||
prereqs: [AugmentationNames.ENMCoreV2],
|
prereqs: [AugmentationNames.ENMCoreV2, AugmentationNames.ENMCore, AugmentationNames.ENM],
|
||||||
hacking_speed_mult: 1.05,
|
hacking_speed_mult: 1.05,
|
||||||
hacking_money_mult: 1.4,
|
hacking_money_mult: 1.4,
|
||||||
hacking_chance_mult: 1.1,
|
hacking_chance_mult: 1.1,
|
||||||
@ -826,7 +835,7 @@ export const initGeneralAugmentations = (): Augmentation[] => [
|
|||||||
"are a set of specialized microprocessors that are attached to " +
|
"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 " +
|
"neurons in the brain. These chips process neural signals to quickly and automatically perform specific computations " +
|
||||||
"so that the brain doesn't have to.",
|
"so that the brain doesn't have to.",
|
||||||
prereqs: [AugmentationNames.CranialSignalProcessorsG2],
|
prereqs: [AugmentationNames.CranialSignalProcessorsG2, AugmentationNames.CranialSignalProcessorsG1],
|
||||||
hacking_speed_mult: 1.02,
|
hacking_speed_mult: 1.02,
|
||||||
hacking_money_mult: 1.15,
|
hacking_money_mult: 1.15,
|
||||||
hacking_mult: 1.09,
|
hacking_mult: 1.09,
|
||||||
@ -841,7 +850,11 @@ export const initGeneralAugmentations = (): Augmentation[] => [
|
|||||||
"are a set of specialized microprocessors that are attached to " +
|
"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 " +
|
"neurons in the brain. These chips process neural signals to quickly and automatically perform specific computations " +
|
||||||
"so that the brain doesn't have to.",
|
"so that the brain doesn't have to.",
|
||||||
prereqs: [AugmentationNames.CranialSignalProcessorsG3],
|
prereqs: [
|
||||||
|
AugmentationNames.CranialSignalProcessorsG3,
|
||||||
|
AugmentationNames.CranialSignalProcessorsG2,
|
||||||
|
AugmentationNames.CranialSignalProcessorsG1,
|
||||||
|
],
|
||||||
hacking_speed_mult: 1.02,
|
hacking_speed_mult: 1.02,
|
||||||
hacking_money_mult: 1.2,
|
hacking_money_mult: 1.2,
|
||||||
hacking_grow_mult: 1.25,
|
hacking_grow_mult: 1.25,
|
||||||
@ -856,7 +869,12 @@ export const initGeneralAugmentations = (): Augmentation[] => [
|
|||||||
"are a set of specialized microprocessors that are attached to " +
|
"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 " +
|
"neurons in the brain. These chips process neural signals to quickly and automatically perform specific computations " +
|
||||||
"so that the brain doesn't have to.",
|
"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_mult: 1.3,
|
||||||
hacking_money_mult: 1.25,
|
hacking_money_mult: 1.25,
|
||||||
hacking_grow_mult: 1.75,
|
hacking_grow_mult: 1.75,
|
||||||
@ -1254,6 +1272,7 @@ export const initGeneralAugmentations = (): Augmentation[] => [
|
|||||||
moneyCost: 0,
|
moneyCost: 0,
|
||||||
info: "It's time to leave the cave.",
|
info: "It's time to leave the cave.",
|
||||||
stats: null,
|
stats: null,
|
||||||
|
isSpecial: true,
|
||||||
factions: [FactionNames.Daedalus],
|
factions: [FactionNames.Daedalus],
|
||||||
}),
|
}),
|
||||||
new Augmentation({
|
new Augmentation({
|
||||||
@ -1952,7 +1971,7 @@ export const initChurchOfTheMachineGodAugmentations = (): Augmentation[] => [
|
|||||||
"You will become greater than the sum of our parts. As One. Embrace your gift " +
|
"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 " +
|
"fully and wholly free of it's accursed toll. Serenity brings tranquility the form " +
|
||||||
"of no longer suffering a stat penalty. ",
|
"of no longer suffering a stat penalty. ",
|
||||||
prereqs: [AugmentationNames.StaneksGift2],
|
prereqs: [AugmentationNames.StaneksGift2, AugmentationNames.StaneksGift1],
|
||||||
isSpecial: true,
|
isSpecial: true,
|
||||||
hacking_chance_mult: 1 / 0.95,
|
hacking_chance_mult: 1 / 0.95,
|
||||||
hacking_speed_mult: 1 / 0.95,
|
hacking_speed_mult: 1 / 0.95,
|
||||||
@ -2003,6 +2022,7 @@ export function initNeuroFluxGovernor(): Augmentation {
|
|||||||
multiplicatively.
|
multiplicatively.
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
|
isSpecial: true,
|
||||||
hacking_chance_mult: 1.01 + donationBonus,
|
hacking_chance_mult: 1.01 + donationBonus,
|
||||||
hacking_speed_mult: 1.01 + donationBonus,
|
hacking_speed_mult: 1.01 + donationBonus,
|
||||||
hacking_money_mult: 1.01 + donationBonus,
|
hacking_money_mult: 1.01 + donationBonus,
|
||||||
|
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 React from "react";
|
||||||
|
|
||||||
import { Augmentation } from "../../Augmentation/Augmentation";
|
import { Augmentation } from "../Augmentation";
|
||||||
import { Faction } from "../Faction";
|
import { Faction } from "../../Faction/Faction";
|
||||||
import { purchaseAugmentation } from "../FactionHelpers";
|
import { purchaseAugmentation } from "../../Faction/FactionHelpers";
|
||||||
import { isRepeatableAug } from "../../Augmentation/AugmentationHelpers";
|
import { isRepeatableAug } from "../AugmentationHelpers";
|
||||||
import { Money } from "../../ui/React/Money";
|
import { Money } from "../../ui/React/Money";
|
||||||
import { Modal } from "../../ui/React/Modal";
|
import { Modal } from "../../ui/React/Modal";
|
||||||
import { use } from "../../ui/Context";
|
import { use } from "../../ui/Context";
|
||||||
@ -13,21 +13,23 @@ import Button from "@mui/material/Button";
|
|||||||
interface IProps {
|
interface IProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
faction: Faction;
|
faction?: Faction;
|
||||||
aug: Augmentation;
|
aug?: Augmentation;
|
||||||
rerender: () => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PurchaseAugmentationModal(props: IProps): React.ReactElement {
|
export function PurchaseAugmentationModal(props: IProps): React.ReactElement {
|
||||||
|
if (typeof props.aug === "undefined" || typeof props.faction === "undefined") {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
const player = use.Player();
|
const player = use.Player();
|
||||||
|
|
||||||
function buy(): void {
|
function buy(): void {
|
||||||
if (!isRepeatableAug(props.aug) && player.hasAugmentation(props.aug)) {
|
if (!isRepeatableAug(props.aug as Augmentation) && player.hasAugmentation(props.aug as Augmentation)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
purchaseAugmentation(props.aug, props.faction);
|
purchaseAugmentation(props.aug as Augmentation, props.faction as Faction);
|
||||||
props.rerender();
|
|
||||||
props.onClose();
|
props.onClose();
|
||||||
}
|
}
|
||||||
|
|
@ -120,7 +120,7 @@ export const CONSTANTS: {
|
|||||||
LatestUpdate: string;
|
LatestUpdate: string;
|
||||||
} = {
|
} = {
|
||||||
VersionString: "1.6.4",
|
VersionString: "1.6.4",
|
||||||
VersionNumber: 15,
|
VersionNumber: 16,
|
||||||
|
|
||||||
// Speed (in ms) at which the main loop is updated
|
// Speed (in ms) at which the main loop is updated
|
||||||
_idleSpeed: 200,
|
_idleSpeed: 200,
|
||||||
|
@ -11,11 +11,41 @@ import { exportScripts } from "./Terminal/commands/download";
|
|||||||
import { CONSTANTS } from "./Constants";
|
import { CONSTANTS } from "./Constants";
|
||||||
import { hash } from "./hash/hash";
|
import { hash } from "./hash/hash";
|
||||||
|
|
||||||
|
interface IReturnWebStatus extends IReturnStatus {
|
||||||
|
data?: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
appNotifier: {
|
||||||
|
terminal: (message: string, type?: string) => void;
|
||||||
|
toast: (message: string, type: ToastVariant, duration?: number) => void;
|
||||||
|
};
|
||||||
|
appSaveFns: {
|
||||||
|
triggerSave: () => Promise<void>;
|
||||||
|
triggerGameExport: () => void;
|
||||||
|
triggerScriptsExport: () => void;
|
||||||
|
getSaveData: () => { save: string; fileName: string };
|
||||||
|
getSaveInfo: (base64save: string) => Promise<ImportPlayerData | undefined>;
|
||||||
|
pushSaveData: (base64save: string, automatic?: boolean) => void;
|
||||||
|
};
|
||||||
|
electronBridge: {
|
||||||
|
send: (channel: string, data?: unknown) => void;
|
||||||
|
receive: (channel: string, func: (...args: any[]) => void) => void;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
interface Document {
|
||||||
|
getFiles: () => IReturnWebStatus;
|
||||||
|
deleteFile: (filename: string) => IReturnWebStatus;
|
||||||
|
saveFile: (filename: string, code: string) => IReturnWebStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function initElectron(): void {
|
export function initElectron(): void {
|
||||||
const userAgent = navigator.userAgent.toLowerCase();
|
const userAgent = navigator.userAgent.toLowerCase();
|
||||||
if (userAgent.indexOf(" electron/") > -1) {
|
if (userAgent.indexOf(" electron/") > -1) {
|
||||||
// Electron-specific code
|
// Electron-specific code
|
||||||
(document as any).achievements = [];
|
document.achievements = [];
|
||||||
initWebserver();
|
initWebserver();
|
||||||
initAppNotifier();
|
initAppNotifier();
|
||||||
initSaveFunctions();
|
initSaveFunctions();
|
||||||
@ -24,11 +54,6 @@ export function initElectron(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function initWebserver(): void {
|
function initWebserver(): void {
|
||||||
interface IReturnWebStatus extends IReturnStatus {
|
|
||||||
data?: {
|
|
||||||
[propName: string]: any;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
function normalizeFileName(filename: string): string {
|
function normalizeFileName(filename: string): string {
|
||||||
filename = filename.replace(/\/\/+/g, "/");
|
filename = filename.replace(/\/\/+/g, "/");
|
||||||
filename = removeLeadingSlash(filename);
|
filename = removeLeadingSlash(filename);
|
||||||
@ -38,7 +63,7 @@ function initWebserver(): void {
|
|||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
(document as any).getFiles = function (): IReturnWebStatus {
|
document.getFiles = function (): IReturnWebStatus {
|
||||||
const home = GetServer("home");
|
const home = GetServer("home");
|
||||||
if (home === null) {
|
if (home === null) {
|
||||||
return {
|
return {
|
||||||
@ -58,7 +83,7 @@ function initWebserver(): void {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
(document as any).deleteFile = function (filename: string): IReturnWebStatus {
|
document.deleteFile = function (filename: string): IReturnWebStatus {
|
||||||
filename = normalizeFileName(filename);
|
filename = normalizeFileName(filename);
|
||||||
const home = GetServer("home");
|
const home = GetServer("home");
|
||||||
if (home === null) {
|
if (home === null) {
|
||||||
@ -70,7 +95,7 @@ function initWebserver(): void {
|
|||||||
return home.removeFile(filename);
|
return home.removeFile(filename);
|
||||||
};
|
};
|
||||||
|
|
||||||
(document as any).saveFile = function (filename: string, code: string): IReturnWebStatus {
|
document.saveFile = function (filename: string, code: string): IReturnWebStatus {
|
||||||
filename = normalizeFileName(filename);
|
filename = normalizeFileName(filename);
|
||||||
|
|
||||||
code = Buffer.from(code, "base64").toString();
|
code = Buffer.from(code, "base64").toString();
|
||||||
@ -115,7 +140,7 @@ function initAppNotifier(): void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Will be consumud by the electron wrapper.
|
// Will be consumud by the electron wrapper.
|
||||||
(window as any).appNotifier = funcs;
|
window.appNotifier = funcs;
|
||||||
}
|
}
|
||||||
|
|
||||||
function initSaveFunctions(): void {
|
function initSaveFunctions(): void {
|
||||||
@ -149,38 +174,38 @@ function initSaveFunctions(): void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Will be consumud by the electron wrapper.
|
// Will be consumud by the electron wrapper.
|
||||||
(window as any).appSaveFns = funcs;
|
window.appSaveFns = funcs;
|
||||||
}
|
}
|
||||||
|
|
||||||
function initElectronBridge(): void {
|
function initElectronBridge(): void {
|
||||||
const bridge = (window as any).electronBridge as any;
|
const bridge = window.electronBridge;
|
||||||
if (!bridge) return;
|
if (!bridge) return;
|
||||||
|
|
||||||
bridge.receive("get-save-data-request", () => {
|
bridge.receive("get-save-data-request", () => {
|
||||||
const data = (window as any).appSaveFns.getSaveData();
|
const data = window.appSaveFns.getSaveData();
|
||||||
bridge.send("get-save-data-response", data);
|
bridge.send("get-save-data-response", data);
|
||||||
});
|
});
|
||||||
bridge.receive("get-save-info-request", async (save: string) => {
|
bridge.receive("get-save-info-request", async (save: string) => {
|
||||||
const data = await (window as any).appSaveFns.getSaveInfo(save);
|
const data = await window.appSaveFns.getSaveInfo(save);
|
||||||
bridge.send("get-save-info-response", data);
|
bridge.send("get-save-info-response", data);
|
||||||
});
|
});
|
||||||
bridge.receive("push-save-request", ({ save, automatic = false }: { save: string; automatic: boolean }) => {
|
bridge.receive("push-save-request", ({ save, automatic = false }: { save: string; automatic: boolean }) => {
|
||||||
(window as any).appSaveFns.pushSaveData(save, automatic);
|
window.appSaveFns.pushSaveData(save, automatic);
|
||||||
});
|
});
|
||||||
bridge.receive("trigger-save", () => {
|
bridge.receive("trigger-save", () => {
|
||||||
return (window as any).appSaveFns
|
return window.appSaveFns
|
||||||
.triggerSave()
|
.triggerSave()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
bridge.send("save-completed");
|
bridge.send("save-completed");
|
||||||
})
|
})
|
||||||
.catch((error: any) => {
|
.catch((error: unknown) => {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
SnackbarEvents.emit("Could not save game.", ToastVariant.ERROR, 2000);
|
SnackbarEvents.emit("Could not save game.", ToastVariant.ERROR, 2000);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
bridge.receive("trigger-game-export", () => {
|
bridge.receive("trigger-game-export", () => {
|
||||||
try {
|
try {
|
||||||
(window as any).appSaveFns.triggerGameExport();
|
window.appSaveFns.triggerGameExport();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
SnackbarEvents.emit("Could not export game.", ToastVariant.ERROR, 2000);
|
SnackbarEvents.emit("Could not export game.", ToastVariant.ERROR, 2000);
|
||||||
@ -188,7 +213,7 @@ function initElectronBridge(): void {
|
|||||||
});
|
});
|
||||||
bridge.receive("trigger-scripts-export", () => {
|
bridge.receive("trigger-scripts-export", () => {
|
||||||
try {
|
try {
|
||||||
(window as any).appSaveFns.triggerScriptsExport();
|
window.appSaveFns.triggerScriptsExport();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
SnackbarEvents.emit("Could not export scripts.", ToastVariant.ERROR, 2000);
|
SnackbarEvents.emit("Could not export scripts.", ToastVariant.ERROR, 2000);
|
||||||
@ -197,14 +222,14 @@ function initElectronBridge(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function pushGameSaved(data: SaveData): void {
|
export function pushGameSaved(data: SaveData): void {
|
||||||
const bridge = (window as any).electronBridge as any;
|
const bridge = window.electronBridge;
|
||||||
if (!bridge) return;
|
if (!bridge) return;
|
||||||
|
|
||||||
bridge.send("push-game-saved", data);
|
bridge.send("push-game-saved", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pushGameReady(): void {
|
export function pushGameReady(): void {
|
||||||
const bridge = (window as any).electronBridge as any;
|
const bridge = window.electronBridge;
|
||||||
if (!bridge) return;
|
if (!bridge) return;
|
||||||
|
|
||||||
// Send basic information to the electron wrapper
|
// Send basic information to the electron wrapper
|
||||||
@ -222,7 +247,7 @@ export function pushGameReady(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function pushImportResult(wasImported: boolean): void {
|
export function pushImportResult(wasImported: boolean): void {
|
||||||
const bridge = (window as any).electronBridge as any;
|
const bridge = window.electronBridge;
|
||||||
if (!bridge) return;
|
if (!bridge) return;
|
||||||
|
|
||||||
bridge.send("push-import-result", { wasImported });
|
bridge.send("push-import-result", { wasImported });
|
||||||
@ -230,7 +255,7 @@ export function pushImportResult(wasImported: boolean): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function pushDisableRestore(): void {
|
export function pushDisableRestore(): void {
|
||||||
const bridge = (window as any).electronBridge as any;
|
const bridge = window.electronBridge;
|
||||||
if (!bridge) return;
|
if (!bridge) return;
|
||||||
|
|
||||||
bridge.send("push-disable-restore", { duration: 1000 * 60 });
|
bridge.send("push-disable-restore", { duration: 1000 * 60 });
|
||||||
|
@ -54,36 +54,15 @@ export function joinFaction(faction: Faction): void {
|
|||||||
//Returns a boolean indicating whether the player has the prerequisites for the
|
//Returns a boolean indicating whether the player has the prerequisites for the
|
||||||
//specified Augmentation
|
//specified Augmentation
|
||||||
export function hasAugmentationPrereqs(aug: Augmentation): boolean {
|
export function hasAugmentationPrereqs(aug: Augmentation): boolean {
|
||||||
let hasPrereqs = true;
|
return aug.prereqs.every((aug) => Player.hasAugmentation(aug));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function purchaseAugmentation(aug: Augmentation, fac: Faction, sing = false): string {
|
export function purchaseAugmentation(aug: Augmentation, fac: Faction, sing = false): string {
|
||||||
const hasPrereqs = hasAugmentationPrereqs(aug);
|
const hasPrereqs = hasAugmentationPrereqs(aug);
|
||||||
if (!hasPrereqs) {
|
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) {
|
if (sing) {
|
||||||
return txt;
|
return txt;
|
||||||
} else {
|
} else {
|
||||||
@ -165,13 +144,11 @@ export const getFactionAugmentationsFiltered = (player: IPlayer, faction: Factio
|
|||||||
let augs = Object.values(Augmentations);
|
let augs = Object.values(Augmentations);
|
||||||
|
|
||||||
// Remove special augs
|
// Remove special augs
|
||||||
augs = augs.filter((a) => !a.isSpecial);
|
augs = augs.filter((a) => !a.isSpecial || a.name != AugmentationNames.CongruityImplant);
|
||||||
|
|
||||||
const blacklist: string[] = [AugmentationNames.NeuroFluxGovernor, AugmentationNames.CongruityImplant];
|
if (player.bitNodeN === 2) {
|
||||||
|
|
||||||
if (player.bitNodeN !== 2) {
|
|
||||||
// TRP is not available outside of BN2 for Gangs
|
// TRP is not available outside of BN2 for Gangs
|
||||||
blacklist.push(AugmentationNames.TheRedPill);
|
augs.push(Augmentations[AugmentationNames.TheRedPill]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const rng = SFC32RNG(`BN${player.bitNodeN}.${player.sourceFileLvl(player.bitNodeN)}`);
|
const rng = SFC32RNG(`BN${player.bitNodeN}.${player.sourceFileLvl(player.bitNodeN)}`);
|
||||||
@ -190,9 +167,6 @@ export const getFactionAugmentationsFiltered = (player: IPlayer, faction: Factio
|
|||||||
};
|
};
|
||||||
augs = augs.filter(uniqueFilter);
|
augs = augs.filter(uniqueFilter);
|
||||||
|
|
||||||
// Remove blacklisted augs
|
|
||||||
augs = augs.filter((a) => !blacklist.includes(a.name));
|
|
||||||
|
|
||||||
return augs.map((a) => a.name);
|
return augs.map((a) => a.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,30 +1,21 @@
|
|||||||
/**
|
/**
|
||||||
* Root React Component for displaying a faction's "Purchase Augmentations" page
|
* 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 React, { useState } from "react";
|
||||||
|
import { getGenericAugmentationPriceMultiplier } from "../../Augmentation/AugmentationHelpers";
|
||||||
import { PurchaseableAugmentation } from "./PurchaseableAugmentation";
|
|
||||||
|
|
||||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
||||||
import { Faction } from "../Faction";
|
import { PurchasableAugmentations } from "../../Augmentation/ui/PurchasableAugmentations";
|
||||||
import { PurchaseAugmentationsOrderSetting } from "../../Settings/SettingEnums";
|
import { PurchaseAugmentationsOrderSetting } from "../../Settings/SettingEnums";
|
||||||
import { Settings } from "../../Settings/Settings";
|
import { Settings } from "../../Settings/Settings";
|
||||||
import { hasAugmentationPrereqs, getFactionAugmentationsFiltered } from "../FactionHelpers";
|
|
||||||
|
|
||||||
import { use } from "../../ui/Context";
|
import { use } from "../../ui/Context";
|
||||||
import { Reputation } from "../../ui/React/Reputation";
|
|
||||||
import { Favor } from "../../ui/React/Favor";
|
|
||||||
import { numeralWrapper } from "../../ui/numeralFormat";
|
import { numeralWrapper } from "../../ui/numeralFormat";
|
||||||
|
import { Favor } from "../../ui/React/Favor";
|
||||||
import Box from "@mui/material/Box";
|
import { Reputation } from "../../ui/React/Reputation";
|
||||||
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 { FactionNames } from "../data/FactionNames";
|
import { FactionNames } from "../data/FactionNames";
|
||||||
|
import { Faction } from "../Faction";
|
||||||
|
import { getFactionAugmentationsFiltered, hasAugmentationPrereqs, purchaseAugmentation } from "../FactionHelpers";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
faction: Faction;
|
faction: Faction;
|
||||||
@ -137,38 +128,12 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
|
|||||||
aug === AugmentationNames.NeuroFluxGovernor ||
|
aug === AugmentationNames.NeuroFluxGovernor ||
|
||||||
(!player.augmentations.some((a) => a.name === aug) && !player.queuedAugmentations.some((a) => a.name === aug)),
|
(!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));
|
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 =
|
const multiplierComponent =
|
||||||
props.faction.name !== FactionNames.ShadowsOfAnarchy ? (
|
props.faction.name !== FactionNames.ShadowsOfAnarchy ? (
|
||||||
<Typography>
|
<Typography>
|
||||||
Price multiplier: x {numeralWrapper.formatMultiplier(getGenericAugmentationPriceMultiplier())}
|
<b>Price multiplier:</b> x {numeralWrapper.formatReallyBigNumber(getGenericAugmentationPriceMultiplier())}
|
||||||
</Typography>
|
</Typography>
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
@ -176,42 +141,77 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<Container disableGutters maxWidth="lg" sx={{ mx: 0 }}>
|
||||||
<Button onClick={props.routeToMainPage}>Back</Button>
|
<Button onClick={props.routeToMainPage}>Back</Button>
|
||||||
<Typography variant="h4">Faction Augmentations</Typography>
|
<Typography variant="h4">Faction Augmentations</Typography>
|
||||||
|
<Paper sx={{ p: 1, mb: 1 }}>
|
||||||
<Typography>
|
<Typography>
|
||||||
These are all of the Augmentations that are available to purchase from {props.faction.name}. Augmentations are
|
These are all of the Augmentations that are available to purchase from <b>{props.faction.name}</b>.
|
||||||
powerful upgrades that will enhance your abilities.
|
Augmentations are powerful upgrades that will enhance your abilities.
|
||||||
<br />
|
<br />
|
||||||
Reputation: <Reputation reputation={props.faction.playerReputation} /> Favor:{" "}
|
|
||||||
<Favor favor={Math.floor(props.faction.favor)} />
|
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box display="flex">
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: "grid",
|
||||||
|
gridTemplateColumns: `repeat(${props.faction.name === FactionNames.ShadowsOfAnarchy ? "2" : "3"}, 1fr)`,
|
||||||
|
justifyItems: "center",
|
||||||
|
my: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={
|
title={
|
||||||
<Typography>
|
<Typography>
|
||||||
The price of every Augmentation increases for every queued Augmentation and it is reset when you install
|
The price of every Augmentation increases for every queued Augmentation and it is reset when you
|
||||||
them.
|
install them.
|
||||||
</Typography>
|
</Typography>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{multiplierComponent}
|
{multiplierComponent}
|
||||||
</Tooltip>
|
</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>
|
||||||
|
<Box sx={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)" }}>
|
||||||
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Cost)}>Sort by Cost</Button>
|
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Cost)}>Sort by Cost</Button>
|
||||||
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Reputation)}>Sort by Reputation</Button>
|
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Reputation)}>
|
||||||
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Default)}>Sort by Default Order</Button>
|
Sort by Reputation
|
||||||
|
</Button>
|
||||||
|
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Default)}>
|
||||||
|
Sort by Default Order
|
||||||
|
</Button>
|
||||||
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Purchasable)}>
|
<Button onClick={() => switchSortOrder(PurchaseAugmentationsOrderSetting.Purchasable)}>
|
||||||
Sort by Purchasable
|
Sort by Purchasable
|
||||||
</Button>
|
</Button>
|
||||||
<br />
|
</Box>
|
||||||
|
</Paper>
|
||||||
|
</Container>
|
||||||
|
|
||||||
<Table size="small" padding="none">
|
<PurchasableAugmentations
|
||||||
<TableBody>{augListElems}</TableBody>
|
augNames={purchasable}
|
||||||
</Table>
|
ownedAugNames={owned}
|
||||||
|
player={player}
|
||||||
<Table size="small" padding="none">
|
canPurchase={(player, aug) => {
|
||||||
<TableBody>{ownedElem}</TableBody>
|
return (
|
||||||
</Table>
|
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>
|
|
||||||
);
|
|
||||||
}
|
|
@ -31,9 +31,9 @@ export function calculateTradeInformationRepReward(
|
|||||||
const levelBonus = maxLevel * Math.pow(1.01, maxLevel);
|
const levelBonus = maxLevel * Math.pow(1.01, maxLevel);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
Math.pow(reward + 1, 2) *
|
Math.pow(reward + 1, 1.1) *
|
||||||
Math.pow(difficulty, 3) *
|
Math.pow(difficulty, 1.2) *
|
||||||
3e3 *
|
30 *
|
||||||
levelBonus *
|
levelBonus *
|
||||||
(player.hasAugmentation(AugmentationNames.WKSharmonizer, true) ? 1.5 : 1) *
|
(player.hasAugmentation(AugmentationNames.WKSharmonizer, true) ? 1.5 : 1) *
|
||||||
BitNodeMultipliers.InfiltrationMoney
|
BitNodeMultipliers.InfiltrationMoney
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
|
||||||
import { GraftableAugmentation } from "./GraftableAugmentation";
|
import { GraftableAugmentation } from "./GraftableAugmentation";
|
||||||
import { IPlayer } from "../IPlayer";
|
import { IPlayer } from "../IPlayer";
|
||||||
|
|
||||||
@ -7,8 +6,7 @@ export const getGraftingAvailableAugs = (player: IPlayer): string[] => {
|
|||||||
const augs: string[] = [];
|
const augs: string[] = [];
|
||||||
|
|
||||||
for (const [augName, aug] of Object.entries(Augmentations)) {
|
for (const [augName, aug] of Object.entries(Augmentations)) {
|
||||||
if (augName === AugmentationNames.NeuroFluxGovernor || augName === AugmentationNames.TheRedPill || aug.isSpecial)
|
if (aug.isSpecial) continue;
|
||||||
continue;
|
|
||||||
augs.push(augName);
|
augs.push(augName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,6 +139,7 @@ export const GraftingRoot = (): React.ReactElement => {
|
|||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<Box sx={{ maxHeight: 330, overflowY: "scroll" }}>
|
||||||
<Typography color={Settings.theme.info}>
|
<Typography color={Settings.theme.info}>
|
||||||
<b>Time to Graft:</b>{" "}
|
<b>Time to Graft:</b>{" "}
|
||||||
{convertTimeMsToTimeElapsedString(
|
{convertTimeMsToTimeElapsedString(
|
||||||
@ -146,12 +147,13 @@ export const GraftingRoot = (): React.ReactElement => {
|
|||||||
)}
|
)}
|
||||||
{/* Use formula so the displayed creation time is accurate to player bonus */}
|
{/* Use formula so the displayed creation time is accurate to player bonus */}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
{Augmentations[selectedAug].prereqs.length > 0 && (
|
{Augmentations[selectedAug].prereqs.length > 0 && (
|
||||||
<AugPreReqsChecklist player={player} aug={Augmentations[selectedAug]} />
|
<AugPreReqsChecklist player={player} aug={Augmentations[selectedAug]} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
<Typography sx={{ maxHeight: 305, overflowY: "scroll" }}>
|
|
||||||
|
<Typography>
|
||||||
{(() => {
|
{(() => {
|
||||||
const aug = Augmentations[selectedAug];
|
const aug = Augmentations[selectedAug];
|
||||||
|
|
||||||
@ -168,6 +170,7 @@ export const GraftingRoot = (): React.ReactElement => {
|
|||||||
})()}
|
})()}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
</Box>
|
||||||
</Paper>
|
</Paper>
|
||||||
) : (
|
) : (
|
||||||
<Typography>All Augmentations owned</Typography>
|
<Typography>All Augmentations owned</Typography>
|
||||||
|
@ -5,7 +5,6 @@ import { IPlayer } from "../IPlayer";
|
|||||||
|
|
||||||
import { Augmentation } from "../../Augmentation/Augmentation";
|
import { Augmentation } from "../../Augmentation/Augmentation";
|
||||||
import { Augmentations } from "../../Augmentation/Augmentations";
|
import { Augmentations } from "../../Augmentation/Augmentations";
|
||||||
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
|
|
||||||
import { Faction } from "../../Faction/Faction";
|
import { Faction } from "../../Faction/Faction";
|
||||||
import { Factions } from "../../Faction/Factions";
|
import { Factions } from "../../Faction/Factions";
|
||||||
|
|
||||||
@ -22,9 +21,6 @@ export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentat
|
|||||||
// Helper function that helps filter out augs that are already owned
|
// Helper function that helps filter out augs that are already owned
|
||||||
// and augs that aren't allowed for sleeves
|
// and augs that aren't allowed for sleeves
|
||||||
function isAvailableForSleeve(aug: Augmentation): boolean {
|
function isAvailableForSleeve(aug: Augmentation): boolean {
|
||||||
if (aug.name === AugmentationNames.NeuroFluxGovernor) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (ownedAugNames.includes(aug.name)) {
|
if (ownedAugNames.includes(aug.name)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -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 { Sleeve } from "../Sleeve";
|
||||||
import { findSleevePurchasableAugs } from "../SleeveHelpers";
|
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 {
|
interface IProps {
|
||||||
open: boolean;
|
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.
|
// and you must also have enough rep in that faction in order to purchase it.
|
||||||
const availableAugs = findSleevePurchasableAugs(props.sleeve, player);
|
const availableAugs = findSleevePurchasableAugs(props.sleeve, player);
|
||||||
|
|
||||||
function purchaseAugmentation(aug: Augmentation): void {
|
|
||||||
props.sleeve.tryBuyAugmentation(player, aug);
|
|
||||||
rerender();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal open={props.open} onClose={props.onClose}>
|
<Modal open={props.open} onClose={props.onClose}>
|
||||||
<>
|
<Container component={Paper} disableGutters maxWidth="lg" sx={{ mx: 0, mb: 1, p: 1 }}>
|
||||||
<Box sx={{ mx: 1 }}>
|
|
||||||
<Typography>
|
<Typography>
|
||||||
You can purchase Augmentations for your Duplicate Sleeves. These Augmentations have the same effect as they
|
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.
|
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 />
|
<br />
|
||||||
When purchasing an Augmentation for a Duplicate Sleeve, they are immediately installed. This means that the
|
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.
|
Duplicate Sleeve will immediately lose all of its stat experience.
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
Augmentations will appear below as they become available.
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box component={Paper} sx={{ my: 1, p: 1 }}>
|
</Container>
|
||||||
<Table size="small" padding="none">
|
<PurchasableAugmentations
|
||||||
<TableBody>
|
augNames={availableAugs.map((aug) => aug.name)}
|
||||||
{availableAugs.map((aug) => {
|
ownedAugNames={ownedAugNames}
|
||||||
return (
|
player={player}
|
||||||
<TableRow key={aug.name}>
|
canPurchase={(player, aug) => {
|
||||||
<TableCell>
|
return player.money > aug.startingCost;
|
||||||
<Button onClick={() => purchaseAugmentation(aug)} disabled={player.money < aug.startingCost}>
|
}}
|
||||||
Buy
|
purchaseAugmentation={(player, aug, _showModal) => {
|
||||||
</Button>
|
props.sleeve.tryBuyAugmentation(player, aug);
|
||||||
</TableCell>
|
rerender();
|
||||||
<TableCell>
|
}}
|
||||||
<Box display="flex">
|
sleeveAugs
|
||||||
<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>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -400,8 +400,19 @@ function evaluateVersionCompatibility(ver: string | number): void {
|
|||||||
if (ver < 15) {
|
if (ver < 15) {
|
||||||
(Settings as any).EditorTheme = { ...defaultMonacoTheme };
|
(Settings as any).EditorTheme = { ...defaultMonacoTheme };
|
||||||
}
|
}
|
||||||
|
//Fix contract names
|
||||||
if (ver < 16) {
|
if (ver < 16) {
|
||||||
Factions[FactionNames.ShadowsOfAnarchy] = new Faction(FactionNames.ShadowsOfAnarchy);
|
Factions[FactionNames.ShadowsOfAnarchy] = new Faction(FactionNames.ShadowsOfAnarchy);
|
||||||
|
//Iterate over all contracts on all servers
|
||||||
|
for (const server of GetAllServers()) {
|
||||||
|
for (const contract of server.contracts) {
|
||||||
|
//Rename old "HammingCodes: Integer to encoded Binary" contracts
|
||||||
|
//to "HammingCodes: Integer to Encoded Binary"
|
||||||
|
if (contract.type == "HammingCodes: Integer to encoded Binary") {
|
||||||
|
contract.type = "HammingCodes: Integer to Encoded Binary";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1250,7 +1250,7 @@ export const codingContractTypesMetadata: ICodingContractTypeMetadata[] = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "HammingCodes: Integer to encoded Binary",
|
name: "HammingCodes: Integer to Encoded Binary",
|
||||||
numTries: 10,
|
numTries: 10,
|
||||||
difficulty: 5,
|
difficulty: 5,
|
||||||
desc: (n: number): string => {
|
desc: (n: number): string => {
|
||||||
|
Loading…
Reference in New Issue
Block a user