SLEEVES: Add sleeve commands to purchase sleeves and memory via the API (#2443)

This commit is contained in:
TheAimMan
2026-01-20 15:55:51 -05:00
committed by GitHub
parent 19064a1b12
commit 210c338f86
17 changed files with 673 additions and 105 deletions

View File

@@ -5,9 +5,11 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import { makeStyles } from "tss-react/mui";
import { Player } from "@player";
import { Sleeve } from "../../PersonObjects/Sleeve/Sleeve";
import { ButtonWithTooltip } from "../../ui/Components/ButtonWithTooltip";
import { MaxSleevesFromCovenant } from "../../PersonObjects/Sleeve/SleeveCovenantPurchases";
import {
MaxSleevesFromCovenant,
recalculateNumberOfOwnedSleeves,
} from "../../PersonObjects/Sleeve/SleeveCovenantPurchases";
import { validBitNodes } from "../../BitNode/Constants";
import { DeleteServer, GetAllServers } from "../../Server/AllServers";
import { HacknetServer } from "../../Hacknet/HacknetServer";
@@ -48,7 +50,7 @@ export function SourceFilesDev({ parentRerender }: { parentRerender: () => void
Player.sourceFiles.delete(sfN);
Player.bitNodeOptions.sourceFileOverrides.delete(sfN);
if (sfN === 10) {
Sleeve.recalculateNumOwned();
recalculateNumberOfOwnedSleeves();
}
parentRerender();
return;
@@ -56,7 +58,7 @@ export function SourceFilesDev({ parentRerender }: { parentRerender: () => void
Player.sourceFiles.set(sfN, sfLvl);
Player.bitNodeOptions.sourceFileOverrides.set(sfN, sfLvl);
if (sfN === 10) {
Sleeve.recalculateNumOwned();
recalculateNumberOfOwnedSleeves();
}
parentRerender();
},
@@ -69,14 +71,14 @@ export function SourceFilesDev({ parentRerender }: { parentRerender: () => void
const addSleeve = useCallback(() => {
if (Player.sleevesFromCovenant >= 10) return;
Player.sleevesFromCovenant += 1;
Sleeve.recalculateNumOwned();
recalculateNumberOfOwnedSleeves();
parentRerender();
}, [parentRerender]);
const removeSleeve = useCallback(() => {
if (Player.sleevesFromCovenant <= 0) return;
Player.sleevesFromCovenant -= 1;
Sleeve.recalculateNumOwned();
recalculateNumberOfOwnedSleeves();
parentRerender();
}, [parentRerender]);

View File

@@ -1283,14 +1283,17 @@ import nsDoc_bitburner_skills_strength_md from "../../markdown/bitburner.skills.
import nsDoc_bitburner_skillsformulas_calculateexp_md from "../../markdown/bitburner.skillsformulas.calculateexp.md?raw";
import nsDoc_bitburner_skillsformulas_calculateskill_md from "../../markdown/bitburner.skillsformulas.calculateskill.md?raw";
import nsDoc_bitburner_skillsformulas_md from "../../markdown/bitburner.skillsformulas.md?raw";
import nsDoc_bitburner_sleeve_getmemoryupgradecost_md from "../../markdown/bitburner.sleeve.getmemoryupgradecost.md?raw";
import nsDoc_bitburner_sleeve_getnumsleeves_md from "../../markdown/bitburner.sleeve.getnumsleeves.md?raw";
import nsDoc_bitburner_sleeve_getsleeve_md from "../../markdown/bitburner.sleeve.getsleeve.md?raw";
import nsDoc_bitburner_sleeve_getsleeveaugmentationprice_md from "../../markdown/bitburner.sleeve.getsleeveaugmentationprice.md?raw";
import nsDoc_bitburner_sleeve_getsleeveaugmentationrepreq_md from "../../markdown/bitburner.sleeve.getsleeveaugmentationrepreq.md?raw";
import nsDoc_bitburner_sleeve_getsleeveaugmentations_md from "../../markdown/bitburner.sleeve.getsleeveaugmentations.md?raw";
import nsDoc_bitburner_sleeve_getsleevecost_md from "../../markdown/bitburner.sleeve.getsleevecost.md?raw";
import nsDoc_bitburner_sleeve_getsleevepurchasableaugs_md from "../../markdown/bitburner.sleeve.getsleevepurchasableaugs.md?raw";
import nsDoc_bitburner_sleeve_gettask_md from "../../markdown/bitburner.sleeve.gettask.md?raw";
import nsDoc_bitburner_sleeve_md from "../../markdown/bitburner.sleeve.md?raw";
import nsDoc_bitburner_sleeve_purchasesleeve_md from "../../markdown/bitburner.sleeve.purchasesleeve.md?raw";
import nsDoc_bitburner_sleeve_purchasesleeveaug_md from "../../markdown/bitburner.sleeve.purchasesleeveaug.md?raw";
import nsDoc_bitburner_sleeve_settobladeburneraction_md from "../../markdown/bitburner.sleeve.settobladeburneraction.md?raw";
import nsDoc_bitburner_sleeve_settocommitcrime_md from "../../markdown/bitburner.sleeve.settocommitcrime.md?raw";
@@ -1302,6 +1305,7 @@ import nsDoc_bitburner_sleeve_settoshockrecovery_md from "../../markdown/bitburn
import nsDoc_bitburner_sleeve_settosynchronize_md from "../../markdown/bitburner.sleeve.settosynchronize.md?raw";
import nsDoc_bitburner_sleeve_settouniversitycourse_md from "../../markdown/bitburner.sleeve.settouniversitycourse.md?raw";
import nsDoc_bitburner_sleeve_travel_md from "../../markdown/bitburner.sleeve.travel.md?raw";
import nsDoc_bitburner_sleeve_upgradememory_md from "../../markdown/bitburner.sleeve.upgradememory.md?raw";
import nsDoc_bitburner_sleevebladeburnertask_md from "../../markdown/bitburner.sleevebladeburnertask.md?raw";
import nsDoc_bitburner_sleeveclasstask_md from "../../markdown/bitburner.sleeveclasstask.md?raw";
import nsDoc_bitburner_sleevecompanytask_md from "../../markdown/bitburner.sleevecompanytask.md?raw";
@@ -2796,14 +2800,17 @@ AllPages["nsDoc/bitburner.skills.strength.md"] = nsDoc_bitburner_skills_strength
AllPages["nsDoc/bitburner.skillsformulas.calculateexp.md"] = nsDoc_bitburner_skillsformulas_calculateexp_md;
AllPages["nsDoc/bitburner.skillsformulas.calculateskill.md"] = nsDoc_bitburner_skillsformulas_calculateskill_md;
AllPages["nsDoc/bitburner.skillsformulas.md"] = nsDoc_bitburner_skillsformulas_md;
AllPages["nsDoc/bitburner.sleeve.getmemoryupgradecost.md"] = nsDoc_bitburner_sleeve_getmemoryupgradecost_md;
AllPages["nsDoc/bitburner.sleeve.getnumsleeves.md"] = nsDoc_bitburner_sleeve_getnumsleeves_md;
AllPages["nsDoc/bitburner.sleeve.getsleeve.md"] = nsDoc_bitburner_sleeve_getsleeve_md;
AllPages["nsDoc/bitburner.sleeve.getsleeveaugmentationprice.md"] = nsDoc_bitburner_sleeve_getsleeveaugmentationprice_md;
AllPages["nsDoc/bitburner.sleeve.getsleeveaugmentationrepreq.md"] = nsDoc_bitburner_sleeve_getsleeveaugmentationrepreq_md;
AllPages["nsDoc/bitburner.sleeve.getsleeveaugmentations.md"] = nsDoc_bitburner_sleeve_getsleeveaugmentations_md;
AllPages["nsDoc/bitburner.sleeve.getsleevecost.md"] = nsDoc_bitburner_sleeve_getsleevecost_md;
AllPages["nsDoc/bitburner.sleeve.getsleevepurchasableaugs.md"] = nsDoc_bitburner_sleeve_getsleevepurchasableaugs_md;
AllPages["nsDoc/bitburner.sleeve.gettask.md"] = nsDoc_bitburner_sleeve_gettask_md;
AllPages["nsDoc/bitburner.sleeve.md"] = nsDoc_bitburner_sleeve_md;
AllPages["nsDoc/bitburner.sleeve.purchasesleeve.md"] = nsDoc_bitburner_sleeve_purchasesleeve_md;
AllPages["nsDoc/bitburner.sleeve.purchasesleeveaug.md"] = nsDoc_bitburner_sleeve_purchasesleeveaug_md;
AllPages["nsDoc/bitburner.sleeve.settobladeburneraction.md"] = nsDoc_bitburner_sleeve_settobladeburneraction_md;
AllPages["nsDoc/bitburner.sleeve.settocommitcrime.md"] = nsDoc_bitburner_sleeve_settocommitcrime_md;
@@ -2815,6 +2822,7 @@ AllPages["nsDoc/bitburner.sleeve.settoshockrecovery.md"] = nsDoc_bitburner_sleev
AllPages["nsDoc/bitburner.sleeve.settosynchronize.md"] = nsDoc_bitburner_sleeve_settosynchronize_md;
AllPages["nsDoc/bitburner.sleeve.settouniversitycourse.md"] = nsDoc_bitburner_sleeve_settouniversitycourse_md;
AllPages["nsDoc/bitburner.sleeve.travel.md"] = nsDoc_bitburner_sleeve_travel_md;
AllPages["nsDoc/bitburner.sleeve.upgradememory.md"] = nsDoc_bitburner_sleeve_upgradememory_md;
AllPages["nsDoc/bitburner.sleevebladeburnertask.md"] = nsDoc_bitburner_sleevebladeburnertask_md;
AllPages["nsDoc/bitburner.sleeveclasstask.md"] = nsDoc_bitburner_sleeveclasstask_md;
AllPages["nsDoc/bitburner.sleevecompanytask.md"] = nsDoc_bitburner_sleevecompanytask_md;

View File

@@ -384,6 +384,10 @@ const sleeve = {
setToBladeburnerAction: RamCostConstants.SleeveBase,
getSleeveAugmentationPrice: RamCostConstants.SleeveBase,
getSleeveAugmentationRepReq: RamCostConstants.SleeveBase,
purchaseSleeve: RamCostConstants.SleeveBase,
upgradeMemory: RamCostConstants.SleeveBase,
getSleeveCost: RamCostConstants.SleeveBase,
getMemoryUpgradeCost: RamCostConstants.SleeveBase,
} as const;
// Stanek API

View File

@@ -15,6 +15,17 @@ import { Factions } from "../Faction/Factions";
import { SleeveWorkType } from "../PersonObjects/Sleeve/Work/Work";
import { canAccessBitNodeFeature } from "../BitNode/BitNodeUtils";
import { Crimes } from "../Crime/Crimes";
import {
getSleeveCost,
purchaseSleeve,
purchaseSleeveMemoryUpgrade,
} from "../PersonObjects/Sleeve/SleeveCovenantPurchases";
export const checkBitNodeRequirement = function (ctx: NetscriptContext) {
if (Player.bitNodeN !== 10) {
throw helpers.errorMessage(ctx, "You must be in BitNode 10 to use this API.");
}
};
export const checkSleeveAPIAccess = function (ctx: NetscriptContext) {
/**
@@ -290,6 +301,36 @@ export function NetscriptSleeve(): InternalAPI<NetscriptSleeve> {
}
return Player.sleeves[sleeveNumber].bladeburner(action, contract);
},
purchaseSleeve: (ctx) => () => {
checkBitNodeRequirement(ctx);
const result = purchaseSleeve();
if (!result.success) {
helpers.log(ctx, () => result.message);
}
return result;
},
upgradeMemory: (ctx) => (_sleeveNumber, _amount) => {
checkBitNodeRequirement(ctx);
const amount = helpers.positiveInteger(ctx, "amount", _amount);
const sleeveNumber = helpers.integer(ctx, "sleeveNumber", _sleeveNumber);
checkSleeveNumber(ctx, sleeveNumber);
const result = purchaseSleeveMemoryUpgrade(Player.sleeves[sleeveNumber], amount);
if (!result.success) {
helpers.log(ctx, () => result.message);
}
return result;
},
getSleeveCost: (ctx) => () => {
checkSleeveAPIAccess(ctx);
return getSleeveCost(Player.sleevesFromCovenant);
},
getMemoryUpgradeCost: (ctx) => (_sleeveNumber, _amount) => {
checkSleeveAPIAccess(ctx);
const amount = helpers.positiveInteger(ctx, "amount", _amount);
const sleeveNumber = helpers.integer(ctx, "sleeveNumber", _sleeveNumber);
checkSleeveNumber(ctx, sleeveNumber);
return Player.sleeves[sleeveNumber].getMemoryUpgradeCost(amount);
},
};
// Removed functions

View File

@@ -28,7 +28,6 @@ import { Faction } from "../../Faction/Faction";
import { Factions } from "../../Faction/Factions";
import { FactionInvitationEvents } from "../../Faction/ui/FactionInvitationManager";
import { resetGangs } from "../../Gang/AllGangs";
import { Sleeve } from "../Sleeve/Sleeve";
import { SleeveWorkType } from "../Sleeve/Work/Work";
import { calculateSkillProgress as calculateSkillProgressF, ISkillProgress } from "../formulas/skill";
import { AddToAllServers, createUniqueRandomIp } from "../../Server/AllServers";
@@ -57,6 +56,7 @@ import { PlayerEventType, PlayerEvents } from "./PlayerEvents";
import type { Result } from "@nsdefs";
import type { AchievementId } from "../../Achievements/Types";
import { Infiltration } from "../../Infiltration/Infiltration";
import { recalculateNumberOfOwnedSleeves } from "../Sleeve/SleeveCovenantPurchases";
export function init(this: PlayerObject): void {
/* Initialize Player's home computer */
@@ -114,7 +114,7 @@ export function prestigeAugmentation(this: PlayerObject): void {
this.queuedAugmentations = [];
Sleeve.recalculateNumOwned();
recalculateNumberOfOwnedSleeves();
this.sleeves.forEach((sleeve) => (sleeve.shock <= 0 ? sleeve.synchronize() : sleeve.shockRecovery()));

View File

@@ -195,13 +195,8 @@ export class Sleeve extends Person implements SleevePerson {
/** Returns the cost of upgrading this sleeve's memory by a certain amount */
getMemoryUpgradeCost(n: number): number {
const amt = Math.round(n);
if (amt < 0) {
return 0;
}
if (this.memory + amt > 100) {
return this.getMemoryUpgradeCost(100 - this.memory);
if (!Number.isInteger(n) || n < 0 || this.memory + n > 100) {
return Infinity;
}
const mult = 1.02;
@@ -524,24 +519,6 @@ export class Sleeve extends Person implements SleevePerson {
}
}
static recalculateNumOwned() {
/**
* Don't change sourceFileLvl to activeSourceFileLvl. The number of sleeves is a permanent effect. It's too
* troublesome for the player if they lose Sleeves and have to go BN10 to buy them again when they override the
* level of SF 10.
*/
const numSleeves =
Math.min(3, Player.sourceFileLvl(10) + (Player.bitNodeN === 10 ? 1 : 0)) + Player.sleevesFromCovenant;
while (Player.sleeves.length > numSleeves) {
const destroyedSleeve = Player.sleeves.pop();
// This should not happen, but avoid an infinite loop in case sleevesFromCovenent or sf10 level are somehow negative
if (!destroyedSleeve) return;
// Stop work, to prevent destroyed sleeves from continuing their tasks in the void
destroyedSleeve.stopWork();
}
while (Player.sleeves.length < numSleeves) Player.sleeves.push(new Sleeve());
}
whoAmI(): string {
return "Sleeve";
}

View File

@@ -1,3 +1,10 @@
import { Player } from "@player";
import type { Result } from "@nsdefs";
import { Sleeve } from "./Sleeve";
import { Factions } from "../../Faction/Factions";
import { FactionName } from "@enums";
import { formatMoney } from "../../ui/formatNumber";
/**
* Implements the purchasing of extra Duplicate Sleeves from The Covenant,
* as well as the purchasing of upgrades (memory)
@@ -5,3 +12,112 @@
export const MaxSleevesFromCovenant = 5;
export const BaseCostPerSleeve = 10e12;
export function getSleeveCost(sleevesFromCovenant: number): number {
// The first two checks are a bit over-the-top, but they are useful if we allow passing an arbitrary value to this
// function instead of only Player.sleevesFromCovenant.
if (
!Number.isInteger(sleevesFromCovenant) ||
sleevesFromCovenant < 0 ||
sleevesFromCovenant >= MaxSleevesFromCovenant
) {
return Infinity;
}
return Math.pow(10, sleevesFromCovenant) * BaseCostPerSleeve;
}
export function canPurchaseSleeve(): Result {
if (Player.bitNodeN !== 10) {
return {
success: false,
message: "You must be in BitNode 10 to purchase sleeves.",
};
}
if (!Factions[FactionName.TheCovenant].isMember) {
return {
success: false,
message: `You must be a member of ${FactionName.TheCovenant} to purchase sleeves.`,
};
}
if (Player.sleevesFromCovenant >= MaxSleevesFromCovenant) {
return {
success: false,
message: `You already have the maximum amount of sleeves purchasable from ${FactionName.TheCovenant}.`,
};
}
const cost = getSleeveCost(Player.sleevesFromCovenant);
if (!Player.canAfford(cost)) {
return {
success: false,
message: `You must have at least ${formatMoney(cost)} to buy this sleeve.`,
};
}
return { success: true };
}
export function recalculateNumberOfOwnedSleeves(): void {
// Don't change sourceFileLvl to activeSourceFileLvl. The number of sleeves is a permanent effect. It's too
// troublesome for the player if they lose Sleeves and have to go BN10 to buy them again when they override the
// level of SF 10.
const numSleeves =
Math.min(3, Player.sourceFileLvl(10) + (Player.bitNodeN === 10 ? 1 : 0)) + Player.sleevesFromCovenant;
while (Player.sleeves.length > numSleeves) {
const destroyedSleeve = Player.sleeves.pop();
// This should not happen, but avoid an infinite loop in case Player.sleevesFromCovenant or sf10 level are somehow
// negative
if (!destroyedSleeve) return;
// Stop work, to prevent destroyed sleeves from continuing their tasks in the void
destroyedSleeve.stopWork();
}
while (Player.sleeves.length < numSleeves) Player.sleeves.push(new Sleeve());
}
export function purchaseSleeve(): Result {
const validationResult = canPurchaseSleeve();
if (!validationResult.success) {
return validationResult;
}
Player.loseMoney(getSleeveCost(Player.sleevesFromCovenant), "sleeves");
Player.sleevesFromCovenant += 1;
recalculateNumberOfOwnedSleeves();
return { success: true };
}
export function canPurchaseMemoryUpgrade(sleeve: Sleeve, amount: number): Result {
if (Player.bitNodeN !== 10) {
return {
success: false,
message: "You must be in BitNode 10 to purchase sleeves' memory upgrade.",
};
}
if (!Factions[FactionName.TheCovenant].isMember) {
return {
success: false,
message: `You must be a member of ${FactionName.TheCovenant} to purchase sleeves' memory upgrade.`,
};
}
if (sleeve.memory + amount > 100) {
return {
success: false,
message: `Invalid amount of upgrade: ${amount}. The max memory of a sleeve is 100.`,
};
}
const cost = sleeve.getMemoryUpgradeCost(amount);
if (!Player.canAfford(cost)) {
return {
success: false,
message: `You must have at least ${formatMoney(cost)} to buy this sleeve's memory upgrade.`,
};
}
return { success: true };
}
export function purchaseSleeveMemoryUpgrade(sleeve: Sleeve, amount: number): Result {
const validationResult = canPurchaseMemoryUpgrade(sleeve, amount);
if (!validationResult.success) {
return validationResult;
}
Player.loseMoney(sleeve.getMemoryUpgradeCost(amount), "sleeves");
sleeve.upgradeMemory(amount);
return { success: true };
}

View File

@@ -6,8 +6,7 @@ import React from "react";
import { CovenantSleeveMemoryUpgrade } from "./CovenantSleeveMemoryUpgrade";
import { Sleeve } from "../Sleeve";
import { BaseCostPerSleeve, MaxSleevesFromCovenant } from "../SleeveCovenantPurchases";
import { MaxSleevesFromCovenant, canPurchaseSleeve, getSleeveCost, purchaseSleeve } from "../SleeveCovenantPurchases";
import { Money } from "../../../ui/React/Money";
import { Modal } from "../../../ui/React/Modal";
@@ -27,31 +26,13 @@ interface IProps {
export function CovenantPurchasesRoot(props: IProps): React.ReactElement {
const rerender = useRerender();
/** Get the cost to purchase a new Duplicate Sleeve */
function purchaseCost(): number {
return Math.pow(10, Player.sleevesFromCovenant) * BaseCostPerSleeve;
}
// Purchasing a new Duplicate Sleeve
let purchaseDisabled = false;
if (!Player.canAfford(purchaseCost())) {
purchaseDisabled = true;
}
if (Player.sleevesFromCovenant >= MaxSleevesFromCovenant) {
purchaseDisabled = true;
}
function purchaseOnClick(): void {
if (Player.sleevesFromCovenant >= MaxSleevesFromCovenant) return;
if (Player.canAfford(purchaseCost())) {
Player.loseMoney(purchaseCost(), "sleeves");
Player.sleevesFromCovenant += 1;
Sleeve.recalculateNumOwned();
rerender();
} else {
dialogBoxCreate(`You cannot afford to purchase a Duplicate Sleeve`);
const result = purchaseSleeve();
if (!result.success) {
dialogBoxCreate(result.message);
return;
}
rerender();
}
// Purchasing Upgrades for Sleeves
@@ -70,14 +51,14 @@ export function CovenantPurchasesRoot(props: IProps): React.ReactElement {
Purchase an additional Sleeve. These Duplicate Sleeves are permanent (they persist through BitNodes). You
can purchase a total of {MaxSleevesFromCovenant} from {FactionName.TheCovenant}.
</Typography>
<Button disabled={purchaseDisabled} onClick={purchaseOnClick}>
<Button disabled={!canPurchaseSleeve().success} onClick={purchaseOnClick}>
Purchase -&nbsp;
<Money money={purchaseCost()} forPurchase={true} />
<Money money={getSleeveCost(Player.sleevesFromCovenant)} forPurchase={true} />
</Button>
<br />
<br />
</>
)}
<br />
<br />
<Typography>You can also purchase upgrades for your Sleeves. These upgrades are also permanent.</Typography>
{upgradePanels}
</>

View File

@@ -5,7 +5,6 @@
import React, { useState } from "react";
import { Sleeve } from "../Sleeve";
import { Player } from "@player";
import { formatSleeveMemory } from "../../../ui/formatNumber";
import { Money } from "../../../ui/React/Money";
@@ -15,6 +14,8 @@ import TextField from "@mui/material/TextField";
import Button from "@mui/material/Button";
import Box from "@mui/material/Box";
import Paper from "@mui/material/Paper";
import { canPurchaseMemoryUpgrade, purchaseSleeveMemoryUpgrade } from "../SleeveCovenantPurchases";
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
interface IProps {
index: number;
@@ -26,51 +27,29 @@ export function CovenantSleeveMemoryUpgrade(props: IProps): React.ReactElement {
const [amt, setAmt] = useState(1);
function changePurchaseAmount(e: React.ChangeEvent<HTMLInputElement>): void {
let n: number = parseInt(e.target.value);
let n = parseInt(e.target.value);
if (isNaN(n)) n = 1;
if (n < 1) n = 1;
const maxMemory = 100 - props.sleeve.memory;
if (n > maxMemory) n = maxMemory;
if (!Number.isInteger(n)) {
n = 1;
}
const maxAmount = 100 - props.sleeve.memory;
if (n > maxAmount) {
n = maxAmount;
}
if (n < 1) {
n = 1;
}
setAmt(n);
}
function getPurchaseCost(): number {
if (isNaN(amt)) {
return Infinity;
}
const maxMemory = 100 - props.sleeve.memory;
if (amt > maxMemory) {
return Infinity;
}
return props.sleeve.getMemoryUpgradeCost(amt);
}
function purchaseMemory(): void {
const cost = getPurchaseCost();
if (Player.canAfford(cost)) {
props.sleeve.upgradeMemory(amt);
Player.loseMoney(cost, "sleeves");
props.rerender();
const result = purchaseSleeveMemoryUpgrade(props.sleeve, amt);
if (!result.success) {
dialogBoxCreate(result.message);
return;
}
}
// Purchase button props
const cost = getPurchaseCost();
const purchaseBtnDisabled = !Player.canAfford(cost);
let purchaseBtnContent = <></>;
if (isNaN(amt)) {
purchaseBtnContent = <>Invalid value</>;
} else {
purchaseBtnContent = (
<>
Purchase {amt} memory&nbsp;-&nbsp;
<Money money={cost} forPurchase={true} />
</>
);
props.rerender();
}
return (
@@ -88,8 +67,9 @@ export function CovenantSleeveMemoryUpgrade(props: IProps): React.ReactElement {
<TextField onChange={changePurchaseAmount} type={"number"} value={amt} />
</Box>
<br />
<Button disabled={purchaseBtnDisabled} onClick={purchaseMemory}>
{purchaseBtnContent}
<Button disabled={!canPurchaseMemoryUpgrade(props.sleeve, amt).success} onClick={purchaseMemory}>
Purchase {amt} memory&nbsp;-&nbsp;
<Money money={props.sleeve.getMemoryUpgradeCost(amt)} forPurchase={true} />
</Button>
</Paper>
);

View File

@@ -5436,6 +5436,51 @@ export interface Sleeve {
action: BladeburnerActionTypeForSleeve,
contract?: BladeburnerContractName,
): boolean;
/**
* Purchase a sleeve. You must be in BitNode 10 to use this API.
*
* @remarks
* RAM cost: 4 GB
*
* @returns Action result
*/
purchaseSleeve(): Result;
/**
* Upgrade memory of a sleeve. You must be in BitNode 10 to use this API.
*
* @remarks
* RAM cost: 4 GB
*
* @param sleeveNumber - Index of the sleeve.
* @param amount - Number of upgrades. Must be a positive integer.
* @returns Action result
*/
upgradeMemory(sleeveNumber: number, amount: number): Result;
/**
* Get the cost of the next sleeve.
*
* @remarks
* RAM cost: 4 GB
*
* @returns Cost of the next sleeve. Return Infinity if you reach the maximum number of purchasable sleeves.
*/
getSleeveCost(): number;
/**
* Get the cost of memory upgrades.
*
* @remarks
* RAM cost: 4 GB
*
* @param sleeveNumber - Index of the sleeve.
* @param amount - Number of upgrades. Must be a positive integer.
* @returns Cost of the upgrades. Return Infinity if the current memory plus the amount of upgrades is greater than
* 100.
*/
getMemoryUpgradeCost(sleeveNumber: number, amount: number): number;
}
/**