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
@@ -1,14 +1,16 @@
import { StaticAugmentations } from "../../Augmentation/StaticAugmentations";
import { GraftableAugmentation } from "./GraftableAugmentation";
import { Player } from "@player";
import { AugmentationName, FactionName } from "@enums";
import { Augmentations } from "../../Augmentation/Augmentations";
import { calculateIntelligenceBonus } from "../formulas/intelligence";
import { GraftableAugmentation } from "./GraftableAugmentation";
import { getRecordEntries } from "../../Types/Record";
export const getGraftingAvailableAugs = (): string[] => {
const augs: string[] = [];
export const getGraftingAvailableAugs = (): AugmentationName[] => {
const augs: AugmentationName[] = [];
for (const [augName, aug] of Object.entries(StaticAugmentations)) {
if (Player.factions.includes("Bladeburners")) {
if (aug.isSpecial && !aug.factions.includes("Bladeburners")) continue;
for (const [augName, aug] of getRecordEntries(Augmentations)) {
if (Player.factions.includes(FactionName.Bladeburners)) {
if (aug.isSpecial && !aug.factions.includes(FactionName.Bladeburners)) continue;
} else {
if (aug.isSpecial) continue;
}
@@ -1,13 +1,14 @@
import type { Augmentation } from "../../../Augmentation/Augmentation";
import { Player } from "@player";
import { AugmentationName, LocationName } from "@enums";
import React, { useState } from "react";
import { CheckBox, CheckBoxOutlineBlank, Construction } from "@mui/icons-material";
import { Box, Button, Container, List, ListItemButton, Paper, Typography } from "@mui/material";
import { Player } from "@player";
import { AugmentationName, LocationName } from "@enums";
import { GraftingWork } from "../../../Work/GraftingWork";
import { StaticAugmentations } from "../../../Augmentation/StaticAugmentations";
import { Augmentations } from "../../../Augmentation/Augmentations";
import { CONSTANTS } from "../../../Constants";
import { hasAugmentationPrereqs } from "../../../Faction/FactionHelpers";
import { Locations } from "../../../Locations/Locations";
@@ -25,7 +26,7 @@ import { useRerender } from "../../../ui/React/hooks";
export const GraftableAugmentations = (): Record<string, GraftableAugmentation> => {
const gAugs: Record<string, GraftableAugmentation> = {};
for (const aug of Object.values(StaticAugmentations)) {
for (const aug of Object.values(Augmentations)) {
const name = aug.name;
const graftableAug = new GraftableAugmentation(aug);
gAugs[name] = graftableAug;
@@ -66,10 +67,10 @@ export const GraftingRoot = (): React.ReactElement => {
const [selectedAug, setSelectedAug] = useState(getGraftingAvailableAugs()[0]);
const [graftOpen, setGraftOpen] = useState(false);
const selectedAugmentation = StaticAugmentations[selectedAug];
const selectedAugmentation = Augmentations[selectedAug];
const rerender = useRerender(200);
const getAugsSorted = (): string[] => {
const getAugsSorted = (): AugmentationName[] => {
const augs = getGraftingAvailableAugs();
switch (Settings.PurchaseAugmentationsOrder) {
case PurchaseAugmentationsOrderSetting.Cost:
+13 -26
View File
@@ -1,6 +1,6 @@
import { Person } from "./Person";
import { calculateSkill } from "./formulas/skill";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { currentNodeMults } from "../BitNode/BitNodeMultipliers";
import { Player } from "@player";
import { WorkStats } from "@nsdefs";
@@ -14,10 +14,7 @@ export function gainHackingExp(this: Person, exp: number): void {
this.exp.hacking = 0;
}
this.skills.hacking = calculateSkill(
this.exp.hacking,
this.mults.hacking * BitNodeMultipliers.HackingLevelMultiplier,
);
this.skills.hacking = calculateSkill(this.exp.hacking, this.mults.hacking * currentNodeMults.HackingLevelMultiplier);
}
export function gainStrengthExp(this: Person, exp: number): void {
@@ -32,7 +29,7 @@ export function gainStrengthExp(this: Person, exp: number): void {
this.skills.strength = calculateSkill(
this.exp.strength,
this.mults.strength * BitNodeMultipliers.StrengthLevelMultiplier,
this.mults.strength * currentNodeMults.StrengthLevelMultiplier,
);
}
@@ -46,10 +43,7 @@ export function gainDefenseExp(this: Person, exp: number): void {
this.exp.defense = 0;
}
this.skills.defense = calculateSkill(
this.exp.defense,
this.mults.defense * BitNodeMultipliers.DefenseLevelMultiplier,
);
this.skills.defense = calculateSkill(this.exp.defense, this.mults.defense * currentNodeMults.DefenseLevelMultiplier);
const ratio = this.hp.current / this.hp.max;
this.hp.max = Math.floor(10 + this.skills.defense / 10);
this.hp.current = Math.round(this.hp.max * ratio);
@@ -67,7 +61,7 @@ export function gainDexterityExp(this: Person, exp: number): void {
this.skills.dexterity = calculateSkill(
this.exp.dexterity,
this.mults.dexterity * BitNodeMultipliers.DexterityLevelMultiplier,
this.mults.dexterity * currentNodeMults.DexterityLevelMultiplier,
);
}
@@ -81,10 +75,7 @@ export function gainAgilityExp(this: Person, exp: number): void {
this.exp.agility = 0;
}
this.skills.agility = calculateSkill(
this.exp.agility,
this.mults.agility * BitNodeMultipliers.AgilityLevelMultiplier,
);
this.skills.agility = calculateSkill(this.exp.agility, this.mults.agility * currentNodeMults.AgilityLevelMultiplier);
}
export function gainCharismaExp(this: Person, exp: number): void {
@@ -99,7 +90,7 @@ export function gainCharismaExp(this: Person, exp: number): void {
this.skills.charisma = calculateSkill(
this.exp.charisma,
this.mults.charisma * BitNodeMultipliers.CharismaLevelMultiplier,
this.mults.charisma * currentNodeMults.CharismaLevelMultiplier,
);
}
@@ -164,33 +155,29 @@ export function regenerateHp(this: Person, amt: number): void {
export function updateSkillLevels(this: Person): void {
this.skills.hacking = Math.max(
1,
Math.floor(this.calculateSkill(this.exp.hacking, this.mults.hacking * BitNodeMultipliers.HackingLevelMultiplier)),
Math.floor(this.calculateSkill(this.exp.hacking, this.mults.hacking * currentNodeMults.HackingLevelMultiplier)),
);
this.skills.strength = Math.max(
1,
Math.floor(
this.calculateSkill(this.exp.strength, this.mults.strength * BitNodeMultipliers.StrengthLevelMultiplier),
),
Math.floor(this.calculateSkill(this.exp.strength, this.mults.strength * currentNodeMults.StrengthLevelMultiplier)),
);
this.skills.defense = Math.max(
1,
Math.floor(this.calculateSkill(this.exp.defense, this.mults.defense * BitNodeMultipliers.DefenseLevelMultiplier)),
Math.floor(this.calculateSkill(this.exp.defense, this.mults.defense * currentNodeMults.DefenseLevelMultiplier)),
);
this.skills.dexterity = Math.max(
1,
Math.floor(
this.calculateSkill(this.exp.dexterity, this.mults.dexterity * BitNodeMultipliers.DexterityLevelMultiplier),
this.calculateSkill(this.exp.dexterity, this.mults.dexterity * currentNodeMults.DexterityLevelMultiplier),
),
);
this.skills.agility = Math.max(
1,
Math.floor(this.calculateSkill(this.exp.agility, this.mults.agility * BitNodeMultipliers.AgilityLevelMultiplier)),
Math.floor(this.calculateSkill(this.exp.agility, this.mults.agility * currentNodeMults.AgilityLevelMultiplier)),
);
this.skills.charisma = Math.max(
1,
Math.floor(
this.calculateSkill(this.exp.charisma, this.mults.charisma * BitNodeMultipliers.CharismaLevelMultiplier),
),
Math.floor(this.calculateSkill(this.exp.charisma, this.mults.charisma * currentNodeMults.CharismaLevelMultiplier)),
);
const ratio: number = Math.min(this.hp.current / this.hp.max, 1);
+11
View File
@@ -26,6 +26,7 @@ import { cyrb53 } from "../../utils/StringHelperFunctions";
import { getRandomInt } from "../../utils/helpers/getRandomInt";
import { CONSTANTS } from "../../Constants";
import { Person } from "../Person";
import { getEnumHelper } from "../../utils/EnumHelper";
export class PlayerObject extends Person implements IPlayer {
// Player-specific properties
@@ -167,9 +168,19 @@ export class PlayerObject extends Person implements IPlayer {
/** Initializes a PlayerObject object from a JSON save state. */
static fromJSON(value: IReviverValue): PlayerObject {
const player = Generic_fromJSON(PlayerObject, value.data);
// Any statistics that could be infinite would be serialized as null (JSON.stringify(Infinity) is "null")
player.hp = { current: player.hp?.current ?? 10, max: player.hp?.max ?? 10 };
player.money ??= 0;
// Just remove from the save file any augs that have invalid name
player.augmentations = player.augmentations.filter((ownedAug) =>
getEnumHelper("AugmentationName").isMember(ownedAug.name),
);
player.queuedAugmentations = player.queuedAugmentations.filter((ownedAug) =>
getEnumHelper("AugmentationName").isMember(ownedAug.name),
);
player.updateSkillLevels();
// Converstion code for Player.sourceFiles is here instead of normal save conversion area because it needs
// to happen earlier for use in the savegame comparison tool.
if (Array.isArray(player.sourceFiles)) {
// Expect pre-2.3 sourcefile format here.
type OldSourceFiles = { n: number; lvl: number }[];
@@ -1,10 +1,11 @@
import { AugmentationName, CityName, CompletedProgramName, FactionName, LocationName, ToastVariant } from "@enums";
import type { PlayerObject } from "./PlayerObject";
import type { ProgramFilePath } from "../../Paths/ProgramFilePath";
import { applyAugmentation } from "../../Augmentation/AugmentationHelpers";
import { PlayerOwnedAugmentation } from "../../Augmentation/PlayerOwnedAugmentation";
import { AugmentationName, CityName, CompletedProgramName, FactionName, LocationName, ToastVariant } from "@enums";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { currentNodeMults } from "../../BitNode/BitNodeMultipliers";
import { CodingContractRewardType, ICodingContractReward } from "../../CodingContracts";
import { Company } from "../../Company/Company";
import { Companies } from "../../Company/Companies";
@@ -548,22 +549,16 @@ export function reapplyAllAugmentations(this: PlayerObject, resetMultipliers = t
this.resetMultipliers();
}
for (let i = 0; i < this.augmentations.length; ++i) {
//Compatibility with new version
if (this.augmentations[i].name === "HacknetNode NIC Architecture Neural-Upload") {
this.augmentations[i].name = "Hacknet Node NIC Architecture Neural-Upload";
}
const playerAug = this.augmentations[i];
for (const playerAug of this.augmentations) {
const augName = playerAug.name;
if (augName == AugmentationName.NeuroFluxGovernor) {
for (let j = 0; j < playerAug.level; ++j) {
applyAugmentation(this.augmentations[i], true);
for (let i = 0; i < playerAug.level; ++i) {
applyAugmentation(playerAug, true);
}
continue;
}
applyAugmentation(this.augmentations[i], true);
applyAugmentation(playerAug, true);
}
this.updateSkillLevels();
@@ -644,7 +639,7 @@ export function checkForFactionInvitations(this: PlayerObject): Faction[] {
!daedalusFac.isBanned &&
!daedalusFac.isMember &&
!daedalusFac.alreadyInvited &&
numAugmentations >= BitNodeMultipliers.DaedalusAugsRequirement &&
numAugmentations >= currentNodeMults.DaedalusAugsRequirement &&
this.money >= 100000000000 &&
(this.skills.hacking >= 2500 ||
(this.skills.strength >= 1500 &&
@@ -1080,7 +1075,7 @@ export function setBitNodeNumber(this: PlayerObject, n: number): void {
this.bitNodeN = n;
}
export function queueAugmentation(this: PlayerObject, name: string): void {
export function queueAugmentation(this: PlayerObject, name: AugmentationName): void {
for (const aug of this.queuedAugmentations) {
if (aug.name == name) {
console.warn(`tried to queue ${name} twice, this may be a bug`);
@@ -1152,7 +1147,7 @@ export function gainCodingContractReward(
}
case CodingContractRewardType.Money:
default: {
const moneyGain = CONSTANTS.CodingContractBaseMoneyGain * difficulty * BitNodeMultipliers.CodingContractMoney;
const moneyGain = CONSTANTS.CodingContractBaseMoneyGain * difficulty * currentNodeMults.CodingContractMoney;
this.gainMoney(moneyGain, "codingcontract");
return `Gained ${formatMoney(moneyGain)}`;
}
@@ -1,7 +1,7 @@
// Server and HacknetServer-related methods for the Player class (PlayerObject)
import { CONSTANTS } from "../../Constants";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { currentNodeMults } from "../../BitNode/BitNodeMultipliers";
import { Server } from "../../Server/Server";
import { BaseServer } from "../../Server/BaseServer";
import { HacknetServer } from "../../Hacknet/HacknetServer";
@@ -35,7 +35,7 @@ export function getUpgradeHomeRamCost(this: PlayerObject): number {
//Calculate cost
//Have cost increase by some percentage each time RAM has been upgraded
const mult = Math.pow(1.58, numUpgrades);
const cost = currentRam * CONSTANTS.BaseCostFor1GBOfRamHome * mult * BitNodeMultipliers.HomeComputerRamCost;
const cost = currentRam * CONSTANTS.BaseCostFor1GBOfRamHome * mult * currentNodeMults.HomeComputerRamCost;
return cost;
}
+18 -8
View File
@@ -7,14 +7,16 @@
* Sleeves are unlocked in BitNode-10.
*/
import type { SleevePerson } from "@nsdefs";
import type { Augmentation } from "../../Augmentation/Augmentation";
import type { Company } from "../../Company/Company";
import type { CompanyPosition } from "../../Company/CompanyPosition";
import type { SleeveWork } from "./Work/Work";
import { Player } from "@player";
import { Person } from "../Person";
import { Augmentation } from "../../Augmentation/Augmentation";
import { Companies } from "../../Company/Companies";
import { Company } from "../../Company/Company";
import { CompanyPosition } from "../../Company/CompanyPosition";
import { CompanyPositions } from "../../Company/CompanyPositions";
import { Contracts } from "../../Bladeburner/data/Contracts";
import { CONSTANTS } from "../../Constants";
@@ -24,7 +26,6 @@ import { Factions } from "../../Faction/Factions";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../../utils/JSONReviver";
import { formatPercent } from "../../ui/formatNumber";
import { SleeveWork } from "./Work/Work";
import { SleeveClassWork } from "./Work/SleeveClassWork";
import { SleeveSynchroWork } from "./Work/SleeveSynchroWork";
import { SleeveRecoveryWork } from "./Work/SleeveRecoveryWork";
@@ -35,8 +36,8 @@ import { SleeveSupportWork } from "./Work/SleeveSupportWork";
import { SleeveBladeburnerWork } from "./Work/SleeveBladeburnerWork";
import { SleeveCrimeWork } from "./Work/SleeveCrimeWork";
import * as sleeveMethods from "./SleeveMethods";
import { SleevePerson } from "@nsdefs";
import { calculateIntelligenceBonus } from "../formulas/intelligence";
import { getEnumHelper } from "../../utils/EnumHelper";
export class Sleeve extends Person implements SleevePerson {
currentWork: SleeveWork | null = null;
@@ -475,8 +476,17 @@ export class Sleeve extends Person implements SleevePerson {
/** Initializes a Sleeve object from a JSON save state. */
static fromJSON(value: IReviverValue): Sleeve {
if (!value.data.hp?.current || !value.data.hp?.max) value.data.hp = { current: 10, max: 10 };
return Generic_fromJSON(Sleeve, value.data);
const sleeve = Generic_fromJSON(Sleeve, value.data);
if (!sleeve.hp?.current || !sleeve.hp?.max) sleeve.hp = { current: 10, max: 10 };
// Remove any invalid aug names on game load
sleeve.augmentations = sleeve.augmentations.filter((ownedAug) =>
getEnumHelper("AugmentationName").isMember(ownedAug.name),
);
sleeve.queuedAugmentations = sleeve.queuedAugmentations.filter((ownedAug) =>
getEnumHelper("AugmentationName").isMember(ownedAug.name),
);
return sleeve;
}
}
+7 -6
View File
@@ -2,10 +2,11 @@ import { Player } from "@player";
import { AugmentationName, FactionName } from "@enums";
import { Sleeve } from "./Sleeve";
import { Augmentation } from "../../Augmentation/Augmentation";
import { StaticAugmentations } from "../../Augmentation/StaticAugmentations";
import { Augmentations } from "../../Augmentation/Augmentations";
import { Factions } from "../../Faction/Factions";
import { mergeMultipliers, Multipliers } from "../Multipliers";
import { getFactionAugmentationsFiltered } from "../../Faction/FactionHelpers";
import { getAugCost } from "../../Augmentation/AugmentationHelpers";
/** Updates this object's multipliers for the given augmentation */
export function applyAugmentation(this: Sleeve, aug: Augmentation): void {
@@ -61,10 +62,10 @@ export function findPurchasableAugs(this: Sleeve): Augmentation[] {
const gangAugs = getFactionAugmentationsFiltered(fac);
for (const augName of gangAugs) {
const aug = StaticAugmentations[augName];
const aug = Augmentations[augName];
if (!isAvailableForSleeve(aug)) continue;
if (fac.playerReputation > aug.getCost().repCost) {
if (fac.playerReputation > getAugCost(aug).repCost) {
availableAugs.push(aug);
}
}
@@ -77,10 +78,10 @@ export function findPurchasableAugs(this: Sleeve): Augmentation[] {
if (!fac) continue;
for (const augName of fac.augmentations) {
const aug = StaticAugmentations[augName];
const aug = Augmentations[augName];
if (!isAvailableForSleeve(aug)) continue;
if (fac.playerReputation > aug.getCost().repCost) {
if (fac.playerReputation > getAugCost(aug).repCost) {
availableAugs.push(aug);
}
}
@@ -88,7 +89,7 @@ export function findPurchasableAugs(this: Sleeve): Augmentation[] {
// Add the stanek sleeve aug
if (!ownedAugNames.includes(AugmentationName.ZOE) && Player.factions.includes(FactionName.ChurchOfTheMachineGod)) {
const aug = StaticAugmentations[AugmentationName.ZOE];
const aug = Augmentations[AugmentationName.ZOE];
availableAugs.push(aug);
}
+2 -2
View File
@@ -1,5 +1,5 @@
import { CONSTANTS } from "../../Constants";
import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers";
import { currentNodeMults } from "../../BitNode/BitNodeMultipliers";
import { CalculateShareMult } from "../../NetworkShare/Share";
import { Person as IPerson } from "@nsdefs";
import { calculateIntelligenceBonus } from "./intelligence";
@@ -9,7 +9,7 @@ function mult(favor: number): number {
if (isNaN(favorMult)) {
favorMult = 1;
}
return favorMult * BitNodeMultipliers.FactionWorkRepGain;
return favorMult * currentNodeMults.FactionWorkRepGain;
}
export function getHackingWorkRepGain(p: IPerson, favor: number): number {