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
@@ -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();
};
+21 -29
View File
@@ -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);
}
@@ -13,5 +13,5 @@ export function inBladeburner(this: IPlayer): boolean {
}
export function startBladeburner(this: IPlayer): void {
this.bladeburner = new Bladeburner(this);
this.bladeburner = new Bladeburner();
}
@@ -112,15 +112,15 @@ export function prestigeAugmentation(this: PlayerObject): void {
const numSleeves = Math.min(3, this.sourceFileLvl(10) + (this.bitNodeN === 10 ? 1 : 0)) + this.sleevesFromCovenant;
if (this.sleeves.length > numSleeves) this.sleeves.length = numSleeves;
for (let i = this.sleeves.length; i < numSleeves; i++) {
this.sleeves.push(new Sleeve(this));
this.sleeves.push(new Sleeve());
}
for (let i = 0; i < this.sleeves.length; ++i) {
if (this.sleeves[i] instanceof Sleeve) {
if (this.sleeves[i].shock >= 100) {
this.sleeves[i].synchronize(this);
this.sleeves[i].synchronize();
} else {
this.sleeves[i].shockRecovery(this);
this.sleeves[i].shockRecovery();
}
}
}
@@ -149,9 +149,9 @@ export function prestigeSourceFile(this: IPlayer): void {
// Duplicate sleeves are reset to level 1 every Bit Node (but the number of sleeves you have persists)
for (let i = 0; i < this.sleeves.length; ++i) {
if (this.sleeves[i] instanceof Sleeve) {
this.sleeves[i].prestige(this);
this.sleeves[i].prestige();
} else {
this.sleeves[i] = new Sleeve(this);
this.sleeves[i] = new Sleeve();
}
}
@@ -490,7 +490,7 @@ export function regenerateHp(this: IPerson, amt: number): void {
}
export function hospitalize(this: IPlayer): number {
const cost = getHospitalizationCost(this);
const cost = getHospitalizationCost();
SnackbarEvents.emit(`You've been Hospitalized for ${numeralWrapper.formatMoney(cost)}`, ToastVariant.WARNING, 2000);
this.loseMoney(cost, "hospitalization");
@@ -596,7 +596,7 @@ export function quitJob(this: IPlayer, company: string): void {
}
for (const sleeve of this.sleeves) {
if (isSleeveCompanyWork(sleeve.currentWork) && sleeve.currentWork.companyName === company) {
sleeve.stopWork(this);
sleeve.stopWork();
dialogBoxCreate(`You quit ${company} while one of your sleeves was working there. The sleeve is now idle.`);
}
}
@@ -3,20 +3,20 @@ import { IPlayer } from "../IPlayer";
export function start(this: IPlayer, w: Work): void {
if (this.currentWork !== null) {
this.currentWork.finish(this, true);
this.currentWork.finish(true);
}
this.currentWork = w;
}
export function process(this: IPlayer, cycles = 1): void {
if (this.currentWork === null) return;
const finished = this.currentWork.process(this, cycles);
const finished = this.currentWork.process(cycles);
if (finished) {
this.finishWork(false);
}
}
export function finish(this: IPlayer, cancelled: boolean): void {
if (this.currentWork === null) return;
this.currentWork.finish(this, cancelled);
this.currentWork.finish(cancelled);
this.currentWork = null;
this.focus = false;
}
+45 -48
View File
@@ -7,7 +7,7 @@
* Sleeves are unlocked in BitNode-10.
*/
import { IPlayer } from "../IPlayer";
import { Player } from "../../Player";
import { Person } from "../Person";
import { Augmentation } from "../../Augmentation/Augmentation";
@@ -74,11 +74,9 @@ export class Sleeve extends Person {
*/
sync = 1;
constructor(p: IPlayer | null = null) {
constructor() {
super();
if (p != null) {
this.shockRecovery(p);
}
this.shockRecovery();
}
shockBonus(): number {
@@ -89,26 +87,26 @@ export class Sleeve extends Person {
return this.sync / 100;
}
startWork(player: IPlayer, w: Work): void {
if (this.currentWork) this.currentWork.finish(player);
startWork(w: Work): void {
if (this.currentWork) this.currentWork.finish();
this.currentWork = w;
}
stopWork(player: IPlayer): void {
if (this.currentWork) this.currentWork.finish(player);
stopWork(): void {
if (this.currentWork) this.currentWork.finish();
this.currentWork = null;
}
/**
* Commit crimes
*/
commitCrime(p: IPlayer, crimeKey: string): boolean {
commitCrime(crimeKey: string): boolean {
const crime: Crime | null = Crimes[crimeKey] || Object.values(Crimes).find((crime) => crime.name === crimeKey);
if (!crime) {
return false;
}
this.startWork(p, new SleeveCrimeWork(crime.type));
this.startWork(new SleeveCrimeWork(crime.type));
return true;
}
@@ -152,7 +150,7 @@ export class Sleeve extends Person {
/**
* Called on every sleeve for a Source File Prestige
*/
prestige(p: IPlayer): void {
prestige(): void {
// Reset exp
this.exp.hacking = 0;
this.exp.strength = 0;
@@ -164,8 +162,8 @@ export class Sleeve extends Person {
this.hp.current = this.hp.max;
// Reset task-related stuff
this.stopWork(p);
this.shockRecovery(p);
this.stopWork();
this.shockRecovery();
// Reset augs and multipliers
this.augmentations = [];
@@ -186,7 +184,7 @@ export class Sleeve extends Person {
* Returns an object containing the amount of experience that should be
* transferred to all other sleeves
*/
process(p: IPlayer, numCycles = 1): void {
process(numCycles = 1): void {
// Only process once every second (5 cycles)
const CyclesPerSecond = 1000 / CONSTANTS.MilliPerCycle;
this.storedCycles += numCycles;
@@ -196,24 +194,24 @@ export class Sleeve extends Person {
cyclesUsed = Math.min(cyclesUsed, 15);
this.shock = Math.min(100, this.shock + 0.0001 * cyclesUsed);
if (!this.currentWork) return;
this.currentWork.process(p, this, cyclesUsed);
this.currentWork.process(this, cyclesUsed);
this.storedCycles -= cyclesUsed;
}
shockRecovery(p: IPlayer): boolean {
this.startWork(p, new SleeveRecoveryWork());
shockRecovery(): boolean {
this.startWork(new SleeveRecoveryWork());
return true;
}
synchronize(p: IPlayer): boolean {
this.startWork(p, new SleeveSynchroWork());
synchronize(): boolean {
this.startWork(new SleeveSynchroWork());
return true;
}
/**
* Take a course at a university
*/
takeUniversityCourse(p: IPlayer, universityName: string, className: string): boolean {
takeUniversityCourse(universityName: string, className: string): boolean {
// Set exp/money multipliers based on which university.
// Also check that the sleeve is in the right city
let loc: LocationName | undefined;
@@ -261,7 +259,6 @@ export class Sleeve extends Person {
if (!classType) return false;
this.startWork(
p,
new SleeveClassWork({
classType: classType,
location: loc,
@@ -273,8 +270,8 @@ export class Sleeve extends Person {
/**
* Travel to another City. Costs money from player
*/
travel(p: IPlayer, newCity: CityName): boolean {
p.loseMoney(CONSTANTS.TravelCost, "sleeves");
travel(newCity: CityName): boolean {
Player.loseMoney(CONSTANTS.TravelCost, "sleeves");
this.city = newCity;
return true;
@@ -284,13 +281,15 @@ export class Sleeve extends Person {
return this.augmentations.some((a) => a.name === aug);
}
tryBuyAugmentation(p: IPlayer, aug: Augmentation): boolean {
if (!p.canAfford(aug.baseCost)) return false;
tryBuyAugmentation(aug: Augmentation): boolean {
if (!Player.canAfford(aug.baseCost)) {
return false;
}
// Verify that this sleeve does not already have that augmentation.
if (this.hasAugmentation(aug.name)) return false;
p.loseMoney(aug.baseCost, "sleeves");
Player.loseMoney(aug.baseCost, "sleeves");
this.installAugmentation(aug);
return true;
}
@@ -303,17 +302,17 @@ export class Sleeve extends Person {
* Start work for one of the player's companies
* Returns boolean indicating success
*/
workForCompany(p: IPlayer, companyName: string): boolean {
if (!(Companies[companyName] instanceof Company) || p.jobs[companyName] == null) {
workForCompany(companyName: string): boolean {
if (!(Companies[companyName] instanceof Company) || Player.jobs[companyName] == null) {
return false;
}
const company: Company | null = Companies[companyName];
const companyPosition: CompanyPosition | null = CompanyPositions[p.jobs[companyName]];
const companyPosition: CompanyPosition | null = CompanyPositions[Player.jobs[companyName]];
if (company == null) return false;
if (companyPosition == null) return false;
this.startWork(p, new SleeveCompanyWork({ companyName: companyName }));
this.startWork(new SleeveCompanyWork({ companyName: companyName }));
return true;
}
@@ -322,9 +321,9 @@ export class Sleeve extends Person {
* Start work for one of the player's factions
* Returns boolean indicating success
*/
workForFaction(p: IPlayer, factionName: string, workType: string): boolean {
workForFaction(factionName: string, workType: string): boolean {
const faction = Factions[factionName];
if (factionName === "" || !faction || !(faction instanceof Faction) || !p.factions.includes(factionName)) {
if (factionName === "" || !faction || !(faction instanceof Faction) || !Player.factions.includes(factionName)) {
return false;
}
@@ -347,7 +346,6 @@ export class Sleeve extends Person {
}
this.startWork(
p,
new SleeveFactionWork({
factionWorkType: factionWorkType,
factionName: faction.name,
@@ -360,7 +358,7 @@ export class Sleeve extends Person {
/**
* Begin a gym workout task
*/
workoutAtGym(p: IPlayer, gymName: string, stat: string): boolean {
workoutAtGym(gymName: string, stat: string): boolean {
// Set exp/money multipliers based on which university.
// Also check that the sleeve is in the right city
let loc: LocationName | undefined;
@@ -414,7 +412,6 @@ export class Sleeve extends Person {
if (!classType) return false;
this.startWork(
p,
new SleeveClassWork({
classType: classType,
location: loc,
@@ -427,41 +424,41 @@ export class Sleeve extends Person {
/**
* Begin a bladeburner task
*/
bladeburner(p: IPlayer, action: string, contract: string): boolean {
bladeburner(action: string, contract: string): boolean {
switch (action) {
case "Field analysis":
this.startWork(p, new SleeveBladeburnerWork({ type: "General", name: "Field Analysis" }));
this.startWork(new SleeveBladeburnerWork({ type: "General", name: "Field Analysis" }));
return true;
case "Recruitment":
this.startWork(p, new SleeveBladeburnerWork({ type: "General", name: "Recruitment" }));
this.startWork(new SleeveBladeburnerWork({ type: "General", name: "Recruitment" }));
return true;
case "Diplomacy":
this.startWork(p, new SleeveBladeburnerWork({ type: "General", name: "Diplomacy" }));
this.startWork(new SleeveBladeburnerWork({ type: "General", name: "Diplomacy" }));
return true;
case "Hyperbolic Regeneration Chamber":
this.startWork(p, new SleeveBladeburnerWork({ type: "General", name: "Hyperbolic Regeneration Chamber" }));
this.startWork(new SleeveBladeburnerWork({ type: "General", name: "Hyperbolic Regeneration Chamber" }));
return true;
case "Infiltrate synthoids":
this.startWork(p, new SleeveInfiltrateWork());
this.startWork(new SleeveInfiltrateWork());
return true;
case "Support main sleeve":
this.startWork(p, new SleeveSupportWork(p));
this.startWork(new SleeveSupportWork());
return true;
case "Take on contracts":
if (!Contracts[contract]) return false;
this.startWork(p, new SleeveBladeburnerWork({ type: "Contracts", name: contract }));
this.startWork(new SleeveBladeburnerWork({ type: "Contracts", name: contract }));
return true;
}
return false;
}
recruitmentSuccessChance(p: IPlayer): number {
return Math.max(0, Math.min(1, p.bladeburner?.getRecruitmentSuccessChance(this) ?? 0));
recruitmentSuccessChance(): number {
return Math.max(0, Math.min(1, Player.bladeburner?.getRecruitmentSuccessChance(this) ?? 0));
}
contractSuccessChance(p: IPlayer, type: string, name: string): string {
const bb = p.bladeburner;
contractSuccessChance(type: string, name: string): string {
const bb = Player.bladeburner;
if (bb === null) {
const errorLogText = `bladeburner is null`;
console.error(`Function: sleeves.contractSuccessChance; Message: '${errorLogText}'`);
+7 -8
View File
@@ -1,7 +1,6 @@
import { FactionNames } from "../../Faction/data/FactionNames";
import { Sleeve } from "./Sleeve";
import { IPlayer } from "../IPlayer";
import { Player } from "../../Player";
import { Augmentation } from "../../Augmentation/Augmentation";
@@ -11,7 +10,7 @@ import { Multipliers } from "../Multipliers";
import { AugmentationNames } from "../../Augmentation/data/AugmentationNames";
import { getFactionAugmentationsFiltered } from "../../Faction/FactionHelpers";
export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentation[] {
export function findSleevePurchasableAugs(sleeve: Sleeve): Augmentation[] {
// You can only purchase Augmentations that are actually available from
// your factions. I.e. you must be in a faction that has the Augmentation
// and you must also have enough rep in that faction in order to purchase it.
@@ -55,21 +54,21 @@ export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentat
// If player is in a gang, then we return all augs that the player
// has enough reputation for (since that gang offers all augs)
if (p.inGang()) {
const fac = p.getGangFaction();
const gangAugs = getFactionAugmentationsFiltered(Player, fac);
if (Player.inGang()) {
const fac = Player.getGangFaction();
const gangAugs = getFactionAugmentationsFiltered(fac);
for (const augName of gangAugs) {
const aug = StaticAugmentations[augName];
if (!isAvailableForSleeve(aug)) continue;
if (fac.playerReputation > aug.getCost(p).repCost) {
if (fac.playerReputation > aug.getCost().repCost) {
availableAugs.push(aug);
}
}
}
for (const facName of p.factions) {
for (const facName of Player.factions) {
if (facName === FactionNames.Bladeburners) continue;
if (facName === FactionNames.Netburners) continue;
const fac = Factions[facName];
@@ -79,7 +78,7 @@ export function findSleevePurchasableAugs(sleeve: Sleeve, p: IPlayer): Augmentat
const aug = StaticAugmentations[augName];
if (!isAvailableForSleeve(aug)) continue;
if (fac.playerReputation > aug.getCost(p).repCost) {
if (fac.playerReputation > aug.getCost().repCost) {
availableAugs.push(aug);
}
}
@@ -1,4 +1,4 @@
import { IPlayer } from "../../IPlayer";
import { Player } from "../../../Player";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver";
import { Sleeve } from "../Sleeve";
import { applySleeveGains, Work, WorkType } from "./Work";
@@ -25,45 +25,45 @@ export class SleeveBladeburnerWork extends Work {
this.actionName = params?.name ?? "Field analysis";
}
cyclesNeeded(player: IPlayer, sleeve: Sleeve): number {
const ret = player.bladeburner?.getActionTimeNetscriptFn(sleeve, this.actionType, this.actionName);
cyclesNeeded(sleeve: Sleeve): number {
const ret = Player.bladeburner?.getActionTimeNetscriptFn(sleeve, this.actionType, this.actionName);
if (!ret || typeof ret === "string") throw new Error(`Error querying ${this.actionName} time`);
return ret / CONSTANTS._idleSpeed;
}
process(player: IPlayer, sleeve: Sleeve, cycles: number): number {
if (!player.bladeburner) throw new Error("sleeve doing blade work without being a member");
process(sleeve: Sleeve, cycles: number): number {
if (!Player.bladeburner) throw new Error("sleeve doing blade work without being a member");
this.cyclesWorked += cycles;
const actionIdent = player.bladeburner.getActionIdFromTypeAndName(this.actionType, this.actionName);
const actionIdent = Player.bladeburner.getActionIdFromTypeAndName(this.actionType, this.actionName);
if (!actionIdent) throw new Error(`Error getting ${this.actionName} action`);
if (this.actionType === "Contracts") {
const action = player.bladeburner.getActionObject(actionIdent);
const action = Player.bladeburner.getActionObject(actionIdent);
if (!action) throw new Error(`Error getting ${this.actionName} action object`);
if (action.count <= 0) {
sleeve.stopWork(player);
sleeve.stopWork();
return 0;
}
}
while (this.cyclesWorked > this.cyclesNeeded(player, sleeve)) {
while (this.cyclesWorked > this.cyclesNeeded(sleeve)) {
if (this.actionType === "Contracts") {
const action = player.bladeburner.getActionObject(actionIdent);
const action = Player.bladeburner.getActionObject(actionIdent);
if (!action) throw new Error(`Error getting ${this.actionName} action object`);
if (action.count <= 0) {
sleeve.stopWork(player);
sleeve.stopWork();
return 0;
}
}
const retValue = player.bladeburner.completeAction(player, sleeve, actionIdent, false);
const retValue = Player.bladeburner.completeAction(sleeve, actionIdent, false);
let exp: WorkStats | undefined;
if (this.actionType === "General") {
exp = GeneralActions[this.actionName]?.exp;
if (!exp) throw new Error(`Somehow there was no exp for action ${this.actionType} ${this.actionName}`);
applySleeveGains(player, sleeve, exp, 1);
applySleeveGains(sleeve, exp, 1);
}
player.gainMoney(retValue.money, "sleeves");
player.gainStats(retValue);
this.cyclesWorked -= this.cyclesNeeded(player, sleeve);
Player.gainMoney(retValue.money, "sleeves");
Player.gainStats(retValue);
this.cyclesWorked -= this.cyclesNeeded(sleeve);
}
return 0;
}
@@ -24,9 +24,9 @@ export class SleeveClassWork extends Work {
this.location = params?.location ?? LocationName.Sector12RothmanUniversity;
}
calculateRates(player: IPlayer, sleeve: Sleeve): WorkStats {
calculateRates(sleeve: Sleeve): WorkStats {
return scaleWorkStats(
calculateClassEarnings(player, sleeve, this.classType, this.location),
calculateClassEarnings(sleeve, this.classType, this.location),
sleeve.shockBonus(),
false,
);
@@ -38,9 +38,9 @@ export class SleeveClassWork extends Work {
);
}
process(player: IPlayer, sleeve: Sleeve, cycles: number): number {
const rate = this.calculateRates(player, sleeve);
applySleeveGains(player, sleeve, rate, cycles);
process(sleeve: Sleeve, cycles: number): number {
const rate = this.calculateRates(sleeve);
applySleeveGains(sleeve, rate, cycles);
return 0;
}
APICopy(): Record<string, unknown> {
@@ -30,14 +30,14 @@ export class SleeveCompanyWork extends Work {
return c;
}
getGainRates(player: IPlayer, sleeve: Sleeve): WorkStats {
return calculateCompanyWorkStats(player, sleeve, this.getCompany());
getGainRates(sleeve: Sleeve): WorkStats {
return calculateCompanyWorkStats(sleeve, this.getCompany());
}
process(player: IPlayer, sleeve: Sleeve, cycles: number): number {
process(sleeve: Sleeve, cycles: number): number {
const company = this.getCompany();
const gains = this.getGainRates(player, sleeve);
applySleeveGains(player, sleeve, gains, cycles);
const gains = this.getGainRates(sleeve);
applySleeveGains(sleeve, gains, cycles);
company.playerReputation += gains.reputation * cycles;
influenceStockThroughCompanyWork(company, gains.reputation, cycles);
return 0;
@@ -1,4 +1,4 @@
import { IPlayer } from "../../IPlayer";
import { Player } from "../../../Player";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver";
import { Sleeve } from "../Sleeve";
import { applySleeveGains, Work, WorkType } from "./Work";
@@ -43,19 +43,19 @@ export class SleeveCrimeWork extends Work {
return this.getCrime().time / CONSTANTS._idleSpeed;
}
process(player: IPlayer, sleeve: Sleeve, cycles: number): number {
process(sleeve: Sleeve, cycles: number): number {
this.cyclesWorked += cycles;
const crime = this.getCrime();
let gains = this.getExp();
if (this.cyclesWorked >= this.cyclesNeeded()) {
if (Math.random() < crime.successRate(sleeve)) {
player.karma -= crime.karma * sleeve.syncBonus();
Player.karma -= crime.karma * sleeve.syncBonus();
} else {
gains.money = 0;
gains = scaleWorkStats(gains, 0.25);
}
applySleeveGains(player, sleeve, gains, cycles);
applySleeveGains(sleeve, gains, cycles);
this.cyclesWorked -= this.cyclesNeeded();
}
return 0;
@@ -1,4 +1,4 @@
import { IPlayer } from "../../IPlayer";
import { Player } from "../../../Player";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver";
import { Sleeve } from "../Sleeve";
import { applySleeveGains, Work, WorkType } from "./Work";
@@ -57,16 +57,14 @@ export class SleeveFactionWork extends Work {
return f;
}
process(player: IPlayer, sleeve: Sleeve, cycles: number): number {
if (player.gang) {
if (this.factionName === player.gang.facName) {
sleeve.stopWork(player);
return 0;
}
process(sleeve: Sleeve, cycles: number): number {
if (this.factionName === Player.gang?.facName) {
sleeve.stopWork();
return 0;
}
const exp = this.getExpRates(sleeve);
applySleeveGains(player, sleeve, exp, cycles);
applySleeveGains(sleeve, exp, cycles);
const rep = this.getReputationRate(sleeve);
this.getFaction().playerReputation += rep;
return 0;
@@ -1,4 +1,4 @@
import { IPlayer } from "../../IPlayer";
import { Player } from "../../../Player";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver";
import { Sleeve } from "../Sleeve";
import { Work, WorkType } from "./Work";
@@ -20,12 +20,12 @@ export class SleeveInfiltrateWork extends Work {
return infiltrateCycles;
}
process(player: IPlayer, sleeve: Sleeve, cycles: number): number {
if (!player.bladeburner) throw new Error("sleeve doing blade work without being a member");
process(_sleeve: Sleeve, cycles: number): number {
if (!Player.bladeburner) throw new Error("sleeve doing blade work without being a member");
this.cyclesWorked += cycles;
if (this.cyclesWorked > this.cyclesNeeded()) {
this.cyclesWorked -= this.cyclesNeeded();
player.bladeburner.infiltrateSynthoidCommunities(player);
Player.bladeburner.infiltrateSynthoidCommunities();
}
return 0;
}
@@ -1,4 +1,3 @@
import { IPlayer } from "../../IPlayer";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver";
import { Sleeve } from "../Sleeve";
import { Work, WorkType } from "./Work";
@@ -11,9 +10,9 @@ export class SleeveRecoveryWork extends Work {
super(WorkType.RECOVERY);
}
process(player: IPlayer, sleeve: Sleeve, cycles: number): number {
process(sleeve: Sleeve, cycles: number): number {
sleeve.shock = Math.min(100, sleeve.shock + 0.0002 * cycles);
if (sleeve.shock >= 100) sleeve.stopWork(player);
if (sleeve.shock >= 100) sleeve.stopWork();
return 0;
}
@@ -1,4 +1,4 @@
import { IPlayer } from "../../../PersonObjects/IPlayer";
import { Player } from "../../../Player";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver";
import { Work, WorkType } from "./Work";
@@ -6,17 +6,17 @@ export const isSleeveSupportWork = (w: Work | null): w is SleeveSupportWork =>
w !== null && w.type === WorkType.SUPPORT;
export class SleeveSupportWork extends Work {
constructor(player?: IPlayer) {
constructor() {
super(WorkType.SUPPORT);
if (player) player.bladeburner?.sleeveSupport(true);
Player.bladeburner?.sleeveSupport(true);
}
process(): number {
return 0;
}
finish(player: IPlayer): void {
player.bladeburner?.sleeveSupport(false);
finish(): void {
Player.bladeburner?.sleeveSupport(false);
}
APICopy(): Record<string, unknown> {
@@ -1,4 +1,4 @@
import { IPlayer } from "../../IPlayer";
import { Player } from "../../../Player";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver";
import { Sleeve } from "../Sleeve";
import { Work, WorkType } from "./Work";
@@ -11,9 +11,9 @@ export class SleeveSynchroWork extends Work {
super(WorkType.SYNCHRO);
}
process(player: IPlayer, sleeve: Sleeve, cycles: number): number {
sleeve.sync = Math.min(100, sleeve.sync + player.getIntelligenceBonus(0.5) * 0.0002 * cycles);
if (sleeve.sync >= 100) sleeve.stopWork(player);
process(sleeve: Sleeve, cycles: number): number {
sleeve.sync = Math.min(100, sleeve.sync + Player.getIntelligenceBonus(0.5) * 0.0002 * cycles);
if (sleeve.sync >= 100) sleeve.stopWork();
return 0;
}
+6 -6
View File
@@ -1,14 +1,14 @@
import { IPlayer } from "../../IPlayer";
import { Player } from "../../../Player";
import { IReviverValue } from "../../../utils/JSONReviver";
import { Sleeve } from "../Sleeve";
import { applyWorkStats, applyWorkStatsExp, scaleWorkStats, WorkStats } from "../../../Work/WorkStats";
export const applySleeveGains = (player: IPlayer, sleeve: Sleeve, rawStats: WorkStats, cycles = 1): void => {
export const applySleeveGains = (sleeve: Sleeve, rawStats: WorkStats, cycles = 1): void => {
const shockedStats = scaleWorkStats(rawStats, sleeve.shockBonus(), rawStats.money > 0);
applyWorkStatsExp(sleeve, shockedStats, cycles);
const syncStats = scaleWorkStats(shockedStats, sleeve.syncBonus(), rawStats.money > 0);
applyWorkStats(player, player, syncStats, cycles, "sleeves");
player.sleeves.filter((s) => s != sleeve).forEach((s) => applyWorkStatsExp(s, syncStats, cycles));
applyWorkStats(Player, syncStats, cycles, "sleeves");
Player.sleeves.filter((s) => s !== sleeve).forEach((s) => applyWorkStatsExp(s, syncStats, cycles));
};
export abstract class Work {
@@ -18,10 +18,10 @@ export abstract class Work {
this.type = type;
}
abstract process(player: IPlayer, sleeve: Sleeve, cycles: number): number;
abstract process(sleeve: Sleeve, cycles: number): number;
abstract APICopy(): Record<string, unknown>;
abstract toJSON(): IReviverValue;
finish(__player: IPlayer): void {
finish(): void {
/* left for children to implement */
}
}
@@ -56,7 +56,7 @@ export function CovenantPurchasesRoot(props: IProps): React.ReactElement {
if (player.canAfford(purchaseCost())) {
player.loseMoney(purchaseCost(), "sleeves");
player.sleevesFromCovenant += 1;
player.sleeves.push(new Sleeve(player));
player.sleeves.push(new Sleeve());
rerender();
} else {
dialogBoxCreate(`You cannot afford to purchase a Duplicate Sleeve`);
@@ -67,7 +67,7 @@ export function CovenantPurchasesRoot(props: IProps): React.ReactElement {
const upgradePanels = [];
for (let i = 0; i < player.sleeves.length; ++i) {
const sleeve = player.sleeves[i];
upgradePanels.push(<CovenantSleeveMemoryUpgrade index={i} p={player} rerender={rerender} sleeve={sleeve} />);
upgradePanels.push(<CovenantSleeveMemoryUpgrade index={i} rerender={rerender} sleeve={sleeve} />);
}
return (
@@ -81,7 +81,7 @@ export function CovenantPurchasesRoot(props: IProps): React.ReactElement {
</Typography>
<Button disabled={purchaseDisabled} onClick={purchaseOnClick}>
Purchase -&nbsp;
<Money money={purchaseCost()} player={player} />
<Money money={purchaseCost()} forPurchase={true} />
</Button>
</>
)}
@@ -5,7 +5,7 @@
import React, { useState } from "react";
import { Sleeve } from "../Sleeve";
import { IPlayer } from "../../IPlayer";
import { Player } from "../../../Player";
import { numeralWrapper } from "../../../ui/numeralFormat";
import { Money } from "../../../ui/React/Money";
@@ -18,7 +18,6 @@ import Paper from "@mui/material/Paper";
interface IProps {
index: number;
p: IPlayer;
rerender: () => void;
sleeve: Sleeve;
}
@@ -52,16 +51,16 @@ export function CovenantSleeveMemoryUpgrade(props: IProps): React.ReactElement {
function purchaseMemory(): void {
const cost = getPurchaseCost();
if (props.p.canAfford(cost)) {
if (Player.canAfford(cost)) {
props.sleeve.upgradeMemory(amt);
props.p.loseMoney(cost, "sleeves");
Player.loseMoney(cost, "sleeves");
props.rerender();
}
}
// Purchase button props
const cost = getPurchaseCost();
const purchaseBtnDisabled = !props.p.canAfford(cost);
const purchaseBtnDisabled = !Player.canAfford(cost);
let purchaseBtnContent = <></>;
if (isNaN(amt)) {
purchaseBtnContent = <>Invalid value</>;
@@ -69,7 +68,7 @@ export function CovenantSleeveMemoryUpgrade(props: IProps): React.ReactElement {
purchaseBtnContent = (
<>
Purchase {amt} memory&nbsp;-&nbsp;
<Money money={cost} player={props.p} />
<Money money={cost} forPurchase={true} />
</>
);
}
@@ -1,7 +1,7 @@
import { Container, Typography, Paper } from "@mui/material";
import React, { useEffect, useState } from "react";
import { PurchasableAugmentations } from "../../../Augmentation/ui/PurchasableAugmentations";
import { use } from "../../../ui/Context";
import { Player } from "../../../Player";
import { Modal } from "../../../ui/React/Modal";
import { Sleeve } from "../Sleeve";
import { findSleevePurchasableAugs } from "../SleeveHelpers";
@@ -13,7 +13,6 @@ interface IProps {
}
export function SleeveAugmentationsModal(props: IProps): React.ReactElement {
const player = use.Player();
const setRerender = useState(false)[1];
function rerender(): void {
setRerender((old) => !old);
@@ -30,7 +29,7 @@ export function SleeveAugmentationsModal(props: IProps): React.ReactElement {
// You can only purchase Augmentations that are actually available from
// your factions. I.e. you must be in a faction that has the Augmentation
// and you must also have enough rep in that faction in order to purchase it.
const availableAugs = findSleevePurchasableAugs(props.sleeve, player);
const availableAugs = findSleevePurchasableAugs(props.sleeve);
return (
<Modal open={props.open} onClose={props.onClose}>
@@ -50,12 +49,11 @@ export function SleeveAugmentationsModal(props: IProps): React.ReactElement {
<PurchasableAugmentations
augNames={availableAugs.map((aug) => aug.name)}
ownedAugNames={ownedAugNames}
player={player}
canPurchase={(player, aug) => {
return player.money > aug.baseCost;
canPurchase={(aug) => {
return Player.money > aug.baseCost;
}}
purchaseAugmentation={(player, aug) => {
props.sleeve.tryBuyAugmentation(player, aug);
purchaseAugmentation={(aug) => {
props.sleeve.tryBuyAugmentation(aug);
rerender();
}}
sleeveAugs
+14 -15
View File
@@ -2,7 +2,7 @@ import { Box, Button, Paper, Tooltip, Typography } from "@mui/material";
import React, { useState } from "react";
import { FactionWorkType } from "../../../Work/data/FactionWorkType";
import { CONSTANTS } from "../../../Constants";
import { use } from "../../../ui/Context";
import { Player } from "../../../Player";
import { numeralWrapper } from "../../../ui/numeralFormat";
import { ProgressBar } from "../../../ui/React/Progress";
import { Sleeve } from "../Sleeve";
@@ -27,7 +27,6 @@ interface IProps {
}
export function SleeveElem(props: IProps): React.ReactElement {
const player = use.Player();
const [statsOpen, setStatsOpen] = useState(false);
const [travelOpen, setTravelOpen] = useState(false);
const [augmentationsOpen, setAugmentationsOpen] = useState(false);
@@ -39,28 +38,28 @@ export function SleeveElem(props: IProps): React.ReactElement {
case "------":
break;
case "Work for Company":
props.sleeve.workForCompany(player, abc[1]);
props.sleeve.workForCompany(abc[1]);
break;
case "Work for Faction":
props.sleeve.workForFaction(player, abc[1], abc[2]);
props.sleeve.workForFaction(abc[1], abc[2]);
break;
case "Commit Crime":
props.sleeve.commitCrime(player, abc[1]);
props.sleeve.commitCrime(abc[1]);
break;
case "Take University Course":
props.sleeve.takeUniversityCourse(player, abc[2], abc[1]);
props.sleeve.takeUniversityCourse(abc[2], abc[1]);
break;
case "Workout at Gym":
props.sleeve.workoutAtGym(player, abc[2], abc[1]);
props.sleeve.workoutAtGym(abc[2], abc[1]);
break;
case "Perform Bladeburner Actions":
props.sleeve.bladeburner(player, abc[1], abc[2]);
props.sleeve.bladeburner(abc[1], abc[2]);
break;
case "Shock Recovery":
props.sleeve.shockRecovery(player);
props.sleeve.shockRecovery();
break;
case "Synchronize":
props.sleeve.synchronize(player);
props.sleeve.synchronize();
break;
default:
console.error(`Invalid/Unrecognized taskValue in setSleeveTask(): ${abc[0]}`);
@@ -130,7 +129,7 @@ export function SleeveElem(props: IProps): React.ReactElement {
desc = (
<>
This sleeve is currently attempting to perform {w.actionName}. (
{((100 * w.cyclesWorked) / w.cyclesNeeded(player, props.sleeve)).toFixed(2)}%)
{((100 * w.cyclesWorked) / w.cyclesNeeded(props.sleeve)).toFixed(2)}%)
</>
);
}
@@ -156,11 +155,11 @@ export function SleeveElem(props: IProps): React.ReactElement {
<StatsElement sleeve={props.sleeve} />
<Box display="grid" sx={{ gridTemplateColumns: "1fr 1fr", width: "100%" }}>
<Button onClick={() => setStatsOpen(true)}>More Stats</Button>
<Tooltip title={player.money < CONSTANTS.TravelCost ? <Typography>Insufficient funds</Typography> : ""}>
<Tooltip title={Player.money < CONSTANTS.TravelCost ? <Typography>Insufficient funds</Typography> : ""}>
<span>
<Button
onClick={() => setTravelOpen(true)}
disabled={player.money < CONSTANTS.TravelCost}
disabled={Player.money < CONSTANTS.TravelCost}
sx={{ width: "100%", height: "100%" }}
>
Travel
@@ -184,7 +183,7 @@ export function SleeveElem(props: IProps): React.ReactElement {
</span>
<span>
<EarningsElement sleeve={props.sleeve} />
<TaskSelector player={player} sleeve={props.sleeve} setABC={setABC} />
<TaskSelector sleeve={props.sleeve} setABC={setABC} />
<Button onClick={setTask} sx={{ width: "100%" }}>
Set Task
</Button>
@@ -202,7 +201,7 @@ export function SleeveElem(props: IProps): React.ReactElement {
variant="determinate"
value={
(props.sleeve.currentWork.cyclesWorked /
props.sleeve.currentWork.cyclesNeeded(player, props.sleeve)) *
props.sleeve.currentWork.cyclesNeeded(props.sleeve)) *
100
}
color="primary"
+2 -4
View File
@@ -9,7 +9,6 @@ import { characterOverviewStyles as useStyles } from "../../../ui/React/Characte
import { Money } from "../../../ui/React/Money";
import { MoneyRate } from "../../../ui/React/MoneyRate";
import { ReputationRate } from "../../../ui/React/ReputationRate";
import { use } from "../../../ui/Context";
import { Sleeve } from "../Sleeve";
import { isSleeveClassWork } from "../Work/SleeveClassWork";
@@ -95,7 +94,6 @@ export function StatsElement(props: IProps): React.ReactElement {
export function EarningsElement(props: IProps): React.ReactElement {
const classes = useStyles();
const player = use.Player();
let data: (string | JSX.Element)[][] = [];
if (isSleeveCrimeWork(props.sleeve.currentWork)) {
@@ -111,7 +109,7 @@ export function EarningsElement(props: IProps): React.ReactElement {
];
}
if (isSleeveClassWork(props.sleeve.currentWork)) {
const rates = props.sleeve.currentWork.calculateRates(player, props.sleeve);
const rates = props.sleeve.currentWork.calculateRates(props.sleeve);
data = [
[`Money:`, <MoneyRate money={5 * rates.money} />],
[`Hacking Exp:`, `${numeralWrapper.formatExp(5 * rates.hackExp)} / sec`],
@@ -137,7 +135,7 @@ export function EarningsElement(props: IProps): React.ReactElement {
}
if (isSleeveCompanyWork(props.sleeve.currentWork)) {
const rates = props.sleeve.currentWork.getGainRates(player, props.sleeve);
const rates = props.sleeve.currentWork.getGainRates(props.sleeve);
data = [
[`Money:`, <MoneyRate money={5 * rates.money * BitNodeMultipliers.CompanyWorkMoney} />],
[`Hacking Exp:`, `${numeralWrapper.formatExp(5 * rates.hackExp)} / sec`],
+50 -51
View File
@@ -1,6 +1,6 @@
import React, { useState } from "react";
import { Sleeve } from "../Sleeve";
import { IPlayer } from "../../IPlayer";
import { Player } from "../../../Player";
import { Crimes } from "../../../Crime/Crimes";
import { LocationName } from "../../../Locations/data/LocationNames";
import { CityName } from "../../../Locations/data/CityNames";
@@ -43,7 +43,6 @@ const bladeburnerSelectorOptions: string[] = [
interface IProps {
sleeve: Sleeve;
player: IPlayer;
setABC: (abc: string[]) => void;
}
@@ -52,10 +51,10 @@ interface ITaskDetails {
second: (s1: string) => string[];
}
function possibleJobs(player: IPlayer, sleeve: Sleeve): string[] {
function possibleJobs(sleeve: Sleeve): string[] {
// Array of all companies that other sleeves are working at
const forbiddenCompanies: string[] = [];
for (const otherSleeve of player.sleeves) {
for (const otherSleeve of Player.sleeves) {
if (sleeve === otherSleeve) {
continue;
}
@@ -63,18 +62,18 @@ function possibleJobs(player: IPlayer, sleeve: Sleeve): string[] {
forbiddenCompanies.push(otherSleeve.currentWork.companyName);
}
}
const allJobs: string[] = Object.keys(player.jobs);
const allJobs: string[] = Object.keys(Player.jobs);
return allJobs.filter((company) => !forbiddenCompanies.includes(company));
}
function possibleFactions(player: IPlayer, sleeve: Sleeve): string[] {
function possibleFactions(sleeve: Sleeve): string[] {
// Array of all factions that other sleeves are working for
const forbiddenFactions = [FactionNames.Bladeburners as string, FactionNames.ShadowsOfAnarchy as string];
if (player.gang) {
forbiddenFactions.push(player.gang.facName);
if (Player.gang) {
forbiddenFactions.push(Player.gang.facName);
}
for (const otherSleeve of player.sleeves) {
for (const otherSleeve of Player.sleeves) {
if (sleeve === otherSleeve) {
continue;
}
@@ -84,7 +83,7 @@ function possibleFactions(player: IPlayer, sleeve: Sleeve): string[] {
}
const factions = [];
for (const fac of player.factions) {
for (const fac of Player.factions) {
if (!forbiddenFactions.includes(fac)) {
factions.push(fac);
}
@@ -98,13 +97,13 @@ function possibleFactions(player: IPlayer, sleeve: Sleeve): string[] {
});
}
function possibleContracts(player: IPlayer, sleeve: Sleeve): string[] {
const bb = player.bladeburner;
function possibleContracts(sleeve: Sleeve): string[] {
const bb = Player.bladeburner;
if (bb === null) {
return ["------"];
}
let contracts = bb.getContractNamesNetscriptFn();
for (const otherSleeve of player.sleeves) {
for (const otherSleeve of Player.sleeves) {
if (sleeve === otherSleeve) {
continue;
}
@@ -120,28 +119,28 @@ function possibleContracts(player: IPlayer, sleeve: Sleeve): string[] {
}
const tasks: {
[key: string]: undefined | ((player: IPlayer, sleeve: Sleeve) => ITaskDetails);
["------"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
["Work for Company"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
["Work for Faction"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
["Commit Crime"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
["Take University Course"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
["Workout at Gym"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
["Perform Bladeburner Actions"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
["Shock Recovery"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
["Synchronize"]: (player: IPlayer, sleeve: Sleeve) => ITaskDetails;
[key: string]: undefined | ((sleeve: Sleeve) => ITaskDetails);
["------"]: (sleeve: Sleeve) => ITaskDetails;
["Work for Company"]: (sleeve: Sleeve) => ITaskDetails;
["Work for Faction"]: (sleeve: Sleeve) => ITaskDetails;
["Commit Crime"]: (sleeve: Sleeve) => ITaskDetails;
["Take University Course"]: (sleeve: Sleeve) => ITaskDetails;
["Workout at Gym"]: (sleeve: Sleeve) => ITaskDetails;
["Perform Bladeburner Actions"]: (sleeve: Sleeve) => ITaskDetails;
["Shock Recovery"]: (sleeve: Sleeve) => ITaskDetails;
["Synchronize"]: (sleeve: Sleeve) => ITaskDetails;
} = {
"------": (): ITaskDetails => {
return { first: ["------"], second: () => ["------"] };
},
"Work for Company": (player: IPlayer, sleeve: Sleeve): ITaskDetails => {
let jobs = possibleJobs(player, sleeve);
"Work for Company": (sleeve: Sleeve): ITaskDetails => {
let jobs = possibleJobs(sleeve);
if (jobs.length === 0) jobs = ["------"];
return { first: jobs, second: () => ["------"] };
},
"Work for Faction": (player: IPlayer, sleeve: Sleeve): ITaskDetails => {
let factions = possibleFactions(player, sleeve);
"Work for Faction": (sleeve: Sleeve): ITaskDetails => {
let factions = possibleFactions(sleeve);
if (factions.length === 0) factions = ["------"];
return {
@@ -168,7 +167,7 @@ const tasks: {
"Commit Crime": (): ITaskDetails => {
return { first: Object.values(Crimes).map((crime) => crime.name), second: () => ["------"] };
},
"Take University Course": (player: IPlayer, sleeve: Sleeve): ITaskDetails => {
"Take University Course": (sleeve: Sleeve): ITaskDetails => {
let universities: string[] = [];
switch (sleeve.city) {
case CityName.Aevum:
@@ -187,7 +186,7 @@ const tasks: {
return { first: universitySelectorOptions, second: () => universities };
},
"Workout at Gym": (player: IPlayer, sleeve: Sleeve): ITaskDetails => {
"Workout at Gym": (sleeve: Sleeve): ITaskDetails => {
let gyms: string[] = [];
switch (sleeve.city) {
case CityName.Aevum:
@@ -206,12 +205,12 @@ const tasks: {
return { first: gymSelectorOptions, second: () => gyms };
},
"Perform Bladeburner Actions": (player: IPlayer, sleeve: Sleeve): ITaskDetails => {
"Perform Bladeburner Actions": (sleeve: Sleeve): ITaskDetails => {
return {
first: bladeburnerSelectorOptions,
second: (s1: string) => {
if (s1 === "Take on contracts") {
return possibleContracts(player, sleeve);
return possibleContracts(sleeve);
} else {
return ["------"];
}
@@ -227,28 +226,28 @@ const tasks: {
};
const canDo: {
[key: string]: undefined | ((player: IPlayer, sleeve: Sleeve) => boolean);
["------"]: (player: IPlayer, sleeve: Sleeve) => boolean;
["Work for Company"]: (player: IPlayer, sleeve: Sleeve) => boolean;
["Work for Faction"]: (player: IPlayer, sleeve: Sleeve) => boolean;
["Commit Crime"]: (player: IPlayer, sleeve: Sleeve) => boolean;
["Take University Course"]: (player: IPlayer, sleeve: Sleeve) => boolean;
["Workout at Gym"]: (player: IPlayer, sleeve: Sleeve) => boolean;
["Perform Bladeburner Actions"]: (player: IPlayer, sleeve: Sleeve) => boolean;
["Shock Recovery"]: (player: IPlayer, sleeve: Sleeve) => boolean;
["Synchronize"]: (player: IPlayer, sleeve: Sleeve) => boolean;
[key: string]: undefined | ((sleeve: Sleeve) => boolean);
["------"]: (sleeve: Sleeve) => boolean;
["Work for Company"]: (sleeve: Sleeve) => boolean;
["Work for Faction"]: (sleeve: Sleeve) => boolean;
["Commit Crime"]: (sleeve: Sleeve) => boolean;
["Take University Course"]: (sleeve: Sleeve) => boolean;
["Workout at Gym"]: (sleeve: Sleeve) => boolean;
["Perform Bladeburner Actions"]: (sleeve: Sleeve) => boolean;
["Shock Recovery"]: (sleeve: Sleeve) => boolean;
["Synchronize"]: (sleeve: Sleeve) => boolean;
} = {
"------": () => true,
"Work for Company": (player: IPlayer, sleeve: Sleeve) => possibleJobs(player, sleeve).length > 0,
"Work for Faction": (player: IPlayer, sleeve: Sleeve) => possibleFactions(player, sleeve).length > 0,
"Work for Company": (sleeve: Sleeve) => possibleJobs(sleeve).length > 0,
"Work for Faction": (sleeve: Sleeve) => possibleFactions(sleeve).length > 0,
"Commit Crime": () => true,
"Take University Course": (player: IPlayer, sleeve: Sleeve) =>
"Take University Course": (sleeve: Sleeve) =>
[CityName.Aevum, CityName.Sector12, CityName.Volhaven].includes(sleeve.city),
"Workout at Gym": (player: IPlayer, sleeve: Sleeve) =>
"Workout at Gym": (sleeve: Sleeve) =>
[CityName.Aevum, CityName.Sector12, CityName.Volhaven].includes(sleeve.city),
"Perform Bladeburner Actions": (player: IPlayer) => player.inBladeburner(),
"Shock Recovery": (player: IPlayer, sleeve: Sleeve) => sleeve.shock < 100,
Synchronize: (player: IPlayer, sleeve: Sleeve) => sleeve.sync < 100,
"Perform Bladeburner Actions": () => Player.inBladeburner(),
"Shock Recovery": (sleeve: Sleeve) => sleeve.shock < 100,
Synchronize: (sleeve: Sleeve) => sleeve.sync < 100,
};
function getABC(sleeve: Sleeve): [string, string, string] {
@@ -345,12 +344,12 @@ export function TaskSelector(props: IProps): React.ReactElement {
const [s2, setS2] = useState(abc[2]);
const validActions = Object.keys(canDo).filter((k) =>
(canDo[k] as (player: IPlayer, sleeve: Sleeve) => boolean)(props.player, props.sleeve),
(canDo[k] as (sleeve: Sleeve) => boolean)(props.sleeve),
);
const detailsF = tasks[s0];
if (detailsF === undefined) throw new Error(`No function for task '${s0}'`);
const details = detailsF(props.player, props.sleeve);
const details = detailsF(props.sleeve);
const details2 = details.second(s1);
if (details.first.length > 0 && !details.first.includes(s1)) {
@@ -366,7 +365,7 @@ export function TaskSelector(props: IProps): React.ReactElement {
const n = event.target.value;
const detailsF = tasks[n];
if (detailsF === undefined) throw new Error(`No function for task '${s0}'`);
const details = detailsF(props.player, props.sleeve);
const details = detailsF(props.sleeve);
const details2 = details.second(details.first[0]) ?? ["------"];
setS2(details2[0]);
setS1(details.first[0]);
+5 -6
View File
@@ -6,7 +6,7 @@ import { WorldMap } from "../../../ui/React/WorldMap";
import { CityName } from "../../../Locations/data/CityNames";
import { Settings } from "../../../Settings/Settings";
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
import { use } from "../../../ui/Context";
import { Player } from "../../../Player";
import { Modal } from "../../../ui/React/Modal";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
@@ -19,14 +19,13 @@ interface IProps {
}
export function TravelModal(props: IProps): React.ReactElement {
const player = use.Player();
function travel(city: string): void {
if (!player.canAfford(CONSTANTS.TravelCost)) {
if (!Player.canAfford(CONSTANTS.TravelCost)) {
dialogBoxCreate("You cannot afford to have this sleeve travel to another city");
}
props.sleeve.city = city as CityName;
player.loseMoney(CONSTANTS.TravelCost, "sleeve");
props.sleeve.stopWork(player);
Player.loseMoney(CONSTANTS.TravelCost, "sleeve");
props.sleeve.stopWork();
props.rerender();
props.onClose();
}
@@ -36,7 +35,7 @@ export function TravelModal(props: IProps): React.ReactElement {
<>
<Typography>
Have this sleeve travel to a different city. This affects the gyms and universities at which this sleeve can
study. Traveling to a different city costs <Money money={CONSTANTS.TravelCost} player={player} />. It will
study. Traveling to a different city costs <Money money={CONSTANTS.TravelCost} forPurchase={true} />. It will
also set your current sleeve task to idle.
</Typography>
{Settings.DisableASCIIArt ? (