TYPESAFETY: FactionName (#644)

This commit is contained in:
Snarling
2023-06-25 22:53:35 -04:00
committed by GitHub
parent 1de676972f
commit 9a0a843ffc
31 changed files with 295 additions and 751 deletions

View File

@ -23,7 +23,7 @@ import { BladeburnerConstants } from "./data/Constants";
import { formatExp, formatMoney, formatPercent, formatBigNumber, formatStamina } from "../ui/formatNumber";
import { currentNodeMults } from "../BitNode/BitNodeMultipliers";
import { addOffset } from "../utils/helpers/addOffset";
import { Factions, factionExists } from "../Faction/Factions";
import { Factions } from "../Faction/Factions";
import { calculateHospitalizationCost } from "../Hospital/Hospital";
import { dialogBoxCreate } from "../ui/React/DialogBox";
import { Settings } from "../Settings/Settings";
@ -1608,18 +1608,11 @@ export class Bladeburner {
this.maxRank = Math.max(this.rank, this.maxRank);
const bladeburnersFactionName = FactionName.Bladeburners;
if (factionExists(bladeburnersFactionName)) {
const bladeburnerFac = Factions[bladeburnersFactionName];
if (!bladeburnerFac) {
throw new Error(
`Could not properly get ${FactionName.Bladeburners} Faction object in ${FactionName.Bladeburners} UI Overview Faction button`,
);
}
if (bladeburnerFac.isMember) {
const favorBonus = 1 + bladeburnerFac.favor / 100;
bladeburnerFac.playerReputation +=
BladeburnerConstants.RankToFactionRepFactor * change * person.mults.faction_rep * favorBonus;
}
const bladeburnerFac = Factions[bladeburnersFactionName];
if (bladeburnerFac.isMember) {
const favorBonus = 1 + bladeburnerFac.favor / 100;
bladeburnerFac.playerReputation +=
BladeburnerConstants.RankToFactionRepFactor * change * person.mults.faction_rep * favorBonus;
}
// Gain skill points

View File

@ -124,38 +124,29 @@ function getRandomProblemType(): string {
}
function getRandomReward(): ICodingContractReward {
const reward: ICodingContractReward = {
name: "",
type: getRandomInt(0, CodingContractRewardType.Money),
};
reward.type = sanitizeRewardType(reward.type);
const rewardType = sanitizeRewardType(getRandomInt(0, CodingContractRewardType.Money));
// Add additional information based on the reward type
const factionsThatAllowHacking = Player.factions.filter((fac) => Factions[fac].getInfo().offerHackingWork);
switch (reward.type) {
switch (rewardType) {
case CodingContractRewardType.FactionReputation: {
// Get a random faction that player is a part of. That
// faction must allow hacking contracts
const numFactions = factionsThatAllowHacking.length;
const randFaction = factionsThatAllowHacking[getRandomInt(0, numFactions - 1)];
reward.name = randFaction;
break;
return { type: rewardType, name: randFaction };
}
case CodingContractRewardType.CompanyReputation: {
const allJobs = Object.keys(Player.jobs);
if (allJobs.length > 0) {
reward.name = allJobs[getRandomInt(0, allJobs.length - 1)];
} else {
reward.type = CodingContractRewardType.Money;
return { type: CodingContractRewardType.CompanyReputation, name: allJobs[getRandomInt(0, allJobs.length - 1)] };
}
break;
return { type: CodingContractRewardType.Money };
}
default:
break;
return { type: rewardType };
}
return reward;
}
function getRandomServer(): BaseServer {
@ -182,7 +173,7 @@ function getRandomServer(): BaseServer {
function getRandomFilename(
server: BaseServer,
reward: ICodingContractReward = { name: "", type: 0 },
reward: ICodingContractReward = { type: CodingContractRewardType.Money },
): ContractFilePath {
let contractFn = `contract-${getRandomInt(0, 1e6)}`;
@ -197,7 +188,7 @@ function getRandomFilename(
contractFn = `contract-${getRandomInt(0, 1e6)}`;
}
if (reward.name) {
if ("name" in reward) {
// Only alphanumeric characters in the reward name.
contractFn += `-${reward.name.replace(/[^a-zA-Z0-9]/g, "")}`;
}

View File

@ -1,3 +1,4 @@
import type { FactionName } from "@enums";
import { codingContractTypesMetadata, DescriptionFunc, GeneratorFunc, SolverFunc } from "./data/codingcontracttypes";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "./utils/JSONReviver";
@ -73,11 +74,21 @@ export enum CodingContractResult {
}
/** A class that represents the type of reward a contract gives */
export interface ICodingContractReward {
/* Name of Company/Faction name for reward, if applicable */
name?: string;
type: CodingContractRewardType;
}
export type ICodingContractReward =
| {
type: CodingContractRewardType.Money;
}
| {
type: CodingContractRewardType.FactionReputationAll;
}
| {
type: CodingContractRewardType.CompanyReputation;
name: string;
}
| {
type: CodingContractRewardType.FactionReputation;
name: FactionName;
};
/**
* A Coding Contract is a file that poses a programming-related problem to the Player.

View File

@ -1,17 +1,17 @@
import type { FactionName } from "@enums";
import React, { useState } from "react";
import { Box, Button, MenuItem, Select, SelectChangeEvent, Typography } from "@mui/material";
import { Player } from "@player";
import { Factions } from "../../../Faction/Factions";
import * as corpConstants from "../../data/Constants";
import { formatReputation } from "../../../ui/formatNumber";
import { dialogBoxCreate } from "../../../ui/React/DialogBox";
import { Modal } from "../../../ui/React/Modal";
import { Player } from "@player";
import { useCorporation } from "../Context";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import MenuItem from "@mui/material/MenuItem";
import { NumberInput } from "../../../ui/React/NumberInput";
import Box from "@mui/material/Box";
import Select, { SelectChangeEvent } from "@mui/material/Select";
import { getEnumHelper } from "../../../utils/EnumHelper";
interface IProps {
open: boolean;
@ -19,7 +19,7 @@ interface IProps {
}
export function BribeFactionModal(props: IProps): React.ReactElement {
const factions = Player.factions.filter((name: string) => {
const factions = Player.factions.filter((name) => {
const info = Factions[name].getInfo();
if (!info.offersWork()) return false;
if (Player.hasGangWith(name)) return false;
@ -27,10 +27,11 @@ export function BribeFactionModal(props: IProps): React.ReactElement {
});
const corp = useCorporation();
const [money, setMoney] = useState<number>(NaN);
const [selectedFaction, setSelectedFaction] = useState(factions.length > 0 ? factions[0] : "");
const [selectedFaction, setSelectedFaction] = useState<FactionName | "">(factions.length > 0 ? factions[0] : "");
const disabled = money === 0 || isNaN(money) || money < 0 || corp.funds < money;
function changeFaction(event: SelectChangeEvent): void {
if (!getEnumHelper("FactionName").isMember(event.target.value)) return;
setSelectedFaction(event.target.value);
}
@ -52,6 +53,7 @@ export function BribeFactionModal(props: IProps): React.ReactElement {
}
function bribe(money: number): void {
if (!selectedFaction) return;
const fac = Factions[selectedFaction];
if (disabled) return;
const rep = repGain(money);
@ -69,7 +71,7 @@ export function BribeFactionModal(props: IProps): React.ReactElement {
<Box display="flex" alignItems="center">
<Typography>Faction:</Typography>
<Select value={selectedFaction} onChange={changeFaction}>
{factions.map((name: string) => {
{factions.map((name) => {
const info = Factions[name].getInfo();
if (!info.offersWork()) return;
if (Player.hasGangWith(name)) return;

View File

@ -5,7 +5,7 @@ import React, { useEffect } from "react";
import { General } from "./DevMenu/ui/General";
import { Stats } from "./DevMenu/ui/Stats";
import { Factions } from "./DevMenu/ui/Factions";
import { FactionsDev } from "./DevMenu/ui/FactionsDev";
import { Augmentations } from "./DevMenu/ui/Augmentations";
import { SourceFiles } from "./DevMenu/ui/SourceFiles";
import { Programs } from "./DevMenu/ui/Programs";
@ -34,7 +34,7 @@ export function DevMenuRoot(): React.ReactElement {
<Typography>Development Menu - Only meant to be used for testing/debugging</Typography>
<General />
<Stats />
<Factions />
<FactionsDev />
<Augmentations />
<SourceFiles />
<Programs />

View File

@ -1,7 +1,4 @@
import React, { useState } from "react";
import { Player } from "@player";
import { FactionName } from "@enums";
import {
Accordion,
AccordionSummary,
@ -11,27 +8,33 @@ import {
IconButton,
InputLabel,
MenuItem,
Select,
SelectChangeEvent,
Typography,
} from "@mui/material";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import Select, { SelectChangeEvent } from "@mui/material/Select";
import { Adjuster } from "./Adjuster";
import { Factions as AllFaction } from "../../Faction/Factions";
import ReplyAllIcon from "@mui/icons-material/ReplyAll";
import ReplyIcon from "@mui/icons-material/Reply";
import { Player } from "@player";
import { FactionName } from "@enums";
import { Adjuster } from "./Adjuster";
import { Factions } from "../../Faction/Factions";
import { getRecordValues } from "../../Types/Record";
import { getEnumHelper } from "../../utils/EnumHelper";
const bigNumber = 1e12;
export function Factions(): React.ReactElement {
const [faction, setFaction] = useState(FactionName.Illuminati as string);
export function FactionsDev(): React.ReactElement {
const [factionName, setFactionName] = useState(FactionName.Illuminati);
function setFactionDropdown(event: SelectChangeEvent): void {
setFaction(event.target.value);
if (!getEnumHelper("FactionName").isMember(event.target.value)) return;
setFactionName(event.target.value);
}
function receiveInvite(): void {
Player.receiveInvite(faction);
Player.receiveInvite(factionName);
}
function receiveAllInvites(): void {
@ -40,57 +43,53 @@ export function Factions(): React.ReactElement {
function modifyFactionRep(modifier: number): (x: number) => void {
return function (reputation: number): void {
const fac = AllFaction[faction];
if (fac != null && !isNaN(reputation)) {
const fac = Factions[factionName];
if (!isNaN(reputation)) {
fac.playerReputation += reputation * modifier;
}
};
}
function resetFactionRep(): void {
const fac = AllFaction[faction];
if (fac != null) {
fac.playerReputation = 0;
}
const fac = Factions[factionName];
fac.playerReputation = 0;
}
function modifyFactionFavor(modifier: number): (x: number) => void {
return function (favor: number): void {
const fac = AllFaction[faction];
if (fac != null && !isNaN(favor)) {
const fac = Factions[factionName];
if (!isNaN(favor)) {
fac.favor += favor * modifier;
}
};
}
function resetFactionFavor(): void {
const fac = AllFaction[faction];
if (fac != null) {
fac.favor = 0;
}
const fac = Factions[factionName];
fac.favor = 0;
}
function tonsOfRep(): void {
for (const i of Object.keys(AllFaction)) {
AllFaction[i].playerReputation = bigNumber;
for (const faction of getRecordValues(Factions)) {
faction.playerReputation = bigNumber;
}
}
function resetAllRep(): void {
for (const i of Object.keys(AllFaction)) {
AllFaction[i].playerReputation = 0;
for (const faction of getRecordValues(Factions)) {
faction.playerReputation = 0;
}
}
function tonsOfFactionFavor(): void {
for (const i of Object.keys(AllFaction)) {
AllFaction[i].favor = bigNumber;
for (const faction of getRecordValues(Factions)) {
faction.favor = bigNumber;
}
}
function resetAllFactionFavor(): void {
for (const i of Object.keys(AllFaction)) {
AllFaction[i].favor = 0;
for (const faction of getRecordValues(Factions)) {
faction.favor = 0;
}
}
@ -113,7 +112,7 @@ export function Factions(): React.ReactElement {
labelId="factions-select"
id="factions-dropdown"
onChange={setFactionDropdown}
value={faction}
value={factionName}
startAdornment={
<>
<IconButton onClick={receiveAllInvites} size="large" arial-label="receive-all-invitation">
@ -125,7 +124,7 @@ export function Factions(): React.ReactElement {
</>
}
>
{Object.values(AllFaction).map((faction) => (
{Object.values(Factions).map((faction) => (
<MenuItem key={faction.name} value={faction.name}>
{faction.name}
</MenuItem>

View File

@ -1,24 +1,31 @@
import React, { useEffect, useState } from "react";
import Accordion from "@mui/material/Accordion";
import AccordionSummary from "@mui/material/AccordionSummary";
import AccordionDetails from "@mui/material/AccordionDetails";
import {
Accordion,
AccordionSummary,
AccordionDetails,
Button,
MenuItem,
Select,
SelectChangeEvent,
TextField,
Typography,
} from "@mui/material";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import Typography from "@mui/material/Typography";
import Button from "@mui/material/Button";
import { Money } from "../../ui/React/Money";
import { Player } from "@player";
import { FactionName } from "@enums";
import { Money } from "../../ui/React/Money";
import { Router } from "../../ui/GameRoot";
import { MenuItem, SelectChangeEvent, TextField, Select } from "@mui/material";
import { Bladeburner } from "../../Bladeburner/Bladeburner";
import { GangConstants } from "../../Gang/data/Constants";
import { FactionName } from "@enums";
import { checkForMessagesToSend } from "../../Message/MessageHelpers";
import { ThemeEvents } from "../../Themes/ui/Theme";
import { getEnumHelper } from "../../utils/EnumHelper";
export function General(): React.ReactElement {
const [error, setError] = useState(false);
const [corporationName, setCorporationName] = useState("");
const [gangFaction, setGangFaction] = useState("Slum Snakes");
const [gangFaction, setGangFaction] = useState(FactionName.SlumSnakes);
const [devMoney, setDevMoney] = useState(0);
// Money functions
@ -71,7 +78,11 @@ export function General(): React.ReactElement {
// Rerender so the gang menu option will be removed immediately on the devmenu page selection
ThemeEvents.emit();
};
const setGangFactionDropdown = (event: SelectChangeEvent) => setGangFaction(event.target.value);
const setGangFactionDropdown = (event: SelectChangeEvent) => {
// Todo: Make this a more specific check when a GangName enumlike is added
if (!getEnumHelper("FactionName").isMember(event.target.value)) return;
setGangFaction(event.target.value);
};
// Misc functions
const checkMessages = () => checkForMessagesToSend();

View File

@ -1,8 +1,8 @@
import type { AugmentationName } from "@enums";
import { AugmentationName, FactionName } from "@enums";
import { FactionInfo, FactionInfos } from "./FactionInfo";
import { favorToRep, repToFavor } from "./formulas/favor";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver";
import { getEnumHelper } from "../utils/EnumHelper";
import { getKeyList } from "../utils/helpers/getKeyList";
export class Faction {
/**
@ -24,12 +24,12 @@ export class Faction {
isMember = false;
/** Name of faction */
name = "";
name: FactionName;
/** Amount of reputation player has with this faction */
playerReputation = 0;
constructor(name = "") {
constructor(name = FactionName.Sector12) {
this.name = name;
}
@ -44,11 +44,24 @@ export class Faction {
return info;
}
gainFavor(): void {
if (this.favor == null) {
this.favor = 0;
}
prestigeSourceFile() {
// Reset favor, reputation, and flags
this.favor = 0;
this.playerReputation = 0;
this.alreadyInvited = false;
this.isMember = false;
this.isBanned = false;
}
prestigeAugmentation(): void {
// Gain favor
if (this.favor == null) this.favor = 0;
this.favor += this.getFavorGain();
// Reset reputation and flags
this.playerReputation = 0;
this.alreadyInvited = false;
this.isMember = false;
this.isBanned = false;
}
//Returns an array with [How much favor would be gained, how much rep would be left over]
@ -62,21 +75,16 @@ export class Faction {
return newFavor - this.favor;
}
static savedKeys = getKeyList(Faction, { removedKeys: ["augmentations", "name"] });
/** Serialize the current object to a JSON save state. */
toJSON(): IReviverValue {
return Generic_toJSON("Faction", this);
return Generic_toJSON("Faction", this, Faction.savedKeys);
}
/** Initializes a Faction object from a JSON save state. */
static fromJSON(value: IReviverValue): Faction {
const faction = Generic_fromJSON(Faction, value.data);
if (!Array.isArray(faction.augmentations)) faction.augmentations = [];
// Remove invalid augs from faction. Augs are repopulated with correct augs during any reset.
const augHelper = getEnumHelper("AugmentationName");
faction.augmentations = faction.augmentations.filter((augName) => augHelper.isMember(augName));
// Fix broken saves, this will soon be removed when better fix is implemented
faction.augmentations = [...new Set(faction.augmentations)];
return faction;
return Generic_fromJSON(Faction, value.data, Faction.savedKeys);
}
}

View File

@ -1,12 +1,13 @@
import type { Augmentation } from "../Augmentation/Augmentation";
import type { Faction } from "./Faction";
import { Augmentations } from "../Augmentation/Augmentations";
import { Augmentation } from "../Augmentation/Augmentation";
import { PlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
import { AugmentationName, FactionName } from "@enums";
import { currentNodeMults } from "../BitNode/BitNodeMultipliers";
import { Faction } from "./Faction";
import { Factions } from "./Factions";
import { Player } from "@player";
import { Factions } from "./Factions";
import { Settings } from "../Settings/Settings";
import {
getHackingWorkRepGain,
@ -19,6 +20,7 @@ import { InvitationEvent } from "./ui/InvitationModal";
import { SFC32RNG } from "../Casino/RNG";
import { isFactionWork } from "../Work/FactionWork";
import { getAugCost } from "../Augmentation/AugmentationHelpers";
import { createEnumKeyedRecord, getRecordKeys } from "../Types/Record";
export function inviteToFaction(faction: Faction): void {
Player.receiveInvite(faction.name);
@ -32,8 +34,9 @@ export function joinFaction(faction: Faction): void {
if (faction.isMember) return;
faction.isMember = true;
Player.factions.push(faction.name);
const allFactions = Object.values(FactionName).map((faction) => faction as string);
Player.factions.sort((a, b) => allFactions.indexOf(a) - allFactions.indexOf(b));
let i = 0;
const factionIndexes = createEnumKeyedRecord(FactionName, (__) => i++);
Player.factions.sort((a, b) => factionIndexes[a] - factionIndexes[b]);
const factionInfo = faction.getInfo();
//Determine what factions you are banned from now that you have joined this faction
@ -108,9 +111,8 @@ export function purchaseAugmentation(aug: Augmentation, fac: Faction, sing = fal
export function processPassiveFactionRepGain(numCycles: number): void {
if (Player.bitNodeN === 2) return;
for (const name of Object.keys(Factions)) {
for (const name of getRecordKeys(Factions)) {
if (isFactionWork(Player.currentWork) && name === Player.currentWork.factionName) continue;
if (!Object.hasOwn(Factions, name)) continue;
const faction = Factions[name];
if (!faction.isMember) continue;
// No passive rep for special factions

View File

@ -7,7 +7,7 @@ import { Typography } from "@mui/material";
interface FactionInfoParams {
infoText?: JSX.Element;
enemies?: string[];
enemies?: FactionName[];
offerHackingWork?: boolean;
offerFieldWork?: boolean;
offerSecurityWork?: boolean;
@ -19,7 +19,7 @@ interface FactionInfoParams {
/** Contains the "information" property for all the Factions, which is just a description of each faction */
export class FactionInfo {
/** The names of all other factions considered to be enemies to this faction. */
enemies: string[];
enemies: FactionName[];
/** The descriptive text to show on the faction's page. */
infoText: JSX.Element;
@ -60,7 +60,7 @@ export class FactionInfo {
}
/** A map of all factions and associated info to them. */
export const FactionInfos: Record<string, FactionInfo> = {
export const FactionInfos: Record<FactionName, FactionInfo> = {
// Endgame
[FactionName.Illuminati]: new FactionInfo({
infoText: (

View File

@ -2,63 +2,42 @@
* Initialization and manipulation of the Factions object, which stores data
* about all Factions in the game
*/
import { FactionName } from "@enums";
import { Faction } from "./Faction";
import { FactionInfos } from "./FactionInfo";
import { Reviver } from "../utils/JSONReviver";
import { getRecordValues } from "../Types/Record";
import { Augmentations, initCircadianModulator } from "../Augmentation/Augmentations";
import { Reviver, assertLoadingType } from "../utils/JSONReviver";
import { createEnumKeyedRecord, getRecordValues } from "../Types/Record";
import { Augmentations } from "../Augmentation/Augmentations";
import { getEnumHelper } from "../utils/EnumHelper";
export let Factions: Record<string, Faction> = {};
/** The static list of all factions. Initialized once and never modified. */
export const Factions = createEnumKeyedRecord(FactionName, (name) => new Faction(name));
// Add the associated augs to every faction
for (const aug of getRecordValues(Augmentations)) {
for (const factionName of aug.factions) {
const faction = Factions[factionName];
faction.augmentations.push(aug.name);
}
}
export function loadFactions(saveString: string): void {
Factions = JSON.parse(saveString, Reviver);
// safety check for when we load older save file that don't have newer factions
for (const faction of Object.keys(Factions)) {
try {
Factions[faction].getInfo();
} catch (err) {
console.error("deleting " + faction);
delete Factions[faction];
}
// The only information that should be loaded from player save is
const loadedFactions = JSON.parse(saveString, Reviver) as unknown;
// This loading method allows invalid data in player save, but just ignores anything invalid
if (!loadedFactions) return;
if (typeof loadedFactions !== "object") return;
for (const [loadedFactionName, loadedFaction] of Object.entries(loadedFactions) as [string, unknown][]) {
if (!getEnumHelper("FactionName").isMember(loadedFactionName)) continue;
if (!loadedFaction) continue;
const faction = Factions[loadedFactionName];
if (typeof loadedFaction !== "object") continue;
assertLoadingType<Faction>(loadedFaction);
const { playerReputation: loadedRep, favor: loadedFavor } = loadedFaction;
if (typeof loadedRep === "number" && loadedRep > 0) faction.playerReputation = loadedRep;
if (typeof loadedFavor === "number" && loadedFavor > 0) faction.favor = loadedFavor;
// 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;
}
}
function AddToFactions(faction: Faction): void {
const name: string = faction.name;
Factions[name] = faction;
}
export function factionExists(name: string): boolean {
return Object.hasOwn(Factions, name);
}
export function initFactions(): void {
for (const name of Object.keys(FactionInfos)) {
resetFaction(new Faction(name));
}
// All factions are added, this is a good place to add augs back to factions.
initCircadianModulator();
for (const aug of getRecordValues(Augmentations)) {
for (const factionName of aug.factions) {
const faction = Factions[factionName];
if (!faction) {
console.error(`Faction ${factionName} did not exist while adding augs to factions`);
continue;
}
faction.augmentations.push(aug.name);
}
}
}
//Resets a faction during (re-)initialization. Saves the favor in the new
//Faction object and deletes the old Faction Object from "Factions". Then
//reinserts the new Faction object
function resetFaction(newFactionObject: Faction): void {
const factionName: string = newFactionObject.name;
if (factionExists(factionName)) {
newFactionObject.favor = Factions[factionName].favor;
delete Factions[factionName];
}
AddToFactions(newFactionObject);
}

View File

@ -11,7 +11,7 @@ import { FactionName } from "@enums";
interface IProps {
open: boolean;
onClose: () => void;
facName: string;
facName: FactionName;
}
/** React Component for the popup used to create a new gang. */
@ -27,7 +27,7 @@ export function CreateGangModal(props: IProps): React.ReactElement {
"is not as important.";
function isHacking(): boolean {
return [FactionName.NiteSec as string, FactionName.TheBlackHand as string].includes(props.facName);
return [FactionName.NiteSec, FactionName.TheBlackHand].includes(props.facName);
}
function createGang(): void {

View File

@ -1,12 +1,13 @@
import type { Faction } from "../Faction";
import React, { useEffect } from "react";
import { Explore, Info, LastPage, LocalPolice, NewReleases, Report, SportsMma } from "@mui/icons-material";
import { Box, Button, Container, Paper, Tooltip, Typography, useTheme } from "@mui/material";
import React, { useEffect } from "react";
import { Player } from "@player";
import { Settings } from "../../Settings/Settings";
import { formatFavor, formatReputation } from "../../ui/formatNumber";
import { Router } from "../../ui/GameRoot";
import { FactionName } from "@enums";
import { Faction } from "../Faction";
import { getFactionAugmentationsFiltered, joinFaction } from "../FactionHelpers";
import { Factions } from "../Factions";
import { useRerender } from "../../ui/React/hooks";
@ -59,7 +60,7 @@ const FactionElement = (props: FactionElementProps): React.ReactElement => {
Router.toFaction(faction, true);
}
function acceptInvitation(event: React.MouseEvent<HTMLButtonElement>, faction: string): void {
function acceptInvitation(event: React.MouseEvent<HTMLButtonElement>, faction: FactionName): void {
if (!event.isTrusted) return;
joinFaction(Factions[faction]);
props.rerender();

View File

@ -23,9 +23,10 @@ import { GangMember } from "./GangMember";
import { WorkerScript } from "../Netscript/WorkerScript";
import { Player } from "@player";
import { PowerMultiplier } from "./data/power";
import { FactionName } from "@enums";
export class Gang {
facName: string;
facName: FactionName;
members: GangMember[];
wanted: number;
respect: number;
@ -48,7 +49,7 @@ export class Gang {
notifyMemberDeath: boolean;
constructor(facName = "", hacking = false) {
constructor(facName = FactionName.SlumSnakes, hacking = false) {
this.facName = facName;
this.members = [];
this.wanted = 1;

View File

@ -1,11 +1,13 @@
import { Box, Button, MenuItem, Paper, Select, SelectChangeEvent, Typography } from "@mui/material";
import React, { useState } from "react";
import { Box, Button, MenuItem, Paper, Select, SelectChangeEvent, Typography } from "@mui/material";
import { Player } from "@player";
import { FactionName } from "@enums";
import { inviteToFaction } from "../../Faction/FactionHelpers";
import { Factions } from "../../Faction/Factions";
import { Router } from "../../ui/GameRoot";
import { Page } from "../../ui/Router";
import { Player } from "@player";
import { Money } from "../../ui/React/Money";
import { Reputation } from "../../ui/React/Reputation";
import { formatNumberNoSuffix } from "../../ui/formatNumber";
@ -14,6 +16,7 @@ import {
calculateSellInformationCashReward,
calculateTradeInformationRepReward,
} from "../formulas/victory";
import { getEnumHelper } from "../../utils/EnumHelper";
interface IProps {
StartingDifficulty: number;
@ -23,7 +26,7 @@ interface IProps {
}
export function Victory(props: IProps): React.ReactElement {
const [faction, setFaction] = useState("none");
const [factionName, setFactionName] = useState("none");
function quitInfiltration(): void {
handleInfiltrators();
@ -43,13 +46,13 @@ export function Victory(props: IProps): React.ReactElement {
}
function trade(): void {
if (faction === "none") return;
Factions[faction].playerReputation += repGain;
if (!getEnumHelper("FactionName").isMember(factionName)) return;
Factions[factionName].playerReputation += repGain;
quitInfiltration();
}
function changeDropdown(event: SelectChangeEvent): void {
setFaction(event.target.value);
setFactionName(event.target.value);
}
function handleInfiltrators(): void {
@ -75,7 +78,7 @@ export function Victory(props: IProps): React.ReactElement {
</Typography>
<Box sx={{ width: "fit-content" }}>
<Box sx={{ width: "100%" }}>
<Select value={faction} onChange={changeDropdown} sx={{ mr: 1 }}>
<Select value={factionName} onChange={changeDropdown} sx={{ mr: 1 }}>
<MenuItem key={"none"} value={"none"}>
{"none"}
</MenuItem>

View File

@ -3,15 +3,15 @@ import { Player } from "@player";
import { Factions } from "../Faction/Factions";
import { Faction } from "../Faction/Faction";
import { GetServer } from "../Server/AllServers";
import { FactionName } from "@enums";
import { AugmentationName, FactionName } from "@enums";
import { Server } from "../Server/Server";
function allFactionAugs(f: Faction): boolean {
const factionAugs = f.augmentations.slice().filter((aug) => aug !== "NeuroFlux Governor");
for (const factionAug of factionAugs) {
function allFactionAugs(faction: Faction): boolean {
for (const factionAugName of faction.augmentations) {
if (factionAugName === AugmentationName.NeuroFluxGovernor) continue;
if (
!Player.augmentations.some((aug) => {
return aug.name == factionAug;
return aug.name == factionAugName;
})
)
return false;

View File

@ -51,7 +51,7 @@ import {
} from "../Corporation/Actions";
import { CorpUnlocks } from "../Corporation/data/CorporationUnlocks";
import { CorpUpgrades } from "../Corporation/data/CorporationUpgrades";
import { CorpUnlockName, CorpUpgradeName, CorpEmployeeJob, CityName } from "@enums";
import { CorpUnlockName, CorpUpgradeName, CorpEmployeeJob, CityName, FactionName } from "@enums";
import { IndustriesData, IndustryResearchTrees } from "../Corporation/data/IndustryData";
import * as corpConstants from "../Corporation/data/Constants";
import { ResearchMap } from "../Corporation/ResearchMap";
@ -174,8 +174,7 @@ export function NetscriptCorporation(): InternalAPI<NSCorporation> {
return division.researched.has(researchName);
}
function bribe(factionName: string, amountCash: number): boolean {
if (!player.factions.includes(factionName)) throw new Error("Invalid faction name");
function bribe(factionName: FactionName, amountCash: number): boolean {
if (isNaN(amountCash) || amountCash < 0)
throw new Error("Invalid value for amount field! Must be numeric, greater than 0.");
@ -825,7 +824,7 @@ export function NetscriptCorporation(): InternalAPI<NSCorporation> {
},
bribe: (ctx) => (_factionName, _amountCash) => {
checkAccess(ctx);
const factionName = helpers.string(ctx, "factionName", _factionName);
const factionName = getEnumHelper("FactionName").nsGetMember(ctx, _factionName);
const amountCash = helpers.number(ctx, "amountCash", _amountCash);
return bribe(factionName, amountCash);
},

View File

@ -1,16 +1,17 @@
import type { Gang as IGang, EquipmentStats, GangOtherInfoObject } from "@nsdefs";
import type { Gang } from "../Gang/Gang";
import type { GangMember } from "../Gang/GangMember";
import type { GangMemberTask } from "../Gang/GangMemberTask";
import type { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { Player } from "@player";
import { FactionName } from "@enums";
import { GangConstants } from "../Gang/data/Constants";
import { Player } from "@player";
import { Gang } from "../Gang/Gang";
import { AllGangs } from "../Gang/AllGangs";
import { GangMemberTasks } from "../Gang/GangMemberTasks";
import { GangMemberUpgrades } from "../Gang/GangMemberUpgrades";
import { GangMember } from "../Gang/GangMember";
import { GangMemberTask } from "../Gang/GangMemberTask";
import { helpers } from "../Netscript/NetscriptHelpers";
import { Gang as IGang, EquipmentStats, GangOtherInfoObject } from "@nsdefs";
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { getEnumHelper } from "../utils/EnumHelper";
export function NetscriptGang(): InternalAPI<IGang> {
/** Functions as an API check and also returns the gang object */
@ -36,9 +37,7 @@ export function NetscriptGang(): InternalAPI<IGang> {
return {
createGang: (ctx) => (_faction) => {
const faction = helpers.string(ctx, "faction", _faction);
// this list is copied from Faction/ui/Root.tsx
const faction = getEnumHelper("FactionName").nsGetMember(ctx, _faction);
if (!Player.canAccessGang() || !GangConstants.Names.includes(faction)) return false;
if (Player.gang) return false;
if (!Player.factions.includes(faction)) return false;

View File

@ -1,6 +1,5 @@
import type { Singularity as ISingularity } from "@nsdefs";
import type { Company } from "../Company/Company";
import type { Faction } from "../Faction/Faction";
import { Player } from "@player";
import {
@ -33,7 +32,7 @@ import { formatMoney, formatRam, formatReputation } from "../ui/formatNumber";
import { currentNodeMults } from "../BitNode/BitNodeMultipliers";
import { Companies } from "../Company/Companies";
import { companiesMetadata } from "../Company/data/CompaniesMetadata";
import { Factions, factionExists } from "../Faction/Factions";
import { Factions } from "../Faction/Factions";
import { helpers } from "../Netscript/NetscriptHelpers";
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
import { getServerOnNetwork } from "../Server/ServerHelpers";
@ -59,14 +58,6 @@ import { ScriptFilePath, resolveScriptFilePath } from "../Paths/ScriptFilePath";
import { root } from "../Paths/Directory";
export function NetscriptSingularity(): InternalAPI<ISingularity> {
const getFaction = function (ctx: NetscriptContext, name: string): Faction {
if (!factionExists(name)) {
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid faction name: '${name}`);
}
return Factions[name];
};
const getCompany = function (ctx: NetscriptContext, name: string): Company {
const company = Companies[name];
if (!company) throw helpers.makeRuntimeErrorMsg(ctx, `Invalid company name: '${name}'`);
@ -112,9 +103,8 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
},
getAugmentationsFromFaction: (ctx) => (_facName) => {
helpers.checkSingularityAccess(ctx);
const facName = helpers.string(ctx, "facName", _facName);
const faction = getFaction(ctx, facName);
const facName = getEnumHelper("FactionName").nsGetMember(ctx, _facName);
const faction = Factions[facName];
return getFactionAugmentationsFiltered(faction);
},
getAugmentationPrereq: (ctx) => (_augName) => {
@ -149,19 +139,19 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
},
purchaseAugmentation: (ctx) => (_facName, _augName) => {
helpers.checkSingularityAccess(ctx);
const facName = helpers.string(ctx, "facName", _facName);
const facName = getEnumHelper("FactionName").nsGetMember(ctx, _facName);
const augName = getEnumHelper("AugmentationName").nsGetMember(ctx, _augName);
const fac = getFaction(ctx, facName);
const fac = Factions[facName];
const aug = Augmentations[augName];
const augs = getFactionAugmentationsFiltered(fac);
const factionAugs = getFactionAugmentationsFiltered(fac);
if (!Player.factions.includes(fac.name)) {
if (!Player.factions.includes(facName)) {
helpers.log(ctx, () => `You can't purchase augmentations from '${facName}' because you aren't a member`);
return false;
}
if (!augs.includes(augName)) {
if (!factionAugs.includes(augName)) {
helpers.log(ctx, () => `Faction '${facName}' does not have the '${augName}' augmentation.`);
return false;
}
@ -867,8 +857,7 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
},
joinFaction: (ctx) => (_facName) => {
helpers.checkSingularityAccess(ctx);
const facName = helpers.string(ctx, "facName", _facName);
getFaction(ctx, facName);
const facName = getEnumHelper("FactionName").nsGetMember(ctx, _facName);
if (!Player.factionInvitations.includes(facName)) {
helpers.log(ctx, () => `You have not been invited by faction '${facName}'`);
@ -892,10 +881,10 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
(ctx) =>
(_facName, _type, _focus = true) => {
helpers.checkSingularityAccess(ctx);
const facName = helpers.string(ctx, "facName", _facName);
const facName = getEnumHelper("FactionName").nsGetMember(ctx, _facName);
const type = helpers.string(ctx, "type", _type);
const focus = !!_focus;
const faction = getFaction(ctx, facName);
const faction = Factions[facName];
// if the player is in a gang and the target faction is any of the gang faction, fail
if (Player.gang && faction.name === Player.getGangFaction().name) {
@ -987,27 +976,27 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
},
getFactionRep: (ctx) => (_facName) => {
helpers.checkSingularityAccess(ctx);
const facName = helpers.string(ctx, "facName", _facName);
const faction = getFaction(ctx, facName);
const facName = getEnumHelper("FactionName").nsGetMember(ctx, _facName);
const faction = Factions[facName];
return faction.playerReputation;
},
getFactionFavor: (ctx) => (_facName) => {
helpers.checkSingularityAccess(ctx);
const facName = helpers.string(ctx, "facName", _facName);
const faction = getFaction(ctx, facName);
const facName = getEnumHelper("FactionName").nsGetMember(ctx, _facName);
const faction = Factions[facName];
return faction.favor;
},
getFactionFavorGain: (ctx) => (_facName) => {
helpers.checkSingularityAccess(ctx);
const facName = helpers.string(ctx, "facName", _facName);
const faction = getFaction(ctx, facName);
const facName = getEnumHelper("FactionName").nsGetMember(ctx, _facName);
const faction = Factions[facName];
return faction.getFavorGain();
},
donateToFaction: (ctx) => (_facName, _amt) => {
helpers.checkSingularityAccess(ctx);
const facName = helpers.string(ctx, "facName", _facName);
const facName = getEnumHelper("FactionName").nsGetMember(ctx, _facName);
const amt = helpers.number(ctx, "amt", _amt);
const faction = getFaction(ctx, facName);
const faction = Factions[facName];
if (!Player.factions.includes(faction.name)) {
helpers.log(ctx, () => `You can't donate to '${facName}' because you aren't a member`);
return false;

View File

@ -17,7 +17,7 @@ import * as serverMethods from "./PlayerObjectServerMethods";
import * as workMethods from "./PlayerObjectWorkMethods";
import { setPlayer } from "../../Player";
import { LocationName } from "@enums";
import { FactionName, LocationName } from "@enums";
import { HashManager } from "../../Hacknet/HashManager";
import { MoneySourceTracker } from "../../utils/MoneySourceTracker";
import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../../utils/JSONReviver";
@ -35,8 +35,8 @@ export class PlayerObject extends Person implements IPlayer {
gang: Gang | null = null;
bladeburner: Bladeburner | null = null;
currentServer = "";
factions: string[] = [];
factionInvitations: string[] = [];
factions: FactionName[] = [];
factionInvitations: FactionName[] = [];
hacknetNodes: (HacknetNode | string)[] = []; // HacknetNode object or hostname of Hacknet Server
has4SData = false;
has4SDataTixApi = false;

View File

@ -1,11 +1,12 @@
import type { PlayerObject } from "./PlayerObject";
import type { FactionName } from "@enums";
import type { Faction } from "../../Faction/Faction";
import { Factions } from "../../Faction/Factions";
import { Faction } from "../../Faction/Faction";
import { Gang } from "../../Gang/Gang";
import { GangConstants } from "../../Gang/data/Constants";
import { isFactionWork } from "../../Work/FactionWork";
import type { PlayerObject } from "./PlayerObject";
export function canAccessGang(this: PlayerObject): boolean {
if (this.bitNodeN === 2) {
return true;
@ -36,12 +37,12 @@ export function getGangName(this: PlayerObject): string {
return gang ? gang.facName : "";
}
export function hasGangWith(this: PlayerObject, facName: string): boolean {
export function hasGangWith(this: PlayerObject, facName: FactionName): boolean {
const gang = this.gang;
return gang ? gang.facName === facName : false;
}
export function startGang(this: PlayerObject, factionName: string, hacking: boolean): void {
export function startGang(this: PlayerObject, factionName: FactionName, hacking: boolean): void {
// isFactionWork handles null internally, finishWork might need to be run with true
if (isFactionWork(this.currentWork) && this.currentWork.factionName === factionName) this.finishWork(false);

View File

@ -158,7 +158,7 @@ export function prestigeSourceFile(this: PlayerObject): void {
this.augmentations = [];
}
export function receiveInvite(this: PlayerObject, factionName: string): void {
export function receiveInvite(this: PlayerObject, factionName: FactionName): void {
if (this.factionInvitations.includes(factionName) || this.factions.includes(factionName)) {
return;
}
@ -1099,34 +1099,34 @@ export function gainCodingContractReward(
reward: ICodingContractReward | null,
difficulty = 1,
): string {
if (reward == null || reward.type == null) {
return `No reward for this contract`;
}
if (!reward) return `No reward for this contract`;
/* eslint-disable no-case-declarations */
switch (reward.type) {
case CodingContractRewardType.FactionReputation:
if (reward.name == null || !Factions[reward.name]) {
// If no/invalid faction was designated, just give rewards to all factions
reward.type = CodingContractRewardType.FactionReputationAll;
return this.gainCodingContractReward(reward);
case CodingContractRewardType.FactionReputation: {
if (!Factions[reward.name]) {
return this.gainCodingContractReward({ type: CodingContractRewardType.FactionReputationAll });
}
const repGain = CONSTANTS.CodingContractBaseFactionRepGain * difficulty;
Factions[reward.name].playerReputation += repGain;
return `Gained ${repGain} faction reputation for ${reward.name}`;
case CodingContractRewardType.FactionReputationAll:
}
case CodingContractRewardType.FactionReputationAll: {
const totalGain = CONSTANTS.CodingContractBaseFactionRepGain * difficulty;
// Ignore Bladeburners and other special factions for this calculation
const specialFactions = [FactionName.Bladeburners as string];
const specialFactions = [
FactionName.Bladeburners,
FactionName.ShadowsOfAnarchy,
FactionName.ChurchOfTheMachineGod,
];
const factions = this.factions.slice().filter((f) => {
return !specialFactions.includes(f);
});
// If the player was only part of the special factions, we'll just give money
if (factions.length == 0) {
reward.type = CodingContractRewardType.Money;
return this.gainCodingContractReward(reward, difficulty);
return this.gainCodingContractReward({ type: CodingContractRewardType.Money }, difficulty);
}
const gainPerFaction = Math.floor(totalGain / factions.length);
@ -1135,11 +1135,11 @@ export function gainCodingContractReward(
Factions[facName].playerReputation += gainPerFaction;
}
return `Gained ${gainPerFaction} reputation for each of the following factions: ${factions.join(", ")}`;
}
case CodingContractRewardType.CompanyReputation: {
if (reward.name == null || !Companies[reward.name]) {
if (!Companies[reward.name]) {
//If no/invalid company was designated, just give rewards to all factions
reward.type = CodingContractRewardType.FactionReputationAll;
return this.gainCodingContractReward(reward);
return this.gainCodingContractReward({ type: CodingContractRewardType.FactionReputationAll });
}
const repGain = CONSTANTS.CodingContractBaseCompanyRepGain * difficulty;
Companies[reward.name].playerReputation += repGain;

View File

@ -292,38 +292,31 @@ export class Sleeve extends Person implements SleevePerson {
return true;
}
/**
* Start work for one of the player's factions
* Returns boolean indicating success
*/
workForFaction(factionName: string, workType: string): boolean {
/** TODO 2.4: Make this take in type correct data */
workForFaction(_factionName: string, _workType: string): boolean {
const factionName = getEnumHelper("FactionName").fuzzyGetMember(_factionName);
if (!factionName) return false;
const faction = Factions[factionName];
if (factionName === "" || !faction || !Player.factions.includes(factionName)) {
return false;
}
const workType = getEnumHelper("FactionWorkType").fuzzyGetMember(_workType);
if (!workType) return false;
const factionInfo = faction.getInfo();
// Set type of work (hacking/field/security), and the experience gains
const sanitizedWorkType = workType.toLowerCase();
let factionWorkType: FactionWorkType;
if (sanitizedWorkType.includes("hack")) {
if (!factionInfo.offerHackingWork) return false;
factionWorkType = FactionWorkType.hacking;
} else if (sanitizedWorkType.includes("field")) {
if (!factionInfo.offerFieldWork) return false;
factionWorkType = FactionWorkType.field;
} else if (sanitizedWorkType.includes("security")) {
if (!factionInfo.offerSecurityWork) return false;
factionWorkType = FactionWorkType.security;
} else {
return false;
switch (workType) {
case FactionWorkType.field:
if (!factionInfo.offerFieldWork) return false;
break;
case FactionWorkType.hacking:
if (!factionInfo.offerHackingWork) return false;
break;
case FactionWorkType.security:
if (!factionInfo.offerSecurityWork) return false;
break;
}
this.startWork(
new SleeveFactionWork({
factionWorkType: factionWorkType,
factionName: faction.name,
factionWorkType: workType,
factionName: factionName,
}),
);

View File

@ -7,11 +7,11 @@ import { Factions } from "../../../Faction/Factions";
import { calculateFactionExp, calculateFactionRep } from "../../../Work/Formulas";
import { Faction } from "../../../Faction/Faction";
import { scaleWorkStats, WorkStats } from "../../../Work/WorkStats";
import { findEnumMember } from "../../../utils/helpers/enum";
import { getEnumHelper } from "../../../utils/EnumHelper";
interface SleeveFactionWorkParams {
factionWorkType: FactionWorkType;
factionName: string;
factionName: FactionName;
}
export const isSleeveFactionWork = (w: SleeveWorkClass | null): w is SleeveFactionWork =>
@ -20,7 +20,7 @@ export const isSleeveFactionWork = (w: SleeveWorkClass | null): w is SleeveFacti
export class SleeveFactionWork extends SleeveWorkClass {
type: SleeveWorkType.FACTION = SleeveWorkType.FACTION;
factionWorkType: FactionWorkType;
factionName: string;
factionName: FactionName;
constructor(params?: SleeveFactionWorkParams) {
super();
@ -67,8 +67,8 @@ export class SleeveFactionWork extends SleeveWorkClass {
/** Initializes a FactionWork object from a JSON save state. */
static fromJSON(value: IReviverValue): SleeveFactionWork {
const factionWork = Generic_fromJSON(SleeveFactionWork, value.data);
factionWork.factionWorkType =
findEnumMember(FactionWorkType, factionWork.factionWorkType) ?? FactionWorkType.hacking;
factionWork.factionWorkType = getEnumHelper("FactionWorkType").fuzzyGetMember(factionWork.factionWorkType, true);
factionWork.factionName = getEnumHelper("FactionName").fuzzyGetMember(factionWork.factionName, true);
return factionWork;
}
}

View File

@ -137,10 +137,9 @@ const tasks: {
return {
first: factions,
second: (s1: string) => {
second: (s1) => {
if (!getEnumHelper("FactionName").isMember(s1)) return ["------"];
const faction = Factions[s1];
if (!faction) return ["------"];
const facInfo = faction.getInfo();
const options: string[] = [];
if (facInfo.offerHackingWork) {

View File

@ -2,7 +2,7 @@ import { AugmentationName, CityName, CompletedProgramName, FactionName, Literatu
import { initBitNodeMultipliers } from "./BitNode/BitNode";
import { Companies, initCompanies } from "./Company/Companies";
import { resetIndustryResearchTrees } from "./Corporation/data/IndustryData";
import { Factions, initFactions } from "./Faction/Factions";
import { Factions } from "./Faction/Factions";
import { joinFaction } from "./Faction/FactionHelpers";
import { updateHashManagerCapacity } from "./Hacknet/HacknetHelpers";
import { prestigeWorkerScripts } from "./NetscriptWorker";
@ -23,6 +23,7 @@ import { ProgramsSeen } from "./Programs/ui/ProgramsRoot";
import { InvitationsSeen } from "./Faction/ui/FactionsRoot";
import { CONSTANTS } from "./Constants";
import { LogBoxClearEvents } from "./ui/React/LogBoxManager";
import { initCircadianModulator } from "./Augmentation/Augmentations";
const BitNode8StartingMoney = 250e6;
function delayedDialog(message: string) {
@ -71,7 +72,7 @@ export function prestigeAugmentation(): void {
// Gain favor for Companies and Factions
for (const company of Object.values(Companies)) company.gainFavor();
for (const faction of Object.values(Factions)) faction.gainFavor();
for (const faction of Object.values(Factions)) faction.prestigeAugmentation();
// Stop a Terminal action if there is one.
if (Terminal.action !== null) {
@ -80,10 +81,11 @@ export function prestigeAugmentation(): void {
Terminal.clear();
LogBoxClearEvents.emit();
// Re-initialize things - This will update any changes
initFactions(); // Factions must be initialized before augmentations
// Recalculate the bonus for circadian modulator aug
initCircadianModulator();
Player.factionInvitations = Player.factionInvitations.concat(maintainMembership);
for (const factionName of maintainMembership) Factions[factionName].alreadyInvited = true;
Player.reapplyAllAugmentations();
Player.reapplyAllSourceFiles();
Player.hp.current = Player.hp.max;
@ -193,7 +195,7 @@ export function prestigeSourceFile(isFlume: boolean): void {
// Reset favor for Companies and Factions
for (const company of Object.values(Companies)) company.favor = 0;
for (const faction of Object.values(Factions)) faction.favor = 0;
for (const faction of Object.values(Factions)) faction.prestigeSourceFile();
// Stop a Terminal action if there is one
if (Terminal.action !== null) {
@ -208,8 +210,8 @@ export function prestigeSourceFile(isFlume: boolean): void {
});
}
// Re-initialize things - This will update any changes
initFactions(); // Factions must be initialized before augmentations
initCircadianModulator();
Player.reapplyAllAugmentations();
Player.reapplyAllSourceFiles();
initCompanies();

View File

@ -1,28 +1,29 @@
import type { Faction } from "../Faction/Faction";
import React from "react";
import { Work, WorkType } from "./Work";
import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver";
import { Player } from "@player";
import { AugmentationName, FactionName, FactionWorkType } from "@enums";
import { Factions } from "../Faction/Factions";
import { Faction } from "../Faction/Faction";
import { applyWorkStats, scaleWorkStats, WorkStats } from "./WorkStats";
import { dialogBoxCreate } from "../ui/React/DialogBox";
import { Reputation } from "../ui/React/Reputation";
import { CONSTANTS } from "../Constants";
import { calculateFactionExp, calculateFactionRep } from "./Formulas";
import { findEnumMember } from "../utils/helpers/enum";
import { getEnumHelper } from "../utils/EnumHelper";
interface FactionWorkParams {
singularity: boolean;
factionWorkType: FactionWorkType;
faction: string;
faction: FactionName;
}
export const isFactionWork = (w: Work | null): w is FactionWork => w !== null && w.type === WorkType.FACTION;
export class FactionWork extends Work {
factionWorkType: FactionWorkType;
factionName: string;
factionName: FactionName;
constructor(params?: FactionWorkParams) {
super(WorkType.FACTION, params?.singularity ?? true);
@ -31,9 +32,7 @@ export class FactionWork extends Work {
}
getFaction(): Faction {
const f = Factions[this.factionName];
if (!f) throw new Error(`Faction work started with invalid / unknown faction: '${this.factionName}'`);
return f;
return Factions[this.factionName];
}
getReputationRate(): number {
@ -92,8 +91,8 @@ export class FactionWork extends Work {
/** Initializes a FactionWork object from a JSON save state. */
static fromJSON(value: IReviverValue): FactionWork {
const factionWork = Generic_fromJSON(FactionWork, value.data);
factionWork.factionWorkType =
findEnumMember(FactionWorkType, factionWork.factionWorkType) ?? FactionWorkType.hacking;
factionWork.factionWorkType = getEnumHelper("FactionWorkType").fuzzyGetMember(factionWork.factionWorkType, true);
factionWork.factionName = getEnumHelper("FactionName").fuzzyGetMember(factionWork.factionName, true);
return factionWork;
}
}

View File

@ -5,7 +5,7 @@ import { initSourceFiles } from "./SourceFile/SourceFiles";
import { generateRandomContract } from "./CodingContractGenerator";
import { initCompanies } from "./Company/Companies";
import { CONSTANTS } from "./Constants";
import { Factions, initFactions } from "./Faction/Factions";
import { Factions } from "./Faction/Factions";
import { staneksGift } from "./CotMG/Helper";
import { processPassiveFactionRepGain, inviteToFaction } from "./Faction/FactionHelpers";
import { Router } from "./ui/GameRoot";
@ -375,7 +375,6 @@ const Engine: {
Player.init();
initForeignServers(Player.getHomeComputer());
initCompanies();
initFactions();
Player.reapplyAllAugmentations();
// Start interactive tutorial

View File

@ -1,4 +1,6 @@
/* Generic Reviver, toJSON, and fromJSON functions used for saving and loading objects */
import type { Unknownify } from "../types";
import { ObjectValidator, validateObject } from "./Validator";
import { JSONMap, JSONSet } from "../Types/Jsonable";
@ -102,3 +104,7 @@ export function Generic_fromJSON<T extends Record<string, any>>(
for (const [key, val] of Object.entries(data) as [keyof T, T[keyof T]][]) obj[key] = val;
return obj;
}
// This function is empty because Unknownify<T> is a typesafe assertion on any object with no runtime checks needed.
// eslint-disable-next-line @typescript-eslint/no-empty-function
export function assertLoadingType<T extends object>(val: object): asserts val is Unknownify<T> {}

View File

@ -1,5 +1,5 @@
import { saveObject } from "../../src/SaveObject";
import { Factions, initFactions } from "../../src/Faction/Factions";
import { Factions } from "../../src/Faction/Factions";
import { Player, setPlayer } from "../../src/Player";
import { PlayerObject } from "../../src/PersonObjects/Player/PlayerObject";
import { joinFaction } from "../../src/Faction/FactionHelpers";
@ -33,7 +33,6 @@ function establishInitialConditions() {
setPlayer(new PlayerObject());
Player.init();
Player.identifier = "Overwritten identifier";
initFactions();
Player.sleevesFromCovenant = 1;
Player.sourceFiles.set(10, 1);
Player.prestigeAugmentation();

View File

@ -6,19 +6,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Wired Reflexes",
"Speech Processor Implant",
"Synaptic Enhancement Implant",
"Neuralstimulator",
"PCMatrix",
"NeuroFlux Governor",
"Neurotrainer I",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "Aevum",
"playerReputation": 0,
},
},
@ -26,20 +16,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Enhanced Social Interaction Implant",
"Neuralstimulator",
"Nuoptimal Nootropic Injector Implant",
"Speech Enhancement",
"FocusWire",
"ADR-V2 Pheromone Gene",
"NeuroFlux Governor",
"SmartJaw",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "Bachman & Associates",
"playerReputation": 0,
},
},
@ -47,25 +26,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Artificial Bio-neural Network Implant",
"Enhanced Myelin Sheathing",
"DataJack",
"Embedded Netburner Module",
"Embedded Netburner Module Core Implant",
"Embedded Netburner Module Core V2 Upgrade",
"Neural Accelerator",
"Cranial Signal Processors - Gen III",
"Cranial Signal Processors - Gen IV",
"Cranial Signal Processors - Gen V",
"NeuroFlux Governor",
"Neurotrainer II",
"BitRunners Neurolink",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "BitRunners",
"playerReputation": 0,
},
},
@ -73,30 +36,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Augmented Targeting I",
"Augmented Targeting II",
"Augmented Targeting III",
"Synfibril Muscle",
"Combat Rib I",
"Combat Rib II",
"Combat Rib III",
"Nanofiber Weave",
"Bionic Spine",
"Bionic Legs",
"Embedded Netburner Module",
"Embedded Netburner Module Core Implant",
"Embedded Netburner Module Core V2 Upgrade",
"PC Direct-Neural Interface",
"PC Direct-Neural Interface Optimization Submodule",
"NeuroFlux Governor",
"HyperSight Corneal Implant",
"Neotra",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "Blade Industries",
"playerReputation": 0,
},
},
@ -104,29 +46,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"EsperTech Bladeburner Eyewear",
"EMS-4 Recombination",
"ORION-MKIV Shoulder",
"Hyperion Plasma Cannon V1",
"Hyperion Plasma Cannon V2",
"GOLEM Serum",
"Vangelis Virus",
"Vangelis Virus 3.0",
"I.N.T.E.R.L.I.N.K.E.D",
"Blade's Runners",
"BLADE-51b Tesla Armor",
"BLADE-51b Tesla Armor: Power Cells Upgrade",
"BLADE-51b Tesla Armor: Energy Shielding Upgrade",
"BLADE-51b Tesla Armor: Unibeam Upgrade",
"BLADE-51b Tesla Armor: Omnibeam Upgrade",
"BLADE-51b Tesla Armor: IPU Upgrade",
"The Blade's Simulacrum",
],
"favor": 0,
"isBanned": false,
"isMember": true,
"name": "Bladeburners",
"playerReputation": 4000,
},
},
@ -134,18 +56,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Speech Processor Implant",
"DataJack",
"Neuralstimulator",
"Nuoptimal Nootropic Injector Implant",
"NeuroFlux Governor",
"Neuregen Gene Modification",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "Chongqing",
"playerReputation": 0,
},
},
@ -153,15 +66,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Stanek's Gift - Genesis",
"Stanek's Gift - Awakening",
"Stanek's Gift - Serenity",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "Church of the Machine God",
"playerReputation": 0,
},
},
@ -169,21 +76,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Enhanced Social Interaction Implant",
"Neuralstimulator",
"Neuronal Densification",
"Nuoptimal Nootropic Injector Implant",
"Speech Enhancement",
"FocusWire",
"ADR-V2 Pheromone Gene",
"NeuroFlux Governor",
"nextSENS Gene Modification",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "Clarke Incorporated",
"playerReputation": 0,
},
},
@ -191,18 +86,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"BitWire",
"Synaptic Enhancement Implant",
"Cranial Signal Processors - Gen I",
"Cranial Signal Processors - Gen II",
"NeuroFlux Governor",
"Neurotrainer I",
],
"favor": 20,
"isBanned": false,
"isMember": true,
"name": "CyberSec",
"playerReputation": 1000000,
},
},
@ -210,20 +96,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Synthetic Heart",
"Synfibril Muscle",
"NEMEAN Subdermal Weave",
"Embedded Netburner Module Core V3 Upgrade",
"Embedded Netburner Module Analyze Engine",
"Embedded Netburner Module Direct Memory Access Upgrade",
"NeuroFlux Governor",
"The Red Pill",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "Daedalus",
"playerReputation": 0,
},
},
@ -231,24 +106,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Graphene Bionic Spine Upgrade",
"Graphene Bionic Legs Upgrade",
"Embedded Netburner Module",
"Embedded Netburner Module Core Implant",
"Embedded Netburner Module Core V2 Upgrade",
"Embedded Netburner Module Core V3 Upgrade",
"Embedded Netburner Module Analyze Engine",
"Embedded Netburner Module Direct Memory Access Upgrade",
"PC Direct-Neural Interface",
"PC Direct-Neural Interface Optimization Submodule",
"NeuroFlux Governor",
"ECorp HVMind Implant",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "ECorp",
"playerReputation": 0,
},
},
@ -256,22 +116,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Enhanced Social Interaction Implant",
"Neuralstimulator",
"Nuoptimal Nootropic Injector Implant",
"Speech Enhancement",
"FocusWire",
"PC Direct-Neural Interface",
"ADR-V1 Pheromone Gene",
"ADR-V2 Pheromone Gene",
"NeuroFlux Governor",
"Neurotrainer III",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "Four Sigma",
"playerReputation": 0,
},
},
@ -279,30 +126,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Synthetic Heart",
"Synfibril Muscle",
"Nanofiber Weave",
"NEMEAN Subdermal Weave",
"Graphene Bone Lacings",
"Graphene Bionic Spine Upgrade",
"Graphene Bionic Legs Upgrade",
"Artificial Bio-neural Network Implant",
"Enhanced Myelin Sheathing",
"Embedded Netburner Module",
"Embedded Netburner Module Core Implant",
"Embedded Netburner Module Core V2 Upgrade",
"Embedded Netburner Module Core V3 Upgrade",
"Embedded Netburner Module Analyze Engine",
"Embedded Netburner Module Direct Memory Access Upgrade",
"PC Direct-Neural Interface Optimization Submodule",
"PC Direct-Neural Interface NeuroNet Injector",
"NeuroFlux Governor",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "Fulcrum Secret Technologies",
"playerReputation": 0,
},
},
@ -310,20 +136,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Synthetic Heart",
"Synfibril Muscle",
"NEMEAN Subdermal Weave",
"Embedded Netburner Module Core V3 Upgrade",
"Embedded Netburner Module Analyze Engine",
"Embedded Netburner Module Direct Memory Access Upgrade",
"NeuroFlux Governor",
"QLink",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "Illuminati",
"playerReputation": 0,
},
},
@ -331,19 +146,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Augmented Targeting I",
"Combat Rib I",
"Wired Reflexes",
"Speech Processor Implant",
"Neuralstimulator",
"NeuroFlux Governor",
"INFRARET Enhancement",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "Ishima",
"playerReputation": 0,
},
},
@ -351,28 +156,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Augmented Targeting I",
"Augmented Targeting II",
"Augmented Targeting III",
"Synthetic Heart",
"Synfibril Muscle",
"Combat Rib I",
"Combat Rib II",
"Combat Rib III",
"Bionic Spine",
"Bionic Legs",
"Embedded Netburner Module Core V2 Upgrade",
"Speech Enhancement",
"FocusWire",
"NeuroFlux Governor",
"HyperSight Corneal Implant",
"Photosynthetic Cells",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "KuaiGong International",
"playerReputation": 0,
},
},
@ -380,22 +166,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Graphene Bionic Legs Upgrade",
"Embedded Netburner Module",
"Embedded Netburner Module Core Implant",
"Embedded Netburner Module Core V2 Upgrade",
"Embedded Netburner Module Core V3 Upgrade",
"Embedded Netburner Module Analyze Engine",
"Embedded Netburner Module Direct Memory Access Upgrade",
"ADR-V1 Pheromone Gene",
"NeuroFlux Governor",
"CordiARC Fusion Reactor",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "MegaCorp",
"playerReputation": 0,
},
},
@ -403,27 +176,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Synthetic Heart",
"Synfibril Muscle",
"Enhanced Social Interaction Implant",
"Embedded Netburner Module",
"Embedded Netburner Module Core Implant",
"Embedded Netburner Module Core V2 Upgrade",
"Embedded Netburner Module Core V3 Upgrade",
"Embedded Netburner Module Analyze Engine",
"Embedded Netburner Module Direct Memory Access Upgrade",
"ADR-V1 Pheromone Gene",
"NeuroFlux Governor",
"Neurotrainer III",
"Power Recirculation Core",
"Xanipher",
"Hydroflame Left Arm",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "NWO",
"playerReputation": 0,
},
},
@ -431,18 +186,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Hacknet Node CPU Architecture Neural-Upload",
"Hacknet Node Cache Architecture Neural-Upload",
"Hacknet Node NIC Architecture Neural-Upload",
"Hacknet Node Kernel Direct-Neural Interface",
"Hacknet Node Core Direct-Neural Interface",
"NeuroFlux Governor",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "Netburners",
"playerReputation": 0,
},
},
@ -450,18 +196,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Speech Processor Implant",
"DataJack",
"Neuralstimulator",
"Nuoptimal Nootropic Injector Implant",
"NeuroFlux Governor",
"NutriGen Implant",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "New Tokyo",
"playerReputation": 0,
},
},
@ -469,23 +206,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"BitWire",
"Artificial Synaptic Potentiation",
"Neural-Retention Enhancement",
"DataJack",
"Embedded Netburner Module",
"Cranial Signal Processors - Gen I",
"Cranial Signal Processors - Gen II",
"Cranial Signal Processors - Gen III",
"NeuroFlux Governor",
"Neurotrainer II",
"CRTX42-AA Gene Modification",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "NiteSec",
"playerReputation": 0,
},
},
@ -493,26 +216,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Augmented Targeting I",
"Augmented Targeting II",
"Augmented Targeting III",
"Combat Rib I",
"Combat Rib II",
"Combat Rib III",
"Nanofiber Weave",
"Bionic Spine",
"Bionic Legs",
"Enhanced Social Interaction Implant",
"Embedded Netburner Module Core V2 Upgrade",
"PC Direct-Neural Interface",
"NeuroFlux Governor",
"OmniTek InfoLoad",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "OmniTek Incorporated",
"playerReputation": 0,
},
},
@ -520,19 +226,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Augmented Targeting I",
"Augmented Targeting II",
"Wired Reflexes",
"Speech Processor Implant",
"Neuralstimulator",
"NeuroFlux Governor",
"CashRoot Starter Kit",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "Sector-12",
"playerReputation": 0,
},
},
@ -540,21 +236,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"SoA - Might of Ares",
"SoA - Wisdom of Athena",
"SoA - Trickery of Hermes",
"SoA - Beauty of Aphrodite",
"SoA - Chaos of Dionysus",
"SoA - Flood of Poseidon",
"SoA - Hunt of Artemis",
"SoA - Knowledge of Apollo",
"SoA - phyzical WKS harmonizer",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "Shadows of Anarchy",
"playerReputation": 0,
},
},
@ -562,16 +246,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Speech Processor Implant",
"TITN-41 Gene-Modification Injection",
"ADR-V2 Pheromone Gene",
"NeuroFlux Governor",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "Silhouette",
"playerReputation": 0,
},
},
@ -579,19 +256,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Augmented Targeting I",
"Combat Rib I",
"Wired Reflexes",
"NeuroFlux Governor",
"LuminCloaking-V1 Skin Implant",
"LuminCloaking-V2 Skin Implant",
"SmartSonar Implant",
],
"favor": 0,
"isBanned": false,
"isMember": true,
"name": "Slum Snakes",
"playerReputation": 0,
},
},
@ -599,23 +266,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Synthetic Heart",
"Synfibril Muscle",
"Nanofiber Weave",
"Wired Reflexes",
"Bionic Spine",
"Bionic Legs",
"Speech Enhancement",
"The Shadow's Simulacrum",
"NeuroFlux Governor",
"Unstable Circadian Modulator",
"Graphene BrachiBlades Upgrade",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "Speakers for the Dead",
"playerReputation": 0,
},
},
@ -623,18 +276,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"NeuroFlux Governor",
"LuminCloaking-V1 Skin Implant",
"LuminCloaking-V2 Skin Implant",
"HemoRecirculator",
"Power Recirculation Core",
"Bionic Arms",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "Tetrads",
"playerReputation": 0,
},
},
@ -642,22 +286,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Artificial Synaptic Potentiation",
"Enhanced Myelin Sheathing",
"DataJack",
"Embedded Netburner Module",
"Embedded Netburner Module Core Implant",
"Neuralstimulator",
"Cranial Signal Processors - Gen III",
"Cranial Signal Processors - Gen IV",
"NeuroFlux Governor",
"The Black Hand",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "The Black Hand",
"playerReputation": 0,
},
},
@ -665,23 +296,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Augmented Targeting III",
"Synthetic Heart",
"Synfibril Muscle",
"Combat Rib III",
"NEMEAN Subdermal Weave",
"Graphene Bone Lacings",
"Embedded Netburner Module Core V3 Upgrade",
"Embedded Netburner Module Analyze Engine",
"Embedded Netburner Module Direct Memory Access Upgrade",
"NeuroFlux Governor",
"SPTN-97 Gene Modification",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "The Covenant",
"playerReputation": 0,
},
},
@ -689,25 +306,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Augmented Targeting I",
"Augmented Targeting II",
"Augmented Targeting III",
"Combat Rib I",
"Combat Rib II",
"Combat Rib III",
"Nanofiber Weave",
"Wired Reflexes",
"The Shadow's Simulacrum",
"NeuroFlux Governor",
"HemoRecirculator",
"Power Recirculation Core",
"Graphene Bionic Arms Upgrade",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "The Dark Army",
"playerReputation": 0,
},
},
@ -715,29 +316,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Augmented Targeting I",
"Augmented Targeting II",
"Augmented Targeting III",
"Combat Rib I",
"Combat Rib II",
"Combat Rib III",
"Nanofiber Weave",
"NEMEAN Subdermal Weave",
"Wired Reflexes",
"Bionic Spine",
"Bionic Legs",
"ADR-V1 Pheromone Gene",
"The Shadow's Simulacrum",
"NeuroFlux Governor",
"HemoRecirculator",
"Power Recirculation Core",
"BrachiBlades",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "The Syndicate",
"playerReputation": 0,
},
},
@ -745,21 +326,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Nanofiber Weave",
"Wired Reflexes",
"Speech Processor Implant",
"Neuroreceptor Management Implant",
"Nuoptimal Nootropic Injector Implant",
"Speech Enhancement",
"ADR-V1 Pheromone Gene",
"NeuroFlux Governor",
"Social Negotiation Assistant (S.N.A)",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "Tian Di Hui",
"playerReputation": 0,
},
},
@ -767,20 +336,9 @@ exports[`Check Save File Continuity FactionsSave continuity 1`] = `
"ctor": "Faction",
"data": {
"alreadyInvited": false,
"augmentations": [
"Combat Rib I",
"Combat Rib II",
"Wired Reflexes",
"Speech Processor Implant",
"Neuralstimulator",
"Nuoptimal Nootropic Injector Implant",
"NeuroFlux Governor",
"DermaForce Particle Barrier",
],
"favor": 0,
"isBanned": false,
"isMember": false,
"name": "Volhaven",
"playerReputation": 0,
},
},