This commit is contained in:
Snarling 2022-09-06 09:07:12 -04:00
parent cc2246213f
commit 83d357e758
203 changed files with 2263 additions and 3018 deletions

@ -347,18 +347,18 @@ export const achievements: IMap<Achievement> = {
FIRST_HACKNET_NODE: {
...achievementData["FIRST_HACKNET_NODE"],
Icon: "node",
Condition: () => !hasHacknetServers(Player) && Player.hacknetNodes.length > 0,
Condition: () => !hasHacknetServers() && Player.hacknetNodes.length > 0,
},
"30_HACKNET_NODE": {
...achievementData["30_HACKNET_NODE"],
Icon: "hacknet-all",
Condition: () => !hasHacknetServers(Player) && Player.hacknetNodes.length >= 30,
Condition: () => !hasHacknetServers() && Player.hacknetNodes.length >= 30,
},
MAX_HACKNET_NODE: {
...achievementData["MAX_HACKNET_NODE"],
Icon: "hacknet-max",
Condition: (): boolean => {
if (hasHacknetServers(Player)) return false;
if (hasHacknetServers()) return false;
for (const h of Player.hacknetNodes) {
if (!(h instanceof HacknetNode)) return false;
if (
@ -374,7 +374,7 @@ export const achievements: IMap<Achievement> = {
HACKNET_NODE_10M: {
...achievementData["HACKNET_NODE_10M"],
Icon: "hacknet-10m",
Condition: () => !hasHacknetServers(Player) && Player.moneySourceB.hacknet >= 10e6,
Condition: () => !hasHacknetServers() && Player.moneySourceB.hacknet >= 10e6,
},
REPUTATION_10M: {
...achievementData["REPUTATION_10M"],
@ -515,14 +515,14 @@ export const achievements: IMap<Achievement> = {
...achievementData["FIRST_HACKNET_SERVER"],
Icon: "HASHNET",
Visible: () => hasAccessToSF(Player, 9),
Condition: () => hasHacknetServers(Player) && Player.hacknetNodes.length > 0,
Condition: () => hasHacknetServers() && Player.hacknetNodes.length > 0,
AdditionalUnlock: [achievementData.FIRST_HACKNET_NODE.ID],
},
ALL_HACKNET_SERVER: {
...achievementData["ALL_HACKNET_SERVER"],
Icon: "HASHNETALL",
Visible: () => hasAccessToSF(Player, 9),
Condition: () => hasHacknetServers(Player) && Player.hacknetNodes.length === HacknetServerConstants.MaxServers,
Condition: () => hasHacknetServers() && Player.hacknetNodes.length === HacknetServerConstants.MaxServers,
AdditionalUnlock: [achievementData["30_HACKNET_NODE"].ID],
},
MAX_HACKNET_SERVER: {
@ -530,7 +530,7 @@ export const achievements: IMap<Achievement> = {
Icon: "HASHNETALL",
Visible: () => hasAccessToSF(Player, 9),
Condition: (): boolean => {
if (!hasHacknetServers(Player)) return false;
if (!hasHacknetServers()) return false;
for (const h of Player.hacknetNodes) {
if (typeof h !== "string") return false;
const hs = GetServer(h);
@ -551,7 +551,7 @@ export const achievements: IMap<Achievement> = {
...achievementData["HACKNET_SERVER_1B"],
Icon: "HASHNETMONEY",
Visible: () => hasAccessToSF(Player, 9),
Condition: () => hasHacknetServers(Player) && Player.moneySourceB.hacknet >= 1e9,
Condition: () => hasHacknetServers() && Player.moneySourceB.hacknet >= 1e9,
AdditionalUnlock: [achievementData.HACKNET_NODE_10M.ID],
},
MAX_CACHE: {
@ -559,7 +559,7 @@ export const achievements: IMap<Achievement> = {
Icon: "HASHNETCAP",
Visible: () => hasAccessToSF(Player, 9),
Condition: () =>
hasHacknetServers(Player) &&
hasHacknetServers() &&
Player.hashManager.hashes === Player.hashManager.capacity &&
Player.hashManager.capacity > 0,
},

@ -8,7 +8,7 @@ import { Money } from "../ui/React/Money";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../utils/JSONReviver";
import { FactionNames } from "../Faction/data/FactionNames";
import { IPlayer } from "../PersonObjects/IPlayer";
import { Player } from "../Player";
import { AugmentationNames } from "./data/AugmentationNames";
import { CONSTANTS } from "../Constants";
import { StaticAugmentations } from "./StaticAugmentations";
@ -531,26 +531,26 @@ export class Augmentation {
}
}
getCost(player: IPlayer): AugmentationCosts {
getCost(): AugmentationCosts {
const augmentationReference = StaticAugmentations[this.name];
let moneyCost = augmentationReference.baseCost;
let repCost = augmentationReference.baseRepRequirement;
if (augmentationReference.name === AugmentationNames.NeuroFluxGovernor) {
let nextLevel = this.getLevel(player);
let nextLevel = this.getLevel();
--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) {
for (let i = 0; i < Player.queuedAugmentations.length; ++i) {
moneyCost *= getBaseAugmentationPriceMultiplier();
}
} else if (augmentationReference.factions.includes(FactionNames.ShadowsOfAnarchy)) {
const soaAugmentationNames = initSoAAugmentations().map((augmentation) => augmentation.name);
const soaMultiplier = Math.pow(
CONSTANTS.SoACostMult,
soaAugmentationNames.filter((augmentationName) => player.hasAugmentation(augmentationName)).length,
soaAugmentationNames.filter((augmentationName) => Player.hasAugmentation(augmentationName)).length,
);
moneyCost = augmentationReference.baseCost * soaMultiplier;
if (soaAugmentationNames.find((augmentationName) => augmentationName === augmentationReference.name)) {
@ -566,19 +566,19 @@ export class Augmentation {
return { moneyCost, repCost };
}
getLevel(player: IPlayer): number {
getLevel(): 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;
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) {
for (let i = 0; i < Player.queuedAugmentations.length; ++i) {
if (Player.queuedAugmentations[i].name == AugmentationNames.NeuroFluxGovernor) {
++currLevel;
}
}

@ -20,7 +20,7 @@ import Paper from "@mui/material/Paper";
import Container from "@mui/material/Container";
import { Settings } from "../../Settings/Settings";
import { ConfirmationModal } from "../../ui/React/ConfirmationModal";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { AugmentationNames } from "../data/AugmentationNames";
import { StaticAugmentations } from "../StaticAugmentations";
import { CONSTANTS } from "../../Constants";
@ -29,12 +29,8 @@ import { Info } from "@mui/icons-material";
import { Link } from "@mui/material";
import { AlertEvents } from "../../ui/React/AlertManager";
interface NFGDisplayProps {
player: IPlayer;
}
const NeuroFluxDisplay = ({ player }: NFGDisplayProps): React.ReactElement => {
const level = player.augmentations.find((e) => e.name === AugmentationNames.NeuroFluxGovernor)?.level ?? 0;
const NeuroFluxDisplay = (): React.ReactElement => {
const level = Player.augmentations.find((e) => e.name === AugmentationNames.NeuroFluxGovernor)?.level ?? 0;
const openBloodDonation = () => {
AlertEvents.emit(
@ -67,18 +63,14 @@ const NeuroFluxDisplay = ({ player }: NFGDisplayProps): React.ReactElement => {
);
};
interface EntropyDisplayProps {
player: IPlayer;
}
const EntropyDisplay = ({ player }: EntropyDisplayProps): React.ReactElement => {
return player.entropy > 0 ? (
const EntropyDisplay = (): React.ReactElement => {
return Player.entropy > 0 ? (
<Paper sx={{ p: 1 }}>
<Typography variant="h5" color={Settings.theme.error}>
Entropy Virus - Level {player.entropy}
Entropy Virus - Level {Player.entropy}
</Typography>
<Typography color={Settings.theme.error}>
<b>All multipliers decreased by:</b> {formatNumber((1 - CONSTANTS.EntropyEffect ** player.entropy) * 100, 3)}%
<b>All multipliers decreased by:</b> {formatNumber((1 - CONSTANTS.EntropyEffect ** Player.entropy) * 100, 3)}%
(multiplicative)
</Typography>
</Paper>
@ -222,8 +214,8 @@ export function AugmentationsRoot(props: IProps): React.ReactElement {
gap: 1,
}}
>
<NeuroFluxDisplay player={player} />
<EntropyDisplay player={player} />
<NeuroFluxDisplay />
<EntropyDisplay />
</Box>
<Box>

@ -6,7 +6,7 @@ import { CheckBox, CheckBoxOutlineBlank, CheckCircle, NewReleases, Report } from
import { Box, Button, Container, Paper, Tooltip, Typography } from "@mui/material";
import React, { useState } from "react";
import { Faction } from "../../Faction/Faction";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { Settings } from "../../Settings/Settings";
import { numeralWrapper } from "../../ui/numeralFormat";
import { Augmentation } from "../Augmentation";
@ -15,12 +15,11 @@ import { StaticAugmentations } from "../StaticAugmentations";
import { PurchaseAugmentationModal } from "./PurchaseAugmentationModal";
interface IPreReqsProps {
player: IPlayer;
aug: Augmentation;
}
const PreReqs = (props: IPreReqsProps): React.ReactElement => {
const ownedPreReqs = props.aug.prereqs.filter((aug) => props.player.hasAugmentation(aug));
const ownedPreReqs = props.aug.prereqs.filter((aug) => Player.hasAugmentation(aug));
const hasPreReqs = props.aug.prereqs.length > 0 && ownedPreReqs.length === props.aug.prereqs.length;
return (
@ -32,7 +31,7 @@ const PreReqs = (props: IPreReqsProps): React.ReactElement => {
</Typography>
{props.aug.prereqs.map((preAug) => (
<Requirement
fulfilled={props.player.hasAugmentation(preAug)}
fulfilled={Player.hasAugmentation(preAug)}
value={preAug}
color={Settings.theme.money}
key={preAug}
@ -68,7 +67,6 @@ const PreReqs = (props: IPreReqsProps): React.ReactElement => {
};
interface IExclusiveProps {
player: IPlayer;
aug: Augmentation;
}
@ -85,12 +83,12 @@ const Exclusive = (props: IExclusiveProps): React.ReactElement => {
<li>
<b>{props.aug.factions[0]}</b> faction
</li>
{props.player.isAwareOfGang() && !props.aug.isSpecial && (
{Player.isAwareOfGang() && !props.aug.isSpecial && (
<li>
Certain <b>gangs</b>
</li>
)}
{props.player.canAccessGrafting() &&
{Player.canAccessGrafting() &&
!props.aug.isSpecial &&
props.aug.name !== AugmentationNames.TheRedPill && (
<li>
@ -130,10 +128,9 @@ const Requirement = (props: IReqProps): React.ReactElement => {
interface IPurchasableAugsProps {
augNames: string[];
ownedAugNames: string[];
player: IPlayer;
canPurchase: (player: IPlayer, aug: Augmentation) => boolean;
purchaseAugmentation: (player: IPlayer, aug: Augmentation, showModal: (open: boolean) => void) => void;
canPurchase: (aug: Augmentation) => boolean;
purchaseAugmentation: (aug: Augmentation, showModal: (open: boolean) => void) => void;
rep?: number;
sleeveAugs?: boolean;
@ -167,7 +164,7 @@ export function PurchasableAugmentation(props: IPurchasableAugProps): React.Reac
const [open, setOpen] = useState(false);
const aug = StaticAugmentations[props.augName];
const augCosts = aug.getCost(props.parent.player);
const augCosts = aug.getCost();
const cost = props.parent.sleeveAugs ? aug.baseCost : augCosts.moneyCost;
const repCost = augCosts.repCost;
const info = typeof aug.info === "string" ? <span>{aug.info}</span> : aug.info;
@ -195,11 +192,11 @@ export function PurchasableAugmentation(props: IPurchasableAugProps): React.Reac
<Box sx={{ display: "flex", alignItems: "center" }}>
<Button
onClick={() =>
props.parent.purchaseAugmentation(props.parent.player, aug, (open): void => {
props.parent.purchaseAugmentation(aug, (open): void => {
setOpen(open);
})
}
disabled={!props.parent.canPurchase(props.parent.player, aug) || props.owned}
disabled={!props.parent.canPurchase(aug) || props.owned}
sx={{ width: "48px", height: "36px", float: "left", clear: "none", mr: 1 }}
>
{props.owned ? "Owned" : "Buy"}
@ -213,7 +210,7 @@ export function PurchasableAugmentation(props: IPurchasableAugProps): React.Reac
<Typography variant="h5">
{props.augName}
{props.augName === AugmentationNames.NeuroFluxGovernor &&
` - Level ${aug.getLevel(props.parent.player)}`}
` - Level ${aug.getLevel()}`}
</Typography>
<Typography>{description}</Typography>
</>
@ -226,20 +223,20 @@ export function PurchasableAugmentation(props: IPurchasableAugProps): React.Reac
whiteSpace: "nowrap",
overflow: "hidden",
color:
props.owned || !props.parent.canPurchase(props.parent.player, aug)
props.owned || !props.parent.canPurchase(aug)
? Settings.theme.disabled
: Settings.theme.primary,
}}
>
{aug.name}
{aug.name === AugmentationNames.NeuroFluxGovernor && ` - Level ${aug.getLevel(props.parent.player)}`}
{aug.name === AugmentationNames.NeuroFluxGovernor && ` - Level ${aug.getLevel()}`}
</Typography>
</Tooltip>
{aug.factions.length === 1 && !props.parent.sleeveAugs && (
<Exclusive player={props.parent.player} aug={aug} />
<Exclusive aug={aug} />
)}
{aug.prereqs.length > 0 && !props.parent.sleeveAugs && <PreReqs player={props.parent.player} aug={aug} />}
{aug.prereqs.length > 0 && !props.parent.sleeveAugs && <PreReqs aug={aug} />}
</Box>
</Box>
</Box>
@ -247,7 +244,7 @@ export function PurchasableAugmentation(props: IPurchasableAugProps): React.Reac
{props.owned || (
<Box sx={{ display: "grid", alignItems: "center", gridTemplateColumns: "1fr 1fr" }}>
<Requirement
fulfilled={cost === 0 || props.parent.player.money > cost}
fulfilled={cost === 0 || Player.money > cost}
value={numeralWrapper.formatMoney(cost)}
color={Settings.theme.money}
/>

@ -44,7 +44,7 @@ export function PurchaseAugmentationModal(props: IProps): React.ReactElement {
<br />
<br />
Would you like to purchase the {props.aug.name} Augmentation for&nbsp;
<Money money={props.aug.getCost(player).moneyCost} />?
<Money money={props.aug.getCost().moneyCost} />?
<br />
<br />
</Typography>

@ -1,6 +1,6 @@
import React from "react";
import { BitNodeMultipliers, IBitNodeMultipliers } from "./BitNodeMultipliers";
import { IPlayer } from "../PersonObjects/IPlayer";
import { Player } from "../Player";
import { IMap } from "../types";
import { FactionNames } from "../Faction/data/FactionNames";
import { CityName } from "../Locations/data/CityNames";
@ -876,6 +876,6 @@ export function getBitNodeMultipliers(n: number, lvl: number): IBitNodeMultiplie
}
}
export function initBitNodeMultipliers(p: IPlayer): void {
Object.assign(BitNodeMultipliers, getBitNodeMultipliers(p.bitNodeN, p.sourceFileLvl(p.bitNodeN)));
export function initBitNodeMultipliers(): void {
Object.assign(BitNodeMultipliers, getBitNodeMultipliers(Player.bitNodeN, Player.sourceFileLvl(Player.bitNodeN)));
}

@ -14,10 +14,10 @@ import { Skills } from "./Skills";
import { Skill } from "./Skill";
import { City } from "./City";
import { IAction } from "./IAction";
import { IPlayer } from "../PersonObjects/IPlayer";
import { Player } from "../Player";
import { createTaskTracker, ITaskTracker } from "../PersonObjects/ITaskTracker";
import { IPerson } from "../PersonObjects/IPerson";
import { IRouter } from "../ui/Router";
import { Router } from "../ui/GameRoot";
import { ConsoleHelpText } from "./data/Help";
import { exceptionAlert } from "../utils/helpers/exceptionAlert";
import { getRandomInt } from "../utils/helpers/getRandomInt";
@ -39,7 +39,7 @@ import { KEY } from "../utils/helpers/keyCodes";
import { isSleeveInfiltrateWork } from "../PersonObjects/Sleeve/Work/SleeveInfiltrateWork";
import { isSleeveSupportWork } from "../PersonObjects/Sleeve/Work/SleeveSupportWork";
interface BlackOpsAttempt {
export interface BlackOpsAttempt {
error?: string;
isAvailable?: boolean;
action?: BlackOperation;
@ -100,7 +100,7 @@ export class Bladeburner implements IBladeburner {
consoleHistory: string[] = [];
consoleLogs: string[] = ["Bladeburner Console", "Type 'help' to see console commands"];
constructor(player?: IPlayer) {
constructor() {
for (let i = 0; i < BladeburnerConstants.CityNames.length; ++i) {
this.cities[BladeburnerConstants.CityNames[i]] = new City(BladeburnerConstants.CityNames[i]);
}
@ -108,7 +108,7 @@ export class Bladeburner implements IBladeburner {
this.updateSkillMultipliers(); // Calls resetSkillMultipliers()
// Max Stamina is based on stats and Bladeburner-specific bonuses
if (player) this.calculateMaxStamina(player);
this.calculateMaxStamina();
this.stamina = this.maxStamina;
this.create();
}
@ -162,7 +162,8 @@ export class Bladeburner implements IBladeburner {
return { isAvailable: true, action };
}
startAction(person: IPerson, actionId: IActionIdentifier): void {
/** This function is only for the player. Sleeves use their own functions to perform blade work. */
startAction(actionId: IActionIdentifier): void {
if (actionId == null) return;
this.action = actionId;
this.actionTimeCurrent = 0;
@ -179,7 +180,7 @@ export class Bladeburner implements IBladeburner {
if (action.count < 1) {
return this.resetAction();
}
this.actionTimeToComplete = action.getActionTime(this, person);
this.actionTimeToComplete = action.getActionTime(this, Player);
} catch (e: unknown) {
exceptionAlert(e);
}
@ -196,7 +197,7 @@ export class Bladeburner implements IBladeburner {
if (actionId.name === "Raid" && this.getCurrentCity().comms === 0) {
return this.resetAction();
}
this.actionTimeToComplete = action.getActionTime(this, person);
this.actionTimeToComplete = action.getActionTime(this, Player);
} catch (e: unknown) {
exceptionAlert(e);
}
@ -214,14 +215,14 @@ export class Bladeburner implements IBladeburner {
if (testBlackOp.action === undefined) {
throw new Error("action should not be null");
}
this.actionTimeToComplete = testBlackOp.action.getActionTime(this, person);
this.actionTimeToComplete = testBlackOp.action.getActionTime(this, Player);
} catch (e: unknown) {
exceptionAlert(e);
}
break;
}
case ActionTypes["Recruitment"]:
this.actionTimeToComplete = this.getRecruitmentTime(person);
this.actionTimeToComplete = this.getRecruitmentTime(Player);
break;
case ActionTypes["Training"]:
case ActionTypes["FieldAnalysis"]:
@ -234,7 +235,7 @@ export class Bladeburner implements IBladeburner {
this.actionTimeToComplete = 60;
break;
default:
throw new Error("Invalid Action Type in startAction(Bladeburner,player, ): " + actionId.type);
throw new Error("Invalid Action Type in bladeburner.startAction(): " + actionId.type);
}
}
@ -252,7 +253,7 @@ export class Bladeburner implements IBladeburner {
this.updateSkillMultipliers();
}
executeConsoleCommands(player: IPlayer, commands: string): void {
executeConsoleCommands(commands: string): void {
try {
// Console History
if (this.consoleHistory[this.consoleHistory.length - 1] != commands) {
@ -264,7 +265,7 @@ export class Bladeburner implements IBladeburner {
const arrayOfCommands = commands.split(";");
for (let i = 0; i < arrayOfCommands.length; ++i) {
this.executeConsoleCommand(player, arrayOfCommands[i]);
this.executeConsoleCommand(arrayOfCommands[i]);
}
} catch (e: unknown) {
exceptionAlert(e);
@ -394,7 +395,7 @@ export class Bladeburner implements IBladeburner {
return null;
}
executeStartConsoleCommand(player: IPlayer, args: string[]): void {
executeStartConsoleCommand(args: string[]): void {
if (args.length !== 3) {
this.postToConsole("Invalid usage of 'start' console command: start [type] [name]");
this.postToConsole("Use 'help start' for more info");
@ -407,7 +408,7 @@ export class Bladeburner implements IBladeburner {
if (GeneralActions[name] != null) {
this.action.type = ActionTypes[name];
this.action.name = name;
this.startAction(player, this.action);
this.startAction(this.action);
} else {
this.postToConsole("Invalid action name specified: " + args[2]);
}
@ -417,7 +418,7 @@ export class Bladeburner implements IBladeburner {
if (this.contracts[name] != null) {
this.action.type = ActionTypes.Contract;
this.action.name = name;
this.startAction(player, this.action);
this.startAction(this.action);
} else {
this.postToConsole("Invalid contract name specified: " + args[2]);
}
@ -429,7 +430,7 @@ export class Bladeburner implements IBladeburner {
if (this.operations[name] != null) {
this.action.type = ActionTypes.Operation;
this.action.name = name;
this.startAction(player, this.action);
this.startAction(this.action);
} else {
this.postToConsole("Invalid Operation name specified: " + args[2]);
}
@ -441,7 +442,7 @@ export class Bladeburner implements IBladeburner {
if (BlackOperations[name] != null) {
this.action.type = ActionTypes.BlackOperation;
this.action.name = name;
this.startAction(player, this.action);
this.startAction(this.action);
} else {
this.postToConsole("Invalid BlackOp name specified: " + args[2]);
}
@ -820,7 +821,7 @@ export class Bladeburner implements IBladeburner {
return args;
}
executeConsoleCommand(player: IPlayer, command: string): void {
executeConsoleCommand(command: string): void {
command = command.trim();
command = command.replace(/\s\s+/g, " "); // Replace all whitespace w/ a single space
@ -845,7 +846,7 @@ export class Bladeburner implements IBladeburner {
this.executeSkillConsoleCommand(args);
break;
case "start":
this.executeStartConsoleCommand(player, args);
this.executeStartConsoleCommand(args);
break;
case "stop":
this.resetAction();
@ -1105,7 +1106,7 @@ export class Bladeburner implements IBladeburner {
}
}
completeOperation(success: boolean, player: IPlayer): void {
completeOperation(success: boolean): void {
if (this.action.type !== ActionTypes.Operation) {
throw new Error("completeOperation() called even though current action is not an Operation");
}
@ -1126,7 +1127,7 @@ export class Bladeburner implements IBladeburner {
const losses = getRandomInt(0, max);
this.teamSize -= losses;
if (this.teamSize < this.sleeveSize) {
const sup = player.sleeves.filter((x) => isSleeveSupportWork(x.currentWork));
const sup = Player.sleeves.filter((x) => isSleeveSupportWork(x.currentWork));
for (let i = 0; i > this.teamSize - this.sleeveSize; i--) {
const r = Math.floor(Math.random() * sup.length);
sup[r].takeDamage(sup[r].hp.max);
@ -1256,7 +1257,7 @@ export class Bladeburner implements IBladeburner {
}
}
completeAction(player: IPlayer, person: IPerson, actionIdent: IActionIdentifier, isPlayer = true): ITaskTracker {
completeAction(person: IPerson, actionIdent: IActionIdentifier, isPlayer = true): ITaskTracker {
let retValue = createTaskTracker();
switch (actionIdent.type) {
case ActionTypes["Contract"]:
@ -1304,24 +1305,16 @@ export class Bladeburner implements IBladeburner {
this.changeRank(person, gain);
if (isOperation && this.logging.ops) {
this.log(
`${person.whoAmI()}: ` +
action.name +
" successfully completed! Gained " +
formatNumber(gain, 3) +
" rank",
`${person.whoAmI()}: ${action.name} successfully completed! Gained ${formatNumber(gain, 3)} rank`,
);
} else if (!isOperation && this.logging.contracts) {
this.log(
`${person.whoAmI()}: ` +
action.name +
" contract successfully completed! Gained " +
formatNumber(gain, 3) +
" rank and " +
numeralWrapper.formatMoney(moneyGain),
`${person.whoAmI()}: ${action.name} contract successfully completed! Gained ` +
`${formatNumber(gain, 3)} rank and ${numeralWrapper.formatMoney(moneyGain)}`,
);
}
}
isOperation ? this.completeOperation(true, player) : this.completeContract(true, actionIdent);
isOperation ? this.completeOperation(true) : this.completeContract(true, actionIdent);
} else {
retValue = this.getActionStats(action, person, false);
++action.failures;
@ -1335,7 +1328,7 @@ export class Bladeburner implements IBladeburner {
damage = action.hpLoss * difficultyMultiplier;
damage = Math.ceil(addOffset(damage, 10));
this.hpLost += damage;
const cost = calculateHospitalizationCost(player, damage);
const cost = calculateHospitalizationCost(damage);
if (person.takeDamage(damage)) {
++this.numHosp;
this.moneyLost += cost;
@ -1353,7 +1346,7 @@ export class Bladeburner implements IBladeburner {
} else if (!isOperation && this.logging.contracts) {
this.log(`${person.whoAmI()}: ` + action.name + " contract failed! " + logLossText);
}
isOperation ? this.completeOperation(false, player) : this.completeContract(false, actionIdent);
isOperation ? this.completeOperation(false) : this.completeContract(false, actionIdent);
}
if (action.autoLevel) {
action.level = action.maxLevel;
@ -1412,7 +1405,7 @@ export class Bladeburner implements IBladeburner {
if (action.hpLoss) {
damage = action.hpLoss * difficultyMultiplier;
damage = Math.ceil(addOffset(damage, 10));
const cost = calculateHospitalizationCost(player, damage);
const cost = calculateHospitalizationCost(damage);
if (person.takeDamage(damage)) {
++this.numHosp;
this.moneyLost += cost;
@ -1440,7 +1433,7 @@ export class Bladeburner implements IBladeburner {
const losses = getRandomInt(1, teamLossMax);
this.teamSize -= losses;
if (this.teamSize < this.sleeveSize) {
const sup = player.sleeves.filter((x) => isSleeveSupportWork(x.currentWork));
const sup = Player.sleeves.filter((x) => isSleeveSupportWork(x.currentWork));
for (let i = 0; i > this.teamSize - this.sleeveSize; i--) {
const r = Math.floor(Math.random() * sup.length);
sup[r].takeDamage(sup[r].hp.max);
@ -1603,8 +1596,8 @@ export class Bladeburner implements IBladeburner {
return retValue;
}
infiltrateSynthoidCommunities(p: IPlayer): void {
const infilSleeves = p.sleeves.filter((s) => isSleeveInfiltrateWork(s.currentWork)).length;
infiltrateSynthoidCommunities(): void {
const infilSleeves = Player.sleeves.filter((s) => isSleeveInfiltrateWork(s.currentWork)).length;
const amt = Math.pow(infilSleeves, -0.5) / 2;
for (const contract of Object.keys(this.contracts)) {
this.contracts[contract].count += amt;
@ -1654,7 +1647,7 @@ export class Bladeburner implements IBladeburner {
}
}
processAction(router: IRouter, player: IPlayer, seconds: number): void {
processAction(seconds: number): void {
if (this.action.type === ActionTypes["Idle"]) return;
if (this.actionTimeToComplete <= 0) {
throw new Error(`Invalid actionTimeToComplete value: ${this.actionTimeToComplete}, type; ${this.action.type}`);
@ -1670,31 +1663,31 @@ export class Bladeburner implements IBladeburner {
if (this.actionTimeCurrent >= this.actionTimeToComplete) {
this.actionTimeOverflow = this.actionTimeCurrent - this.actionTimeToComplete;
const action = this.getActionObject(this.action);
const retValue = this.completeAction(player, player, this.action);
player.gainMoney(retValue.money, "bladeburner");
player.gainStats(retValue);
const retValue = this.completeAction(Player, this.action);
Player.gainMoney(retValue.money, "bladeburner");
Player.gainStats(retValue);
// Operation Daedalus
if (action == null) {
throw new Error("Failed to get BlackOperation Object for: " + this.action.name);
} else if (this.action.type != ActionTypes["BlackOperation"] && this.action.type != ActionTypes["BlackOp"]) {
this.startAction(player, this.action); // Repeat action
this.startAction(this.action); // Repeat action
}
}
}
calculateStaminaGainPerSecond(player: IPlayer): number {
const effAgility = player.skills.agility * this.skillMultipliers.effAgi;
calculateStaminaGainPerSecond(): number {
const effAgility = Player.skills.agility * this.skillMultipliers.effAgi;
const maxStaminaBonus = this.maxStamina / BladeburnerConstants.MaxStaminaToGainFactor;
const gain = (BladeburnerConstants.StaminaGainPerSecond + maxStaminaBonus) * Math.pow(effAgility, 0.17);
return gain * (this.skillMultipliers.stamina * player.mults.bladeburner_stamina_gain);
return gain * (this.skillMultipliers.stamina * Player.mults.bladeburner_stamina_gain);
}
calculateMaxStamina(player: IPlayer): void {
const effAgility = player.skills.agility * this.skillMultipliers.effAgi;
calculateMaxStamina(): void {
const effAgility = Player.skills.agility * this.skillMultipliers.effAgi;
const maxStamina =
(Math.pow(effAgility, 0.8) + this.staminaBonus) *
this.skillMultipliers.stamina *
player.mults.bladeburner_max_stamina;
Player.mults.bladeburner_max_stamina;
if (this.maxStamina !== maxStamina) {
const oldMax = this.maxStamina;
this.maxStamina = maxStamina;
@ -1974,12 +1967,12 @@ export class Bladeburner implements IBladeburner {
});
}
process(router: IRouter, player: IPlayer): void {
process(): void {
// Edge race condition when the engine checks the processing counters and attempts to route before the router is initialized.
if (!router.isInitialized) return;
if (!Router.isInitialized) return;
// If the Player starts doing some other actions, set action to idle and alert
if (!player.hasAugmentation(AugmentationNames.BladesSimulacrum, true) && player.currentWork) {
if (!Player.hasAugmentation(AugmentationNames.BladesSimulacrum, true) && Player.currentWork) {
if (this.action.type !== ActionTypes["Idle"]) {
let msg = "Your Bladeburner action was cancelled because you started doing something else.";
if (this.automateEnabled) {
@ -2006,8 +1999,8 @@ export class Bladeburner implements IBladeburner {
this.storedCycles -= seconds * BladeburnerConstants.CyclesPerSecond;
// Stamina
this.calculateMaxStamina(player);
this.stamina += this.calculateStaminaGainPerSecond(player) * seconds;
this.calculateMaxStamina();
this.stamina += this.calculateStaminaGainPerSecond() * seconds;
this.stamina = Math.min(this.maxStamina, this.stamina);
// Count increase for contracts/operations
@ -2042,7 +2035,7 @@ export class Bladeburner implements IBladeburner {
this.randomEventCounter += getRandomInt(240, 600);
}
this.processAction(router, player, seconds);
this.processAction(seconds);
// Automation
if (this.automateEnabled) {
@ -2053,7 +2046,7 @@ export class Bladeburner implements IBladeburner {
type: this.automateActionLow.type,
name: this.automateActionLow.name,
});
this.startAction(player, this.action);
this.startAction(this.action);
}
} else if (this.stamina >= this.automateThreshHigh) {
if (this.action.name !== this.automateActionHigh.name || this.action.type !== this.automateActionHigh.type) {
@ -2061,7 +2054,7 @@ export class Bladeburner implements IBladeburner {
type: this.automateActionHigh.type,
name: this.automateActionHigh.name,
});
this.startAction(player, this.action);
this.startAction(this.action);
}
}
}
@ -2121,7 +2114,7 @@ export class Bladeburner implements IBladeburner {
return Object.keys(Skills);
}
startActionNetscriptFn(player: IPlayer, type: string, name: string, workerScript: WorkerScript): boolean {
startActionNetscriptFn(type: string, name: string, workerScript: WorkerScript): boolean {
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
const actionId = this.getActionIdFromTypeAndName(type, name);
if (actionId == null) {
@ -2139,7 +2132,7 @@ export class Bladeburner implements IBladeburner {
}
try {
this.startAction(player, actionId);
this.startAction(actionId);
workerScript.log(
"bladeburner.startAction",
() => `Starting bladeburner action with type '${type}' and name '${name}'`,

@ -2,13 +2,13 @@ import { IActionIdentifier } from "./IActionIdentifier";
import { City } from "./City";
import { Skill } from "./Skill";
import { IAction } from "./IAction";
import { IPlayer } from "../PersonObjects/IPlayer";
import { IPerson } from "../PersonObjects/IPerson";
import { ITaskTracker } from "../PersonObjects/ITaskTracker";
import { IRouter } from "../ui/Router";
import { WorkerScript } from "../Netscript/WorkerScript";
import { Contract } from "./Contract";
import { Operation } from "./Operation";
import { IReviverValue } from "../utils/JSONReviver";
import { BlackOpsAttempt } from "./Bladeburner";
export interface IBladeburner {
numHosp: number;
@ -20,6 +20,7 @@ export interface IBladeburner {
totalSkillPoints: number;
teamSize: number;
sleeveSize: number;
teamLost: number;
hpLost: number;
@ -60,9 +61,10 @@ export interface IBladeburner {
getCurrentCity(): City;
calculateStaminaPenalty(): number;
startAction(player: IPlayer, action: IActionIdentifier): void;
canAttemptBlackOp(actionId: IActionIdentifier): BlackOpsAttempt;
startAction(action: IActionIdentifier): void;
upgradeSkill(skill: Skill): void;
executeConsoleCommands(player: IPlayer, command: string): void;
executeConsoleCommands(command: string): void;
postToConsole(input: string, saveToLogs?: boolean): void;
log(input: string): void;
resetAction(): void;
@ -79,7 +81,7 @@ export interface IBladeburner {
getBlackOpNamesNetscriptFn(): string[];
getGeneralActionNamesNetscriptFn(): string[];
getSkillNamesNetscriptFn(): string[];
startActionNetscriptFn(player: IPlayer, type: string, name: string, workerScript: WorkerScript): boolean;
startActionNetscriptFn(type: string, name: string, workerScript: WorkerScript): boolean;
getActionTimeNetscriptFn(person: IPerson, type: string, name: string): number | string;
getActionEstimatedSuccessChanceNetscriptFn(person: IPerson, type: string, name: string): [number, number] | string;
getActionCountRemainingNetscriptFn(type: string, name: string, workerScript: WorkerScript): number;
@ -90,32 +92,33 @@ export interface IBladeburner {
setTeamSizeNetscriptFn(type: string, name: string, size: number, workerScript: WorkerScript): number;
joinBladeburnerFactionNetscriptFn(workerScript: WorkerScript): boolean;
getActionIdFromTypeAndName(type: string, name: string): IActionIdentifier | null;
executeStartConsoleCommand(player: IPlayer, args: string[]): void;
executeStartConsoleCommand(args: string[]): void;
executeSkillConsoleCommand(args: string[]): void;
executeLogConsoleCommand(args: string[]): void;
executeHelpConsoleCommand(args: string[]): void;
executeAutomateConsoleCommand(args: string[]): void;
parseCommandArguments(command: string): string[];
executeConsoleCommand(player: IPlayer, command: string): void;
executeConsoleCommand(command: string): void;
triggerMigration(sourceCityName: string): void;
triggerPotentialMigration(sourceCityName: string, chance: number): void;
randomEvent(): void;
getDiplomacyEffectiveness(player: IPlayer): number;
getRecruitmentSuccessChance(player: IPerson): number;
getRecruitmentTime(player: IPerson): number;
getDiplomacyEffectiveness(person: IPerson): number;
getRecruitmentSuccessChance(person: IPerson): number;
getRecruitmentTime(person: IPerson): number;
resetSkillMultipliers(): void;
updateSkillMultipliers(): void;
completeOperation(success: boolean, player: IPlayer): void;
completeOperation(success: boolean): void;
getActionObject(actionId: IActionIdentifier): IAction | null;
completeContract(success: boolean, actionIdent: IActionIdentifier): void;
completeAction(player: IPlayer, person: IPerson, actionIdent: IActionIdentifier, isPlayer?: boolean): ITaskTracker;
infiltrateSynthoidCommunities(p: IPlayer): void;
changeRank(player: IPlayer, change: number): void;
processAction(router: IRouter, player: IPlayer, seconds: number): void;
calculateStaminaGainPerSecond(player: IPlayer): number;
calculateMaxStamina(player: IPlayer): void;
completeAction(person: IPerson, actionIdent: IActionIdentifier, isPlayer?: boolean): ITaskTracker;
infiltrateSynthoidCommunities(): void;
changeRank(person: IPerson, change: number): void;
processAction(seconds: number): void;
calculateStaminaGainPerSecond(): number;
calculateMaxStamina(): void;
create(): void;
process(router: IRouter, player: IPlayer): void;
process(): void;
getActionStats(action: IAction, person: IPerson, success: boolean): ITaskTracker;
sleeveSupport(joining: boolean): void;
toJSON():IReviverValue;
}

@ -27,14 +27,14 @@ export function ActionLevel({ action, isActive, bladeburner, rerender }: IProps)
function increaseLevel(): void {
if (!canIncrease) return;
++action.level;
if (isActive) bladeburner.startAction(player, bladeburner.action);
if (isActive) bladeburner.startAction(bladeburner.action);
rerender();
}
function decreaseLevel(): void {
if (!canDecrease) return;
--action.level;
if (isActive) bladeburner.startAction(player, bladeburner.action);
if (isActive) bladeburner.startAction(bladeburner.action);
rerender();
}

@ -5,7 +5,6 @@ import { OperationPage } from "./OperationPage";
import { BlackOpPage } from "./BlackOpPage";
import { SkillPage } from "./SkillPage";
import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
import Tabs from "@mui/material/Tabs";
import Tab from "@mui/material/Tab";
@ -13,7 +12,6 @@ import Box from "@mui/material/Box";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
}
export function AllPages(props: IProps): React.ReactElement {
@ -33,10 +31,10 @@ export function AllPages(props: IProps): React.ReactElement {
<Tab label="Skills" />
</Tabs>
<Box sx={{ p: 1 }}>
{value === 0 && <GeneralActionPage bladeburner={props.bladeburner} player={props.player} />}
{value === 1 && <ContractPage bladeburner={props.bladeburner} player={props.player} />}
{value === 2 && <OperationPage bladeburner={props.bladeburner} player={props.player} />}
{value === 3 && <BlackOpPage bladeburner={props.bladeburner} player={props.player} />}
{value === 0 && <GeneralActionPage bladeburner={props.bladeburner} />}
{value === 1 && <ContractPage bladeburner={props.bladeburner} />}
{value === 2 && <OperationPage bladeburner={props.bladeburner} />}
{value === 3 && <BlackOpPage bladeburner={props.bladeburner} />}
{value === 4 && <SkillPage bladeburner={props.bladeburner} />}
</Box>
</>

@ -6,7 +6,7 @@ import { TeamSizeButton } from "./TeamSizeButton";
import { IBladeburner } from "../IBladeburner";
import { BlackOperation } from "../BlackOperation";
import { BlackOperations } from "../data/BlackOperations";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { CopyableText } from "../../ui/React/CopyableText";
import { SuccessChance } from "./SuccessChance";
import { StartButton } from "./StartButton";
@ -16,7 +16,6 @@ import Paper from "@mui/material/Paper";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
action: BlackOperation;
}
@ -37,7 +36,7 @@ export function BlackOpElem(props: IProps): React.ReactElement {
const isActive =
props.bladeburner.action.type === ActionTypes["BlackOperation"] &&
props.action.name === props.bladeburner.action.name;
const actionTime = props.action.getActionTime(props.bladeburner, props.player);
const actionTime = props.action.getActionTime(props.bladeburner, Player);
const hasReqdRank = props.bladeburner.rank >= props.action.reqdRank;
const computedActionTimeCurrent = Math.min(
props.bladeburner.actionTimeCurrent + props.bladeburner.actionTimeOverflow,

@ -3,11 +3,9 @@ import { BlackOperations } from "../BlackOperations";
import { BlackOperation } from "../BlackOperation";
import { BlackOpElem } from "./BlackOpElem";
import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
}
export function BlackOpList(props: IProps): React.ReactElement {
@ -35,7 +33,7 @@ export function BlackOpList(props: IProps): React.ReactElement {
return (
<>
{blackops.map((blackop: BlackOperation) => (
<BlackOpElem key={blackop.name} bladeburner={props.bladeburner} action={blackop} player={props.player} />
<BlackOpElem key={blackop.name} bladeburner={props.bladeburner} action={blackop} />
))}
</>
);

@ -1,7 +1,6 @@
import * as React from "react";
import { BlackOpList } from "./BlackOpList";
import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
import Typography from "@mui/material/Typography";
import { FactionNames } from "../../Faction/data/FactionNames";
import { use } from "../../ui/Context";
@ -11,7 +10,6 @@ import { CorruptableText } from "../../ui/React/CorruptableText";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
}
export function BlackOpPage(props: IProps): React.ReactElement {
@ -37,7 +35,7 @@ export function BlackOpPage(props: IProps): React.ReactElement {
<CorruptableText content="Destroy w0rld_d34mon"></CorruptableText>
</Button>
) : (
<BlackOpList bladeburner={props.bladeburner} player={props.player} />
<BlackOpList bladeburner={props.bladeburner} />
)}
</>
);

@ -24,11 +24,11 @@ export function BladeburnerRoot(): React.ReactElement {
return (
<Box display="flex" flexDirection="column">
<Box sx={{ display: "grid", gridTemplateColumns: "4fr 8fr", p: 1 }}>
<Stats bladeburner={bladeburner} player={player} router={router} />
<Console bladeburner={bladeburner} player={player} />
<Stats bladeburner={bladeburner} />
<Console bladeburner={bladeburner} />
</Box>
<AllPages bladeburner={bladeburner} player={player} />
<AllPages bladeburner={bladeburner} />
</Box>
);
}

@ -2,7 +2,6 @@ import React, { useState, useRef, useEffect } from "react";
import { IBladeburner } from "../IBladeburner";
import { KEY } from "../../utils/helpers/keyCodes";
import { IPlayer } from "../../PersonObjects/IPlayer";
import Paper from "@mui/material/Paper";
import List from "@mui/material/List";
import ListItem from "@mui/material/ListItem";
@ -50,7 +49,6 @@ function Line(props: ILineProps): React.ReactElement {
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
}
export function Console(props: IProps): React.ReactElement {
@ -81,7 +79,7 @@ export function Console(props: IProps): React.ReactElement {
event.preventDefault();
if (command.length > 0) {
props.bladeburner.postToConsole("> " + command);
props.bladeburner.executeConsoleCommands(props.player, command);
props.bladeburner.executeConsoleCommands(command);
setConsoleHistoryIndex(props.bladeburner.consoleHistory.length);
setCommand("");
}

@ -5,7 +5,7 @@ import { formatNumber, convertTimeMsToTimeElapsedString } from "../../utils/Stri
import { Contracts } from "../data/Contracts";
import { IBladeburner } from "../IBladeburner";
import { IAction } from "../IAction";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { SuccessChance } from "./SuccessChance";
import { CopyableText } from "../../ui/React/CopyableText";
import { ActionLevel } from "./ActionLevel";
@ -17,7 +17,6 @@ import Paper from "@mui/material/Paper";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
action: IAction;
}
@ -32,7 +31,7 @@ export function ContractElem(props: IProps): React.ReactElement {
props.bladeburner.actionTimeCurrent + props.bladeburner.actionTimeOverflow,
props.bladeburner.actionTimeToComplete,
);
const actionTime = props.action.getActionTime(props.bladeburner, props.player);
const actionTime = props.action.getActionTime(props.bladeburner, Player);
const actionData = Contracts[props.action.name];
if (actionData === undefined) {

@ -1,11 +1,9 @@
import React from "react";
import { ContractElem } from "./ContractElem";
import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
}
export function ContractList(props: IProps): React.ReactElement {
@ -14,7 +12,7 @@ export function ContractList(props: IProps): React.ReactElement {
return (
<>
{names.map((name: string) => (
<ContractElem key={name} bladeburner={props.bladeburner} action={contracts[name]} player={props.player} />
<ContractElem key={name} bladeburner={props.bladeburner} action={contracts[name]} />
))}
</>
);

@ -1,12 +1,10 @@
import * as React from "react";
import { ContractList } from "./ContractList";
import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
import Typography from "@mui/material/Typography";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
}
export function ContractPage(props: IProps): React.ReactElement {
@ -20,7 +18,7 @@ export function ContractPage(props: IProps): React.ReactElement {
You can unlock higher-level contracts by successfully completing them. Higher-level contracts are more
difficult, but grant more rank, experience, and money.
</Typography>
<ContractList bladeburner={props.bladeburner} player={props.player} />
<ContractList bladeburner={props.bladeburner} />
</>
);
}

@ -5,7 +5,7 @@ import { formatNumber, convertTimeMsToTimeElapsedString } from "../../utils/Stri
import { IBladeburner } from "../IBladeburner";
import { IAction } from "../IAction";
import { GeneralActions } from "../data/GeneralActions";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { CopyableText } from "../../ui/React/CopyableText";
import { StartButton } from "./StartButton";
@ -16,7 +16,6 @@ import Paper from "@mui/material/Paper";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
action: IAction;
}
@ -40,13 +39,13 @@ export function GeneralActionElem(props: IProps): React.ReactElement {
case "Incite Violence":
return 60;
case "Recruitment":
return props.bladeburner.getRecruitmentTime(props.player);
return props.bladeburner.getRecruitmentTime(Player);
}
return -1; // dead code
})();
const successChance =
props.action.name === "Recruitment"
? Math.max(0, Math.min(props.bladeburner.getRecruitmentSuccessChance(props.player), 1))
? Math.max(0, Math.min(props.bladeburner.getRecruitmentSuccessChance(Player), 1))
: -1;
const actionData = GeneralActions[props.action.name];

@ -3,11 +3,9 @@ import { GeneralActionElem } from "./GeneralActionElem";
import { Action } from "../Action";
import { GeneralActions } from "../GeneralActions";
import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
}
export function GeneralActionList(props: IProps): React.ReactElement {
@ -20,7 +18,7 @@ export function GeneralActionList(props: IProps): React.ReactElement {
return (
<>
{actions.map((action: Action) => (
<GeneralActionElem key={action.name} bladeburner={props.bladeburner} action={action} player={props.player} />
<GeneralActionElem key={action.name} bladeburner={props.bladeburner} action={action} />
))}
</>
);

@ -1,19 +1,17 @@
import * as React from "react";
import { GeneralActionList } from "./GeneralActionList";
import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
import Typography from "@mui/material/Typography";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
}
export function GeneralActionPage(props: IProps): React.ReactElement {
return (
<>
<Typography>These are generic actions that will assist you in your Bladeburner duties.</Typography>
<GeneralActionList bladeburner={props.bladeburner} player={props.player} />
<GeneralActionList bladeburner={props.bladeburner} />
</>
);
}

@ -10,7 +10,7 @@ import { TeamSizeButton } from "./TeamSizeButton";
import { IBladeburner } from "../IBladeburner";
import { Operation } from "../Operation";
import { Operations } from "../data/Operations";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { CopyableText } from "../../ui/React/CopyableText";
import Typography from "@mui/material/Typography";
@ -18,7 +18,6 @@ import Paper from "@mui/material/Paper";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
action: Operation;
}
@ -33,7 +32,7 @@ export function OperationElem(props: IProps): React.ReactElement {
props.bladeburner.actionTimeCurrent + props.bladeburner.actionTimeOverflow,
props.bladeburner.actionTimeToComplete,
);
const actionTime = props.action.getActionTime(props.bladeburner, props.player);
const actionTime = props.action.getActionTime(props.bladeburner, Player);
const actionData = Operations[props.action.name];
if (actionData === undefined) {

@ -1,11 +1,9 @@
import React from "react";
import { OperationElem } from "./OperationElem";
import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
}
export function OperationList(props: IProps): React.ReactElement {
@ -14,7 +12,7 @@ export function OperationList(props: IProps): React.ReactElement {
return (
<>
{names.map((name: string) => (
<OperationElem key={name} bladeburner={props.bladeburner} action={operations[name]} player={props.player} />
<OperationElem key={name} bladeburner={props.bladeburner} action={operations[name]} />
))}
</>
);

@ -1,12 +1,10 @@
import * as React from "react";
import { OperationList } from "./OperationList";
import { IBladeburner } from "../IBladeburner";
import { IPlayer } from "../../PersonObjects/IPlayer";
import Typography from "@mui/material/Typography";
interface IProps {
bladeburner: IBladeburner;
player: IPlayer;
}
export function OperationPage(props: IProps): React.ReactElement {
@ -29,7 +27,7 @@ export function OperationPage(props: IProps): React.ReactElement {
You can unlock higher-level operations by successfully completing them. Higher-level operations are more
difficult, but grant more rank and experience.
</Typography>
<OperationList bladeburner={props.bladeburner} player={props.player} />
<OperationList bladeburner={props.bladeburner} />
</>
);
}

@ -34,7 +34,7 @@ export function StartButton(props: IProps): React.ReactElement {
props.bladeburner.action.type = props.type;
props.bladeburner.action.name = props.name;
if (!player.hasAugmentation(AugmentationNames.BladesSimulacrum, true)) player.finishWork(true);
props.bladeburner.startAction(player, props.bladeburner.action);
props.bladeburner.startAction(props.bladeburner.action);
props.rerender();
}

@ -1,11 +1,11 @@
import React, { useState, useEffect } from "react";
import { formatNumber, convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions";
import { BladeburnerConstants } from "../data/Constants";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { Money } from "../../ui/React/Money";
import { numeralWrapper } from "../../ui/numeralFormat";
import { Factions } from "../../Faction/Factions";
import { IRouter } from "../../ui/Router";
import { Router } from "../../ui/GameRoot";
import { joinFaction } from "../../Faction/FactionHelpers";
import { IBladeburner } from "../IBladeburner";
@ -19,8 +19,6 @@ import { FactionNames } from "../../Faction/data/FactionNames";
interface IProps {
bladeburner: IBladeburner;
router: IRouter;
player: IPlayer;
}
export function Stats(props: IProps): React.ReactElement {
@ -40,7 +38,7 @@ export function Stats(props: IProps): React.ReactElement {
joinFaction(faction);
}
props.router.toFaction(faction);
Router.toFaction(faction);
}
return (
@ -170,13 +168,13 @@ export function Stats(props: IProps): React.ReactElement {
<Typography>Skill Points: {formatNumber(props.bladeburner.skillPoints, 0)}</Typography>
<br />
<Typography>
Aug. Success Chance mult: {formatNumber(props.player.mults.bladeburner_success_chance * 100, 1)}%
Aug. Success Chance mult: {formatNumber(Player.mults.bladeburner_success_chance * 100, 1)}%
<br />
Aug. Max Stamina mult: {formatNumber(props.player.mults.bladeburner_max_stamina * 100, 1)}%
Aug. Max Stamina mult: {formatNumber(Player.mults.bladeburner_max_stamina * 100, 1)}%
<br />
Aug. Stamina Gain mult: {formatNumber(props.player.mults.bladeburner_stamina_gain * 100, 1)}%
Aug. Stamina Gain mult: {formatNumber(Player.mults.bladeburner_stamina_gain * 100, 1)}%
<br />
Aug. Field Analysis mult: {formatNumber(props.player.mults.bladeburner_analysis * 100, 1)}%
Aug. Field Analysis mult: {formatNumber(Player.mults.bladeburner_analysis * 100, 1)}%
</Typography>
</Box>
</Paper>

@ -1,8 +1,8 @@
import * as React from "react";
import { IPlayer } from "../PersonObjects/IPlayer";
import { Player } from "../Player";
import { Money } from "../ui/React/Money";
import { Game, reachedLimit } from "./Game";
import { win, reachedLimit } from "./Game";
import { Deck } from "./CardDeck/Deck";
import { Hand } from "./CardDeck/Hand";
import { InputAdornment } from "@mui/material";
@ -24,10 +24,6 @@ enum Result {
Tie = "Push! (Tie)",
}
type Props = {
p: IPlayer;
};
type State = {
playerHand: Hand;
dealerHand: Hand;
@ -40,11 +36,11 @@ type State = {
wagerInvalidHelperText: string;
};
export class Blackjack extends Game<Props, State> {
export class Blackjack extends React.Component<{},State> {
deck: Deck;
constructor(props: Props) {
super(props);
constructor() {
super({});
this.deck = new Deck(DECK_COUNT);
@ -64,20 +60,19 @@ export class Blackjack extends Game<Props, State> {
}
canStartGame = (): boolean => {
const { p } = this.props;
const { bet } = this.state;
return p.canAfford(bet);
return Player.canAfford(bet);
};
startGame = (): void => {
if (!this.canStartGame() || reachedLimit(this.props.p)) {
if (!this.canStartGame() || reachedLimit()) {
return;
}
// Take money from player right away so that player's dont just "leave" to avoid the loss (I mean they could
// always reload without saving but w.e) TODO: Save/Restore the RNG state to limit the value of save-scumming.
this.props.p.loseMoney(this.state.bet, "casino");
win(-this.state.bet);
const playerHand = new Hand([this.deck.safeDrawCard(), this.deck.safeDrawCard()]);
const dealerHand = new Hand([this.deck.safeDrawCard(), this.deck.safeDrawCard()]);
@ -230,7 +225,7 @@ export class Blackjack extends Game<Props, State> {
: (() => {
throw new Error(`Unexpected result: ${result}`);
})(); // This can't happen, right?
this.win(this.props.p, gains);
win(gains);
this.setState({
gameInProgress: false,
result,
@ -239,7 +234,6 @@ export class Blackjack extends Game<Props, State> {
};
wagerOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
const { p } = this.props;
const betInput = event.target.value;
const wager = Math.round(parseFloat(betInput));
if (isNaN(wager)) {
@ -263,7 +257,7 @@ export class Blackjack extends Game<Props, State> {
wagerInvalid: true,
wagerInvalidHelperText: "Exceeds max bet",
});
} else if (!p.canAfford(wager)) {
} else if (!Player.canAfford(wager)) {
this.setState({
bet: 0,
betInput,

@ -5,7 +5,6 @@
*/
import React, { useState } from "react";
import { IPlayer } from "../PersonObjects/IPlayer";
import { BadRNG } from "./RNG";
import { win, reachedLimit } from "./Game";
import { trusted } from "./utils";
@ -15,14 +14,10 @@ import TextField from "@mui/material/TextField";
import Button from "@mui/material/Button";
import Box from "@mui/material/Box";
type IProps = {
p: IPlayer;
};
const minPlay = 0;
const maxPlay = 10e3;
export function CoinFlip(props: IProps): React.ReactElement {
export function CoinFlip(): React.ReactElement {
const [investment, setInvestment] = useState(1000);
const [result, setResult] = useState(<span> </span>);
const [status, setStatus] = useState("");
@ -43,7 +38,7 @@ export function CoinFlip(props: IProps): React.ReactElement {
}
function play(guess: string): void {
if (reachedLimit(props.p)) return;
if (reachedLimit()) return;
const v = BadRNG.random();
let letter: string;
if (v < 0.5) {
@ -65,11 +60,11 @@ export function CoinFlip(props: IProps): React.ReactElement {
setTimeout(() => setPlayLock(false), 250);
if (correct) {
win(props.p, investment);
win(investment);
} else {
win(props.p, -investment);
win(-investment);
}
if (reachedLimit(props.p)) return;
if (reachedLimit()) return;
}
return (

16
src/Casino/Game.ts Normal file

@ -0,0 +1,16 @@
import { Player } from "../Player";
import { dialogBoxCreate } from "../ui/React/DialogBox";
const gainLimit = 10e9;
export function win(n: number): void {
Player.gainMoney(n, "casino");
}
export function reachedLimit(): boolean {
const reached = Player.getCasinoWinnings() > gainLimit;
if (reached) {
dialogBoxCreate("Alright cheater get out of here. You're not allowed here anymore.");
}
return reached;
}

@ -1,31 +0,0 @@
import * as React from "react";
import { IPlayer } from "../PersonObjects/IPlayer";
import { dialogBoxCreate } from "../ui/React/DialogBox";
const gainLimit = 10e9;
export function win(p: IPlayer, n: number): void {
p.gainMoney(n, "casino");
}
export function reachedLimit(p: IPlayer): boolean {
const reached = p.getCasinoWinnings() > gainLimit;
if (reached) {
dialogBoxCreate("Alright cheater get out of here. You're not allowed here anymore.");
}
return reached;
}
export class Game<T, U> extends React.Component<T, U> {
win(p: IPlayer, n: number): void {
p.gainMoney(n, "casino");
}
reachedLimit(p: IPlayer): boolean {
const reached = p.getCasinoWinnings() > gainLimit;
if (reached) {
dialogBoxCreate("Alright cheater get out of here. You're not allowed here anymore.");
}
return reached;
}
}

@ -1,6 +1,5 @@
import React, { useState, useEffect } from "react";
import { IPlayer } from "../PersonObjects/IPlayer";
import { Money } from "../ui/React/Money";
import { win, reachedLimit } from "./Game";
import { WHRNG } from "./RNG";
@ -9,10 +8,6 @@ import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import TextField from "@mui/material/TextField";
type IProps = {
p: IPlayer;
};
const minPlay = 0;
const maxPlay = 1e7;
@ -111,7 +106,7 @@ function Single(s: number): Strategy {
};
}
export function Roulette(props: IProps): React.ReactElement {
export function Roulette(): React.ReactElement {
const [rng] = useState(new WHRNG(new Date().getTime()));
const [investment, setInvestment] = useState(1000);
const [canPlay, setCanPlay] = useState(true);
@ -151,7 +146,7 @@ export function Roulette(props: IProps): React.ReactElement {
}
function play(strategy: Strategy): void {
if (reachedLimit(props.p)) return;
if (reachedLimit()) return;
setCanPlay(false);
setLock(false);
@ -184,14 +179,14 @@ export function Roulette(props: IProps): React.ReactElement {
</>
);
}
win(props.p, gain);
win(gain);
setCanPlay(true);
setLock(true);
setStatus(status);
setN(n);
reachedLimit(props.p);
reachedLimit();
}, 1600);
}

@ -1,6 +1,6 @@
import React, { useState, useEffect } from "react";
import { IPlayer } from "../PersonObjects/IPlayer";
import { Player } from "../Player";
import { Money } from "../ui/React/Money";
import { WHRNG } from "./RNG";
import { win, reachedLimit } from "./Game";
@ -9,10 +9,6 @@ import Typography from "@mui/material/Typography";
import TextField from "@mui/material/TextField";
import Button from "@mui/material/Button";
type IProps = {
p: IPlayer;
};
// statically shuffled array of symbols.
const symbols = [
"D",
@ -141,8 +137,8 @@ const payLines = [
const minPlay = 0;
const maxPlay = 1e6;
export function SlotMachine(props: IProps): React.ReactElement {
const [rng] = useState(new WHRNG(props.p.totalPlaytime));
export function SlotMachine(): React.ReactElement {
const [rng] = useState(new WHRNG(Player.totalPlaytime));
const [index, setIndex] = useState<number[]>([0, 0, 0, 0, 0]);
const [locks, setLocks] = useState<number[]>([0, 0, 0, 0, 0]);
const [investment, setInvestment] = useState(1000);
@ -191,9 +187,9 @@ export function SlotMachine(props: IProps): React.ReactElement {
}
function play(): void {
if (reachedLimit(props.p)) return;
if (reachedLimit()) return;
setStatus("playing");
win(props.p, -investment);
win(-investment);
if (!canPlay) return;
unlock();
setTimeout(lock, rng.random() * 2000 + 1000);
@ -235,7 +231,7 @@ export function SlotMachine(props: IProps): React.ReactElement {
if (count < 3) continue;
const payout = getPayout(data[0], count - 3);
gains += investment * payout;
win(props.p, investment * payout);
win(investment * payout);
}
setStatus(
@ -244,7 +240,7 @@ export function SlotMachine(props: IProps): React.ReactElement {
</>,
);
setCanPlay(true);
if (reachedLimit(props.p)) return;
if (reachedLimit()) return;
}
function unlock(): void {

@ -1,5 +1,4 @@
import { Player } from "../Player";
import { IPlayer } from "src/PersonObjects/IPlayer";
import { MaterialSizes } from "./MaterialSizes";
import { ICorporation } from "./ICorporation";
import { Corporation } from "./Corporation";
@ -271,7 +270,7 @@ export function BulkPurchase(corp: ICorporation, warehouse: Warehouse, material:
}
}
export function SellShares(corporation: ICorporation, player: IPlayer, numShares: number): number {
export function SellShares(corporation: ICorporation, numShares: number): number {
if (isNaN(numShares)) throw new Error("Invalid value for number of shares");
if (numShares < 0) throw new Error("Invalid value for number of shares");
if (numShares > corporation.numShares) throw new Error("You don't have that many shares to sell!");
@ -287,20 +286,20 @@ export function SellShares(corporation: ICorporation, player: IPlayer, numShares
corporation.sharePrice = newSharePrice;
corporation.shareSalesUntilPriceUpdate = newSharesUntilUpdate;
corporation.shareSaleCooldown = CorporationConstants.SellSharesCooldown;
player.gainMoney(profit, "corporation");
Player.gainMoney(profit, "corporation");
return profit;
}
export function BuyBackShares(corporation: ICorporation, player: IPlayer, numShares: number): boolean {
export function BuyBackShares(corporation: ICorporation, numShares: number): boolean {
if (isNaN(numShares)) throw new Error("Invalid value for number of shares");
if (numShares < 0) throw new Error("Invalid value for number of shares");
if (numShares > corporation.issuedShares) throw new Error("You don't have that many shares to buy!");
if (!corporation.public) throw new Error("You haven't gone public!");
const buybackPrice = corporation.sharePrice * 1.1;
if (player.money < numShares * buybackPrice) throw new Error("You cant afford that many shares!");
if (Player.money < numShares * buybackPrice) throw new Error("You cant afford that many shares!");
corporation.numShares += numShares;
corporation.issuedShares -= numShares;
player.loseMoney(numShares * buybackPrice, "corporation");
Player.loseMoney(numShares * buybackPrice, "corporation");
return true;
}

@ -8,7 +8,7 @@ import { Industry } from "./Industry";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { showLiterature } from "../Literature/LiteratureHelpers";
import { LiteratureNames } from "../Literature/data/LiteratureNames";
import { IPlayer } from "../PersonObjects/IPlayer";
import { Player } from "../Player";
import { dialogBoxCreate } from "../ui/React/DialogBox";
import { Reviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver";
@ -76,7 +76,7 @@ export class Corporation {
this.storedCycles += numCycles;
}
process(player: IPlayer): void {
process(): void {
if (this.storedCycles >= CorporationConstants.CyclesPerIndustryStateCycle) {
const state = this.getState();
const marketCycles = 1;
@ -139,7 +139,7 @@ export class Corporation {
} else {
const totalDividends = this.dividendRate * cycleProfit;
const retainedEarnings = cycleProfit - totalDividends;
player.gainMoney(this.getCycleDividends(), "corporation");
Player.gainMoney(this.getCycleDividends(), "corporation");
this.addFunds(retainedEarnings);
}
} else {
@ -428,9 +428,9 @@ export class Corporation {
// Adds the Corporation Handbook (Starter Guide) to the player's home computer.
// This is a lit file that gives introductory info to the player
// This occurs when the player clicks the "Getting Started Guide" button on the overview panel
getStarterGuide(player: IPlayer): void {
getStarterGuide(): void {
// Check if player already has Corporation Handbook
const homeComp = player.getHomeComputer();
const homeComp = Player.getHomeComputer();
let hasHandbook = false;
const handbookFn = LiteratureNames.CorporationManagementHandbook;
for (let i = 0; i < homeComp.messages.length; ++i) {

@ -31,7 +31,6 @@ export function Industry(props: IProps): React.ReactElement {
<Box sx={{ width: "50%" }}>
<IndustryWarehouse
rerender={props.rerender}
player={player}
corp={corp}
currentCity={props.city}
division={division}

@ -15,7 +15,6 @@ import { numeralWrapper } from "../../ui/numeralFormat";
import { ICorporation } from "../ICorporation";
import { IIndustry } from "../IIndustry";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { MoneyCost } from "./MoneyCost";
import { isRelevantMaterial } from "./Helpers";
import { IndustryProductEquation } from "./IndustryProductEquation";
@ -35,7 +34,6 @@ interface IProps {
division: IIndustry;
warehouse: Warehouse | 0;
currentCity: string;
player: IPlayer;
rerender: () => void;
}

@ -35,7 +35,7 @@ export function BuybackSharesModal(props: IProps): React.ReactElement {
function buy(): void {
if (disabled) return;
try {
BuyBackShares(corp, player, shares);
BuyBackShares(corp, shares);
} catch (err) {
dialogBoxCreate(err + "");
}

@ -72,7 +72,7 @@ export function CreateCorporationModal(props: IProps): React.ReactElement {
</Button>
)}
<Button onClick={selfFund} disabled={name == "" || !canSelfFund}>
Self-Fund (<Money money={150e9} player={player} />)
Self-Fund (<Money money={150e9} forPurchase={true} />)
</Button>
</Modal>
);

@ -49,7 +49,7 @@ export function SellSharesModal(props: IProps): React.ReactElement {
function sell(): void {
if (disabled) return;
try {
const profit = SellShares(corp, player, shares);
const profit = SellShares(corp, shares);
props.onClose();
dialogBoxCreate(
<>

@ -1,16 +1,16 @@
import { Crimes } from "./Crimes";
import { Crime } from "./Crime";
import { IPlayer } from "../PersonObjects/IPlayer";
import { Player } from "../Player";
import { dialogBoxCreate } from "../ui/React/DialogBox";
export function determineCrimeSuccess(p: IPlayer, type: string): boolean {
export function determineCrimeSuccess(type: string): boolean {
let chance = 0;
let found = false;
for (const i of Object.keys(Crimes)) {
const crime = Crimes[i];
if (crime.type === type) {
chance = crime.successRate(p);
chance = crime.successRate(Player);
found = true;
break;
}

@ -1,7 +1,5 @@
import { IPlayer } from "./PersonObjects/IPlayer";
import { Player } from "./Player";
import { Bladeburner } from "./Bladeburner/Bladeburner";
import { IEngine } from "./IEngine";
import { IRouter } from "./ui/Router";
import { AugmentationNames } from "./Augmentation/data/AugmentationNames";
import React, { useEffect } from "react";
@ -28,44 +26,38 @@ import { Entropy } from "./DevMenu/ui/Entropy";
import Typography from "@mui/material/Typography";
import { Exploit } from "./Exploits/Exploit";
interface IProps {
player: IPlayer;
engine: IEngine;
router: IRouter;
}
export function DevMenuRoot(props: IProps): React.ReactElement {
export function DevMenuRoot(): React.ReactElement {
useEffect(() => {
props.player.giveExploit(Exploit.YoureNotMeantToAccessThis);
Player.giveExploit(Exploit.YoureNotMeantToAccessThis);
}, []);
return (
<>
<Typography>Development Menu - Only meant to be used for testing/debugging</Typography>
<General player={props.player} router={props.router} />
<Stats player={props.player} />
<Factions player={props.player} />
<Augmentations player={props.player} />
<SourceFiles player={props.player} />
<Programs player={props.player} />
<General />
<Stats />
<Factions />
<Augmentations />
<SourceFiles />
<Programs />
<Servers />
<Companies />
{props.player.bladeburner instanceof Bladeburner && <BladeburnerElem player={props.player} />}
{Player.bladeburner instanceof Bladeburner && <BladeburnerElem />}
{props.player.inGang() && <Gang player={props.player} />}
{Player.inGang() && <Gang />}
{props.player.hasCorporation() && <Corporation player={props.player} />}
{Player.hasCorporation() && <Corporation />}
<CodingContracts />
{props.player.hasWseAccount && <StockMarket />}
{Player.hasWseAccount && <StockMarket />}
{props.player.sleeves.length > 0 && <Sleeves player={props.player} />}
{props.player.augmentations.some((aug) => aug.name === AugmentationNames.StaneksGift1) && <Stanek />}
{Player.sleeves.length > 0 && <Sleeves />}
{Player.augmentations.some((aug) => aug.name === AugmentationNames.StaneksGift1) && <Stanek />}
<TimeSkip player={props.player} engine={props.engine} />
<Achievements player={props.player} engine={props.engine} />
<Entropy player={props.player} engine={props.engine} />
<TimeSkip />
<Achievements />
<Entropy />
<SaveFile />
</>
);

@ -11,44 +11,39 @@ import { Tooltip } from "@mui/material";
import LockIcon from "@mui/icons-material/Lock";
import LockOpenIcon from "@mui/icons-material/LockOpen";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { achievements } from "../../Achievements/Achievements";
import { IEngine } from "../../IEngine";
import { Engine } from "../../engine";
interface IProps {
player: IPlayer;
engine: IEngine;
}
export function Achievements(props: IProps): React.ReactElement {
const [playerAchievement, setPlayerAchievements] = useState(props.player.achievements.map((m) => m.ID));
export function Achievements(): React.ReactElement {
const [playerAchievement, setPlayerAchievements] = useState(Player.achievements.map((m) => m.ID));
function grantAchievement(id: string): void {
props.player.giveAchievement(id);
setPlayerAchievements(props.player.achievements.map((m) => m.ID));
Player.giveAchievement(id);
setPlayerAchievements(Player.achievements.map((m) => m.ID));
}
function grantAllAchievements(): void {
Object.values(achievements).forEach((a) => props.player.giveAchievement(a.ID));
setPlayerAchievements(props.player.achievements.map((m) => m.ID));
Object.values(achievements).forEach((a) => Player.giveAchievement(a.ID));
setPlayerAchievements(Player.achievements.map((m) => m.ID));
}
function removeAchievement(id: string): void {
props.player.achievements = props.player.achievements.filter((a) => a.ID !== id);
setPlayerAchievements(props.player.achievements.map((m) => m.ID));
Player.achievements = Player.achievements.filter((a) => a.ID !== id);
setPlayerAchievements(Player.achievements.map((m) => m.ID));
}
function clearAchievements(): void {
props.player.achievements = [];
setPlayerAchievements(props.player.achievements.map((m) => m.ID));
Player.achievements = [];
setPlayerAchievements(Player.achievements.map((m) => m.ID));
}
function disableEngine(): void {
props.engine.Counters.achievementsCounter = Number.MAX_VALUE;
Engine.Counters.achievementsCounter = Number.MAX_VALUE;
}
function enableEngine(): void {
props.engine.Counters.achievementsCounter = 0;
Engine.Counters.achievementsCounter = 0;
}
return (

@ -12,34 +12,30 @@ import {
} from "@mui/material";
import React, { useState } from "react";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
interface IProps {
player: IPlayer;
}
export function Augmentations(props: IProps): React.ReactElement {
export function Augmentations(): React.ReactElement {
const [augmentation, setAugmentation] = useState("Augmented Targeting I");
function setAugmentationDropdown(event: SelectChangeEvent<string>): void {
setAugmentation(event.target.value);
}
function queueAug(): void {
props.player.queueAugmentation(augmentation);
Player.queueAugmentation(augmentation);
}
function queueAllAugs(): void {
for (const augName of Object.values(AugmentationNames)) {
props.player.queueAugmentation(augName);
Player.queueAugmentation(augName);
}
}
function clearAugs(): void {
props.player.augmentations = [];
Player.augmentations = [];
}
function clearQueuedAugs(): void {
props.player.queuedAugmentations = [];
Player.queuedAugmentations = [];
}
return (

@ -7,21 +7,17 @@ import AccordionDetails from "@mui/material/AccordionDetails";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import { Adjuster } from "./Adjuster";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
const bigNumber = 1e27;
interface IProps {
player: IPlayer;
}
export function Bladeburner(props: IProps): React.ReactElement {
const bladeburner = props.player.bladeburner;
export function Bladeburner(): React.ReactElement {
const bladeburner = Player.bladeburner;
if (bladeburner === null) return <></>;
function modifyBladeburnerRank(modify: number): (x: number) => void {
return function (rank: number): void {
if (!bladeburner) return;
bladeburner.changeRank(props.player, rank * modify);
bladeburner.changeRank(Player, rank * modify);
};
}
@ -34,7 +30,7 @@ export function Bladeburner(props: IProps): React.ReactElement {
function addTonsBladeburnerRank(): void {
if (!bladeburner) return;
bladeburner.changeRank(props.player, bigNumber);
bladeburner.changeRank(Player, bigNumber);
}
function modifyBladeburnerCycles(modify: number): (x: number) => void {

@ -8,58 +8,54 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import { Adjuster } from "./Adjuster";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
const bigNumber = 1e27;
interface IProps {
player: IPlayer;
}
export function Corporation(props: IProps): React.ReactElement {
export function Corporation(): React.ReactElement {
function addTonsCorporationFunds(): void {
if (props.player.corporation) {
props.player.corporation.funds = props.player.corporation.funds + bigNumber;
if (Player.corporation) {
Player.corporation.funds = Player.corporation.funds + bigNumber;
}
}
function modifyCorporationFunds(modify: number): (x: number) => void {
return function (funds: number): void {
if (props.player.corporation) {
props.player.corporation.funds += funds * modify;
if (Player.corporation) {
Player.corporation.funds += funds * modify;
}
};
}
function resetCorporationFunds(): void {
if (props.player.corporation) {
props.player.corporation.funds = props.player.corporation.funds - props.player.corporation.funds;
if (Player.corporation) {
Player.corporation.funds = Player.corporation.funds - Player.corporation.funds;
}
}
function addTonsCorporationCycles(): void {
if (props.player.corporation) {
props.player.corporation.storedCycles = bigNumber;
if (Player.corporation) {
Player.corporation.storedCycles = bigNumber;
}
}
function modifyCorporationCycles(modify: number): (x: number) => void {
return function (cycles: number): void {
if (props.player.corporation) {
props.player.corporation.storedCycles += cycles * modify;
if (Player.corporation) {
Player.corporation.storedCycles += cycles * modify;
}
};
}
function resetCorporationCycles(): void {
if (props.player.corporation) {
props.player.corporation.storedCycles = 0;
if (Player.corporation) {
Player.corporation.storedCycles = 0;
}
}
function finishCorporationProducts(): void {
if (!props.player.corporation) return;
props.player.corporation.divisions.forEach((div) => {
if (!Player.corporation) return;
Player.corporation.divisions.forEach((div) => {
Object.keys(div.products).forEach((prod) => {
const product = div.products[prod];
if (product === undefined) throw new Error("Impossible product undefined");
@ -69,8 +65,8 @@ export function Corporation(props: IProps): React.ReactElement {
}
function addCorporationResearch(): void {
if (!props.player.corporation) return;
props.player.corporation.divisions.forEach((div) => {
if (!Player.corporation) return;
Player.corporation.divisions.forEach((div) => {
div.sciResearch.qty += 1e10;
});
}

@ -6,18 +6,12 @@ import AccordionDetails from "@mui/material/AccordionDetails";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import Typography from "@mui/material/Typography";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { Adjuster } from "./Adjuster";
import { IEngine } from "../../IEngine";
// Update as additional BitNodes get implemented
interface IProps {
player: IPlayer;
engine: IEngine;
}
export function Entropy(props: IProps): React.ReactElement {
export function Entropy(): React.ReactElement {
return (
<Accordion TransitionProps={{ unmountOnExit: true }}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
@ -28,20 +22,20 @@ export function Entropy(props: IProps): React.ReactElement {
label="Set entropy"
placeholder="entropy"
add={(num) => {
props.player.entropy += num;
props.player.applyEntropy(props.player.entropy);
Player.entropy += num;
Player.applyEntropy(Player.entropy);
}}
subtract={(num) => {
props.player.entropy -= num;
props.player.applyEntropy(props.player.entropy);
Player.entropy -= num;
Player.applyEntropy(Player.entropy);
}}
tons={() => {
props.player.entropy += 1e12;
props.player.applyEntropy(props.player.entropy);
Player.entropy += 1e12;
Player.applyEntropy(Player.entropy);
}}
reset={() => {
props.player.entropy = 0;
props.player.applyEntropy(props.player.entropy);
Player.entropy = 0;
Player.applyEntropy(Player.entropy);
}}
/>
</AccordionDetails>

@ -9,7 +9,7 @@ import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import Select, { SelectChangeEvent } from "@mui/material/Select";
import { Adjuster } from "./Adjuster";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { Factions as AllFaction } from "../../Faction/Factions";
import FormControl from "@mui/material/FormControl";
import MenuItem from "@mui/material/MenuItem";
@ -21,11 +21,7 @@ import { FactionNames } from "../../Faction/data/FactionNames";
const bigNumber = 1e12;
interface IProps {
player: IPlayer;
}
export function Factions(props: IProps): React.ReactElement {
export function Factions(): React.ReactElement {
const [faction, setFaction] = useState(FactionNames.Illuminati as string);
function setFactionDropdown(event: SelectChangeEvent<string>): void {
@ -33,11 +29,11 @@ export function Factions(props: IProps): React.ReactElement {
}
function receiveInvite(): void {
props.player.receiveInvite(faction);
Player.receiveInvite(faction);
}
function receiveAllInvites(): void {
Object.values(FactionNames).forEach((faction) => props.player.receiveInvite(faction));
Object.values(FactionNames).forEach((faction) => Player.receiveInvite(faction));
}
function modifyFactionRep(modifier: number): (x: number) => void {

@ -7,32 +7,28 @@ import AccordionDetails from "@mui/material/AccordionDetails";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import { Adjuster } from "./Adjuster";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
const bigNumber = 1e27;
interface IProps {
player: IPlayer;
}
export function Gang(props: IProps): React.ReactElement {
export function Gang(): React.ReactElement {
function addTonsGangCycles(): void {
if (props.player.gang) {
props.player.gang.storedCycles = bigNumber;
if (Player.gang) {
Player.gang.storedCycles = bigNumber;
}
}
function modifyGangCycles(modify: number): (x: number) => void {
return function (cycles: number): void {
if (props.player.gang) {
props.player.gang.storedCycles += cycles * modify;
if (Player.gang) {
Player.gang.storedCycles += cycles * modify;
}
};
}
function resetGangCycles(): void {
if (props.player.gang) {
props.player.gang.storedCycles = 0;
if (Player.gang) {
Player.gang.storedCycles = 0;
}
}

@ -8,61 +8,56 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import { Money } from "../../ui/React/Money";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { IRouter } from "../../ui/Router";
import { Player } from "../../Player";
import { Router } from "../../ui/GameRoot";
import { MenuItem, SelectChangeEvent, TextField, Select } from "@mui/material";
import { Bladeburner } from "../../Bladeburner/Bladeburner";
import { GangConstants } from "../../Gang/data/Constants";
import { FactionNames } from "../../Faction/data/FactionNames";
import { checkForMessagesToSend } from "../../Message/MessageHelpers";
interface IProps {
player: IPlayer;
router: IRouter;
}
export function General(props: IProps): React.ReactElement {
export function General(): React.ReactElement {
const [error, setError] = useState(false);
const [corporationName, setCorporationName] = useState("");
const [gangFaction, setGangFaction] = useState("");
function addMoney(n: number) {
return function () {
props.player.gainMoney(n, "other");
Player.gainMoney(n, "other");
};
}
function upgradeRam(): void {
props.player.getHomeComputer().maxRam *= 2;
Player.getHomeComputer().maxRam *= 2;
}
function quickB1tFlum3(): void {
props.router.toBitVerse(true, true);
Router.toBitVerse(true, true);
}
function b1tflum3(): void {
props.router.toBitVerse(true, false);
Router.toBitVerse(true, false);
}
function quickHackW0r1dD43m0n(): void {
props.router.toBitVerse(false, true);
Router.toBitVerse(false, true);
}
function hackW0r1dD43m0n(): void {
props.router.toBitVerse(false, false);
Router.toBitVerse(false, false);
}
function createCorporation(): void {
props.player.startCorporation(corporationName);
Player.startCorporation(corporationName);
}
function joinBladeburner(): void {
props.player.bladeburner = new Bladeburner(props.player);
Player.bladeburner = new Bladeburner();
}
function startGang(): void {
const isHacking = gangFaction === FactionNames.NiteSec || gangFaction === FactionNames.TheBlackHand;
props.player.startGang(gangFaction, isHacking);
Player.startGang(gangFaction, isHacking);
}
function setGangFactionDropdown(event: SelectChangeEvent<string>): void {

@ -8,29 +8,25 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import Select, { SelectChangeEvent } from "@mui/material/Select";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { Programs as AllPrograms } from "../../Programs/Programs";
import MenuItem from "@mui/material/MenuItem";
interface IProps {
player: IPlayer;
}
export function Programs(props: IProps): React.ReactElement {
export function Programs(): React.ReactElement {
const [program, setProgram] = useState("NUKE.exe");
function setProgramDropdown(event: SelectChangeEvent<string>): void {
setProgram(event.target.value);
}
function addProgram(): void {
if (!props.player.hasProgram(program)) {
props.player.getHomeComputer().programs.push(program);
if (!Player.hasProgram(program)) {
Player.getHomeComputer().programs.push(program);
}
}
function addAllPrograms(): void {
for (const i of Object.keys(AllPrograms)) {
if (!props.player.hasProgram(AllPrograms[i].name)) {
props.player.getHomeComputer().programs.push(AllPrograms[i].name);
if (!Player.hasProgram(AllPrograms[i].name)) {
Player.getHomeComputer().programs.push(AllPrograms[i].name);
}
}
}

@ -7,41 +7,37 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import Button from "@mui/material/Button";
import Typography from "@mui/material/Typography";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { Adjuster } from "./Adjuster";
interface IProps {
player: IPlayer;
}
export function Sleeves(props: IProps): React.ReactElement {
export function Sleeves(): React.ReactElement {
function sleeveMaxAllShock(): void {
for (let i = 0; i < props.player.sleeves.length; ++i) {
props.player.sleeves[i].shock = 0;
for (let i = 0; i < Player.sleeves.length; ++i) {
Player.sleeves[i].shock = 0;
}
}
function sleeveClearAllShock(): void {
for (let i = 0; i < props.player.sleeves.length; ++i) {
props.player.sleeves[i].shock = 100;
for (let i = 0; i < Player.sleeves.length; ++i) {
Player.sleeves[i].shock = 100;
}
}
function sleeveSyncMaxAll(): void {
for (let i = 0; i < props.player.sleeves.length; ++i) {
props.player.sleeves[i].sync = 100;
for (let i = 0; i < Player.sleeves.length; ++i) {
Player.sleeves[i].sync = 100;
}
}
function sleeveSyncClearAll(): void {
for (let i = 0; i < props.player.sleeves.length; ++i) {
props.player.sleeves[i].sync = 0;
for (let i = 0; i < Player.sleeves.length; ++i) {
Player.sleeves[i].sync = 0;
}
}
function sleeveSetStoredCycles(cycles: number): void {
for (let i = 0; i < props.player.sleeves.length; ++i) {
props.player.sleeves[i].storedCycles = cycles;
for (let i = 0; i < Player.sleeves.length; ++i) {
Player.sleeves[i].storedCycles = cycles;
}
}

@ -8,35 +8,31 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import { PlayerOwnedSourceFile } from "../../SourceFile/PlayerOwnedSourceFile";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import ButtonGroup from "@mui/material/ButtonGroup";
// Update as additional BitNodes get implemented
const validSFN = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13];
interface IProps {
player: IPlayer;
}
export function SourceFiles(props: IProps): React.ReactElement {
export function SourceFiles(): React.ReactElement {
function setSF(sfN: number, sfLvl: number) {
return function () {
if (sfN === 9) {
props.player.hacknetNodes = [];
Player.hacknetNodes = [];
}
if (sfLvl === 0) {
props.player.sourceFiles = props.player.sourceFiles.filter((sf) => sf.n !== sfN);
Player.sourceFiles = Player.sourceFiles.filter((sf) => sf.n !== sfN);
return;
}
if (!props.player.sourceFiles.some((sf) => sf.n === sfN)) {
props.player.sourceFiles.push(new PlayerOwnedSourceFile(sfN, sfLvl));
if (!Player.sourceFiles.some((sf) => sf.n === sfN)) {
Player.sourceFiles.push(new PlayerOwnedSourceFile(sfN, sfLvl));
return;
}
for (let i = 0; i < props.player.sourceFiles.length; i++) {
if (props.player.sourceFiles[i].n === sfN) {
props.player.sourceFiles[i].lvl = sfLvl;
for (let i = 0; i < Player.sourceFiles.length; i++) {
if (Player.sourceFiles[i].n === sfN) {
Player.sourceFiles[i].lvl = sfLvl;
}
}
};
@ -51,7 +47,7 @@ export function SourceFiles(props: IProps): React.ReactElement {
}
function clearExploits(): void {
props.player.exploits = [];
Player.exploits = [];
}
return (

@ -8,132 +8,128 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import { Adjuster } from "./Adjuster";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
const bigNumber = 1e27;
interface IProps {
player: IPlayer;
}
export function Stats(props: IProps): React.ReactElement {
export function Stats(): React.ReactElement {
function modifyExp(stat: string, modifier: number) {
return function (exp: number) {
switch (stat) {
case "hacking":
if (exp) {
props.player.gainHackingExp(exp * modifier);
Player.gainHackingExp(exp * modifier);
}
break;
case "strength":
if (exp) {
props.player.gainStrengthExp(exp * modifier);
Player.gainStrengthExp(exp * modifier);
}
break;
case "defense":
if (exp) {
props.player.gainDefenseExp(exp * modifier);
Player.gainDefenseExp(exp * modifier);
}
break;
case "dexterity":
if (exp) {
props.player.gainDexterityExp(exp * modifier);
Player.gainDexterityExp(exp * modifier);
}
break;
case "agility":
if (exp) {
props.player.gainAgilityExp(exp * modifier);
Player.gainAgilityExp(exp * modifier);
}
break;
case "charisma":
if (exp) {
props.player.gainCharismaExp(exp * modifier);
Player.gainCharismaExp(exp * modifier);
}
break;
case "intelligence":
if (exp) {
props.player.gainIntelligenceExp(exp * modifier);
Player.gainIntelligenceExp(exp * modifier);
}
break;
}
props.player.updateSkillLevels();
Player.updateSkillLevels();
};
}
function modifyKarma(modifier: number) {
return function (amt: number) {
props.player.karma += amt * modifier;
Player.karma += amt * modifier;
};
}
function tonsOfExp(): void {
props.player.gainHackingExp(bigNumber);
props.player.gainStrengthExp(bigNumber);
props.player.gainDefenseExp(bigNumber);
props.player.gainDexterityExp(bigNumber);
props.player.gainAgilityExp(bigNumber);
props.player.gainCharismaExp(bigNumber);
props.player.gainIntelligenceExp(bigNumber);
props.player.updateSkillLevels();
Player.gainHackingExp(bigNumber);
Player.gainStrengthExp(bigNumber);
Player.gainDefenseExp(bigNumber);
Player.gainDexterityExp(bigNumber);
Player.gainAgilityExp(bigNumber);
Player.gainCharismaExp(bigNumber);
Player.gainIntelligenceExp(bigNumber);
Player.updateSkillLevels();
}
function resetAllExp(): void {
props.player.exp.hacking = 0;
props.player.exp.strength = 0;
props.player.exp.defense = 0;
props.player.exp.dexterity = 0;
props.player.exp.agility = 0;
props.player.exp.charisma = 0;
props.player.exp.intelligence = 0;
props.player.updateSkillLevels();
Player.exp.hacking = 0;
Player.exp.strength = 0;
Player.exp.defense = 0;
Player.exp.dexterity = 0;
Player.exp.agility = 0;
Player.exp.charisma = 0;
Player.exp.intelligence = 0;
Player.updateSkillLevels();
}
function resetExperience(stat: string): () => void {
return function () {
switch (stat) {
case "hacking":
props.player.exp.hacking = 0;
Player.exp.hacking = 0;
break;
case "strength":
props.player.exp.strength = 0;
Player.exp.strength = 0;
break;
case "defense":
props.player.exp.defense = 0;
Player.exp.defense = 0;
break;
case "dexterity":
props.player.exp.dexterity = 0;
Player.exp.dexterity = 0;
break;
case "agility":
props.player.exp.agility = 0;
Player.exp.agility = 0;
break;
case "charisma":
props.player.exp.charisma = 0;
Player.exp.charisma = 0;
break;
case "intelligence":
props.player.exp.intelligence = 0;
Player.exp.intelligence = 0;
break;
}
props.player.updateSkillLevels();
Player.updateSkillLevels();
};
}
function resetKarma(): () => void {
return function () {
props.player.karma = 0;
Player.karma = 0;
};
}
function enableIntelligence(): void {
if (props.player.skills.intelligence === 0) {
props.player.skills.intelligence = 1;
props.player.updateSkillLevels();
if (Player.skills.intelligence === 0) {
Player.skills.intelligence = 1;
Player.updateSkillLevels();
}
}
function disableIntelligence(): void {
props.player.exp.intelligence = 0;
props.player.skills.intelligence = 0;
props.player.updateSkillLevels();
Player.exp.intelligence = 0;
Player.skills.intelligence = 0;
Player.updateSkillLevels();
}
return (

@ -7,22 +7,17 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { saveObject } from "../../SaveObject";
import { IEngine } from "../../IEngine";
import { Engine } from "../../engine";
// Update as additional BitNodes get implemented
interface IProps {
player: IPlayer;
engine: IEngine;
}
export function TimeSkip(props: IProps): React.ReactElement {
export function TimeSkip(): React.ReactElement {
function timeskip(time: number) {
return () => {
props.player.lastUpdate -= time;
props.engine._lastUpdate -= time;
Player.lastUpdate -= time;
Engine._lastUpdate -= time;
saveObject.saveGame();
setTimeout(() => location.reload(), 1000);
};

@ -1,5 +1,5 @@
import { Factions } from "./Faction/Factions";
import { IPlayer } from "./PersonObjects/IPlayer";
import { Player } from "./Player";
export let LastExportBonus = 0;
@ -9,9 +9,9 @@ export function canGetBonus(): boolean {
return now - LastExportBonus > bonusTimer;
}
export function onExport(p: IPlayer): void {
export function onExport(): void {
if (!canGetBonus()) return;
for (const facName of p.factions) {
for (const facName of Player.factions) {
Factions[facName].favor++;
}
LastExportBonus = new Date().getTime();

@ -7,7 +7,6 @@ import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { Faction } from "./Faction";
import { Factions } from "./Factions";
import { Player } from "../Player";
import { IPlayer } from "../PersonObjects/IPlayer";
import { Settings } from "../Settings/Settings";
import {
getHackingWorkRepGain,
@ -59,7 +58,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);
const augCosts = aug.getCost();
if (!hasPrereqs) {
const txt = `You must first purchase or install ${aug.prereqs
.filter((req) => !Player.hasAugmentation(req))
@ -84,7 +83,7 @@ export function purchaseAugmentation(aug: Augmentation, fac: Faction, sing = fal
} else if (augCosts.moneyCost === 0 || Player.money >= augCosts.moneyCost) {
const queuedAugmentation = new PlayerOwnedAugmentation(aug.name);
if (aug.name == AugmentationNames.NeuroFluxGovernor) {
queuedAugmentation.level = aug.getLevel(Player);
queuedAugmentation.level = aug.getLevel();
}
Player.queuedAugmentations.push(queuedAugmentation);
@ -134,20 +133,20 @@ export function processPassiveFactionRepGain(numCycles: number): void {
}
}
export const getFactionAugmentationsFiltered = (player: IPlayer, faction: Faction): string[] => {
export const getFactionAugmentationsFiltered = (faction: Faction): string[] => {
// If player has a gang with this faction, return (almost) all augmentations
if (player.hasGangWith(faction.name)) {
if (Player.hasGangWith(faction.name)) {
let augs = Object.values(StaticAugmentations);
// Remove special augs
augs = augs.filter((a) => !a.isSpecial && a.name !== AugmentationNames.CongruityImplant);
if (player.bitNodeN === 2) {
if (Player.bitNodeN === 2) {
// TRP is not available outside of BN2 for Gangs
augs.push(StaticAugmentations[AugmentationNames.TheRedPill]);
}
const rng = SFC32RNG(`BN${player.bitNodeN}.${player.sourceFileLvl(player.bitNodeN)}`);
const rng = SFC32RNG(`BN${Player.bitNodeN}.${Player.sourceFileLvl(Player.bitNodeN)}`);
// Remove faction-unique augs that don't belong to this faction
const uniqueFilter = (a: Augmentation): boolean => {
// Keep all the non-unique one

@ -1,6 +1,6 @@
import { CONSTANTS } from "../../Constants";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { IPerson } from "../../PersonObjects/IPerson";
export function repFromDonation(amt: number, player: IPlayer): number {
return (amt / CONSTANTS.DonateMoneyToRepDivisor) * player.mults.faction_rep;
export function repFromDonation(amt: number, person: IPerson): number {
return (amt / CONSTANTS.DonateMoneyToRepDivisor) * person.mults.faction_rep;
}

@ -10,7 +10,7 @@ import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { PurchasableAugmentations } from "../../Augmentation/ui/PurchasableAugmentations";
import { PurchaseAugmentationsOrderSetting } from "../../Settings/SettingEnums";
import { Settings } from "../../Settings/Settings";
import { use } from "../../ui/Context";
import { Player } from "../../Player";
import { numeralWrapper } from "../../ui/numeralFormat";
import { Favor } from "../../ui/React/Favor";
import { Reputation } from "../../ui/React/Reputation";
@ -24,8 +24,6 @@ type IProps = {
};
export function AugmentationsPage(props: IProps): React.ReactElement {
const player = use.Player();
const setRerender = useState(false)[1];
function rerender(): void {
@ -33,7 +31,7 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
}
function getAugs(): string[] {
return getFactionAugmentationsFiltered(player, props.faction);
return getFactionAugmentationsFiltered(props.faction);
}
function getAugsSorted(): string[] {
@ -61,7 +59,7 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
throw new Error("Invalid Augmentation Names");
}
return aug1.getCost(player).moneyCost - aug2.getCost(player).moneyCost;
return aug1.getCost().moneyCost - aug2.getCost().moneyCost;
});
return augs;
@ -71,11 +69,11 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
const augs = getAugs();
function canBuy(augName: string): boolean {
const aug = StaticAugmentations[augName];
const augCosts = aug.getCost(player);
const augCosts = aug.getCost();
const repCost = augCosts.repCost;
const hasReq = props.faction.playerReputation >= repCost;
const hasRep = hasAugmentationPrereqs(aug);
const hasCost = augCosts.moneyCost !== 0 && player.money > augCosts.moneyCost;
const hasCost = augCosts.moneyCost !== 0 && Player.money > augCosts.moneyCost;
return hasCost && hasReq && hasRep;
}
const buy = augs.filter(canBuy).sort((augName1, augName2) => {
@ -85,7 +83,7 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
throw new Error("Invalid Augmentation Names");
}
return aug1.getCost(player).moneyCost - aug2.getCost(player).moneyCost;
return aug1.getCost().moneyCost - aug2.getCost().moneyCost;
});
const cantBuy = augs
.filter((aug) => !canBuy(aug))
@ -95,7 +93,7 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
if (aug1 == null || aug2 == null) {
throw new Error("Invalid Augmentation Names");
}
return aug1.getCost(player).repCost - aug2.getCost(player).repCost;
return aug1.getCost().repCost - aug2.getCost().repCost;
});
return buy.concat(cantBuy);
@ -109,7 +107,7 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
if (aug1 == null || aug2 == null) {
throw new Error("Invalid Augmentation Names");
}
return aug1.getCost(player).repCost - aug2.getCost(player).repCost;
return aug1.getCost().repCost - aug2.getCost().repCost;
});
return augs;
@ -128,7 +126,7 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
const purchasable = augs.filter(
(aug: string) =>
aug === AugmentationNames.NeuroFluxGovernor ||
(!player.augmentations.some((a) => a.name === aug) && !player.queuedAugmentations.some((a) => a.name === aug)),
(!Player.augmentations.some((a) => a.name === aug) && !Player.queuedAugmentations.some((a) => a.name === aug)),
);
const owned = augs.filter((aug: string) => !purchasable.includes(aug));
@ -195,16 +193,15 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
<PurchasableAugmentations
augNames={purchasable}
ownedAugNames={owned}
player={player}
canPurchase={(player, aug) => {
const costs = aug.getCost(player);
canPurchase={(aug) => {
const costs = aug.getCost();
return (
hasAugmentationPrereqs(aug) &&
props.faction.playerReputation >= costs.repCost &&
(costs.moneyCost === 0 || player.money > costs.moneyCost)
(costs.moneyCost === 0 || Player.money > costs.moneyCost)
);
}}
purchaseAugmentation={(player, aug, showModal) => {
purchaseAugmentation={(aug, showModal) => {
if (!Settings.SuppressBuyAugmentationConfirmation) {
showModal(true);
} else {

@ -5,7 +5,7 @@ import React, { useState } from "react";
import { CONSTANTS } from "../../Constants";
import { Faction } from "../Faction";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { repFromDonation } from "../formulas/donation";
import { Favor } from "../../ui/React/Favor";
@ -24,7 +24,6 @@ type IProps = {
faction: Faction;
disabled: boolean;
favorToDonate: number;
p: IPlayer;
rerender: () => void;
};
@ -35,7 +34,7 @@ export function DonateOption(props: IProps): React.ReactElement {
function canDonate(): boolean {
if (isNaN(donateAmt)) return false;
if (isNaN(donateAmt) || donateAmt <= 0) return false;
if (props.p.money < donateAmt) return false;
if (Player.money < donateAmt) return false;
return true;
}
@ -44,8 +43,8 @@ export function DonateOption(props: IProps): React.ReactElement {
const amt = donateAmt;
if (isNaN(amt)) return;
if (!canDonate()) return;
props.p.loseMoney(amt, "other");
const repGain = repFromDonation(amt, props.p);
Player.loseMoney(amt, "other");
const repGain = repFromDonation(amt, Player);
props.faction.playerReputation += repGain;
dialogBoxCreate(
<>
@ -58,12 +57,12 @@ export function DonateOption(props: IProps): React.ReactElement {
function Status(): React.ReactElement {
if (isNaN(donateAmt)) return <></>;
if (!canDonate()) {
if (props.p.money < donateAmt) return <Typography>Insufficient funds</Typography>;
if (Player.money < donateAmt) return <Typography>Insufficient funds</Typography>;
return <Typography>Invalid donate amount entered!</Typography>;
}
return (
<Typography>
This donation will result in <Reputation reputation={repFromDonation(donateAmt, props.p)} /> reputation gain
This donation will result in <Reputation reputation={repFromDonation(donateAmt, Player)} /> reputation gain
</Typography>
);
}

@ -15,7 +15,8 @@ import { CONSTANTS } from "../../Constants";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { Faction } from "../Faction";
import { use } from "../../ui/Context";
import { Router } from "../../ui/GameRoot";
import { Player } from "../../Player";
import { Typography, Button } from "@mui/material";
import { CovenantPurchasesRoot } from "../../PersonObjects/Sleeve/ui/CovenantPurchasesRoot";
@ -58,18 +59,16 @@ interface IMainProps {
}
function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.ReactElement {
const player = use.Player();
const router = use.Router();
const [sleevesOpen, setSleevesOpen] = useState(false);
const factionInfo = faction.getInfo();
function startWork(): void {
player.startFocusing();
router.toWork();
Player.startFocusing();
Router.toWork();
}
function startFieldWork(faction: Faction): void {
player.startWork(
Player.startWork(
new FactionWork({
singularity: false,
faction: faction.name,
@ -80,7 +79,7 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
}
function startHackingContracts(faction: Faction): void {
player.startWork(
Player.startWork(
new FactionWork({
singularity: false,
faction: faction.name,
@ -91,7 +90,7 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
}
function startSecurityWork(faction: Faction): void {
player.startWork(
Player.startWork(
new FactionWork({
singularity: false,
faction: faction.name,
@ -103,18 +102,18 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
// We have a special flag for whether the player this faction is the player's
// gang faction because if the player has a gang, they cannot do any other action
const isPlayersGang = player.inGang() && player.getGangName() === faction.name;
const isPlayersGang = Player.inGang() && Player.getGangName() === faction.name;
// Flags for whether special options (gang, sleeve purchases, donate, etc.)
// should be shown
const favorToDonate = Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction);
const canDonate = faction.favor >= favorToDonate;
const canPurchaseSleeves = faction.name === FactionNames.TheCovenant && player.bitNodeN === 10;
const canPurchaseSleeves = faction.name === FactionNames.TheCovenant && Player.bitNodeN === 10;
return (
<>
<Button onClick={() => router.toFactions()}>Back</Button>
<Button onClick={() => Router.toFactions()}>Back</Button>
<Typography variant="h4" color="primary">
{faction.name}
</Typography>
@ -134,13 +133,7 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
<Option buttonText={"Security Work"} infoText={securityWorkInfo} onClick={() => startSecurityWork(faction)} />
)}
{!isPlayersGang && factionInfo.offersWork() && (
<DonateOption
faction={faction}
p={player}
rerender={rerender}
favorToDonate={favorToDonate}
disabled={!canDonate}
/>
<DonateOption faction={faction} rerender={rerender} favorToDonate={favorToDonate} disabled={!canDonate} />
)}
<Option buttonText={"Purchase Augmentations"} infoText={augmentationsInfo} onClick={onAugmentations} />
{canPurchaseSleeves && (
@ -159,8 +152,6 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
export function FactionRoot(props: IProps): React.ReactElement {
const setRerender = useState(false)[1];
const player = use.Player();
const router = use.Router();
const [purchasingAugs, setPurchasingAugs] = useState(props.augPage);
function rerender(): void {
@ -174,13 +165,13 @@ export function FactionRoot(props: IProps): React.ReactElement {
const faction = props.faction;
if (player && !player.factions.includes(faction.name)) {
if (!Player.factions.includes(faction.name)) {
return (
<>
<Typography variant="h4" color="primary">
You have not joined {faction.name} yet!
</Typography>
<Button onClick={() => router.toFactions()}>Back to Factions</Button>
<Button onClick={() => Router.toFactions()}>Back to Factions</Button>
</>
);
}

@ -1,10 +1,10 @@
import { Explore, Info, LastPage, LocalPolice, NewReleases, Report, SportsMma } from "@mui/icons-material";
import { Box, Button, Container, Paper, Tooltip, Typography, useTheme } from "@mui/material";
import React, { useEffect, useState } from "react";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { Settings } from "../../Settings/Settings";
import { numeralWrapper } from "../../ui/numeralFormat";
import { IRouter } from "../../ui/Router";
import { Router } from "../../ui/GameRoot";
import { FactionNames } from "../data/FactionNames";
import { Faction } from "../Faction";
import { getFactionAugmentationsFiltered, joinFaction } from "../FactionHelpers";
@ -12,10 +12,10 @@ import { Factions } from "../Factions";
export const InvitationsSeen: string[] = [];
const getAugsLeft = (faction: Faction, player: IPlayer): number => {
const augs = getFactionAugmentationsFiltered(player, faction);
const getAugsLeft = (faction: Faction): number => {
const augs = getFactionAugmentationsFiltered(faction);
return augs.filter((augmentation: string) => !player.hasAugmentation(augmentation)).length;
return augs.filter((augmentation: string) => !Player.hasAugmentation(augmentation)).length;
};
interface IWorkTypeProps {
@ -50,8 +50,6 @@ const WorkTypesOffered = (props: IWorkTypeProps): React.ReactElement => {
};
interface IFactionProps {
player: IPlayer;
router: IRouter;
faction: Faction;
joined: boolean;
@ -63,11 +61,11 @@ const FactionElement = (props: IFactionProps): React.ReactElement => {
const facInfo = props.faction.getInfo();
function openFaction(faction: Faction): void {
props.router.toFaction(faction);
Router.toFaction(faction);
}
function openFactionAugPage(faction: Faction): void {
props.router.toFaction(faction, true);
Router.toFaction(faction, true);
}
function acceptInvitation(event: React.MouseEvent<HTMLButtonElement, MouseEvent>, faction: string): void {
@ -124,7 +122,7 @@ const FactionElement = (props: IFactionProps): React.ReactElement => {
</span>
<span style={{ display: "flex", alignItems: "center" }}>
{props.player.hasGangWith(props.faction.name) && (
{Player.hasGangWith(props.faction.name) && (
<Tooltip title="You have a gang with this Faction">
<SportsMma sx={{ color: Settings.theme.hp, ml: 1 }} />
</Tooltip>
@ -157,11 +155,11 @@ const FactionElement = (props: IFactionProps): React.ReactElement => {
</Typography>
<span style={{ display: "flex", alignItems: "center" }}>
{!props.player.hasGangWith(props.faction.name) && <WorkTypesOffered faction={props.faction} />}
{!Player.hasGangWith(props.faction.name) && <WorkTypesOffered faction={props.faction} />}
{props.joined && (
<Typography variant="body2" sx={{ display: "flex" }}>
{getAugsLeft(props.faction, props.player)} Augmentations left
{getAugsLeft(props.faction)} Augmentations left
</Typography>
)}
</span>
@ -182,12 +180,7 @@ const FactionElement = (props: IFactionProps): React.ReactElement => {
);
};
interface IProps {
player: IPlayer;
router: IRouter;
}
export function FactionsRoot(props: IProps): React.ReactElement {
export function FactionsRoot(): React.ReactElement {
const theme = useTheme();
const setRerender = useState(false)[1];
function rerender(): void {
@ -199,16 +192,16 @@ export function FactionsRoot(props: IProps): React.ReactElement {
}, []);
useEffect(() => {
props.player.factionInvitations.forEach((faction) => {
Player.factionInvitations.forEach((faction) => {
if (InvitationsSeen.includes(faction)) return;
InvitationsSeen.push(faction);
});
}, []);
const allFactions = Object.values(FactionNames).map((faction) => faction as string);
const allJoinedFactions = [...props.player.factions];
const allJoinedFactions = [...Player.factions];
allJoinedFactions.sort((a, b) => allFactions.indexOf(a) - allFactions.indexOf(b));
const invitations = props.player.factionInvitations;
const invitations = Player.factionInvitations;
return (
<Container disableGutters maxWidth="lg" sx={{ mx: 0, mb: 10 }}>
@ -249,16 +242,7 @@ export function FactionsRoot(props: IProps): React.ReactElement {
<Box>
{invitations.map((facName) => {
if (!Factions.hasOwnProperty(facName)) return null;
return (
<FactionElement
key={facName}
faction={Factions[facName]}
player={props.player}
router={props.router}
joined={false}
rerender={rerender}
/>
);
return <FactionElement key={facName} faction={Factions[facName]} joined={false} rerender={rerender} />;
})}
</Box>
</span>
@ -272,16 +256,7 @@ export function FactionsRoot(props: IProps): React.ReactElement {
{allJoinedFactions.length > 0 ? (
allJoinedFactions.map((facName) => {
if (!Factions.hasOwnProperty(facName)) return null;
return (
<FactionElement
key={facName}
faction={Factions[facName]}
player={props.player}
router={props.router}
joined={true}
rerender={rerender}
/>
);
return <FactionElement key={facName} faction={Factions[facName]} joined={true} rerender={rerender} />;
})
) : (
<Typography>You have not yet joined any Factions.</Typography>

@ -1,7 +1,5 @@
import { Box, Container, Typography } from "@mui/material";
import React, { useState } from "react";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { IRouter } from "../../ui/Router";
import { GameOptionsTab } from "../GameOptionsTab";
import { GameOptionsSidebar } from "./GameOptionsSidebar";
import { GameplayPage } from "./GameplayPage";
@ -11,8 +9,6 @@ import { RemoteAPIPage } from "./RemoteAPIPage";
import { SystemPage } from "./SystemPage";
interface IProps {
player: IPlayer;
router: IRouter;
save: () => void;
export: () => void;
forceKill: () => void;
@ -29,8 +25,6 @@ export function GameOptionsRoot(props: IProps): React.ReactElement {
<GameOptionsSidebar
tab={currentTab}
setTab={setCurrentTab}
player={props.player}
router={props.router}
save={props.save}
export={props.export}
forceKill={props.forceKill}

@ -13,7 +13,6 @@ import {
import { Box, Button, List, ListItemButton, Paper, Tooltip, Typography } from "@mui/material";
import { default as React, useRef, useState } from "react";
import { FileDiagnosticModal } from "../../Diagnostic/FileDiagnosticModal";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { ImportData, saveObject } from "../../SaveObject";
import { Settings } from "../../Settings/Settings";
import { StyleEditorButton } from "../../Themes/ui/StyleEditorButton";
@ -22,15 +21,13 @@ import { ConfirmationModal } from "../../ui/React/ConfirmationModal";
import { DeleteGameButton } from "../../ui/React/DeleteGameButton";
import { SnackbarEvents, ToastVariant } from "../../ui/React/Snackbar";
import { SoftResetButton } from "../../ui/React/SoftResetButton";
import { IRouter } from "../../ui/Router";
import { Router } from "../../ui/GameRoot";
import { convertTimeMsToTimeElapsedString } from "../../utils/StringHelperFunctions";
import { GameOptionsTab } from "../GameOptionsTab";
interface IProps {
tab: GameOptionsTab;
setTab: (tab: GameOptionsTab) => void;
player: IPlayer;
router: IRouter;
save: () => void;
export: () => void;
forceKill: () => void;
@ -94,7 +91,7 @@ export const GameOptionsSidebar = (props: IProps): React.ReactElement => {
function compareSaveGame(): void {
if (!importData) return;
props.router.toImportSave(importData.base64);
Router.toImportSave(importData.base64);
setImportSaveOpen(false);
setImportData(null);
}
@ -219,12 +216,12 @@ export const GameOptionsSidebar = (props: IProps): React.ReactElement => {
</Button>
</Tooltip>
<Tooltip title="Head to the theme browser to see a collection of prebuilt themes.">
<Button startIcon={<Palette />} onClick={() => props.router.toThemeBrowser()} sx={{ gridArea: "browse" }}>
<Button startIcon={<Palette />} onClick={() => Router.toThemeBrowser()} sx={{ gridArea: "browse" }}>
Theme Browser
</Button>
</Tooltip>
<Box sx={{ gridArea: "theme", "& .MuiButton-root": { height: "100%", width: "100%" } }}>
<ThemeEditorButton router={props.router} />
<ThemeEditorButton />
</Box>
<Box sx={{ gridArea: "style", "& .MuiButton-root": { height: "100%", width: "100%" } }}>
<StyleEditorButton />

@ -1,21 +1,21 @@
import { BitNodeMultipliers } from "./BitNode/BitNodeMultipliers";
import { IPlayer } from "./PersonObjects/IPlayer";
import { IPerson } from "./PersonObjects/IPerson";
import { calculateIntelligenceBonus } from "./PersonObjects/formulas/intelligence";
import { Server } from "./Server/Server";
/**
* Returns the chance the player has to successfully hack a server
* Returns the chance the person has to successfully hack a server
*/
export function calculateHackingChance(server: Server, player: IPlayer): number {
export function calculateHackingChance(server: Server, person: IPerson): number {
const hackFactor = 1.75;
const difficultyMult = (100 - server.hackDifficulty) / 100;
const skillMult = hackFactor * player.skills.hacking;
const skillMult = hackFactor * person.skills.hacking;
const skillChance = (skillMult - server.requiredHackingSkill) / skillMult;
const chance =
skillChance *
difficultyMult *
player.mults.hacking_chance *
calculateIntelligenceBonus(player.skills.intelligence, 1);
person.mults.hacking_chance *
calculateIntelligenceBonus(person.skills.intelligence, 1);
if (chance > 1) {
return 1;
}
@ -27,10 +27,10 @@ export function calculateHackingChance(server: Server, player: IPlayer): number
}
/**
* Returns the amount of hacking experience the player will gain upon
* Returns the amount of hacking experience the person will gain upon
* successfully hacking a server
*/
export function calculateHackingExpGain(server: Server, player: IPlayer): number {
export function calculateHackingExpGain(server: Server, person: IPerson): number {
const baseExpGain = 3;
const diffFactor = 0.3;
if (server.baseDifficulty == null) {
@ -39,21 +39,21 @@ export function calculateHackingExpGain(server: Server, player: IPlayer): number
let expGain = baseExpGain;
expGain += server.baseDifficulty * diffFactor;
return expGain * player.mults.hacking_exp * BitNodeMultipliers.HackExpGain;
return expGain * person.mults.hacking_exp * BitNodeMultipliers.HackExpGain;
}
/**
* Returns the percentage of money that will be stolen from a server if
* it is successfully hacked (returns the decimal form, not the actual percent value)
*/
export function calculatePercentMoneyHacked(server: Server, player: IPlayer): number {
export function calculatePercentMoneyHacked(server: Server, person: IPerson): number {
// Adjust if needed for balancing. This is the divisor for the final calculation
const balanceFactor = 240;
const difficultyMult = (100 - server.hackDifficulty) / 100;
const skillMult = (player.skills.hacking - (server.requiredHackingSkill - 1)) / player.skills.hacking;
const skillMult = (person.skills.hacking - (server.requiredHackingSkill - 1)) / person.skills.hacking;
const percentMoneyHacked =
(difficultyMult * skillMult * player.mults.hacking_money * BitNodeMultipliers.ScriptHackMoney) / balanceFactor;
(difficultyMult * skillMult * person.mults.hacking_money * BitNodeMultipliers.ScriptHackMoney) / balanceFactor;
if (percentMoneyHacked < 0) {
return 0;
}
@ -67,7 +67,7 @@ export function calculatePercentMoneyHacked(server: Server, player: IPlayer): nu
/**
* Returns time it takes to complete a hack on a server, in seconds
*/
export function calculateHackingTime(server: Server, player: IPlayer): number {
export function calculateHackingTime(server: Server, person: IPerson): number {
const difficultyMult = server.requiredHackingSkill * server.hackDifficulty;
const baseDiff = 500;
@ -75,12 +75,12 @@ export function calculateHackingTime(server: Server, player: IPlayer): number {
const diffFactor = 2.5;
let skillFactor = diffFactor * difficultyMult + baseDiff;
// tslint:disable-next-line
skillFactor /= player.skills.hacking + baseSkill;
skillFactor /= person.skills.hacking + baseSkill;
const hackTimeMultiplier = 5;
const hackingTime =
(hackTimeMultiplier * skillFactor) /
(player.mults.hacking_speed * calculateIntelligenceBonus(player.skills.intelligence, 1));
(person.mults.hacking_speed * calculateIntelligenceBonus(person.skills.intelligence, 1));
return hackingTime;
}
@ -88,17 +88,17 @@ export function calculateHackingTime(server: Server, player: IPlayer): number {
/**
* Returns time it takes to complete a grow operation on a server, in seconds
*/
export function calculateGrowTime(server: Server, player: IPlayer): number {
export function calculateGrowTime(server: Server, person: IPerson): number {
const growTimeMultiplier = 3.2; // Relative to hacking time. 16/5 = 3.2
return growTimeMultiplier * calculateHackingTime(server, player);
return growTimeMultiplier * calculateHackingTime(server, person);
}
/**
* Returns time it takes to complete a weaken operation on a server, in seconds
*/
export function calculateWeakenTime(server: Server, player: IPlayer): number {
export function calculateWeakenTime(server: Server, person: IPerson): number {
const weakenTimeMultiplier = 4; // Relative to hacking time
return weakenTimeMultiplier * calculateHackingTime(server, player);
return weakenTimeMultiplier * calculateHackingTime(server, person);
}

@ -6,7 +6,7 @@
*/
import { IReturnStatus } from "../types";
import { IPlayer } from "../PersonObjects/IPlayer";
import { Player } from "../Player";
import { Server } from "../Server/Server";
function baseCheck(server: Server, fnName: string): IReturnStatus {
@ -29,14 +29,14 @@ function baseCheck(server: Server, fnName: string): IReturnStatus {
return { res: true };
}
export function netscriptCanHack(server: Server, p: IPlayer): IReturnStatus {
export function netscriptCanHack(server: Server): IReturnStatus {
const initialCheck = baseCheck(server, "hack");
if (!initialCheck.res) {
return initialCheck;
}
const s = server;
if (s.requiredHackingSkill > p.skills.hacking) {
if (s.requiredHackingSkill > Player.skills.hacking) {
return {
res: false,
msg: `Cannot hack ${server.hostname} server because your hacking skill is not high enough`,

@ -18,17 +18,17 @@ import { HashUpgrades } from "./HashUpgrades";
import { generateRandomContract } from "../CodingContractGenerator";
import { iTutorialSteps, iTutorialNextStep, ITutorial } from "../InteractiveTutorial";
import { IPlayer } from "../PersonObjects/IPlayer";
import { Player } from "../Player";
import { GetServer } from "../Server/AllServers";
import { Server } from "../Server/Server";
// Returns a boolean indicating whether the player has Hacknet Servers
// (the upgraded form of Hacknet Nodes)
export function hasHacknetServers(player: IPlayer): boolean {
return player.bitNodeN === 9 || player.sourceFileLvl(9) > 0;
export function hasHacknetServers(): boolean {
return Player.bitNodeN === 9 || Player.sourceFileLvl(9) > 0;
}
export function purchaseHacknet(player: IPlayer): number {
export function purchaseHacknet(): number {
/* INTERACTIVE TUTORIAL */
if (ITutorial.isRunning) {
if (ITutorial.currStep === iTutorialSteps.HacknetNodesIntroduction) {
@ -39,72 +39,68 @@ export function purchaseHacknet(player: IPlayer): number {
}
/* END INTERACTIVE TUTORIAL */
const numOwned = player.hacknetNodes.length;
if (hasHacknetServers(player)) {
const cost = getCostOfNextHacknetServer(player);
const numOwned = Player.hacknetNodes.length;
if (hasHacknetServers()) {
const cost = getCostOfNextHacknetServer();
if (isNaN(cost)) {
throw new Error(`Calculated cost of purchasing HacknetServer is NaN`);
}
if (!player.canAfford(cost) || numOwned >= HacknetServerConstants.MaxServers) {
if (!Player.canAfford(cost) || numOwned >= HacknetServerConstants.MaxServers) {
return -1;
}
player.loseMoney(cost, "hacknet_expenses");
player.createHacknetServer();
updateHashManagerCapacity(player);
Player.loseMoney(cost, "hacknet_expenses");
Player.createHacknetServer();
updateHashManagerCapacity();
return numOwned;
} else {
const cost = getCostOfNextHacknetNode(player);
const cost = getCostOfNextHacknetNode();
if (isNaN(cost)) {
throw new Error(`Calculated cost of purchasing HacknetNode is NaN`);
}
if (!player.canAfford(cost)) {
if (!Player.canAfford(cost)) {
return -1;
}
// Auto generate a name for the Node
const name = "hacknet-node-" + numOwned;
const node = new HacknetNode(name, player.mults.hacknet_node_money);
const node = new HacknetNode(name, Player.mults.hacknet_node_money);
player.loseMoney(cost, "hacknet_expenses");
player.hacknetNodes.push(node);
Player.loseMoney(cost, "hacknet_expenses");
Player.hacknetNodes.push(node);
return numOwned;
}
}
export function hasMaxNumberHacknetServers(player: IPlayer): boolean {
return hasHacknetServers(player) && player.hacknetNodes.length >= HacknetServerConstants.MaxServers;
export function hasMaxNumberHacknetServers(): boolean {
return hasHacknetServers() && Player.hacknetNodes.length >= HacknetServerConstants.MaxServers;
}
export function getCostOfNextHacknetNode(player: IPlayer): number {
return calculateNodeCost(player.hacknetNodes.length + 1, player.mults.hacknet_node_purchase_cost);
export function getCostOfNextHacknetNode(): number {
return calculateNodeCost(Player.hacknetNodes.length + 1, Player.mults.hacknet_node_purchase_cost);
}
export function getCostOfNextHacknetServer(player: IPlayer): number {
return calculateServerCost(player.hacknetNodes.length + 1, player.mults.hacknet_node_purchase_cost);
export function getCostOfNextHacknetServer(): number {
return calculateServerCost(Player.hacknetNodes.length + 1, Player.mults.hacknet_node_purchase_cost);
}
// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's level
export function getMaxNumberLevelUpgrades(
player: IPlayer,
nodeObj: HacknetNode | HacknetServer,
maxLevel: number,
): number {
export function getMaxNumberLevelUpgrades(nodeObj: HacknetNode | HacknetServer, maxLevel: number): number {
if (maxLevel == null) {
throw new Error(`getMaxNumberLevelUpgrades() called without maxLevel arg`);
}
if (player.money < nodeObj.calculateLevelUpgradeCost(1, player.mults.hacknet_node_level_cost)) {
if (Player.money < nodeObj.calculateLevelUpgradeCost(1, Player.mults.hacknet_node_level_cost)) {
return 0;
}
let min = 1;
let max = maxLevel - 1;
const levelsToMax = maxLevel - nodeObj.level;
if (player.money > nodeObj.calculateLevelUpgradeCost(levelsToMax, player.mults.hacknet_node_level_cost)) {
if (Player.money > nodeObj.calculateLevelUpgradeCost(levelsToMax, Player.mults.hacknet_node_level_cost)) {
return levelsToMax;
}
@ -112,13 +108,13 @@ export function getMaxNumberLevelUpgrades(
const curr = ((min + max) / 2) | 0;
if (
curr !== maxLevel &&
player.money > nodeObj.calculateLevelUpgradeCost(curr, player.mults.hacknet_node_level_cost) &&
player.money < nodeObj.calculateLevelUpgradeCost(curr + 1, player.mults.hacknet_node_level_cost)
Player.money > nodeObj.calculateLevelUpgradeCost(curr, Player.mults.hacknet_node_level_cost) &&
Player.money < nodeObj.calculateLevelUpgradeCost(curr + 1, Player.mults.hacknet_node_level_cost)
) {
return Math.min(levelsToMax, curr);
} else if (player.money < nodeObj.calculateLevelUpgradeCost(curr, player.mults.hacknet_node_level_cost)) {
} else if (Player.money < nodeObj.calculateLevelUpgradeCost(curr, Player.mults.hacknet_node_level_cost)) {
max = curr - 1;
} else if (player.money > nodeObj.calculateLevelUpgradeCost(curr, player.mults.hacknet_node_level_cost)) {
} else if (Player.money > nodeObj.calculateLevelUpgradeCost(curr, Player.mults.hacknet_node_level_cost)) {
min = curr + 1;
} else {
return Math.min(levelsToMax, curr);
@ -128,16 +124,12 @@ export function getMaxNumberLevelUpgrades(
}
// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's RAM
export function getMaxNumberRamUpgrades(
player: IPlayer,
nodeObj: HacknetNode | HacknetServer,
maxLevel: number,
): number {
export function getMaxNumberRamUpgrades(nodeObj: HacknetNode | HacknetServer, maxLevel: number): number {
if (maxLevel == null) {
throw new Error(`getMaxNumberRamUpgrades() called without maxLevel arg`);
}
if (player.money < nodeObj.calculateRamUpgradeCost(1, player.mults.hacknet_node_ram_cost)) {
if (Player.money < nodeObj.calculateRamUpgradeCost(1, Player.mults.hacknet_node_ram_cost)) {
return 0;
}
@ -147,13 +139,13 @@ export function getMaxNumberRamUpgrades(
} else {
levelsToMax = Math.round(Math.log2(maxLevel / nodeObj.ram));
}
if (player.money > nodeObj.calculateRamUpgradeCost(levelsToMax, player.mults.hacknet_node_ram_cost)) {
if (Player.money > nodeObj.calculateRamUpgradeCost(levelsToMax, Player.mults.hacknet_node_ram_cost)) {
return levelsToMax;
}
//We'll just loop until we find the max
for (let i = levelsToMax - 1; i >= 0; --i) {
if (player.money > nodeObj.calculateRamUpgradeCost(i, player.mults.hacknet_node_ram_cost)) {
if (Player.money > nodeObj.calculateRamUpgradeCost(i, Player.mults.hacknet_node_ram_cost)) {
return i;
}
}
@ -162,7 +154,6 @@ export function getMaxNumberRamUpgrades(
// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's cores
export function getMaxNumberCoreUpgrades(
player: IPlayer,
nodeObj: HacknetNode | HacknetServer,
maxLevel: number,
): number {
@ -170,14 +161,14 @@ export function getMaxNumberCoreUpgrades(
throw new Error(`getMaxNumberCoreUpgrades() called without maxLevel arg`);
}
if (player.money < nodeObj.calculateCoreUpgradeCost(1, player.mults.hacknet_node_core_cost)) {
if (Player.money < nodeObj.calculateCoreUpgradeCost(1, Player.mults.hacknet_node_core_cost)) {
return 0;
}
let min = 1;
let max = maxLevel - 1;
const levelsToMax = maxLevel - nodeObj.cores;
if (player.money > nodeObj.calculateCoreUpgradeCost(levelsToMax, player.mults.hacknet_node_core_cost)) {
if (Player.money > nodeObj.calculateCoreUpgradeCost(levelsToMax, Player.mults.hacknet_node_core_cost)) {
return levelsToMax;
}
@ -186,13 +177,13 @@ export function getMaxNumberCoreUpgrades(
const curr = ((min + max) / 2) | 0;
if (
curr != maxLevel &&
player.money > nodeObj.calculateCoreUpgradeCost(curr, player.mults.hacknet_node_core_cost) &&
player.money < nodeObj.calculateCoreUpgradeCost(curr + 1, player.mults.hacknet_node_core_cost)
Player.money > nodeObj.calculateCoreUpgradeCost(curr, Player.mults.hacknet_node_core_cost) &&
Player.money < nodeObj.calculateCoreUpgradeCost(curr + 1, Player.mults.hacknet_node_core_cost)
) {
return Math.min(levelsToMax, curr);
} else if (player.money < nodeObj.calculateCoreUpgradeCost(curr, player.mults.hacknet_node_core_cost)) {
} else if (Player.money < nodeObj.calculateCoreUpgradeCost(curr, Player.mults.hacknet_node_core_cost)) {
max = curr - 1;
} else if (player.money > nodeObj.calculateCoreUpgradeCost(curr, player.mults.hacknet_node_core_cost)) {
} else if (Player.money > nodeObj.calculateCoreUpgradeCost(curr, Player.mults.hacknet_node_core_cost)) {
min = curr + 1;
} else {
return Math.min(levelsToMax, curr);
@ -203,19 +194,19 @@ export function getMaxNumberCoreUpgrades(
}
// Calculate the maximum number of times the Player can afford to upgrade a Hacknet Node's cache
export function getMaxNumberCacheUpgrades(player: IPlayer, nodeObj: HacknetServer, maxLevel: number): number {
export function getMaxNumberCacheUpgrades(nodeObj: HacknetServer, maxLevel: number): number {
if (maxLevel == null) {
throw new Error(`getMaxNumberCacheUpgrades() called without maxLevel arg`);
}
if (!player.canAfford(nodeObj.calculateCacheUpgradeCost(1))) {
if (!Player.canAfford(nodeObj.calculateCacheUpgradeCost(1))) {
return 0;
}
let min = 1;
let max = maxLevel - 1;
const levelsToMax = maxLevel - nodeObj.cache;
if (player.canAfford(nodeObj.calculateCacheUpgradeCost(levelsToMax))) {
if (Player.canAfford(nodeObj.calculateCacheUpgradeCost(levelsToMax))) {
return levelsToMax;
}
@ -224,13 +215,13 @@ export function getMaxNumberCacheUpgrades(player: IPlayer, nodeObj: HacknetServe
const curr = ((min + max) / 2) | 0;
if (
curr != maxLevel &&
player.canAfford(nodeObj.calculateCacheUpgradeCost(curr)) &&
!player.canAfford(nodeObj.calculateCacheUpgradeCost(curr + 1))
Player.canAfford(nodeObj.calculateCacheUpgradeCost(curr)) &&
!Player.canAfford(nodeObj.calculateCacheUpgradeCost(curr + 1))
) {
return Math.min(levelsToMax, curr);
} else if (!player.canAfford(nodeObj.calculateCacheUpgradeCost(curr))) {
} else if (!Player.canAfford(nodeObj.calculateCacheUpgradeCost(curr))) {
max = curr - 1;
} else if (player.canAfford(nodeObj.calculateCacheUpgradeCost(curr))) {
} else if (Player.canAfford(nodeObj.calculateCacheUpgradeCost(curr))) {
min = curr + 1;
} else {
return Math.min(levelsToMax, curr);
@ -240,9 +231,9 @@ export function getMaxNumberCacheUpgrades(player: IPlayer, nodeObj: HacknetServe
return 0;
}
export function purchaseLevelUpgrade(player: IPlayer, node: HacknetNode | HacknetServer, levels = 1): boolean {
export function purchaseLevelUpgrade(node: HacknetNode | HacknetServer, levels = 1): boolean {
const sanitizedLevels = Math.round(levels);
const cost = node.calculateLevelUpgradeCost(sanitizedLevels, player.mults.hacknet_node_level_cost);
const cost = node.calculateLevelUpgradeCost(sanitizedLevels, Player.mults.hacknet_node_level_cost);
if (isNaN(cost) || cost <= 0 || sanitizedLevels < 0) {
return false;
}
@ -258,22 +249,22 @@ export function purchaseLevelUpgrade(player: IPlayer, node: HacknetNode | Hackne
// the maximum number of upgrades and use that
if (node.level + sanitizedLevels > (isServer ? HacknetServerConstants.MaxLevel : HacknetNodeConstants.MaxLevel)) {
const diff = Math.max(0, (isServer ? HacknetServerConstants.MaxLevel : HacknetNodeConstants.MaxLevel) - node.level);
return purchaseLevelUpgrade(player, node, diff);
return purchaseLevelUpgrade(node, diff);
}
if (!player.canAfford(cost)) {
if (!Player.canAfford(cost)) {
return false;
}
player.loseMoney(cost, "hacknet_expenses");
node.upgradeLevel(sanitizedLevels, player.mults.hacknet_node_money);
Player.loseMoney(cost, "hacknet_expenses");
node.upgradeLevel(sanitizedLevels, Player.mults.hacknet_node_money);
return true;
}
export function purchaseRamUpgrade(player: IPlayer, node: HacknetNode | HacknetServer, levels = 1): boolean {
export function purchaseRamUpgrade(node: HacknetNode | HacknetServer, levels = 1): boolean {
const sanitizedLevels = Math.round(levels);
const cost = node.calculateRamUpgradeCost(sanitizedLevels, player.mults.hacknet_node_ram_cost);
const cost = node.calculateRamUpgradeCost(sanitizedLevels, Player.mults.hacknet_node_ram_cost);
if (isNaN(cost) || cost <= 0 || sanitizedLevels < 0) {
return false;
}
@ -291,28 +282,28 @@ export function purchaseRamUpgrade(player: IPlayer, node: HacknetNode | HacknetS
if (node instanceof HacknetServer) {
if (node.maxRam * Math.pow(2, sanitizedLevels) > HacknetServerConstants.MaxRam) {
const diff = Math.max(0, Math.log2(Math.round(HacknetServerConstants.MaxRam / node.maxRam)));
return purchaseRamUpgrade(player, node, diff);
return purchaseRamUpgrade(node, diff);
}
} else if (node instanceof HacknetNode) {
if (node.ram * Math.pow(2, sanitizedLevels) > HacknetNodeConstants.MaxRam) {
const diff = Math.max(0, Math.log2(Math.round(HacknetNodeConstants.MaxRam / node.ram)));
return purchaseRamUpgrade(player, node, diff);
return purchaseRamUpgrade(node, diff);
}
}
if (!player.canAfford(cost)) {
if (!Player.canAfford(cost)) {
return false;
}
player.loseMoney(cost, "hacknet_expenses");
node.upgradeRam(sanitizedLevels, player.mults.hacknet_node_money);
Player.loseMoney(cost, "hacknet_expenses");
node.upgradeRam(sanitizedLevels, Player.mults.hacknet_node_money);
return true;
}
export function purchaseCoreUpgrade(player: IPlayer, node: HacknetNode | HacknetServer, levels = 1): boolean {
export function purchaseCoreUpgrade(node: HacknetNode | HacknetServer, levels = 1): boolean {
const sanitizedLevels = Math.round(levels);
const cost = node.calculateCoreUpgradeCost(sanitizedLevels, player.mults.hacknet_node_core_cost);
const cost = node.calculateCoreUpgradeCost(sanitizedLevels, Player.mults.hacknet_node_core_cost);
if (isNaN(cost) || cost <= 0 || sanitizedLevels < 0) {
return false;
}
@ -328,20 +319,20 @@ export function purchaseCoreUpgrade(player: IPlayer, node: HacknetNode | Hacknet
// the max possible number of upgrades and use that
if (node.cores + sanitizedLevels > (isServer ? HacknetServerConstants.MaxCores : HacknetNodeConstants.MaxCores)) {
const diff = Math.max(0, (isServer ? HacknetServerConstants.MaxCores : HacknetNodeConstants.MaxCores) - node.cores);
return purchaseCoreUpgrade(player, node, diff);
return purchaseCoreUpgrade(node, diff);
}
if (!player.canAfford(cost)) {
if (!Player.canAfford(cost)) {
return false;
}
player.loseMoney(cost, "hacknet_expenses");
node.upgradeCore(sanitizedLevels, player.mults.hacknet_node_money);
Player.loseMoney(cost, "hacknet_expenses");
node.upgradeCore(sanitizedLevels, Player.mults.hacknet_node_money);
return true;
}
export function purchaseCacheUpgrade(player: IPlayer, node: HacknetServer, levels = 1): boolean {
export function purchaseCacheUpgrade(node: HacknetServer, levels = 1): boolean {
const sanitizedLevels = Math.round(levels);
const cost = node.calculateCacheUpgradeCost(sanitizedLevels);
if (isNaN(cost) || cost <= 0 || sanitizedLevels < 0) {
@ -356,71 +347,71 @@ export function purchaseCacheUpgrade(player: IPlayer, node: HacknetServer, level
// Fail if we're already at max
if (node.cache + sanitizedLevels > HacknetServerConstants.MaxCache) {
const diff = Math.max(0, HacknetServerConstants.MaxCache - node.cache);
return purchaseCacheUpgrade(player, node, diff);
return purchaseCacheUpgrade(node, diff);
}
if (!player.canAfford(cost)) {
if (!Player.canAfford(cost)) {
return false;
}
player.loseMoney(cost, "hacknet_expenses");
Player.loseMoney(cost, "hacknet_expenses");
node.upgradeCache(sanitizedLevels);
return true;
}
export function processHacknetEarnings(player: IPlayer, numCycles: number): number {
export function processHacknetEarnings(numCycles: number): number {
// Determine if player has Hacknet Nodes or Hacknet Servers, then
// call the appropriate function
if (player.hacknetNodes.length === 0) {
if (Player.hacknetNodes.length === 0) {
return 0;
}
if (hasHacknetServers(player)) {
return processAllHacknetServerEarnings(player, numCycles);
} else if (player.hacknetNodes[0] instanceof HacknetNode) {
return processAllHacknetNodeEarnings(player, numCycles);
if (hasHacknetServers()) {
return processAllHacknetServerEarnings(numCycles);
} else if (Player.hacknetNodes[0] instanceof HacknetNode) {
return processAllHacknetNodeEarnings(numCycles);
} else {
return 0;
}
}
function processAllHacknetNodeEarnings(player: IPlayer, numCycles: number): number {
function processAllHacknetNodeEarnings(numCycles: number): number {
let total = 0;
for (let i = 0; i < player.hacknetNodes.length; ++i) {
const node = player.hacknetNodes[i];
for (let i = 0; i < Player.hacknetNodes.length; ++i) {
const node = Player.hacknetNodes[i];
if (typeof node === "string") throw new Error("player node should not be ip string");
total += processSingleHacknetNodeEarnings(player, numCycles, node);
total += processSingleHacknetNodeEarnings(numCycles, node);
}
return total;
}
function processSingleHacknetNodeEarnings(player: IPlayer, numCycles: number, nodeObj: HacknetNode): number {
function processSingleHacknetNodeEarnings(numCycles: number, nodeObj: HacknetNode): number {
const totalEarnings = nodeObj.process(numCycles);
player.gainMoney(totalEarnings, "hacknet");
Player.gainMoney(totalEarnings, "hacknet");
return totalEarnings;
}
function processAllHacknetServerEarnings(player: IPlayer, numCycles: number): number {
if (!(player.hashManager instanceof HashManager)) {
function processAllHacknetServerEarnings(numCycles: number): number {
if (!(Player.hashManager instanceof HashManager)) {
throw new Error(`Player does not have a HashManager (should be in 'hashManager' prop)`);
}
let hashes = 0;
for (let i = 0; i < player.hacknetNodes.length; ++i) {
for (let i = 0; i < Player.hacknetNodes.length; ++i) {
// hacknetNodes array only contains the IP addresses of the servers.
// Also, update the hash rate before processing
const ip = player.hacknetNodes[i];
const ip = Player.hacknetNodes[i];
if (ip instanceof HacknetNode) throw new Error(`player nodes should not be HacketNode`);
const hserver = GetServer(ip);
if (!(hserver instanceof HacknetServer)) throw new Error(`player nodes shoud not be Server`);
hserver.updateHashRate(player.mults.hacknet_node_money);
hserver.updateHashRate(Player.mults.hacknet_node_money);
const h = hserver.process(numCycles);
hashes += h;
}
const wastedHashes = player.hashManager.storeHashes(hashes);
const wastedHashes = Player.hashManager.storeHashes(hashes);
if (wastedHashes > 0) {
const upgrade = HashUpgrades["Sell for Money"];
if (upgrade === null) throw new Error("Could not get the hash upgrade");
@ -428,65 +419,65 @@ function processAllHacknetServerEarnings(player: IPlayer, numCycles: number): nu
const multiplier = wastedHashes / upgrade.cost;
if (multiplier > 0) {
player.gainMoney(upgrade.value * multiplier, "hacknet");
Player.gainMoney(upgrade.value * multiplier, "hacknet");
}
}
return hashes;
}
export function updateHashManagerCapacity(player: IPlayer): void {
if (!(player.hashManager instanceof HashManager)) {
export function updateHashManagerCapacity(): void {
if (!(Player.hashManager instanceof HashManager)) {
console.error(`Player does not have a HashManager`);
return;
}
const nodes = player.hacknetNodes;
const nodes = Player.hacknetNodes;
if (nodes.length === 0) {
player.hashManager.updateCapacity(0);
Player.hashManager.updateCapacity(0);
return;
}
let total = 0;
for (let i = 0; i < nodes.length; ++i) {
if (typeof nodes[i] !== "string") {
player.hashManager.updateCapacity(0);
Player.hashManager.updateCapacity(0);
return;
}
const ip = nodes[i];
if (ip instanceof HacknetNode) throw new Error(`player nodes should be string but isn't`);
const h = GetServer(ip);
if (!(h instanceof HacknetServer)) {
player.hashManager.updateCapacity(0);
Player.hashManager.updateCapacity(0);
return;
}
total += h.hashCapacity;
}
player.hashManager.updateCapacity(total);
Player.hashManager.updateCapacity(total);
}
export function purchaseHashUpgrade(player: IPlayer, upgName: string, upgTarget: string, count = 1): boolean {
if (!(player.hashManager instanceof HashManager)) {
export function purchaseHashUpgrade(upgName: string, upgTarget: string, count = 1): boolean {
if (!(Player.hashManager instanceof HashManager)) {
console.error(`Player does not have a HashManager`);
return false;
}
// HashManager handles the transaction. This just needs to actually implement
// the effects of the upgrade
if (player.hashManager.upgrade(upgName, count)) {
if (Player.hashManager.upgrade(upgName, count)) {
const upg = HashUpgrades[upgName];
switch (upgName) {
case "Sell for Money": {
player.gainMoney(upg.value * count, "hacknet");
Player.gainMoney(upg.value * count, "hacknet");
break;
}
case "Sell for Corporation Funds": {
const corp = player.corporation;
const corp = Player.corporation;
if (corp === null) {
player.hashManager.refundUpgrade(upgName, count);
Player.hashManager.refundUpgrade(upgName, count);
return false;
}
corp.funds = corp.funds + upg.value * count;
@ -503,7 +494,7 @@ export function purchaseHashUpgrade(player: IPlayer, upgName: string, upgTarget:
target.changeMinimumSecurity(upg.value ** count, true);
} catch (e) {
player.hashManager.refundUpgrade(upgName, count);
Player.hashManager.refundUpgrade(upgName, count);
return false;
}
break;
@ -522,7 +513,7 @@ export function purchaseHashUpgrade(player: IPlayer, upgName: string, upgTarget:
target.changeMaximumMoney(upg.value);
}
} catch (e) {
player.hashManager.refundUpgrade(upgName, count);
Player.hashManager.refundUpgrade(upgName, count);
return false;
}
break;
@ -537,9 +528,9 @@ export function purchaseHashUpgrade(player: IPlayer, upgName: string, upgTarget:
}
case "Exchange for Corporation Research": {
// This will throw if player doesn't have a corporation
const corp = player.corporation;
const corp = Player.corporation;
if (corp === null) {
player.hashManager.refundUpgrade(upgName, count);
Player.hashManager.refundUpgrade(upgName, count);
return false;
}
for (const division of corp.divisions) {
@ -549,19 +540,19 @@ export function purchaseHashUpgrade(player: IPlayer, upgName: string, upgTarget:
}
case "Exchange for Bladeburner Rank": {
// This will throw if player isnt in Bladeburner
const bladeburner = player.bladeburner;
const bladeburner = Player.bladeburner;
if (bladeburner === null) {
player.hashManager.refundUpgrade(upgName, count);
Player.hashManager.refundUpgrade(upgName, count);
return false;
}
bladeburner.changeRank(player, upg.value * count);
bladeburner.changeRank(Player, upg.value * count);
break;
}
case "Exchange for Bladeburner SP": {
// This will throw if player isnt in Bladeburner
const bladeburner = player.bladeburner;
const bladeburner = Player.bladeburner;
if (bladeburner === null) {
player.hashManager.refundUpgrade(upgName, count);
Player.hashManager.refundUpgrade(upgName, count);
return false;
}

@ -14,7 +14,7 @@ import {
purchaseCoreUpgrade,
} from "../HacknetHelpers";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { HacknetNode } from "../HacknetNode";
import { Money } from "../../ui/React/Money";
@ -36,7 +36,6 @@ interface IProps {
node: HacknetNode;
purchaseMultiplier: number | "MAX";
rerender: () => void;
player: IPlayer;
}
export function HacknetNodeElem(props: IProps): React.ReactElement {
@ -51,16 +50,16 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
} else {
let multiplier = 0;
if (purchaseMult === "MAX") {
multiplier = getMaxNumberLevelUpgrades(props.player, node, HacknetNodeConstants.MaxLevel);
multiplier = getMaxNumberLevelUpgrades(node, HacknetNodeConstants.MaxLevel);
} else {
const levelsToMax = HacknetNodeConstants.MaxLevel - node.level;
multiplier = Math.min(levelsToMax, purchaseMult);
}
const increase =
calculateMoneyGainRate(node.level + multiplier, node.ram, node.cores, props.player.mults.hacknet_node_money) -
calculateMoneyGainRate(node.level + multiplier, node.ram, node.cores, Player.mults.hacknet_node_money) -
node.moneyGainRatePerSecond;
const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, props.player.mults.hacknet_node_level_cost);
const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, Player.mults.hacknet_node_level_cost);
upgradeLevelButton = (
<Tooltip
title={
@ -71,7 +70,7 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
>
<Button onClick={upgradeLevelOnClick}>
+{multiplier} -&nbsp;
<Money money={upgradeLevelCost} player={props.player} />
<Money money={upgradeLevelCost} forPurchase={true} />
</Button>
</Tooltip>
);
@ -79,9 +78,9 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
function upgradeLevelOnClick(): void {
const numUpgrades =
purchaseMult === "MAX"
? getMaxNumberLevelUpgrades(props.player, node, HacknetNodeConstants.MaxLevel)
? getMaxNumberLevelUpgrades(node, HacknetNodeConstants.MaxLevel)
: purchaseMult;
purchaseLevelUpgrade(props.player, node, numUpgrades);
purchaseLevelUpgrade(node, numUpgrades);
rerender();
}
@ -91,7 +90,7 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
} else {
let multiplier = 0;
if (purchaseMult === "MAX") {
multiplier = getMaxNumberRamUpgrades(props.player, node, HacknetNodeConstants.MaxRam);
multiplier = getMaxNumberRamUpgrades(node, HacknetNodeConstants.MaxRam);
} else {
const levelsToMax = Math.round(Math.log2(HacknetNodeConstants.MaxRam / node.ram));
multiplier = Math.min(levelsToMax, purchaseMult);
@ -102,9 +101,9 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
node.level,
node.ram * Math.pow(2, multiplier),
node.cores,
props.player.mults.hacknet_node_money,
Player.mults.hacknet_node_money,
) - node.moneyGainRatePerSecond;
const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, props.player.mults.hacknet_node_ram_cost);
const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, Player.mults.hacknet_node_ram_cost);
upgradeRAMButton = (
<Tooltip
title={
@ -115,24 +114,24 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
>
<Button onClick={upgradeRamOnClick}>
+{multiplier} -&nbsp;
<Money money={upgradeRamCost} player={props.player} />
<Money money={upgradeRamCost} forPurchase={true} />
</Button>
</Tooltip>
);
}
function upgradeRamOnClick(): void {
const numUpgrades =
purchaseMult === "MAX" ? getMaxNumberRamUpgrades(props.player, node, HacknetNodeConstants.MaxRam) : purchaseMult;
purchaseRamUpgrade(props.player, node, numUpgrades);
purchaseMult === "MAX" ? getMaxNumberRamUpgrades(node, HacknetNodeConstants.MaxRam) : purchaseMult;
purchaseRamUpgrade(node, numUpgrades);
rerender();
}
function upgradeCoresOnClick(): void {
const numUpgrades =
purchaseMult === "MAX"
? getMaxNumberCoreUpgrades(props.player, node, HacknetNodeConstants.MaxCores)
? getMaxNumberCoreUpgrades(node, HacknetNodeConstants.MaxCores)
: purchaseMult;
purchaseCoreUpgrade(props.player, node, numUpgrades);
purchaseCoreUpgrade(node, numUpgrades);
rerender();
}
let upgradeCoresButton;
@ -141,16 +140,16 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
} else {
let multiplier = 0;
if (purchaseMult === "MAX") {
multiplier = getMaxNumberCoreUpgrades(props.player, node, HacknetNodeConstants.MaxCores);
multiplier = getMaxNumberCoreUpgrades(node, HacknetNodeConstants.MaxCores);
} else {
const levelsToMax = HacknetNodeConstants.MaxCores - node.cores;
multiplier = Math.min(levelsToMax, purchaseMult);
}
const increase =
calculateMoneyGainRate(node.level, node.ram, node.cores + multiplier, props.player.mults.hacknet_node_money) -
calculateMoneyGainRate(node.level, node.ram, node.cores + multiplier, Player.mults.hacknet_node_money) -
node.moneyGainRatePerSecond;
const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, props.player.mults.hacknet_node_core_cost);
const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, Player.mults.hacknet_node_core_cost);
upgradeCoresButton = (
<Tooltip
title={
@ -161,7 +160,7 @@ export function HacknetNodeElem(props: IProps): React.ReactElement {
>
<Button onClick={upgradeCoresOnClick}>
+{multiplier} -&nbsp;
<Money money={upgradeCoreCost} player={props.player} />
<Money money={upgradeCoreCost} forPurchase={true} />
</Button>
</Tooltip>
);

@ -21,7 +21,7 @@ import {
purchaseHacknet,
} from "../HacknetHelpers";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { GetServer } from "../../Server/AllServers";
import Typography from "@mui/material/Typography";
@ -29,11 +29,7 @@ import Grid from "@mui/material/Grid";
import Button from "@mui/material/Button";
import { Box } from "@mui/material";
interface IProps {
player: IPlayer;
}
export function HacknetRoot(props: IProps): React.ReactElement {
export function HacknetRoot(): React.ReactElement {
const [open, setOpen] = useState(false);
const setRerender = useState(false)[1];
function rerender(): void {
@ -47,9 +43,9 @@ export function HacknetRoot(props: IProps): React.ReactElement {
}, []);
let totalProduction = 0;
for (let i = 0; i < props.player.hacknetNodes.length; ++i) {
const node = props.player.hacknetNodes[i];
if (hasHacknetServers(props.player)) {
for (let i = 0; i < Player.hacknetNodes.length; ++i) {
const node = Player.hacknetNodes[i];
if (hasHacknetServers()) {
if (node instanceof HacknetNode) throw new Error("node was hacknet node"); // should never happen
const hserver = GetServer(node);
if (!(hserver instanceof HacknetServer)) throw new Error("node was not hacknet server"); // should never happen
@ -65,16 +61,16 @@ export function HacknetRoot(props: IProps): React.ReactElement {
}
function handlePurchaseButtonClick(): void {
purchaseHacknet(props.player);
purchaseHacknet();
rerender();
}
// Cost to purchase a new Hacknet Node
let purchaseCost;
if (hasHacknetServers(props.player)) {
purchaseCost = getCostOfNextHacknetServer(props.player);
if (hasHacknetServers()) {
purchaseCost = getCostOfNextHacknetServer();
} else {
purchaseCost = getCostOfNextHacknetNode(props.player);
purchaseCost = getCostOfNextHacknetNode();
}
// onClick event handlers for purchase multiplier buttons
@ -86,8 +82,8 @@ export function HacknetRoot(props: IProps): React.ReactElement {
];
// HacknetNode components
const nodes = props.player.hacknetNodes.map((node: string | HacknetNode) => {
if (hasHacknetServers(props.player)) {
const nodes = Player.hacknetNodes.map((node: string | HacknetNode) => {
if (hasHacknetServers()) {
if (node instanceof HacknetNode) throw new Error("node was hacknet node"); // should never happen
const hserver = GetServer(node);
if (hserver == null) {
@ -96,7 +92,6 @@ export function HacknetRoot(props: IProps): React.ReactElement {
if (!(hserver instanceof HacknetServer)) throw new Error("node was not hacknet server"); // should never happen
return (
<HacknetServerElem
player={props.player}
key={hserver.hostname}
node={hserver}
purchaseMultiplier={purchaseMultiplier}
@ -106,21 +101,15 @@ export function HacknetRoot(props: IProps): React.ReactElement {
} else {
if (typeof node === "string") throw new Error("node was ip string"); // should never happen
return (
<HacknetNodeElem
player={props.player}
key={node.name}
node={node}
purchaseMultiplier={purchaseMultiplier}
rerender={rerender}
/>
<HacknetNodeElem key={node.name} node={node} purchaseMultiplier={purchaseMultiplier} rerender={rerender} />
);
}
});
return (
<>
<Typography variant="h4">Hacknet {hasHacknetServers(props.player) ? "Servers" : "Nodes"}</Typography>
<GeneralInfo hasHacknetServers={hasHacknetServers(props.player)} />
<Typography variant="h4">Hacknet {hasHacknetServers() ? "Servers" : "Nodes"}</Typography>
<GeneralInfo hasHacknetServers={hasHacknetServers()} />
<PurchaseButton cost={purchaseCost} multiplier={purchaseMultiplier} onClick={handlePurchaseButtonClick} />
@ -128,14 +117,14 @@ export function HacknetRoot(props: IProps): React.ReactElement {
<Grid container spacing={2}>
<Grid item xs={6}>
<PlayerInfo totalProduction={totalProduction} player={props.player} />
<PlayerInfo totalProduction={totalProduction} />
</Grid>
<Grid item xs={6}>
<MultiplierButtons onClicks={purchaseMultiplierOnClicks} purchaseMultiplier={purchaseMultiplier} />
</Grid>
</Grid>
{hasHacknetServers(props.player) && <Button onClick={() => setOpen(true)}>Spend Hashes on Upgrades</Button>}
{hasHacknetServers() && <Button onClick={() => setOpen(true)}>Spend Hashes on Upgrades</Button>}
<Box sx={{ display: "grid", width: "fit-content", gridTemplateColumns: "repeat(3, 1fr)" }}>{nodes}</Box>
<HashUpgradeModal open={open} onClose={() => setOpen(false)} />

@ -17,7 +17,7 @@ import {
updateHashManagerCapacity,
} from "../HacknetHelpers";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { HacknetServer } from "../HacknetServer";
import { Money } from "../../ui/React/Money";
@ -39,7 +39,6 @@ interface IProps {
node: HacknetServer;
purchaseMultiplier: number | string;
rerender: () => void;
player: IPlayer;
}
export function HacknetServerElem(props: IProps): React.ReactElement {
@ -54,7 +53,7 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
} else {
let multiplier = 0;
if (purchaseMult === "MAX") {
multiplier = getMaxNumberLevelUpgrades(props.player, node, HacknetServerConstants.MaxLevel);
multiplier = getMaxNumberLevelUpgrades(node, HacknetServerConstants.MaxLevel);
} else {
const levelsToMax = HacknetServerConstants.MaxLevel - node.level;
multiplier = Math.min(levelsToMax, purchaseMult as number);
@ -66,11 +65,11 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
0,
node.maxRam,
node.cores,
props.player.mults.hacknet_node_money,
) - calculateHashGainRate(node.level, 0, node.maxRam, node.cores, props.player.mults.hacknet_node_money);
Player.mults.hacknet_node_money,
) - calculateHashGainRate(node.level, 0, node.maxRam, node.cores, Player.mults.hacknet_node_money);
const modded_increase = (base_increase * (node.maxRam - node.ramUsed)) / node.maxRam;
const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, props.player.mults.hacknet_node_level_cost);
const upgradeLevelCost = node.calculateLevelUpgradeCost(multiplier, Player.mults.hacknet_node_level_cost);
upgradeLevelButton = (
<Tooltip
title={
@ -86,7 +85,7 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
>
<Button onClick={upgradeLevelOnClick}>
+{multiplier}&nbsp;-&nbsp;
<Money money={upgradeLevelCost} player={props.player} />
<Money money={upgradeLevelCost} forPurchase={true} />
</Button>
</Tooltip>
);
@ -94,18 +93,18 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
function upgradeLevelOnClick(): void {
let numUpgrades = purchaseMult;
if (purchaseMult === "MAX") {
numUpgrades = getMaxNumberLevelUpgrades(props.player, node, HacknetServerConstants.MaxLevel);
numUpgrades = getMaxNumberLevelUpgrades(node, HacknetServerConstants.MaxLevel);
}
purchaseLevelUpgrade(props.player, node, numUpgrades as number);
purchaseLevelUpgrade(node, numUpgrades as number);
rerender();
}
function upgradeRamOnClick(): void {
let numUpgrades = purchaseMult;
if (purchaseMult === "MAX") {
numUpgrades = getMaxNumberRamUpgrades(props.player, node, HacknetServerConstants.MaxRam);
numUpgrades = getMaxNumberRamUpgrades(node, HacknetServerConstants.MaxRam);
}
purchaseRamUpgrade(props.player, node, numUpgrades as number);
purchaseRamUpgrade(node, numUpgrades as number);
rerender();
}
// Upgrade RAM Button
@ -115,7 +114,7 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
} else {
let multiplier = 0;
if (purchaseMult === "MAX") {
multiplier = getMaxNumberRamUpgrades(props.player, node, HacknetServerConstants.MaxRam);
multiplier = getMaxNumberRamUpgrades(node, HacknetServerConstants.MaxRam);
} else {
const levelsToMax = Math.round(Math.log2(HacknetServerConstants.MaxRam / node.maxRam));
multiplier = Math.min(levelsToMax, purchaseMult as number);
@ -127,8 +126,8 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
0,
node.maxRam * Math.pow(2, multiplier),
node.cores,
props.player.mults.hacknet_node_money,
) - calculateHashGainRate(node.level, 0, node.maxRam, node.cores, props.player.mults.hacknet_node_money);
Player.mults.hacknet_node_money,
) - calculateHashGainRate(node.level, 0, node.maxRam, node.cores, Player.mults.hacknet_node_money);
const modded_increase =
calculateHashGainRate(
@ -136,11 +135,11 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
node.ramUsed,
node.maxRam * Math.pow(2, multiplier),
node.cores,
props.player.mults.hacknet_node_money,
Player.mults.hacknet_node_money,
) -
calculateHashGainRate(node.level, node.ramUsed, node.maxRam, node.cores, props.player.mults.hacknet_node_money);
calculateHashGainRate(node.level, node.ramUsed, node.maxRam, node.cores, Player.mults.hacknet_node_money);
const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, props.player.mults.hacknet_node_ram_cost);
const upgradeRamCost = node.calculateRamUpgradeCost(multiplier, Player.mults.hacknet_node_ram_cost);
upgradeRamButton = (
<Tooltip
title={
@ -156,7 +155,7 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
>
<Button onClick={upgradeRamOnClick}>
+{multiplier}&nbsp;-&nbsp;
<Money money={upgradeRamCost} player={props.player} />
<Money money={upgradeRamCost} forPurchase={true} />
</Button>
</Tooltip>
);
@ -165,9 +164,9 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
function upgradeCoresOnClick(): void {
let numUpgrades = purchaseMult;
if (purchaseMult === "MAX") {
numUpgrades = getMaxNumberCoreUpgrades(props.player, node, HacknetServerConstants.MaxCores);
numUpgrades = getMaxNumberCoreUpgrades(node, HacknetServerConstants.MaxCores);
}
purchaseCoreUpgrade(props.player, node, numUpgrades as number);
purchaseCoreUpgrade(node, numUpgrades as number);
rerender();
}
// Upgrade Cores Button
@ -177,7 +176,7 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
} else {
let multiplier = 0;
if (purchaseMult === "MAX") {
multiplier = getMaxNumberCoreUpgrades(props.player, node, HacknetServerConstants.MaxCores);
multiplier = getMaxNumberCoreUpgrades(node, HacknetServerConstants.MaxCores);
} else {
const levelsToMax = HacknetServerConstants.MaxCores - node.cores;
multiplier = Math.min(levelsToMax, purchaseMult as number);
@ -189,11 +188,11 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
0,
node.maxRam,
node.cores + multiplier,
props.player.mults.hacknet_node_money,
) - calculateHashGainRate(node.level, 0, node.maxRam, node.cores, props.player.mults.hacknet_node_money);
Player.mults.hacknet_node_money,
) - calculateHashGainRate(node.level, 0, node.maxRam, node.cores, Player.mults.hacknet_node_money);
const modded_increase = (base_increase * (node.maxRam - node.ramUsed)) / node.maxRam;
const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, props.player.mults.hacknet_node_core_cost);
const upgradeCoreCost = node.calculateCoreUpgradeCost(multiplier, Player.mults.hacknet_node_core_cost);
upgradeCoresButton = (
<Tooltip
title={
@ -209,7 +208,7 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
>
<Button onClick={upgradeCoresOnClick}>
+{multiplier}&nbsp;-&nbsp;
<Money money={upgradeCoreCost} player={props.player} />
<Money money={upgradeCoreCost} forPurchase={true} />
</Button>
</Tooltip>
);
@ -222,7 +221,7 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
} else {
let multiplier = 0;
if (purchaseMult === "MAX") {
multiplier = getMaxNumberCacheUpgrades(props.player, node, HacknetServerConstants.MaxCache);
multiplier = getMaxNumberCacheUpgrades(node, HacknetServerConstants.MaxCache);
} else {
const levelsToMax = HacknetServerConstants.MaxCache - node.cache;
multiplier = Math.min(levelsToMax, purchaseMult as number);
@ -240,22 +239,22 @@ export function HacknetServerElem(props: IProps): React.ReactElement {
>
<Button onClick={upgradeCacheOnClick}>
+{multiplier}&nbsp;-&nbsp;
<Money money={upgradeCacheCost} player={props.player} />
<Money money={upgradeCacheCost} forPurchase={true} />
</Button>
</Tooltip>
);
if (props.player.money < upgradeCacheCost) {
if (Player.money < upgradeCacheCost) {
} else {
}
}
function upgradeCacheOnClick(): void {
let numUpgrades = purchaseMult;
if (purchaseMult === "MAX") {
numUpgrades = getMaxNumberCacheUpgrades(props.player, node, HacknetServerConstants.MaxCache);
numUpgrades = getMaxNumberCacheUpgrades(node, HacknetServerConstants.MaxCache);
}
purchaseCacheUpgrade(props.player, node, numUpgrades as number);
purchaseCacheUpgrade(node, numUpgrades as number);
rerender();
updateHashManagerCapacity(props.player);
updateHashManagerCapacity();
}
return (

@ -4,8 +4,6 @@ import { purchaseHashUpgrade } from "../HacknetHelpers";
import { HashManager } from "../HashManager";
import { HashUpgrade } from "../HashUpgrade";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { ServerDropdown, ServerType } from "../../ui/React/ServerDropdown";
import { dialogBoxCreate } from "../../ui/React/DialogBox";
@ -19,7 +17,6 @@ import { SelectChangeEvent } from "@mui/material/Select";
import { FactionNames } from "../../Faction/data/FactionNames";
interface IProps {
player: IPlayer;
hashManager: HashManager;
upg: HashUpgrade;
rerender: () => void;
@ -39,7 +36,7 @@ export function HacknetUpgradeElem(props: IProps): React.ReactElement {
function purchase(): void {
const canPurchase = props.hashManager.hashes >= props.hashManager.getUpgradeCost(props.upg.name);
if (canPurchase) {
const res = purchaseHashUpgrade(props.player, props.upg.name, selectedServer);
const res = purchaseHashUpgrade(props.upg.name, selectedServer);
if (!res) {
dialogBoxCreate(
"Failed to purchase upgrade. This may be because you do not have enough hashes, " +

@ -9,7 +9,7 @@ import { HashUpgrades } from "../HashUpgrades";
import { Hashes } from "../../ui/React/Hashes";
import { HacknetUpgradeElem } from "./HacknetUpgradeElem";
import { Modal } from "../../ui/React/Modal";
import { use } from "../../ui/Context";
import { Player } from "../../Player";
import Typography from "@mui/material/Typography";
interface IProps {
@ -18,7 +18,6 @@ interface IProps {
}
export function HashUpgradeModal(props: IProps): React.ReactElement {
const player = use.Player();
const setRerender = useState(false)[1];
function rerender(): void {
setRerender((old) => !old);
@ -29,7 +28,7 @@ export function HashUpgradeModal(props: IProps): React.ReactElement {
return () => clearInterval(id);
}, []);
const hashManager = player.hashManager;
const hashManager = Player.hashManager;
if (!(hashManager instanceof HashManager)) {
throw new Error(`Player does not have a HashManager)`);
}
@ -39,19 +38,11 @@ export function HashUpgradeModal(props: IProps): React.ReactElement {
<>
<Typography>Spend your hashes on a variety of different upgrades</Typography>
<Typography>
Hashes: <Hashes hashes={player.hashManager.hashes} />
Hashes: <Hashes hashes={Player.hashManager.hashes} />
</Typography>
{Object.keys(HashUpgrades).map((upgName) => {
const upg = HashUpgrades[upgName];
return (
<HacknetUpgradeElem
player={player}
upg={upg}
hashManager={hashManager}
key={upg.name}
rerender={rerender}
/>
);
return <HacknetUpgradeElem upg={upg} hashManager={hashManager} key={upg.name} rerender={rerender} />;
})}
</>
</Modal>

@ -7,7 +7,7 @@
import React from "react";
import { hasHacknetServers } from "../HacknetHelpers";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { Money } from "../../ui/React/Money";
import { MoneyRate } from "../../ui/React/MoneyRate";
import { HashRate } from "../../ui/React/HashRate";
@ -16,11 +16,10 @@ import Typography from "@mui/material/Typography";
interface IProps {
totalProduction: number;
player: IPlayer;
}
export function PlayerInfo(props: IProps): React.ReactElement {
const hasServers = hasHacknetServers(props.player);
const hasServers = hasHacknetServers();
let prod;
if (hasServers) {
@ -33,14 +32,13 @@ export function PlayerInfo(props: IProps): React.ReactElement {
<>
<Typography>
Money:
<Money money={props.player.money} />
<Money money={Player.money} />
</Typography>
{hasServers && (
<>
<Typography>
Hashes: <Hashes hashes={props.player.hashManager.hashes} /> /{" "}
<Hashes hashes={props.player.hashManager.capacity} />
Hashes: <Hashes hashes={Player.hashManager.hashes} /> / <Hashes hashes={Player.hashManager.capacity} />
</Typography>
</>
)}

@ -18,14 +18,14 @@ interface IProps {
export function PurchaseButton(props: IProps): React.ReactElement {
const cost = props.cost;
let text;
if (hasHacknetServers(Player)) {
if (hasMaxNumberHacknetServers(Player)) {
if (hasHacknetServers()) {
if (hasMaxNumberHacknetServers()) {
text = <>Hacknet Server limit reached</>;
} else {
text = (
<>
Purchase Hacknet Server -&nbsp;
<Money money={cost} player={Player} />
<Money money={cost} forPurchase={true} />
</>
);
}
@ -33,7 +33,7 @@ export function PurchaseButton(props: IProps): React.ReactElement {
text = (
<>
Purchase Hacknet Node -&nbsp;
<Money money={cost} player={Player} />
<Money money={cost} forPurchase={true} />
</>
);
}

@ -1,18 +1,18 @@
import { IPlayer } from "../PersonObjects/IPlayer";
import { Player } from "../Player";
import { CONSTANTS } from "../Constants";
export function getHospitalizationCost(p: IPlayer): number {
if (p.money < 0) {
export function getHospitalizationCost(): number {
if (Player.money < 0) {
return 0;
}
return Math.min(p.money * 0.1, (p.hp.max - p.hp.current) * CONSTANTS.HospitalCostPerHp);
return Math.min(Player.money * 0.1, (Player.hp.max - Player.hp.current) * CONSTANTS.HospitalCostPerHp);
}
export function calculateHospitalizationCost(p: IPlayer, damage: number): number {
const oldhp = p.hp.current;
p.hp.current -= damage;
const cost = getHospitalizationCost(p);
p.hp.current = oldhp;
export function calculateHospitalizationCost(damage: number): number {
const oldhp = Player.hp.current;
Player.hp.current -= damage;
const cost = getHospitalizationCost();
Player.hp.current = oldhp;
return cost;
}

@ -1,40 +0,0 @@
/**
* Location and traveling-related helper functions.
* Mostly used for UI
*/
import { SpecialServers } from "../Server/data/SpecialServers";
import { CONSTANTS } from "../Constants";
import { IPlayer } from "../PersonObjects/IPlayer";
import { GetServer } from "../Server/AllServers";
import { dialogBoxCreate } from "../ui/React/DialogBox";
/**
* Attempt to purchase a TOR router
* @param {IPlayer} p - Player object
*/
export function purchaseTorRouter(p: IPlayer): void {
if (p.hasTorRouter()) {
dialogBoxCreate(`You already have a TOR Router!`);
return;
}
if (!p.canAfford(CONSTANTS.TorRouterCost)) {
dialogBoxCreate("You cannot afford to purchase the TOR router!");
return;
}
p.loseMoney(CONSTANTS.TorRouterCost, "other");
const darkweb = GetServer(SpecialServers.DarkWeb);
if (!darkweb) {
throw new Error("Dark web is not a server.");
}
p.getHomeComputer().serversOnNetwork.push(darkweb.hostname);
darkweb.serversOnNetwork.push(p.getHomeComputer().hostname);
dialogBoxCreate(
"You have purchased a TOR router!\n" +
"You now have access to the dark web from your home computer.\n" +
"Use the scan/scan-analyze commands to search for the dark web connection.",
);
}

@ -9,7 +9,6 @@ import { Blackjack, DECK_COUNT } from "../../Casino/Blackjack";
import { CoinFlip } from "../../Casino/CoinFlip";
import { Roulette } from "../../Casino/Roulette";
import { SlotMachine } from "../../Casino/SlotMachine";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Box } from "@mui/material";
enum GameType {
@ -20,11 +19,7 @@ enum GameType {
Blackjack = "blackjack",
}
type IProps = {
p: IPlayer;
};
export function CasinoLocation(props: IProps): React.ReactElement {
export function CasinoLocation(): React.ReactElement {
const [game, setGame] = useState(GameType.None);
function updateGame(game: GameType): void {
@ -44,10 +39,10 @@ export function CasinoLocation(props: IProps): React.ReactElement {
{game !== GameType.None && (
<>
<Button onClick={() => updateGame(GameType.None)}>Stop playing</Button>
{game === GameType.Coin && <CoinFlip p={props.p} />}
{game === GameType.Slots && <SlotMachine p={props.p} />}
{game === GameType.Roulette && <Roulette p={props.p} />}
{game === GameType.Blackjack && <Blackjack p={props.p} />}
{game === GameType.Coin && <CoinFlip />}
{game === GameType.Slots && <SlotMachine />}
{game === GameType.Roulette && <Roulette />}
{game === GameType.Blackjack && <Blackjack />}
</>
)}
</>

@ -3,29 +3,28 @@ import Button from "@mui/material/Button";
import Tooltip from "@mui/material/Tooltip";
import Typography from "@mui/material/Typography";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { Money } from "../../ui/React/Money";
import { MathJaxWrapper } from "../../MathJaxWrapper";
type IProps = {
p: IPlayer;
rerender: () => void;
};
export function CoresButton(props: IProps): React.ReactElement {
const homeComputer = props.p.getHomeComputer();
const homeComputer = Player.getHomeComputer();
const maxCores = homeComputer.cpuCores >= 8;
if (maxCores) {
return <Button>Upgrade 'home' cores - MAX</Button>;
}
const cost = props.p.getUpgradeHomeCoresCost();
const cost = Player.getUpgradeHomeCoresCost();
function buy(): void {
if (maxCores) return;
if (!props.p.canAfford(cost)) return;
props.p.loseMoney(cost, "servers");
if (!Player.canAfford(cost)) return;
Player.loseMoney(cost, "servers");
homeComputer.cpuCores++;
props.rerender();
}
@ -38,9 +37,9 @@ export function CoresButton(props: IProps): React.ReactElement {
<i>"Cores increase the effectiveness of grow() and weaken() on 'home'"</i>
</Typography>
<br />
<Button disabled={!props.p.canAfford(cost)} onClick={buy}>
<Button disabled={!Player.canAfford(cost)} onClick={buy}>
Upgrade 'home' cores ({homeComputer.cpuCores} -&gt; {homeComputer.cpuCores + 1}) -&nbsp;
<Money money={cost} player={props.p} />
<Money money={cost} forPurchase={true} />
</Button>
</span>
</Tooltip>

@ -27,7 +27,7 @@ import { isBackdoorInstalled } from "../../Server/ServerHelpers";
import { GetServer } from "../../Server/AllServers";
import { CorruptableText } from "../../ui/React/CorruptableText";
import { use } from "../../ui/Context";
import { Router } from "../../ui/GameRoot";
import { serverMetadata } from "../../Server/data/servers";
import { Tooltip } from "@mui/material";
@ -36,8 +36,6 @@ type IProps = {
};
export function GenericLocation({ loc }: IProps): React.ReactElement {
const router = use.Router();
const player = use.Player();
/**
* Determine what needs to be rendered for this location based on the locations
* type. Returns an array of React components that should be rendered
@ -50,11 +48,11 @@ export function GenericLocation({ loc }: IProps): React.ReactElement {
}
if (loc.types.includes(LocationType.Gym)) {
content.push(<GymLocation key={"gymlocation"} router={router} loc={loc} p={player} />);
content.push(<GymLocation key={"gymlocation"} loc={loc} />);
}
if (loc.types.includes(LocationType.Hospital)) {
content.push(<HospitalLocation key={"hospitallocation"} p={player} />);
content.push(<HospitalLocation key={"hospitallocation"} />);
}
if (loc.types.includes(LocationType.Slums)) {
@ -70,7 +68,7 @@ export function GenericLocation({ loc }: IProps): React.ReactElement {
}
if (loc.types.includes(LocationType.TravelAgency)) {
content.push(<TravelAgencyRoot key={"travelagencylocation"} p={player} router={router} />);
content.push(<TravelAgencyRoot key={"travelagencylocation"} />);
}
if (loc.types.includes(LocationType.University)) {
@ -78,7 +76,7 @@ export function GenericLocation({ loc }: IProps): React.ReactElement {
}
if (loc.types.includes(LocationType.Casino)) {
content.push(<CasinoLocation key={"casinoLocation"} p={player} />);
content.push(<CasinoLocation key={"casinoLocation"} />);
}
return content;
@ -92,7 +90,7 @@ export function GenericLocation({ loc }: IProps): React.ReactElement {
return (
<>
<Button onClick={() => router.toCity()}>Return to World</Button>
<Button onClick={() => Router.toCity()}>Return to World</Button>
<Typography variant="h4" sx={{ mt: 1 }}>
{backdoorInstalled && !Settings.DisableTextEffects ? (
<Tooltip title={`Backdoor installed on ${loc.name}.`}>

@ -8,31 +8,29 @@ import Button from "@mui/material/Button";
import { Location } from "../Location";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { Money } from "../../ui/React/Money";
import { IRouter } from "../../ui/Router";
import { Router } from "../../ui/GameRoot";
import { Box } from "@mui/material";
import { ClassWork, ClassType, Classes } from "../../Work/ClassWork";
import { calculateCost } from "../../Work/formulas/Class";
type IProps = {
loc: Location;
p: IPlayer;
router: IRouter;
};
export function GymLocation(props: IProps): React.ReactElement {
function train(stat: ClassType): void {
props.p.startWork(
Player.startWork(
new ClassWork({
classType: stat,
location: props.loc.name,
singularity: false,
}),
);
props.p.startFocusing();
props.router.toWork();
Player.startFocusing();
Router.toWork();
}
const cost = calculateCost(Classes[ClassType.GymStrength], props.loc);
@ -40,16 +38,16 @@ export function GymLocation(props: IProps): React.ReactElement {
return (
<Box sx={{ display: "grid", width: "fit-content" }}>
<Button onClick={() => train(ClassType.GymStrength)}>
Train Strength (<Money money={cost} player={props.p} /> / sec)
Train Strength (<Money money={cost} forPurchase={true} /> / sec)
</Button>
<Button onClick={() => train(ClassType.GymDefense)}>
Train Defense (<Money money={cost} player={props.p} /> / sec)
Train Defense (<Money money={cost} forPurchase={true} /> / sec)
</Button>
<Button onClick={() => train(ClassType.GymDexterity)}>
Train Dexterity (<Money money={cost} player={props.p} /> / sec)
Train Dexterity (<Money money={cost} forPurchase={true} /> / sec)
</Button>
<Button onClick={() => train(ClassType.GymAgility)}>
Train Agility (<Money money={cost} player={props.p} /> / sec)
Train Agility (<Money money={cost} forPurchase={true} /> / sec)
</Button>
</Box>
);

@ -6,16 +6,14 @@
import * as React from "react";
import Button from "@mui/material/Button";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { getHospitalizationCost } from "../../Hospital/Hospital";
import { Money } from "../../ui/React/Money";
import { dialogBoxCreate } from "../../ui/React/DialogBox";
type IProps = {
p: IPlayer;
};
type IProps = {};
type IState = {
currHp: number;
@ -34,12 +32,12 @@ export class HospitalLocation extends React.Component<IProps, IState> {
this.getHealed = this.getHealed.bind(this);
this.state = {
currHp: this.props.p.hp.current,
currHp: Player.hp.current,
};
}
getCost(): number {
return getHospitalizationCost(this.props.p);
return getHospitalizationCost();
}
getHealed(e: React.MouseEvent<HTMLElement>): void {
@ -47,20 +45,20 @@ export class HospitalLocation extends React.Component<IProps, IState> {
return;
}
if (this.props.p.hp.current < 0) {
this.props.p.hp.current = 0;
if (Player.hp.current < 0) {
Player.hp.current = 0;
}
if (this.props.p.hp.current >= this.props.p.hp.max) {
if (Player.hp.current >= Player.hp.max) {
return;
}
const cost = this.getCost();
this.props.p.loseMoney(cost, "hospitalization");
this.props.p.hp.current = this.props.p.hp.max;
Player.loseMoney(cost, "hospitalization");
Player.hp.current = Player.hp.max;
// This just forces a re-render to update the cost
this.setState({
currHp: this.props.p.hp.current,
currHp: Player.hp.current,
});
dialogBoxCreate(
@ -75,7 +73,7 @@ export class HospitalLocation extends React.Component<IProps, IState> {
return (
<Button onClick={this.getHealed} style={this.btnStyle}>
Get treatment for wounds - <Money money={cost} player={this.props.p} />
Get treatment for wounds - <Money money={cost} forPurchase={true} />
</Button>
);
}

@ -25,7 +25,7 @@ export function PurchaseServerModal(props: IProps): React.ReactElement {
const [hostname, setHostname] = useState("");
function tryToPurchaseServer(): void {
purchaseServer(hostname, props.ram, props.cost, player);
purchaseServer(hostname, props.ram, props.cost);
props.onClose();
}
@ -41,7 +41,7 @@ export function PurchaseServerModal(props: IProps): React.ReactElement {
<Modal open={props.open} onClose={props.onClose}>
<Typography>
Would you like to purchase a new server with {numeralWrapper.formatRAM(props.ram)} of RAM for{" "}
<Money money={props.cost} player={player} />?
<Money money={props.cost} forPurchase={true} />?
</Typography>
<br />
<br />

@ -4,7 +4,7 @@ import Tooltip from "@mui/material/Tooltip";
import Typography from "@mui/material/Typography";
import { CONSTANTS } from "../../Constants";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { purchaseRamForHomeComputer } from "../../Server/ServerPurchases";
import { Money } from "../../ui/React/Money";
@ -14,20 +14,19 @@ import { MathJaxWrapper } from "../../MathJaxWrapper";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
type IProps = {
p: IPlayer;
rerender: () => void;
};
export function RamButton(props: IProps): React.ReactElement {
const homeComputer = props.p.getHomeComputer();
const homeComputer = Player.getHomeComputer();
if (homeComputer.maxRam >= CONSTANTS.HomeComputerMaxRam) {
return <Button>Upgrade 'home' RAM - MAX</Button>;
}
const cost = props.p.getUpgradeHomeRamCost();
const cost = Player.getUpgradeHomeRamCost();
function buy(): void {
purchaseRamForHomeComputer(props.p);
purchaseRamForHomeComputer();
props.rerender();
}
@ -45,10 +44,10 @@ export function RamButton(props: IProps): React.ReactElement {
<i>"More RAM means more scripts on 'home'"</i>
</Typography>
<br />
<Button disabled={!props.p.canAfford(cost)} onClick={buy}>
<Button disabled={!Player.canAfford(cost)} onClick={buy}>
Upgrade 'home' RAM ({numeralWrapper.formatRAM(homeComputer.maxRam)} -&gt;&nbsp;
{numeralWrapper.formatRAM(homeComputer.maxRam * 2)}) -&nbsp;
<Money money={cost} player={props.p} />
<Money money={cost} forPurchase={true} />
</Button>
</span>
</Tooltip>

@ -15,7 +15,7 @@ import { CoresButton } from "./CoresButton";
import { getPurchaseServerCost } from "../../Server/ServerPurchases";
import { Money } from "../../ui/React/Money";
import { use } from "../../ui/Context";
import { Player } from "../../Player";
import { PurchaseServerModal } from "./PurchaseServerModal";
import { numeralWrapper } from "../../ui/numeralFormat";
import { Box } from "@mui/material";
@ -27,13 +27,12 @@ interface IServerProps {
function ServerButton(props: IServerProps): React.ReactElement {
const [open, setOpen] = useState(false);
const player = use.Player();
const cost = getPurchaseServerCost(props.ram);
return (
<>
<Button onClick={() => setOpen(true)} disabled={!player.canAfford(cost)}>
<Button onClick={() => setOpen(true)} disabled={!Player.canAfford(cost)}>
Purchase {numeralWrapper.formatRAM(props.ram)} Server&nbsp;-&nbsp;
<Money money={cost} player={player} />
<Money money={cost} forPurchase={true} />
</Button>
<PurchaseServerModal
open={open}
@ -51,7 +50,6 @@ type IProps = {
};
export function TechVendorLocation(props: IProps): React.ReactElement {
const player = use.Player();
const setRerender = useState(false)[1];
function rerender(): void {
setRerender((old) => !old);
@ -76,11 +74,11 @@ export function TechVendorLocation(props: IProps): React.ReactElement {
<i>"You can order bigger servers via scripts. We don't take custom orders in person."</i>
</Typography>
<br />
<TorButton p={player} rerender={rerender} />
<TorButton rerender={rerender} />
<br />
<RamButton p={player} rerender={rerender} />
<RamButton rerender={rerender} />
<br />
<CoresButton p={player} rerender={rerender} />
<CoresButton rerender={rerender} />
</>
);
}

@ -1,32 +1,62 @@
import React from "react";
import Button from "@mui/material/Button";
import { purchaseTorRouter } from "../LocationsHelpers";
import { dialogBoxCreate } from "../../ui/React/DialogBox";
import { GetServer } from "../../Server/AllServers";
import { SpecialServers } from "../../Server/data/SpecialServers";
import { CONSTANTS } from "../../Constants";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { Money } from "../../ui/React/Money";
/**
* Attempt to purchase a TOR router using the button.
*/
export function purchaseTorRouter(): void {
if (Player.hasTorRouter()) {
dialogBoxCreate(`You already have a TOR Router!`);
return;
}
if (!Player.canAfford(CONSTANTS.TorRouterCost)) {
dialogBoxCreate("You cannot afford to purchase the TOR router!");
return;
}
Player.loseMoney(CONSTANTS.TorRouterCost, "other");
const darkweb = GetServer(SpecialServers.DarkWeb);
if (!darkweb) {
throw new Error("Dark web is not a server.");
}
Player.getHomeComputer().serversOnNetwork.push(darkweb.hostname);
darkweb.serversOnNetwork.push(Player.getHomeComputer().hostname);
dialogBoxCreate(
"You have purchased a TOR router!\n" +
"You now have access to the dark web from your home computer.\n" +
"Use the scan/scan-analyze commands to search for the dark web connection.",
);
}
type IProps = {
p: IPlayer;
rerender: () => void;
};
export function TorButton(props: IProps): React.ReactElement {
function buy(): void {
purchaseTorRouter(props.p);
purchaseTorRouter();
props.rerender();
}
if (props.p.hasTorRouter()) {
if (Player.hasTorRouter()) {
return <Button>TOR Router - Purchased</Button>;
}
return (
<Button disabled={!props.p.canAfford(CONSTANTS.TorRouterCost)} onClick={buy}>
<Button disabled={!Player.canAfford(CONSTANTS.TorRouterCost)} onClick={buy}>
Purchase TOR router -&nbsp;
<Money money={CONSTANTS.TorRouterCost} player={props.p} />
<Money money={CONSTANTS.TorRouterCost} forPurchase={true} />
</Button>
);
}

@ -9,11 +9,10 @@ import { CityName } from "../data/CityNames";
import { TravelConfirmationModal } from "./TravelConfirmationModal";
import { CONSTANTS } from "../../Constants";
import { IPlayer } from "../../PersonObjects/IPlayer";
import { IRouter } from "../../ui/Router";
import { Player } from "../../Player";
import { Router } from "../../ui/GameRoot";
import { Settings } from "../../Settings/Settings";
import { use } from "../../ui/Context";
import { Money } from "../../ui/React/Money";
import { WorldMap } from "../../ui/React/WorldMap";
import { dialogBoxCreate } from "../../ui/React/DialogBox";
@ -22,26 +21,19 @@ import Typography from "@mui/material/Typography";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
type IProps = {
p: IPlayer;
router: IRouter;
};
function travel(p: IPlayer, router: IRouter, to: CityName): void {
function travel(to: CityName): void {
const cost = CONSTANTS.TravelCost;
if (!p.canAfford(cost)) {
if (!Player.canAfford(cost)) {
return;
}
p.loseMoney(cost, "other");
p.travel(to);
Player.loseMoney(cost, "other");
Player.travel(to);
dialogBoxCreate(`You are now in ${to}!`);
router.toCity();
Router.toCity();
}
export function TravelAgencyRoot(props: IProps): React.ReactElement {
const player = use.Player();
const router = use.Router();
export function TravelAgencyRoot(): React.ReactElement {
const setRerender = useState(false)[1];
const [open, setOpen] = useState(false);
const [destination, setDestination] = useState(CityName.Sector12);
@ -56,11 +48,11 @@ export function TravelAgencyRoot(props: IProps): React.ReactElement {
function startTravel(city: CityName): void {
const cost = CONSTANTS.TravelCost;
if (!player.canAfford(cost)) {
if (!Player.canAfford(cost)) {
return;
}
if (Settings.SuppressTravelConfirmation) {
travel(player, router, city);
travel(city);
return;
}
setOpen(true);
@ -73,12 +65,12 @@ export function TravelAgencyRoot(props: IProps): React.ReactElement {
<Box mx={2}>
<Typography>
From here, you can travel to any other city! A ticket costs{" "}
<Money money={CONSTANTS.TravelCost} player={props.p} />.
<Money money={CONSTANTS.TravelCost} forPurchase={true} />.
</Typography>
{Settings.DisableASCIIArt ? (
<>
{Object.values(CityName)
.filter((city: string) => city != props.p.city)
.filter((city: string) => city != Player.city)
.map((city: string) => {
const match = Object.entries(CityName).find((entry) => entry[1] === city);
if (match === undefined) throw new Error(`could not find key for city '${city}'`);
@ -93,12 +85,12 @@ export function TravelAgencyRoot(props: IProps): React.ReactElement {
})}
</>
) : (
<WorldMap currentCity={props.p.city} onTravel={(city: CityName) => startTravel(city)} />
<WorldMap currentCity={Player.city} onTravel={(city: CityName) => startTravel(city)} />
)}
</Box>
<TravelConfirmationModal
city={destination}
travel={() => travel(player, router, destination)}
travel={() => travel(destination)}
open={open}
onClose={() => setOpen(false)}
/>

@ -24,7 +24,7 @@ export function TravelConfirmationModal(props: IProps): React.ReactElement {
return (
<Modal open={props.open} onClose={props.onClose}>
<Typography>
Would you like to travel to {props.city}? The trip will cost <Money money={cost} player={player} />.
Would you like to travel to {props.city}? The trip will cost <Money money={cost} forPurchase={true} />.
</Typography>
<br />
<br />

@ -53,31 +53,31 @@ export function UniversityLocation(props: IProps): React.ReactElement {
<Tooltip title={earnHackingExpTooltip}>
<Button onClick={() => take(ClassType.DataStructures)}>
Take Data Structures course (
<Money money={dataStructuresCost} player={player} /> / sec)
<Money money={dataStructuresCost} forPurchase={true} /> / sec)
</Button>
</Tooltip>
<Tooltip title={earnHackingExpTooltip}>
<Button onClick={() => take(ClassType.Networks)}>
Take Networks course (
<Money money={networksCost} player={player} /> / sec)
<Money money={networksCost} forPurchase={true} /> / sec)
</Button>
</Tooltip>
<Tooltip title={earnHackingExpTooltip}>
<Button onClick={() => take(ClassType.Algorithms)}>
Take Algorithms course (
<Money money={algorithmsCost} player={player} /> / sec)
<Money money={algorithmsCost} forPurchase={true} /> / sec)
</Button>
</Tooltip>
<Tooltip title={earnCharismaExpTooltip}>
<Button onClick={() => take(ClassType.Management)}>
Take Management course (
<Money money={managementCost} player={player} /> / sec)
<Money money={managementCost} forPurchase={true} /> / sec)
</Button>
</Tooltip>
<Tooltip title={earnCharismaExpTooltip}>
<Button onClick={() => take(ClassType.Leadership)}>
Take Leadership course (
<Money money={leadershipCost} player={player} /> / sec)
<Money money={leadershipCost} forPurchase={true} /> / sec)
</Button>
</Tooltip>
</Box>

@ -1,4 +1,4 @@
import { IPlayer } from "../../PersonObjects/IPlayer";
import { Player } from "../../Player";
import { Milestones } from "../Milestones";
import { Milestone } from "../Milestone";
import * as React from "react";
@ -6,26 +6,22 @@ import * as React from "react";
import Typography from "@mui/material/Typography";
import Box from "@mui/material/Box";
interface IProps {
player: IPlayer;
}
function highestMilestone(p: IPlayer, milestones: Milestone[]): number {
function highestMilestone(milestones: Milestone[]): number {
let n = -1;
for (let i = 0; i < milestones.length; i++) {
if (milestones[i].fulfilled(p)) n = i;
if (milestones[i].fulfilled(Player)) n = i;
}
return n;
}
export function MilestonesRoot(props: IProps): JSX.Element {
const n = highestMilestone(props.player, Milestones);
export function MilestonesRoot(): JSX.Element {
const n = highestMilestone(Milestones);
const milestones = Milestones.map((milestone: Milestone, i: number) => {
if (i <= n + 1) {
return (
<Typography key={i}>
[{milestone.fulfilled(props.player) ? "x" : " "}] {milestone.title}
[{milestone.fulfilled(Player) ? "x" : " "}] {milestone.title}
</Typography>
);
}

@ -390,7 +390,7 @@ function hack(
const hackingTime = calculateHackingTime(server, Player); // This is in seconds
// No root access or skill level too low
const canHack = netscriptCanHack(server, Player);
const canHack = netscriptCanHack(server);
if (!canHack.res) {
throw makeRuntimeErrorMsg(ctx, canHack.msg || "");
}

@ -1,4 +1,4 @@
import { Player as player } from "../Player";
import { Player } from "../Player";
import { Bladeburner } from "../Bladeburner/Bladeburner";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { Bladeburner as INetscriptBladeburner, BladeburnerCurAction } from "../ScriptEditor/NetscriptDefinitions";
@ -8,29 +8,23 @@ import { BlackOperation } from "../Bladeburner/BlackOperation";
import { helpers } from "../Netscript/NetscriptHelpers";
export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
const checkBladeburnerAccess = function (ctx: NetscriptContext, skipjoined = false): void {
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Must have joined bladeburner");
const apiAccess =
player.bitNodeN === 7 ||
player.sourceFiles.some((a) => {
return a.n === 7;
});
const checkBladeburnerAccess = function (ctx: NetscriptContext): void {
getBladeburner(ctx);
return;
};
const getBladeburner = function (ctx: NetscriptContext): Bladeburner {
const apiAccess = Player.bitNodeN === 7 || Player.sourceFiles.some((a) => a.n === 7);
if (!apiAccess) {
const apiDenied = `You do not currently have access to the Bladeburner API. You must either be in BitNode-7 or have Source-File 7.`;
throw helpers.makeRuntimeErrorMsg(ctx, apiDenied);
}
if (!skipjoined) {
const bladeburnerAccess = bladeburner instanceof Bladeburner;
if (!bladeburnerAccess) {
const bladeburnerDenied = `You must be a member of the Bladeburner division to use this API.`;
throw helpers.makeRuntimeErrorMsg(ctx, bladeburnerDenied);
}
throw helpers.makeRuntimeErrorMsg(ctx, "You have not unlocked the bladeburner API.", "API ACCESS");
}
const bladeburner = Player.bladeburner;
if (!bladeburner)
throw helpers.makeRuntimeErrorMsg(ctx, "You must be a member of the Bladeburner division to use this API.");
return bladeburner;
};
const checkBladeburnerCity = function (ctx: NetscriptContext, city: string): void {
const bladeburner = player.bladeburner;
const bladeburner = Player.bladeburner;
if (bladeburner === null) throw new Error("Must have joined bladeburner");
if (!bladeburner.cities.hasOwnProperty(city)) {
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid city: ${city}`);
@ -38,7 +32,7 @@ export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
};
const getBladeburnerActionObject = function (ctx: NetscriptContext, type: string, name: string): IAction {
const bladeburner = player.bladeburner;
const bladeburner = Player.bladeburner;
if (bladeburner === null) throw new Error("Must have joined bladeburner");
const actionId = bladeburner.getActionIdFromTypeAndName(type, name);
if (!actionId) {
@ -54,21 +48,15 @@ export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
return {
getContractNames: (ctx: NetscriptContext) => (): string[] => {
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
return bladeburner.getContractNamesNetscriptFn();
},
getOperationNames: (ctx: NetscriptContext) => (): string[] => {
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
return bladeburner.getOperationNamesNetscriptFn();
},
getBlackOpNames: (ctx: NetscriptContext) => (): string[] => {
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
return bladeburner.getBlackOpNamesNetscriptFn();
},
getBlackOpRank:
@ -81,15 +69,11 @@ export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
return action.reqdRank;
},
getGeneralActionNames: (ctx: NetscriptContext) => (): string[] => {
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
return bladeburner.getGeneralActionNamesNetscriptFn();
},
getSkillNames: (ctx: NetscriptContext) => (): string[] => {
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
return bladeburner.getSkillNamesNetscriptFn();
},
startAction:
@ -97,25 +81,19 @@ export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
(_type: unknown, _name: unknown): boolean => {
const type = helpers.string(ctx, "type", _type);
const name = helpers.string(ctx, "name", _name);
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
try {
return bladeburner.startActionNetscriptFn(player, type, name, ctx.workerScript);
return bladeburner.startActionNetscriptFn(type, name, ctx.workerScript);
} catch (e: unknown) {
throw helpers.makeRuntimeErrorMsg(ctx, String(e));
}
},
stopBladeburnerAction: (ctx: NetscriptContext) => (): void => {
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
return bladeburner.resetAction();
},
getCurrentAction: (ctx: NetscriptContext) => (): BladeburnerCurAction => {
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
return bladeburner.getTypeAndNameFromActionId(bladeburner.action);
},
getActionTime:
@ -123,11 +101,9 @@ export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
(_type: unknown, _name: unknown): number => {
const type = helpers.string(ctx, "type", _type);
const name = helpers.string(ctx, "name", _name);
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
try {
const time = bladeburner.getActionTimeNetscriptFn(player, type, name);
const time = bladeburner.getActionTimeNetscriptFn(Player, type, name);
if (typeof time === "string") {
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
helpers.log(ctx, () => errorLogText);
@ -140,9 +116,7 @@ export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
}
},
getActionCurrentTime: (ctx: NetscriptContext) => (): number => {
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
try {
const timecomputed =
Math.min(bladeburner.actionTimeCurrent + bladeburner.actionTimeOverflow, bladeburner.actionTimeToComplete) *
@ -157,11 +131,9 @@ export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
(_type: unknown, _name: unknown): [number, number] => {
const type = helpers.string(ctx, "type", _type);
const name = helpers.string(ctx, "name", _name);
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
try {
const chance = bladeburner.getActionEstimatedSuccessChanceNetscriptFn(player, type, name);
const chance = bladeburner.getActionEstimatedSuccessChanceNetscriptFn(Player, type, name);
if (typeof chance === "string") {
const errorLogText = `Invalid action: type='${type}' name='${name}'`;
helpers.log(ctx, () => errorLogText);
@ -195,9 +167,7 @@ export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
(_type: unknown, _name: unknown): number => {
const type = helpers.string(ctx, "type", _type);
const name = helpers.string(ctx, "name", _name);
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
try {
return bladeburner.getActionCountRemainingNetscriptFn(type, name, ctx.workerScript);
} catch (e: unknown) {
@ -255,24 +225,18 @@ export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
action.level = level;
},
getRank: (ctx: NetscriptContext) => (): number => {
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
return bladeburner.rank;
},
getSkillPoints: (ctx: NetscriptContext) => (): number => {
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
return bladeburner.skillPoints;
},
getSkillLevel:
(ctx: NetscriptContext) =>
(_skillName: unknown): number => {
const skillName = helpers.string(ctx, "skillName", _skillName);
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
try {
return bladeburner.getSkillLevelNetscriptFn(skillName, ctx.workerScript);
} catch (e: unknown) {
@ -284,9 +248,7 @@ export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
(_skillName: unknown, _count: unknown = 1): number => {
const skillName = helpers.string(ctx, "skillName", _skillName);
const count = helpers.number(ctx, "count", _count);
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
try {
return bladeburner.getSkillUpgradeCostNetscriptFn(skillName, count, ctx.workerScript);
} catch (e: unknown) {
@ -298,9 +260,7 @@ export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
(_skillName: unknown, _count: unknown = 1): boolean => {
const skillName = helpers.string(ctx, "skillName", _skillName);
const count = helpers.number(ctx, "count", _count);
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
try {
return bladeburner.upgradeSkillNetscriptFn(skillName, count, ctx.workerScript);
} catch (e: unknown) {
@ -312,9 +272,7 @@ export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
(_type: unknown, _name: unknown): number => {
const type = helpers.string(ctx, "type", _type);
const name = helpers.string(ctx, "name", _name);
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
try {
return bladeburner.getTeamSizeNetscriptFn(type, name, ctx.workerScript);
} catch (e: unknown) {
@ -327,9 +285,7 @@ export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
const type = helpers.string(ctx, "type", _type);
const name = helpers.string(ctx, "name", _name);
const size = helpers.number(ctx, "size", _size);
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
try {
return bladeburner.setTeamSizeNetscriptFn(type, name, size, ctx.workerScript);
} catch (e: unknown) {
@ -342,7 +298,7 @@ export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
const cityName = helpers.string(ctx, "cityName", _cityName);
checkBladeburnerAccess(ctx);
checkBladeburnerCity(ctx, cityName);
const bladeburner = player.bladeburner;
const bladeburner = Player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
return bladeburner.cities[cityName].popEst;
},
@ -352,7 +308,7 @@ export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
const cityName = helpers.string(ctx, "cityName", _cityName);
checkBladeburnerAccess(ctx);
checkBladeburnerCity(ctx, cityName);
const bladeburner = player.bladeburner;
const bladeburner = Player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
return bladeburner.cities[cityName].comms;
},
@ -362,14 +318,12 @@ export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
const cityName = helpers.string(ctx, "cityName", _cityName);
checkBladeburnerAccess(ctx);
checkBladeburnerCity(ctx, cityName);
const bladeburner = player.bladeburner;
const bladeburner = Player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
return bladeburner.cities[cityName].chaos;
},
getCity: (ctx: NetscriptContext) => (): string => {
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
return bladeburner.city;
},
switchCity:
@ -378,37 +332,33 @@ export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
const cityName = helpers.string(ctx, "cityName", _cityName);
checkBladeburnerAccess(ctx);
checkBladeburnerCity(ctx, cityName);
const bladeburner = player.bladeburner;
const bladeburner = Player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
bladeburner.city = cityName;
return true;
},
getStamina: (ctx: NetscriptContext) => (): [number, number] => {
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
return [bladeburner.stamina, bladeburner.maxStamina];
},
joinBladeburnerFaction: (ctx: NetscriptContext) => (): boolean => {
checkBladeburnerAccess(ctx, true);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
return bladeburner.joinBladeburnerFactionNetscriptFn(ctx.workerScript);
},
joinBladeburnerDivision: (ctx: NetscriptContext) => (): boolean => {
if (player.bitNodeN === 7 || player.sourceFileLvl(7) > 0) {
if (Player.bitNodeN === 7 || Player.sourceFileLvl(7) > 0) {
if (BitNodeMultipliers.BladeburnerRank === 0) {
return false; // Disabled in this bitnode
}
if (player.bladeburner instanceof Bladeburner) {
if (Player.bladeburner instanceof Bladeburner) {
return true; // Already member
} else if (
player.skills.strength >= 100 &&
player.skills.defense >= 100 &&
player.skills.dexterity >= 100 &&
player.skills.agility >= 100
Player.skills.strength >= 100 &&
Player.skills.defense >= 100 &&
Player.skills.dexterity >= 100 &&
Player.skills.agility >= 100
) {
player.bladeburner = new Bladeburner(player);
Player.bladeburner = new Bladeburner();
helpers.log(ctx, () => "You have been accepted into the Bladeburner division");
return true;
@ -420,9 +370,7 @@ export function NetscriptBladeburner(): InternalAPI<INetscriptBladeburner> {
return false;
},
getBonusTime: (ctx: NetscriptContext) => (): number => {
checkBladeburnerAccess(ctx);
const bladeburner = player.bladeburner;
if (bladeburner === null) throw new Error("Should not be called without Bladeburner");
const bladeburner = getBladeburner(ctx);
return Math.round(bladeburner.storedCycles / 5) * 1000;
},
};

@ -1047,14 +1047,14 @@ export function NetscriptCorporation(): InternalAPI<NSCorporation> {
(_numShares: unknown): number => {
checkAccess(ctx);
const numShares = helpers.number(ctx, "numShares", _numShares);
return SellShares(getCorporation(), player, numShares);
return SellShares(getCorporation(), numShares);
},
buyBackShares:
(ctx: NetscriptContext) =>
(_numShares: unknown): boolean => {
checkAccess(ctx);
const numShares = helpers.number(ctx, "numShares", _numShares);
return BuyBackShares(getCorporation(), player, numShares);
return BuyBackShares(getCorporation(), numShares);
},
bribe:
(ctx: NetscriptContext) =>

@ -410,11 +410,11 @@ export function NetscriptFormulas(): InternalAPI<IFormulas> {
},
classGains:
(ctx: NetscriptContext) =>
(_player: unknown, _classType: unknown, _locationName: unknown): WorkStats => {
const target = helpers.player(ctx, _player);
(_person: unknown, _classType: unknown, _locationName: unknown): WorkStats => {
const person = helpers.player(ctx, _person);
const classType = helpers.string(ctx, "classType", _classType);
const locationName = helpers.string(ctx, "locationName", _locationName);
return calculateClassEarnings(player, target, classType as ClassType, locationName as LocationName);
return calculateClassEarnings(person, classType as ClassType, locationName as LocationName);
},
factionGains:
(ctx: NetscriptContext) =>

@ -26,7 +26,7 @@ export function NetscriptGrafting(): InternalAPI<IGrafting> {
(_augName: unknown): number => {
const augName = helpers.string(ctx, "augName", _augName);
checkGraftingAPIAccess(ctx);
if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) {
if (!getGraftingAvailableAugs().includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) {
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid aug: ${augName}`);
}
const graftableAug = new GraftableAugmentation(StaticAugmentations[augName]);
@ -38,16 +38,16 @@ export function NetscriptGrafting(): InternalAPI<IGrafting> {
(_augName: string): number => {
const augName = helpers.string(ctx, "augName", _augName);
checkGraftingAPIAccess(ctx);
if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) {
if (!getGraftingAvailableAugs().includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) {
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid aug: ${augName}`);
}
const graftableAug = new GraftableAugmentation(StaticAugmentations[augName]);
return calculateGraftingTimeWithBonus(player, graftableAug);
return calculateGraftingTimeWithBonus(graftableAug);
},
getGraftableAugmentations: (ctx: NetscriptContext) => (): string[] => {
checkGraftingAPIAccess(ctx);
const graftableAugs = getGraftingAvailableAugs(player);
const graftableAugs = getGraftingAvailableAugs();
return graftableAugs;
},
@ -60,7 +60,7 @@ export function NetscriptGrafting(): InternalAPI<IGrafting> {
if (player.city !== CityName.NewTokyo) {
throw helpers.makeRuntimeErrorMsg(ctx, "You must be in New Tokyo to begin grafting an Augmentation.");
}
if (!getGraftingAvailableAugs(player).includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) {
if (!getGraftingAvailableAugs().includes(augName) || !StaticAugmentations.hasOwnProperty(augName)) {
helpers.log(ctx, () => `Invalid aug: ${augName}`);
return false;
}
@ -82,7 +82,6 @@ export function NetscriptGrafting(): InternalAPI<IGrafting> {
new GraftingWork({
singularity: true,
augmentation: augName,
player: player,
}),
);

@ -29,7 +29,7 @@ export function NetscriptHacknet(): InternalAPI<IHacknet> {
throw helpers.makeRuntimeErrorMsg(ctx, "Index specified for Hacknet Node is out-of-bounds: " + i);
}
if (hasHacknetServers(player)) {
if (hasHacknetServers()) {
const hi = player.hacknetNodes[i];
if (typeof hi !== "string") throw new Error("hacknet node was not a string");
const hserver = GetServer(hi);
@ -54,19 +54,19 @@ export function NetscriptHacknet(): InternalAPI<IHacknet> {
return player.hacknetNodes.length;
},
maxNumNodes: () => (): number => {
if (hasHacknetServers(player)) {
if (hasHacknetServers()) {
return HacknetServerConstants.MaxServers;
}
return Infinity;
},
purchaseNode: () => (): number => {
return purchaseHacknet(player);
return purchaseHacknet();
},
getPurchaseNodeCost: () => (): number => {
if (hasHacknetServers(player)) {
return getCostOfNextHacknetServer(player);
if (hasHacknetServers()) {
return getCostOfNextHacknetServer();
} else {
return getCostOfNextHacknetNode(player);
return getCostOfNextHacknetNode();
}
},
getNodeStats:
@ -74,7 +74,7 @@ export function NetscriptHacknet(): InternalAPI<IHacknet> {
(_i: unknown): NodeStats => {
const i = helpers.number(ctx, "i", _i);
const node = getHacknetNode(ctx, i);
const hasUpgraded = hasHacknetServers(player);
const hasUpgraded = hasHacknetServers();
const res: NodeStats = {
name: node instanceof HacknetServer ? node.hostname : node.name,
level: node.level,
@ -99,7 +99,7 @@ export function NetscriptHacknet(): InternalAPI<IHacknet> {
const i = helpers.number(ctx, "i", _i);
const n = helpers.number(ctx, "n", _n);
const node = getHacknetNode(ctx, i);
return purchaseLevelUpgrade(player, node, n);
return purchaseLevelUpgrade(node, n);
},
upgradeRam:
(ctx: NetscriptContext) =>
@ -107,7 +107,7 @@ export function NetscriptHacknet(): InternalAPI<IHacknet> {
const i = helpers.number(ctx, "i", _i);
const n = helpers.number(ctx, "n", _n);
const node = getHacknetNode(ctx, i);
return purchaseRamUpgrade(player, node, n);
return purchaseRamUpgrade(node, n);
},
upgradeCore:
(ctx: NetscriptContext) =>
@ -115,14 +115,14 @@ export function NetscriptHacknet(): InternalAPI<IHacknet> {
const i = helpers.number(ctx, "i", _i);
const n = helpers.number(ctx, "n", _n);
const node = getHacknetNode(ctx, i);
return purchaseCoreUpgrade(player, node, n);
return purchaseCoreUpgrade(node, n);
},
upgradeCache:
(ctx: NetscriptContext) =>
(_i: unknown, _n: unknown = 1): boolean => {
const i = helpers.number(ctx, "i", _i);
const n = helpers.number(ctx, "n", _n);
if (!hasHacknetServers(player)) {
if (!hasHacknetServers()) {
return false;
}
const node = getHacknetNode(ctx, i);
@ -130,9 +130,9 @@ export function NetscriptHacknet(): InternalAPI<IHacknet> {
helpers.log(ctx, () => "Can only be called on hacknet servers");
return false;
}
const res = purchaseCacheUpgrade(player, node, n);
const res = purchaseCacheUpgrade(node, n);
if (res) {
updateHashManagerCapacity(player);
updateHashManagerCapacity();
}
return res;
},
@ -165,7 +165,7 @@ export function NetscriptHacknet(): InternalAPI<IHacknet> {
(_i: unknown, _n: unknown = 1): number => {
const i = helpers.number(ctx, "i", _i);
const n = helpers.number(ctx, "n", _n);
if (!hasHacknetServers(player)) {
if (!hasHacknetServers()) {
return Infinity;
}
const node = getHacknetNode(ctx, i);
@ -176,13 +176,13 @@ export function NetscriptHacknet(): InternalAPI<IHacknet> {
return node.calculateCacheUpgradeCost(n);
},
numHashes: () => (): number => {
if (!hasHacknetServers(player)) {
if (!hasHacknetServers()) {
return 0;
}
return player.hashManager.hashes;
},
hashCapacity: () => (): number => {
if (!hasHacknetServers(player)) {
if (!hasHacknetServers()) {
return 0;
}
return player.hashManager.capacity;
@ -192,7 +192,7 @@ export function NetscriptHacknet(): InternalAPI<IHacknet> {
(_upgName: unknown, _count: unknown = 1): number => {
const upgName = helpers.string(ctx, "upgName", _upgName);
const count = helpers.number(ctx, "count", _count);
if (!hasHacknetServers(player)) {
if (!hasHacknetServers()) {
return Infinity;
}
@ -204,13 +204,13 @@ export function NetscriptHacknet(): InternalAPI<IHacknet> {
const upgName = helpers.string(ctx, "upgName", _upgName);
const upgTarget = helpers.string(ctx, "upgTarget", _upgTarget);
const count = helpers.number(ctx, "count", _count);
if (!hasHacknetServers(player)) {
if (!hasHacknetServers()) {
return false;
}
return purchaseHashUpgrade(player, upgName, upgTarget, count);
return purchaseHashUpgrade(upgName, upgTarget, count);
},
getHashUpgrades: () => (): string[] => {
if (!hasHacknetServers(player)) {
if (!hasHacknetServers()) {
return [];
}
return Object.values(HashUpgrades).map((upgrade: HashUpgrade) => upgrade.name);
@ -226,13 +226,13 @@ export function NetscriptHacknet(): InternalAPI<IHacknet> {
return level;
},
getStudyMult: () => (): number => {
if (!hasHacknetServers(player)) {
if (!hasHacknetServers()) {
return 1;
}
return player.hashManager.getStudyMult();
},
getTrainingMult: () => (): number => {
if (!hasHacknetServers(player)) {
if (!hasHacknetServers()) {
return 1;
}
return player.hashManager.getTrainingMult();

File diff suppressed because it is too large Load Diff

@ -1,4 +1,4 @@
import { Player as player } from "../Player";
import { Player } from "../Player";
import { findSleevePurchasableAugs } from "../PersonObjects/Sleeve/SleeveHelpers";
import { StaticAugmentations } from "../Augmentation/StaticAugmentations";
import { CityName } from "../Locations/data/CityNames";
@ -21,7 +21,7 @@ import { helpers } from "../Netscript/NetscriptHelpers";
export function NetscriptSleeve(): InternalAPI<ISleeve> {
const checkSleeveAPIAccess = function (ctx: NetscriptContext): void {
if (player.bitNodeN !== 10 && !player.sourceFileLvl(10)) {
if (Player.bitNodeN !== 10 && !Player.sourceFileLvl(10)) {
throw helpers.makeRuntimeErrorMsg(
ctx,
"You do not currently have access to the Sleeve API. This is either because you are not in BitNode-10 or because you do not have Source-File 10",
@ -30,7 +30,7 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
};
const checkSleeveNumber = function (ctx: NetscriptContext, sleeveNumber: number): void {
if (sleeveNumber >= player.sleeves.length || sleeveNumber < 0) {
if (sleeveNumber >= Player.sleeves.length || sleeveNumber < 0) {
const msg = `Invalid sleeve number: ${sleeveNumber}`;
helpers.log(ctx, () => msg);
throw helpers.makeRuntimeErrorMsg(ctx, msg);
@ -38,7 +38,7 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
};
const getSleeveStats = function (sleeveNumber: number): SleeveSkills {
const sl = player.sleeves[sleeveNumber];
const sl = Player.sleeves[sleeveNumber];
return {
shock: 100 - sl.shock,
sync: sl.sync,
@ -55,7 +55,7 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
return {
getNumSleeves: (ctx: NetscriptContext) => (): number => {
checkSleeveAPIAccess(ctx);
return player.sleeves.length;
return Player.sleeves.length;
},
setToShockRecovery:
(ctx: NetscriptContext) =>
@ -63,7 +63,7 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
return player.sleeves[sleeveNumber].shockRecovery(player);
return Player.sleeves[sleeveNumber].shockRecovery();
},
setToSynchronize:
(ctx: NetscriptContext) =>
@ -71,7 +71,7 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
return player.sleeves[sleeveNumber].synchronize(player);
return Player.sleeves[sleeveNumber].synchronize();
},
setToCommitCrime:
(ctx: NetscriptContext) =>
@ -84,7 +84,7 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
if (crime === null) {
return false;
}
return player.sleeves[sleeveNumber].commitCrime(player, crime.name);
return Player.sleeves[sleeveNumber].commitCrime(crime.name);
},
setToUniversityCourse:
(ctx: NetscriptContext) =>
@ -94,7 +94,7 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
const className = helpers.string(ctx, "className", _className);
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
return player.sleeves[sleeveNumber].takeUniversityCourse(player, universityName, className);
return Player.sleeves[sleeveNumber].takeUniversityCourse(universityName, className);
},
travel:
(ctx: NetscriptContext) =>
@ -104,7 +104,7 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
if (checkEnum(CityName, cityName)) {
return player.sleeves[sleeveNumber].travel(player, cityName);
return Player.sleeves[sleeveNumber].travel(cityName);
} else {
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid city name: '${cityName}'.`);
}
@ -118,11 +118,11 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
checkSleeveNumber(ctx, sleeveNumber);
// Cannot work at the same company that another sleeve is working at
for (let i = 0; i < player.sleeves.length; ++i) {
for (let i = 0; i < Player.sleeves.length; ++i) {
if (i === sleeveNumber) {
continue;
}
const other = player.sleeves[i];
const other = Player.sleeves[i];
if (isSleeveCompanyWork(other.currentWork) && other.currentWork.companyName === companyName) {
throw helpers.makeRuntimeErrorMsg(
ctx,
@ -131,7 +131,7 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
}
}
return player.sleeves[sleeveNumber].workForCompany(player, companyName);
return Player.sleeves[sleeveNumber].workForCompany(companyName);
},
setToFactionWork:
(ctx: NetscriptContext) =>
@ -143,11 +143,11 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
checkSleeveNumber(ctx, sleeveNumber);
// Cannot work at the same faction that another sleeve is working at
for (let i = 0; i < player.sleeves.length; ++i) {
for (let i = 0; i < Player.sleeves.length; ++i) {
if (i === sleeveNumber) {
continue;
}
const other = player.sleeves[i];
const other = Player.sleeves[i];
if (isSleeveFactionWork(other.currentWork) && other.currentWork.factionName === factionName) {
throw helpers.makeRuntimeErrorMsg(
ctx,
@ -156,14 +156,14 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
}
}
if (player.gang && player.gang.facName == factionName) {
if (Player.gang && Player.gang.facName == factionName) {
throw helpers.makeRuntimeErrorMsg(
ctx,
`Sleeve ${sleeveNumber} cannot work for faction ${factionName} because you have started a gang with them.`,
);
}
return player.sleeves[sleeveNumber].workForFaction(player, factionName, workType);
return Player.sleeves[sleeveNumber].workForFaction(factionName, workType);
},
setToGymWorkout:
(ctx: NetscriptContext) =>
@ -174,7 +174,7 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
return player.sleeves[sleeveNumber].workoutAtGym(player, gymName, stat);
return Player.sleeves[sleeveNumber].workoutAtGym(gymName, stat);
},
getSleeveStats:
(ctx: NetscriptContext) =>
@ -191,7 +191,7 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
const sl = player.sleeves[sleeveNumber];
const sl = Player.sleeves[sleeveNumber];
if (sl.currentWork === null) return null;
return sl.currentWork.APICopy();
},
@ -202,13 +202,13 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
const sl = player.sleeves[sleeveNumber];
const sl = Player.sleeves[sleeveNumber];
return {
tor: false,
city: sl.city,
hp: sl.hp,
jobs: Object.keys(player.jobs), // technically sleeves have the same jobs as the player.
jobTitle: Object.values(player.jobs),
jobs: Object.keys(Player.jobs), // technically sleeves have the same jobs as the player.
jobTitle: Object.values(Player.jobs),
mult: {
agility: sl.mults.agility,
@ -239,8 +239,8 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
checkSleeveNumber(ctx, sleeveNumber);
const augs = [];
for (let i = 0; i < player.sleeves[sleeveNumber].augmentations.length; i++) {
augs.push(player.sleeves[sleeveNumber].augmentations[i].name);
for (let i = 0; i < Player.sleeves[sleeveNumber].augmentations.length; i++) {
augs.push(Player.sleeves[sleeveNumber].augmentations[i].name);
}
return augs;
},
@ -251,7 +251,7 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber);
const purchasableAugs = findSleevePurchasableAugs(player.sleeves[sleeveNumber], player);
const purchasableAugs = findSleevePurchasableAugs(Player.sleeves[sleeveNumber]);
const augs = [];
for (let i = 0; i < purchasableAugs.length; i++) {
const aug = purchasableAugs[i];
@ -280,7 +280,7 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid aug: ${augName}`);
}
return player.sleeves[sleeveNumber].tryBuyAugmentation(player, aug);
return Player.sleeves[sleeveNumber].tryBuyAugmentation(aug);
},
getSleeveAugmentationPrice:
(ctx: NetscriptContext) =>
@ -296,7 +296,7 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
checkSleeveAPIAccess(ctx);
const augName = helpers.string(ctx, "augName", _augName);
const aug: Augmentation = StaticAugmentations[augName];
return aug.getCost(player).repCost;
return aug.getCost().repCost;
},
setToBladeburnerAction:
(ctx: NetscriptContext) =>
@ -314,11 +314,11 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
// Cannot Take on Contracts if another sleeve is performing that action
if (action === "Take on contracts") {
for (let i = 0; i < player.sleeves.length; ++i) {
for (let i = 0; i < Player.sleeves.length; ++i) {
if (i === sleeveNumber) {
continue;
}
const other = player.sleeves[i];
const other = Player.sleeves[i];
if (isSleeveBladeburnerWork(other.currentWork) && other.currentWork.actionName === contract) {
throw helpers.makeRuntimeErrorMsg(
ctx,
@ -328,7 +328,7 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
}
}
return player.sleeves[sleeveNumber].bladeburner(player, action, contract);
return Player.sleeves[sleeveNumber].bladeburner(action, contract);
},
};
}

@ -1,47 +1,47 @@
import { CONSTANTS } from "../../Constants";
import { IPlayer } from "../IPlayer";
import { Player } from "../../Player";
import { Multipliers } from "../Multipliers";
export const calculateEntropy = (player: IPlayer, stacks = 1): Multipliers => {
export const calculateEntropy = (stacks = 1): Multipliers => {
const nerf = CONSTANTS.EntropyEffect ** stacks;
return {
hacking_chance: player.mults.hacking_chance * nerf,
hacking_speed: player.mults.hacking_speed * nerf,
hacking_money: player.mults.hacking_money * nerf,
hacking_grow: player.mults.hacking_grow * nerf,
hacking_chance: Player.mults.hacking_chance * nerf,
hacking_speed: Player.mults.hacking_speed * nerf,
hacking_money: Player.mults.hacking_money * nerf,
hacking_grow: Player.mults.hacking_grow * nerf,
hacking: player.mults.hacking * nerf,
strength: player.mults.strength * nerf,
defense: player.mults.defense * nerf,
dexterity: player.mults.dexterity * nerf,
agility: player.mults.agility * nerf,
charisma: player.mults.charisma * nerf,
hacking: Player.mults.hacking * nerf,
strength: Player.mults.strength * nerf,
defense: Player.mults.defense * nerf,
dexterity: Player.mults.dexterity * nerf,
agility: Player.mults.agility * nerf,
charisma: Player.mults.charisma * nerf,
hacking_exp: player.mults.hacking_exp * nerf,
strength_exp: player.mults.strength_exp * nerf,
defense_exp: player.mults.defense_exp * nerf,
dexterity_exp: player.mults.dexterity_exp * nerf,
agility_exp: player.mults.agility_exp * nerf,
charisma_exp: player.mults.charisma_exp * nerf,
hacking_exp: Player.mults.hacking_exp * nerf,
strength_exp: Player.mults.strength_exp * nerf,
defense_exp: Player.mults.defense_exp * nerf,
dexterity_exp: Player.mults.dexterity_exp * nerf,
agility_exp: Player.mults.agility_exp * nerf,
charisma_exp: Player.mults.charisma_exp * nerf,
company_rep: player.mults.company_rep * nerf,
faction_rep: player.mults.faction_rep * nerf,
company_rep: Player.mults.company_rep * nerf,
faction_rep: Player.mults.faction_rep * nerf,
crime_money: player.mults.crime_money * nerf,
crime_success: player.mults.crime_success * nerf,
crime_money: Player.mults.crime_money * nerf,
crime_success: Player.mults.crime_success * nerf,
hacknet_node_money: player.mults.hacknet_node_money * nerf,
hacknet_node_purchase_cost: player.mults.hacknet_node_purchase_cost * nerf,
hacknet_node_ram_cost: player.mults.hacknet_node_ram_cost * nerf,
hacknet_node_core_cost: player.mults.hacknet_node_core_cost * nerf,
hacknet_node_level_cost: player.mults.hacknet_node_level_cost * nerf,
hacknet_node_money: Player.mults.hacknet_node_money * nerf,
hacknet_node_purchase_cost: Player.mults.hacknet_node_purchase_cost * nerf,
hacknet_node_ram_cost: Player.mults.hacknet_node_ram_cost * nerf,
hacknet_node_core_cost: Player.mults.hacknet_node_core_cost * nerf,
hacknet_node_level_cost: Player.mults.hacknet_node_level_cost * nerf,
work_money: player.mults.work_money * nerf,
work_money: Player.mults.work_money * nerf,
bladeburner_max_stamina: player.mults.bladeburner_max_stamina * nerf,
bladeburner_stamina_gain: player.mults.bladeburner_stamina_gain * nerf,
bladeburner_analysis: player.mults.bladeburner_analysis * nerf,
bladeburner_success_chance: player.mults.bladeburner_success_chance * nerf,
bladeburner_max_stamina: Player.mults.bladeburner_max_stamina * nerf,
bladeburner_stamina_gain: Player.mults.bladeburner_stamina_gain * nerf,
bladeburner_analysis: Player.mults.bladeburner_analysis * nerf,
bladeburner_success_chance: Player.mults.bladeburner_success_chance * nerf,
};
};

@ -1,8 +1,8 @@
import { StaticAugmentations } from "../../Augmentation/StaticAugmentations";
import { GraftableAugmentation } from "./GraftableAugmentation";
import { IPlayer } from "../IPlayer";
import { Player } from "../../Player";
export const getGraftingAvailableAugs = (player: IPlayer): string[] => {
export const getGraftingAvailableAugs = (): string[] => {
const augs: string[] = [];
for (const [augName, aug] of Object.entries(StaticAugmentations)) {
@ -10,14 +10,14 @@ export const getGraftingAvailableAugs = (player: IPlayer): string[] => {
augs.push(augName);
}
return augs.filter((augmentation: string) => !player.hasAugmentation(augmentation));
return augs.filter((augmentation: string) => !Player.hasAugmentation(augmentation));
};
export const graftingIntBonus = (player: IPlayer): number => {
return 1 + (player.getIntelligenceBonus(3) - 1) / 3;
export const graftingIntBonus = (): number => {
return 1 + (Player.getIntelligenceBonus(3) - 1) / 3;
};
export const calculateGraftingTimeWithBonus = (player: IPlayer, aug: GraftableAugmentation): number => {
export const calculateGraftingTimeWithBonus = (aug: GraftableAugmentation): number => {
const baseTime = aug.time;
return baseTime / graftingIntBonus(player);
return baseTime / graftingIntBonus();
};

@ -11,11 +11,11 @@ import { LocationName } from "../../../Locations/data/LocationNames";
import { Locations } from "../../../Locations/Locations";
import { PurchaseAugmentationsOrderSetting } from "../../../Settings/SettingEnums";
import { Settings } from "../../../Settings/Settings";
import { use } from "../../../ui/Context";
import { Router } from "../../../ui/GameRoot";
import { ConfirmationModal } from "../../../ui/React/ConfirmationModal";
import { Money } from "../../../ui/React/Money";
import { convertTimeMsToTimeElapsedString, formatNumber } from "../../../utils/StringHelperFunctions";
import { IPlayer } from "../../IPlayer";
import { Player } from "../../../Player";
import { GraftableAugmentation } from "../GraftableAugmentation";
import { calculateGraftingTimeWithBonus, getGraftingAvailableAugs } from "../GraftingHelpers";
@ -29,21 +29,19 @@ export const GraftableAugmentations = (): Record<string, GraftableAugmentation>
return gAugs;
};
const canGraft = (player: IPlayer, aug: GraftableAugmentation): boolean => {
if (player.money < aug.cost) {
const canGraft = (aug: GraftableAugmentation): boolean => {
if (Player.money < aug.cost) {
return false;
}
return hasAugmentationPrereqs(aug.augmentation);
};
interface IProps {
player: IPlayer;
aug: Augmentation;
}
const AugPreReqsChecklist = (props: IProps): React.ReactElement => {
const aug = props.aug,
player = props.player;
const aug = props.aug;
return (
<Typography color={Settings.theme.money}>
@ -51,7 +49,7 @@ const AugPreReqsChecklist = (props: IProps): React.ReactElement => {
<br />
{aug.prereqs.map((preAug) => (
<span style={{ display: "flex", alignItems: "center" }}>
{player.hasAugmentation(preAug) ? <CheckBox sx={{ mr: 1 }} /> : <CheckBoxOutlineBlank sx={{ mr: 1 }} />}
{Player.hasAugmentation(preAug) ? <CheckBox sx={{ mr: 1 }} /> : <CheckBoxOutlineBlank sx={{ mr: 1 }} />}
{preAug}
</span>
))}
@ -60,12 +58,9 @@ const AugPreReqsChecklist = (props: IProps): React.ReactElement => {
};
export const GraftingRoot = (): React.ReactElement => {
const player = use.Player();
const router = use.Router();
const graftableAugmentations = useState(GraftableAugmentations())[0];
const [selectedAug, setSelectedAug] = useState(getGraftingAvailableAugs(player)[0]);
const [selectedAug, setSelectedAug] = useState(getGraftingAvailableAugs()[0]);
const [graftOpen, setGraftOpen] = useState(false);
const selectedAugmentation = StaticAugmentations[selectedAug];
@ -75,7 +70,7 @@ export const GraftingRoot = (): React.ReactElement => {
}
const getAugsSorted = (): string[] => {
const augs = getGraftingAvailableAugs(player);
const augs = getGraftingAvailableAugs();
switch (Settings.PurchaseAugmentationsOrder) {
case PurchaseAugmentationsOrderSetting.Cost:
return augs.sort((a, b) => graftableAugmentations[a].cost - graftableAugmentations[b].cost);
@ -96,7 +91,7 @@ export const GraftingRoot = (): React.ReactElement => {
return (
<Container disableGutters maxWidth="lg" sx={{ mx: 0 }}>
<Button onClick={() => router.toLocation(Locations[LocationName.NewTokyoVitaLife])}>Back</Button>
<Button onClick={() => Router.toLocation(Locations[LocationName.NewTokyoVitaLife])}>Back</Button>
<Typography variant="h4">Grafting Laboratory</Typography>
<Typography>
You find yourself in a secret laboratory, owned by a mysterious researcher.
@ -122,14 +117,14 @@ export const GraftingRoot = (): React.ReactElement => {
</Button>
</Box>
</Paper>
{getGraftingAvailableAugs(player).length > 0 ? (
{getGraftingAvailableAugs().length > 0 ? (
<Paper sx={{ mb: 1, width: "fit-content", display: "grid", gridTemplateColumns: "1fr 3fr" }}>
<List sx={{ height: 400, overflowY: "scroll", borderRight: `1px solid ${Settings.theme.welllight}` }}>
{getAugsSorted().map((k, i) => (
<ListItemButton key={i + 1} onClick={() => setSelectedAug(k)} selected={selectedAug === k}>
<Typography
sx={{
color: canGraft(player, graftableAugmentations[k])
color: canGraft(graftableAugmentations[k])
? Settings.theme.primary
: Settings.theme.disabled,
}}
@ -146,11 +141,11 @@ export const GraftingRoot = (): React.ReactElement => {
<Button
onClick={() => setGraftOpen(true)}
sx={{ width: "100%" }}
disabled={!canGraft(player, graftableAugmentations[selectedAug])}
disabled={!canGraft(graftableAugmentations[selectedAug])}
>
Graft Augmentation (
<Typography>
<Money money={graftableAugmentations[selectedAug].cost} player={player} />
<Money money={graftableAugmentations[selectedAug].cost} forPurchase={true} />
</Typography>
)
</Button>
@ -158,21 +153,20 @@ export const GraftingRoot = (): React.ReactElement => {
open={graftOpen}
onClose={() => setGraftOpen(false)}
onConfirm={() => {
player.startWork(
Player.startWork(
new GraftingWork({
augmentation: selectedAug,
singularity: false,
player: player,
}),
);
player.startFocusing();
router.toWork();
Player.startFocusing();
Router.toWork();
}}
confirmationText={
<>
Cancelling grafting will <b>not</b> save grafting progress, and the money you spend will <b>not</b>{" "}
be returned.
{!player.hasAugmentation(AugmentationNames.CongruityImplant) && (
{!Player.hasAugmentation(AugmentationNames.CongruityImplant) && (
<>
<br />
<br />
@ -186,14 +180,12 @@ export const GraftingRoot = (): React.ReactElement => {
<Typography color={Settings.theme.info}>
<b>Time to Graft:</b>{" "}
{convertTimeMsToTimeElapsedString(
calculateGraftingTimeWithBonus(player, graftableAugmentations[selectedAug]),
calculateGraftingTimeWithBonus(graftableAugmentations[selectedAug]),
)}
{/* Use formula so the displayed creation time is accurate to player bonus */}
</Typography>
{selectedAugmentation.prereqs.length > 0 && (
<AugPreReqsChecklist player={player} aug={selectedAugmentation} />
)}
{selectedAugmentation.prereqs.length > 0 && <AugPreReqsChecklist aug={selectedAugmentation} />}
<br />
@ -229,10 +221,10 @@ export const GraftingRoot = (): React.ReactElement => {
<Paper sx={{ my: 1, p: 1, width: "fit-content" }}>
<Typography>
<b>Entropy strength:</b> {player.entropy}
<b>Entropy strength:</b> {Player.entropy}
<br />
<b>All multipliers decreased by:</b>{" "}
{formatNumber((1 - CONSTANTS.EntropyEffect ** player.entropy) * 100, 3)}% (multiplicative)
{formatNumber((1 - CONSTANTS.EntropyEffect ** Player.entropy) * 100, 3)}% (multiplicative)
</Typography>
</Paper>

@ -32,5 +32,5 @@ export function applyEntropy(this: IPlayer, stacks = 1): void {
this.reapplyAllAugmentations();
this.reapplyAllSourceFiles();
this.mults = calculateEntropy(this, stacks);
this.mults = calculateEntropy(stacks);
}

Some files were not shown because too many files have changed in this diff Show More