made staneks gift work with prestiges

This commit is contained in:
Olivier Gagnon 2021-10-08 03:16:51 -04:00
parent f4ecbd9b48
commit 4355420349
16 changed files with 168 additions and 7 deletions

@ -583,6 +583,8 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers[mult] = 1; BitNodeMultipliers[mult] = 1;
} }
} }
// Special case.
BitNodeMultipliers.StaneksGiftExtraSize = 0;
switch (p.bitNodeN) { switch (p.bitNodeN) {
case 1: // Source Genesis (every multiplier is 1) case 1: // Source Genesis (every multiplier is 1)
@ -860,6 +862,8 @@ export function initBitNodeMultipliers(p: IPlayer): void {
BitNodeMultipliers.BladeburnerRank = 0.1; BitNodeMultipliers.BladeburnerRank = 0.1;
BitNodeMultipliers.BladeburnerSkillCost = 5; BitNodeMultipliers.BladeburnerSkillCost = 5;
BitNodeMultipliers.GangKarmaRequirement = 20; BitNodeMultipliers.GangKarmaRequirement = 20;
BitNodeMultipliers.StaneksGiftPowerMultiplier = 2;
BitNodeMultipliers.StaneksGiftExtraSize = 1;
break; break;
} }
default: default:

@ -212,6 +212,16 @@ interface IBitNodeMultipliers {
*/ */
StrengthLevelMultiplier: number; StrengthLevelMultiplier: number;
/**
* Influences the power of the gift.
*/
StaneksGiftPowerMultiplier: number;
/**
* Influences the size of the gift.
*/
StaneksGiftExtraSize: number;
// Index signature // Index signature
[key: string]: number; [key: string]: number;
} }
@ -274,4 +284,7 @@ export const BitNodeMultipliers: IBitNodeMultipliers = {
DaedalusAugsRequirement: 1, DaedalusAugsRequirement: 1,
GangKarmaRequirement: 1, GangKarmaRequirement: 1,
StaneksGiftPowerMultiplier: 1,
StaneksGiftExtraSize: 0,
}; };

