diff --git a/src/Augmentation/Augmentation.tsx b/src/Augmentation/Augmentation.tsx index eead67a98..247c535a3 100644 --- a/src/Augmentation/Augmentation.tsx +++ b/src/Augmentation/Augmentation.tsx @@ -9,6 +9,18 @@ import { Money } from "../ui/React/Money"; import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver"; import { FactionNames } from "../Faction/data/FactionNames"; +import { IPlayer } from "../PersonObjects/IPlayer"; +import { AugmentationNames } from "./data/AugmentationNames"; +import { CONSTANTS } from "../Constants"; +import { StaticAugmentations } from "./StaticAugmentations"; +import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers"; +import { getBaseAugmentationPriceMultiplier, getGenericAugmentationPriceMultiplier } from "./AugmentationHelpers"; +import { initInfiltratorsAugmentations } from "./data/AugmentationCreator"; + +export interface AugmentationCosts { + moneyCost: number; + repCost: number; +} export interface IConstructorParams { info: string | JSX.Element; @@ -410,10 +422,10 @@ function generateStatsDescription(mults: IMap, programs?: string[], star } export class Augmentation { - // How much money this costs to buy + // How much money this costs to buy before multipliers baseCost = 0; - // How much faction reputation is required to unlock this + // How much faction reputation is required to unlock this before multipliers baseRepRequirement = 0; // Description of what this Aug is and what it does @@ -425,9 +437,6 @@ export class Augmentation { // Any Augmentation not immediately available in BitNode-1 is special (e.g. Bladeburner augs) isSpecial = false; - // Augmentation level - for repeatable Augs like NeuroFlux Governor - level = 0; - // Name of Augmentation name = ""; @@ -438,12 +447,6 @@ export class Augmentation { // The Player/Person classes mults: IMap = {}; - // Initial cost. Doesn't change when you purchase multiple Augmentation - startingCost = 0; - - // Initial rep requirement. Doesn't change when you purchase multiple Augmentation - startingRepRequirement = 0; - // Factions that offer this aug. factions: string[] = []; @@ -462,16 +465,12 @@ export class Augmentation { this.baseRepRequirement = params.repCost; this.baseCost = params.moneyCost; - this.startingCost = this.baseCost; - this.startingRepRequirement = this.baseRepRequirement; this.factions = params.factions; if (params.isSpecial) { this.isSpecial = true; } - this.level = 0; - // Set multipliers if (params.hacking_mult) { this.mults.hacking_mult = params.hacking_mult; @@ -600,6 +599,59 @@ export class Augmentation { } } + getCost(player: IPlayer): AugmentationCosts { + const augmentationReference = StaticAugmentations[this.name]; + let moneyCost = augmentationReference.baseCost; + let repCost = augmentationReference.baseRepRequirement; + + if (augmentationReference.name === AugmentationNames.NeuroFluxGovernor) { + let nextLevel = this.getLevel(player); + --nextLevel; + const multiplier = Math.pow(CONSTANTS.NeuroFluxGovernorLevelMult, nextLevel); + repCost = augmentationReference.baseRepRequirement * multiplier * BitNodeMultipliers.AugmentationRepCost; + moneyCost = augmentationReference.baseCost * multiplier * BitNodeMultipliers.AugmentationMoneyCost; + + for (let i = 0; i < player.queuedAugmentations.length; ++i) { + augmentationReference.baseCost *= getBaseAugmentationPriceMultiplier(); + } + } else if (augmentationReference.factions.includes(FactionNames.Infiltrators)) { + const infiltratorAugmentationNames = initInfiltratorsAugmentations().map((augmentation) => augmentation.name); + const infiltratorMultiplier = + infiltratorAugmentationNames.filter((augmentationName) => player.hasAugmentation(augmentationName)).length + 1; + moneyCost = Math.pow(augmentationReference.baseCost * 1000, infiltratorMultiplier); + if (infiltratorAugmentationNames.find((augmentationName) => augmentationName === augmentationReference.name)) { + repCost = augmentationReference.baseRepRequirement * infiltratorMultiplier; + } + } else { + moneyCost = + augmentationReference.baseCost * + getGenericAugmentationPriceMultiplier() * + BitNodeMultipliers.AugmentationMoneyCost; + } + return { moneyCost, repCost }; + } + + getLevel(player: IPlayer): number { + // Get current Neuroflux level based on Player's augmentations + if (this.name === AugmentationNames.NeuroFluxGovernor) { + let currLevel = 0; + for (let i = 0; i < player.augmentations.length; ++i) { + if (player.augmentations[i].name === AugmentationNames.NeuroFluxGovernor) { + currLevel = player.augmentations[i].level; + } + } + + // Account for purchased but uninstalled Augmentations + for (let i = 0; i < player.queuedAugmentations.length; ++i) { + if (player.queuedAugmentations[i].name == AugmentationNames.NeuroFluxGovernor) { + ++currLevel; + } + } + return currLevel + 1; + } + return 0; + } + // Adds this Augmentation to all Factions addToAllFactions(): void { for (const fac of Object.keys(Factions)) { diff --git a/src/Augmentation/AugmentationHelpers.tsx b/src/Augmentation/AugmentationHelpers.tsx index a302347e5..ba96f378e 100644 --- a/src/Augmentation/AugmentationHelpers.tsx +++ b/src/Augmentation/AugmentationHelpers.tsx @@ -20,30 +20,10 @@ import { initNeuroFluxGovernor, initUnstableCircadianModulator, } from "./data/AugmentationCreator"; -import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers"; import { Router } from "../ui/GameRoot"; export function AddToStaticAugmentations(aug: Augmentation): void { const name = aug.name; - Augmentations[name] = aug; -} - -export function getNextNeuroFluxLevel(): number { - // Get current Neuroflux level based on Player's augmentations - let currLevel = 0; - for (let i = 0; i < Player.augmentations.length; ++i) { - if (Player.augmentations[i].name === AugmentationNames.NeuroFluxGovernor) { - currLevel = Player.augmentations[i].level; - } - } - - // Account for purchased but uninstalled Augmentations - for (let i = 0; i < Player.queuedAugmentations.length; ++i) { - if (Player.queuedAugmentations[i].name == AugmentationNames.NeuroFluxGovernor) { - ++currLevel; - } - } - return currLevel + 1; StaticAugmentations[name] = aug; } @@ -70,59 +50,16 @@ function initAugmentations(): void { resetFactionAugmentations(); clearObject(StaticAugmentations); createAugmentations(); - updateAugmentationCosts(); Player.reapplyAllAugmentations(); } -function getBaseAugmentationPriceMultiplier(): number { +export function getBaseAugmentationPriceMultiplier(): number { return CONSTANTS.MultipleAugMultiplier * [1, 0.96, 0.94, 0.93][Player.sourceFileLvl(11)]; } export function getGenericAugmentationPriceMultiplier(): number { return Math.pow(getBaseAugmentationPriceMultiplier(), Player.queuedAugmentations.length); } -function updateNeuroFluxGovernorCosts(neuroFluxGovernorAugmentation: Augmentation): void { - let nextLevel = getNextNeuroFluxLevel(); - --nextLevel; - const multiplier = Math.pow(CONSTANTS.NeuroFluxGovernorLevelMult, nextLevel); - neuroFluxGovernorAugmentation.baseRepRequirement = - neuroFluxGovernorAugmentation.startingRepRequirement * multiplier * BitNodeMultipliers.AugmentationRepCost; - neuroFluxGovernorAugmentation.baseCost = - neuroFluxGovernorAugmentation.startingCost * multiplier * BitNodeMultipliers.AugmentationMoneyCost; - - for (let i = 0; i < Player.queuedAugmentations.length; ++i) { - neuroFluxGovernorAugmentation.baseCost *= getBaseAugmentationPriceMultiplier(); - } -} - -function updateInfiltratorCosts(infiltratorAugmentation: Augmentation): void { - const infiltratorAugmentationNames = initInfiltratorsAugmentations().map((augmentation) => augmentation.name); - const infiltratorMultiplier = - infiltratorAugmentationNames.filter((augmentationName) => Player.hasAugmentation(augmentationName)).length + 1; - infiltratorAugmentation.baseCost = Math.pow(infiltratorAugmentation.startingCost * 1000, infiltratorMultiplier); - if (infiltratorAugmentationNames.find((augmentationName) => augmentationName === infiltratorAugmentation.name)) { - infiltratorAugmentation.baseRepRequirement = infiltratorAugmentation.startingRepRequirement * infiltratorMultiplier; - } -} - -export function updateAugmentationCosts(): void { - for (const name of Object.keys(Augmentations)) { - if (Augmentations.hasOwnProperty(name)) { - const augmentationToUpdate = Augmentations[name]; - if (augmentationToUpdate.name === AugmentationNames.NeuroFluxGovernor) { - updateNeuroFluxGovernorCosts(augmentationToUpdate); - } else if (augmentationToUpdate.factions.includes(FactionNames.Infiltrators)) { - updateInfiltratorCosts(augmentationToUpdate); - } else { - augmentationToUpdate.baseCost = - augmentationToUpdate.startingCost * - getGenericAugmentationPriceMultiplier() * - BitNodeMultipliers.AugmentationMoneyCost; - } - } - } -} - //Resets an Augmentation during (re-initizliation) function resetAugmentation(aug: Augmentation): void { aug.addToFactions(aug.factions); @@ -142,20 +79,6 @@ function applyAugmentation(aug: IPlayerOwnedAugmentation, reapply = false): void Player.setMult(mult, v); } - // Special logic for NeuroFlux Governor - if (aug.name === AugmentationNames.NeuroFluxGovernor) { - if (!reapply) { - Augmentations[aug.name].level = aug.level; - for (let i = 0; i < Player.augmentations.length; ++i) { - if (Player.augmentations[i].name == AugmentationNames.NeuroFluxGovernor) { - Player.augmentations[i].level = aug.level; - return; - // break; - } - } - } - } - // Special logic for Congruity Implant if (aug.name === AugmentationNames.CongruityImplant && !reapply) { Player.entropy = 0; diff --git a/src/Faction/FactionHelpers.tsx b/src/Faction/FactionHelpers.tsx index 43b8d80b6..ba13ac477 100644 --- a/src/Faction/FactionHelpers.tsx +++ b/src/Faction/FactionHelpers.tsx @@ -18,7 +18,6 @@ import { import { dialogBoxCreate } from "../ui/React/DialogBox"; import { InvitationEvent } from "./ui/InvitationModal"; import { FactionNames } from "./data/FactionNames"; -import { updateAugmentationCosts, getNextNeuroFluxLevel } from "../Augmentation/AugmentationHelpers"; import { SFC32RNG } from "../Casino/RNG"; export function inviteToFaction(faction: Faction): void { @@ -82,6 +81,7 @@ export function hasAugmentationPrereqs(aug: Augmentation): boolean { export function purchaseAugmentation(aug: Augmentation, fac: Faction, sing = false): string { const hasPrereqs = hasAugmentationPrereqs(aug); + const augCosts = aug.getCost(Player); if (!hasPrereqs) { const txt = `You must first purchase or install ${aug.prereqs.join(",")} before you can purchase this one.`; if (sing) { @@ -89,28 +89,26 @@ export function purchaseAugmentation(aug: Augmentation, fac: Faction, sing = fal } else { dialogBoxCreate(txt); } - } else if (aug.baseCost !== 0 && Player.money < aug.baseCost) { + } else if (augCosts.moneyCost !== 0 && Player.money < augCosts.moneyCost) { const txt = "You don't have enough money to purchase " + aug.name; if (sing) { return txt; } dialogBoxCreate(txt); - } else if (fac.playerReputation < aug.baseRepRequirement) { + } else if (fac.playerReputation < augCosts.repCost) { const txt = "You don't have enough faction reputation to purchase " + aug.name; if (sing) { return txt; } dialogBoxCreate(txt); - } else if (aug.baseCost === 0 || Player.money >= aug.baseCost) { + } else if (augCosts.moneyCost === 0 || Player.money >= augCosts.moneyCost) { const queuedAugmentation = new PlayerOwnedAugmentation(aug.name); if (aug.name == AugmentationNames.NeuroFluxGovernor) { - queuedAugmentation.level = getNextNeuroFluxLevel(); + queuedAugmentation.level = aug.getLevel(Player); } Player.queuedAugmentations.push(queuedAugmentation); - Player.loseMoney(aug.baseCost, "augmentations"); - - updateAugmentationCosts(); + Player.loseMoney(augCosts.moneyCost, "augmentations"); if (sing) { return "You purchased " + aug.name; diff --git a/src/Faction/ui/AugmentationsPage.tsx b/src/Faction/ui/AugmentationsPage.tsx index ea6b90e4c..79dad99dc 100644 --- a/src/Faction/ui/AugmentationsPage.tsx +++ b/src/Faction/ui/AugmentationsPage.tsx @@ -69,7 +69,7 @@ export function AugmentationsPage(props: IProps): React.ReactElement { throw new Error("Invalid Augmentation Names"); } - return aug1.baseCost - aug2.baseCost; + return aug1.getCost(player).moneyCost - aug2.getCost(player).moneyCost; }); return augs; @@ -78,11 +78,12 @@ export function AugmentationsPage(props: IProps): React.ReactElement { function getAugsSortedByPurchasable(): string[] { const augs = getAugs(); function canBuy(augName: string): boolean { - const repCost = aug.baseRepRequirement; const aug = StaticAugmentations[augName]; + const augCosts = aug.getCost(player) + const repCost = augCosts.repCost; const hasReq = props.faction.playerReputation >= repCost; const hasRep = hasAugmentationPrereqs(aug); - const hasCost = aug.baseCost !== 0 && player.money > aug.baseCost; + const hasCost = augCosts.moneyCost !== 0 && player.money > augCosts.moneyCost; return hasCost && hasReq && hasRep; } const buy = augs.filter(canBuy).sort((augName1, augName2) => { @@ -92,7 +93,7 @@ export function AugmentationsPage(props: IProps): React.ReactElement { throw new Error("Invalid Augmentation Names"); } - return aug1.baseCost - aug2.baseCost; + return aug1.getCost(player).moneyCost - aug2.getCost(player).moneyCost; }); const cantBuy = augs .filter((aug) => !canBuy(aug)) @@ -102,7 +103,7 @@ export function AugmentationsPage(props: IProps): React.ReactElement { if (aug1 == null || aug2 == null) { throw new Error("Invalid Augmentation Names"); } - return aug1.baseRepRequirement - aug2.baseRepRequirement; + return aug1.getCost(player).repCost - aug2.getCost(player).repCost; }); return buy.concat(cantBuy); @@ -116,7 +117,7 @@ export function AugmentationsPage(props: IProps): React.ReactElement { if (aug1 == null || aug2 == null) { throw new Error("Invalid Augmentation Names"); } - return aug1.baseRepRequirement - aug2.baseRepRequirement; + return aug1.getCost(player).repCost - aug2.getCost(player).repCost; }); return augs; diff --git a/src/Faction/ui/PurchaseAugmentationModal.tsx b/src/Faction/ui/PurchaseAugmentationModal.tsx index 658978aaf..22e01c4b4 100644 --- a/src/Faction/ui/PurchaseAugmentationModal.tsx +++ b/src/Faction/ui/PurchaseAugmentationModal.tsx @@ -42,7 +42,7 @@ export function PurchaseAugmentationModal(props: IProps): React.ReactElement {

Would you like to purchase the {props.aug.name} Augmentation for  - ? + ?

diff --git a/src/Faction/ui/PurchaseableAugmentation.tsx b/src/Faction/ui/PurchaseableAugmentation.tsx index 9446faf5e..3d4ec6728 100644 --- a/src/Faction/ui/PurchaseableAugmentation.tsx +++ b/src/Faction/ui/PurchaseableAugmentation.tsx @@ -22,7 +22,7 @@ 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"; +import { use } from "../../ui/Context"; interface IReqProps { augName: string; @@ -74,6 +74,7 @@ interface IProps { } export function PurchaseableAugmentation(props: IProps): React.ReactElement { + const player = use.Player(); const [open, setOpen] = useState(false); const aug = StaticAugmentations[props.augName]; if (aug == null) throw new Error(`aug ${props.augName} does not exists`); @@ -85,11 +86,12 @@ export function PurchaseableAugmentation(props: IProps): React.ReactElement { return <>; } - const moneyCost = aug.baseCost; - const repCost = aug.baseRepRequirement; + const repCosts = aug.getCost(player); + const moneyCost = repCosts.moneyCost; + const repCost = repCosts.repCost; const hasReq = hasAugmentationPrereqs(aug); const hasRep = props.faction.playerReputation >= repCost; - const hasCost = aug.baseCost === 0 || props.p.money > aug.baseCost; + const hasCost = moneyCost === 0 || props.p.money > moneyCost; // Determine UI properties const color: "error" | "primary" = !hasReq || !hasRep || !hasCost ? "error" : "primary"; @@ -97,7 +99,7 @@ export function PurchaseableAugmentation(props: IProps): React.ReactElement { // Determine button txt let btnTxt = aug.name; if (aug.name === AugmentationNames.NeuroFluxGovernor) { - btnTxt += ` - Level ${getNextNeuroFluxLevel()}`; + btnTxt += ` - Level ${aug.getLevel(player)}`; } let tooltip = <>; diff --git a/src/NetscriptFunctions/Singularity.ts b/src/NetscriptFunctions/Singularity.ts index 9921b0ce6..5d9fa48bb 100644 --- a/src/NetscriptFunctions/Singularity.ts +++ b/src/NetscriptFunctions/Singularity.ts @@ -1,3 +1,4 @@ +import { AugmentationCosts } from "./../Augmentation/Augmentation"; import { WorkerScript } from "../Netscript/WorkerScript"; import { IPlayer } from "../PersonObjects/IPlayer"; import { purchaseAugmentation, joinFaction, getFactionAugmentationsFiltered } from "../Faction/FactionHelpers"; @@ -122,7 +123,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript _ctx.helper.checkSingularityAccess(); const augName = _ctx.helper.string("augName", _augName); const aug = getAugmentation(_ctx, augName); - return [aug.baseRepRequirement, aug.baseCost]; + return [aug.getCost(player).moneyCost, aug.getCost(player).repCost]; }, getAugmentationPrereq: (_ctx: NetscriptContext) => function (_augName: unknown): string[] { @@ -136,14 +137,14 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript _ctx.helper.checkSingularityAccess(); const augName = _ctx.helper.string("augName", _augName); const aug = getAugmentation(_ctx, augName); - return aug.baseCost; + return aug.getCost(player).moneyCost; }, getAugmentationRepReq: (_ctx: NetscriptContext) => function (_augName: unknown): number { _ctx.helper.checkSingularityAccess(); const augName = _ctx.helper.string("augName", _augName); const aug = getAugmentation(_ctx, augName); - return aug.baseRepRequirement; + return aug.getCost(player).repCost; }, getAugmentationStats: (_ctx: NetscriptContext) => function (_augName: unknown): AugmentationStats { @@ -186,7 +187,7 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript } } - if (fac.playerReputation < aug.baseRepRequirement) { + if (fac.playerReputation < aug.getCost(player).repCost) { workerScript.log("purchaseAugmentation", () => `You do not have enough reputation with '${fac.name}'.`); return false; } @@ -1128,7 +1129,6 @@ export function NetscriptSingularity(player: IPlayer, workerScript: WorkerScript workerScript.log("workForFaction", () => `Invalid work type: '${type}`); return false; } - return true; }, getFactionRep: (_ctx: NetscriptContext) => function (_facName: unknown): number { diff --git a/src/NetscriptFunctions/Sleeve.ts b/src/NetscriptFunctions/Sleeve.ts index d3aafceb6..d2aa0b452 100644 --- a/src/NetscriptFunctions/Sleeve.ts +++ b/src/NetscriptFunctions/Sleeve.ts @@ -281,7 +281,7 @@ export function NetscriptSleeve(player: IPlayer, workerScript: WorkerScript, hel const aug = purchasableAugs[i]; augs.push({ name: aug.name, - cost: aug.startingCost, + cost: aug.baseCost, }); } diff --git a/src/PersonObjects/Grafting/GraftableAugmentation.ts b/src/PersonObjects/Grafting/GraftableAugmentation.ts index dbace889d..6875bbfc4 100644 --- a/src/PersonObjects/Grafting/GraftableAugmentation.ts +++ b/src/PersonObjects/Grafting/GraftableAugmentation.ts @@ -18,7 +18,7 @@ export class GraftableAugmentation { } get cost(): number { - return this.augmentation.startingCost * CONSTANTS.AugmentationGraftingCostMult; + return this.augmentation.baseCost * CONSTANTS.AugmentationGraftingCostMult; } get time(): number { diff --git a/src/PersonObjects/Sleeve/Sleeve.ts b/src/PersonObjects/Sleeve/Sleeve.ts index 74295b062..144e79357 100644 --- a/src/PersonObjects/Sleeve/Sleeve.ts +++ b/src/PersonObjects/Sleeve/Sleeve.ts @@ -678,7 +678,7 @@ export class Sleeve extends Person { } tryBuyAugmentation(p: IPlayer, aug: Augmentation): boolean { - if (!p.canAfford(aug.startingCost)) { + if (!p.canAfford(aug.baseCost)) { return false; } @@ -687,7 +687,7 @@ export class Sleeve extends Person { return false; } - p.loseMoney(aug.startingCost, "sleeves"); + p.loseMoney(aug.baseCost, "sleeves"); this.installAugmentation(aug); return true; } diff --git a/src/PersonObjects/Sleeve/SleeveHelpers.ts b/src/PersonObjects/Sleeve/SleeveHelpers.ts index 402547632..a53470573 100644 --- a/src/PersonObjects/Sleeve/SleeveHelpers.ts +++ b/src/PersonObjects/Sleeve/SleeveHelpers.ts @@ -74,7 +74,7 @@ export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentat continue; } - if (fac.playerReputation > aug.baseRepRequirement) { + if (fac.playerReputation > aug.getCost(p).repCost) { availableAugs.push(aug); } } @@ -98,7 +98,7 @@ export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentat continue; } - if (fac.playerReputation > aug.baseRepRequirement) { + if (fac.playerReputation > aug.getCost(p).repCost) { availableAugs.push(aug); } } diff --git a/src/PersonObjects/Sleeve/ui/SleeveAugmentationsModal.tsx b/src/PersonObjects/Sleeve/ui/SleeveAugmentationsModal.tsx index c3db83ec3..34446f202 100644 --- a/src/PersonObjects/Sleeve/ui/SleeveAugmentationsModal.tsx +++ b/src/PersonObjects/Sleeve/ui/SleeveAugmentationsModal.tsx @@ -66,7 +66,7 @@ export function SleeveAugmentationsModal(props: IProps): React.ReactElement { return ( - @@ -78,7 +78,7 @@ export function SleeveAugmentationsModal(props: IProps): React.ReactElement { - + );