post-grafting changes

This commit is contained in:
Olivier Gagnon 2022-03-29 14:09:17 -04:00
parent fb1bce579f
commit 680081c548
22 changed files with 198 additions and 190 deletions

@ -12,4 +12,5 @@ must be unlocked.
Source-Files <advancedgameplay/sourcefiles>
Intelligence <advancedgameplay/intelligence>
Sleeves <advancedgameplay/sleeves>
Grafting <advancedgameplay/grafting>
Hacking algorithms <advancedgameplay/hackingalgorithms>

@ -0,0 +1,18 @@
.. _gameplay_grafting:
Grafting
========
Grafting is an experimental process through which you can obtain the benefits of
Augmentations, without needing to reboot your body.
In order to graft, you must first purchase a blueprint for and craft the Augmentation.
This can be done at VitaLife in New Tokyo, where you'll find a shady researcher with
questionable connections. Once you purchase a blueprint, you will start crafting the
Augmentation, and it will be grafted to your body once complete.
Be warned, some who have tested grafting have reported an unidentified malware. Dubbed
"Entropy", this virus seems to grow in potency as more Augmentations are grafted,
causing unpredictable affects to the victim.
Note that when crafting an Augmentation, cancelling will **not** save your progress,
and the money spent will **not** be returned.

@ -16,4 +16,4 @@ Intelligence will boost your production for many actions in the game, including:
* Crime success rate
* Bladeburner
* Reputation gain for companies & factions
* Augmentation crafting speed
* Augmentation grafting speed

@ -91,20 +91,3 @@ and above, and is only available after defeating BitNode-10 at least once.
Memory is a persistent stat, meaning it never gets reset back to 1.
The maximum possible value for a sleeve's memory is 100.
Grafting
^^^^^^^^
Grafting is an experimental process through which you can obtain the benefits of
Augmentations, without needing to install them.
In order to graft, you must first purchase a blueprint for and craft the Augmentation.
This can be done at VitaLife in New Tokyo, where you'll find a shady researcher with
questionable connections. Once you purchase a blueprint, you will start crafting the
Augmentation, and it will be grafted to your body once complete.
Be warned, some who have tested grafting have reported an unidentified malware. Dubbed
"Entropy", this virus seems to grow in potency as more Augmentations are grafted,
causing unpredictable affects to the victim.
Note that when crafting an Augmentation, cancelling will **not** save your progress,
and the money spent will **not** be returned.

@ -53,7 +53,7 @@ List of all Source-Files
+-------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|| BitNode-10: Digital Carbon || * Each level of this grants a Duplicate Sleeve. |
|| || * Allows the player to access the `Sleeve API <https://github.com/danielyxie/bitburner/blob/dev/markdown/bitburner.sleeve.md>`_ in other BitNodes. |
|| || * Grants the player access to the VitaLife grafting laboratory in other BitNodes. Also grants access to the Grafting API. |
|| || * Grants the player access to the VitaLife secret laboratory in other BitNodes. Also grants access to the Grafting API. |
+-------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|| BitNode-11: The Big Crash || * Company favor increases both the player's salary and reputation gain at that |
|| || company by 1% per favor (rather than just the reputation gain). |

