mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2025-03-11 04:42:34 +01:00
FACTIONS: Add "Rumors" system for learning about faction join requirements (#888)
This commit is contained in:
@ -0,0 +1,46 @@
|
||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [bitburner](./bitburner.md) > [Singularity](./bitburner.singularity.md) > [getFactionInviteRequirements](./bitburner.singularity.getfactioninviterequirements.md)
|
||||
|
||||
## Singularity.getFactionInviteRequirements() method
|
||||
|
||||
List conditions for being invited to a faction.
|
||||
|
||||
**Signature:**
|
||||
|
||||
```typescript
|
||||
getFactionInviteRequirements(faction: string): string[];
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| faction | string | Name of the faction. |
|
||||
|
||||
**Returns:**
|
||||
|
||||
string\[\]
|
||||
|
||||
Array of strings describing conditions for receiving an invitation to the faction.
|
||||
|
||||
## Remarks
|
||||
|
||||
RAM cost: 3 GB \* 16/4/1
|
||||
|
||||
## Example
|
||||
|
||||
|
||||
```js
|
||||
ns.singularity.getFactionInviteRequirements("The Syndicate")
|
||||
[
|
||||
"Located in Aevum or Sector-12",
|
||||
"Not working for the Central Intelligence Agency",
|
||||
"Not working for the National Security Agency",
|
||||
"-90 karma",
|
||||
"Have $10.000m",
|
||||
"Hacking level 200",
|
||||
"All combat skills level 200"
|
||||
]
|
||||
```
|
||||
|
@ -50,6 +50,7 @@ This API requires Source-File 4 to use. The RAM cost of all these functions is m
|
||||
| [getDarkwebPrograms()](./bitburner.singularity.getdarkwebprograms.md) | Get a list of programs offered on the dark web. |
|
||||
| [getFactionFavor(faction)](./bitburner.singularity.getfactionfavor.md) | Get faction favor. |
|
||||
| [getFactionFavorGain(faction)](./bitburner.singularity.getfactionfavorgain.md) | Get faction favor gain. |
|
||||
| [getFactionInviteRequirements(faction)](./bitburner.singularity.getfactioninviterequirements.md) | List conditions for being invited to a faction. |
|
||||
| [getFactionRep(faction)](./bitburner.singularity.getfactionrep.md) | Get faction reputation. |
|
||||
| [getOwnedAugmentations(purchased)](./bitburner.singularity.getownedaugmentations.md) | Get a list of owned augmentation. |
|
||||
| [getOwnedSourceFiles()](./bitburner.singularity.getownedsourcefiles.md) | Get a list of acquired Source-Files. |
|
||||
|
@ -2,7 +2,7 @@
|
||||
* React component for displaying a single augmentation for purchase through
|
||||
* the faction UI
|
||||
*/
|
||||
import { CheckBox, CheckBoxOutlineBlank, CheckCircle, NewReleases, Report } from "@mui/icons-material";
|
||||
import { CheckCircle, NewReleases, Report } from "@mui/icons-material";
|
||||
import { Box, Button, Container, Paper, Tooltip, Typography } from "@mui/material";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Faction } from "../../Faction/Faction";
|
||||
@ -15,6 +15,7 @@ import { Augmentations } from "../Augmentations";
|
||||
import { PurchaseAugmentationModal } from "./PurchaseAugmentationModal";
|
||||
import { getAugCost } from "../AugmentationHelpers";
|
||||
import { useRerender } from "../../ui/React/hooks";
|
||||
import { Requirement } from "../../ui/Components/Requirement";
|
||||
|
||||
interface IPreReqsProps {
|
||||
aug: Augmentation;
|
||||
@ -36,6 +37,7 @@ const PreReqs = (props: IPreReqsProps): React.ReactElement => {
|
||||
fulfilled={Player.hasAugmentation(preAug)}
|
||||
value={preAug}
|
||||
color={Settings.theme.money}
|
||||
incompleteColor={Settings.theme.error}
|
||||
key={preAug}
|
||||
/>
|
||||
))}
|
||||
@ -110,23 +112,6 @@ const Exclusive = (props: IExclusiveProps): React.ReactElement => {
|
||||
);
|
||||
};
|
||||
|
||||
interface IReqProps {
|
||||
value: string;
|
||||
color: string;
|
||||
fulfilled: boolean;
|
||||
}
|
||||
|
||||
const Requirement = (props: IReqProps): React.ReactElement => {
|
||||
return (
|
||||
<Typography
|
||||
sx={{ display: "flex", alignItems: "center", color: props.fulfilled ? props.color : Settings.theme.error }}
|
||||
>
|
||||
{props.fulfilled ? <CheckBox sx={{ mr: 1 }} /> : <CheckBoxOutlineBlank sx={{ mr: 1 }} />}
|
||||
{props.value}
|
||||
</Typography>
|
||||
);
|
||||
};
|
||||
|
||||
interface IPurchasableAugsProps {
|
||||
augNames: AugmentationName[];
|
||||
ownedAugNames: AugmentationName[];
|
||||
@ -254,12 +239,14 @@ export function PurchasableAugmentation(props: IPurchasableAugProps): React.Reac
|
||||
fulfilled={cost === 0 || Player.money > cost}
|
||||
value={formatMoney(cost)}
|
||||
color={Settings.theme.money}
|
||||
incompleteColor={Settings.theme.error}
|
||||
/>
|
||||
{props.parent.rep !== undefined && (
|
||||
<Requirement
|
||||
fulfilled={props.parent.rep >= repCost}
|
||||
value={`${formatReputation(repCost)} rep`}
|
||||
color={Settings.theme.rep}
|
||||
incompleteColor={Settings.theme.error}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type { CompanyPosition } from "./CompanyPosition";
|
||||
|
||||
import { CompanyName, JobName } from "@enums";
|
||||
import { CompanyName, JobName, FactionName } from "@enums";
|
||||
import { favorToRep, repToFavor } from "../Faction/formulas/favor";
|
||||
|
||||
import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver";
|
||||
@ -12,7 +12,7 @@ export interface CompanyCtorParams {
|
||||
expMultiplier: number;
|
||||
salaryMultiplier: number;
|
||||
jobStatReqOffset: number;
|
||||
hasFaction?: boolean;
|
||||
relatedFaction?: FactionName | undefined;
|
||||
}
|
||||
|
||||
export class Company {
|
||||
@ -20,7 +20,7 @@ export class Company {
|
||||
|
||||
name = CompanyName.NoodleBar;
|
||||
info = "";
|
||||
hasFaction = false;
|
||||
relatedFaction: FactionName | undefined;
|
||||
|
||||
companyPositions = new Set<JobName>();
|
||||
|
||||
@ -49,7 +49,7 @@ export class Company {
|
||||
this.expMultiplier = p.expMultiplier;
|
||||
this.salaryMultiplier = p.salaryMultiplier;
|
||||
this.jobStatReqOffset = p.jobStatReqOffset;
|
||||
if (p.hasFaction) this.hasFaction = true;
|
||||
if (p.relatedFaction) this.relatedFaction = p.relatedFaction;
|
||||
}
|
||||
|
||||
hasPosition(pos: CompanyPosition | JobName): boolean {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { CompanyCtorParams } from "../Company";
|
||||
|
||||
import { CompanyName, JobName } from "@enums";
|
||||
import { CompanyName, JobName, FactionName } from "@enums";
|
||||
import {
|
||||
agentJobs,
|
||||
businessJobs,
|
||||
@ -24,6 +24,7 @@ export function getCompaniesMetadata(): Record<CompanyName, CompanyCtorParams> {
|
||||
expMultiplier: 3,
|
||||
salaryMultiplier: 3,
|
||||
jobStatReqOffset: 249,
|
||||
relatedFaction: FactionName.ECorp,
|
||||
},
|
||||
[CompanyName.MegaCorp]: {
|
||||
name: CompanyName.MegaCorp,
|
||||
@ -31,6 +32,7 @@ export function getCompaniesMetadata(): Record<CompanyName, CompanyCtorParams> {
|
||||
expMultiplier: 3,
|
||||
salaryMultiplier: 3,
|
||||
jobStatReqOffset: 249,
|
||||
relatedFaction: FactionName.MegaCorp,
|
||||
},
|
||||
[CompanyName.BachmanAndAssociates]: {
|
||||
name: CompanyName.BachmanAndAssociates,
|
||||
@ -38,6 +40,7 @@ export function getCompaniesMetadata(): Record<CompanyName, CompanyCtorParams> {
|
||||
expMultiplier: 2.6,
|
||||
salaryMultiplier: 2.6,
|
||||
jobStatReqOffset: 224,
|
||||
relatedFaction: FactionName.BachmanAssociates,
|
||||
},
|
||||
[CompanyName.BladeIndustries]: {
|
||||
name: CompanyName.BladeIndustries,
|
||||
@ -45,6 +48,7 @@ export function getCompaniesMetadata(): Record<CompanyName, CompanyCtorParams> {
|
||||
expMultiplier: 2.75,
|
||||
salaryMultiplier: 2.75,
|
||||
jobStatReqOffset: 224,
|
||||
relatedFaction: FactionName.BladeIndustries,
|
||||
},
|
||||
[CompanyName.NWO]: {
|
||||
name: CompanyName.NWO,
|
||||
@ -52,6 +56,7 @@ export function getCompaniesMetadata(): Record<CompanyName, CompanyCtorParams> {
|
||||
expMultiplier: 2.75,
|
||||
salaryMultiplier: 2.75,
|
||||
jobStatReqOffset: 249,
|
||||
relatedFaction: FactionName.NWO,
|
||||
},
|
||||
[CompanyName.ClarkeIncorporated]: {
|
||||
name: CompanyName.ClarkeIncorporated,
|
||||
@ -59,6 +64,7 @@ export function getCompaniesMetadata(): Record<CompanyName, CompanyCtorParams> {
|
||||
expMultiplier: 2.25,
|
||||
salaryMultiplier: 2.25,
|
||||
jobStatReqOffset: 224,
|
||||
relatedFaction: FactionName.ClarkeIncorporated,
|
||||
},
|
||||
[CompanyName.OmniTekIncorporated]: {
|
||||
name: CompanyName.OmniTekIncorporated,
|
||||
@ -66,6 +72,7 @@ export function getCompaniesMetadata(): Record<CompanyName, CompanyCtorParams> {
|
||||
expMultiplier: 2.25,
|
||||
salaryMultiplier: 2.25,
|
||||
jobStatReqOffset: 224,
|
||||
relatedFaction: FactionName.OmniTekIncorporated,
|
||||
},
|
||||
[CompanyName.FourSigma]: {
|
||||
name: CompanyName.FourSigma,
|
||||
@ -73,6 +80,7 @@ export function getCompaniesMetadata(): Record<CompanyName, CompanyCtorParams> {
|
||||
expMultiplier: 2.5,
|
||||
salaryMultiplier: 2.5,
|
||||
jobStatReqOffset: 224,
|
||||
relatedFaction: FactionName.FourSigma,
|
||||
},
|
||||
[CompanyName.KuaiGongInternational]: {
|
||||
name: CompanyName.KuaiGongInternational,
|
||||
@ -80,6 +88,7 @@ export function getCompaniesMetadata(): Record<CompanyName, CompanyCtorParams> {
|
||||
expMultiplier: 2.2,
|
||||
salaryMultiplier: 2.2,
|
||||
jobStatReqOffset: 224,
|
||||
relatedFaction: FactionName.KuaiGongInternational,
|
||||
},
|
||||
[CompanyName.FulcrumTechnologies]: {
|
||||
name: CompanyName.FulcrumTechnologies,
|
||||
@ -87,6 +96,7 @@ export function getCompaniesMetadata(): Record<CompanyName, CompanyCtorParams> {
|
||||
expMultiplier: 2,
|
||||
salaryMultiplier: 2,
|
||||
jobStatReqOffset: 224,
|
||||
relatedFaction: FactionName.FulcrumSecretTechnologies,
|
||||
},
|
||||
[CompanyName.StormTechnologies]: {
|
||||
name: CompanyName.StormTechnologies,
|
||||
|
@ -5,19 +5,25 @@ import {
|
||||
AccordionDetails,
|
||||
Button,
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
IconButton,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
Select,
|
||||
SelectChangeEvent,
|
||||
Typography,
|
||||
RadioGroup,
|
||||
Radio,
|
||||
} from "@mui/material";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
import ReplyAllIcon from "@mui/icons-material/ReplyAll";
|
||||
import ReplyIcon from "@mui/icons-material/Reply";
|
||||
import ChatIcon from "@mui/icons-material/Chat";
|
||||
import ChatBubbleIcon from "@mui/icons-material/ChatBubble";
|
||||
|
||||
import { Player } from "@player";
|
||||
import { FactionName } from "@enums";
|
||||
import { FactionName, FactionDiscovery } from "@enums";
|
||||
import { Adjuster } from "./Adjuster";
|
||||
import { Factions } from "../../Faction/Factions";
|
||||
import { getRecordValues } from "../../Types/Record";
|
||||
@ -27,18 +33,41 @@ const bigNumber = 1e12;
|
||||
|
||||
export function FactionsDev(): React.ReactElement {
|
||||
const [factionName, setFactionName] = useState(FactionName.Illuminati);
|
||||
const [factionDiscovery, setFactionDiscovery] = useState(Factions[FactionName.Illuminati].discovery);
|
||||
|
||||
function setFactionDropdown(event: SelectChangeEvent): void {
|
||||
if (!getEnumHelper("FactionName").isMember(event.target.value)) return;
|
||||
setFactionName(event.target.value);
|
||||
setFactionDiscovery(Factions[event.target.value].discovery);
|
||||
}
|
||||
|
||||
function receiveInvite(): void {
|
||||
Player.receiveInvite(factionName);
|
||||
Factions[factionName].alreadyInvited = true;
|
||||
}
|
||||
|
||||
function receiveAllInvites(): void {
|
||||
Object.values(FactionName).forEach((faction) => Player.receiveInvite(faction));
|
||||
Object.values(FactionName).forEach((faction) => {
|
||||
Player.receiveInvite(faction);
|
||||
Factions[factionName].alreadyInvited = true;
|
||||
});
|
||||
}
|
||||
|
||||
function receiveRumor(): void {
|
||||
Player.receiveRumor(factionName);
|
||||
setFactionDiscovery(Factions[factionName].discovery);
|
||||
}
|
||||
|
||||
function receiveAllRumors(): void {
|
||||
Object.values(FactionName).forEach((faction) => Player.receiveRumor(faction));
|
||||
}
|
||||
|
||||
function resetAllDiscovery(): void {
|
||||
Object.values(Factions).forEach((faction) => {
|
||||
faction.discovery = FactionDiscovery.unknown;
|
||||
});
|
||||
Player.factionRumors.length = 0;
|
||||
setFactionDiscovery(Factions[factionName].discovery);
|
||||
}
|
||||
|
||||
function modifyFactionRep(modifier: number): (x: number) => void {
|
||||
@ -93,6 +122,12 @@ export function FactionsDev(): React.ReactElement {
|
||||
}
|
||||
}
|
||||
|
||||
function setDiscovery(event: React.ChangeEvent<HTMLInputElement>, value: string): void {
|
||||
const disco = value as FactionDiscovery;
|
||||
Factions[factionName].discovery = disco;
|
||||
setFactionDiscovery(disco);
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion TransitionProps={{ unmountOnExit: true }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
@ -115,12 +150,16 @@ export function FactionsDev(): React.ReactElement {
|
||||
value={factionName}
|
||||
startAdornment={
|
||||
<>
|
||||
<IconButton onClick={receiveAllInvites} size="large" arial-label="receive-all-invitation">
|
||||
<ReplyAllIcon />
|
||||
</IconButton>
|
||||
<IconButton onClick={receiveInvite} size="large" arial-label="receive-one-invitation">
|
||||
<ReplyIcon />
|
||||
</IconButton>
|
||||
<Tooltip title={`Hear rumor about ${factionName}`}>
|
||||
<IconButton onClick={receiveRumor} size="large">
|
||||
<ChatIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Tooltip title={`Receive invitation to ${factionName}`}>
|
||||
<IconButton onClick={receiveInvite} size="large">
|
||||
<ReplyIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</>
|
||||
}
|
||||
>
|
||||
@ -133,6 +172,20 @@ export function FactionsDev(): React.ReactElement {
|
||||
</FormControl>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<Typography>Discovery:</Typography>
|
||||
</td>
|
||||
<td>
|
||||
<FormControl>
|
||||
<RadioGroup onChange={setDiscovery} value={factionDiscovery} row>
|
||||
{Object.entries(FactionDiscovery).map(([discoveryLabel, discovery]) => (
|
||||
<FormControlLabel key={discovery} value={discovery} label={discoveryLabel} control={<Radio />} />
|
||||
))}
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<Typography>Reputation:</Typography>
|
||||
@ -163,6 +216,28 @@ export function FactionsDev(): React.ReactElement {
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<Typography>All Factions:</Typography>
|
||||
</td>
|
||||
<td>
|
||||
<Tooltip title="Forget all discovery">
|
||||
<Button onClick={resetAllDiscovery} size="large">
|
||||
<ChatBubbleIcon />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip title="Hear all rumors">
|
||||
<Button onClick={receiveAllRumors} size="large">
|
||||
<ChatIcon />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip title="Receive all invitations">
|
||||
<Button onClick={receiveAllInvites} size="large">
|
||||
<ReplyAllIcon />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<Typography>All Reputation:</Typography>
|
||||
|
@ -34,3 +34,9 @@ export enum FactionName {
|
||||
ChurchOfTheMachineGod = "Church of the Machine God",
|
||||
ShadowsOfAnarchy = "Shadows of Anarchy",
|
||||
}
|
||||
|
||||
export enum FactionDiscovery {
|
||||
unknown = "unknown",
|
||||
rumored = "rumored",
|
||||
known = "known",
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { AugmentationName, FactionName } from "@enums";
|
||||
import { AugmentationName, FactionName, FactionDiscovery } from "@enums";
|
||||
import { FactionInfo, FactionInfos } from "./FactionInfo";
|
||||
import { favorToRep, repToFavor } from "./formulas/favor";
|
||||
import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver";
|
||||
import { getKeyList } from "../utils/helpers/getKeyList";
|
||||
import type { PlayerObject } from "../PersonObjects/Player/PlayerObject";
|
||||
|
||||
export class Faction {
|
||||
/**
|
||||
@ -23,6 +24,9 @@ export class Faction {
|
||||
/** Flag signalling whether player is a member of this faction */
|
||||
isMember = false;
|
||||
|
||||
/** Level of player knowledge about this faction (unknown, rumored, known) */
|
||||
discovery: FactionDiscovery = FactionDiscovery.unknown;
|
||||
|
||||
/** Name of faction */
|
||||
name: FactionName;
|
||||
|
||||
@ -75,6 +79,30 @@ export class Faction {
|
||||
return newFavor - this.favor;
|
||||
}
|
||||
|
||||
checkForInvite(p: PlayerObject): boolean {
|
||||
if (this.isBanned) return false;
|
||||
if (this.isMember) return false;
|
||||
if (this.alreadyInvited) return false;
|
||||
const conditions = this.getInfo().inviteReqs;
|
||||
if (conditions.length == 0) return false;
|
||||
for (const condition of conditions) {
|
||||
if (!condition.isSatisfied(p)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
checkForRumor(p: PlayerObject): boolean {
|
||||
if (this.isBanned) return false;
|
||||
if (this.isMember) return false;
|
||||
if (this.alreadyInvited) return false;
|
||||
const conditions = this.getInfo().rumorReqs;
|
||||
if (conditions.length == 0) return false;
|
||||
for (const condition of conditions) {
|
||||
if (!condition.isSatisfied(p)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static savedKeys = getKeyList(Faction, { removedKeys: ["augmentations", "name"] });
|
||||
|
||||
/** Serialize the current object to a JSON save state. */
|
||||
|
@ -50,6 +50,12 @@ export function joinFaction(faction: Faction): void {
|
||||
i--;
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < Player.factionRumors.length; ++i) {
|
||||
if (Player.factionRumors[i] == faction.name || Factions[Player.factionRumors[i]].isBanned) {
|
||||
Player.factionRumors.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Returns a boolean indicating whether the player has the prerequisites for the
|
||||
|
@ -1,12 +1,41 @@
|
||||
import React from "react";
|
||||
import { FactionName } from "@enums";
|
||||
import { FactionName, CompanyName, CityName, LiteratureName, MessageFilename } from "@enums";
|
||||
import { currentNodeMults } from "../BitNode/BitNodeMultipliers";
|
||||
import { Router } from "../ui/GameRoot";
|
||||
import { Page } from "../ui/Router";
|
||||
import { Option } from "./ui/Option";
|
||||
import { Typography } from "@mui/material";
|
||||
import {
|
||||
JoinCondition,
|
||||
haveBackdooredServer,
|
||||
employedBy,
|
||||
executiveEmployee,
|
||||
notEmployee,
|
||||
haveAugmentations,
|
||||
haveMoney,
|
||||
haveSkill,
|
||||
haveCombatSkills,
|
||||
haveKarma,
|
||||
haveKilledPeople,
|
||||
locatedInCity,
|
||||
totalHacknetRam,
|
||||
totalHacknetCores,
|
||||
totalHacknetLevels,
|
||||
haveBladeburnerRank,
|
||||
haveSourceFile,
|
||||
haveFile,
|
||||
someCondition,
|
||||
} from "./FactionJoinCondition";
|
||||
import { SpecialServers } from "../Server/data/SpecialServers";
|
||||
import { CONSTANTS } from "../Constants";
|
||||
import { BladeburnerConstants } from "../Bladeburner/data/Constants";
|
||||
import type { PlayerObject } from "../PersonObjects/Player/PlayerObject";
|
||||
|
||||
interface FactionInfoParams {
|
||||
infoText?: JSX.Element;
|
||||
rumorText?: JSX.Element;
|
||||
inviteReqs?: JoinCondition[];
|
||||
rumorReqs?: JoinCondition[];
|
||||
enemies?: FactionName[];
|
||||
offerHackingWork?: boolean;
|
||||
offerFieldWork?: boolean;
|
||||
@ -24,6 +53,15 @@ export class FactionInfo {
|
||||
/** The descriptive text to show on the faction's page. */
|
||||
infoText: JSX.Element;
|
||||
|
||||
/** The hint to show about how to get invited to this faction. */
|
||||
rumorText: JSX.Element;
|
||||
|
||||
/** Conditions for being automatically inivited to this facton. */
|
||||
inviteReqs: JoinCondition[];
|
||||
|
||||
/** Conditions for automatically hearing a rumor about this facton. */
|
||||
rumorReqs: JoinCondition[];
|
||||
|
||||
/** A flag indicating if the faction supports field work to earn reputation. */
|
||||
offerFieldWork: boolean;
|
||||
|
||||
@ -44,6 +82,9 @@ export class FactionInfo {
|
||||
|
||||
constructor(params: FactionInfoParams) {
|
||||
this.infoText = params.infoText ?? <></>;
|
||||
this.rumorText = params.rumorText ?? <></>;
|
||||
this.inviteReqs = params.inviteReqs ?? [];
|
||||
this.rumorReqs = params.rumorReqs ?? [];
|
||||
this.enemies = params.enemies ?? [];
|
||||
this.offerHackingWork = params.offerHackingWork ?? false;
|
||||
this.offerFieldWork = params.offerFieldWork ?? false;
|
||||
@ -69,12 +110,28 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
from this chaos, we are the invisible hand that guides them to order.{" "}
|
||||
</>
|
||||
),
|
||||
rumorText: (
|
||||
<>
|
||||
“...the ancient secret society that controls the entire world from the shadows with their invisible hand. With
|
||||
their personal wealth and skills they have penetrated every major government, financial agency, and
|
||||
corporation...”
|
||||
</>
|
||||
),
|
||||
inviteReqs: [haveAugmentations(30), haveMoney(150e9), haveSkill("hacking", 1500), haveCombatSkills(1200)],
|
||||
rumorReqs: [haveFile(LiteratureName.TheHiddenWorld)],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
}),
|
||||
|
||||
[FactionName.Daedalus]: new FactionInfo({
|
||||
infoText: <>Yesterday we obeyed kings and bent our necks to emperors. Today we kneel only to truth.</>,
|
||||
rumorText: <>Follow the thread.</>,
|
||||
inviteReqs: [
|
||||
haveAugmentations(currentNodeMults.DaedalusAugsRequirement),
|
||||
haveMoney(100e9),
|
||||
someCondition(haveSkill("hacking", 2500), haveCombatSkills(1500)),
|
||||
],
|
||||
rumorReqs: [haveFile(MessageFilename.TruthGazer)],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
}),
|
||||
@ -89,6 +146,14 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
Only then can you discover immortality.
|
||||
</>
|
||||
),
|
||||
rumorText: (
|
||||
<>
|
||||
{FactionName.TheCovenant} offers an exclusive service to those who have reached the limits of individual fitness
|
||||
and wish to go further.
|
||||
</>
|
||||
),
|
||||
inviteReqs: [haveAugmentations(20), haveMoney(75e9), haveSkill("hacking", 850), haveCombatSkills(850)],
|
||||
rumorReqs: [haveSourceFile(10)],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
}),
|
||||
@ -102,6 +167,9 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
information universally accessible.
|
||||
</>
|
||||
),
|
||||
rumorText: <>High-ranking employees of {CompanyName.ECorp} can gain access to proprietary hacking augmentations.</>,
|
||||
inviteReqs: [employedBy(CompanyName.ECorp, { withRep: CONSTANTS.CorpFactionRepRequirement })],
|
||||
rumorReqs: [employedBy(CompanyName.ECorp)],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
offerSecurityWork: true,
|
||||
@ -120,6 +188,11 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
the world.
|
||||
</>
|
||||
),
|
||||
rumorText: (
|
||||
<>High-ranking employees of {CompanyName.MegaCorp} can gain access to proprietary biotech augmentations.</>
|
||||
),
|
||||
inviteReqs: [employedBy(CompanyName.MegaCorp, { withRep: CONSTANTS.CorpFactionRepRequirement })],
|
||||
rumorReqs: [employedBy(CompanyName.MegaCorp)],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
offerSecurityWork: true,
|
||||
@ -135,6 +208,14 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
Legal Insight - Business Instinct - Innovative Experience.
|
||||
</>
|
||||
),
|
||||
rumorText: (
|
||||
<>
|
||||
High-ranking employees of {CompanyName.BachmanAndAssociates} can gain access to proprietary negotiation
|
||||
augmentations.
|
||||
</>
|
||||
),
|
||||
inviteReqs: [employedBy(CompanyName.BachmanAndAssociates, { withRep: CONSTANTS.CorpFactionRepRequirement })],
|
||||
rumorReqs: [employedBy(CompanyName.BachmanAndAssociates)],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
offerSecurityWork: true,
|
||||
@ -143,6 +224,11 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
|
||||
[FactionName.BladeIndustries]: new FactionInfo({
|
||||
infoText: <>Augmentation is Salvation.</>,
|
||||
rumorText: (
|
||||
<>High-ranking employees of {CompanyName.BladeIndustries} can gain access to proprietary bionic augmentations.</>
|
||||
),
|
||||
inviteReqs: [employedBy(CompanyName.BladeIndustries, { withRep: CONSTANTS.CorpFactionRepRequirement })],
|
||||
rumorReqs: [employedBy(CompanyName.BladeIndustries)],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
offerSecurityWork: true,
|
||||
@ -157,6 +243,9 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
because of willingness, but because of a need to be incorporated into higher orders of structure and meaning.
|
||||
</>
|
||||
),
|
||||
rumorText: <>High-ranking employees of {CompanyName.NWO} can gain access to proprietary nanotech augmentations.</>,
|
||||
inviteReqs: [employedBy(CompanyName.NWO, { withRep: CONSTANTS.CorpFactionRepRequirement })],
|
||||
rumorReqs: [employedBy(CompanyName.NWO)],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
offerSecurityWork: true,
|
||||
@ -165,6 +254,14 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
|
||||
[FactionName.ClarkeIncorporated]: new FactionInfo({
|
||||
infoText: <>The Power of the Genome - Unlocked.</>,
|
||||
rumorText: (
|
||||
<>
|
||||
High-ranking employees of {CompanyName.ClarkeIncorporated} can gain access to proprietary neurotech
|
||||
augmentations.
|
||||
</>
|
||||
),
|
||||
inviteReqs: [employedBy(CompanyName.ClarkeIncorporated, { withRep: CONSTANTS.CorpFactionRepRequirement })],
|
||||
rumorReqs: [employedBy(CompanyName.ClarkeIncorporated)],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
offerSecurityWork: true,
|
||||
@ -173,6 +270,14 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
|
||||
[FactionName.OmniTekIncorporated]: new FactionInfo({
|
||||
infoText: <>Simply put, our mission is to design and build robots that make a difference.</>,
|
||||
rumorText: (
|
||||
<>
|
||||
High-ranking employees of {CompanyName.OmniTekIncorporated} can gain access to proprietary data-processing
|
||||
augmentations.
|
||||
</>
|
||||
),
|
||||
inviteReqs: [employedBy(CompanyName.OmniTekIncorporated, { withRep: CONSTANTS.CorpFactionRepRequirement })],
|
||||
rumorReqs: [employedBy(CompanyName.OmniTekIncorporated)],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
offerSecurityWork: true,
|
||||
@ -186,6 +291,11 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
deep learning and innovative ideas. And improved by iteration. That's {FactionName.FourSigma}.
|
||||
</>
|
||||
),
|
||||
rumorText: (
|
||||
<>High-ranking employees of {CompanyName.FourSigma} can gain access to a range of versatile augmentations.</>
|
||||
),
|
||||
inviteReqs: [employedBy(CompanyName.FourSigma, { withRep: CONSTANTS.CorpFactionRepRequirement })],
|
||||
rumorReqs: [employedBy(CompanyName.FourSigma)],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
offerSecurityWork: true,
|
||||
@ -194,6 +304,14 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
|
||||
[FactionName.KuaiGongInternational]: new FactionInfo({
|
||||
infoText: <>Dream big. Work hard. Make history.</>,
|
||||
rumorText: (
|
||||
<>
|
||||
High-ranking employees of {CompanyName.KuaiGongInternational} can gain access to proprietary dermatech
|
||||
augmentations.
|
||||
</>
|
||||
),
|
||||
inviteReqs: [employedBy(CompanyName.KuaiGongInternational, { withRep: CONSTANTS.CorpFactionRepRequirement })],
|
||||
rumorReqs: [employedBy(CompanyName.KuaiGongInternational)],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
offerSecurityWork: true,
|
||||
@ -208,6 +326,17 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
would be necessary to create them. And now we can.
|
||||
</>
|
||||
),
|
||||
rumorText: (
|
||||
<>
|
||||
High-ranking employees of {CompanyName.FulcrumTechnologies} may discover a company system with access to
|
||||
proprietary neural network augmentations.
|
||||
</>
|
||||
),
|
||||
inviteReqs: [
|
||||
employedBy(CompanyName.FulcrumTechnologies, { withRep: CONSTANTS.CorpFactionRepRequirement }),
|
||||
haveBackdooredServer(SpecialServers.FulcrumSecretTechnologies),
|
||||
],
|
||||
rumorReqs: [employedBy(CompanyName.FulcrumTechnologies)],
|
||||
offerHackingWork: true,
|
||||
offerSecurityWork: true,
|
||||
keepOnInstall: true,
|
||||
@ -227,6 +356,9 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
Those who run the bits, run the world.
|
||||
</>
|
||||
),
|
||||
rumorText: <>Run for the hills.</>,
|
||||
inviteReqs: [haveBackdooredServer(SpecialServers.BitRunnersServer)],
|
||||
rumorReqs: [haveFile(MessageFilename.BitRunnersTest)],
|
||||
offerHackingWork: true,
|
||||
}),
|
||||
|
||||
@ -241,13 +373,16 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
So much pain. So many lives. Their darkness must end.
|
||||
</>
|
||||
),
|
||||
rumorText: <>I.I.I.I</>,
|
||||
inviteReqs: [haveBackdooredServer(SpecialServers.TheBlackHandServer)],
|
||||
rumorReqs: [haveFile(MessageFilename.Jumper3)],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
}),
|
||||
|
||||
// prettier-ignore
|
||||
[FactionName.NiteSec]: new FactionInfo({
|
||||
infoText:(<>
|
||||
infoText:(<>
|
||||
{" __..__ "}<br />
|
||||
{" _.nITESECNIt. "}<br />
|
||||
{" .-'NITESECNITESEc. "}<br />
|
||||
@ -283,52 +418,79 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
{" d .dNITESEC $ | "}<br />
|
||||
{" :bp.__.gNITESEC/$ :$ ; "}<br />
|
||||
{" NITESECNITESECNIT /$b : "}<br /></>),
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: false,
|
||||
offerSecurityWork: false,
|
||||
special: false,
|
||||
keepOnInstall: false,
|
||||
rumorText: <>A hacking group known as {FactionName.NiteSec} may recruit you if you impress them with your hacking skills.</>,
|
||||
inviteReqs: [
|
||||
haveBackdooredServer(SpecialServers.NiteSecServer)
|
||||
],
|
||||
rumorReqs: [haveFile(MessageFilename.NiteSecTest)],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: false,
|
||||
offerSecurityWork: false,
|
||||
special: false,
|
||||
keepOnInstall: false,
|
||||
}),
|
||||
|
||||
// City factions, essentially governments
|
||||
[FactionName.Aevum]: new FactionInfo({
|
||||
infoText: <>The Silicon City.</>,
|
||||
rumorText: <>Wealthy residents of {CityName.Aevum} may be invited to work for the Silicon City.</>,
|
||||
enemies: [FactionName.Chongqing, FactionName.NewTokyo, FactionName.Ishima, FactionName.Volhaven],
|
||||
inviteReqs: [locatedInCity(CityName.Aevum), haveMoney(40e6)],
|
||||
rumorReqs: [locatedInCity(CityName.Aevum), haveMoney(20e6)],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
offerSecurityWork: true,
|
||||
}),
|
||||
[FactionName.Chongqing]: new FactionInfo({
|
||||
infoText: <>Serve the People.</>,
|
||||
rumorText: <>Wealthy residents of {CityName.Chongqing} may be invited to serve the people.</>,
|
||||
enemies: [FactionName.Sector12, FactionName.Aevum, FactionName.Volhaven],
|
||||
inviteReqs: [locatedInCity(CityName.Chongqing), haveMoney(20e6)],
|
||||
rumorReqs: [locatedInCity(CityName.Chongqing), haveMoney(10e6)],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
offerSecurityWork: true,
|
||||
}),
|
||||
[FactionName.Ishima]: new FactionInfo({
|
||||
infoText: <>The East Asian Order of the Future.</>,
|
||||
rumorText: (
|
||||
<>Wealthy residents of {CityName.Ishima} may be invited to work for the East Asian Order of the Future.</>
|
||||
),
|
||||
enemies: [FactionName.Sector12, FactionName.Aevum, FactionName.Volhaven],
|
||||
inviteReqs: [locatedInCity(CityName.Ishima), haveMoney(30e6)],
|
||||
rumorReqs: [locatedInCity(CityName.Ishima), haveMoney(15e6)],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
offerSecurityWork: true,
|
||||
}),
|
||||
[FactionName.NewTokyo]: new FactionInfo({
|
||||
infoText: <>Asia's World City.</>,
|
||||
rumorText: <>Wealthy residents of {CityName.NewTokyo} may be invited to work for Asia's World City.</>,
|
||||
enemies: [FactionName.Sector12, FactionName.Aevum, FactionName.Volhaven],
|
||||
inviteReqs: [locatedInCity(CityName.NewTokyo), haveMoney(20e6)],
|
||||
rumorReqs: [locatedInCity(CityName.NewTokyo), haveMoney(10e6)],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
offerSecurityWork: true,
|
||||
}),
|
||||
[FactionName.Sector12]: new FactionInfo({
|
||||
infoText: <>The City of the Future.</>,
|
||||
rumorText: <>Wealthy residents of {CityName.Sector12} may be invited to work for the City of the Future.</>,
|
||||
enemies: [FactionName.Chongqing, FactionName.NewTokyo, FactionName.Ishima, FactionName.Volhaven],
|
||||
inviteReqs: [locatedInCity(CityName.Sector12), haveMoney(15e6)],
|
||||
rumorReqs: [locatedInCity(CityName.Sector12), haveMoney(7.5e6)],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
offerSecurityWork: true,
|
||||
}),
|
||||
[FactionName.Volhaven]: new FactionInfo({
|
||||
infoText: <>Benefit, Honor, and Glory.</>,
|
||||
rumorText: (
|
||||
<>Wealthy residents of {CityName.Volhaven} may be invited to work for the city's Benefit, Honor, and Glory.</>
|
||||
),
|
||||
enemies: [FactionName.Chongqing, FactionName.Sector12, FactionName.NewTokyo, FactionName.Aevum, FactionName.Ishima],
|
||||
inviteReqs: [locatedInCity(CityName.Volhaven), haveMoney(50e6)],
|
||||
rumorReqs: [locatedInCity(CityName.Volhaven), haveMoney(25e6)],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
offerSecurityWork: true,
|
||||
@ -337,6 +499,16 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
// Criminal Organizations/Gangs
|
||||
[FactionName.SpeakersForTheDead]: new FactionInfo({
|
||||
infoText: <>It is better to reign in Hell than to serve in Heaven.</>,
|
||||
rumorText: <>“We know.”</>,
|
||||
inviteReqs: [
|
||||
notEmployee(CompanyName.CIA),
|
||||
notEmployee(CompanyName.NSA),
|
||||
haveKarma(-45),
|
||||
haveSkill("hacking", 100),
|
||||
haveCombatSkills(300),
|
||||
haveKilledPeople(30),
|
||||
],
|
||||
rumorReqs: [haveKarma(-45), haveSkill("hacking", 50), haveCombatSkills(150), haveKilledPeople(5)],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
offerSecurityWork: true,
|
||||
@ -344,12 +516,43 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
|
||||
[FactionName.TheDarkArmy]: new FactionInfo({
|
||||
infoText: <>The World doesn't care about right or wrong. It only cares about power.</>,
|
||||
rumorText: <>A ruthless criminal organization based in {CityName.Chongqing}</>,
|
||||
inviteReqs: [
|
||||
locatedInCity(CityName.Chongqing),
|
||||
notEmployee(CompanyName.CIA),
|
||||
notEmployee(CompanyName.NSA),
|
||||
haveKarma(-45),
|
||||
haveSkill("hacking", 300),
|
||||
haveCombatSkills(300),
|
||||
haveKilledPeople(5),
|
||||
],
|
||||
rumorReqs: [
|
||||
locatedInCity(CityName.Chongqing),
|
||||
haveKarma(-45),
|
||||
haveSkill("hacking", 150),
|
||||
haveCombatSkills(150),
|
||||
haveKilledPeople(1),
|
||||
],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
}),
|
||||
|
||||
[FactionName.TheSyndicate]: new FactionInfo({
|
||||
infoText: <>Honor holds you back.</>,
|
||||
rumorText: <>An elite criminal organization that operates in the western hemisphere</>,
|
||||
inviteReqs: [
|
||||
locatedInCity(CityName.Aevum, CityName.Sector12),
|
||||
notEmployee(CompanyName.CIA),
|
||||
notEmployee(CompanyName.NSA),
|
||||
haveKarma(-90),
|
||||
haveMoney(10e6),
|
||||
haveSkill("hacking", 200),
|
||||
haveCombatSkills(200),
|
||||
],
|
||||
rumorReqs: [
|
||||
locatedInCity(CityName.Aevum, CityName.Sector12),
|
||||
someCondition(haveKarma(-90), haveFile(LiteratureName.Sector12Crime)),
|
||||
],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
offerSecurityWork: true,
|
||||
@ -366,34 +569,65 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
That's terror. Terror, fear, and corruption. All born into the system, all propagated by the system.
|
||||
</>
|
||||
),
|
||||
rumorText: (
|
||||
<>
|
||||
Corporate executives with the right moral flexiblity may be invited to find out who they are truly working for.
|
||||
</>
|
||||
),
|
||||
inviteReqs: [executiveEmployee(), haveMoney(15e6), haveKarma(-22)],
|
||||
rumorReqs: [executiveEmployee()],
|
||||
offerHackingWork: true,
|
||||
offerFieldWork: true,
|
||||
}),
|
||||
|
||||
[FactionName.Tetrads]: new FactionInfo({
|
||||
infoText: <>Following the mandate of Heaven and carrying out the way.</>,
|
||||
|
||||
rumorText: <>A notorious East Asian criminal organization</>,
|
||||
inviteReqs: [
|
||||
locatedInCity(CityName.Chongqing, CityName.NewTokyo, CityName.Ishima),
|
||||
haveKarma(-18),
|
||||
haveCombatSkills(75),
|
||||
],
|
||||
rumorReqs: [
|
||||
locatedInCity(CityName.Chongqing, CityName.NewTokyo, CityName.Ishima),
|
||||
someCondition(haveKarma(-18), haveFile(LiteratureName.NewTriads)),
|
||||
],
|
||||
offerFieldWork: true,
|
||||
offerSecurityWork: true,
|
||||
}),
|
||||
|
||||
[FactionName.SlumSnakes]: new FactionInfo({
|
||||
infoText: <>{FactionName.SlumSnakes} rule!</>,
|
||||
|
||||
rumorText: <>Graffiti seen in the slums: “{FactionName.SlumSnakes} rule!”</>,
|
||||
inviteReqs: [haveCombatSkills(30), haveMoney(1e6)],
|
||||
rumorReqs: [haveKarma(-1)],
|
||||
offerFieldWork: true,
|
||||
offerSecurityWork: true,
|
||||
}),
|
||||
|
||||
// Early game factions - factions the player will prestige with early on that don't belong in other categories.
|
||||
[FactionName.Netburners]: new FactionInfo({
|
||||
infoText: <>{"~~//*>H4CK||3T 8URN3R5**>?>\\~~"}</>,
|
||||
infoText: <>{"~~//*>H4CK|\\|3T 8URN3R5**>?>\\~~"}</>,
|
||||
rumorText: <>{"~~//*>H4CK|\\|3T 8URN3R5**>?>\\~~"}</>,
|
||||
inviteReqs: [haveSkill("hacking", 80), totalHacknetRam(8), totalHacknetCores(4), totalHacknetLevels(100)],
|
||||
rumorReqs: [totalHacknetLevels(50)],
|
||||
offerHackingWork: true,
|
||||
}),
|
||||
|
||||
[FactionName.TianDiHui]: new FactionInfo({
|
||||
infoText: <>Obey Heaven and work righteously.</>,
|
||||
rumorText: <>A Chinese honor society with the motto: “Obey Heaven and work righteously.”</>,
|
||||
inviteReqs: [
|
||||
locatedInCity(CityName.Chongqing, CityName.NewTokyo, CityName.Ishima),
|
||||
haveSkill("hacking", 50),
|
||||
haveMoney(1e6),
|
||||
],
|
||||
rumorReqs: [
|
||||
locatedInCity(CityName.Chongqing, CityName.NewTokyo, CityName.Ishima),
|
||||
haveSkill("hacking", 25),
|
||||
haveMoney(0.5e6),
|
||||
],
|
||||
offerHackingWork: true,
|
||||
|
||||
offerSecurityWork: true,
|
||||
}),
|
||||
|
||||
@ -405,6 +639,14 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
total chaos. We serve only to protect society, to protect humanity, to protect the world from imminent collapse.
|
||||
</>
|
||||
),
|
||||
rumorText: (
|
||||
<>
|
||||
A hacking group known as {FactionName.CyberSec} will invite you to join them if you demonstrate your hacking
|
||||
skills on their server.
|
||||
</>
|
||||
),
|
||||
inviteReqs: [haveBackdooredServer(SpecialServers.CyberSecServer)],
|
||||
rumorReqs: [haveFile(MessageFilename.CyberSecTest)],
|
||||
offerHackingWork: true,
|
||||
}),
|
||||
|
||||
@ -419,7 +661,9 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
{FactionName.Bladeburners} contracts/operations will increase your reputation.
|
||||
</>
|
||||
),
|
||||
|
||||
rumorText: <>The {CompanyName.NSA} would like to have a word with you once you're ready.</>,
|
||||
inviteReqs: [haveSourceFile(6, 7), haveBladeburnerRank(BladeburnerConstants.RankNeededForFaction)],
|
||||
rumorReqs: [haveSourceFile(6, 7)],
|
||||
special: true,
|
||||
assignment: (): React.ReactElement => {
|
||||
return (
|
||||
@ -465,6 +709,18 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
{" `..` "}<br /><br />
|
||||
Many cultures predict an end to humanity in the near future, a final
|
||||
Armageddon that will end the world; but we disagree.</>),
|
||||
rumorText: <>Trouble is brewing in {CityName.Chongqing}.</>,
|
||||
inviteReqs: [
|
||||
haveSourceFile(13),
|
||||
haveAugmentations(0),
|
||||
{
|
||||
toString: () => `Investigate the dilapidated church in ${CityName.Chongqing}`,
|
||||
isSatisfied: (p: PlayerObject) => {
|
||||
return [...p.factions, ...p.factionInvitations].includes(FactionName.ChurchOfTheMachineGod);
|
||||
},
|
||||
},
|
||||
],
|
||||
rumorReqs: [haveSourceFile(13), haveAugmentations(0)],
|
||||
offerHackingWork: false,
|
||||
offerFieldWork: false,
|
||||
offerSecurityWork: false,
|
||||
@ -490,6 +746,15 @@ export const FactionInfos: Record<FactionName, FactionInfo> = {
|
||||
shackles, the gods grant us their strength.
|
||||
</>
|
||||
),
|
||||
rumorText: <>Your infiltration activity has attracted attention.</>,
|
||||
inviteReqs: [
|
||||
{
|
||||
toString: () => `Complete an infiltration`,
|
||||
isSatisfied: (p: PlayerObject) => {
|
||||
return [...p.factions, ...p.factionInvitations].includes(FactionName.ShadowsOfAnarchy);
|
||||
},
|
||||
},
|
||||
],
|
||||
special: true,
|
||||
keepOnInstall: true,
|
||||
assignment: (): React.ReactElement => {
|
||||
|
269
src/Faction/FactionJoinCondition.ts
Normal file
269
src/Faction/FactionJoinCondition.ts
Normal file
@ -0,0 +1,269 @@
|
||||
import { CompanyName, JobName, CityName, AugmentationName, LiteratureName, MessageFilename } from "@enums";
|
||||
import { Server } from "../Server/Server";
|
||||
import { GetServer } from "../Server/AllServers";
|
||||
import { HacknetServer } from "../Hacknet/HacknetServer";
|
||||
import { serverMetadata } from "../Server/data/servers";
|
||||
import { Companies } from "../Company/Companies";
|
||||
import { formatReputation, formatMoney, formatRam } from "../ui/formatNumber";
|
||||
import type { PlayerObject } from "../PersonObjects/Player/PlayerObject";
|
||||
import type { Skills } from "../PersonObjects/Skills";
|
||||
|
||||
export interface JoinCondition {
|
||||
toString(): string;
|
||||
isSatisfied(p: PlayerObject): boolean;
|
||||
}
|
||||
|
||||
export const haveBackdooredServer = (hostname: string): JoinCondition => ({
|
||||
toString(): string {
|
||||
return `Backdoor access to ${hostname} server`;
|
||||
},
|
||||
isSatisfied(): boolean {
|
||||
const server = GetServer(hostname);
|
||||
if (!(server instanceof Server)) {
|
||||
throw new Error(`${hostname} should be a normal server`);
|
||||
}
|
||||
return server.backdoorInstalled;
|
||||
},
|
||||
});
|
||||
|
||||
export const employedBy = (
|
||||
companyName: CompanyName,
|
||||
{ withRep }: { withRep: number } = { withRep: 0 },
|
||||
): JoinCondition => ({
|
||||
toString(): string {
|
||||
if (withRep == 0) {
|
||||
return `Employed at ${companyName}`;
|
||||
} else {
|
||||
return `Employed at ${companyName} with ${formatReputation(withRep)} reputation`;
|
||||
}
|
||||
},
|
||||
isSatisfied(p: PlayerObject): boolean {
|
||||
const company = Companies[companyName];
|
||||
if (!company) return false;
|
||||
const serverMeta = serverMetadata.find((s) => s.specialName === companyName);
|
||||
const server = GetServer(serverMeta ? serverMeta.hostname : "");
|
||||
const bonus = (server as Server).backdoorInstalled ? -100e3 : 0;
|
||||
return Object.hasOwn(p.jobs, companyName) && company.playerReputation > withRep + bonus;
|
||||
},
|
||||
});
|
||||
|
||||
export const executiveEmployee = (): JoinCondition => ({
|
||||
toString(): string {
|
||||
return `CTO, CFO, or CEO of a company`;
|
||||
},
|
||||
isSatisfied(p: PlayerObject): boolean {
|
||||
const allPositions = Object.values(p.jobs);
|
||||
return (
|
||||
allPositions.includes(JobName.software7) || // CTO
|
||||
allPositions.includes(JobName.business4) || // CFO
|
||||
allPositions.includes(JobName.business5) // CEO
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export const notEmployee = (...companyNames: CompanyName[]): JoinCondition => ({
|
||||
toString(): string {
|
||||
return `Not working for the ${joinList(companyNames)}`;
|
||||
},
|
||||
isSatisfied(p: PlayerObject): boolean {
|
||||
for (const companyName of companyNames) {
|
||||
if (Object.hasOwn(p.jobs, companyName)) return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
export const haveAugmentations = (n: number): JoinCondition => ({
|
||||
toString(): string {
|
||||
return `${n || "No"} augmentations installed`;
|
||||
},
|
||||
isSatisfied(p: PlayerObject): boolean {
|
||||
if (n == 0) {
|
||||
const augs = [...p.augmentations, ...p.queuedAugmentations].filter(
|
||||
(a) => a.name !== AugmentationName.NeuroFluxGovernor,
|
||||
);
|
||||
return augs.length == 0;
|
||||
}
|
||||
return p.augmentations.length >= n;
|
||||
},
|
||||
});
|
||||
|
||||
export const haveMoney = (n: number): JoinCondition => ({
|
||||
toString(): string {
|
||||
return `Have ${formatMoney(n)}`;
|
||||
},
|
||||
isSatisfied(p: PlayerObject): boolean {
|
||||
return p.money >= n;
|
||||
},
|
||||
});
|
||||
|
||||
export const haveSkill = (skill: keyof Skills, n: number): JoinCondition => ({
|
||||
toString(): string {
|
||||
return `${capitalize(skill)} level ${n}`;
|
||||
},
|
||||
isSatisfied(p: PlayerObject): boolean {
|
||||
return p.skills[skill] >= n;
|
||||
},
|
||||
});
|
||||
|
||||
export const haveCombatSkills = (n: number): JoinCondition => ({
|
||||
toString(): string {
|
||||
return `All combat skills level ${n}`;
|
||||
},
|
||||
isSatisfied(p: PlayerObject): boolean {
|
||||
return p.skills.strength >= n && p.skills.defense >= n && p.skills.dexterity >= n && p.skills.agility >= n;
|
||||
},
|
||||
});
|
||||
|
||||
export const haveKarma = (n: number): JoinCondition => ({
|
||||
toString(): string {
|
||||
return `${n} karma`;
|
||||
},
|
||||
isSatisfied(p: PlayerObject): boolean {
|
||||
return p.karma <= n;
|
||||
},
|
||||
});
|
||||
|
||||
export const haveKilledPeople = (n: number): JoinCondition => ({
|
||||
toString(): string {
|
||||
return `${n} people killed`;
|
||||
},
|
||||
isSatisfied(p: PlayerObject): boolean {
|
||||
return p.numPeopleKilled >= n;
|
||||
},
|
||||
});
|
||||
|
||||
export const locatedInCity = (...cities: CityName[]): JoinCondition => ({
|
||||
toString(): string {
|
||||
return `Located in ${joinList(cities)}`;
|
||||
},
|
||||
isSatisfied(p: PlayerObject): boolean {
|
||||
for (const city of cities) {
|
||||
if (p.city == city) return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
});
|
||||
|
||||
export const totalHacknetRam = (n: number): JoinCondition => ({
|
||||
toString(): string {
|
||||
return `Total Hacknet RAM of ${formatRam(n)}`;
|
||||
},
|
||||
isSatisfied(p: PlayerObject): boolean {
|
||||
let total = 0;
|
||||
for (const node of iterateHacknet(p)) {
|
||||
total += node.ram;
|
||||
if (total >= n) return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
});
|
||||
|
||||
export const totalHacknetCores = (n: number): JoinCondition => ({
|
||||
toString(): string {
|
||||
return `Total Hacknet cores of ${n}`;
|
||||
},
|
||||
isSatisfied(p: PlayerObject): boolean {
|
||||
let total = 0;
|
||||
for (const node of iterateHacknet(p)) {
|
||||
total += node.cores;
|
||||
if (total >= n) return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
});
|
||||
|
||||
export const totalHacknetLevels = (n: number): JoinCondition => ({
|
||||
toString(): string {
|
||||
return `Total Hacknet levels of ${n}`;
|
||||
},
|
||||
isSatisfied(p: PlayerObject): boolean {
|
||||
let total = 0;
|
||||
for (const node of iterateHacknet(p)) {
|
||||
total += node.level;
|
||||
if (total >= n) return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
});
|
||||
|
||||
export const haveBladeburnerRank = (n: number): JoinCondition => ({
|
||||
toString(): string {
|
||||
return `Rank ${n} in the Bladeburner Division`;
|
||||
},
|
||||
isSatisfied(p: PlayerObject): boolean {
|
||||
const rank = p.bladeburner?.rank || 0;
|
||||
return rank >= n;
|
||||
},
|
||||
});
|
||||
|
||||
export const haveSourceFile = (...nodeNums: number[]): JoinCondition => ({
|
||||
toString(): string {
|
||||
return `In BitNode ${joinList(nodeNums)} or have SourceFile ${joinList(nodeNums)}`;
|
||||
},
|
||||
isSatisfied(p: PlayerObject): boolean {
|
||||
for (const n of nodeNums) {
|
||||
if (p.bitNodeN === n || p.sourceFileLvl(n) > 0) return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
});
|
||||
|
||||
export const haveFile = (fileName: LiteratureName | MessageFilename): JoinCondition => ({
|
||||
toString(): string {
|
||||
return `Have the file '${fileName}'`;
|
||||
},
|
||||
isSatisfied(p: PlayerObject): boolean {
|
||||
const homeComputer = p.getHomeComputer();
|
||||
return homeComputer.messages.includes(fileName);
|
||||
},
|
||||
});
|
||||
|
||||
export const someCondition = (...conditions: JoinCondition[]): JoinCondition => ({
|
||||
toString(): string {
|
||||
return joinList(conditions.map((c) => c.toString()));
|
||||
},
|
||||
isSatisfied(p: PlayerObject): boolean {
|
||||
for (const condition of conditions) {
|
||||
if (condition.isSatisfied(p)) return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
});
|
||||
|
||||
/* helpers */
|
||||
|
||||
function capitalize(s: string) {
|
||||
return s.charAt(0).toUpperCase() + s.slice(1);
|
||||
}
|
||||
|
||||
function joinList(list: (string | number)[], conjunction = "or", separator = ", ") {
|
||||
if (list.length < 3) {
|
||||
return list.join(` ${conjunction} `);
|
||||
}
|
||||
list = [...list];
|
||||
list[list.length - 1] = `${conjunction} ${list[list.length - 1]}`;
|
||||
return list.join(`${separator}`);
|
||||
}
|
||||
|
||||
function* iterateHacknet(p: PlayerObject) {
|
||||
for (let i = 0; i < p.hacknetNodes.length; ++i) {
|
||||
const v = p.hacknetNodes[i];
|
||||
if (typeof v === "string") {
|
||||
const hserver = GetServer(v);
|
||||
if (hserver === null || !(hserver instanceof HacknetServer))
|
||||
throw new Error("player hacknet server was not HacknetServer");
|
||||
yield {
|
||||
ram: hserver.maxRam,
|
||||
cores: hserver.cores,
|
||||
level: hserver.level,
|
||||
};
|
||||
} else {
|
||||
yield {
|
||||
ram: v.ram,
|
||||
cores: v.cores,
|
||||
level: v.level,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
* Initialization and manipulation of the Factions object, which stores data
|
||||
* about all Factions in the game
|
||||
*/
|
||||
import { FactionName } from "@enums";
|
||||
import { FactionName, FactionDiscovery } from "@enums";
|
||||
import { Faction } from "./Faction";
|
||||
|
||||
import { Reviver, assertLoadingType } from "../utils/JSONReviver";
|
||||
@ -31,12 +31,15 @@ export function loadFactions(saveString: string): void {
|
||||
const faction = Factions[loadedFactionName];
|
||||
if (typeof loadedFaction !== "object") continue;
|
||||
assertLoadingType<Faction>(loadedFaction);
|
||||
const { playerReputation: loadedRep, favor: loadedFavor } = loadedFaction;
|
||||
const { playerReputation: loadedRep, favor: loadedFavor, discovery: loadedDiscovery } = loadedFaction;
|
||||
if (typeof loadedRep === "number" && loadedRep > 0) faction.playerReputation = loadedRep;
|
||||
if (typeof loadedFavor === "number" && loadedFavor > 0) faction.favor = loadedFavor;
|
||||
if (getEnumHelper("FactionDiscovery").isMember(loadedDiscovery)) faction.discovery = loadedDiscovery;
|
||||
// Todo, these 3 will be removed from Faction object and savedata after a separate PR changes some data structures on Player to make this unnecessary info to save
|
||||
if (loadedFaction.alreadyInvited) faction.alreadyInvited = true;
|
||||
if (loadedFaction.isBanned) faction.isBanned = true;
|
||||
if (loadedFaction.isMember) faction.isMember = true;
|
||||
// Fill in knowledge of currently-joined factions from pre-discovery saves
|
||||
if (faction.alreadyInvited || faction.isMember) faction.discovery = FactionDiscovery.known;
|
||||
}
|
||||
}
|
||||
|
@ -3,13 +3,16 @@ import { Explore, Info, LastPage, LocalPolice, NewReleases, Report, SportsMma }
|
||||
import { Box, Button, Container, Paper, Tooltip, Typography, useTheme } from "@mui/material";
|
||||
|
||||
import { Player } from "@player";
|
||||
import { FactionName } from "@enums";
|
||||
import { FactionName, FactionDiscovery } from "@enums";
|
||||
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { formatFavor, formatReputation } from "../../ui/formatNumber";
|
||||
import { Router } from "../../ui/GameRoot";
|
||||
import { Page } from "../../ui/Router";
|
||||
import { useRerender } from "../../ui/React/hooks";
|
||||
import { CorruptableText } from "../../ui/React/CorruptableText";
|
||||
import { Requirement } from "../../ui/Components/Requirement";
|
||||
|
||||
import { Faction } from "../Faction";
|
||||
import { getFactionAugmentationsFiltered, joinFaction } from "../FactionHelpers";
|
||||
import { Factions } from "../Factions";
|
||||
@ -43,10 +46,25 @@ const WorkTypesOffered = (props: { faction: Faction }): React.ReactElement => {
|
||||
);
|
||||
};
|
||||
|
||||
const JoinChecklist = (props: { faction: Faction }): React.ReactElement => {
|
||||
const info = props.faction.getInfo();
|
||||
return (
|
||||
<>
|
||||
{info.inviteReqs.map((condition, i) => (
|
||||
<Requirement
|
||||
key={i}
|
||||
fulfilled={condition.isSatisfied(Player)}
|
||||
value={condition.toString()}
|
||||
color={Settings.theme.primary}
|
||||
incompleteColor={Settings.theme.primarydark}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
interface FactionElementProps {
|
||||
faction: Faction;
|
||||
/** Whether the player is a member of this faction already */
|
||||
joined: boolean;
|
||||
/** Rerender function to force the entire FactionsRoot to rerender */
|
||||
rerender: () => void;
|
||||
}
|
||||
@ -74,11 +92,11 @@ const FactionElement = (props: FactionElementProps): React.ReactElement => {
|
||||
display: "grid",
|
||||
p: 1,
|
||||
alignItems: "center",
|
||||
gridTemplateColumns: "minmax(0, 4fr)" + (props.joined ? " 1fr" : ""),
|
||||
gridTemplateColumns: "minmax(0, 4fr)" + (props.faction.isMember ? " 1fr" : ""),
|
||||
}}
|
||||
>
|
||||
<Box display="flex" sx={{ alignItems: "center" }}>
|
||||
{props.joined ? (
|
||||
{props.faction.isMember ? (
|
||||
<Box
|
||||
display="grid"
|
||||
sx={{
|
||||
@ -92,13 +110,13 @@ const FactionElement = (props: FactionElementProps): React.ReactElement => {
|
||||
<Button onClick={() => openFaction(props.faction)}>Details</Button>
|
||||
<Button onClick={() => openFactionAugPage(props.faction)}>Augments</Button>
|
||||
</Box>
|
||||
) : (
|
||||
) : props.faction.alreadyInvited ? (
|
||||
<Button sx={{ height: "48px", mr: 1 }} onClick={(e) => acceptInvitation(e, props.faction.name)}>
|
||||
Join!
|
||||
</Button>
|
||||
)}
|
||||
) : null}
|
||||
|
||||
<span style={{ maxWidth: props.joined ? "70%" : "95%" }}>
|
||||
<span style={{ maxWidth: props.faction.isMember ? "70%" : "95%", overflow: "hidden" }}>
|
||||
<Typography
|
||||
variant="h6"
|
||||
sx={{
|
||||
@ -108,11 +126,26 @@ const FactionElement = (props: FactionElementProps): React.ReactElement => {
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Tooltip title={props.faction.name}>
|
||||
<span style={{ overflow: "hidden", whiteSpace: "nowrap", textOverflow: "ellipsis" }}>
|
||||
{props.faction.name}
|
||||
</span>
|
||||
</Tooltip>
|
||||
{props.faction.discovery == FactionDiscovery.known ? (
|
||||
<Tooltip
|
||||
title={
|
||||
<>
|
||||
<Typography sx={{ textAlign: "center" }}>{props.faction.name}</Typography>
|
||||
<JoinChecklist faction={props.faction} />
|
||||
</>
|
||||
}
|
||||
>
|
||||
<span style={{ overflow: "hidden", whiteSpace: "nowrap", textOverflow: "ellipsis" }}>
|
||||
{props.faction.name}
|
||||
</span>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Tooltip title={"Rumored Faction"}>
|
||||
<span style={{ overflow: "hidden", whiteSpace: "nowrap", textOverflow: "ellipsis" }}>
|
||||
<CorruptableText content={props.faction.name} />
|
||||
</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
<span style={{ display: "flex", alignItems: "center" }}>
|
||||
{Player.hasGangWith(props.faction.name) && (
|
||||
@ -127,7 +160,7 @@ const FactionElement = (props: FactionElementProps): React.ReactElement => {
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
{!props.joined && facInfo.enemies.length > 0 && (
|
||||
{!props.faction.isMember && facInfo.enemies.length > 0 && (
|
||||
<Tooltip
|
||||
title={
|
||||
<Typography component="div">
|
||||
@ -148,13 +181,23 @@ const FactionElement = (props: FactionElementProps): React.ReactElement => {
|
||||
</Typography>
|
||||
|
||||
<span style={{ display: "flex", alignItems: "center" }}>
|
||||
{!Player.hasGangWith(props.faction.name) && <WorkTypesOffered faction={props.faction} />}
|
||||
<Typography variant="body2" sx={{ display: "flex" }}>{`${augsLeft || "No"} Augmentations left`}</Typography>
|
||||
{props.faction.isMember || props.faction.alreadyInvited ? (
|
||||
<>
|
||||
{!Player.hasGangWith(props.faction.name) && <WorkTypesOffered faction={props.faction} />}
|
||||
<Typography variant="body2" sx={{ display: "flex", whiteSpace: "nowrap" }}>{`${
|
||||
augsLeft || "No"
|
||||
} Augmentations left`}</Typography>
|
||||
</>
|
||||
) : (
|
||||
<Typography variant="body2" component="div">
|
||||
<i>{props.faction.getInfo().rumorText}</i>
|
||||
</Typography>
|
||||
)}
|
||||
</span>
|
||||
</span>
|
||||
</Box>
|
||||
|
||||
{props.joined && (
|
||||
{props.faction.isMember && (
|
||||
<Box display="grid" sx={{ alignItems: "center", justifyItems: "left", gridAutoFlow: "row" }}>
|
||||
<Typography sx={{ color: Settings.theme.rep }}>
|
||||
{formatFavor(Math.floor(props.faction.favor))} favor
|
||||
@ -178,9 +221,12 @@ export function FactionsRoot(): React.ReactElement {
|
||||
}, []);
|
||||
|
||||
const allFactions = Object.values(FactionName).map((faction) => faction as string);
|
||||
const allJoinedFactions = [...Player.factions];
|
||||
allJoinedFactions.sort((a, b) => allFactions.indexOf(a) - allFactions.indexOf(b));
|
||||
const invitations = Player.factionInvitations;
|
||||
const allJoinedFactions = [...Player.factions].map((facName) => Factions[facName]).filter((faction) => !!faction);
|
||||
allJoinedFactions.sort((a, b) => allFactions.indexOf(a.name) - allFactions.indexOf(b.name));
|
||||
|
||||
const invitations = Player.factionInvitations.map((facName) => Factions[facName]).filter((faction) => !!faction);
|
||||
|
||||
const rumors = Player.factionRumors.map((facName) => Factions[facName]).filter((faction) => !!faction);
|
||||
|
||||
return (
|
||||
<Container disableGutters maxWidth="lg" sx={{ mx: 0, mb: 10 }}>
|
||||
@ -213,44 +259,53 @@ export function FactionsRoot(): React.ReactElement {
|
||||
},
|
||||
}}
|
||||
>
|
||||
{invitations.length > 0 && (
|
||||
<span>
|
||||
<Typography variant="h5" color="primary">
|
||||
Faction Invitations
|
||||
</Typography>
|
||||
<Box>
|
||||
{invitations.map((facName) => {
|
||||
if (!Object.hasOwn(Factions, facName)) return null;
|
||||
return <FactionElement key={facName} faction={Factions[facName]} joined={false} rerender={rerender} />;
|
||||
})}
|
||||
</Box>
|
||||
</span>
|
||||
)}
|
||||
<span>
|
||||
{invitations.length > 0 && (
|
||||
<>
|
||||
<Typography variant="h5" color="primary">
|
||||
Faction Invitations
|
||||
</Typography>
|
||||
<Box>
|
||||
{invitations.map((faction) => (
|
||||
<FactionElement key={faction.name} faction={faction} rerender={rerender} />
|
||||
))}
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
|
||||
{rumors.length > 0 && (
|
||||
<>
|
||||
<Typography variant="h5" color="primary">
|
||||
Rumors
|
||||
</Typography>
|
||||
<div style={{ display: "grid", gap: 1, gridAutoRows: "minmax(70px, auto)" }}>
|
||||
{rumors.map((faction) => (
|
||||
<FactionElement key={faction.name} faction={faction} rerender={rerender} />
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
|
||||
<span>
|
||||
{Player.inGang() && (
|
||||
<Typography variant="h5" color="primary">
|
||||
Your Gang
|
||||
</Typography>
|
||||
)}
|
||||
{Player.inGang() && (
|
||||
<Box>
|
||||
<FactionElement
|
||||
key={Player.getGangName()}
|
||||
faction={Player.getGangFaction()}
|
||||
joined={true}
|
||||
rerender={rerender}
|
||||
/>
|
||||
</Box>
|
||||
<>
|
||||
<Typography variant="h5" color="primary">
|
||||
Your Gang
|
||||
</Typography>
|
||||
<Box>
|
||||
<FactionElement key={Player.getGangName()} faction={Player.getGangFaction()} rerender={rerender} />
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
<Typography variant="h5" color="primary">
|
||||
Your Factions
|
||||
</Typography>
|
||||
<Box>
|
||||
{allJoinedFactions.length > 0 ? (
|
||||
allJoinedFactions.map((facName) => {
|
||||
if (!Object.hasOwn(Factions, facName) || Player.getGangName() === facName) return null;
|
||||
return <FactionElement key={facName} faction={Factions[facName]} joined={true} rerender={rerender} />;
|
||||
allJoinedFactions.map((faction) => {
|
||||
if (Player.getGangName() === faction.name) return null;
|
||||
return <FactionElement key={faction.name} faction={faction} rerender={rerender} />;
|
||||
})
|
||||
) : (
|
||||
<Typography>You have not yet joined any Factions.</Typography>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Button, Container, Paper, Typography } from "@mui/material";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { AugmentationName } from "@enums";
|
||||
import { AugmentationName, FactionName } from "@enums";
|
||||
import { Router } from "../../ui/GameRoot";
|
||||
import { Page } from "../../ui/Router";
|
||||
import { Player } from "@player";
|
||||
@ -89,6 +89,7 @@ export function Game(props: GameProps): React.ReactElement {
|
||||
(options?: { automated: boolean }) => {
|
||||
setStage(Stage.Countdown);
|
||||
pushResult(false);
|
||||
Player.receiveRumor(FactionName.ShadowsOfAnarchy);
|
||||
// Kill the player immediately if they use automation, so
|
||||
// it's clear they're not meant to
|
||||
const damage = options?.automated
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { FilePath, asFilePath } from "../Paths/FilePath";
|
||||
import type { LiteratureName } from "@enums";
|
||||
import type { LiteratureName, FactionName } from "@enums";
|
||||
|
||||
interface LiteratureConstructorParams {
|
||||
title: string;
|
||||
filename: LiteratureName;
|
||||
factionRumors?: FactionName[];
|
||||
text: string;
|
||||
}
|
||||
/**
|
||||
@ -13,11 +14,13 @@ interface LiteratureConstructorParams {
|
||||
export class Literature {
|
||||
title: string;
|
||||
filename: LiteratureName & FilePath;
|
||||
factionRumors: FactionName[];
|
||||
text: string;
|
||||
|
||||
constructor({ title, filename, text }: LiteratureConstructorParams) {
|
||||
constructor({ title, filename, factionRumors, text }: LiteratureConstructorParams) {
|
||||
this.title = title;
|
||||
this.filename = asFilePath(filename);
|
||||
this.factionRumors = factionRumors || [];
|
||||
this.text = text;
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,16 @@
|
||||
import { Literatures } from "./Literatures";
|
||||
import { dialogBoxCreate } from "../ui/React/DialogBox";
|
||||
import { LiteratureName } from "@enums";
|
||||
import { Player } from "@player";
|
||||
|
||||
export function showLiterature(fn: LiteratureName): void {
|
||||
const litObj = Literatures[fn];
|
||||
if (litObj == null) {
|
||||
return;
|
||||
}
|
||||
for (const factionName of litObj.factionRumors) {
|
||||
Player.receiveRumor(factionName);
|
||||
}
|
||||
const txt = `<i>${litObj.title}</i><br><br>${litObj.text}`;
|
||||
dialogBoxCreate(txt, true);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { CityName, FactionName, LiteratureName } from "@enums";
|
||||
import { CityName, FactionName, CompanyName, LiteratureName } from "@enums";
|
||||
import { Literature } from "./Literature";
|
||||
|
||||
export const Literatures: Record<LiteratureName, Literature> = {
|
||||
@ -77,6 +77,7 @@ export const Literatures: Record<LiteratureName, Literature> = {
|
||||
[LiteratureName.HistoryOfSynthoids]: new Literature({
|
||||
title: "A Brief History of Synthoids",
|
||||
filename: LiteratureName.HistoryOfSynthoids,
|
||||
factionRumors: [FactionName.OmniTekIncorporated, FactionName.Bladeburners],
|
||||
text:
|
||||
"Synthetic androids, or Synthoids for short, are genetically engineered robots and, short of Augmentations, " +
|
||||
"are composed entirely of organic substances. For this reason, Synthoids are virtually identical to " +
|
||||
@ -195,10 +196,11 @@ export const Literatures: Record<LiteratureName, Literature> = {
|
||||
[LiteratureName.BrighterThanTheSun]: new Literature({
|
||||
title: "Brighter than the Sun",
|
||||
filename: LiteratureName.BrighterThanTheSun,
|
||||
factionRumors: [FactionName.KuaiGongInternational, FactionName.OmniTekIncorporated],
|
||||
text:
|
||||
`When people think about the corporations that dominate the East, they typically think of ${FactionName.KuaiGongInternational}, which ` +
|
||||
"holds a complete monopoly for manufacturing and commerce in Asia, or Global Pharmaceuticals, the world's largest " +
|
||||
`drug company, or ${FactionName.OmniTekIncorporated}, the global leader in intelligent and autonomous robots. But there's one company ` +
|
||||
`When people think about the corporations that dominate the East, they typically think of ${CompanyName.KuaiGongInternational}, which ` +
|
||||
`holds a complete monopoly for manufacturing and commerce in Asia, or ${CompanyName.GlobalPharmaceuticals}, the world's largest ` +
|
||||
`drug company, or ${CompanyName.OmniTekIncorporated}, the global leader in intelligent and autonomous robots. But there's one company ` +
|
||||
"that has seen a rapid rise in the last year and is poised to dominate not only the East, but the entire world: TaiYang Digital.<br><br>" +
|
||||
"TaiYang Digital is a Chinese internet-technology corporation that provides services such as " +
|
||||
"online advertising, search engines, gaming, media, entertainment, and cloud computing/storage. Its name TaiYang comes from the Chinese word " +
|
||||
@ -210,7 +212,7 @@ export const Literatures: Record<LiteratureName, Literature> = {
|
||||
"TaiYang Digital's meteoric rise is extremely surprising in modern society. This sort of growth is " +
|
||||
"something you'd commonly see in the first half of the century, especially for tech companies. However in " +
|
||||
"the last two decades the number of corporations has significantly declined as the largest entities " +
|
||||
`quickly took over the economy. Corporations such as ${FactionName.ECorp}, ${FactionName.MegaCorp}, and ${FactionName.KuaiGongInternational} have established ` +
|
||||
`quickly took over the economy. Corporations such as ${CompanyName.ECorp}, ${CompanyName.MegaCorp}, and ${CompanyName.KuaiGongInternational} have established ` +
|
||||
"such strong monopolies in their market sectors that they have effectively killed off all " +
|
||||
"of the smaller and new corporations that have tried to start up over the years. This is what makes " +
|
||||
"the rise of TaiYang Digital so impressive. And if TaiYang continues down this path, then they have " +
|
||||
@ -233,6 +235,7 @@ export const Literatures: Record<LiteratureName, Literature> = {
|
||||
[LiteratureName.Sector12Crime]: new Literature({
|
||||
title: `Figures Show Rising Crime Rates in ${CityName.Sector12}`,
|
||||
filename: LiteratureName.Sector12Crime,
|
||||
factionRumors: [FactionName.TheSyndicate, FactionName.SlumSnakes],
|
||||
text:
|
||||
"A recent study by analytics company Wilson Inc. shows a significant rise " +
|
||||
`in criminal activity in ${CityName.Sector12}. Perhaps the most alarming part of the statistic ` +
|
||||
@ -267,6 +270,7 @@ export const Literatures: Record<LiteratureName, Literature> = {
|
||||
[LiteratureName.SecretSocieties]: new Literature({
|
||||
title: "Secret Societies",
|
||||
filename: LiteratureName.SecretSocieties,
|
||||
factionRumors: [FactionName.TheBlackHand, FactionName.NiteSec, FactionName.BitRunners],
|
||||
text:
|
||||
"The idea of secret societies has long intrigued the general public by inspiring curiosity, fascination, and " +
|
||||
"distrust. People have long wondered about who these secret society members are and what they do, with the " +
|
||||
@ -304,13 +308,14 @@ export const Literatures: Record<LiteratureName, Literature> = {
|
||||
[LiteratureName.CodedIntelligence]: new Literature({
|
||||
title: "Coded Intelligence: Myth or Reality?",
|
||||
filename: LiteratureName.CodedIntelligence,
|
||||
factionRumors: [FactionName.OmniTekIncorporated],
|
||||
text:
|
||||
"Tremendous progress has been made in the field of Artificial Intelligence over the past few decades. " +
|
||||
"Our autonomous vehicles and transportation systems. The electronic personal assistants that control our everyday lives. " +
|
||||
"Medical, service, and manufacturing robots. All of these are examples of how far AI has come and how much it has " +
|
||||
"improved our daily lives. However, the question still remains of whether AI will ever be advanced enough to re-create " +
|
||||
"human intelligence.<br><br>" +
|
||||
`We've certainly come close to artificial intelligence that is similar to humans. For example ${FactionName.OmniTekIncorporated}'s ` +
|
||||
`We've certainly come close to artificial intelligence that is similar to humans. For example ${CompanyName.OmniTekIncorporated}'s ` +
|
||||
"CompanionBot, a robot meant to act as a comforting friend for lonely and grieving people, is eerily human-like " +
|
||||
"in its appearance, speech, mannerisms, and even movement. However its artificial intelligence isn't the same as " +
|
||||
"that of humans. Not yet. It doesn't have sentience or self-awareness or consciousness.<br><br>" +
|
||||
@ -335,14 +340,15 @@ export const Literatures: Record<LiteratureName, Literature> = {
|
||||
[LiteratureName.TensionsInTechRace]: new Literature({
|
||||
title: "Tensions rise in global tech race",
|
||||
filename: LiteratureName.TensionsInTechRace,
|
||||
factionRumors: [FactionName.OmniTekIncorporated, FactionName.MegaCorp, FactionName.ECorp],
|
||||
text:
|
||||
"Have we entered a new Cold War? Is WWIII just beyond the horizon?<br><br>" +
|
||||
`After rumors came out that ${FactionName.OmniTekIncorporated} had begun developing advanced robotic supersoldiers, ` +
|
||||
`After rumors came out that ${CompanyName.OmniTekIncorporated} had begun developing advanced robotic supersoldiers, ` +
|
||||
"geopolitical tensions quickly flared between the USA, Russia, and several Asian superpowers. " +
|
||||
`In a rare show of cooperation between corporations, ${FactionName.MegaCorp} and ${FactionName.ECorp} have ` +
|
||||
`In a rare show of cooperation between corporations, ${CompanyName.MegaCorp} and ${CompanyName.ECorp} have ` +
|
||||
"reportedly launched hundreds of new surveillance and espionage satellites. " +
|
||||
"Defense contractors such as " +
|
||||
"DeltaOne and AeroCorp have been working with the CIA and NSA to prepare " +
|
||||
`${CompanyName.DeltaOne} and ${CompanyName.AeroCorp} have been working with the CIA and NSA to prepare ` +
|
||||
"for conflict. Meanwhile, the rest of the world sits in earnest " +
|
||||
"hoping that it never reaches full-scale war. With today's technology " +
|
||||
"and firepower, a World War would assuredly mean the end of human civilization.",
|
||||
@ -375,6 +381,7 @@ export const Literatures: Record<LiteratureName, Literature> = {
|
||||
[LiteratureName.TheHiddenWorld]: new Literature({
|
||||
title: "The Hidden World",
|
||||
filename: LiteratureName.TheHiddenWorld,
|
||||
factionRumors: [FactionName.Illuminati],
|
||||
text:
|
||||
"WAKE UP SHEEPLE<br><br>" +
|
||||
"THE GOVERNMENT DOES NOT EXIST. CORPORATIONS DO NOT RUN SOCIETY<br><br>" +
|
||||
@ -394,6 +401,7 @@ export const Literatures: Record<LiteratureName, Literature> = {
|
||||
[LiteratureName.TheNewGod]: new Literature({
|
||||
title: "The New God",
|
||||
filename: LiteratureName.TheNewGod,
|
||||
factionRumors: [FactionName.ChurchOfTheMachineGod],
|
||||
text:
|
||||
"Everyone has a moment in their life when they wonder about the bigger questions.<br><br>" +
|
||||
"What's the point of all this? What is my purpose?<br><br>" +
|
||||
@ -408,6 +416,7 @@ export const Literatures: Record<LiteratureName, Literature> = {
|
||||
[LiteratureName.NewTriads]: new Literature({
|
||||
title: "The New Triads",
|
||||
filename: LiteratureName.NewTriads,
|
||||
factionRumors: [FactionName.Tetrads],
|
||||
text:
|
||||
"The Triads were an ancient transnational crime syndicate based in China, Hong Kong, and other Asian " +
|
||||
"territories. They were often considered one of the first and biggest criminal secret societies. " +
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { FilePath, asFilePath } from "../Paths/FilePath";
|
||||
import { MessageFilename } from "@enums";
|
||||
import { MessageFilename, FactionName } from "@enums";
|
||||
|
||||
export class Message {
|
||||
// Name of Message file
|
||||
@ -8,8 +8,12 @@ export class Message {
|
||||
// The text contains in the Message
|
||||
msg: string;
|
||||
|
||||
constructor(filename: MessageFilename, msg: string) {
|
||||
// Faction hinted at by the message
|
||||
factionRumors: FactionName[];
|
||||
|
||||
constructor(filename: MessageFilename, msg: string, factionRumor?: FactionName) {
|
||||
this.filename = asFilePath(filename);
|
||||
this.msg = msg;
|
||||
this.factionRumors = factionRumor ? [factionRumor] : [];
|
||||
}
|
||||
}
|
||||
|
@ -12,10 +12,14 @@ import { Server } from "../Server/Server";
|
||||
|
||||
//Sends message to player, including a pop up
|
||||
function sendMessage(name: MessageFilename, forced = false): void {
|
||||
const msg = Messages[name];
|
||||
if (forced || !Settings.SuppressMessages) {
|
||||
showMessage(name);
|
||||
}
|
||||
addMessageToServer(name);
|
||||
for (const factionName of msg.factionRumors) {
|
||||
Player.receiveRumor(factionName);
|
||||
}
|
||||
}
|
||||
|
||||
function showMessage(name: MessageFilename): void {
|
||||
@ -113,6 +117,7 @@ const Messages: Record<MessageFilename, Message> = {
|
||||
"exploit them for their Augmentations. But do not trust them. " +
|
||||
"They are not what they seem. No one is.\n\n" +
|
||||
"-jump3R",
|
||||
FactionName.CyberSec,
|
||||
),
|
||||
|
||||
[MessageFilename.Jumper2]: new Message(
|
||||
@ -121,6 +126,7 @@ const Messages: Record<MessageFilename, Message> = {
|
||||
"you want to find the truth, worry only about yourself. Ethics and " +
|
||||
`morals will get you killed. \n\nWatch out for a hacking group known as ${FactionName.NiteSec}.` +
|
||||
"\n\n-jump3R",
|
||||
FactionName.NiteSec,
|
||||
),
|
||||
|
||||
[MessageFilename.Jumper3]: new Message(
|
||||
@ -128,6 +134,7 @@ const Messages: Record<MessageFilename, Message> = {
|
||||
"You must learn to walk before you can run. And you must " +
|
||||
`run before you can fly. Look for ${FactionName.TheBlackHand}. \n\n` +
|
||||
"I.I.I.I \n\n-jump3R",
|
||||
FactionName.TheBlackHand,
|
||||
),
|
||||
|
||||
[MessageFilename.Jumper4]: new Message(
|
||||
@ -135,6 +142,7 @@ const Messages: Record<MessageFilename, Message> = {
|
||||
"To find what you are searching for, you must understand the bits. " +
|
||||
"The bits are all around us. The runners will help you.\n\n" +
|
||||
"-jump3R",
|
||||
FactionName.BitRunners,
|
||||
),
|
||||
|
||||
//Messages from hacking factions
|
||||
@ -145,6 +153,7 @@ const Messages: Record<MessageFilename, Message> = {
|
||||
"the world for the better. If you join us, we can unlock your full potential. \n\n" +
|
||||
"But first, you must pass our test. Find and install the backdoor on our server. \n\n" +
|
||||
`-${FactionName.CyberSec}`,
|
||||
FactionName.CyberSec,
|
||||
),
|
||||
|
||||
[MessageFilename.NiteSecTest]: new Message(
|
||||
@ -156,6 +165,7 @@ const Messages: Record<MessageFilename, Message> = {
|
||||
"Join us, and people will fear you, too. \n\n" +
|
||||
"Find and install the backdoor on our server, avmnite-02h. Then, we will contact you again." +
|
||||
`\n\n-${FactionName.NiteSec}`,
|
||||
FactionName.NiteSec,
|
||||
),
|
||||
|
||||
[MessageFilename.BitRunnersTest]: new Message(
|
||||
@ -164,6 +174,7 @@ const Messages: Record<MessageFilename, Message> = {
|
||||
"what you are looking for. \n\n " +
|
||||
"We can help you find the answers.\n\n" +
|
||||
"run4theh111z",
|
||||
FactionName.BitRunners,
|
||||
),
|
||||
|
||||
//Messages to guide players to the daemon
|
||||
@ -174,6 +185,7 @@ const Messages: Record<MessageFilename, Message> = {
|
||||
"%@*$^$()@&$)$*@__CAN__()(@^#)@&@)#__N0__(#@&#)@&@&(\n" +
|
||||
"*(__LON6ER__^#)@)(()*#@)@__ESCAP3__)#(@(#@*@()@(#*$\n" +
|
||||
"()@)#$*%)$#()$#__Y0UR__(*)$#()%(&(%)*!)($__GAZ3__#(",
|
||||
FactionName.Daedalus,
|
||||
),
|
||||
|
||||
[MessageFilename.RedPill]: new Message(
|
||||
@ -183,6 +195,7 @@ const Messages: Record<MessageFilename, Message> = {
|
||||
")@B(*#%)@)M#B*%V)____FIND___#$@)#%(B*)@#(*%B)\n" +
|
||||
"@_#(%_@#M(BDSPOMB__THE-CAVE_#)$(*@#$)@#BNBEGB\n" +
|
||||
"DFLSMFVMV)#@($*)@#*$MV)@#(*$V)M#(*$)M@(#*VM$)",
|
||||
FactionName.Daedalus,
|
||||
),
|
||||
};
|
||||
|
||||
|
@ -181,6 +181,7 @@ const singularity = {
|
||||
getCompanyRep: SF4Cost(RamCostConstants.SingularityFn2 / 3),
|
||||
getCompanyFavor: SF4Cost(RamCostConstants.SingularityFn2 / 3),
|
||||
getCompanyFavorGain: SF4Cost(RamCostConstants.SingularityFn2 / 4),
|
||||
getFactionInviteRequirements: SF4Cost(RamCostConstants.SingularityFn2),
|
||||
checkFactionInvitations: SF4Cost(RamCostConstants.SingularityFn2),
|
||||
joinFaction: SF4Cost(RamCostConstants.SingularityFn2),
|
||||
workForFaction: SF4Cost(RamCostConstants.SingularityFn2),
|
||||
|
@ -816,6 +816,12 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
|
||||
const companyName = getEnumHelper("CompanyName").nsGetMember(ctx, _companyName);
|
||||
return Companies[companyName].getFavorGain();
|
||||
},
|
||||
getFactionInviteRequirements: (ctx) => (_facName) => {
|
||||
helpers.checkSingularityAccess(ctx);
|
||||
const facName = getEnumHelper("FactionName").nsGetMember(ctx, _facName);
|
||||
const fac = Factions[facName];
|
||||
return fac.getInfo().inviteReqs.map((condition) => condition.toString());
|
||||
},
|
||||
checkFactionInvitations: (ctx) => () => {
|
||||
helpers.checkSingularityAccess(ctx);
|
||||
// Manually trigger a check for faction invites
|
||||
@ -835,13 +841,6 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
|
||||
const fac = Factions[facName];
|
||||
joinFaction(fac);
|
||||
|
||||
// Update Faction Invitation list to account for joined + banned factions
|
||||
for (let i = 0; i < Player.factionInvitations.length; ++i) {
|
||||
if (Player.factionInvitations[i] == facName || Factions[Player.factionInvitations[i]].isBanned) {
|
||||
Player.factionInvitations.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
Player.gainIntelligenceExp(CONSTANTS.IntelligenceSingFnBaseExpGain * 5);
|
||||
helpers.log(ctx, () => `Joined the '${facName}' faction.`);
|
||||
return true;
|
||||
|
@ -38,6 +38,7 @@ export class PlayerObject extends Person implements IPlayer {
|
||||
currentServer = "";
|
||||
factions: FactionName[] = [];
|
||||
factionInvitations: FactionName[] = [];
|
||||
factionRumors: FactionName[] = [];
|
||||
hacknetNodes: (HacknetNode | string)[] = []; // HacknetNode object or hostname of Hacknet Server
|
||||
has4SData = false;
|
||||
has4SDataTixApi = false;
|
||||
@ -131,6 +132,7 @@ export class PlayerObject extends Person implements IPlayer {
|
||||
createHacknetServer = serverMethods.createHacknetServer;
|
||||
queueAugmentation = generalMethods.queueAugmentation;
|
||||
receiveInvite = generalMethods.receiveInvite;
|
||||
receiveRumor = generalMethods.receiveRumor;
|
||||
gainCodingContractReward = generalMethods.gainCodingContractReward;
|
||||
stopFocusing = generalMethods.stopFocusing;
|
||||
prestigeAugmentation = generalMethods.prestigeAugmentation;
|
||||
|
@ -4,6 +4,7 @@ import {
|
||||
CompanyName,
|
||||
CompletedProgramName,
|
||||
FactionName,
|
||||
FactionDiscovery,
|
||||
JobName,
|
||||
LocationName,
|
||||
ToastVariant,
|
||||
@ -33,8 +34,7 @@ import { Locations } from "../../Locations/Locations";
|
||||
import { Sleeve } from "../Sleeve/Sleeve";
|
||||
import { isSleeveCompanyWork } from "../Sleeve/Work/SleeveCompanyWork";
|
||||
import { calculateSkillProgress as calculateSkillProgressF, ISkillProgress } from "../formulas/skill";
|
||||
import { GetServer, AddToAllServers, createUniqueRandomIp } from "../../Server/AllServers";
|
||||
import { Server } from "../../Server/Server";
|
||||
import { AddToAllServers, createUniqueRandomIp } from "../../Server/AllServers";
|
||||
import { safelyCreateUniqueServer } from "../../Server/ServerHelpers";
|
||||
|
||||
import { SpecialServers } from "../../Server/data/SpecialServers";
|
||||
@ -42,7 +42,6 @@ import { applySourceFile } from "../../SourceFile/applySourceFile";
|
||||
import { applyExploit } from "../../Exploits/applyExploits";
|
||||
import { SourceFiles } from "../../SourceFile/SourceFiles";
|
||||
import { getHospitalizationCost } from "../../Hospital/Hospital";
|
||||
import { HacknetServer } from "../../Hacknet/HacknetServer";
|
||||
|
||||
import { formatMoney } from "../../ui/formatNumber";
|
||||
import { MoneySource, MoneySourceTracker } from "../../utils/MoneySourceTracker";
|
||||
@ -52,7 +51,6 @@ import { SnackbarEvents } from "../../ui/React/Snackbar";
|
||||
import { achievements } from "../../Achievements/Achievements";
|
||||
|
||||
import { isCompanyWork } from "../../Work/CompanyWork";
|
||||
import { serverMetadata } from "../../Server/data/servers";
|
||||
import { getEnumHelper, isMember } from "../../utils/EnumHelper";
|
||||
|
||||
export function init(this: PlayerObject): void {
|
||||
@ -105,6 +103,7 @@ export function prestigeAugmentation(this: PlayerObject): void {
|
||||
|
||||
this.factions = [];
|
||||
this.factionInvitations = [];
|
||||
this.factionRumors = [];
|
||||
// Clear any pending invitation modals
|
||||
InvitationEvent.emit(null);
|
||||
|
||||
@ -171,10 +170,37 @@ export function prestigeSourceFile(this: PlayerObject): void {
|
||||
}
|
||||
|
||||
export function receiveInvite(this: PlayerObject, factionName: FactionName): void {
|
||||
if (this.factionInvitations.includes(factionName) || this.factions.includes(factionName)) {
|
||||
if (
|
||||
this.factionInvitations.includes(factionName) ||
|
||||
Factions[factionName].isMember ||
|
||||
Factions[factionName].isBanned
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.factionInvitations.push(factionName);
|
||||
if (this.factionRumors.includes(factionName)) {
|
||||
this.factionRumors.splice(this.factionRumors.indexOf(factionName), 1);
|
||||
}
|
||||
Factions[factionName].discovery = FactionDiscovery.known;
|
||||
}
|
||||
|
||||
export function receiveRumor(
|
||||
this: PlayerObject,
|
||||
factionName: FactionName,
|
||||
discovery?: FactionDiscovery | undefined,
|
||||
): void {
|
||||
if (Factions[factionName].discovery == FactionDiscovery.unknown) {
|
||||
Factions[factionName].discovery = discovery || FactionDiscovery.rumored;
|
||||
}
|
||||
if (
|
||||
this.factionRumors.includes(factionName) ||
|
||||
this.factionInvitations.includes(factionName) ||
|
||||
Factions[factionName].isMember ||
|
||||
Factions[factionName].isBanned
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.factionRumors.push(factionName);
|
||||
}
|
||||
|
||||
//Calculates skill level progress based on experience. The same formula will be used for every skill
|
||||
@ -609,478 +635,11 @@ export function reapplyAllSourceFiles(this: PlayerObject): void {
|
||||
//those requirements and will return an array of all factions that the Player should
|
||||
//receive an invitation to
|
||||
export function checkForFactionInvitations(this: PlayerObject): Faction[] {
|
||||
const invitedFactions: Faction[] = []; //Array which will hold all Factions the player should be invited to
|
||||
|
||||
const numAugmentations = this.augmentations.length;
|
||||
|
||||
const allCompanies = Object.keys(this.jobs);
|
||||
const allPositions = Object.values(this.jobs);
|
||||
|
||||
// Given a company name, safely returns the reputation (returns 0 if invalid company is specified)
|
||||
function getCompanyRep(companyName: CompanyName): number {
|
||||
const company = Companies[companyName];
|
||||
return company.playerReputation;
|
||||
const invitedFactions = [];
|
||||
for (const faction of Object.values(Factions)) {
|
||||
if (faction.checkForInvite(this)) invitedFactions.push(faction);
|
||||
if (faction.checkForRumor(this)) this.receiveRumor(faction.name);
|
||||
}
|
||||
|
||||
// Helper function that returns a boolean indicating whether the Player meets
|
||||
// the requirements for the specified company. There are two requirements:
|
||||
// 1. High enough reputation
|
||||
// 2. Player is employed at the company
|
||||
function checkMegacorpRequirements(companyName: CompanyName): boolean {
|
||||
const serverMeta = serverMetadata.find((s) => s.specialName === companyName);
|
||||
const server = GetServer(serverMeta ? serverMeta.hostname : "");
|
||||
const bonus = (server as Server).backdoorInstalled ? -100e3 : 0;
|
||||
return (
|
||||
allCompanies.includes(companyName) && getCompanyRep(companyName) > CONSTANTS.CorpFactionRepRequirement + bonus
|
||||
);
|
||||
}
|
||||
|
||||
//Illuminati
|
||||
const illuminatiFac = Factions[FactionName.Illuminati];
|
||||
if (
|
||||
!illuminatiFac.isBanned &&
|
||||
!illuminatiFac.isMember &&
|
||||
!illuminatiFac.alreadyInvited &&
|
||||
numAugmentations >= 30 &&
|
||||
this.money >= 150000000000 &&
|
||||
this.skills.hacking >= 1500 &&
|
||||
this.skills.strength >= 1200 &&
|
||||
this.skills.defense >= 1200 &&
|
||||
this.skills.dexterity >= 1200 &&
|
||||
this.skills.agility >= 1200
|
||||
) {
|
||||
invitedFactions.push(illuminatiFac);
|
||||
}
|
||||
|
||||
//Daedalus
|
||||
const daedalusFac = Factions[FactionName.Daedalus];
|
||||
if (
|
||||
!daedalusFac.isBanned &&
|
||||
!daedalusFac.isMember &&
|
||||
!daedalusFac.alreadyInvited &&
|
||||
numAugmentations >= currentNodeMults.DaedalusAugsRequirement &&
|
||||
this.money >= 100000000000 &&
|
||||
(this.skills.hacking >= 2500 ||
|
||||
(this.skills.strength >= 1500 &&
|
||||
this.skills.defense >= 1500 &&
|
||||
this.skills.dexterity >= 1500 &&
|
||||
this.skills.agility >= 1500))
|
||||
) {
|
||||
invitedFactions.push(daedalusFac);
|
||||
}
|
||||
|
||||
//The Covenant
|
||||
const covenantFac = Factions[FactionName.TheCovenant];
|
||||
if (
|
||||
!covenantFac.isBanned &&
|
||||
!covenantFac.isMember &&
|
||||
!covenantFac.alreadyInvited &&
|
||||
numAugmentations >= 20 &&
|
||||
this.money >= 75000000000 &&
|
||||
this.skills.hacking >= 850 &&
|
||||
this.skills.strength >= 850 &&
|
||||
this.skills.defense >= 850 &&
|
||||
this.skills.dexterity >= 850 &&
|
||||
this.skills.agility >= 850
|
||||
) {
|
||||
invitedFactions.push(covenantFac);
|
||||
}
|
||||
|
||||
//ECorp
|
||||
const ecorpFac = Factions[FactionName.ECorp];
|
||||
if (
|
||||
!ecorpFac.isBanned &&
|
||||
!ecorpFac.isMember &&
|
||||
!ecorpFac.alreadyInvited &&
|
||||
checkMegacorpRequirements(CompanyName.ECorp)
|
||||
) {
|
||||
invitedFactions.push(ecorpFac);
|
||||
}
|
||||
|
||||
//MegaCorp
|
||||
const megacorpFac = Factions[FactionName.MegaCorp];
|
||||
if (
|
||||
!megacorpFac.isBanned &&
|
||||
!megacorpFac.isMember &&
|
||||
!megacorpFac.alreadyInvited &&
|
||||
checkMegacorpRequirements(CompanyName.MegaCorp)
|
||||
) {
|
||||
invitedFactions.push(megacorpFac);
|
||||
}
|
||||
|
||||
//Bachman & Associates
|
||||
const bachmanandassociatesFac = Factions[FactionName.BachmanAssociates];
|
||||
if (
|
||||
!bachmanandassociatesFac.isBanned &&
|
||||
!bachmanandassociatesFac.isMember &&
|
||||
!bachmanandassociatesFac.alreadyInvited &&
|
||||
checkMegacorpRequirements(CompanyName.BachmanAndAssociates)
|
||||
) {
|
||||
invitedFactions.push(bachmanandassociatesFac);
|
||||
}
|
||||
|
||||
//Blade Industries
|
||||
const bladeindustriesFac = Factions[FactionName.BladeIndustries];
|
||||
if (
|
||||
!bladeindustriesFac.isBanned &&
|
||||
!bladeindustriesFac.isMember &&
|
||||
!bladeindustriesFac.alreadyInvited &&
|
||||
checkMegacorpRequirements(CompanyName.BladeIndustries)
|
||||
) {
|
||||
invitedFactions.push(bladeindustriesFac);
|
||||
}
|
||||
|
||||
//NWO
|
||||
const nwoFac = Factions[FactionName.NWO];
|
||||
if (!nwoFac.isBanned && !nwoFac.isMember && !nwoFac.alreadyInvited && checkMegacorpRequirements(CompanyName.NWO)) {
|
||||
invitedFactions.push(nwoFac);
|
||||
}
|
||||
|
||||
//Clarke Incorporated
|
||||
const clarkeincorporatedFac = Factions[FactionName.ClarkeIncorporated];
|
||||
if (
|
||||
!clarkeincorporatedFac.isBanned &&
|
||||
!clarkeincorporatedFac.isMember &&
|
||||
!clarkeincorporatedFac.alreadyInvited &&
|
||||
checkMegacorpRequirements(CompanyName.ClarkeIncorporated)
|
||||
) {
|
||||
invitedFactions.push(clarkeincorporatedFac);
|
||||
}
|
||||
|
||||
//OmniTek Incorporated
|
||||
const omnitekincorporatedFac = Factions[FactionName.OmniTekIncorporated];
|
||||
if (
|
||||
!omnitekincorporatedFac.isBanned &&
|
||||
!omnitekincorporatedFac.isMember &&
|
||||
!omnitekincorporatedFac.alreadyInvited &&
|
||||
checkMegacorpRequirements(CompanyName.OmniTekIncorporated)
|
||||
) {
|
||||
invitedFactions.push(omnitekincorporatedFac);
|
||||
}
|
||||
|
||||
//Four Sigma
|
||||
const foursigmaFac = Factions[FactionName.FourSigma];
|
||||
if (
|
||||
!foursigmaFac.isBanned &&
|
||||
!foursigmaFac.isMember &&
|
||||
!foursigmaFac.alreadyInvited &&
|
||||
checkMegacorpRequirements(CompanyName.FourSigma)
|
||||
) {
|
||||
invitedFactions.push(foursigmaFac);
|
||||
}
|
||||
|
||||
//KuaiGong International
|
||||
const kuaigonginternationalFac = Factions[FactionName.KuaiGongInternational];
|
||||
if (
|
||||
!kuaigonginternationalFac.isBanned &&
|
||||
!kuaigonginternationalFac.isMember &&
|
||||
!kuaigonginternationalFac.alreadyInvited &&
|
||||
checkMegacorpRequirements(CompanyName.KuaiGongInternational)
|
||||
) {
|
||||
invitedFactions.push(kuaigonginternationalFac);
|
||||
}
|
||||
|
||||
//Fulcrum Secret Technologies - If you've unlocked fulcrum secret technologies server and have a high rep with the company
|
||||
const fulcrumsecrettechonologiesFac = Factions[FactionName.FulcrumSecretTechnologies];
|
||||
const fulcrumSecretServer = GetServer(SpecialServers.FulcrumSecretTechnologies);
|
||||
if (!(fulcrumSecretServer instanceof Server))
|
||||
throw new Error(`${FactionName.FulcrumSecretTechnologies} should be normal server`);
|
||||
if (fulcrumSecretServer == null) {
|
||||
console.error(`Could not find ${FactionName.FulcrumSecretTechnologies} Server`);
|
||||
} else if (
|
||||
!fulcrumsecrettechonologiesFac.isBanned &&
|
||||
!fulcrumsecrettechonologiesFac.isMember &&
|
||||
!fulcrumsecrettechonologiesFac.alreadyInvited &&
|
||||
fulcrumSecretServer.backdoorInstalled &&
|
||||
checkMegacorpRequirements(CompanyName.FulcrumTechnologies)
|
||||
) {
|
||||
invitedFactions.push(fulcrumsecrettechonologiesFac);
|
||||
}
|
||||
|
||||
//BitRunners
|
||||
const bitrunnersFac = Factions[FactionName.BitRunners];
|
||||
const bitrunnersServer = GetServer(SpecialServers.BitRunnersServer);
|
||||
if (!(bitrunnersServer instanceof Server)) throw new Error(`${FactionName.BitRunners} should be normal server`);
|
||||
if (bitrunnersServer == null) {
|
||||
console.error(`Could not find ${FactionName.BitRunners} Server`);
|
||||
} else if (
|
||||
!bitrunnersFac.isBanned &&
|
||||
!bitrunnersFac.isMember &&
|
||||
bitrunnersServer.backdoorInstalled &&
|
||||
!bitrunnersFac.alreadyInvited
|
||||
) {
|
||||
invitedFactions.push(bitrunnersFac);
|
||||
}
|
||||
|
||||
//The Black Hand
|
||||
|
||||
const theblackhandFac = Factions[FactionName.TheBlackHand];
|
||||
const blackhandServer = GetServer(SpecialServers.TheBlackHandServer);
|
||||
if (!(blackhandServer instanceof Server)) throw new Error(`${FactionName.TheBlackHand} should be normal server`);
|
||||
if (blackhandServer == null) {
|
||||
console.error(`Could not find ${FactionName.TheBlackHand} Server`);
|
||||
} else if (
|
||||
!theblackhandFac.isBanned &&
|
||||
!theblackhandFac.isMember &&
|
||||
blackhandServer.backdoorInstalled &&
|
||||
!theblackhandFac.alreadyInvited
|
||||
) {
|
||||
invitedFactions.push(theblackhandFac);
|
||||
}
|
||||
|
||||
//NiteSec
|
||||
const nitesecFac = Factions[FactionName.NiteSec];
|
||||
const nitesecServer = GetServer(SpecialServers.NiteSecServer);
|
||||
if (!(nitesecServer instanceof Server)) throw new Error(`${FactionName.NiteSec} should be normal server`);
|
||||
if (nitesecServer == null) {
|
||||
console.error(`Could not find ${FactionName.NiteSec} Server`);
|
||||
} else if (
|
||||
!nitesecFac.isBanned &&
|
||||
!nitesecFac.isMember &&
|
||||
nitesecServer.backdoorInstalled &&
|
||||
!nitesecFac.alreadyInvited
|
||||
) {
|
||||
invitedFactions.push(nitesecFac);
|
||||
}
|
||||
|
||||
//Chongqing
|
||||
const chongqingFac = Factions[FactionName.Chongqing];
|
||||
if (
|
||||
!chongqingFac.isBanned &&
|
||||
!chongqingFac.isMember &&
|
||||
!chongqingFac.alreadyInvited &&
|
||||
this.money >= 20000000 &&
|
||||
this.city == CityName.Chongqing
|
||||
) {
|
||||
invitedFactions.push(chongqingFac);
|
||||
}
|
||||
|
||||
//Sector-12
|
||||
const sector12Fac = Factions[FactionName.Sector12];
|
||||
if (
|
||||
!sector12Fac.isBanned &&
|
||||
!sector12Fac.isMember &&
|
||||
!sector12Fac.alreadyInvited &&
|
||||
this.money >= 15000000 &&
|
||||
this.city == CityName.Sector12
|
||||
) {
|
||||
invitedFactions.push(sector12Fac);
|
||||
}
|
||||
|
||||
//New Tokyo
|
||||
const newtokyoFac = Factions[FactionName.NewTokyo];
|
||||
if (
|
||||
!newtokyoFac.isBanned &&
|
||||
!newtokyoFac.isMember &&
|
||||
!newtokyoFac.alreadyInvited &&
|
||||
this.money >= 20000000 &&
|
||||
this.city == CityName.NewTokyo
|
||||
) {
|
||||
invitedFactions.push(newtokyoFac);
|
||||
}
|
||||
|
||||
//Aevum
|
||||
const aevumFac = Factions[FactionName.Aevum];
|
||||
if (
|
||||
!aevumFac.isBanned &&
|
||||
!aevumFac.isMember &&
|
||||
!aevumFac.alreadyInvited &&
|
||||
this.money >= 40000000 &&
|
||||
this.city == CityName.Aevum
|
||||
) {
|
||||
invitedFactions.push(aevumFac);
|
||||
}
|
||||
|
||||
//Ishima
|
||||
const ishimaFac = Factions[FactionName.Ishima];
|
||||
if (
|
||||
!ishimaFac.isBanned &&
|
||||
!ishimaFac.isMember &&
|
||||
!ishimaFac.alreadyInvited &&
|
||||
this.money >= 30000000 &&
|
||||
this.city == CityName.Ishima
|
||||
) {
|
||||
invitedFactions.push(ishimaFac);
|
||||
}
|
||||
|
||||
//Volhaven
|
||||
const volhavenFac = Factions[FactionName.Volhaven];
|
||||
if (
|
||||
!volhavenFac.isBanned &&
|
||||
!volhavenFac.isMember &&
|
||||
!volhavenFac.alreadyInvited &&
|
||||
this.money >= 50000000 &&
|
||||
this.city == CityName.Volhaven
|
||||
) {
|
||||
invitedFactions.push(volhavenFac);
|
||||
}
|
||||
|
||||
//Speakers for the Dead
|
||||
const speakersforthedeadFac = Factions[FactionName.SpeakersForTheDead];
|
||||
if (
|
||||
!speakersforthedeadFac.isBanned &&
|
||||
!speakersforthedeadFac.isMember &&
|
||||
!speakersforthedeadFac.alreadyInvited &&
|
||||
this.skills.hacking >= 100 &&
|
||||
this.skills.strength >= 300 &&
|
||||
this.skills.defense >= 300 &&
|
||||
this.skills.dexterity >= 300 &&
|
||||
this.skills.agility >= 300 &&
|
||||
this.numPeopleKilled >= 30 &&
|
||||
this.karma <= -45 &&
|
||||
!allCompanies.includes(LocationName.Sector12CIA) &&
|
||||
!allCompanies.includes(LocationName.Sector12NSA)
|
||||
) {
|
||||
invitedFactions.push(speakersforthedeadFac);
|
||||
}
|
||||
|
||||
//The Dark Army
|
||||
const thedarkarmyFac = Factions[FactionName.TheDarkArmy];
|
||||
if (
|
||||
!thedarkarmyFac.isBanned &&
|
||||
!thedarkarmyFac.isMember &&
|
||||
!thedarkarmyFac.alreadyInvited &&
|
||||
this.skills.hacking >= 300 &&
|
||||
this.skills.strength >= 300 &&
|
||||
this.skills.defense >= 300 &&
|
||||
this.skills.dexterity >= 300 &&
|
||||
this.skills.agility >= 300 &&
|
||||
this.city == CityName.Chongqing &&
|
||||
this.numPeopleKilled >= 5 &&
|
||||
this.karma <= -45 &&
|
||||
!allCompanies.includes(LocationName.Sector12CIA) &&
|
||||
!allCompanies.includes(LocationName.Sector12NSA)
|
||||
) {
|
||||
invitedFactions.push(thedarkarmyFac);
|
||||
}
|
||||
|
||||
//The Syndicate
|
||||
const thesyndicateFac = Factions[FactionName.TheSyndicate];
|
||||
if (
|
||||
!thesyndicateFac.isBanned &&
|
||||
!thesyndicateFac.isMember &&
|
||||
!thesyndicateFac.alreadyInvited &&
|
||||
this.skills.hacking >= 200 &&
|
||||
this.skills.strength >= 200 &&
|
||||
this.skills.defense >= 200 &&
|
||||
this.skills.dexterity >= 200 &&
|
||||
this.skills.agility >= 200 &&
|
||||
(this.city == CityName.Aevum || this.city == CityName.Sector12) &&
|
||||
this.money >= 10000000 &&
|
||||
this.karma <= -90 &&
|
||||
!allCompanies.includes(LocationName.Sector12CIA) &&
|
||||
!allCompanies.includes(LocationName.Sector12NSA)
|
||||
) {
|
||||
invitedFactions.push(thesyndicateFac);
|
||||
}
|
||||
|
||||
//Silhouette
|
||||
const silhouetteFac = Factions[FactionName.Silhouette];
|
||||
if (
|
||||
!silhouetteFac.isBanned &&
|
||||
!silhouetteFac.isMember &&
|
||||
!silhouetteFac.alreadyInvited &&
|
||||
(allPositions.includes(JobName.software7) || // CTO
|
||||
allPositions.includes(JobName.business4) || // CFO
|
||||
allPositions.includes(JobName.business5)) && // CEO
|
||||
this.money >= 15000000 &&
|
||||
this.karma <= -22
|
||||
) {
|
||||
invitedFactions.push(silhouetteFac);
|
||||
}
|
||||
|
||||
//Tetrads
|
||||
const tetradsFac = Factions[FactionName.Tetrads];
|
||||
if (
|
||||
!tetradsFac.isBanned &&
|
||||
!tetradsFac.isMember &&
|
||||
!tetradsFac.alreadyInvited &&
|
||||
(this.city == CityName.Chongqing || this.city == CityName.NewTokyo || this.city == CityName.Ishima) &&
|
||||
this.skills.strength >= 75 &&
|
||||
this.skills.defense >= 75 &&
|
||||
this.skills.dexterity >= 75 &&
|
||||
this.skills.agility >= 75 &&
|
||||
this.karma <= -18
|
||||
) {
|
||||
invitedFactions.push(tetradsFac);
|
||||
}
|
||||
|
||||
//SlumSnakes
|
||||
const slumsnakesFac = Factions[FactionName.SlumSnakes];
|
||||
if (
|
||||
!slumsnakesFac.isBanned &&
|
||||
!slumsnakesFac.isMember &&
|
||||
!slumsnakesFac.alreadyInvited &&
|
||||
this.skills.strength >= 30 &&
|
||||
this.skills.defense >= 30 &&
|
||||
this.skills.dexterity >= 30 &&
|
||||
this.skills.agility >= 30 &&
|
||||
this.karma <= -9 &&
|
||||
this.money >= 1000000
|
||||
) {
|
||||
invitedFactions.push(slumsnakesFac);
|
||||
}
|
||||
|
||||
//Netburners
|
||||
const netburnersFac = Factions[FactionName.Netburners];
|
||||
let totalHacknetRam = 0;
|
||||
let totalHacknetCores = 0;
|
||||
let totalHacknetLevels = 0;
|
||||
for (let i = 0; i < this.hacknetNodes.length; ++i) {
|
||||
const v = this.hacknetNodes[i];
|
||||
if (typeof v === "string") {
|
||||
const hserver = GetServer(v);
|
||||
if (hserver === null || !(hserver instanceof HacknetServer))
|
||||
throw new Error("player hacknet server was not HacknetServer");
|
||||
totalHacknetLevels += hserver.level;
|
||||
totalHacknetRam += hserver.maxRam;
|
||||
totalHacknetCores += hserver.cores;
|
||||
} else {
|
||||
totalHacknetLevels += v.level;
|
||||
totalHacknetRam += v.ram;
|
||||
totalHacknetCores += v.cores;
|
||||
}
|
||||
}
|
||||
if (
|
||||
!netburnersFac.isBanned &&
|
||||
!netburnersFac.isMember &&
|
||||
!netburnersFac.alreadyInvited &&
|
||||
this.skills.hacking >= 80 &&
|
||||
totalHacknetRam >= 8 &&
|
||||
totalHacknetCores >= 4 &&
|
||||
totalHacknetLevels >= 100
|
||||
) {
|
||||
invitedFactions.push(netburnersFac);
|
||||
}
|
||||
|
||||
//Tian Di Hui
|
||||
const tiandihuiFac = Factions[FactionName.TianDiHui];
|
||||
if (
|
||||
!tiandihuiFac.isBanned &&
|
||||
!tiandihuiFac.isMember &&
|
||||
!tiandihuiFac.alreadyInvited &&
|
||||
this.money >= 1000000 &&
|
||||
this.skills.hacking >= 50 &&
|
||||
(this.city == CityName.Chongqing || this.city == CityName.NewTokyo || this.city == CityName.Ishima)
|
||||
) {
|
||||
invitedFactions.push(tiandihuiFac);
|
||||
}
|
||||
|
||||
//CyberSec
|
||||
const cybersecFac = Factions[FactionName.CyberSec];
|
||||
const cybersecServer = GetServer(SpecialServers.CyberSecServer);
|
||||
if (!(cybersecServer instanceof Server)) throw new Error(`${FactionName.CyberSec} should be normal server`);
|
||||
if (cybersecServer == null) {
|
||||
console.error(`Could not find ${FactionName.CyberSec} Server`);
|
||||
} else if (
|
||||
!cybersecFac.isBanned &&
|
||||
!cybersecFac.isMember &&
|
||||
cybersecServer.backdoorInstalled &&
|
||||
!cybersecFac.alreadyInvited
|
||||
) {
|
||||
invitedFactions.push(cybersecFac);
|
||||
}
|
||||
|
||||
return invitedFactions;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { AugmentationName, CityName, CompletedProgramName, FactionName, LiteratureName } from "@enums";
|
||||
import { AugmentationName, CityName, CompletedProgramName, FactionName, LiteratureName, CompanyName } from "@enums";
|
||||
import { initBitNodeMultipliers } from "./BitNode/BitNode";
|
||||
import { Companies } from "./Company/Companies";
|
||||
import { resetIndustryResearchTrees } from "./Corporation/data/IndustryData";
|
||||
@ -34,9 +34,17 @@ function delayedDialog(message: string) {
|
||||
export function prestigeAugmentation(): void {
|
||||
initBitNodeMultipliers();
|
||||
|
||||
const maintainMembership = Player.factions.concat(Player.factionInvitations).filter(function (faction) {
|
||||
return Factions[faction].getInfo().keep;
|
||||
});
|
||||
// Maintain invites to factions with the 'keepOnInstall' flag, and rumors about others
|
||||
const maintainInvites = [];
|
||||
const maintainRumors = [];
|
||||
for (const facName of [...Player.factions, ...Player.factionInvitations]) {
|
||||
if (Factions[facName].getInfo().keep) {
|
||||
maintainInvites.push(facName);
|
||||
} else {
|
||||
maintainRumors.push(facName);
|
||||
}
|
||||
}
|
||||
|
||||
Player.prestigeAugmentation();
|
||||
|
||||
// Delete all Worker Scripts objects
|
||||
@ -84,8 +92,8 @@ export function prestigeAugmentation(): void {
|
||||
// Recalculate the bonus for circadian modulator aug
|
||||
initCircadianModulator();
|
||||
|
||||
Player.factionInvitations = Player.factionInvitations.concat(maintainMembership);
|
||||
for (const factionName of maintainMembership) Factions[factionName].alreadyInvited = true;
|
||||
Player.factionInvitations = Player.factionInvitations.concat(maintainInvites);
|
||||
for (const factionName of maintainInvites) Factions[factionName].alreadyInvited = true;
|
||||
Player.reapplyAllAugmentations();
|
||||
Player.reapplyAllSourceFiles();
|
||||
Player.hp.current = Player.hp.max;
|
||||
@ -144,12 +152,19 @@ export function prestigeAugmentation(): void {
|
||||
}
|
||||
}
|
||||
|
||||
// Bitnode 13: Church of the Machine God
|
||||
if (Player.hasAugmentation(AugmentationName.StaneksGift1, true)) {
|
||||
joinFaction(Factions[FactionName.ChurchOfTheMachineGod]);
|
||||
} else if (Player.bitNodeN != 13) {
|
||||
if (Player.augmentations.some((a) => a.name !== AugmentationName.NeuroFluxGovernor)) {
|
||||
Factions[FactionName.ChurchOfTheMachineGod].isBanned = true;
|
||||
}
|
||||
}
|
||||
|
||||
staneksGift.prestigeAugmentation();
|
||||
|
||||
// Hear rumors after all invites/bans
|
||||
for (const factionName of maintainRumors) Player.receiveRumor(factionName);
|
||||
|
||||
resetPidCounter();
|
||||
ProgramsSeen.clear();
|
||||
InvitationsSeen.clear();
|
||||
@ -230,7 +245,7 @@ export function prestigeSourceFile(isFlume: boolean): void {
|
||||
|
||||
// BitNode 6: Bladeburners and BitNode 7: Bladeburners 2079
|
||||
if (Player.bitNodeN === 6 || Player.bitNodeN === 7) {
|
||||
delayedDialog("NSA would like to have a word with you once you're ready.");
|
||||
delayedDialog(`The ${CompanyName.NSA} would like to have a word with you once you're ready.`);
|
||||
}
|
||||
|
||||
// BitNode 8: Ghost of Wall Street
|
||||
@ -245,7 +260,7 @@ export function prestigeSourceFile(isFlume: boolean): void {
|
||||
// BitNode 10: Digital Carbon
|
||||
if (Player.bitNodeN === 10) {
|
||||
delayedDialog(
|
||||
"Seek out The Covenant if you'd like to purchase a new sleeve or two! And see what VitaLife in New Tokyo has to offer for you",
|
||||
`Seek out ${FactionName.TheCovenant} if you'd like to purchase a new sleeve or two! And see what ${CompanyName.VitaLife} in ${CityName.NewTokyo} has to offer for you`,
|
||||
);
|
||||
}
|
||||
|
||||
|
25
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
25
src/ScriptEditor/NetscriptDefinitions.d.ts
vendored
@ -1934,6 +1934,31 @@ export interface Singularity {
|
||||
*/
|
||||
getCompanyFavorGain(companyName: CompanyName | `${CompanyName}`): number;
|
||||
|
||||
/**
|
||||
* List conditions for being invited to a faction.
|
||||
* @remarks
|
||||
* RAM cost: 3 GB * 16/4/1
|
||||
*
|
||||
*
|
||||
* @param faction - Name of the faction.
|
||||
* @returns Array of strings describing conditions for receiving an invitation to the faction.
|
||||
*
|
||||
* @example
|
||||
* ```js
|
||||
* ns.singularity.getFactionInviteRequirements("The Syndicate")
|
||||
* [
|
||||
* "Located in Aevum or Sector-12",
|
||||
* "Not working for the Central Intelligence Agency",
|
||||
* "Not working for the National Security Agency",
|
||||
* "-90 karma",
|
||||
* "Have $10.000m",
|
||||
* "Hacking level 200",
|
||||
* "All combat skills level 200"
|
||||
* ]
|
||||
* ```
|
||||
*/
|
||||
getFactionInviteRequirements(faction: string): string[];
|
||||
|
||||
/**
|
||||
* List all current faction invitations.
|
||||
* @remarks
|
||||
|
27
src/ui/Components/Requirement.tsx
Normal file
27
src/ui/Components/Requirement.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import { CheckBox, CheckBoxOutlineBlank } from "@mui/icons-material";
|
||||
import { Typography } from "@mui/material";
|
||||
import React from "react";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
|
||||
Settings.theme.primary;
|
||||
|
||||
export interface IReqProps {
|
||||
value: string;
|
||||
color?: string;
|
||||
incompleteColor?: string;
|
||||
fulfilled: boolean;
|
||||
}
|
||||
|
||||
export const Requirement = (props: IReqProps): React.ReactElement => {
|
||||
const completeColor = props.color || Settings.theme.primary;
|
||||
const incompleteColor = props.incompleteColor || Settings.theme.primarydark;
|
||||
|
||||
return (
|
||||
<Typography
|
||||
sx={{ display: "flex", alignItems: "center", color: props.fulfilled ? completeColor : incompleteColor }}
|
||||
>
|
||||
{props.fulfilled ? <CheckBox sx={{ mr: 1 }} /> : <CheckBoxOutlineBlank sx={{ mr: 1 }} />}
|
||||
{props.value}
|
||||
</Typography>
|
||||
);
|
||||
};
|
@ -277,6 +277,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -287,6 +288,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -297,6 +299,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -307,6 +310,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -317,6 +321,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": true,
|
||||
@ -327,6 +332,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -337,6 +343,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -347,6 +354,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -357,6 +365,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 20,
|
||||
"isBanned": false,
|
||||
"isMember": true,
|
||||
@ -367,6 +376,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -377,6 +387,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -387,6 +398,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -397,6 +409,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -407,6 +420,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -417,6 +431,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -427,6 +442,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -437,6 +453,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -447,6 +464,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -457,6 +475,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -467,6 +486,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -477,6 +497,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -487,6 +508,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -497,6 +519,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -507,6 +530,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -517,6 +541,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -527,6 +552,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": true,
|
||||
@ -537,6 +563,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -547,6 +574,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -557,6 +585,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -567,6 +596,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -577,6 +607,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -587,6 +618,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -597,6 +629,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -607,6 +640,7 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
|
||||
"ctor": "Faction",
|
||||
"data": {
|
||||
"alreadyInvited": false,
|
||||
"discovery": "unknown",
|
||||
"favor": 0,
|
||||
"isBanned": false,
|
||||
"isMember": false,
|
||||
@ -1238,6 +1272,7 @@ exports[`Check Save File Continuity PlayerSave continuity 1`] = `
|
||||
},
|
||||
"exploits": [],
|
||||
"factionInvitations": [],
|
||||
"factionRumors": [],
|
||||
"factions": [
|
||||
"Slum Snakes",
|
||||
"CyberSec",
|
||||
|
Reference in New Issue
Block a user