MISC: A bunch of enums stuff. (#212)

* Some game enums moved to utils/enums. Others can eventually be moved there as well.
* findEnumMember function for performing fuzzy matching of player input with enum members, without needing separate fuzzy functions for every enum.
* Also used findEnumMember for safely loading save games (allows case changes in enum values)
* Changed capitalization on some enums.
* BREAKING: removed classGains work formulas function
* Split ClassType enum into UniversityClassType and GymType.
* Added universityGains and gymGains work formulas functions
* Provided the new split enums to the player on ns.enums.
This commit is contained in:
Snarling 2022-11-20 08:37:11 -05:00 committed by GitHub
parent 629d610532
commit 88d51e9a7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 346 additions and 432 deletions

@ -14,7 +14,7 @@ import { Cities } from "../Locations/Cities";
import { EmployeePositions } from "./EmployeePositions"; import { EmployeePositions } from "./EmployeePositions";
import { ResearchMap } from "./ResearchMap"; import { ResearchMap } from "./ResearchMap";
import { isRelevantMaterial } from "./ui/Helpers"; import { isRelevantMaterial } from "./ui/Helpers";
import { checkEnum } from "../utils/helpers/checkEnum"; import { checkEnum } from "../utils/helpers/enum";
import { CityName } from "../Locations/data/CityNames"; import { CityName } from "../Locations/data/CityNames";
export function NewIndustry(corporation: Corporation, industry: IndustryType, name: string): void { export function NewIndustry(corporation: Corporation, industry: IndustryType, name: string): void {

@ -2,7 +2,7 @@ import { CONSTANTS } from "../Constants";
import { Player } from "@player"; import { Player } from "@player";
import { Person as IPerson } from "../ScriptEditor/NetscriptDefinitions"; import { Person as IPerson } from "../ScriptEditor/NetscriptDefinitions";
import { WorkerScript } from "../Netscript/WorkerScript"; import { WorkerScript } from "../Netscript/WorkerScript";
import { CrimeType } from "../utils/WorkType"; import { CrimeType } from "../utils/enums";
import { CrimeWork } from "../Work/CrimeWork"; import { CrimeWork } from "../Work/CrimeWork";
import { calculateIntelligenceBonus } from "../PersonObjects/formulas/intelligence"; import { calculateIntelligenceBonus } from "../PersonObjects/formulas/intelligence";
@ -25,6 +25,9 @@ interface IConstructorParams {
} }
export class Crime { export class Crime {
// Corresponding type, also the name of the crime.
type: CrimeType;
// Number representing the difficulty of the crime. Used for success chance calculations // Number representing the difficulty of the crime. Used for success chance calculations
difficulty: number; difficulty: number;
@ -37,9 +40,6 @@ export class Crime {
// How much money is given by the // How much money is given by the
money: number; money: number;
// Name of crime
name: string;
// Name of crime as it appears on work screen: "You are attempting..." // Name of crime as it appears on work screen: "You are attempting..."
workName: string; workName: string;
@ -49,9 +49,6 @@ export class Crime {
// Milliseconds it takes to attempt the crime // Milliseconds it takes to attempt the crime
time = 0; time = 0;
// Corresponding type in CONSTANTS. Contains a description for the crime activity
type: CrimeType;
// Weighting factors that determine how stats affect the success rate of this crime // Weighting factors that determine how stats affect the success rate of this crime
hacking_success_weight = 0; hacking_success_weight = 0;
strength_success_weight = 0; strength_success_weight = 0;
@ -70,7 +67,6 @@ export class Crime {
intelligence_exp = 0; intelligence_exp = 0;
constructor( constructor(
name: string,
workName: string, workName: string,
tooltipText: string, tooltipText: string,
type: CrimeType, type: CrimeType,
@ -80,7 +76,6 @@ export class Crime {
karma: number, karma: number,
params: IConstructorParams, params: IConstructorParams,
) { ) {
this.name = name;
this.workName = workName; this.workName = workName;
this.tooltipText = tooltipText; this.tooltipText = tooltipText;
this.type = type; this.type = type;

@ -3,8 +3,8 @@ import { Crime } from "./Crime";
import { Player } from "@player"; import { Player } from "@player";
import { dialogBoxCreate } from "../ui/React/DialogBox"; import { dialogBoxCreate } from "../ui/React/DialogBox";
import { checkEnum } from "../utils/helpers/checkEnum"; import { checkEnum } from "../utils/helpers/enum";
import { CrimeType } from "../utils/WorkType"; import { CrimeType } from "../utils/enums";
//This is only used for the player //This is only used for the player
export function determineCrimeSuccess(type: string): boolean { export function determineCrimeSuccess(type: string): boolean {
@ -20,31 +20,18 @@ export function determineCrimeSuccess(type: string): boolean {
export function findCrime(roughName: string): Crime | null { export function findCrime(roughName: string): Crime | null {
if (checkEnum(CrimeType, roughName)) return Crimes[roughName]; if (checkEnum(CrimeType, roughName)) return Crimes[roughName];
roughName = roughName.toLowerCase(); roughName = roughName.toLowerCase();
if (roughName.includes("shoplift")) { if (roughName.includes("shoplift")) return Crimes[CrimeType.shoplift];
return Crimes[CrimeType.SHOPLIFT]; else if (roughName.includes("rob") && roughName.includes("store")) return Crimes[CrimeType.robStore];
} else if (roughName.includes("rob") && roughName.includes("store")) { else if (roughName.includes("mug")) return Crimes[CrimeType.mug];
return Crimes[CrimeType.ROB_STORE]; else if (roughName.includes("larceny")) return Crimes[CrimeType.larceny];
} else if (roughName.includes("mug")) { else if (roughName.includes("drugs")) return Crimes[CrimeType.dealDrugs];
return Crimes[CrimeType.MUG]; else if (roughName.includes("bond") && roughName.includes("forge")) return Crimes[CrimeType.bondForgery];
} else if (roughName.includes("larceny")) { else if ((roughName.includes("traffic") || roughName.includes("illegal")) && roughName.includes("arms")) {
return Crimes[CrimeType.LARCENY]; return Crimes[CrimeType.traffickArms];
} else if (roughName.includes("drugs")) { } else if (roughName.includes("homicide")) return Crimes[CrimeType.homicide];
return Crimes[CrimeType.DRUGS]; else if (roughName.includes("grand") && roughName.includes("auto")) return Crimes[CrimeType.grandTheftAuto];
} else if (roughName.includes("bond") && roughName.includes("forge")) { else if (roughName.includes("kidnap")) return Crimes[CrimeType.kidnap];
return Crimes[CrimeType.BOND_FORGERY]; else if (roughName.includes("assassin")) return Crimes[CrimeType.assassination];
} else if ((roughName.includes("traffic") || roughName.includes("illegal")) && roughName.includes("arms")) { else if (roughName.includes("heist")) return Crimes[CrimeType.heist];
return Crimes[CrimeType.TRAFFIC_ARMS];
} else if (roughName.includes("homicide")) {
return Crimes[CrimeType.HOMICIDE];
} else if (roughName.includes("grand") && roughName.includes("auto")) {
return Crimes[CrimeType.GRAND_THEFT_AUTO];
} else if (roughName.includes("kidnap")) {
return Crimes[CrimeType.KIDNAP];
} else if (roughName.includes("assassin")) {
return Crimes[CrimeType.ASSASSINATION];
} else if (roughName.includes("heist")) {
return Crimes[CrimeType.HEIST];
}
return null; return null;
} }

@ -1,15 +1,12 @@
import { Crime } from "./Crime"; import { Crime } from "./Crime";
import { CONSTANTS } from "../Constants"; import { CONSTANTS } from "../Constants";
import { CrimeType } from "../utils/enums";
import { CrimeType } from "../utils/WorkType";
// TODO: What is the point of CrimeType using totally different strings than
export const Crimes: Record<CrimeType, Crime> = { export const Crimes: Record<CrimeType, Crime> = {
[CrimeType.SHOPLIFT]: new Crime( [CrimeType.shoplift]: new Crime(
"Shoplift",
"to shoplift", "to shoplift",
"Attempt to shoplift from a low-end retailer", "Attempt to shoplift from a low-end retailer",
CrimeType.SHOPLIFT, CrimeType.shoplift,
2e3, 2e3,
15e3, 15e3,
1 / 20, 1 / 20,
@ -23,11 +20,10 @@ export const Crimes: Record<CrimeType, Crime> = {
}, },
), ),
[CrimeType.ROB_STORE]: new Crime( [CrimeType.robStore]: new Crime(
"Rob Store",
"to rob a store", "to rob a store",
"Attempt to commit armed robbery on a high-end store", "Attempt to commit armed robbery on a high-end store",
CrimeType.ROB_STORE, CrimeType.robStore,
60e3, 60e3,
400e3, 400e3,
1 / 5, 1 / 5,
@ -45,11 +41,10 @@ export const Crimes: Record<CrimeType, Crime> = {
}, },
), ),
[CrimeType.MUG]: new Crime( [CrimeType.mug]: new Crime(
"Mug",
"to mug", "to mug",
"Attempt to mug a random person on the street", "Attempt to mug a random person on the street",
CrimeType.MUG, CrimeType.mug,
4e3, 4e3,
36e3, 36e3,
1 / 5, 1 / 5,
@ -67,11 +62,10 @@ export const Crimes: Record<CrimeType, Crime> = {
}, },
), ),
[CrimeType.LARCENY]: new Crime( [CrimeType.larceny]: new Crime(
"Larceny",
"larceny", "larceny",
"Attempt to rob property from someone's house", "Attempt to rob property from someone's house",
CrimeType.LARCENY, CrimeType.larceny,
90e3, 90e3,
800e3, 800e3,
1 / 3, 1 / 3,
@ -89,31 +83,20 @@ export const Crimes: Record<CrimeType, Crime> = {
}, },
), ),
[CrimeType.DRUGS]: new Crime( [CrimeType.dealDrugs]: new Crime("to deal drugs", "Attempt to deal drugs", CrimeType.dealDrugs, 10e3, 120e3, 1, 0.5, {
"Deal Drugs", dexterity_exp: 5,
"to deal drugs", agility_exp: 5,
"Attempt to deal drugs", charisma_exp: 10,
CrimeType.DRUGS,
10e3,
120e3,
1,
0.5,
{
dexterity_exp: 5,
agility_exp: 5,
charisma_exp: 10,
charisma_success_weight: 3, charisma_success_weight: 3,
dexterity_success_weight: 2, dexterity_success_weight: 2,
agility_success_weight: 1, agility_success_weight: 1,
}, }),
),
[CrimeType.BOND_FORGERY]: new Crime( [CrimeType.bondForgery]: new Crime(
"Bond Forgery",
"to forge bonds", "to forge bonds",
"Attempt to forge corporate bonds", "Attempt to forge corporate bonds",
CrimeType.BOND_FORGERY, CrimeType.bondForgery,
300e3, 300e3,
4.5e6, 4.5e6,
1 / 2, 1 / 2,
@ -130,11 +113,10 @@ export const Crimes: Record<CrimeType, Crime> = {
}, },
), ),
[CrimeType.TRAFFIC_ARMS]: new Crime( [CrimeType.traffickArms]: new Crime(
"Traffick Arms",
"to traffic arms", "to traffic arms",
"Attempt to smuggle illegal arms into the city", "Attempt to smuggle illegal arms into the city",
CrimeType.TRAFFIC_ARMS, CrimeType.traffickArms,
40e3, 40e3,
600e3, 600e3,
2, 2,
@ -154,11 +136,10 @@ export const Crimes: Record<CrimeType, Crime> = {
}, },
), ),
[CrimeType.HOMICIDE]: new Crime( [CrimeType.homicide]: new Crime(
"Homicide",
"homicide", "homicide",
"Attempt to murder a random person on the street", "Attempt to murder a random person on the street",
CrimeType.HOMICIDE, CrimeType.homicide,
3e3, 3e3,
45e3, 45e3,
1, 1,
@ -178,11 +159,10 @@ export const Crimes: Record<CrimeType, Crime> = {
}, },
), ),
[CrimeType.GRAND_THEFT_AUTO]: new Crime( [CrimeType.grandTheftAuto]: new Crime(
"Grand Theft Auto",
"grand theft auto", "grand theft auto",
"Attempt to commit grand theft auto", "Attempt to commit grand theft auto",
CrimeType.GRAND_THEFT_AUTO, CrimeType.grandTheftAuto,
80e3, 80e3,
1.6e6, 1.6e6,
8, 8,
@ -204,11 +184,10 @@ export const Crimes: Record<CrimeType, Crime> = {
}, },
), ),
[CrimeType.KIDNAP]: new Crime( [CrimeType.kidnap]: new Crime(
"Kidnap",
"to kidnap", "to kidnap",
"Attempt to kidnap and ransom a high-profile-target", "Attempt to kidnap and ransom a high-profile-target",
CrimeType.KIDNAP, CrimeType.kidnap,
120e3, 120e3,
3.6e6, 3.6e6,
5, 5,
@ -229,11 +208,10 @@ export const Crimes: Record<CrimeType, Crime> = {
}, },
), ),
[CrimeType.ASSASSINATION]: new Crime( [CrimeType.assassination]: new Crime(
"Assassination",
"to assassinate", "to assassinate",
"Attempt to assassinate a high-profile target", "Attempt to assassinate a high-profile target",
CrimeType.ASSASSINATION, CrimeType.assassination,
300e3, 300e3,
12e6, 12e6,
8, 8,
@ -254,11 +232,10 @@ export const Crimes: Record<CrimeType, Crime> = {
}, },
), ),
[CrimeType.HEIST]: new Crime( [CrimeType.heist]: new Crime(
"Heist",
"a heist", "a heist",
"Attempt to pull off the ultimate heist", "Attempt to pull off the ultimate heist",
CrimeType.HEIST, CrimeType.heist,
600e3, 600e3,
120e6, 120e6,
18, 18,

@ -23,7 +23,7 @@ import { CovenantPurchasesRoot } from "../../PersonObjects/Sleeve/ui/CovenantPur
import { FactionNames } from "../data/FactionNames"; import { FactionNames } from "../data/FactionNames";
import { GangButton } from "./GangButton"; import { GangButton } from "./GangButton";
import { FactionWork } from "../../Work/FactionWork"; import { FactionWork } from "../../Work/FactionWork";
import { FactionWorkType } from "../../Work/data/FactionWorkType"; import { FactionWorkType } from "../../utils/enums";
type IProps = { type IProps = {
faction: Faction; faction: Faction;
@ -72,7 +72,7 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
new FactionWork({ new FactionWork({
singularity: false, singularity: false,
faction: faction.name, faction: faction.name,
factionWorkType: FactionWorkType.FIELD, factionWorkType: FactionWorkType.field,
}), }),
); );
startWork(); startWork();
@ -83,7 +83,7 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
new FactionWork({ new FactionWork({
singularity: false, singularity: false,
faction: faction.name, faction: faction.name,
factionWorkType: FactionWorkType.HACKING, factionWorkType: FactionWorkType.hacking,
}), }),
); );
startWork(); startWork();
@ -94,7 +94,7 @@ function MainPage({ faction, rerender, onAugmentations }: IMainProps): React.Rea
new FactionWork({ new FactionWork({
singularity: false, singularity: false,
faction: faction.name, faction: faction.name,
factionWorkType: FactionWorkType.SECURITY, factionWorkType: FactionWorkType.security,
}), }),
); );
startWork(); startWork();

@ -13,15 +13,16 @@ import { Player } from "@player";
import { Money } from "../../ui/React/Money"; import { Money } from "../../ui/React/Money";
import { Router } from "../../ui/GameRoot"; import { Router } from "../../ui/GameRoot";
import { Box } from "@mui/material"; import { Box } from "@mui/material";
import { ClassWork, ClassType, Classes } from "../../Work/ClassWork"; import { ClassWork, Classes } from "../../Work/ClassWork";
import { calculateCost } from "../../Work/Formulas"; import { calculateCost } from "../../Work/Formulas";
import { GymType } from "../../utils/enums";
type IProps = { type IProps = {
loc: Location; loc: Location;
}; };
export function GymLocation(props: IProps): React.ReactElement { export function GymLocation(props: IProps): React.ReactElement {
function train(stat: ClassType): void { function train(stat: GymType): void {
Player.startWork( Player.startWork(
new ClassWork({ new ClassWork({
classType: stat, classType: stat,
@ -33,20 +34,20 @@ export function GymLocation(props: IProps): React.ReactElement {
Router.toWork(); Router.toWork();
} }
const cost = calculateCost(Classes[ClassType.GymStrength], props.loc); const cost = calculateCost(Classes[GymType.strength], props.loc);
return ( return (
<Box sx={{ display: "grid", width: "fit-content" }}> <Box sx={{ display: "grid", width: "fit-content" }}>
<Button onClick={() => train(ClassType.GymStrength)}> <Button onClick={() => train(GymType.strength)}>
Train Strength (<Money money={cost} forPurchase={true} /> / sec) Train Strength (<Money money={cost} forPurchase={true} /> / sec)
</Button> </Button>
<Button onClick={() => train(ClassType.GymDefense)}> <Button onClick={() => train(GymType.defense)}>
Train Defense (<Money money={cost} forPurchase={true} /> / sec) Train Defense (<Money money={cost} forPurchase={true} /> / sec)
</Button> </Button>
<Button onClick={() => train(ClassType.GymDexterity)}> <Button onClick={() => train(GymType.dexterity)}>
Train Dexterity (<Money money={cost} forPurchase={true} /> / sec) Train Dexterity (<Money money={cost} forPurchase={true} /> / sec)
</Button> </Button>
<Button onClick={() => train(ClassType.GymAgility)}> <Button onClick={() => train(GymType.agility)}>
Train Agility (<Money money={cost} forPurchase={true} /> / sec) Train Agility (<Money money={cost} forPurchase={true} /> / sec)
</Button> </Button>
</Box> </Box>

@ -36,7 +36,7 @@ export function SlumsLocation(): React.ReactElement {
{crimes.map((crime) => ( {crimes.map((crime) => (
<Tooltip title={crime.tooltipText}> <Tooltip title={crime.tooltipText}>
<Button onClick={(e) => doCrime(e, crime)}> <Button onClick={(e) => doCrime(e, crime)}>
{crime.name} ({numeralWrapper.formatPercentage(crime.successRate(Player))} chance of success) {crime.type} ({numeralWrapper.formatPercentage(crime.successRate(Player))} chance of success)
</Button> </Button>
</Tooltip> </Tooltip>
))} ))}

@ -14,15 +14,16 @@ import { Router } from "../../ui/GameRoot";
import { Player } from "@player"; import { Player } from "@player";
import { Box } from "@mui/material"; import { Box } from "@mui/material";
import { ClassWork, ClassType, Classes } from "../../Work/ClassWork"; import { ClassWork, Classes } from "../../Work/ClassWork";
import { calculateCost } from "../../Work/Formulas"; import { calculateCost } from "../../Work/Formulas";
import { UniversityClassType } from "../../utils/enums";
type IProps = { type IProps = {
loc: Location; loc: Location;
}; };
export function UniversityLocation(props: IProps): React.ReactElement { export function UniversityLocation(props: IProps): React.ReactElement {
function take(classType: ClassType): void { function take(classType: UniversityClassType): void {
Player.startWork( Player.startWork(
new ClassWork({ new ClassWork({
classType: classType, classType: classType,
@ -34,11 +35,11 @@ export function UniversityLocation(props: IProps): React.ReactElement {
Router.toWork(); Router.toWork();
} }
const dataStructuresCost = calculateCost(Classes[ClassType.DataStructures], props.loc); const dataStructuresCost = calculateCost(Classes[UniversityClassType.dataStructures], props.loc);
const networksCost = calculateCost(Classes[ClassType.Networks], props.loc); const networksCost = calculateCost(Classes[UniversityClassType.networks], props.loc);
const algorithmsCost = calculateCost(Classes[ClassType.Algorithms], props.loc); const algorithmsCost = calculateCost(Classes[UniversityClassType.algorithms], props.loc);
const managementCost = calculateCost(Classes[ClassType.Management], props.loc); const managementCost = calculateCost(Classes[UniversityClassType.management], props.loc);
const leadershipCost = calculateCost(Classes[ClassType.Leadership], props.loc); const leadershipCost = calculateCost(Classes[UniversityClassType.leadership], props.loc);
const earnHackingExpTooltip = `Gain hacking experience!`; const earnHackingExpTooltip = `Gain hacking experience!`;
const earnCharismaExpTooltip = `Gain charisma experience!`; const earnCharismaExpTooltip = `Gain charisma experience!`;
@ -46,34 +47,34 @@ export function UniversityLocation(props: IProps): React.ReactElement {
return ( return (
<Box sx={{ display: "grid", width: "fit-content" }}> <Box sx={{ display: "grid", width: "fit-content" }}>
<Tooltip title={earnHackingExpTooltip}> <Tooltip title={earnHackingExpTooltip}>
<Button onClick={() => take(ClassType.StudyComputerScience)}>Study Computer Science (free)</Button> <Button onClick={() => take(UniversityClassType.computerScience)}>Study Computer Science (free)</Button>
</Tooltip> </Tooltip>
<Tooltip title={earnHackingExpTooltip}> <Tooltip title={earnHackingExpTooltip}>
<Button onClick={() => take(ClassType.DataStructures)}> <Button onClick={() => take(UniversityClassType.dataStructures)}>
Take Data Structures course ( Take Data Structures course (
<Money money={dataStructuresCost} forPurchase={true} /> / sec) <Money money={dataStructuresCost} forPurchase={true} /> / sec)
</Button> </Button>
</Tooltip> </Tooltip>
<Tooltip title={earnHackingExpTooltip}> <Tooltip title={earnHackingExpTooltip}>
<Button onClick={() => take(ClassType.Networks)}> <Button onClick={() => take(UniversityClassType.networks)}>
Take Networks course ( Take Networks course (
<Money money={networksCost} forPurchase={true} /> / sec) <Money money={networksCost} forPurchase={true} /> / sec)
</Button> </Button>
</Tooltip> </Tooltip>
<Tooltip title={earnHackingExpTooltip}> <Tooltip title={earnHackingExpTooltip}>
<Button onClick={() => take(ClassType.Algorithms)}> <Button onClick={() => take(UniversityClassType.algorithms)}>
Take Algorithms course ( Take Algorithms course (
<Money money={algorithmsCost} forPurchase={true} /> / sec) <Money money={algorithmsCost} forPurchase={true} /> / sec)
</Button> </Button>
</Tooltip> </Tooltip>
<Tooltip title={earnCharismaExpTooltip}> <Tooltip title={earnCharismaExpTooltip}>
<Button onClick={() => take(ClassType.Management)}> <Button onClick={() => take(UniversityClassType.management)}>
Take Management course ( Take Management course (
<Money money={managementCost} forPurchase={true} /> / sec) <Money money={managementCost} forPurchase={true} /> / sec)
</Button> </Button>
</Tooltip> </Tooltip>
<Tooltip title={earnCharismaExpTooltip}> <Tooltip title={earnCharismaExpTooltip}>
<Button onClick={() => take(ClassType.Leadership)}> <Button onClick={() => take(UniversityClassType.leadership)}>
Take Leadership course ( Take Leadership course (
<Money money={leadershipCost} forPurchase={true} /> / sec) <Money money={leadershipCost} forPurchase={true} /> / sec)
</Button> </Button>

@ -33,7 +33,7 @@ import { arrayToString } from "../utils/helpers/arrayToString";
import { HacknetServer } from "../Hacknet/HacknetServer"; import { HacknetServer } from "../Hacknet/HacknetServer";
import { BaseServer } from "../Server/BaseServer"; import { BaseServer } from "../Server/BaseServer";
import { dialogBoxCreate } from "../ui/React/DialogBox"; import { dialogBoxCreate } from "../ui/React/DialogBox";
import { checkEnum } from "../utils/helpers/checkEnum"; import { checkEnum } from "../utils/helpers/enum";
export const helpers = { export const helpers = {
string, string,

@ -602,7 +602,8 @@ export const RamCosts: RamCostTree<NSFull> = {
work: { work: {
crimeSuccessChance: 0, crimeSuccessChance: 0,
crimeGains: 0, crimeGains: 0,
classGains: 0, gymGains: 0,
universityGains: 0,
factionGains: 0, factionGains: 0,
companyGains: 0, companyGains: 0,
}, },

@ -66,7 +66,7 @@ import { NetscriptSingularity } from "./NetscriptFunctions/Singularity";
import { dialogBoxCreate } from "./ui/React/DialogBox"; import { dialogBoxCreate } from "./ui/React/DialogBox";
import { SnackbarEvents, ToastVariant } from "./ui/React/Snackbar"; import { SnackbarEvents, ToastVariant } from "./ui/React/Snackbar";
import { checkEnum } from "./utils/helpers/checkEnum"; import { checkEnum } from "./utils/helpers/enum";
import { Flags } from "./NetscriptFunctions/Flags"; import { Flags } from "./NetscriptFunctions/Flags";
import { calculateIntelligenceBonus } from "./PersonObjects/formulas/intelligence"; import { calculateIntelligenceBonus } from "./PersonObjects/formulas/intelligence";
@ -77,16 +77,16 @@ import { INetscriptExtra } from "./NetscriptFunctions/Extra";
import { ScriptDeath } from "./Netscript/ScriptDeath"; import { ScriptDeath } from "./Netscript/ScriptDeath";
import { getBitNodeMultipliers } from "./BitNode/BitNode"; import { getBitNodeMultipliers } from "./BitNode/BitNode";
import { assert, arrayAssert, stringAssert, objectAssert } from "./utils/helpers/typeAssertion"; import { assert, arrayAssert, stringAssert, objectAssert } from "./utils/helpers/typeAssertion";
import { CompanyPosNames, CrimeType } from "./utils/WorkType"; import { CompanyPosNames, CrimeType, GymType, UniversityClassType } from "./utils/enums";
import { cloneDeep } from "lodash"; import { cloneDeep } from "lodash";
import { FactionWorkType } from "./Work/data/FactionWorkType"; import { FactionWorkType } from "./utils/enums";
import { ClassType } from "./Work/ClassWork";
export const enums: NSEnums = { export const enums: NSEnums = {
toast: ToastVariant, toast: ToastVariant,
CrimeType, CrimeType,
FactionWorkType, FactionWorkType,
ClassType, GymType,
UniversityClassType,
CompanyPosNames, CompanyPosNames,
}; };

@ -58,7 +58,7 @@ import { Factions } from "../Faction/Factions";
import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers"; import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers";
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper"; import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { assertEnumMember, helpers } from "../Netscript/NetscriptHelpers"; import { assertEnumMember, helpers } from "../Netscript/NetscriptHelpers";
import { checkEnum } from "../utils/helpers/checkEnum"; import { checkEnum } from "../utils/helpers/enum";
import { CityName } from "../Locations/data/CityNames"; import { CityName } from "../Locations/data/CityNames";
export function NetscriptCorporation(): InternalAPI<NSCorporation> { export function NetscriptCorporation(): InternalAPI<NSCorporation> {

@ -40,19 +40,18 @@ import { repFromDonation } from "../Faction/formulas/donation";
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper"; import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { helpers } from "../Netscript/NetscriptHelpers"; import { helpers } from "../Netscript/NetscriptHelpers";
import { calculateCrimeWorkStats } from "../Work/Formulas"; import { calculateCrimeWorkStats } from "../Work/Formulas";
import { Crimes } from "../Crime/Crimes";
import { calculateCompanyWorkStats } from "../Work/Formulas"; import { calculateCompanyWorkStats } from "../Work/Formulas";
import { Companies } from "../Company/Companies"; import { Companies } from "../Company/Companies";
import { calculateClassEarnings } from "../Work/Formulas"; import { calculateClassEarnings } from "../Work/Formulas";
import { ClassType } from "../Work/ClassWork";
import { LocationName } from "../Locations/data/LocationNames"; import { LocationName } from "../Locations/data/LocationNames";
import { calculateFactionExp, calculateFactionRep } from "../Work/Formulas"; import { calculateFactionExp, calculateFactionRep } from "../Work/Formulas";
import { FactionWorkType } from "../Work/data/FactionWorkType"; import { FactionWorkType, GymType, UniversityClassType } from "../utils/enums";
import { defaultMultipliers } from "../PersonObjects/Multipliers"; import { defaultMultipliers } from "../PersonObjects/Multipliers";
import { checkEnum } from "../utils/helpers/checkEnum"; import { checkEnum, findEnumMember } from "../utils/helpers/enum";
import { CompanyPosNames, CrimeType } from "../utils/WorkType"; import { CompanyPosNames } from "../utils/enums";
import { CompanyPositions } from "../Company/CompanyPositions"; import { CompanyPositions } from "../Company/CompanyPositions";
import { findCrime } from "../Crime/CrimeHelpers";
export function NetscriptFormulas(): InternalAPI<IFormulas> { export function NetscriptFormulas(): InternalAPI<IFormulas> {
const checkFormulasAccess = function (ctx: NetscriptContext): void { const checkFormulasAccess = function (ctx: NetscriptContext): void {
@ -356,22 +355,31 @@ export function NetscriptFormulas(): InternalAPI<IFormulas> {
crimeSuccessChance: (ctx) => (_person, _crimeType) => { crimeSuccessChance: (ctx) => (_person, _crimeType) => {
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
const person = helpers.person(ctx, _person); const person = helpers.person(ctx, _person);
const crimeType = helpers.string(ctx, "crimeType", _crimeType); const crime = findCrime(helpers.string(ctx, "crimeType", _crimeType));
if (!checkEnum(CrimeType, crimeType)) throw new Error(`Invalid crime type: ${crimeType}`); if (!crime) throw new Error(`Invalid crime type: ${_crimeType}`);
return Crimes[crimeType].successRate(person); return crime.successRate(person);
}, },
crimeGains: (ctx) => (_person, _crimeType) => { crimeGains: (ctx) => (_person, _crimeType) => {
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
const person = helpers.person(ctx, _person); const person = helpers.person(ctx, _person);
const crimeType = helpers.string(ctx, "crimeType", _crimeType); const crime = findCrime(helpers.string(ctx, "crimeType", _crimeType));
if (!checkEnum(CrimeType, crimeType)) throw new Error(`Invalid crime type: ${crimeType}`); if (!crime) throw new Error(`Invalid crime type: ${_crimeType}`);
return calculateCrimeWorkStats(person, Crimes[crimeType]); return calculateCrimeWorkStats(person, crime);
}, },
classGains: (ctx) => (_person, _classType, _locationName) => { gymGains: (ctx) => (_person, _classType, _locationName) => {
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
const person = helpers.person(ctx, _person); const person = helpers.person(ctx, _person);
const classType = helpers.string(ctx, "classType", _classType); const classType = findEnumMember(GymType, helpers.string(ctx, "classType", _classType));
if (!checkEnum(ClassType, classType)) throw new Error(`Invalid class type: ${classType}`); if (!classType) throw new Error(`Invalid gym training type: ${_classType}`);
const locationName = helpers.string(ctx, "locationName", _locationName);
if (!checkEnum(LocationName, locationName)) throw new Error(`Invalid location name: ${locationName}`);
return calculateClassEarnings(person, classType, locationName);
},
universityGains: (ctx) => (_person, _classType, _locationName) => {
checkFormulasAccess(ctx);
const person = helpers.person(ctx, _person);
const classType = findEnumMember(UniversityClassType, helpers.string(ctx, "classType", _classType));
if (!classType) throw new Error(`Invalid university class type: ${_classType}`);
const locationName = helpers.string(ctx, "locationName", _locationName); const locationName = helpers.string(ctx, "locationName", _locationName);
if (!checkEnum(LocationName, locationName)) throw new Error(`Invalid location name: ${locationName}`); if (!checkEnum(LocationName, locationName)) throw new Error(`Invalid location name: ${locationName}`);
return calculateClassEarnings(person, classType, locationName); return calculateClassEarnings(person, classType, locationName);
@ -379,8 +387,8 @@ export function NetscriptFormulas(): InternalAPI<IFormulas> {
factionGains: (ctx) => (_player, _workType, _favor) => { factionGains: (ctx) => (_player, _workType, _favor) => {
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
const player = helpers.person(ctx, _player); const player = helpers.person(ctx, _player);
const workType = helpers.string(ctx, "_workType", _workType); const workType = findEnumMember(FactionWorkType, helpers.string(ctx, "_workType", _workType));
if (!checkEnum(FactionWorkType, workType)) throw new Error(`Invalid faction work type: ${workType}`); if (!workType) throw new Error(`Invalid faction work type: ${_workType}`);
const favor = helpers.number(ctx, "favor", _favor); const favor = helpers.number(ctx, "favor", _favor);
const exp = calculateFactionExp(player, workType); const exp = calculateFactionExp(player, workType);
const rep = calculateFactionRep(player, workType, favor); const rep = calculateFactionRep(player, workType, favor);
@ -390,8 +398,8 @@ export function NetscriptFormulas(): InternalAPI<IFormulas> {
companyGains: (ctx) => (_person, _companyName, _positionName, _favor) => { companyGains: (ctx) => (_person, _companyName, _positionName, _favor) => {
checkFormulasAccess(ctx); checkFormulasAccess(ctx);
const person = helpers.person(ctx, _person); const person = helpers.person(ctx, _person);
const positionName = helpers.string(ctx, "_positionName", _positionName); const positionName = findEnumMember(CompanyPosNames, helpers.string(ctx, "_positionName", _positionName));
if (!checkEnum(CompanyPosNames, positionName)) throw new Error(`Invalid company position: ${positionName}`); if (!positionName) throw new Error(`Invalid company position: ${_positionName}`);
const position = CompanyPositions[positionName]; const position = CompanyPositions[positionName];
const companyName = helpers.string(ctx, "_companyName", _companyName); const companyName = helpers.string(ctx, "_companyName", _companyName);
const company = Object.values(Companies).find((c) => c.name === companyName); const company = Object.values(Companies).find((c) => c.name === companyName);

@ -10,7 +10,7 @@ import {
import { FactionNames } from "../Faction/data/FactionNames"; import { FactionNames } from "../Faction/data/FactionNames";
import { Factions } from "../Faction/Factions"; import { Factions } from "../Faction/Factions";
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper"; import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { checkEnum } from "../utils/helpers/checkEnum"; import { checkEnum } from "../utils/helpers/enum";
import { LocationName } from "../Locations/data/LocationNames"; import { LocationName } from "../Locations/data/LocationNames";
import { helpers } from "../Netscript/NetscriptHelpers"; import { helpers } from "../Netscript/NetscriptHelpers";

@ -41,14 +41,15 @@ import { InternalAPI, NetscriptContext } from "src/Netscript/APIWrapper";
import { BlackOperationNames } from "../Bladeburner/data/BlackOperationNames"; import { BlackOperationNames } from "../Bladeburner/data/BlackOperationNames";
import { enterBitNode } from "../RedPill"; import { enterBitNode } from "../RedPill";
import { FactionNames } from "../Faction/data/FactionNames"; import { FactionNames } from "../Faction/data/FactionNames";
import { ClassWork, ClassType } from "../Work/ClassWork"; import { ClassWork } from "../Work/ClassWork";
import { CreateProgramWork, isCreateProgramWork } from "../Work/CreateProgramWork"; import { CreateProgramWork, isCreateProgramWork } from "../Work/CreateProgramWork";
import { FactionWork } from "../Work/FactionWork"; import { FactionWork } from "../Work/FactionWork";
import { FactionWorkType } from "../Work/data/FactionWorkType"; import { FactionWorkType, GymType, UniversityClassType } from "../utils/enums";
import { CompanyWork } from "../Work/CompanyWork"; import { CompanyWork } from "../Work/CompanyWork";
import { canGetBonus, onExport } from "../ExportBonus"; import { canGetBonus, onExport } from "../ExportBonus";
import { saveObject } from "../SaveObject"; import { saveObject } from "../SaveObject";
import { calculateCrimeWorkStats } from "../Work/Formulas"; import { calculateCrimeWorkStats } from "../Work/Formulas";
import { findEnumMember } from "../utils/helpers/enum";
export function NetscriptSingularity(): InternalAPI<ISingularity> { export function NetscriptSingularity(): InternalAPI<ISingularity> {
const getAugmentation = function (ctx: NetscriptContext, name: string): Augmentation { const getAugmentation = function (ctx: NetscriptContext, name: string): Augmentation {
@ -253,7 +254,11 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
(_universityName, _className, _focus = true) => { (_universityName, _className, _focus = true) => {
helpers.checkSingularityAccess(ctx); helpers.checkSingularityAccess(ctx);
const universityName = helpers.string(ctx, "universityName", _universityName); const universityName = helpers.string(ctx, "universityName", _universityName);
const className = helpers.string(ctx, "className", _className); const classType = findEnumMember(UniversityClassType, helpers.string(ctx, "className", _className));
if (!classType) {
helpers.log(ctx, () => `Invalid class name: ${_className}.`);
return false;
}
const focus = !!_focus; const focus = !!_focus;
const wasFocusing = Player.focus; const wasFocusing = Player.focus;
@ -293,33 +298,9 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
return false; return false;
} }
let task: ClassType;
switch (className.toLowerCase()) {
case "Study Computer Science".toLowerCase():
task = ClassType.StudyComputerScience;
break;
case "Data Structures".toLowerCase():
task = ClassType.DataStructures;
break;
case "Networks".toLowerCase():
task = ClassType.Networks;
break;
case "Algorithms".toLowerCase():
task = ClassType.Algorithms;
break;
case "Management".toLowerCase():
task = ClassType.Management;
break;
case "Leadership".toLowerCase():
task = ClassType.Leadership;
break;
default:
helpers.log(ctx, () => `Invalid class name: ${className}.`);
return false;
}
Player.startWork( Player.startWork(
new ClassWork({ new ClassWork({
classType: task, classType,
location: Player.location, location: Player.location,
singularity: true, singularity: true,
}), }),
@ -331,7 +312,7 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
Player.stopFocusing(); Player.stopFocusing();
Router.toTerminal(); Router.toTerminal();
} }
helpers.log(ctx, () => `Started ${task} at ${universityName}`); helpers.log(ctx, () => `Started ${classType} at ${universityName}`);
return true; return true;
}, },
@ -340,7 +321,11 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
(_gymName, _stat, _focus = true) => { (_gymName, _stat, _focus = true) => {
helpers.checkSingularityAccess(ctx); helpers.checkSingularityAccess(ctx);
const gymName = helpers.string(ctx, "gymName", _gymName); const gymName = helpers.string(ctx, "gymName", _gymName);
const stat = helpers.string(ctx, "stat", _stat); const classType = findEnumMember(GymType, helpers.string(ctx, "stat", _stat));
if (!classType) {
helpers.log(ctx, () => `Invalid stat: ${_stat}.`);
return false;
}
const focus = !!_focus; const focus = !!_focus;
const wasFocusing = Player.focus; const wasFocusing = Player.focus;
@ -405,35 +390,7 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
return false; return false;
} }
switch (stat.toLowerCase()) { Player.startWork(new ClassWork({ classType, location: Player.location, singularity: true }));
case "strength".toLowerCase():
case "str".toLowerCase():
Player.startWork(
new ClassWork({ classType: ClassType.GymStrength, location: Player.location, singularity: true }),
);
break;
case "defense".toLowerCase():
case "def".toLowerCase():
Player.startWork(
new ClassWork({ classType: ClassType.GymDefense, location: Player.location, singularity: true }),
);
break;
case "dexterity".toLowerCase():
case "dex".toLowerCase():
Player.startWork(
new ClassWork({ classType: ClassType.GymDexterity, location: Player.location, singularity: true }),
);
break;
case "agility".toLowerCase():
case "agi".toLowerCase():
Player.startWork(
new ClassWork({ classType: ClassType.GymAgility, location: Player.location, singularity: true }),
);
break;
default:
helpers.log(ctx, () => `Invalid stat: ${stat}.`);
return false;
}
if (focus) { if (focus) {
Player.startFocusing(); Player.startFocusing();
Router.toWork(); Router.toWork();
@ -441,7 +398,7 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
Player.stopFocusing(); Player.stopFocusing();
Router.toTerminal(); Router.toTerminal();
} }
helpers.log(ctx, () => `Started training ${stat} at ${gymName}`); helpers.log(ctx, () => `Started training ${classType} at ${gymName}`);
return true; return true;
}, },
@ -926,7 +883,7 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
Player.startWork( Player.startWork(
new FactionWork({ new FactionWork({
singularity: true, singularity: true,
factionWorkType: FactionWorkType.HACKING, factionWorkType: FactionWorkType.hacking,
faction: faction.name, faction: faction.name,
}), }),
); );
@ -949,7 +906,7 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
Player.startWork( Player.startWork(
new FactionWork({ new FactionWork({
singularity: true, singularity: true,
factionWorkType: FactionWorkType.FIELD, factionWorkType: FactionWorkType.field,
faction: faction.name, faction: faction.name,
}), }),
); );
@ -972,7 +929,7 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
Player.startWork( Player.startWork(
new FactionWork({ new FactionWork({
singularity: true, singularity: true,
factionWorkType: FactionWorkType.SECURITY, factionWorkType: FactionWorkType.security,
faction: faction.name, faction: faction.name,
}), }),
); );
@ -1118,7 +1075,7 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
const crime = findCrime(crimeType); const crime = findCrime(crimeType);
if (crime == null) throw helpers.makeRuntimeErrorMsg(ctx, `Invalid crime: '${crimeType}'`); if (crime == null) throw helpers.makeRuntimeErrorMsg(ctx, `Invalid crime: '${crimeType}'`);
helpers.log(ctx, () => `Attempting to commit ${crime.name}...`); helpers.log(ctx, () => `Attempting to commit ${crime.type}...`);
const crimeTime = crime.commit(1, ctx.workerScript); const crimeTime = crime.commit(1, ctx.workerScript);
if (focus) { if (focus) {
Player.startFocusing(); Player.startFocusing();

@ -5,7 +5,7 @@ import { findCrime } from "../Crime/CrimeHelpers";
import { Augmentation } from "../Augmentation/Augmentation"; import { Augmentation } from "../Augmentation/Augmentation";
import { sleeve } from "../ScriptEditor/NetscriptDefinitions"; import { sleeve } from "../ScriptEditor/NetscriptDefinitions";
import { checkEnum } from "../utils/helpers/checkEnum"; import { checkEnum } from "../utils/helpers/enum";
import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper"; import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper";
import { isSleeveBladeburnerWork } from "../PersonObjects/Sleeve/Work/SleeveBladeburnerWork"; import { isSleeveBladeburnerWork } from "../PersonObjects/Sleeve/Work/SleeveBladeburnerWork";
import { isSleeveFactionWork } from "../PersonObjects/Sleeve/Work/SleeveFactionWork"; import { isSleeveFactionWork } from "../PersonObjects/Sleeve/Work/SleeveFactionWork";

@ -18,7 +18,7 @@ import { CompanyPosition } from "../../Company/CompanyPosition";
import { CompanyPositions } from "../../Company/CompanyPositions"; import { CompanyPositions } from "../../Company/CompanyPositions";
import { Contracts } from "../../Bladeburner/data/Contracts"; import { Contracts } from "../../Bladeburner/data/Contracts";
import { CONSTANTS } from "../../Constants"; import { CONSTANTS } from "../../Constants";
import { CrimeType } from "../../utils/WorkType"; import { CrimeType, GymType, UniversityClassType } from "../../utils/enums";
import { CityName } from "../../Locations/data/CityNames"; import { CityName } from "../../Locations/data/CityNames";
import { Factions } from "../../Faction/Factions"; import { Factions } from "../../Faction/Factions";
@ -27,7 +27,7 @@ import { LocationName } from "../../Locations/data/LocationNames";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../utils/JSONReviver";
import { numeralWrapper } from "../../ui/numeralFormat"; import { numeralWrapper } from "../../ui/numeralFormat";
import { FactionWorkType } from "../../Work/data/FactionWorkType"; import { FactionWorkType } from "../../utils/enums";
import { Work } from "./Work/Work"; import { Work } from "./Work/Work";
import { SleeveClassWork } from "./Work/SleeveClassWork"; import { SleeveClassWork } from "./Work/SleeveClassWork";
import { ClassType } from "../../Work/ClassWork"; import { ClassType } from "../../Work/ClassWork";
@ -221,22 +221,22 @@ export class Sleeve extends Person implements ISleeve {
let classType: ClassType | undefined; let classType: ClassType | undefined;
switch (className.toLowerCase()) { switch (className.toLowerCase()) {
case "study computer science": case "study computer science":
classType = ClassType.StudyComputerScience; classType = UniversityClassType.computerScience;
break; break;
case "data structures": case "data structures":
classType = ClassType.DataStructures; classType = UniversityClassType.dataStructures;
break; break;
case "networks": case "networks":
classType = ClassType.Networks; classType = UniversityClassType.networks;
break; break;
case "algorithms": case "algorithms":
classType = ClassType.Algorithms; classType = UniversityClassType.algorithms;
break; break;
case "management": case "management":
classType = ClassType.Management; classType = UniversityClassType.management;
break; break;
case "leadership": case "leadership":
classType = ClassType.Leadership; classType = UniversityClassType.leadership;
break; break;
} }
if (!classType) return false; if (!classType) return false;
@ -311,13 +311,13 @@ export class Sleeve extends Person implements ISleeve {
let factionWorkType: FactionWorkType; let factionWorkType: FactionWorkType;
if (sanitizedWorkType.includes("hack")) { if (sanitizedWorkType.includes("hack")) {
if (!factionInfo.offerHackingWork) return false; if (!factionInfo.offerHackingWork) return false;
factionWorkType = FactionWorkType.HACKING; factionWorkType = FactionWorkType.hacking;
} else if (sanitizedWorkType.includes("field")) { } else if (sanitizedWorkType.includes("field")) {
if (!factionInfo.offerFieldWork) return false; if (!factionInfo.offerFieldWork) return false;
factionWorkType = FactionWorkType.FIELD; factionWorkType = FactionWorkType.field;
} else if (sanitizedWorkType.includes("security")) { } else if (sanitizedWorkType.includes("security")) {
if (!factionInfo.offerSecurityWork) return false; if (!factionInfo.offerSecurityWork) return false;
factionWorkType = FactionWorkType.SECURITY; factionWorkType = FactionWorkType.security;
} else { } else {
return false; return false;
} }
@ -372,16 +372,16 @@ export class Sleeve extends Person implements ISleeve {
// set stat to a default value. // set stat to a default value.
let classType: ClassType | undefined; let classType: ClassType | undefined;
if (sanitizedStat.includes("str")) { if (sanitizedStat.includes("str")) {
classType = ClassType.GymStrength; classType = GymType.strength;
} }
if (sanitizedStat.includes("def")) { if (sanitizedStat.includes("def")) {
classType = ClassType.GymDefense; classType = GymType.defense;
} }
if (sanitizedStat.includes("dex")) { if (sanitizedStat.includes("dex")) {
classType = ClassType.GymDexterity; classType = GymType.dexterity;
} }
if (sanitizedStat.includes("agi")) { if (sanitizedStat.includes("agi")) {
classType = ClassType.GymAgility; classType = GymType.agility;
} }
// if stat is still equals its default value, then validation has failed. // if stat is still equals its default value, then validation has failed.
if (!classType) return false; if (!classType) return false;

@ -5,6 +5,8 @@ import { LocationName } from "../../../Locations/data/LocationNames";
import { calculateClassEarnings } from "../../../Work/Formulas"; import { calculateClassEarnings } from "../../../Work/Formulas";
import { Sleeve } from "../Sleeve"; import { Sleeve } from "../Sleeve";
import { scaleWorkStats, WorkStats } from "../../../Work/WorkStats"; import { scaleWorkStats, WorkStats } from "../../../Work/WorkStats";
import { GymType, UniversityClassType } from "../../../utils/enums";
import { checkEnum } from "../../../utils/helpers/enum";
export const isSleeveClassWork = (w: Work | null): w is SleeveClassWork => w !== null && w.type === WorkType.CLASS; export const isSleeveClassWork = (w: Work | null): w is SleeveClassWork => w !== null && w.type === WorkType.CLASS;
@ -19,7 +21,7 @@ export class SleeveClassWork extends Work {
constructor(params?: ClassWorkParams) { constructor(params?: ClassWorkParams) {
super(WorkType.CLASS); super(WorkType.CLASS);
this.classType = params?.classType ?? ClassType.StudyComputerScience; this.classType = params?.classType ?? UniversityClassType.computerScience;
this.location = params?.location ?? LocationName.Sector12RothmanUniversity; this.location = params?.location ?? LocationName.Sector12RothmanUniversity;
} }
@ -28,9 +30,7 @@ export class SleeveClassWork extends Work {
} }
isGym(): boolean { isGym(): boolean {
return [ClassType.GymAgility, ClassType.GymDefense, ClassType.GymDexterity, ClassType.GymStrength].includes( return checkEnum(GymType, this.classType);
this.classType,
);
} }
process(sleeve: Sleeve, cycles: number) { process(sleeve: Sleeve, cycles: number) {

@ -2,13 +2,14 @@ import { Player } from "@player";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver";
import { Sleeve } from "../Sleeve"; import { Sleeve } from "../Sleeve";
import { applySleeveGains, Work, WorkType } from "./Work"; import { applySleeveGains, Work, WorkType } from "./Work";
import { CrimeType } from "../../../utils/WorkType"; import { CrimeType } from "../../../utils/enums";
import { Crimes } from "../../../Crime/Crimes"; import { Crimes } from "../../../Crime/Crimes";
import { Crime } from "../../../Crime/Crime"; import { Crime } from "../../../Crime/Crime";
import { scaleWorkStats, WorkStats } from "../../../Work/WorkStats"; import { scaleWorkStats, WorkStats } from "../../../Work/WorkStats";
import { CONSTANTS } from "../../../Constants"; import { CONSTANTS } from "../../../Constants";
import { checkEnum } from "../../../utils/helpers/checkEnum"; import { checkEnum } from "../../../utils/helpers/enum";
import { calculateCrimeWorkStats } from "../../../Work/Formulas"; import { calculateCrimeWorkStats } from "../../../Work/Formulas";
import { findCrime } from "../../../Crime/CrimeHelpers";
export const isSleeveCrimeWork = (w: Work | null): w is SleeveCrimeWork => w !== null && w.type === WorkType.CRIME; export const isSleeveCrimeWork = (w: Work | null): w is SleeveCrimeWork => w !== null && w.type === WorkType.CRIME;
@ -17,7 +18,7 @@ export class SleeveCrimeWork extends Work {
cyclesWorked = 0; cyclesWorked = 0;
constructor(crimeType?: CrimeType) { constructor(crimeType?: CrimeType) {
super(WorkType.CRIME); super(WorkType.CRIME);
this.crimeType = crimeType ?? CrimeType.SHOPLIFT; this.crimeType = crimeType ?? CrimeType.shoplift;
} }
getCrime(): Crime { getCrime(): Crime {
@ -60,7 +61,9 @@ export class SleeveCrimeWork extends Work {
/** Initializes a RecoveryWork object from a JSON save state. */ /** Initializes a RecoveryWork object from a JSON save state. */
static fromJSON(value: IReviverValue): SleeveCrimeWork { static fromJSON(value: IReviverValue): SleeveCrimeWork {
return Generic_fromJSON(SleeveCrimeWork, value.data); const crimeWork = Generic_fromJSON(SleeveCrimeWork, value.data);
crimeWork.crimeType = findCrime(crimeWork.crimeType)?.type ?? CrimeType.shoplift;
return crimeWork;
} }
} }

@ -2,7 +2,7 @@ import { Player } from "@player";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver"; import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../../utils/JSONReviver";
import { Sleeve } from "../Sleeve"; import { Sleeve } from "../Sleeve";
import { applySleeveGains, Work, WorkType } from "./Work"; import { applySleeveGains, Work, WorkType } from "./Work";
import { FactionWorkType } from "../../../Work/data/FactionWorkType"; import { FactionWorkType } from "../../../utils/enums";
import { FactionNames } from "../../../Faction/data/FactionNames"; import { FactionNames } from "../../../Faction/data/FactionNames";
import { Factions } from "../../../Faction/Factions"; import { Factions } from "../../../Faction/Factions";
import { calculateFactionExp, calculateFactionRep } from "../../../Work/Formulas"; import { calculateFactionExp, calculateFactionRep } from "../../../Work/Formulas";
@ -23,7 +23,7 @@ export class SleeveFactionWork extends Work {
constructor(params?: SleeveFactionWorkParams) { constructor(params?: SleeveFactionWorkParams) {
super(WorkType.FACTION); super(WorkType.FACTION);
this.factionWorkType = params?.factionWorkType ?? FactionWorkType.HACKING; this.factionWorkType = params?.factionWorkType ?? FactionWorkType.hacking;
this.factionName = params?.factionName ?? FactionNames.Sector12; this.factionName = params?.factionName ?? FactionNames.Sector12;
} }

@ -1,6 +1,6 @@
import { Box, Button, Paper, Tooltip, Typography } from "@mui/material"; import { Box, Button, Paper, Tooltip, Typography } from "@mui/material";
import React, { useState } from "react"; import React, { useState } from "react";
import { FactionWorkType } from "../../../Work/data/FactionWorkType"; import { FactionWorkType } from "../../../utils/enums";
import { CONSTANTS } from "../../../Constants"; import { CONSTANTS } from "../../../Constants";
import { Player } from "@player"; import { Player } from "@player";
import { numeralWrapper } from "../../../ui/numeralFormat"; import { numeralWrapper } from "../../../ui/numeralFormat";
@ -21,7 +21,7 @@ import { isSleeveSupportWork } from "../Work/SleeveSupportWork";
import { isSleeveBladeburnerWork } from "../Work/SleeveBladeburnerWork"; import { isSleeveBladeburnerWork } from "../Work/SleeveBladeburnerWork";
import { isSleeveCrimeWork } from "../Work/SleeveCrimeWork"; import { isSleeveCrimeWork } from "../Work/SleeveCrimeWork";
import { findCrime } from "../../../Crime/CrimeHelpers"; import { findCrime } from "../../../Crime/CrimeHelpers";
import { CrimeType } from "../../../utils/WorkType"; import { CrimeType } from "../../../utils/enums";
interface IProps { interface IProps {
sleeve: Sleeve; sleeve: Sleeve;
@ -46,7 +46,7 @@ export function SleeveElem(props: IProps): React.ReactElement {
props.sleeve.workForFaction(abc[1], abc[2]); props.sleeve.workForFaction(abc[1], abc[2]);
break; break;
case "Commit Crime": case "Commit Crime":
props.sleeve.commitCrime(findCrime(abc[1])?.type ?? CrimeType.SHOPLIFT); props.sleeve.commitCrime(findCrime(abc[1])?.type ?? CrimeType.shoplift);
break; break;
case "Take University Course": case "Take University Course":
props.sleeve.takeUniversityCourse(abc[2], abc[1]); props.sleeve.takeUniversityCourse(abc[2], abc[1]);
@ -106,13 +106,13 @@ export function SleeveElem(props: IProps): React.ReactElement {
if (isSleeveFactionWork(props.sleeve.currentWork)) { if (isSleeveFactionWork(props.sleeve.currentWork)) {
let doing = "nothing"; let doing = "nothing";
switch (props.sleeve.currentWork.factionWorkType) { switch (props.sleeve.currentWork.factionWorkType) {
case FactionWorkType.FIELD: case FactionWorkType.field:
doing = "Field work"; doing = "Field work";
break; break;
case FactionWorkType.HACKING: case FactionWorkType.hacking:
doing = "Hacking contracts"; doing = "Hacking contracts";
break; break;
case FactionWorkType.SECURITY: case FactionWorkType.security:
doing = "Security work"; doing = "Security work";
break; break;
} }

@ -16,11 +16,9 @@ import { isSleeveSynchroWork } from "../Work/SleeveSynchroWork";
import { isSleeveClassWork } from "../Work/SleeveClassWork"; import { isSleeveClassWork } from "../Work/SleeveClassWork";
import { isSleeveInfiltrateWork } from "../Work/SleeveInfiltrateWork"; import { isSleeveInfiltrateWork } from "../Work/SleeveInfiltrateWork";
import { isSleeveSupportWork } from "../Work/SleeveSupportWork"; import { isSleeveSupportWork } from "../Work/SleeveSupportWork";
import { ClassType } from "../../../Work/ClassWork";
import { isSleeveCrimeWork } from "../Work/SleeveCrimeWork"; import { isSleeveCrimeWork } from "../Work/SleeveCrimeWork";
import { FactionWorkType } from "../../../Work/data/FactionWorkType"; import { CrimeType, FactionWorkType, GymType, UniversityClassType } from "../../../utils/enums";
import { checkEnum } from "../../../utils/helpers/checkEnum"; import { checkEnum } from "../../../utils/helpers/enum";
import { CrimeType } from "../../../utils/WorkType";
const universitySelectorOptions: string[] = [ const universitySelectorOptions: string[] = [
"Study Computer Science", "Study Computer Science",
@ -167,7 +165,7 @@ const tasks: {
}; };
}, },
"Commit Crime": (): ITaskDetails => { "Commit Crime": (): ITaskDetails => {
return { first: Object.values(Crimes).map((crime) => crime.name), second: () => ["------"] }; return { first: Object.keys(Crimes), second: () => ["------"] };
}, },
"Take University Course": (sleeve: Sleeve): ITaskDetails => { "Take University Course": (sleeve: Sleeve): ITaskDetails => {
let universities: string[] = []; let universities: string[] = [];
@ -263,13 +261,13 @@ function getABC(sleeve: Sleeve): [string, string, string] {
if (isSleeveFactionWork(w)) { if (isSleeveFactionWork(w)) {
let workType = ""; let workType = "";
switch (w.factionWorkType) { switch (w.factionWorkType) {
case FactionWorkType.HACKING: case FactionWorkType.hacking:
workType = "Hacking Contracts"; workType = "Hacking Contracts";
break; break;
case FactionWorkType.FIELD: case FactionWorkType.field:
workType = "Field Work"; workType = "Field Work";
break; break;
case FactionWorkType.SECURITY: case FactionWorkType.security:
workType = "Security Work"; workType = "Security Work";
break; break;
} }
@ -293,30 +291,30 @@ function getABC(sleeve: Sleeve): [string, string, string] {
if (isSleeveClassWork(w)) { if (isSleeveClassWork(w)) {
switch (w.classType) { switch (w.classType) {
case ClassType.StudyComputerScience: case UniversityClassType.computerScience:
return ["Take University Course", "Study Computer Science", w.location]; return ["Take University Course", "Study Computer Science", w.location];
case ClassType.DataStructures: case UniversityClassType.dataStructures:
return ["Take University Course", "Data Structures", w.location]; return ["Take University Course", "Data Structures", w.location];
case ClassType.Networks: case UniversityClassType.networks:
return ["Take University Course", "Networks", w.location]; return ["Take University Course", "Networks", w.location];
case ClassType.Algorithms: case UniversityClassType.algorithms:
return ["Take University Course", "Algorithms", w.location]; return ["Take University Course", "Algorithms", w.location];
case ClassType.Management: case UniversityClassType.management:
return ["Take University Course", "Management", w.location]; return ["Take University Course", "Management", w.location];
case ClassType.Leadership: case UniversityClassType.leadership:
return ["Take University Course", "Leadership", w.location]; return ["Take University Course", "Leadership", w.location];
case ClassType.GymStrength: case GymType.strength:
return ["Workout at Gym", "Train Strength", w.location]; return ["Workout at Gym", "Train Strength", w.location];
case ClassType.GymDefense: case GymType.defense:
return ["Workout at Gym", "Train Defense", w.location]; return ["Workout at Gym", "Train Defense", w.location];
case ClassType.GymDexterity: case GymType.dexterity:
return ["Workout at Gym", "Train Dexterity", w.location]; return ["Workout at Gym", "Train Dexterity", w.location];
case ClassType.GymAgility: case GymType.agility:
return ["Workout at Gym", "Train Agility", w.location]; return ["Workout at Gym", "Train Agility", w.location];
} }
} }
if (isSleeveCrimeWork(w)) { if (isSleeveCrimeWork(w)) {
return ["Commit Crime", checkEnum(CrimeType, w.crimeType) ? Crimes[w.crimeType].name : "Shoplift", "------"]; return ["Commit Crime", checkEnum(CrimeType, w.crimeType) ? w.crimeType : "Shoplift", "------"];
} }
if (isSleeveSupportWork(w)) { if (isSleeveSupportWork(w)) {
return ["Perform Bladeburner Actions", "Support main sleeve", "------"]; return ["Perform Bladeburner Actions", "Support main sleeve", "------"];

@ -211,8 +211,6 @@ export interface CrimeStats {
kills: number; kills: number;
/** How much money is given */ /** How much money is given */
money: number; money: number;
/** Name of crime */
name: string;
/** Milliseconds it takes to attempt the crime */ /** Milliseconds it takes to attempt the crime */
time: number; time: number;
/** Description of the crime activity */ /** Description of the crime activity */
@ -3817,8 +3815,14 @@ interface WorkFormulas {
crimeSuccessChance(person: Person, crimeType: CrimeType | `${CrimeType}`): number; crimeSuccessChance(person: Person, crimeType: CrimeType | `${CrimeType}`): number;
/** @returns The WorkStats gained when completing one instance of the specified crime. */ /** @returns The WorkStats gained when completing one instance of the specified crime. */
crimeGains(person: Person, crimeType: CrimeType | `${CrimeType}`): WorkStats; crimeGains(person: Person, crimeType: CrimeType | `${CrimeType}`): WorkStats;
/** @returns The WorkStats applied every game cycle (200ms) by taking the specified class. */ /** @returns The WorkStats applied every game cycle (200ms) by taking the specified gym class. */
classGains(person: Person, classType: ClassType | `${ClassType}`, locationName: string): WorkStats; gymGains(person: Person, gymType: GymType | `${GymType}`, locationName: string): WorkStats;
/** @returns The WorkStats applied every game cycle (200ms) by taking the specified university class. */
universityGains(
person: Person,
classType: UniversityClassType | `${UniversityClassType}`,
locationName: string,
): WorkStats;
/** @returns The WorkStats applied every game cycle (200ms) by performing the specified faction work. */ /** @returns The WorkStats applied every game cycle (200ms) by performing the specified faction work. */
factionGains(person: Person, workType: FactionWorkType | `${FactionWorkType}`, favor: number): WorkStats; factionGains(person: Person, workType: FactionWorkType | `${FactionWorkType}`, favor: number): WorkStats;
/** @returns The WorkStats applied every game cycle (200ms) by performing the specified company work. */ /** @returns The WorkStats applied every game cycle (200ms) by performing the specified company work. */
@ -6815,42 +6819,46 @@ declare enum ToastVariant {
/** @public */ /** @public */
declare enum CrimeType { declare enum CrimeType {
SHOPLIFT = "SHOPLIFT", shoplift = "Shoplift",
ROB_STORE = "ROBSTORE", robStore = "Rob Store",
MUG = "MUG", mug = "Mug",
LARCENY = "LARCENY", larceny = "Larceny",
DRUGS = "DRUGS", dealDrugs = "Deal Drugs",
BOND_FORGERY = "BONDFORGERY", bondForgery = "Bond Forgery",
TRAFFIC_ARMS = "TRAFFICKARMS", traffickArms = "Traffick Arms",
HOMICIDE = "HOMICIDE", homicide = "Homicide",
GRAND_THEFT_AUTO = "GRANDTHEFTAUTO", grandTheftAuto = "Grand Theft Auto",
KIDNAP = "KIDNAP", kidnap = "Kidnap",
ASSASSINATION = "ASSASSINATION", assassination = "Assassination",
HEIST = "HEIST", heist = "Heist",
} }
/** @public */ /** @public */
declare enum FactionWorkType { declare enum FactionWorkType {
HACKING = "HACKING", hacking = "hacking",
FIELD = "FIELD", field = "field",
SECURITY = "SECURITY", security = "security",
} }
// TODO: split ClassType enum into separate enums for gym and uni so they can actually be used for player input.
/** @public */ /** @public */
declare enum ClassType { declare enum UniversityClassType {
StudyComputerScience = "STUDYCOMPUTERSCIENCE", computerScience = "Computer Science",
DataStructures = "DATASTRUCTURES", dataStructures = "Data Structures",
Networks = "NETWORKS", networks = "Networks",
Algorithms = "ALGORITHMS", algorithms = "Algorithms",
Management = "MANAGEMENT", management = "Management",
Leadership = "LEADERSHIP", leadership = "Leadership",
GymStrength = "GYMSTRENGTH",
GymDefense = "GYMDEFENSE",
GymDexterity = "GYMDEXTERITY",
GymAgility = "GYMAGILITY",
} }
/** @public */
declare enum GymType {
strength = "str",
defense = "def",
dexterity = "dex",
agility = "agi",
}
/** @public */
declare enum CompanyPosNames { declare enum CompanyPosNames {
sw0 = "Software Engineering Intern", sw0 = "Software Engineering Intern",
sw1 = "Junior Software Engineer", sw1 = "Junior Software Engineer",
@ -6927,7 +6935,8 @@ export type NSEnums = {
toast: typeof ToastVariant; toast: typeof ToastVariant;
CrimeType: typeof CrimeType; CrimeType: typeof CrimeType;
FactionWorkType: typeof FactionWorkType; FactionWorkType: typeof FactionWorkType;
ClassType: typeof ClassType; GymType: typeof GymType;
UniversityClassType: typeof UniversityClassType;
CompanyPosNames: typeof CompanyPosNames; CompanyPosNames: typeof CompanyPosNames;
}; };

@ -3,7 +3,7 @@ import { BaseServer } from "../../Server/BaseServer";
import { MessageFilenames, showMessage } from "../../Message/MessageHelpers"; import { MessageFilenames, showMessage } from "../../Message/MessageHelpers";
import { showLiterature } from "../../Literature/LiteratureHelpers"; import { showLiterature } from "../../Literature/LiteratureHelpers";
import { dialogBoxCreate } from "../../ui/React/DialogBox"; import { dialogBoxCreate } from "../../ui/React/DialogBox";
import { checkEnum } from "../../utils/helpers/checkEnum"; import { checkEnum } from "../../utils/helpers/enum";
export function cat(args: (string | number | boolean)[], server: BaseServer): void { export function cat(args: (string | number | boolean)[], server: BaseServer): void {
if (args.length !== 1) { if (args.length !== 1) {

@ -10,110 +10,67 @@ import { Player } from "@player";
import { calculateClassEarnings as calculateClassEarningsRate } from "./Formulas"; import { calculateClassEarnings as calculateClassEarningsRate } from "./Formulas";
import { Work, WorkType } from "./Work"; import { Work, WorkType } from "./Work";
import { applyWorkStats, newWorkStats, sumWorkStats, WorkStats } from "./WorkStats"; import { applyWorkStats, newWorkStats, sumWorkStats, WorkStats } from "./WorkStats";
import { GymType, UniversityClassType } from "../utils/enums";
import { checkEnum, findEnumMember } from "../utils/helpers/enum";
export enum ClassType { export type ClassType = UniversityClassType | GymType;
StudyComputerScience = "STUDYCOMPUTERSCIENCE",
DataStructures = "DATASTRUCTURES",
Networks = "NETWORKS",
Algorithms = "ALGORITHMS",
Management = "MANAGEMENT",
Leadership = "LEADERSHIP",
GymStrength = "GYMSTRENGTH",
GymDefense = "GYMDEFENSE",
GymDexterity = "GYMDEXTERITY",
GymAgility = "GYMAGILITY",
}
export interface Class { export interface Class {
youAreCurrently: string;
type: ClassType; type: ClassType;
youAreCurrently: string;
earnings: WorkStats; earnings: WorkStats;
} }
export const Classes: Record<ClassType, Class> = { export const Classes: Record<ClassType, Class> = {
[ClassType.StudyComputerScience]: { [UniversityClassType.computerScience]: {
youAreCurrently: "studying Computer Science", type: UniversityClassType.computerScience,
type: ClassType.StudyComputerScience, youAreCurrently: `studying Computer Science`,
earnings: newWorkStats({ hackExp: 0.5, intExp: 0.01 }), earnings: newWorkStats({ hackExp: 0.5, intExp: 0.01 }),
}, },
[ClassType.DataStructures]: { [UniversityClassType.dataStructures]: {
type: UniversityClassType.dataStructures,
youAreCurrently: "taking a Data Structures course", youAreCurrently: "taking a Data Structures course",
type: ClassType.DataStructures, earnings: newWorkStats({ money: -40, hackExp: 1, intExp: 0.01 }),
earnings: newWorkStats({
money: -40,
hackExp: 1,
intExp: 0.01,
}),
}, },
[ClassType.Networks]: { [UniversityClassType.networks]: {
type: UniversityClassType.networks,
youAreCurrently: "taking a Networks course", youAreCurrently: "taking a Networks course",
type: ClassType.Networks, earnings: newWorkStats({ money: -80, hackExp: 2, intExp: 0.01 }),
earnings: newWorkStats({
money: -80,
hackExp: 2,
intExp: 0.01,
}),
}, },
[ClassType.Algorithms]: { [UniversityClassType.algorithms]: {
type: UniversityClassType.algorithms,
youAreCurrently: "taking an Algorithms course", youAreCurrently: "taking an Algorithms course",
type: ClassType.Algorithms, earnings: newWorkStats({ money: -320, hackExp: 4, intExp: 0.01 }),
earnings: newWorkStats({
money: -320,
hackExp: 4,
intExp: 0.01,
}),
}, },
[ClassType.Management]: { [UniversityClassType.management]: {
type: UniversityClassType.management,
youAreCurrently: "taking a Management course", youAreCurrently: "taking a Management course",
type: ClassType.Management, earnings: newWorkStats({ money: -160, chaExp: 2, intExp: 0.01 }),
earnings: newWorkStats({
money: -160,
chaExp: 2,
intExp: 0.01,
}),
}, },
[ClassType.Leadership]: { [UniversityClassType.leadership]: {
type: UniversityClassType.leadership,
youAreCurrently: "taking a Leadership course", youAreCurrently: "taking a Leadership course",
type: ClassType.Leadership, earnings: newWorkStats({ money: -320, chaExp: 4, intExp: 0.01 }),
earnings: newWorkStats({
money: -320,
chaExp: 4,
intExp: 0.01,
}),
}, },
[ClassType.GymStrength]: { [GymType.strength]: {
type: GymType.strength,
youAreCurrently: "training your strength at a gym", youAreCurrently: "training your strength at a gym",
type: ClassType.GymStrength, earnings: newWorkStats({ money: -120, strExp: 1 }),
earnings: newWorkStats({
money: -120,
strExp: 1,
}),
}, },
[ClassType.GymDefense]: { [GymType.defense]: {
type: GymType.defense,
youAreCurrently: "training your defense at a gym", youAreCurrently: "training your defense at a gym",
type: ClassType.GymDefense, earnings: newWorkStats({ money: -120, defExp: 1 }),
earnings: newWorkStats({
money: -120,
defExp: 1,
}),
}, },
[ClassType.GymDexterity]: { [GymType.dexterity]: {
type: GymType.dexterity,
youAreCurrently: "training your dexterity at a gym", youAreCurrently: "training your dexterity at a gym",
type: ClassType.GymDexterity, earnings: newWorkStats({ money: -120, dexExp: 1 }),
earnings: newWorkStats({
money: -120,
dexExp: 1,
}),
}, },
[ClassType.GymAgility]: { [GymType.agility]: {
type: GymType.agility,
youAreCurrently: "training your agility at a gym", youAreCurrently: "training your agility at a gym",
type: ClassType.GymAgility, earnings: newWorkStats({ money: -120, agiExp: 1 }),
earnings: newWorkStats({
money: -120,
agiExp: 1,
}),
}, },
}; };
@ -132,14 +89,12 @@ export class ClassWork extends Work {
constructor(params?: ClassWorkParams) { constructor(params?: ClassWorkParams) {
super(WorkType.CLASS, params?.singularity ?? true); super(WorkType.CLASS, params?.singularity ?? true);
this.classType = params?.classType ?? ClassType.StudyComputerScience; this.classType = params?.classType ?? UniversityClassType.computerScience;
this.location = params?.location ?? LocationName.Sector12RothmanUniversity; this.location = params?.location ?? LocationName.Sector12RothmanUniversity;
} }
isGym(): boolean { isGym(): boolean {
return [ClassType.GymAgility, ClassType.GymDefense, ClassType.GymDexterity, ClassType.GymStrength].includes( return checkEnum(GymType, this.classType);
this.classType,
);
} }
getClass(): Class { getClass(): Class {
@ -195,7 +150,12 @@ export class ClassWork extends Work {
/** Initializes a ClassWork object from a JSON save state. */ /** Initializes a ClassWork object from a JSON save state. */
static fromJSON(value: IReviverValue): ClassWork { static fromJSON(value: IReviverValue): ClassWork {
return Generic_fromJSON(ClassWork, value.data); const classWork = Generic_fromJSON(ClassWork, value.data);
classWork.classType =
findEnumMember(UniversityClassType, classWork.classType) ??
findEnumMember(GymType, classWork.classType) ??
UniversityClassType.computerScience;
return classWork;
} }
} }

@ -5,11 +5,11 @@ import { determineCrimeSuccess } from "../Crime/CrimeHelpers";
import { Crimes } from "../Crime/Crimes"; import { Crimes } from "../Crime/Crimes";
import { Player } from "@player"; import { Player } from "@player";
import { dialogBoxCreate } from "../ui/React/DialogBox"; import { dialogBoxCreate } from "../ui/React/DialogBox";
import { CrimeType } from "../utils/WorkType"; import { CrimeType } from "../utils/enums";
import { Work, WorkType } from "./Work"; import { Work, WorkType } from "./Work";
import { scaleWorkStats, WorkStats } from "./WorkStats"; import { scaleWorkStats, WorkStats } from "./WorkStats";
import { calculateCrimeWorkStats } from "./Formulas"; import { calculateCrimeWorkStats } from "./Formulas";
import { checkEnum } from "../utils/helpers/checkEnum"; import { checkEnum } from "../utils/helpers/enum";
interface CrimeWorkParams { interface CrimeWorkParams {
crimeType: CrimeType; crimeType: CrimeType;
@ -24,7 +24,7 @@ export class CrimeWork extends Work {
constructor(params?: CrimeWorkParams) { constructor(params?: CrimeWorkParams) {
super(WorkType.CRIME, params?.singularity ?? true); super(WorkType.CRIME, params?.singularity ?? true);
this.crimeType = params?.crimeType ?? CrimeType.SHOPLIFT; this.crimeType = params?.crimeType ?? CrimeType.shoplift;
this.unitCompleted = 0; this.unitCompleted = 0;
} }
@ -89,7 +89,7 @@ export class CrimeWork extends Work {
return { return {
type: this.type, type: this.type,
cyclesWorked: this.cyclesWorked, cyclesWorked: this.cyclesWorked,
crimeType: checkEnum(CrimeType, this.crimeType) ? this.crimeType : CrimeType.SHOPLIFT, crimeType: checkEnum(CrimeType, this.crimeType) ? this.crimeType : CrimeType.shoplift,
}; };
} }

@ -11,7 +11,7 @@ import { Reputation } from "../ui/React/Reputation";
import { CONSTANTS } from "../Constants"; import { CONSTANTS } from "../Constants";
import { AugmentationNames } from "../Augmentation/data/AugmentationNames"; import { AugmentationNames } from "../Augmentation/data/AugmentationNames";
import { calculateFactionExp, calculateFactionRep } from "./Formulas"; import { calculateFactionExp, calculateFactionRep } from "./Formulas";
import { FactionWorkType } from "./data/FactionWorkType"; import { FactionWorkType } from "../utils/enums";
interface FactionWorkParams { interface FactionWorkParams {
singularity: boolean; singularity: boolean;
@ -27,7 +27,7 @@ export class FactionWork extends Work {
constructor(params?: FactionWorkParams) { constructor(params?: FactionWorkParams) {
super(WorkType.FACTION, params?.singularity ?? true); super(WorkType.FACTION, params?.singularity ?? true);
this.factionWorkType = params?.factionWorkType ?? FactionWorkType.HACKING; this.factionWorkType = params?.factionWorkType ?? FactionWorkType.hacking;
this.factionName = params?.faction ?? FactionNames.Sector12; this.factionName = params?.faction ?? FactionNames.Sector12;
} }
@ -92,7 +92,9 @@ export class FactionWork extends Work {
/** Initializes a FactionWork object from a JSON save state. */ /** Initializes a FactionWork object from a JSON save state. */
static fromJSON(value: IReviverValue): FactionWork { static fromJSON(value: IReviverValue): FactionWork {
return Generic_fromJSON(FactionWork, value.data); const factionWork = Generic_fromJSON(FactionWork, value.data);
factionWork.factionWorkType = factionWork.factionWorkType.toLowerCase() as FactionWorkType;
return factionWork;
} }
} }

@ -3,7 +3,7 @@ import { Crime } from "../Crime/Crime";
import { newWorkStats, scaleWorkStats, WorkStats, multWorkStats } from "./WorkStats"; import { newWorkStats, scaleWorkStats, WorkStats, multWorkStats } from "./WorkStats";
import { Person as IPerson } from "../ScriptEditor/NetscriptDefinitions"; import { Person as IPerson } from "../ScriptEditor/NetscriptDefinitions";
import { CONSTANTS } from "../Constants"; import { CONSTANTS } from "../Constants";
import { FactionWorkType } from "./data/FactionWorkType"; import { FactionWorkType, GymType } from "../utils/enums";
import { import {
getFactionFieldWorkRepGain, getFactionFieldWorkRepGain,
getFactionSecurityWorkRepGain, getFactionSecurityWorkRepGain,
@ -19,11 +19,12 @@ import { serverMetadata } from "../Server/data/servers";
import { LocationName } from "../Locations/data/LocationNames"; import { LocationName } from "../Locations/data/LocationNames";
import { Company } from "../Company/Company"; import { Company } from "../Company/Company";
import { CompanyPosition } from "../Company/CompanyPosition"; import { CompanyPosition } from "../Company/CompanyPosition";
import { checkEnum } from "../utils/helpers/enum";
const gameCPS = 1000 / CONSTANTS._idleSpeed; // 5 cycles per second const gameCPS = 1000 / CONSTANTS._idleSpeed; // 5 cycles per second
export const FactionWorkStats: Record<FactionWorkType, WorkStats> = { export const FactionWorkStats: Record<FactionWorkType, WorkStats> = {
[FactionWorkType.HACKING]: newWorkStats({ hackExp: 15 }), [FactionWorkType.hacking]: newWorkStats({ hackExp: 15 }),
[FactionWorkType.FIELD]: newWorkStats({ [FactionWorkType.field]: newWorkStats({
hackExp: 10, hackExp: 10,
strExp: 10, strExp: 10,
defExp: 10, defExp: 10,
@ -31,7 +32,7 @@ export const FactionWorkStats: Record<FactionWorkType, WorkStats> = {
agiExp: 10, agiExp: 10,
chaExp: 10, chaExp: 10,
}), }),
[FactionWorkType.SECURITY]: newWorkStats({ [FactionWorkType.security]: newWorkStats({
hackExp: 5, hackExp: 5,
strExp: 15, strExp: 15,
defExp: 15, defExp: 15,
@ -66,9 +67,9 @@ export function calculateCrimeWorkStats(person: IPerson, crime: Crime): WorkStat
/** @returns faction rep rate per cycle */ /** @returns faction rep rate per cycle */
export const calculateFactionRep = (person: IPerson, type: FactionWorkType, favor: number): number => { export const calculateFactionRep = (person: IPerson, type: FactionWorkType, favor: number): number => {
const repFormulas = { const repFormulas = {
[FactionWorkType.HACKING]: getHackingWorkRepGain, [FactionWorkType.hacking]: getHackingWorkRepGain,
[FactionWorkType.FIELD]: getFactionFieldWorkRepGain, [FactionWorkType.field]: getFactionFieldWorkRepGain,
[FactionWorkType.SECURITY]: getFactionSecurityWorkRepGain, [FactionWorkType.security]: getFactionSecurityWorkRepGain,
}; };
return repFormulas[type](person, favor); return repFormulas[type](person, favor);
}; };
@ -95,11 +96,7 @@ export function calculateClassEarnings(person: IPerson, type: ClassType, locatio
const classs = Classes[type]; const classs = Classes[type];
const location = Locations[locationName]; const location = Locations[locationName];
const hashMult = [ClassType.GymAgility, ClassType.GymDefense, ClassType.GymStrength, ClassType.GymDexterity].includes( const hashMult = checkEnum(GymType, type) ? hashManager.getTrainingMult() : hashManager.getStudyMult();
type,
)
? hashManager.getTrainingMult()
: hashManager.getStudyMult();
const earnings = multWorkStats( const earnings = multWorkStats(
scaleWorkStats(classs.earnings, (location.expMult / gameCPS) * hashMult, false), scaleWorkStats(classs.earnings, (location.expMult / gameCPS) * hashMult, false),

@ -1,5 +0,0 @@
export enum FactionWorkType {
HACKING = "HACKING",
FIELD = "FIELD",
SECURITY = "SECURITY",
}

@ -1,20 +1,13 @@
/** Construct a type using the values from an object. Requires object to be defined "as const" */ /** Status object for functions that return a boolean indicating success/failure
export type ValuesFrom<T> = T[keyof T]; * and an optional message */
/**
* Status object for functions that return a boolean indicating success/failure
* and an optional message
*/
export interface IReturnStatus { export interface IReturnStatus {
res: boolean; res: boolean;
msg?: string; msg?: string;
} }
/** /** Defines the minimum and maximum values for a range.
* Defines the minimum and maximum values for a range.
* It is up to the consumer if these values are inclusive or exclusive. * It is up to the consumer if these values are inclusive or exclusive.
* It is up to the implementor to ensure max > min. * It is up to the implementor to ensure max > min. */
*/
export interface IMinMaxRange { export interface IMinMaxRange {
/** Value by which the bounds are to be divided for the final range */ /** Value by which the bounds are to be divided for the final range */
divisor?: number; divisor?: number;

@ -24,7 +24,7 @@ import { WorkStats } from "../Work/WorkStats";
import { isCreateProgramWork } from "../Work/CreateProgramWork"; import { isCreateProgramWork } from "../Work/CreateProgramWork";
import { isGraftingWork } from "../Work/GraftingWork"; import { isGraftingWork } from "../Work/GraftingWork";
import { isFactionWork } from "../Work/FactionWork"; import { isFactionWork } from "../Work/FactionWork";
import { FactionWorkType } from "../Work/data/FactionWorkType"; import { FactionWorkType } from "../utils/enums";
import { isCompanyWork } from "../Work/CompanyWork"; import { isCompanyWork } from "../Work/CompanyWork";
const CYCLES_PER_SEC = 1000 / CONSTANTS.MilliPerCycle; const CYCLES_PER_SEC = 1000 / CONSTANTS.MilliPerCycle;
@ -394,9 +394,9 @@ export function WorkInProgressRoot(): React.ReactElement {
} }
const description = { const description = {
[FactionWorkType.HACKING]: "carrying out hacking contracts", [FactionWorkType.hacking]: "carrying out hacking contracts",
[FactionWorkType.FIELD]: "carrying out field missions", [FactionWorkType.field]: "carrying out field missions",
[FactionWorkType.SECURITY]: "performing security detail", [FactionWorkType.security]: "performing security detail",
}; };
const exp = Player.currentWork.getExpRates(); const exp = Player.currentWork.getExpRates();

@ -1,18 +1,3 @@
export enum CrimeType {
SHOPLIFT = "SHOPLIFT", //"shoplift",
ROB_STORE = "ROBSTORE", //"rob a store",
MUG = "MUG", //"mug someone",
LARCENY = "LARCENY", //"commit larceny",
DRUGS = "DRUGS", //"deal drugs",
BOND_FORGERY = "BONDFORGERY", //"forge corporate bonds",
TRAFFIC_ARMS = "TRAFFICKARMS", //"traffick illegal arms",
HOMICIDE = "HOMICIDE", //"commit homicide",
GRAND_THEFT_AUTO = "GRANDTHEFTAUTO", //"commit grand theft auto",
KIDNAP = "KIDNAP", //"kidnap someone for ransom",
ASSASSINATION = "ASSASSINATION", //"assassinate a high-profile target",
HEIST = "HEIST", //"pull off the ultimate heist",
}
export enum CompanyPosNames { export enum CompanyPosNames {
sw0 = "Software Engineering Intern", sw0 = "Software Engineering Intern",
sw1 = "Junior Software Engineer", sw1 = "Junior Software Engineer",
@ -53,3 +38,41 @@ export enum CompanyPosNames {
waiterPT = "Part-time Waiter", waiterPT = "Part-time Waiter",
employeePT = "Part-time Employee", employeePT = "Part-time Employee",
} }
export enum CrimeType {
shoplift = "Shoplift",
robStore = "Rob Store",
mug = "Mug",
larceny = "Larceny",
dealDrugs = "Deal Drugs",
bondForgery = "Bond Forgery",
traffickArms = "Traffick Arms",
homicide = "Homicide",
grandTheftAuto = "Grand Theft Auto",
kidnap = "Kidnap",
assassination = "Assassination",
heist = "Heist",
}
export enum FactionWorkType {
hacking = "hacking",
field = "field",
security = "security",
}
export enum UniversityClassType {
computerScience = "Computer Science",
dataStructures = "Data Structures",
networks = "Networks",
algorithms = "Algorithms",
management = "Management",
leadership = "Leadership",
}
//Uses skill short codes to allow easier fuzzy matching with player input
export enum GymType {
strength = "str",
defense = "def",
dexterity = "dex",
agility = "agi",
}

@ -1,4 +0,0 @@
/** Verifies that a supplied value is a member of the provided object/enum. Works for enums as well as enum-like objects (const {} as const). */
export function checkEnum<T extends Record<string, unknown>>(obj: T, value: unknown): value is T[keyof T] {
return Object.values(obj).includes(value);
}

11
src/utils/helpers/enum.ts Normal file

@ -0,0 +1,11 @@
/** Verifies that a supplied value is a member of the provided object/enum. Works for enums as well as enum-like objects (const {} as const). */
export function checkEnum<T extends Record<string, unknown>>(obj: T, value: unknown): value is T[keyof T] {
return Object.values(obj).includes(value);
}
export function findEnumMember<T extends Record<string, string>>(obj: T, value: string): T[keyof T] | undefined {
const lowerValue = value.toLowerCase().replace(/ /g, "");
for (const member of Object.values(obj) as T[keyof T][]) {
if (lowerValue.includes(member.toLowerCase().replace(/ /g, ""))) return member;
}
}