BUGFIX: Sleeves can earn exp and purchase augmentations when enabling disableSleeveExpAndAugmentation (#2467)

This commit is contained in:
catloversg
2026-02-05 19:47:24 +07:00
committed by GitHub
parent 77cc582bf9
commit 796bef81b3
8 changed files with 125 additions and 20 deletions
+49 -6
View File
@@ -7,7 +7,7 @@
* Sleeves are unlocked in BitNode-10.
*/
import type { SleevePerson } from "@nsdefs";
import type { Result, SleevePerson } from "@nsdefs";
import type { Augmentation } from "../../Augmentation/Augmentation";
import type { SleeveWork } from "./Work/Work";
@@ -50,6 +50,7 @@ import { getFactionAugmentationsFiltered } from "../../Faction/FactionHelpers";
import { Augmentations } from "../../Augmentation/Augmentations";
import { getAugCost } from "../../Augmentation/AugmentationHelpers";
import type { MoneySource } from "../../utils/MoneySourceTracker";
import { formatMoney, formatSleeveShock } from "../../ui/formatNumber";
export class Sleeve extends Person implements SleevePerson {
currentWork: SleeveWork | null = null;
@@ -338,20 +339,62 @@ export class Sleeve extends Person implements SleevePerson {
return true;
}
tryBuyAugmentation(aug: Augmentation): boolean {
/**
* This function is only used in UI code for checking whether the "Manage Augmentations" button can be enabled. If you
* want to check if the player can purchase a specific augmentation, you need to call canPurchaseAugmentation.
*/
checkPreconditionsOfPurchasingAugmentations(): Result {
if (Player.bitNodeOptions.disableSleeveExpAndAugmentation) {
return {
success: false,
message: `The "Disable Sleeves' experience and augmentation" option was enabled. You cannot purchase augmentations for your sleeves.`,
};
}
if (this.shock > 0) {
return {
success: false,
message: `You must reduce the sleeve shock to 0. The current shock is ${formatSleeveShock(this.shock)}.`,
};
}
return { success: true };
}
canPurchaseAugmentation(aug: Augmentation): Result {
const checkingPreconditions = this.checkPreconditionsOfPurchasingAugmentations();
if (!checkingPreconditions.success) {
return checkingPreconditions;
}
if (!Player.canAfford(aug.baseCost)) {
return false;
return {
success: false,
message: `You must have at least ${formatMoney(aug.baseCost)}.`,
};
}
// Verify that this sleeve does not already have that augmentation.
if (this.hasAugmentation(aug.name)) return false;
if (this.hasAugmentation(aug.name)) {
return { success: false, message: `This sleeve already has "${aug.name}" augmentation.` };
}
// Verify that the augmentation is available for purchase.
if (!this.findPurchasableAugs().includes(aug)) return false;
if (!this.findPurchasableAugs().includes(aug)) {
return { success: false, message: `"${aug.name}" is not in the list of purchasable augmentations.` };
}
return { success: true };
}
purchaseAugmentation(aug: Augmentation): Result {
const validationResult = this.canPurchaseAugmentation(aug);
if (!validationResult.success) {
return validationResult;
}
Player.loseMoney(aug.baseCost, "sleeves");
this.installAugmentation(aug);
return true;
return { success: true };
}
upgradeMemory(n: number): void {
@@ -1,10 +1,10 @@
import { Container, Typography, Paper } from "@mui/material";
import React from "react";
import { PurchasableAugmentations } from "../../../Augmentation/ui/PurchasableAugmentations";
import { Player } from "@player";
import { Modal } from "../../../ui/React/Modal";
import { Sleeve } from "../Sleeve";
import { useRerender } from "../../../ui/React/hooks";
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
interface IProps {
open: boolean;
@@ -43,10 +43,14 @@ export function SleeveAugmentationsModal(props: IProps): React.ReactElement {
augNames={availableAugs.map((aug) => aug.name)}
ownedAugNames={ownedAugNames}
canPurchase={(aug) => {
return Player.money >= aug.baseCost;
return props.sleeve.canPurchaseAugmentation(aug).success;
}}
purchaseAugmentation={(aug) => {
props.sleeve.tryBuyAugmentation(aug);
const result = props.sleeve.purchaseAugmentation(aug);
if (!result.success) {
dialogBoxCreate(result.message);
return;
}
rerender();
}}
rerender={rerender}
+5 -2
View File
@@ -212,6 +212,7 @@ export function SleeveElem(props: SleeveElemProps): React.ReactElement {
}
}
const desc = getWorkDescription(props.sleeve, progress);
const checkingPreconditionsResult = props.sleeve.checkPreconditionsOfPurchasingAugmentations();
return (
<>
<Paper sx={{ p: 1, display: "grid", gridTemplateColumns: "1fr 1fr", width: "auto", gap: 1 }}>
@@ -231,12 +232,14 @@ export function SleeveElem(props: SleeveElemProps): React.ReactElement {
</span>
</Tooltip>
<Tooltip
title={props.sleeve.shock > 0 ? <Typography>Unlocked when sleeve has fully recovered</Typography> : ""}
title={
!checkingPreconditionsResult.success && <Typography>{checkingPreconditionsResult.message}</Typography>
}
>
<span>
<Button
onClick={() => setAugmentationsOpen(true)}
disabled={props.sleeve.shock > 0}
disabled={!checkingPreconditionsResult.success}
sx={{ width: "100%", height: "100%" }}
>
Manage Augmentations
@@ -7,6 +7,7 @@ import { Player } from "@player";
import { SleeveElem } from "./SleeveElem";
import { FAQModal } from "./FAQModal";
import { useCycleRerender } from "../../../ui/React/hooks";
import { Settings } from "../../../Settings/Settings";
export function SleeveRoot(): React.ReactElement {
const [FAQOpen, setFAQOpen] = useState(false);
@@ -25,6 +26,14 @@ export function SleeveRoot(): React.ReactElement {
<br />
<br />
</Typography>
{Player.bitNodeOptions.disableSleeveExpAndAugmentation && (
<Typography color={Settings.theme.warning}>
You enabled the "Disable Sleeves' experience and augmentation" option. Your sleeves will not gain
experience, and they won't be able to install augmentations.
<br />
<br />
</Typography>
)}
</Container>
<Button onClick={() => setFAQOpen(true)}>FAQ</Button>