@ -59,7 +59,7 @@ export function InstalledAugmentations(): React.ReactElement {
</Button>
</Tooltip>
<List dense>
{player.entropyStacks > 0 &&
{player.entropy > 0 &&
(() => {
const [open, setOpen] = useState(false);
@ -69,7 +69,7 @@ export function InstalledAugmentations(): React.ReactElement {
<ListItemText
primary={
<Typography color={Settings.theme.hp} style={{ whiteSpace: "pre-wrap" }}>
Entropy ({player.entropyStacks} accumulated)
Entropy virus - Level {player.entropy}
</Typography>
}
/>
@ -83,7 +83,7 @@ export function InstalledAugmentations(): React.ReactElement {
<Box m={4}>
<Typography color={Settings.theme.hp}>
<b>All multipliers decreased by:</b>{" "}
{formatNumber((1 - CONSTANTS.EntropyEffect ** player.entropyStacks) * 100, 3)}% (multiplicative)
{formatNumber((1 - CONSTANTS.EntropyEffect ** player.entropy) * 100, 3)}% (multiplicative)
</Typography>
</Box>
</Collapse>

@ -41,7 +41,7 @@ export const CONSTANTS: {
IntelligenceInfiltrationWeight: number;
IntelligenceCrimeBaseExpGain: number;
IntelligenceProgramBaseExpGain: number;
IntelligenceCraftBaseExpGain: number;
IntelligenceGraftBaseExpGain: number;
IntelligenceTerminalHackBaseExpGain: number;
IntelligenceSingFnBaseExpGain: number;
IntelligenceClassBaseExpGain: number;
@ -72,7 +72,7 @@ export const CONSTANTS: {
WorkTypeCreateProgram: string;
WorkTypeStudyClass: string;
WorkTypeCrime: string;
WorkTypeCraftAugmentation: string;
WorkTypeGraftAugmentation: string;
ClassStudyComputerScience: string;
ClassDataStructures: string;
ClassNetworks: string;
@ -110,8 +110,8 @@ export const CONSTANTS: {
CodingContractBaseFactionRepGain: number;
CodingContractBaseCompanyRepGain: number;
CodingContractBaseMoneyGain: number;
AugmentationCraftingCostMult: number;
AugmentationCraftingTimeBase: number;
AugmentationGraftingCostMult: number;
AugmentationGraftingTimeBase: number;
EntropyEffect: number;
TotalNumBitNodes: number;
LatestUpdate: string;
@ -185,7 +185,7 @@ export const CONSTANTS: {
IntelligenceInfiltrationWeight: 0.1, // Weight for how much int affects infiltration success rates
IntelligenceCrimeBaseExpGain: 0.05,
IntelligenceProgramBaseExpGain: 0.1, // Program required hack level divided by this to determine int exp gain
IntelligenceCraftBaseExpGain: 0.05,
IntelligenceGraftBaseExpGain: 0.05,
IntelligenceTerminalHackBaseExpGain: 200, // Hacking exp divided by this to determine int exp gain
IntelligenceSingFnBaseExpGain: 1.5,
IntelligenceClassBaseExpGain: 0.01,
@ -230,7 +230,7 @@ export const CONSTANTS: {
WorkTypeCreateProgram: "Working on Create a Program",
WorkTypeStudyClass: "Studying or Taking a class at university",
WorkTypeCrime: "Committing a crime",
WorkTypeCraftAugmentation: "Crafting an Augmentation",
WorkTypeGraftAugmentation: "Grafting an Augmentation",
ClassStudyComputerScience: "studying Computer Science",
ClassDataStructures: "taking a Data Structures course",
@ -277,11 +277,11 @@ export const CONSTANTS: {
CodingContractBaseMoneyGain: 75e6,
// Augmentation crafting multipliers
AugmentationCraftingCostMult: 1.2,
AugmentationCraftingTimeBase: 3600000,
AugmentationGraftingCostMult: 3,
AugmentationGraftingTimeBase: 3600000,
// Value raised to the number of entropy stacks, then multiplied to player multipliers
EntropyEffect: 0.99,
EntropyEffect: 0.98,
// BitNode/Source-File related stuff
TotalNumBitNodes: 24,

@ -27,21 +27,21 @@ export function Entropy(props: IProps): React.ReactElement {
<Adjuster
label="Set entropy"
placeholder="entropy"
add={num => {
props.player.entropyStacks += num;
props.player.applyEntropy(props.player.entropyStacks);
add={(num) => {
props.player.entropy += num;
props.player.applyEntropy(props.player.entropy);
}}
subtract={num => {
props.player.entropyStacks -= num;
props.player.applyEntropy(props.player.entropyStacks);
subtract={(num) => {
props.player.entropy -= num;
props.player.applyEntropy(props.player.entropy);
}}
tons={() => {
props.player.entropyStacks += 1e12;
props.player.applyEntropy(props.player.entropyStacks);
props.player.entropy += 1e12;
props.player.applyEntropy(props.player.entropy);
}}
reset={() => {
props.player.entropyStacks = 0;
props.player.applyEntropy(props.player.entropyStacks);
props.player.entropy = 0;
props.player.applyEntropy(props.player.entropy);
}}
/>
</AccordionDetails>

@ -389,7 +389,7 @@ export const RamCosts: IMap<any> = {
grafting: {
getAugmentationCraftPrice: 3.75,
getAugmentationCraftTime: 3.75,
craftAugmentation: 7.5,
graftAugmentation: 7.5,
},
heart: {

@ -2318,7 +2318,7 @@ export function NetscriptFunctions(workerScript: WorkerScript): NS {
tor: Player.hasTorRouter(),
inBladeburner: Player.inBladeburner(),
hasCorporation: Player.hasCorporation(),
entropyStacks: Player.entropyStacks,
entropy: Player.entropy,
};
Object.assign(data.jobs, Player.jobs);
return data;

@ -2,16 +2,15 @@ import { CityName } from "../Locations/data/CityNames";
import { Augmentations } from "../Augmentation/Augmentations";
import { getRamCost } from "../Netscript/RamCostGenerator";
import { WorkerScript } from "../Netscript/WorkerScript";
import { CraftableAugmentation } from "../PersonObjects/Grafting/CraftableAugmentation";
import { GraftableAugmentation } from "../PersonObjects/Grafting/GraftableAugmentation";
import { getAvailableAugs } from "../PersonObjects/Grafting/ui/GraftingRoot";
import { IPlayer } from "../PersonObjects/IPlayer";
import { Grafting as IGrafting } from "../ScriptEditor/NetscriptDefinitions";
import { SourceFileFlags } from "../SourceFile/SourceFileFlags";
import { Router } from "../ui/GameRoot";
import { INetscriptHelper } from "./INetscriptHelper";
export function NetscriptGrafting(player: IPlayer, workerScript: WorkerScript, helper: INetscriptHelper): IGrafting {
const checkGraftingAPIAccess = (func: any): void => {
const checkGraftingAPIAccess = (func: string): void => {
if (!player.canAccessGrafting()) {
throw helper.makeRuntimeErrorMsg(
`grafting.${func}`,
@ -21,54 +20,58 @@ export function NetscriptGrafting(player: IPlayer, workerScript: WorkerScript, h
};
return {
getAugmentationCraftPrice: (augName: string): number => {
helper.updateDynamicRam("getAugmentationCraftPrice", getRamCost(player, "grafting", "getAugmentationCraftPrice"));
checkGraftingAPIAccess("getAugmentationCraftPrice");
getAugmentationGraftPrice: (_augName: unknown): number => {
const augName = helper.string("getAugmentationGraftPrice", "augName", _augName);
helper.updateDynamicRam("getAugmentationGraftPrice", getRamCost(player, "grafting", "getAugmentationGraftPrice"));
checkGraftingAPIAccess("getAugmentationGraftPrice");
if (!Augmentations.hasOwnProperty(augName)) {
throw helper.makeRuntimeErrorMsg("grafting.getAugmentationCraftPrice", `Invalid aug: ${augName}`);
throw helper.makeRuntimeErrorMsg("grafting.getAugmentationGraftPrice", `Invalid aug: ${augName}`);
}
const craftableAug = new CraftableAugmentation(Augmentations[augName]);
const craftableAug = new GraftableAugmentation(Augmentations[augName]);
return craftableAug.cost;
},
getAugmentationCraftTime: (augName: string): number => {
helper.updateDynamicRam("getAugmentationCraftTime", getRamCost(player, "grafting", "getAugmentationCraftTime"));
checkGraftingAPIAccess("getAugmentationCraftTime");
getAugmentationGraftTime: (_augName: string): number => {
const augName = helper.string("getAugmentationGraftTime", "augName", _augName);
helper.updateDynamicRam("getAugmentationGraftTime", getRamCost(player, "grafting", "getAugmentationGraftTime"));
checkGraftingAPIAccess("getAugmentationGraftTime");
if (!Augmentations.hasOwnProperty(augName)) {
throw helper.makeRuntimeErrorMsg("grafting.getAugmentationCraftTime", `Invalid aug: ${augName}`);
throw helper.makeRuntimeErrorMsg("grafting.getAugmentationGraftTime", `Invalid aug: ${augName}`);
}
const craftableAug = new CraftableAugmentation(Augmentations[augName]);
const craftableAug = new GraftableAugmentation(Augmentations[augName]);
return craftableAug.time;
},
craftAugmentation: (augName: string, focus = true): boolean => {
helper.updateDynamicRam("craftAugmentation", getRamCost(player, "grafting", "craftAugmentation"));
checkGraftingAPIAccess("craftAugmentation");
graftAugmentation: (_augName: string, _focus: unknown = true): boolean => {
const augName = helper.string("graftAugmentation", "augName", _augName);
const focus = helper.boolean(_focus);
helper.updateDynamicRam("graftAugmentation", getRamCost(player, "grafting", "graftAugmentation"));
checkGraftingAPIAccess("graftAugmentation");
if (player.city !== CityName.NewTokyo) {
throw helper.makeRuntimeErrorMsg(
"grafting.craftAugmentation",
"grafting.graftAugmentation",
"You must be in New Tokyo to begin crafting an Augmentation.",
);
}
if (!getAvailableAugs(player).includes(augName)) {
workerScript.log("grafting.craftAugmentation", () => `Invalid aug: ${augName}`);
workerScript.log("grafting.graftAugmentation", () => `Invalid aug: ${augName}`);
return false;
}
const wasFocusing = player.focus;
if (player.isWorking) {
const txt = player.singularityStopWork();
workerScript.log("craftAugmentation", () => txt);
workerScript.log("graftAugmentation", () => txt);
}
const craftableAug = new CraftableAugmentation(Augmentations[augName]);
const craftableAug = new GraftableAugmentation(Augmentations[augName]);
if (player.money < craftableAug.cost) {
workerScript.log("grafting.craftAugmentation", () => `You don't have enough money to craft ${augName}`);
workerScript.log("grafting.graftAugmentation", () => `You don't have enough money to craft ${augName}`);
return false;
}
player.loseMoney(craftableAug.cost, "augmentations");
player.startCraftAugmentationWork(augName, craftableAug.time);
player.startGraftAugmentationWork(augName, craftableAug.time);
if (focus) {
player.startFocusing();
@ -78,7 +81,7 @@ export function NetscriptGrafting(player: IPlayer, workerScript: WorkerScript, h
Router.toTerminal();
}
workerScript.log("grafting.craftAugmentation", () => `Began crafting Augmentation ${augName}.`);
workerScript.log("grafting.graftAugmentation", () => `Began crafting Augmentation ${augName}.`);
return true;
},
};

@ -9,7 +9,7 @@ export interface IConstructorParams {
readonly time: number;
}
export class CraftableAugmentation {
export class GraftableAugmentation {
// The augmentation that this craftable corresponds to
augmentation: Augmentation;
@ -18,7 +18,7 @@ export class CraftableAugmentation {
}
get cost(): number {
return this.augmentation.startingCost * CONSTANTS.AugmentationCraftingCostMult;
return this.augmentation.startingCost * CONSTANTS.AugmentationGraftingCostMult;
}
get time(): number {
@ -26,6 +26,6 @@ export class CraftableAugmentation {
const antiLog = Math.max(sum(Object.values(this.augmentation.mults)), 1);
const mult = Math.log2(antiLog);
return CONSTANTS.AugmentationCraftingTimeBase * mult + CONSTANTS.MillisecondsPerHalfHour;
return CONSTANTS.AugmentationGraftingTimeBase * mult + CONSTANTS.MillisecondsPerHalfHour;
}
}

@ -17,9 +17,9 @@ import { CONSTANTS } from "../../../Constants";
import { IPlayer } from "../../IPlayer";
import { CraftableAugmentation } from "../CraftableAugmentation";
import { GraftableAugmentation } from "../GraftableAugmentation";
const CraftableAugmentations: IMap<CraftableAugmentation> = {};
const GraftableAugmentations: IMap<GraftableAugmentation> = {};
export const getAvailableAugs = (player: IPlayer): string[] => {
const augs: string[] = [];
@ -39,12 +39,12 @@ export const GraftingRoot = (): React.ReactElement => {
for (const aug of Object.values(Augmentations)) {
const name = aug.name;
const craftableAug = new CraftableAugmentation(aug);
CraftableAugmentations[name] = craftableAug;
const graftableAug = new GraftableAugmentation(aug);
GraftableAugmentations[name] = graftableAug;
}
const [selectedAug, setSelectedAug] = useState(getAvailableAugs(player)[0]);
const [craftOpen, setCraftOpen] = useState(false);
const [graftOpen, setGraftOpen] = useState(false);
return (
<Container disableGutters maxWidth="lg" sx={{ mx: 0 }}>
@ -63,7 +63,7 @@ export const GraftingRoot = (): React.ReactElement => {
</Typography>
<Box sx={{ my: 3 }}>
<Typography variant="h5">Craft Augmentations</Typography>
<Typography variant="h5">Graft Augmentations</Typography>
<Paper sx={{ my: 1, width: "fit-content", display: "grid", gridTemplateColumns: "1fr 3fr" }}>
<List sx={{ maxHeight: 400, overflowY: "scroll", borderRight: `1px solid ${Settings.theme.welllight}` }}>
{getAvailableAugs(player).map((k, i) => (
@ -77,29 +77,29 @@ export const GraftingRoot = (): React.ReactElement => {
<Construction sx={{ mr: 1 }} /> {selectedAug}
</Typography>
<Button
onClick={() => setCraftOpen(true)}
onClick={() => setGraftOpen(true)}
sx={{ width: "100%" }}
disabled={player.money < CraftableAugmentations[selectedAug].cost}
disabled={player.money < GraftableAugmentations[selectedAug].cost}
>
Craft Augmentation (
<Typography color={Settings.theme.money}>
<Money money={CraftableAugmentations[selectedAug].cost} player={player} />
Graft Augmentation (
<Typography>
<Money money={GraftableAugmentations[selectedAug].cost} player={player} />
</Typography>
)
</Button>
<ConfirmationModal
open={craftOpen}
onClose={() => setCraftOpen(false)}
open={graftOpen}
onClose={() => setGraftOpen(false)}
onConfirm={() => {
const craftableAug = CraftableAugmentations[selectedAug];
player.loseMoney(craftableAug.cost, "augmentations");
player.startCraftAugmentationWork(selectedAug, craftableAug.time);
const graftableAug = GraftableAugmentations[selectedAug];
player.loseMoney(graftableAug.cost, "augmentations");
player.startGraftAugmentationWork(selectedAug, graftableAug.time);
player.startFocusing();
router.toWork();
}}
confirmationText={
<>
Cancelling crafting will <b>not</b> save crafting progress, and the money you spend will <b>not</b> be
Cancelling grafting will <b>not</b> save grafting progress, and the money you spend will <b>not</b> be
returned.
<br />
<br />
@ -108,9 +108,9 @@ export const GraftingRoot = (): React.ReactElement => {
}
/>
<Typography color={Settings.theme.info}>
<b>Time to Craft:</b>{" "}
<b>Time to Graft:</b>{" "}
{convertTimeMsToTimeElapsedString(
CraftableAugmentations[selectedAug].time / (1 + (player.getIntelligenceBonus(3) - 1) / 3),
GraftableAugmentations[selectedAug].time / (1 + (player.getIntelligenceBonus(3) - 1) / 3),
)}
{/* Use formula so the displayed creation time is accurate to player bonus */}
</Typography>
@ -135,14 +135,14 @@ export const GraftingRoot = (): React.ReactElement => {
</Box>
<Box sx={{ my: 3 }}>
<Typography variant="h5">Entropy Accumulation</Typography>
<Typography variant="h5">Entropy virus</Typography>
<Paper sx={{ my: 1, p: 1, width: "fit-content" }}>
<Typography>
<b>Accumulated Entropy:</b> {player.entropyStacks}
<b>Entropy strength:</b> {player.entropy}
<br />
<b>All multipliers decreased by:</b>{" "}
{formatNumber((1 - CONSTANTS.EntropyEffect ** player.entropyStacks) * 100, 3)}% (multiplicative)
{formatNumber((1 - CONSTANTS.EntropyEffect ** player.entropy) * 100, 3)}% (multiplicative)
</Typography>
</Paper>

@ -128,8 +128,8 @@ export interface IPlayer {
factionWorkType: string;
createProgramName: string;
timeWorkedCreateProgram: number;
craftAugmentationName: string;
timeWorkedCraftAugmentation: number;
graftAugmentationName: string;
timeWorkedGraftAugmentation: number;
crimeType: string;
committingCrimeThruSingFn: boolean;
singFnCrimeWorkerScript: WorkerScript | null;
@ -160,7 +160,7 @@ export interface IPlayer {
workChaExpGainRate: number;
workMoneyLossRate: number;
entropyStacks: number;
entropy: number;
// Methods
work(numCycles: number): boolean;
@ -288,8 +288,8 @@ export interface IPlayer {
setMult(name: string, mult: number): void;
canAccessCotMG(): boolean;
sourceFileLvl(n: number): number;
startCraftAugmentationWork(augmentationName: string, time: number): void;
craftAugmentationWork(numCycles: number): boolean;
finishCraftAugmentationWork(cancelled: boolean): string;
startGraftAugmentationWork(augmentationName: string, time: number): void;
graftAugmentationWork(numCycles: number): boolean;
finishGraftAugmentationWork(cancelled: boolean): string;
applyEntropy(stacks?: number): void;
}

@ -137,8 +137,8 @@ export class PlayerObject implements IPlayer {
factionWorkType: string;
createProgramName: string;
timeWorkedCreateProgram: number;
craftAugmentationName: string;
timeWorkedCraftAugmentation: number;
graftAugmentationName: string;
timeWorkedGraftAugmentation: number;
crimeType: string;
committingCrimeThruSingFn: boolean;
singFnCrimeWorkerScript: WorkerScript | null;
@ -169,7 +169,7 @@ export class PlayerObject implements IPlayer {
workChaExpGainRate: number;
workMoneyLossRate: number;
entropyStacks: number;
entropy: number;
// Methods
work: (numCycles: number) => boolean;
@ -298,9 +298,9 @@ export class PlayerObject implements IPlayer {
setMult: (name: string, mult: number) => void;
canAccessCotMG: () => boolean;
sourceFileLvl: (n: number) => number;
startCraftAugmentationWork: (augmentationName: string, time: number) => void;
craftAugmentationWork: (numCycles: number) => boolean;
finishCraftAugmentationWork: (cancelled: boolean) => string;
startGraftAugmentationWork: (augmentationName: string, time: number) => void;
graftAugmentationWork: (numCycles: number) => boolean;
finishGraftAugmentationWork: (cancelled: boolean) => string;
applyEntropy: (stacks?: number) => void;
constructor() {
@ -425,8 +425,8 @@ export class PlayerObject implements IPlayer {
this.createProgramName = "";
this.createProgramReqLvl = 0;
this.craftAugmentationName = "";
this.timeWorkedCraftAugmentation = 0;
this.graftAugmentationName = "";
this.timeWorkedGraftAugmentation = 0;
this.className = "";
@ -470,7 +470,7 @@ export class PlayerObject implements IPlayer {
//bitnode
this.bitNodeN = 1;
this.entropyStacks = 0;
this.entropy = 0;
//Used to store the last update time.
this.lastUpdate = 0;
@ -493,11 +493,11 @@ export class PlayerObject implements IPlayer {
// Let's get a hash of some semi-random stuff so we have something unique.
this.identifier = cyrb53(
"I-" +
new Date().getTime() +
navigator.userAgent +
window.innerWidth +
window.innerHeight +
getRandomInt(100, 999),
new Date().getTime() +
navigator.userAgent +
window.innerWidth +
window.innerHeight +
getRandomInt(100, 999),
);
this.init = generalMethods.init;
@ -551,9 +551,9 @@ export class PlayerObject implements IPlayer {
this.startCreateProgramWork = generalMethods.startCreateProgramWork;
this.createProgramWork = generalMethods.createProgramWork;
this.finishCreateProgramWork = generalMethods.finishCreateProgramWork;
this.startCraftAugmentationWork = generalMethods.startCraftAugmentationWork;
this.craftAugmentationWork = generalMethods.craftAugmentationWork;
this.finishCraftAugmentationWork = generalMethods.finishCraftAugmentationWork;
this.startGraftAugmentationWork = generalMethods.startGraftAugmentationWork;
this.graftAugmentationWork = generalMethods.craftAugmentationWork;
this.finishGraftAugmentationWork = generalMethods.finishGraftAugmentationWork;
this.startClass = generalMethods.startClass;
this.takeClass = generalMethods.takeClass;
this.finishClass = generalMethods.finishClass;

@ -180,7 +180,7 @@ export function prestigeAugmentation(this: PlayerObject): void {
}
export function prestigeSourceFile(this: IPlayer): void {
this.entropyStacks = 0;
this.entropy = 0;
this.prestigeAugmentation();
this.karma = 0;
// Duplicate sleeves are reset to level 1 every Bit Node (but the number of sleeves you have persists)
@ -528,12 +528,12 @@ export function resetWorkStatus(this: IPlayer, generalType?: string, group?: str
this.timeWorked = 0;
this.timeWorkedCreateProgram = 0;
this.timeWorkedCraftAugmentation = 0;
this.timeWorkedGraftAugmentation = 0;
this.currentWorkFactionName = "";
this.currentWorkFactionDescription = "";
this.createProgramName = "";
this.craftAugmentationName = "";
this.graftAugmentationName = "";
this.className = "";
this.workType = "";
}
@ -610,8 +610,8 @@ export function process(this: IPlayer, router: IRouter, numCycles = 1): void {
if (this.workPartTime(numCycles)) {
router.toCity();
}
} else if (this.workType === CONSTANTS.WorkTypeCraftAugmentation) {
if (this.craftAugmentationWork(numCycles)) {
} else if (this.workType === CONSTANTS.WorkTypeGraftAugmentation) {
if (this.graftAugmentationWork(numCycles)) {
router.toGrafting();
}
} else if (this.work(numCycles)) {
@ -1335,17 +1335,13 @@ export function finishCreateProgramWork(this: IPlayer, cancelled: boolean): stri
return "You've finished creating " + programName + "! The new program can be found on your home computer.";
}
export function startCraftAugmentationWork(
this: IPlayer,
augmentationName: string,
time: number,
): void {
this.resetWorkStatus()
export function startGraftAugmentationWork(this: IPlayer, augmentationName: string, time: number): void {
this.resetWorkStatus();
this.isWorking = true;
this.workType = CONSTANTS.WorkTypeCraftAugmentation;
this.workType = CONSTANTS.WorkTypeGraftAugmentation;
this.timeNeededToCompleteWork = time;
this.craftAugmentationName = augmentationName;
this.graftAugmentationName = augmentationName;
}
export function craftAugmentationWork(this: IPlayer, numCycles: number): boolean {
@ -1358,35 +1354,37 @@ export function craftAugmentationWork(this: IPlayer, numCycles: number): boolean
skillMult *= focusBonus;
this.timeWorked += CONSTANTS._idleSpeed * numCycles;
this.timeWorkedCraftAugmentation += CONSTANTS._idleSpeed * numCycles * skillMult;
this.timeWorkedGraftAugmentation += CONSTANTS._idleSpeed * numCycles * skillMult;
if (this.timeWorkedCraftAugmentation >= this.timeNeededToCompleteWork) {
this.finishCraftAugmentationWork(false);
if (this.timeWorkedGraftAugmentation >= this.timeNeededToCompleteWork) {
this.finishGraftAugmentationWork(false);
return true;
}
return false;
}
export function finishCraftAugmentationWork(this: IPlayer, cancelled: boolean): string {
const augName = this.craftAugmentationName;
export function finishGraftAugmentationWork(this: IPlayer, cancelled: boolean): string {
const augName = this.graftAugmentationName;
if (cancelled === false) {
dialogBoxCreate(`You've finished crafting ${augName}.<br>The augmentation has been grafted to your body, but you feel a bit off.`)
dialogBoxCreate(
`You've finished crafting ${augName}.<br>The augmentation has been grafted to your body, but you feel a bit off.`,
);
applyAugmentation(Augmentations[augName]);
this.entropyStacks += 1;
this.applyEntropy(this.entropyStacks);
this.entropy += 1;
this.applyEntropy(this.entropy);
} else {
dialogBoxCreate(`You cancelled the crafting of ${augName}.<br>Your money was not returned to you.`)
dialogBoxCreate(`You cancelled the crafting of ${augName}.<br>Your money was not returned to you.`);
}
// Intelligence gain
if (!cancelled) {
this.gainIntelligenceExp((CONSTANTS.IntelligenceCraftBaseExpGain * this.timeWorked) / 10000);
this.gainIntelligenceExp((CONSTANTS.IntelligenceGraftBaseExpGain * this.timeWorked) / 10000);
}
this.isWorking = false;
this.resetWorkStatus();
return `Crafting of ${augName} has ended.`
return `Grafting of ${augName} has ended.`;
}
/* Studying/Taking Classes */
@ -1567,20 +1565,20 @@ export function finishCrime(this: IPlayer, cancelled: boolean): string {
if (ws.disableLogs.ALL == null && ws.disableLogs.commitCrime == null) {
ws.scriptRef.log(
"SUCCESS: Crime successful! Gained " +
numeralWrapper.formatMoney(this.workMoneyGained) +
", " +
numeralWrapper.formatExp(this.workHackExpGained) +
" hack exp, " +
numeralWrapper.formatExp(this.workStrExpGained) +
" str exp, " +
numeralWrapper.formatExp(this.workDefExpGained) +
" def exp, " +
numeralWrapper.formatExp(this.workDexExpGained) +
" dex exp, " +
numeralWrapper.formatExp(this.workAgiExpGained) +
" agi exp, " +
numeralWrapper.formatExp(this.workChaExpGained) +
" cha exp.",
numeralWrapper.formatMoney(this.workMoneyGained) +
", " +
numeralWrapper.formatExp(this.workHackExpGained) +
" hack exp, " +
numeralWrapper.formatExp(this.workStrExpGained) +
" str exp, " +
numeralWrapper.formatExp(this.workDefExpGained) +
" def exp, " +
numeralWrapper.formatExp(this.workDexExpGained) +
" dex exp, " +
numeralWrapper.formatExp(this.workAgiExpGained) +
" agi exp, " +
numeralWrapper.formatExp(this.workChaExpGained) +
" cha exp.",
);
}
} else {
@ -1619,18 +1617,18 @@ export function finishCrime(this: IPlayer, cancelled: boolean): string {
if (ws.disableLogs.ALL == null && ws.disableLogs.commitCrime == null) {
ws.scriptRef.log(
"FAIL: Crime failed! Gained " +
numeralWrapper.formatExp(this.workHackExpGained) +
" hack exp, " +
numeralWrapper.formatExp(this.workStrExpGained) +
" str exp, " +
numeralWrapper.formatExp(this.workDefExpGained) +
" def exp, " +
numeralWrapper.formatExp(this.workDexExpGained) +
" dex exp, " +
numeralWrapper.formatExp(this.workAgiExpGained) +
" agi exp, " +
numeralWrapper.formatExp(this.workChaExpGained) +
" cha exp.",
numeralWrapper.formatExp(this.workHackExpGained) +
" hack exp, " +
numeralWrapper.formatExp(this.workStrExpGained) +
" str exp, " +
numeralWrapper.formatExp(this.workDefExpGained) +
" def exp, " +
numeralWrapper.formatExp(this.workDexExpGained) +
" dex exp, " +
numeralWrapper.formatExp(this.workAgiExpGained) +
" agi exp, " +
numeralWrapper.formatExp(this.workChaExpGained) +
" cha exp.",
);
}
} else {

@ -109,7 +109,7 @@ export function prestigeAugmentation(): void {
initMessages();
// Apply entropy from grafting
Player.applyEntropy(Player.entropyStacks);
Player.applyEntropy(Player.entropy);
// Gang
const gang = Player.gang;

@ -393,6 +393,11 @@ function evaluateVersionCompatibility(ver: string | number): void {
}
}
}
if (ver < 12) {
if (anyPlayer.resleeves !== undefined) {
delete anyPlayer.resleeves;
}
}
}
}

@ -95,7 +95,7 @@ interface Player {
tor: boolean;
hasCorporation: boolean;
inBladeburner: boolean;
entropyStacks: number;
entropy: number;
}
/**
@ -3722,39 +3722,39 @@ export interface Sleeve {
export interface Grafting {
/**
* Retrieve the crafting cost of an aug.
* Retrieve the grafting cost of an aug.
* @remarks
* RAM cost: 3.75 GB
*
* @param augName - Name of the aug to check the price of. Must be an exact match.
* @returns The cost required to craft the named augmentation.
* @returns The cost required to graft the named augmentation.
* @throws Will error if an invalid Augmentation name is provided.
*/
getAugmentationCraftPrice(augName: string): number;
getAugmentationGraftPrice(augName: string): number;
/**
* Retrieves the time required to craft an aug.
* Retrieves the time required to graft an aug.
* @remarks
* RAM cost: 3.75 GB
*
* @param augName - Name of the aug to check the crafting time of. Must be an exact match.
* @returns The time required, in millis, to craft the named augmentation.
* @param augName - Name of the aug to check the grafting time of. Must be an exact match.
* @returns The time required, in millis, to graft the named augmentation.
* @throws Will error if an invalid Augmentation name is provided.
*/
getAugmentationCraftTime(augName: string): number;
getAugmentationGraftTime(augName: string): number;
/**
* Begins crafting the named aug. You must be in New Tokyo to use this.
* Begins grafting the named aug. You must be in New Tokyo to use this.
* @remarks
* RAM cost: 7.5 GB
*
* @param augName - The name of the aug to begin crafting. Must be an exact match.
* @param focus - Acquire player focus on this Augmentation crafting. Optional. Defaults to true.
* @returns True if the aug successfully began crafting, false otherwise (e.g. not enough money, or
* @param augName - The name of the aug to begin grafting. Must be an exact match.
* @param focus - Acquire player focus on this Augmentation grafting. Optional. Defaults to true.
* @returns True if the aug successfully began grafting, false otherwise (e.g. not enough money, or
* invalid Augmentation name provided).
* @throws Will error if called while you are not in New Tokyo.
*/
craftAugmentation(augName: string, focus?: boolean): boolean;
graftAugmentation(augName: string, focus?: boolean): boolean;
}
/**

@ -264,7 +264,7 @@ const Engine: {
}
// Apply penalty for entropy accumulation
Player.applyEntropy(Player.entropyStacks);
Player.applyEntropy(Player.entropy);
// Calculate the number of cycles have elapsed while offline
Engine._lastUpdate = new Date().getTime();
@ -305,8 +305,8 @@ const Engine: {
Player.commitCrime(numCyclesOffline);
} else if (Player.workType == CONSTANTS.WorkTypeCompanyPartTime) {
Player.workPartTime(numCyclesOffline);
} else if (Player.workType === CONSTANTS.WorkTypeCraftAugmentation) {
Player.craftAugmentationWork(numCyclesOffline);
} else if (Player.workType === CONSTANTS.WorkTypeGraftAugmentation) {
Player.graftAugmentationWork(numCyclesOffline);
} else {
Player.work(numCyclesOffline);
}

@ -194,13 +194,13 @@ function Work(): React.ReactElement {
</>
);
break;
case CONSTANTS.WorkTypeCraftAugmentation:
details = <>Crafting {player.craftAugmentationName}</>;
header = <>Crafting an Augmentation</>;
case CONSTANTS.WorkTypeGraftAugmentation:
details = <>Grafting {player.graftAugmentationName}</>;
header = <>Grafting an Augmentation</>;
innerText = (
<>
<strong>{((player.timeWorkedCraftAugmentation / player.timeNeededToCompleteWork) * 100).toFixed(2)}%</strong>
{" "}done
<strong>{((player.timeWorkedGraftAugmentation / player.timeNeededToCompleteWork) * 100).toFixed(2)}%</strong>{" "}
done
</>
);
}

@ -483,9 +483,9 @@ export function WorkInProgressRoot(): React.ReactElement {
);
}
if (player.craftAugmentationName !== "") {
if (player.graftAugmentationName !== "") {
function cancel(): void {
player.finishCraftAugmentationWork(true);
player.finishGraftAugmentationWork(true);
router.toTerminal();
}
function unfocus(): void {
@ -496,14 +496,14 @@ export function WorkInProgressRoot(): React.ReactElement {
<Grid container direction="column" justifyContent="center" alignItems="center" style={{ minHeight: "100vh" }}>
<Grid item>
<Typography>
You are currently working on crafting {player.craftAugmentationName}.
You are currently working on crafting {player.graftAugmentationName}.
<br />
<br />
You have been working for {convertTimeMsToTimeElapsedString(player.timeWorked)}
<br />
<br />
The augmentation is{" "}
{((player.timeWorkedCraftAugmentation / player.timeNeededToCompleteWork) * 100).toFixed(2)}% done being
{((player.timeWorkedGraftAugmentation / player.timeNeededToCompleteWork) * 100).toFixed(2)}% done being
crafted.
<br />
If you cancel, your work will <b>not</b> be saved, and the money you spent will <b>not</b> be returned.