TYPESAFETY: Strict internal typing for AugmentationName (#608)

This commit is contained in:
Snarling
2023-06-16 17:52:42 -04:00
committed by GitHub
parent 12b5c00d14
commit a4b826683e
70 changed files with 2649 additions and 3221 deletions
+8 -2
View File
@@ -1,6 +1,8 @@
import type { AugmentationName } 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";
export class Faction {
/**
@@ -10,7 +12,7 @@ export class Faction {
alreadyInvited = false;
/** Holds names of all augmentations that this Faction offers */
augmentations: string[] = [];
augmentations: AugmentationName[] = [];
/** Amount of favor the player has with this faction. */
favor = 0;
@@ -67,7 +69,11 @@ export class Faction {
/** Initializes a Faction object from a JSON save state. */
static fromJSON(value: IReviverValue): Faction {
return Generic_fromJSON(Faction, value.data);
const faction = Generic_fromJSON(Faction, value.data);
// 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));
return faction;
}
}
+9 -8
View File
@@ -1,8 +1,8 @@
import { StaticAugmentations } from "../Augmentation/StaticAugmentations";
import { Augmentations } from "../Augmentation/Augmentations";
import { Augmentation } from "../Augmentation/Augmentation";
import { PlayerOwnedAugmentation } from "../Augmentation/PlayerOwnedAugmentation";
import { AugmentationName, FactionName } from "@enums";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { currentNodeMults } from "../BitNode/BitNodeMultipliers";
import { Faction } from "./Faction";
import { Factions } from "./Factions";
@@ -18,6 +18,7 @@ import { dialogBoxCreate } from "../ui/React/DialogBox";
import { InvitationEvent } from "./ui/InvitationModal";
import { SFC32RNG } from "../Casino/RNG";
import { isFactionWork } from "../Work/FactionWork";
import { getAugCost } from "../Augmentation/AugmentationHelpers";
export function inviteToFaction(faction: Faction): void {
Player.receiveInvite(faction.name);
@@ -55,7 +56,7 @@ export function hasAugmentationPrereqs(aug: Augmentation): boolean {
export function purchaseAugmentation(aug: Augmentation, fac: Faction, sing = false): string {
const hasPrereqs = hasAugmentationPrereqs(aug);
const augCosts = aug.getCost();
const augCosts = getAugCost(aug);
if (!hasPrereqs) {
const txt = `You must first purchase or install ${aug.prereqs
.filter((req) => !Player.hasAugmentation(req))
@@ -127,21 +128,21 @@ export function processPassiveFactionRepGain(numCycles: number): void {
const fRep = getFactionFieldWorkRepGain(Player, faction.favor);
const rate = Math.max(hRep * favorMult, sRep * favorMult, fRep * favorMult, 1 / 120);
faction.playerReputation += rate * numCycles * Player.mults.faction_rep * BitNodeMultipliers.FactionPassiveRepGain;
faction.playerReputation += rate * numCycles * Player.mults.faction_rep * currentNodeMults.FactionPassiveRepGain;
}
}
export const getFactionAugmentationsFiltered = (faction: Faction): string[] => {
export const getFactionAugmentationsFiltered = (faction: Faction): AugmentationName[] => {
// If player has a gang with this faction, return (almost) all augmentations
if (Player.hasGangWith(faction.name)) {
let augs = Object.values(StaticAugmentations);
let augs = Object.values(Augmentations);
// Remove special augs
augs = augs.filter((a) => !a.isSpecial && a.name !== AugmentationName.CongruityImplant);
if (Player.bitNodeN === 2) {
// TRP is not available outside of BN2 for Gangs
augs.push(StaticAugmentations[AugmentationName.TheRedPill]);
augs.push(Augmentations[AugmentationName.TheRedPill]);
}
const rng = SFC32RNG(`BN${Player.bitNodeN}.${Player.sourceFileLvl(Player.bitNodeN)}`);
@@ -156,7 +157,7 @@ export const getFactionAugmentationsFiltered = (faction: Faction): string[] => {
return true;
}
return rng() >= 1 - BitNodeMultipliers.GangUniqueAugs;
return rng() >= 1 - currentNodeMults.GangUniqueAugs;
};
augs = augs.filter(uniqueFilter);
+14
View File
@@ -6,6 +6,8 @@ import { Faction } from "./Faction";
import { FactionInfos } from "./FactionInfo";
import { Reviver } from "../utils/JSONReviver";
import { getRecordValues } from "../Types/Record";
import { Augmentations, initCircadianModulator } from "../Augmentation/Augmentations";
export let Factions: Record<string, Faction> = {};
@@ -47,4 +49,16 @@ function resetFaction(newFactionObject: Faction): void {
delete Factions[factionName];
}
AddToFactions(newFactionObject);
// 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);
}
}
}
+2 -2
View File
@@ -1,7 +1,7 @@
import { CONSTANTS } from "../../Constants";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { currentNodeMults } from "../../BitNode/BitNodeMultipliers";
import { Person as IPerson } from "@nsdefs";
export function repFromDonation(amt: number, person: IPerson): number {
return (amt / CONSTANTS.DonateMoneyToRepDivisor) * person.mults.faction_rep * BitNodeMultipliers.FactionWorkRepGain;
return (amt / CONSTANTS.DonateMoneyToRepDivisor) * person.mults.faction_rep * currentNodeMults.FactionWorkRepGain;
}
+25 -25
View File
@@ -1,8 +1,8 @@
import { Box, Button, Tooltip, Typography, Paper, Container } from "@mui/material";
import React from "react";
import { StaticAugmentations } from "../../Augmentation/StaticAugmentations";
import { getGenericAugmentationPriceMultiplier } from "../../Augmentation/AugmentationHelpers";
import { Augmentations } from "../../Augmentation/Augmentations";
import { getAugCost, getGenericAugmentationPriceMultiplier } from "../../Augmentation/AugmentationHelpers";
import { AugmentationName, FactionName } from "@enums";
import { PurchasableAugmentations } from "../../Augmentation/ui/PurchasableAugmentations";
import { PurchaseAugmentationsOrderSetting } from "../../Settings/SettingEnums";
@@ -25,11 +25,11 @@ interface IProps {
export function AugmentationsPage(props: IProps): React.ReactElement {
const rerender = useRerender();
function getAugs(): string[] {
function getAugs(): AugmentationName[] {
return getFactionAugmentationsFiltered(props.faction);
}
function getAugsSorted(): string[] {
function getAugsSorted(): AugmentationName[] {
switch (Settings.PurchaseAugmentationsOrder) {
case PurchaseAugmentationsOrderSetting.Cost: {
return getAugsSortedByCost();
@@ -45,26 +45,26 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
}
}
function getAugsSortedByCost(): string[] {
function getAugsSortedByCost(): AugmentationName[] {
const augs = getAugs();
augs.sort((augName1, augName2) => {
const aug1 = StaticAugmentations[augName1],
aug2 = StaticAugmentations[augName2];
const aug1 = Augmentations[augName1],
aug2 = Augmentations[augName2];
if (aug1 == null || aug2 == null) {
throw new Error("Invalid Augmentation Names");
}
return aug1.getCost().moneyCost - aug2.getCost().moneyCost;
return getAugCost(aug1).moneyCost - getAugCost(aug2).moneyCost;
});
return augs;
}
function getAugsSortedByPurchasable(): string[] {
function getAugsSortedByPurchasable(): AugmentationName[] {
const augs = getAugs();
function canBuy(augName: string): boolean {
const aug = StaticAugmentations[augName];
const augCosts = aug.getCost();
function canBuy(augName: AugmentationName): boolean {
const aug = Augmentations[augName];
const augCosts = getAugCost(aug);
const repCost = augCosts.repCost;
const hasReq = props.faction.playerReputation >= repCost;
const hasRep = hasAugmentationPrereqs(aug);
@@ -72,43 +72,43 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
return hasCost && hasReq && hasRep;
}
const buy = augs.filter(canBuy).sort((augName1, augName2) => {
const aug1 = StaticAugmentations[augName1],
aug2 = StaticAugmentations[augName2];
const aug1 = Augmentations[augName1],
aug2 = Augmentations[augName2];
if (aug1 == null || aug2 == null) {
throw new Error("Invalid Augmentation Names");
}
return aug1.getCost().moneyCost - aug2.getCost().moneyCost;
return getAugCost(aug1).moneyCost - getAugCost(aug2).moneyCost;
});
const cantBuy = augs
.filter((aug) => !canBuy(aug))
.sort((augName1, augName2) => {
const aug1 = StaticAugmentations[augName1],
aug2 = StaticAugmentations[augName2];
const aug1 = Augmentations[augName1],
aug2 = Augmentations[augName2];
if (aug1 == null || aug2 == null) {
throw new Error("Invalid Augmentation Names");
}
return aug1.getCost().repCost - aug2.getCost().repCost;
return getAugCost(aug1).repCost - getAugCost(aug2).repCost;
});
return buy.concat(cantBuy);
}
function getAugsSortedByReputation(): string[] {
function getAugsSortedByReputation(): AugmentationName[] {
const augs = getAugs();
augs.sort((augName1, augName2) => {
const aug1 = StaticAugmentations[augName1],
aug2 = StaticAugmentations[augName2];
const aug1 = Augmentations[augName1],
aug2 = Augmentations[augName2];
if (aug1 == null || aug2 == null) {
throw new Error("Invalid Augmentation Names");
}
return aug1.getCost().repCost - aug2.getCost().repCost;
return getAugCost(aug1).repCost - getAugCost(aug2).repCost;
});
return augs;
}
function getAugsSortedByDefault(): string[] {
function getAugsSortedByDefault(): AugmentationName[] {
return getAugs();
}
@@ -123,7 +123,7 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
aug === AugmentationName.NeuroFluxGovernor ||
(!Player.augmentations.some((a) => a.name === aug) && !Player.queuedAugmentations.some((a) => a.name === aug)),
);
const owned = augs.filter((aug: string) => !purchasable.includes(aug));
const owned = augs.filter((aug) => !purchasable.includes(aug));
const multiplierComponent =
props.faction.name !== FactionName.ShadowsOfAnarchy ? (
@@ -213,7 +213,7 @@ export function AugmentationsPage(props: IProps): React.ReactElement {
augNames={purchasable}
ownedAugNames={owned}
canPurchase={(aug) => {
const costs = aug.getCost();
const costs = getAugCost(aug);
return (
hasAugmentationPrereqs(aug) &&
props.faction.playerReputation >= costs.repCost &&
+2 -2
View File
@@ -12,7 +12,7 @@ import { Option } from "./Option";
import { CONSTANTS } from "../../Constants";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { currentNodeMults } from "../../BitNode/BitNodeMultipliers";
import { Faction } from "../Faction";
import { Router } from "../../ui/GameRoot";
@@ -107,7 +107,7 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
// Flags for whether special options (gang, sleeve purchases, donate, etc.)
// should be shown
const favorToDonate = Math.floor(CONSTANTS.BaseFavorToDonate * BitNodeMultipliers.RepToDonateToFaction);
const favorToDonate = Math.floor(CONSTANTS.BaseFavorToDonate * currentNodeMults.RepToDonateToFaction);
const canDonate = faction.favor >= favorToDonate;
const canPurchaseSleeves = faction.name === FactionName.TheCovenant && Player.bitNodeN === 10;