@ -3,6 +3,7 @@ import { Fragment } from "./Fragment";
import { IPlayer } from "../PersonObjects/IPlayer"; import { IPlayer } from "../PersonObjects/IPlayer";
export interface IStaneksGift { export interface IStaneksGift {
storedCycles: number;
fragments: ActiveFragment[]; fragments: ActiveFragment[];
width(): number; width(): number;
height(): number; height(): number;
@ -15,4 +16,7 @@ export interface IStaneksGift {
deleteAt(worldX: number, worldY: number): boolean; deleteAt(worldX: number, worldY: number): boolean;
clear(): void; clear(): void;
count(fragment: Fragment): number; count(fragment: Fragment): number;
inBonus(): boolean;
prestigeAugmentation(): void;
prestigeSourceFile(): void;
} }

@ -6,16 +6,26 @@ import { IPlayer } from "../PersonObjects/IPlayer";
import { Factions } from "../Faction/Factions"; import { Factions } from "../Faction/Factions";
import { CalculateEffect } from "./formulas/effect"; import { CalculateEffect } from "./formulas/effect";
import { CalculateCharge } from "./formulas/charge"; import { CalculateCharge } from "./formulas/charge";
import { StaneksGiftEvents } from "./StaneksGiftEvents";
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
import { CONSTANTS } from "../Constants";
import { StanekConstants } from "./data/Constants";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { Player } from "../Player";
export class StaneksGift implements IStaneksGift { export class StaneksGift implements IStaneksGift {
storedCycles = 0;
fragments: ActiveFragment[] = []; fragments: ActiveFragment[] = [];
baseSize(): number {
return StanekConstants.BaseSize + BitNodeMultipliers.StaneksGiftExtraSize + Player.sourceFileLvl(13);
}
width(): number { width(): number {
return 7; return Math.floor(this.baseSize() / 2 + 1);
} }
height(): number { height(): number {
return 6; return Math.floor(this.baseSize() / 2 + 0.6);
} }
charge(worldX: number, worldY: number, ram: number): number { charge(worldX: number, worldY: number, ram: number): number {
@ -30,8 +40,16 @@ export class StaneksGift implements IStaneksGift {
return ram; return ram;
} }
process(p: IPlayer, numCycles: number): void { inBonus(): boolean {
return (this.storedCycles * CONSTANTS._idleSpeed) / 1000 > 1;
}
process(p: IPlayer, numCycles = 1): void {
this.storedCycles += numCycles;
this.storedCycles -= 5;
this.storedCycles = Math.max(0, this.storedCycles);
this.updateMults(p); this.updateMults(p);
StaneksGiftEvents.emit();
} }
effect(fragment: ActiveFragment): number { effect(fragment: ActiveFragment): number {
@ -177,6 +195,14 @@ export class StaneksGift implements IStaneksGift {
} }
} }
prestigeAugmentation(): void {
this.clear();
}
prestigeSourceFile(): void {
this.clear();
}
/** /**
* Serialize Staneks Gift to a JSON save state. * Serialize Staneks Gift to a JSON save state.
*/ */

@ -0,0 +1,2 @@
import { EventEmitter } from "../utils/EventEmitter";
export const StaneksGiftEvents = new EventEmitter<[]>();

@ -1,5 +1,7 @@
export const StanekConstants: { export const StanekConstants: {
RAMBonus: number; RAMBonus: number;
BaseSize: number;
} = { } = {
RAMBonus: 0.1, RAMBonus: 0.1,
BaseSize: 12,
}; };

@ -1,4 +1,7 @@
import React from "react"; import React, { useState, useEffect } from "react";
import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions";
import { CONSTANTS } from "../../Constants";
import { StaneksGiftEvents } from "../StaneksGiftEvents";
import { Grid } from "./Grid"; import { Grid } from "./Grid";
import { IStaneksGift } from "../IStaneksGift"; import { IStaneksGift } from "../IStaneksGift";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
@ -8,6 +11,11 @@ type IProps = {
}; };
export function StaneksGiftRoot({ staneksGift }: IProps): React.ReactElement { export function StaneksGiftRoot({ staneksGift }: IProps): React.ReactElement {
const setRerender = useState(true)[1];
function rerender(): void {
setRerender((o) => !o);
}
useEffect(() => StaneksGiftEvents.subscribe(rerender), []);
return ( return (
<> <>
<Typography variant="h4">Stanek's Gift</Typography> <Typography variant="h4">Stanek's Gift</Typography>
@ -17,6 +25,11 @@ export function StaneksGiftRoot({ staneksGift }: IProps): React.ReactElement {
in order to become useful. The other kind of fragment is called booster fragments. They increase the efficiency in order to become useful. The other kind of fragment is called booster fragments. They increase the efficiency
of the charged happening on fragments neighboring them (no diagonal) of the charged happening on fragments neighboring them (no diagonal)
</Typography> </Typography>
{staneksGift.storedCycles > 5 && (
<Typography>
Bonus time: {convertTimeMsToTimeElapsedString(CONSTANTS._idleSpeed * staneksGift.storedCycles)}
</Typography>
)}
<Grid gift={staneksGift} /> <Grid gift={staneksGift} />
</> </>
); );

@ -2,6 +2,7 @@ import { IPlayer } from "./PersonObjects/IPlayer";
import { Bladeburner } from "./Bladeburner/Bladeburner"; import { Bladeburner } from "./Bladeburner/Bladeburner";
import { IEngine } from "./IEngine"; import { IEngine } from "./IEngine";
import { IRouter } from "./ui/Router"; import { IRouter } from "./ui/Router";
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
import React from "react"; import React from "react";
@ -19,6 +20,7 @@ import { Corporation } from "./DevMenu/ui/Corporation";
import { CodingContracts } from "./DevMenu/ui/CodingContracts"; import { CodingContracts } from "./DevMenu/ui/CodingContracts";
import { StockMarket } from "./DevMenu/ui/StockMarket"; import { StockMarket } from "./DevMenu/ui/StockMarket";
import { Sleeves } from "./DevMenu/ui/Sleeves"; import { Sleeves } from "./DevMenu/ui/Sleeves";
import { Stanek } from "./DevMenu/ui/Stanek";
import { TimeSkip } from "./DevMenu/ui/TimeSkip"; import { TimeSkip } from "./DevMenu/ui/TimeSkip";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
@ -52,6 +54,7 @@ export function DevMenuRoot(props: IProps): React.ReactElement {
{props.player.hasWseAccount && <StockMarket />} {props.player.hasWseAccount && <StockMarket />}
{props.player.sleeves.length > 0 && <Sleeves player={props.player} />} {props.player.sleeves.length > 0 && <Sleeves player={props.player} />}
{props.player.augmentations.some((aug) => aug.name === AugmentationNames.StaneksGift1) && <Stanek />}
<TimeSkip player={props.player} engine={props.engine} /> <TimeSkip player={props.player} engine={props.engine} />
</> </>

79
src/DevMenu/ui/Stanek.tsx Normal file

@ -0,0 +1,79 @@
import React from "react";
import { staneksGift } from "../../CotMG/Helper";
import Accordion from "@mui/material/Accordion";
import AccordionSummary from "@mui/material/AccordionSummary";
import AccordionDetails from "@mui/material/AccordionDetails";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import Typography from "@mui/material/Typography";
import { Adjuster } from "./Adjuster";
export function Stanek(): React.ReactElement {
function addCycles(): void {
staneksGift.storedCycles = 1e6;
}
function modCycles(modify: number): (x: number) => void {
return function (cycles: number): void {
staneksGift.storedCycles += cycles * modify;
};
}
function resetCycles(): void {
staneksGift.storedCycles = 0;
}
function addCharge(): void {
staneksGift.fragments.forEach((f) => (f.charge = 1e21));
}
function modCharge(modify: number): (x: number) => void {
return function (cycles: number): void {
staneksGift.fragments.forEach((f) => (f.charge += cycles * modify));
};
}
function resetCharge(): void {
staneksGift.fragments.forEach((f) => (f.charge = 0));
}
return (
<Accordion TransitionProps={{ unmountOnExit: true }}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography>Stanek's Gift</Typography>
</AccordionSummary>
<AccordionDetails>
<table>
<tbody>
<tr>
<td>
<Adjuster
label="cycles"
placeholder="amt"
tons={addCycles}
add={modCycles(1)}
subtract={modCycles(-1)}
reset={resetCycles}
/>
</td>
</tr>
<tr>
<td>
<Adjuster
label="all charge"
placeholder="amt"
tons={addCharge}
add={modCharge(1)}
subtract={modCharge(-1)}
reset={resetCharge}
/>
</td>
</tr>
</tbody>
</table>
</AccordionDetails>
</Accordion>
);
}

@ -29,7 +29,8 @@ export function NetscriptStanek(
//checkStanekAPIAccess("charge"); //checkStanekAPIAccess("charge");
const fragment = staneksGift.fragmentAt(worldX, worldY); const fragment = staneksGift.fragmentAt(worldX, worldY);
if (!fragment) throw helper.makeRuntimeErrorMsg("stanek.charge", `No fragment at (${worldX}, ${worldY})`); if (!fragment) throw helper.makeRuntimeErrorMsg("stanek.charge", `No fragment at (${worldX}, ${worldY})`);
return netscriptDelay(1000, workerScript).then(function () { const time = staneksGift.inBonus() ? 200 : 1000;
return netscriptDelay(time, workerScript).then(function () {
if (workerScript.env.stopFlag) { if (workerScript.env.stopFlag) {
return Promise.reject(workerScript); return Promise.reject(workerScript);
} }

@ -276,4 +276,5 @@ export interface IPlayer {
setMult(name: string, mult: number): void; setMult(name: string, mult: number): void;
canAccessCotMG(): boolean; canAccessCotMG(): boolean;
sourceFileLvl(n: number): number;
} }

@ -282,6 +282,7 @@ export class PlayerObject implements IPlayer {
getMult: (name: string) => number; getMult: (name: string) => number;
setMult: (name: string, mult: number) => void; setMult: (name: string, mult: number) => void;
canAccessCotMG: () => boolean; canAccessCotMG: () => boolean;
sourceFileLvl: (n: number) => number;
constructor() { constructor() {
//Skills and stats //Skills and stats
@ -575,6 +576,7 @@ export class PlayerObject implements IPlayer {
this.setMult = generalMethods.setMult; this.setMult = generalMethods.setMult;
this.canAccessCotMG = generalMethods.canAccessCotMG; this.canAccessCotMG = generalMethods.canAccessCotMG;
this.sourceFileLvl = generalMethods.sourceFileLvl;
} }
/** /**

@ -2627,3 +2627,9 @@ export function setMult(this: IPlayer, name: string, mult: number): void {
export function canAccessCotMG(this: IPlayer): boolean { export function canAccessCotMG(this: IPlayer): boolean {
return this.bitNodeN === 13 || SourceFileFlags[13] > 0; return this.bitNodeN === 13 || SourceFileFlags[13] > 0;
} }
export function sourceFileLvl(this: IPlayer, n: number): number {
const sf = this.sourceFiles.find((sf) => sf.n === n);
if (!sf) return 0;
return sf.lvl;
}

@ -205,6 +205,6 @@ SourceFiles["SourceFile12"] = new SourceFile(
<>This Source-File lets the player start with Neuroflux Governor equal to the level of this Source-File.</>, <>This Source-File lets the player start with Neuroflux Governor equal to the level of this Source-File.</>,
); );
SourceFiles["SourceFile13"] = new SourceFile( SourceFiles["SourceFile13"] = new SourceFile(
12, 13,
<>Each level of this Source-File increases the size of Stanek's Gift.</>, <>Each level of this Source-File increases the size of Stanek's Gift.</>,
); );

@ -163,7 +163,10 @@ export function applySourceFile(srcFile: PlayerOwnedSourceFile): void {
break; break;
} }
case 12: // The Recursion case 12: // The Recursion
// No effects, grants neuroflux. // Grants neuroflux.
break;
case 13: // They're Lunatics
// Grants more space on Stanek's Gift.
break; break;
default: default:
console.error(`Invalid source file number: ${srcFile.n}`); console.error(`Invalid source file number: ${srcFile.n}`);

@ -362,6 +362,8 @@ const Engine: {
Player.bladeburner.storeCycles(numCyclesOffline); Player.bladeburner.storeCycles(numCyclesOffline);
} }
staneksGift.process(Player, numCyclesOffline);
// Sleeves offline progress // Sleeves offline progress
for (let i = 0; i < Player.sleeves.length; ++i) { for (let i = 0; i < Player.sleeves.length; ++i) {
if (Player.sleeves[i] instanceof Sleeve) { if (Player.sleeves[i] instanceof Sleeve) {