mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-16 06:18:42 +02:00
Compare commits
2 Commits
e3ae5478d5
...
7425d8a8fd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7425d8a8fd | ||
|
|
3e44f08a0f |
@@ -370,7 +370,7 @@ export function initBitNodes() {
|
||||
<ul>
|
||||
<li>
|
||||
Sleeve: Duplicate your consciousness into Synthoids, allowing you to perform different tasks asynchronously.
|
||||
You cannot buy Sleeves outside this BitNode.
|
||||
You cannot buy Sleeves or upgrade them outside this BitNode.
|
||||
</li>
|
||||
<li>
|
||||
Grafting: Visit VitaLife in New Tokyo to get access to this technology. It allows you to graft
|
||||
|
||||
@@ -74,7 +74,7 @@ export const getCCTReward = (difficulty: number, server: DarknetServer): string
|
||||
return getMoneyReward(difficulty);
|
||||
}
|
||||
for (let i = 0; i < contractCount; i++) {
|
||||
generateContract({ server: server.hostname, rewardScaling: 1 / 5 });
|
||||
generateContract({ server: server.hostname, rewardScaling: 1 / 2 });
|
||||
}
|
||||
return `New coding contracts are now available on the network!`;
|
||||
};
|
||||
|
||||
@@ -196,7 +196,7 @@ achieved immortality - at least for those that could afford it.
|
||||
|
||||
This BitNode unlocks Sleeve and Grafting technology:
|
||||
|
||||
- Sleeve: Duplicate your consciousness into Synthoids, allowing you to perform different tasks asynchronously. You cannot buy Sleeves outside this BitNode.
|
||||
- Sleeve: Duplicate your consciousness into Synthoids, allowing you to perform different tasks asynchronously. You cannot buy Sleeves or upgrade them outside this BitNode.
|
||||
- Grafting: Visit VitaLife in New Tokyo to get access to this technology. It allows you to graft augmentations, which is an alternative way of installing augmentations.
|
||||
|
||||
Destroying this BitNode will give you Source-File 10, or if you already have this Source-File, it will upgrade its level up to a maximum of 3. This Source-File unlocks Sleeve and Grafting API in other BitNodes. Each level of this Source-File also grants you a Sleeve.
|
||||
|
||||
@@ -39,6 +39,7 @@ import { SpecialServers } from "../Server/data/SpecialServers";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
import { BladeburnerConstants } from "../Bladeburner/data/Constants";
|
||||
import type { PlayerObject } from "../PersonObjects/Player/PlayerObject";
|
||||
import { CovenantCampaign } from "./ui/CovenantCampaign";
|
||||
|
||||
interface FactionInfoParams {
|
||||
infoText?: JSX.Element;
|
||||
@@ -51,7 +52,7 @@ interface FactionInfoParams {
|
||||
offerSecurityWork?: boolean;
|
||||
special?: boolean;
|
||||
keepOnInstall?: boolean;
|
||||
assignment?: () => React.ReactElement;
|
||||
campaign?: () => React.ReactElement;
|
||||
}
|
||||
|
||||
/** Contains the "information" property for all the Factions, which is just a description of each faction */
|
||||
@@ -65,10 +66,10 @@ export class FactionInfo {
|
||||
/** The hint to show about how to get invited to this faction. */
|
||||
rumorText: JSX.Element;
|
||||
|
||||
/** Conditions for being automatically inivited to this facton. */
|
||||
/** Conditions for being automatically invited to this faction. */
|
||||
inviteReqs: CompoundPlayerCondition;
|
||||
|
||||
/** Conditions for automatically hearing a rumor about this facton. */
|
||||
/** Conditions for automatically hearing a rumor about this faction. */
|
||||
rumorReqs: CompoundPlayerCondition;
|
||||
|
||||
/** A flag indicating if the faction supports field work to earn reputation. */
|
||||
@@ -87,7 +88,7 @@ export class FactionInfo {
|
||||
special: boolean;
|
||||
|
||||
/** The data to display on the faction screen. */
|
||||
assignment?: () => React.ReactElement;
|
||||
campaign?: () => React.ReactElement;
|
||||
|
||||
constructor(params: FactionInfoParams) {
|
||||
this.infoText = params.infoText ?? <></>;
|
||||
@@ -101,7 +102,7 @@ export class FactionInfo {
|
||||
|
||||
this.keep = params.keepOnInstall ?? false;
|
||||
this.special = params.special ?? false;
|
||||
this.assignment = params.assignment;
|
||||
this.campaign = params.campaign;
|
||||
}
|
||||
|
||||
offersWork(): boolean {
|
||||
@@ -170,6 +171,9 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
campaign: () => {
|
||||
return <CovenantCampaign />;
|
||||
},
|
||||
}),
|
||||
|
||||
// Megacorporations, each forms its own faction
|
||||
@@ -706,7 +710,7 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
offerFieldWork: false,
|
||||
offerSecurityWork: false,
|
||||
special: true,
|
||||
assignment: (): React.ReactElement => {
|
||||
campaign: (): React.ReactElement => {
|
||||
return (
|
||||
<Option
|
||||
buttonText={"Open Bladeburner headquarters"}
|
||||
@@ -768,7 +772,7 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
offerSecurityWork: false,
|
||||
special: true,
|
||||
keepOnInstall: true,
|
||||
assignment: (): React.ReactElement => {
|
||||
campaign: (): React.ReactElement => {
|
||||
return (
|
||||
<Option
|
||||
buttonText={"Open Stanek's Gift"}
|
||||
@@ -803,7 +807,7 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
offerSecurityWork: false,
|
||||
special: true,
|
||||
keepOnInstall: true,
|
||||
assignment: (): React.ReactElement => {
|
||||
campaign: (): React.ReactElement => {
|
||||
return <Typography>{FactionName.ShadowsOfAnarchy} can only gain reputation by infiltrating.</Typography>;
|
||||
},
|
||||
}),
|
||||
|
||||
63
src/Faction/ui/CovenantCampaign.tsx
Normal file
63
src/Faction/ui/CovenantCampaign.tsx
Normal file
@@ -0,0 +1,63 @@
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { Player } from "@player";
|
||||
import React, { useState } from "react";
|
||||
import { CovenantPurchasesRoot } from "../../PersonObjects/Sleeve/ui/CovenantPurchasesRoot";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { Option } from "./Option";
|
||||
import { knowAboutBitverse } from "../../BitNode/BitNodeUtils";
|
||||
|
||||
function CovenantIncompleteCampaign() {
|
||||
const [open, setOpen] = useState(false);
|
||||
return (
|
||||
<>
|
||||
<Option
|
||||
buttonText={"Research"}
|
||||
infoText={"The Beginning of True Immortality"}
|
||||
onClick={() => setOpen(true)}
|
||||
></Option>
|
||||
<Modal open={open} onClose={() => setOpen(false)}>
|
||||
<Typography component="div">
|
||||
You tried your best to help the research team, but this research isn't making any progress.
|
||||
<br />
|
||||
<br />
|
||||
{knowAboutBitverse() ? (
|
||||
"Maybe this research can only be completed in BitNode 10?"
|
||||
) : (
|
||||
<>
|
||||
Research data is always randomly corrupted for unknown reasons, and a weird message is sent to you every
|
||||
time it happens:
|
||||
<br />
|
||||
<br />
|
||||
#@)($*&@__Y0U__^%$#@&*()__HAV3__(&@#*$%(@
|
||||
<br />
|
||||
()@#*$%(__N0T__@&$#)@*(__S33N__)(*@#&$)(
|
||||
<br />
|
||||
@&*($#@&__TH3__#@A&#@*)(@$#@)*
|
||||
<br />
|
||||
%$#@&()@__TRU1H__()*@#$&()@#$
|
||||
</>
|
||||
)}
|
||||
</Typography>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function CovenantCampaign() {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
if (Player.bitNodeN !== 10) {
|
||||
return <CovenantIncompleteCampaign />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Option
|
||||
buttonText={"Purchase & Upgrade Duplicate Sleeves"}
|
||||
infoText={"Purchase Duplicate Sleeves and upgrades. These are permanent!"}
|
||||
onClick={() => setOpen(true)}
|
||||
></Option>
|
||||
<CovenantPurchasesRoot open={open} onClose={() => setOpen(false)} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
* This is the component for displaying a single faction's UI, not the list of all
|
||||
* accessible factions
|
||||
*/
|
||||
import React, { useState } from "react";
|
||||
import React from "react";
|
||||
|
||||
import { DonateOption } from "./DonateOption";
|
||||
import { Info } from "./Info";
|
||||
@@ -16,12 +16,12 @@ import { Page } from "../../ui/Router";
|
||||
import { Player } from "@player";
|
||||
import { Typography, Button } from "@mui/material";
|
||||
|
||||
import { CovenantPurchasesRoot } from "../../PersonObjects/Sleeve/ui/CovenantPurchasesRoot";
|
||||
import { FactionName, FactionWorkType } from "@enums";
|
||||
import { FactionWorkType } from "@enums";
|
||||
import { GangButton } from "./GangButton";
|
||||
import { FactionWork } from "../../Work/FactionWork";
|
||||
import { useCycleRerender } from "../../ui/React/hooks";
|
||||
import { favorNeededToDonate } from "../formulas/donation";
|
||||
import { knowAboutBitverse } from "../../BitNode/BitNodeUtils";
|
||||
|
||||
type FactionRootProps = {
|
||||
faction: Faction;
|
||||
@@ -47,7 +47,6 @@ const augmentationsInfo =
|
||||
"As your reputation with this faction rises, you will " +
|
||||
"unlock augmentations, which you can purchase to enhance " +
|
||||
"your abilities.";
|
||||
const sleevePurchasesInfo = "Purchase Duplicate Sleeves and upgrades. These are permanent!";
|
||||
|
||||
interface IMainProps {
|
||||
faction: Faction;
|
||||
@@ -56,7 +55,6 @@ interface IMainProps {
|
||||
}
|
||||
|
||||
function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.ReactElement {
|
||||
const [sleevesOpen, setSleevesOpen] = useState(false);
|
||||
const factionInfo = faction.getInfo();
|
||||
|
||||
function startWork(): void {
|
||||
@@ -105,7 +103,6 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
|
||||
// should be shown
|
||||
const favorToDonate = favorNeededToDonate();
|
||||
const canDonate = faction.favor >= favorToDonate;
|
||||
const canPurchaseSleeves = faction.name === FactionName.TheCovenant && Player.bitNodeN === 10;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -115,33 +112,41 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
|
||||
</Typography>
|
||||
<Info faction={faction} factionInfo={factionInfo} />
|
||||
<GangButton faction={faction} />
|
||||
{!isPlayersGang && factionInfo.offerHackingWork && (
|
||||
<Option
|
||||
buttonText={"Hacking Contracts"}
|
||||
infoText={hackingContractsInfo}
|
||||
onClick={() => startHackingContracts(faction)}
|
||||
/>
|
||||
)}
|
||||
{!isPlayersGang && factionInfo.offerFieldWork && (
|
||||
<Option buttonText={"Field Work"} infoText={fieldWorkInfo} onClick={() => startFieldWork(faction)} />
|
||||
)}
|
||||
{!isPlayersGang && factionInfo.offerSecurityWork && (
|
||||
<Option buttonText={"Security Work"} infoText={securityWorkInfo} onClick={() => startSecurityWork(faction)} />
|
||||
)}
|
||||
{!isPlayersGang && factionInfo.offersWork() && (
|
||||
<DonateOption faction={faction} rerender={rerender} favorToDonate={favorToDonate} disabled={!canDonate} />
|
||||
)}
|
||||
<Option buttonText={"Purchase Augmentations"} infoText={augmentationsInfo} onClick={onAugmentations} />
|
||||
{canPurchaseSleeves && (
|
||||
{!isPlayersGang && (
|
||||
<>
|
||||
<Option
|
||||
buttonText={"Purchase & Upgrade Duplicate Sleeves"}
|
||||
infoText={sleevePurchasesInfo}
|
||||
onClick={() => setSleevesOpen(true)}
|
||||
/>
|
||||
<CovenantPurchasesRoot open={sleevesOpen} onClose={() => setSleevesOpen(false)} />
|
||||
{factionInfo.offersWork() && (
|
||||
<Typography>
|
||||
Perform work/carry out assignments for your faction to help further its cause! By doing so, you will earn
|
||||
reputation for your faction. You will also gain reputation passively over time, although at a very slow
|
||||
rate.
|
||||
{knowAboutBitverse() && <>Note that the passive reputation gain is disabled in some BitNodes. </>}
|
||||
Earning reputation will allow you to purchase augmentations through this faction, which are powerful
|
||||
upgrades that enhance your abilities.
|
||||
</Typography>
|
||||
)}
|
||||
{factionInfo.offerHackingWork && (
|
||||
<Option
|
||||
buttonText={"Hacking Contracts"}
|
||||
infoText={hackingContractsInfo}
|
||||
onClick={() => startHackingContracts(faction)}
|
||||
/>
|
||||
)}
|
||||
{factionInfo.offerFieldWork && (
|
||||
<Option buttonText={"Field Work"} infoText={fieldWorkInfo} onClick={() => startFieldWork(faction)} />
|
||||
)}
|
||||
{factionInfo.offerSecurityWork && (
|
||||
<Option
|
||||
buttonText={"Security Work"}
|
||||
infoText={securityWorkInfo}
|
||||
onClick={() => startSecurityWork(faction)}
|
||||
/>
|
||||
)}
|
||||
{factionInfo.offersWork() && (
|
||||
<DonateOption faction={faction} rerender={rerender} favorToDonate={favorToDonate} disabled={!canDonate} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<Option buttonText={"Purchase Augmentations"} infoText={augmentationsInfo} onClick={onAugmentations} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,33 +9,20 @@ import { FactionInfo } from "../FactionInfo";
|
||||
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { useCycleRerender } from "../../ui/React/hooks";
|
||||
import { knowAboutBitverse } from "../../BitNode/BitNodeUtils";
|
||||
import { ReputationInfo } from "../../ui/React/ReputationInfo";
|
||||
import { FavorInfo } from "../../ui/React/FavorInfo";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import InfoIcon from "@mui/icons-material/Info";
|
||||
import Grade from "@mui/icons-material/Grade";
|
||||
|
||||
interface IProps {
|
||||
faction: Faction;
|
||||
factionInfo: FactionInfo;
|
||||
}
|
||||
|
||||
function DefaultAssignment(): React.ReactElement {
|
||||
return (
|
||||
<Typography>
|
||||
Perform work/carry out assignments for your faction to help further its cause! By doing so, you will earn
|
||||
reputation for your faction. You will also gain reputation passively over time, although at a very slow
|
||||
rate.
|
||||
{knowAboutBitverse() && <>Note that the passive reputation gain is disabled in some BitNodes. </>}
|
||||
Earning reputation will allow you to purchase augmentations through this faction, which are powerful upgrades that
|
||||
enhance your abilities.
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
export function Info(props: IProps): React.ReactElement {
|
||||
useCycleRerender();
|
||||
|
||||
const Assignment = props.factionInfo.assignment ?? DefaultAssignment;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography sx={{ whiteSpace: "pre-wrap" }}>{props.factionInfo.infoText}</Typography>
|
||||
@@ -50,7 +37,23 @@ export function Info(props: IProps): React.ReactElement {
|
||||
<Typography>-------------------------</Typography>
|
||||
<FavorInfo favor={props.faction.favor} />
|
||||
<Typography>-------------------------</Typography>
|
||||
<Assignment />
|
||||
<Typography variant="h5" style={{ display: "flex", alignItems: "center" }}>
|
||||
<Grade style={{ fontSize: "1.1em", marginRight: "10px" }} />
|
||||
Special Campaign
|
||||
<Tooltip
|
||||
title={
|
||||
<>
|
||||
Some factions are developing special campaigns for researching breakthrough technology or executing
|
||||
initiatives. Some campaigns may be complete, while others remain unfinished. Explore them now, and return
|
||||
later if a campaign is not yet complete to see what unfolds.
|
||||
</>
|
||||
}
|
||||
>
|
||||
<InfoIcon sx={{ fontSize: "0.8em", marginLeft: "10px" }} />
|
||||
</Tooltip>
|
||||
</Typography>
|
||||
{props.factionInfo.campaign ? props.factionInfo.campaign() : <Typography>None</Typography>}
|
||||
<Typography>-------------------------</Typography>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -505,25 +505,27 @@ export function gainCodingContractReward(
|
||||
if (!reward) {
|
||||
return `No reward for this contract`;
|
||||
}
|
||||
// The new standard is smaller, more frequent rewards - a third of the reward size of the previous
|
||||
const adjustedScaling = rewardScaling / 3;
|
||||
|
||||
switch (reward.type) {
|
||||
case CodingContractRewardType.FactionReputation: {
|
||||
const factionsThatAllowHacking = Player.factions.filter((fac) => Factions[fac].getInfo().offerHackingWork);
|
||||
if (factionsThatAllowHacking.length === 0) {
|
||||
return this.gainCodingContractReward({ type: CodingContractRewardType.Money }, difficulty, rewardScaling);
|
||||
return this.gainCodingContractReward({ type: CodingContractRewardType.Money }, difficulty, adjustedScaling);
|
||||
}
|
||||
const randomFaction = factionsThatAllowHacking[getRandomIntInclusive(0, factionsThatAllowHacking.length - 1)];
|
||||
const repGain = CONSTANTS.CodingContractBaseFactionRepGain * difficulty * rewardScaling;
|
||||
const repGain = CONSTANTS.CodingContractBaseFactionRepGain * difficulty * adjustedScaling;
|
||||
Factions[randomFaction].playerReputation += repGain;
|
||||
return `Gained ${repGain} faction reputation for ${randomFaction}`;
|
||||
}
|
||||
case CodingContractRewardType.FactionReputationAll: {
|
||||
const factionsThatAllowHacking = Player.factions.filter((fac) => Factions[fac].getInfo().offerHackingWork);
|
||||
if (factionsThatAllowHacking.length === 0) {
|
||||
return this.gainCodingContractReward({ type: CodingContractRewardType.Money }, difficulty, rewardScaling);
|
||||
return this.gainCodingContractReward({ type: CodingContractRewardType.Money }, difficulty, adjustedScaling);
|
||||
}
|
||||
|
||||
const totalGain = CONSTANTS.CodingContractBaseFactionRepGain * difficulty * rewardScaling;
|
||||
const totalGain = CONSTANTS.CodingContractBaseFactionRepGain * difficulty * adjustedScaling;
|
||||
const gainPerFaction = Math.floor(totalGain / factionsThatAllowHacking.length);
|
||||
for (const facName of factionsThatAllowHacking) {
|
||||
Factions[facName].playerReputation += gainPerFaction;
|
||||
@@ -543,17 +545,17 @@ export function gainCodingContractReward(
|
||||
: CodingContractRewardType.FactionReputationAll,
|
||||
},
|
||||
difficulty,
|
||||
rewardScaling,
|
||||
adjustedScaling,
|
||||
);
|
||||
}
|
||||
const randomCompany = companies[getRandomIntInclusive(0, companies.length - 1)];
|
||||
const repGain = CONSTANTS.CodingContractBaseCompanyRepGain * difficulty * rewardScaling;
|
||||
const repGain = CONSTANTS.CodingContractBaseCompanyRepGain * difficulty * adjustedScaling;
|
||||
Companies[randomCompany].playerReputation += repGain;
|
||||
return `Gained ${repGain} company reputation for ${randomCompany}`;
|
||||
}
|
||||
case CodingContractRewardType.Money: {
|
||||
const moneyGain =
|
||||
CONSTANTS.CodingContractBaseMoneyGain * difficulty * currentNodeMults.CodingContractMoney * rewardScaling;
|
||||
CONSTANTS.CodingContractBaseMoneyGain * difficulty * currentNodeMults.CodingContractMoney * adjustedScaling;
|
||||
this.gainMoney(moneyGain, "codingcontract");
|
||||
return `Gained ${formatMoney(moneyGain)}`;
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ const Engine = {
|
||||
}
|
||||
|
||||
if (Engine.Counters.contractGeneration <= 0) {
|
||||
tryGeneratingRandomContract(1);
|
||||
tryGeneratingRandomContract(3);
|
||||
Engine.Counters.contractGeneration = 3000;
|
||||
}
|
||||
|
||||
@@ -265,7 +265,7 @@ const Engine = {
|
||||
const numCyclesOffline = Math.floor(timeOffline / CONSTANTS.MilliPerCycle);
|
||||
|
||||
// Generate bonus CCTs
|
||||
tryGeneratingRandomContract(timeOffline / CONSTANTS.MillisecondsPerTenMinutes);
|
||||
tryGeneratingRandomContract((timeOffline * 3) / CONSTANTS.MillisecondsPerTenMinutes);
|
||||
|
||||
let offlineReputation = 0;
|
||||
let offlineHackingIncome =
|
||||
|
||||
Reference in New Issue
Block a user