WIP: Crimes streamlining. (#138)

* streamline crimes

* Crimes object is now indexed by CrimeType enum instead of an entirely new set of keys that aren't used for anything else. This eliminated a lot of instances of iterating to find the right crime for a given CrimeType.
* Removed unused `None` CrimeType which allowed typing Crimes as a Record<CrimeType, Crime>.
* Added slums tooltip text as a crime property, to allow streamlining slums.
* Refactor slums location - removed repetitive code, rerenders 1/sec to update chances
* Fix bugged descriptive text when sleeve is committing a crime (was "is attempting to DRUGS", now uses correct text e.g. "to deal drugs").
* Remove unused and now unneeded NewCrimeType enum. Values were identical to existing CrimeType values after removing unused None.

* Add CrimeType enum in NetscriptDefinition.d.ts

* Also update broken ToastVariant type. Better support for enums in player scripts.
* Still todo is modifying some NS functions to expect CrimeType as input (rough crime names will continue to work to avoid breaking scripts)

* Expect enum use for crime functions

Affected functions:
* ns.singularity.commitCrime
* ns.singularity.getCrimeChance
* ns.singularity.getCrimeStats
* ns.sleeve.setToCommitCrime
* formulas.work.crimeGains (param type only)

- Affected functions still will fall back to rough names, except formulas.work.crimeGains which already only accepted the enum members.
- Some documentation changes:
  * examples updated to use uppercase expected form.
  * Note on sleeve.setToCommitCrime that it only accepts exact matches removed. It already, and still does, accept any rough crime name (but the enum is expected input).
  * note about needing to use isBusy to schedule crimes remove - crimes autoloop now.
  * Since expected string inputs are documented directly on the type, removed list of crimes from sleeve.setToCommitCrimes
This commit is contained in:
Snarling 2022-10-21 11:57:37 -04:00 committed by GitHub
parent 06a985bdf8
commit d74c380e42
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 412 additions and 512 deletions

@ -25,22 +25,25 @@ interface IConstructorParams {
export class Crime { export class Crime {
// 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 = 0; difficulty: number;
// Amount of karma lost for SUCCESSFULLY committing this crime // Amount of karma lost for SUCCESSFULLY committing this crime
karma = 0; karma: number;
// How many people die as a result of this crime // How many people die as a result of this crime
kills = 0; kills: number;
// How much money is given by the // How much money is given by the
money = 0; money: number;
// Name of crime // Name of crime
name = ""; 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 = ""; workName: string;
// Tooltip text in slums ui
tooltipText: string;
// Milliseconds it takes to attempt the crime // Milliseconds it takes to attempt the crime
time = 0; time = 0;
@ -66,17 +69,19 @@ export class Crime {
intelligence_exp = 0; intelligence_exp = 0;
constructor( constructor(
name = "", name: string,
workName = "", workName: string,
tooltipText: string,
type: CrimeType, type: CrimeType,
time = 0, time: number,
money = 0, money: number,
difficulty = 0, difficulty: number,
karma = 0, karma: number,
params: IConstructorParams = {}, params: IConstructorParams,
) { ) {
this.name = name; this.name = name;
this.workName = workName; this.workName = workName;
this.tooltipText = tooltipText;
this.type = type; this.type = type;
this.time = time; this.time = time;
this.money = money; this.money = money;

@ -3,53 +3,46 @@ 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 { CrimeType } from "../utils/WorkType";
//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 {
let chance = 0; if (!checkEnum(CrimeType, type)) {
let found = false;
for (const i of Object.keys(Crimes)) {
const crime = Crimes[i];
if (crime.type === type) {
chance = crime.successRate(Player);
found = true;
break;
}
}
if (!found) {
dialogBoxCreate(`ERR: Unrecognized crime type: ${type} This is probably a bug please contact the developer`); dialogBoxCreate(`ERR: Unrecognized crime type: ${type} This is probably a bug please contact the developer`);
return false; return false;
} }
const crime = Crimes[type];
const chance = crime.successRate(Player);
return Math.random() <= chance; return Math.random() <= chance;
} }
export function findCrime(roughName: string): Crime | null { export function findCrime(roughName: string): Crime | null {
roughName = roughName.toLowerCase(); roughName = roughName.toLowerCase();
if (roughName.includes("shoplift")) { if (roughName.includes("shoplift")) {
return Crimes.Shoplift; return Crimes[CrimeType.SHOPLIFT];
} else if (roughName.includes("rob") && roughName.includes("store")) { } else if (roughName.includes("rob") && roughName.includes("store")) {
return Crimes.RobStore; return Crimes[CrimeType.ROB_STORE];
} else if (roughName.includes("mug")) { } else if (roughName.includes("mug")) {
return Crimes.Mug; return Crimes[CrimeType.MUG];
} else if (roughName.includes("larceny")) { } else if (roughName.includes("larceny")) {
return Crimes.Larceny; return Crimes[CrimeType.LARCENY];
} else if (roughName.includes("drugs")) { } else if (roughName.includes("drugs")) {
return Crimes.DealDrugs; return Crimes[CrimeType.DRUGS];
} else if (roughName.includes("bond") && roughName.includes("forge")) { } else if (roughName.includes("bond") && roughName.includes("forge")) {
return Crimes.BondForgery; return Crimes[CrimeType.BOND_FORGERY];
} else if ((roughName.includes("traffic") || roughName.includes("illegal")) && roughName.includes("arms")) { } else if ((roughName.includes("traffic") || roughName.includes("illegal")) && roughName.includes("arms")) {
return Crimes.TraffickArms; return Crimes[CrimeType.TRAFFIC_ARMS];
} else if (roughName.includes("homicide")) { } else if (roughName.includes("homicide")) {
return Crimes.Homicide; return Crimes[CrimeType.HOMICIDE];
} else if (roughName.includes("grand") && roughName.includes("auto")) { } else if (roughName.includes("grand") && roughName.includes("auto")) {
return Crimes.GrandTheftAuto; return Crimes[CrimeType.GRAND_THEFT_AUTO];
} else if (roughName.includes("kidnap")) { } else if (roughName.includes("kidnap")) {
return Crimes.Kidnap; return Crimes[CrimeType.KIDNAP];
} else if (roughName.includes("assassin")) { } else if (roughName.includes("assassin")) {
return Crimes.Assassination; return Crimes[CrimeType.ASSASSINATION];
} else if (roughName.includes("heist")) { } else if (roughName.includes("heist")) {
return Crimes.Heist; return Crimes[CrimeType.HEIST];
} }
return null; return null;

@ -3,17 +3,36 @@ import { Crime } from "./Crime";
import { CONSTANTS } from "../Constants"; import { CONSTANTS } from "../Constants";
import { CrimeType } from "../utils/WorkType"; import { CrimeType } from "../utils/WorkType";
// TODO: What is the point of CrimeType using totally different strings than
export const Crimes: Record<string, Crime> = { export const Crimes: Record<CrimeType, Crime> = {
Shoplift: new Crime("Shoplift", "to shoplift", CrimeType.SHOPLIFT, 2e3, 15e3, 1 / 20, 0.1, { [CrimeType.SHOPLIFT]: new Crime(
"Shoplift",
"to shoplift",
"Attempt to shoplift from a low-end retailer",
CrimeType.SHOPLIFT,
2e3,
15e3,
1 / 20,
0.1,
{
dexterity_success_weight: 1, dexterity_success_weight: 1,
agility_success_weight: 1, agility_success_weight: 1,
dexterity_exp: 2, dexterity_exp: 2,
agility_exp: 2, agility_exp: 2,
}), },
),
RobStore: new Crime("Rob Store", "to rob a store", CrimeType.ROB_STORE, 60e3, 400e3, 1 / 5, 0.5, { [CrimeType.ROB_STORE]: new Crime(
"Rob Store",
"to rob a store",
"Attempt to commit armed robbery on a high-end store",
CrimeType.ROB_STORE,
60e3,
400e3,
1 / 5,
0.5,
{
hacking_exp: 30, hacking_exp: 30,
dexterity_exp: 45, dexterity_exp: 45,
agility_exp: 45, agility_exp: 45,
@ -23,9 +42,19 @@ export const Crimes: Record<string, Crime> = {
agility_success_weight: 1, agility_success_weight: 1,
intelligence_exp: 7.5 * CONSTANTS.IntelligenceCrimeBaseExpGain, intelligence_exp: 7.5 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}), },
),
Mug: new Crime("Mug", "to mug", CrimeType.MUG, 4e3, 36e3, 1 / 5, 0.25, { [CrimeType.MUG]: new Crime(
"Mug",
"to mug",
"Attempt to mug a random person on the street",
CrimeType.MUG,
4e3,
36e3,
1 / 5,
0.25,
{
strength_exp: 3, strength_exp: 3,
defense_exp: 3, defense_exp: 3,
dexterity_exp: 3, dexterity_exp: 3,
@ -35,9 +64,19 @@ export const Crimes: Record<string, Crime> = {
defense_success_weight: 0.5, defense_success_weight: 0.5,
dexterity_success_weight: 1.5, dexterity_success_weight: 1.5,
agility_success_weight: 0.5, agility_success_weight: 0.5,
}), },
),
Larceny: new Crime("Larceny", "larceny", CrimeType.LARCENY, 90e3, 800e3, 1 / 3, 1.5, { [CrimeType.LARCENY]: new Crime(
"Larceny",
"larceny",
"Attempt to rob property from someone's house",
CrimeType.LARCENY,
90e3,
800e3,
1 / 3,
1.5,
{
hacking_exp: 45, hacking_exp: 45,
dexterity_exp: 60, dexterity_exp: 60,
agility_exp: 60, agility_exp: 60,
@ -47,9 +86,19 @@ export const Crimes: Record<string, Crime> = {
agility_success_weight: 1, agility_success_weight: 1,
intelligence_exp: 15 * CONSTANTS.IntelligenceCrimeBaseExpGain, intelligence_exp: 15 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}), },
),
DealDrugs: new Crime("Deal Drugs", "to deal drugs", CrimeType.DRUGS, 10e3, 120e3, 1, 0.5, { [CrimeType.DRUGS]: new Crime(
"Deal Drugs",
"to deal drugs",
"Attempt to deal drugs",
CrimeType.DRUGS,
10e3,
120e3,
1,
0.5,
{
dexterity_exp: 5, dexterity_exp: 5,
agility_exp: 5, agility_exp: 5,
charisma_exp: 10, charisma_exp: 10,
@ -57,9 +106,19 @@ export const Crimes: Record<string, Crime> = {
charisma_success_weight: 3, charisma_success_weight: 3,
dexterity_success_weight: 2, dexterity_success_weight: 2,
agility_success_weight: 1, agility_success_weight: 1,
}), },
),
BondForgery: new Crime("Bond Forgery", "to forge bonds", CrimeType.BOND_FORGERY, 300e3, 4.5e6, 1 / 2, 0.1, { [CrimeType.BOND_FORGERY]: new Crime(
"Bond Forgery",
"to forge bonds",
"Attempt to forge corporate bonds",
CrimeType.BOND_FORGERY,
300e3,
4.5e6,
1 / 2,
0.1,
{
hacking_exp: 100, hacking_exp: 100,
dexterity_exp: 150, dexterity_exp: 150,
charisma_exp: 15, charisma_exp: 15,
@ -68,9 +127,19 @@ export const Crimes: Record<string, Crime> = {
dexterity_success_weight: 1.25, dexterity_success_weight: 1.25,
intelligence_exp: 60 * CONSTANTS.IntelligenceCrimeBaseExpGain, intelligence_exp: 60 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}), },
),
TraffickArms: new Crime("Traffick Arms", "to traffic arms", CrimeType.TRAFFIC_ARMS, 40e3, 600e3, 2, 1, { [CrimeType.TRAFFIC_ARMS]: new Crime(
"Traffick Arms",
"to traffic arms",
"Attempt to smuggle illegal arms into the city",
CrimeType.TRAFFIC_ARMS,
40e3,
600e3,
2,
1,
{
strength_exp: 20, strength_exp: 20,
defense_exp: 20, defense_exp: 20,
dexterity_exp: 20, dexterity_exp: 20,
@ -82,9 +151,19 @@ export const Crimes: Record<string, Crime> = {
defense_success_weight: 1, defense_success_weight: 1,
dexterity_success_weight: 1, dexterity_success_weight: 1,
agility_success_weight: 1, agility_success_weight: 1,
}), },
),
Homicide: new Crime("Homicide", "homicide", CrimeType.HOMICIDE, 3e3, 45e3, 1, 3, { [CrimeType.HOMICIDE]: new Crime(
"Homicide",
"homicide",
"Attempt to murder a random person on the street",
CrimeType.HOMICIDE,
3e3,
45e3,
1,
3,
{
strength_exp: 2, strength_exp: 2,
defense_exp: 2, defense_exp: 2,
dexterity_exp: 2, dexterity_exp: 2,
@ -96,9 +175,19 @@ export const Crimes: Record<string, Crime> = {
agility_success_weight: 0.5, agility_success_weight: 0.5,
kills: 1, kills: 1,
}), },
),
GrandTheftAuto: new Crime("Grand Theft Auto", "grand theft auto", CrimeType.GRAND_THEFT_AUTO, 80e3, 1.6e6, 8, 5, { [CrimeType.GRAND_THEFT_AUTO]: new Crime(
"Grand Theft Auto",
"grand theft auto",
"Attempt to commit grand theft auto",
CrimeType.GRAND_THEFT_AUTO,
80e3,
1.6e6,
8,
5,
{
strength_exp: 20, strength_exp: 20,
defense_exp: 20, defense_exp: 20,
dexterity_exp: 20, dexterity_exp: 20,
@ -112,9 +201,19 @@ export const Crimes: Record<string, Crime> = {
charisma_success_weight: 2, charisma_success_weight: 2,
intelligence_exp: 16 * CONSTANTS.IntelligenceCrimeBaseExpGain, intelligence_exp: 16 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}), },
),
Kidnap: new Crime("Kidnap", "to kidnap", CrimeType.KIDNAP, 120e3, 3.6e6, 5, 6, { [CrimeType.KIDNAP]: new Crime(
"Kidnap",
"to kidnap",
"Attempt to kidnap and ransom a high-profile-target",
CrimeType.KIDNAP,
120e3,
3.6e6,
5,
6,
{
strength_exp: 80, strength_exp: 80,
defense_exp: 80, defense_exp: 80,
dexterity_exp: 80, dexterity_exp: 80,
@ -127,9 +226,19 @@ export const Crimes: Record<string, Crime> = {
agility_success_weight: 1, agility_success_weight: 1,
intelligence_exp: 26 * CONSTANTS.IntelligenceCrimeBaseExpGain, intelligence_exp: 26 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}), },
),
Assassination: new Crime("Assassination", "to assassinate", CrimeType.ASSASSINATION, 300e3, 12e6, 8, 10, { [CrimeType.ASSASSINATION]: new Crime(
"Assassination",
"to assassinate",
"Attempt to assassinate a high-profile target",
CrimeType.ASSASSINATION,
300e3,
12e6,
8,
10,
{
strength_exp: 300, strength_exp: 300,
defense_exp: 300, defense_exp: 300,
dexterity_exp: 300, dexterity_exp: 300,
@ -142,9 +251,19 @@ export const Crimes: Record<string, Crime> = {
intelligence_exp: 65 * CONSTANTS.IntelligenceCrimeBaseExpGain, intelligence_exp: 65 * CONSTANTS.IntelligenceCrimeBaseExpGain,
kills: 1, kills: 1,
}), },
),
Heist: new Crime("Heist", "a heist", CrimeType.HEIST, 600e3, 120e6, 18, 15, { [CrimeType.HEIST]: new Crime(
"Heist",
"a heist",
"Attempt to pull off the ultimate heist",
CrimeType.HEIST,
600e3,
120e6,
18,
15,
{
hacking_exp: 450, hacking_exp: 450,
strength_exp: 450, strength_exp: 450,
defense_exp: 450, defense_exp: 450,
@ -160,5 +279,6 @@ export const Crimes: Record<string, Crime> = {
charisma_success_weight: 1, charisma_success_weight: 1,
intelligence_exp: 130 * CONSTANTS.IntelligenceCrimeBaseExpGain, intelligence_exp: 130 * CONSTANTS.IntelligenceCrimeBaseExpGain,
}), },
),
}; };

@ -3,7 +3,7 @@
* *
* This subcomponent renders all of the buttons for committing crimes * This subcomponent renders all of the buttons for committing crimes
*/ */
import * as React from "react"; import React, { useState, useEffect } from "react";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import Tooltip from "@mui/material/Tooltip"; import Tooltip from "@mui/material/Tooltip";
@ -13,185 +13,33 @@ import { numeralWrapper } from "../../ui/numeralFormat";
import { Router } from "../../ui/GameRoot"; import { Router } from "../../ui/GameRoot";
import { Player } from "@player"; import { Player } from "@player";
import { Box } from "@mui/material"; import { Box } from "@mui/material";
import { Crime } from "../../Crime/Crime";
export function SlumsLocation(): React.ReactElement { export function SlumsLocation(): React.ReactElement {
function shoplift(e: React.MouseEvent<HTMLElement>): void { const setRerender = useState(false)[1];
if (!e.isTrusted) { const rerender = () => setRerender((o) => !o);
return; const crimes = Object.values(Crimes);
} useEffect(() => {
Crimes.Shoplift.commit(); const timerId = setInterval(() => rerender(), 1000);
return () => clearInterval(timerId);
});
function doCrime(e: React.MouseEvent<HTMLElement>, crime: Crime) {
if (!e.isTrusted) return;
crime.commit();
Router.toWork(); Router.toWork();
Player.focus = true; Player.focus = true;
} }
function robStore(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) {
return;
}
Crimes.RobStore.commit();
Router.toWork();
Player.focus = true;
}
function mug(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) {
return;
}
Crimes.Mug.commit();
Router.toWork();
Player.focus = true;
}
function larceny(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) {
return;
}
Crimes.Larceny.commit();
Router.toWork();
Player.focus = true;
}
function dealDrugs(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) {
return;
}
Crimes.DealDrugs.commit();
Router.toWork();
Player.focus = true;
}
function bondForgery(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) {
return;
}
Crimes.BondForgery.commit();
Router.toWork();
Player.focus = true;
}
function traffickArms(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) {
return;
}
Crimes.TraffickArms.commit();
Router.toWork();
Player.focus = true;
}
function homicide(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) {
return;
}
Crimes.Homicide.commit();
Router.toWork();
Player.focus = true;
}
function grandTheftAuto(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) {
return;
}
Crimes.GrandTheftAuto.commit();
Router.toWork();
Player.focus = true;
}
function kidnap(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) {
return;
}
Crimes.Kidnap.commit();
Router.toWork();
Player.focus = true;
}
function assassinate(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) {
return;
}
Crimes.Assassination.commit();
Router.toWork();
Player.focus = true;
}
function heist(e: React.MouseEvent<HTMLElement>): void {
if (!e.isTrusted) {
return;
}
Crimes.Heist.commit();
Router.toWork();
Player.focus = true;
}
const shopliftChance = Crimes.Shoplift.successRate(Player);
const robStoreChance = Crimes.RobStore.successRate(Player);
const mugChance = Crimes.Mug.successRate(Player);
const larcenyChance = Crimes.Larceny.successRate(Player);
const drugsChance = Crimes.DealDrugs.successRate(Player);
const bondChance = Crimes.BondForgery.successRate(Player);
const armsChance = Crimes.TraffickArms.successRate(Player);
const homicideChance = Crimes.Homicide.successRate(Player);
const gtaChance = Crimes.GrandTheftAuto.successRate(Player);
const kidnapChance = Crimes.Kidnap.successRate(Player);
const assassinateChance = Crimes.Assassination.successRate(Player);
const heistChance = Crimes.Heist.successRate(Player);
return ( return (
<Box sx={{ display: "grid", width: "fit-content" }}> <Box sx={{ display: "grid", width: "fit-content" }}>
<Tooltip title={<>Attempt to shoplift from a low-end retailer</>}> {crimes.map((crime) => (
<Button onClick={shoplift}> <Tooltip title={crime.tooltipText}>
Shoplift ({numeralWrapper.formatPercentage(shopliftChance)} chance of success) <Button onClick={(e) => doCrime(e, crime)}>
{crime.name} ({numeralWrapper.formatPercentage(crime.successRate(Player))} chance of success)
</Button> </Button>
</Tooltip> </Tooltip>
<Tooltip title={<>Attempt to commit armed robbery on a high-end store</>}> ))}
<Button onClick={robStore}>
Rob store ({numeralWrapper.formatPercentage(robStoreChance)} chance of success)
</Button>
</Tooltip>
<Tooltip title={<>Attempt to mug a random person on the street</>}>
<Button onClick={mug}>Mug someone ({numeralWrapper.formatPercentage(mugChance)} chance of success)</Button>
</Tooltip>
<Tooltip title={<>Attempt to rob property from someone's house</>}>
<Button onClick={larceny}>Larceny ({numeralWrapper.formatPercentage(larcenyChance)} chance of success)</Button>
</Tooltip>
<Tooltip title={<>Attempt to deal drugs</>}>
<Button onClick={dealDrugs}>
Deal Drugs ({numeralWrapper.formatPercentage(drugsChance)} chance of success)
</Button>
</Tooltip>
<Tooltip title={<>Attempt to forge corporate bonds</>}>
<Button onClick={bondForgery}>
Bond Forgery ({numeralWrapper.formatPercentage(bondChance)} chance of success)
</Button>
</Tooltip>
<Tooltip title={<>Attempt to smuggle illegal arms into the city</>}>
<Button onClick={traffickArms}>
Traffick illegal Arms ({numeralWrapper.formatPercentage(armsChance)} chance of success)
</Button>
</Tooltip>
<Tooltip title={<>Attempt to murder a random person on the street</>}>
<Button onClick={homicide}>
Homicide ({numeralWrapper.formatPercentage(homicideChance)} chance of success)
</Button>
</Tooltip>
<Tooltip title={<>Attempt to commit grand theft auto</>}>
<Button onClick={grandTheftAuto}>
Grand theft Auto ({numeralWrapper.formatPercentage(gtaChance)} chance of success)
</Button>
</Tooltip>
<Tooltip title={<>Attempt to kidnap and ransom a high-profile-target</>}>
<Button onClick={kidnap}>
Kidnap and Ransom ({numeralWrapper.formatPercentage(kidnapChance)} chance of success)
</Button>
</Tooltip>
<Tooltip title={<>Attempt to assassinate a high-profile target</>}>
<Button onClick={assassinate}>
Assassinate ({numeralWrapper.formatPercentage(assassinateChance)} chance of success)
</Button>
</Tooltip>
<Tooltip title={<>Attempt to pull off the ultimate heist</>}>
<Button onClick={heist}>Heist ({numeralWrapper.formatPercentage(heistChance)} chance of success)</Button>
</Tooltip>
</Box> </Box>
); );
} }

@ -77,11 +77,12 @@ 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 { CrimeType } from "./utils/WorkType";
// "Enums" as object
export const enums = { export const enums = {
toast: ToastVariant, toast: ToastVariant,
} as const; crimes: CrimeType,
};
export type NSFull = Readonly<NS & INetscriptExtra>; export type NSFull = Readonly<NS & INetscriptExtra>;
export function NetscriptFunctions(workerScript: WorkerScript): NSFull { export function NetscriptFunctions(workerScript: WorkerScript): NSFull {
@ -125,6 +126,7 @@ const base: InternalAPI<NS> = {
(ctx) => (ctx) =>
(_hostname, opts = {}) => { (_hostname, opts = {}) => {
const hostname = helpers.string(ctx, "hostname", _hostname); const hostname = helpers.string(ctx, "hostname", _hostname);
// Todo: better type safety rework for functions using assertObjectType, then remove function.
const optsValidator: BasicHGWOptions = {}; const optsValidator: BasicHGWOptions = {};
assertObjectType(ctx, "opts", opts, optsValidator); assertObjectType(ctx, "opts", opts, optsValidator);
return helpers.hack(ctx, hostname, false, { threads: opts.threads, stock: opts.stock }); return helpers.hack(ctx, hostname, false, { threads: opts.threads, stock: opts.stock });

@ -48,6 +48,8 @@ import { calculateFactionExp, calculateFactionRep } from "../Work/formulas/Facti
import { FactionWorkType } from "../Work/data/FactionWorkType"; import { FactionWorkType } from "../Work/data/FactionWorkType";
import { defaultMultipliers } from "../PersonObjects/Multipliers"; import { defaultMultipliers } from "../PersonObjects/Multipliers";
import { checkEnum } from "../utils/helpers/checkEnum";
import { CrimeType } from "../utils/WorkType";
export function NetscriptFormulas(): InternalAPI<IFormulas> { export function NetscriptFormulas(): InternalAPI<IFormulas> {
const checkFormulasAccess = function (ctx: NetscriptContext): void { const checkFormulasAccess = function (ctx: NetscriptContext): void {
@ -362,9 +364,8 @@ export function NetscriptFormulas(): InternalAPI<IFormulas> {
work: { work: {
crimeGains: (ctx) => (_crimeType) => { crimeGains: (ctx) => (_crimeType) => {
const crimeType = helpers.string(ctx, "crimeType", _crimeType); const crimeType = helpers.string(ctx, "crimeType", _crimeType);
const crime = Object.values(Crimes).find((c) => String(c.type) === crimeType); if (!checkEnum(CrimeType, crimeType)) throw new Error(`Invalid crime type: ${crimeType}`);
if (!crime) throw new Error(`Invalid crime type: ${crimeType}`); return calculateCrimeWorkStats(Crimes[crimeType]);
return calculateCrimeWorkStats(crime);
}, },
classGains: (ctx) => (_person, _classType, _locationName) => { classGains: (ctx) => (_person, _classType, _locationName) => {
const person = helpers.player(ctx, _person); const person = helpers.player(ctx, _person);

@ -50,6 +50,9 @@ 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/Crime"; import { calculateCrimeWorkStats } from "../Work/formulas/Crime";
import { checkEnum } from "../utils/helpers/checkEnum";
import { Crimes } from "../Crime/Crimes";
import { CrimeType } from "../utils/WorkType";
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 {
@ -1115,26 +1118,19 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
helpers.log(ctx, () => `Began creating program: '${programName}'`); helpers.log(ctx, () => `Began creating program: '${programName}'`);
return true; return true;
}, },
commitCrime: commitCrime: (ctx) => (_crimeType, _focus) => {
(ctx) =>
(_crimeRoughName, _focus = true) => {
helpers.checkSingularityAccess(ctx); helpers.checkSingularityAccess(ctx);
const crimeRoughName = helpers.string(ctx, "crimeRoughName", _crimeRoughName); const crimeType = helpers.string(ctx, "crimeType", _crimeType);
const focus = !!_focus; const focus = _focus === undefined ? true : !!_focus;
const wasFocusing = Player.focus; const wasFocusing = Player.focus;
if (Player.currentWork !== null) { if (Player.currentWork !== null) Player.finishWork(true);
Player.finishWork(true);
}
// Set Location to slums
Player.gotoLocation(LocationName.Slums); Player.gotoLocation(LocationName.Slums);
const crime = findCrime(crimeRoughName.toLowerCase()); // If input isn't a crimeType, use search using roughname.
if (crime == null) { const crime = checkEnum(CrimeType, crimeType) ? Crimes[crimeType] : findCrime(crimeType);
// couldn't find crime if (crime == null) throw helpers.makeRuntimeErrorMsg(ctx, `Invalid crime: '${crimeType}'`);
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid crime: '${crimeRoughName}'`);
}
helpers.log(ctx, () => `Attempting to commit ${crime.name}...`); helpers.log(ctx, () => `Attempting to commit ${crime.name}...`);
const crimeTime = crime.commit(1, ctx.workerScript); const crimeTime = crime.commit(1, ctx.workerScript);
if (focus) { if (focus) {
@ -1146,25 +1142,23 @@ export function NetscriptSingularity(): InternalAPI<ISingularity> {
} }
return crimeTime; return crimeTime;
}, },
getCrimeChance: (ctx) => (_crimeRoughName) => { getCrimeChance: (ctx) => (_crimeType) => {
helpers.checkSingularityAccess(ctx); helpers.checkSingularityAccess(ctx);
const crimeRoughName = helpers.string(ctx, "crimeRoughName", _crimeRoughName); const crimeType = helpers.string(ctx, "crimeType", _crimeType);
const crime = findCrime(crimeRoughName.toLowerCase()); // If input isn't a crimeType, use search using roughname.
if (crime == null) { const crime = checkEnum(CrimeType, crimeType) ? Crimes[crimeType] : findCrime(crimeType);
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid crime: ${crimeRoughName}`); if (crime == null) throw helpers.makeRuntimeErrorMsg(ctx, `Invalid crime: '${crimeType}'`);
}
return crime.successRate(Player); return crime.successRate(Player);
}, },
getCrimeStats: (ctx) => (_crimeRoughName) => { getCrimeStats: (ctx) => (_crimeType) => {
helpers.checkSingularityAccess(ctx); helpers.checkSingularityAccess(ctx);
const crimeRoughName = helpers.string(ctx, "crimeRoughName", _crimeRoughName); const crimeType = helpers.string(ctx, "crimeType", _crimeType);
const crime = findCrime(crimeRoughName.toLowerCase()); // If input isn't a crimeType, use search using roughname.
if (crime == null) { const crime = checkEnum(CrimeType, crimeType) ? Crimes[crimeType] : findCrime(crimeType);
throw helpers.makeRuntimeErrorMsg(ctx, `Invalid crime: ${crimeRoughName}`); if (crime == null) throw helpers.makeRuntimeErrorMsg(ctx, `Invalid crime: '${crimeType}'`);
}
const crimeStatsWithMultipliers = calculateCrimeWorkStats(crime); const crimeStatsWithMultipliers = calculateCrimeWorkStats(crime);

@ -11,6 +11,8 @@ import { isSleeveBladeburnerWork } from "../PersonObjects/Sleeve/Work/SleeveBlad
import { isSleeveFactionWork } from "../PersonObjects/Sleeve/Work/SleeveFactionWork"; import { isSleeveFactionWork } from "../PersonObjects/Sleeve/Work/SleeveFactionWork";
import { isSleeveCompanyWork } from "../PersonObjects/Sleeve/Work/SleeveCompanyWork"; import { isSleeveCompanyWork } from "../PersonObjects/Sleeve/Work/SleeveCompanyWork";
import { helpers } from "../Netscript/NetscriptHelpers"; import { helpers } from "../Netscript/NetscriptHelpers";
import { Crimes } from "../Crime/Crimes";
import { CrimeType } from "../utils/WorkType";
export function NetscriptSleeve(): InternalAPI<ISleeve> { export function NetscriptSleeve(): InternalAPI<ISleeve> {
const checkSleeveAPIAccess = function (ctx: NetscriptContext) { const checkSleeveAPIAccess = function (ctx: NetscriptContext) {
@ -62,15 +64,13 @@ export function NetscriptSleeve(): InternalAPI<ISleeve> {
checkSleeveNumber(ctx, sleeveNumber); checkSleeveNumber(ctx, sleeveNumber);
return Player.sleeves[sleeveNumber].synchronize(); return Player.sleeves[sleeveNumber].synchronize();
}, },
setToCommitCrime: (ctx) => (_sleeveNumber, _crimeRoughName) => { setToCommitCrime: (ctx) => (_sleeveNumber, _crimeType) => {
const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber); const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber);
const crimeRoughName = helpers.string(ctx, "crimeName", _crimeRoughName); const crimeType = helpers.string(ctx, "crimeType", _crimeType);
checkSleeveAPIAccess(ctx); checkSleeveAPIAccess(ctx);
checkSleeveNumber(ctx, sleeveNumber); checkSleeveNumber(ctx, sleeveNumber);
const crime = findCrime(crimeRoughName); const crime = checkEnum(CrimeType, crimeType) ? Crimes[crimeType] : findCrime(crimeType);
if (crime === null) { if (crime == null) return false;
return false;
}
return Player.sleeves[sleeveNumber].commitCrime(crime.name); return Player.sleeves[sleeveNumber].commitCrime(crime.name);
}, },
setToUniversityCourse: (ctx) => (_sleeveNumber, _universityName, _className) => { setToUniversityCourse: (ctx) => (_sleeveNumber, _universityName, _className) => {

@ -12,21 +12,18 @@ import { Person } from "../Person";
import { Augmentation } from "../../Augmentation/Augmentation"; import { Augmentation } from "../../Augmentation/Augmentation";
import { Crime } from "../../Crime/Crime";
import { Crimes } from "../../Crime/Crimes";
import { Companies } from "../../Company/Companies"; import { Companies } from "../../Company/Companies";
import { Company } from "../../Company/Company"; import { Company } from "../../Company/Company";
import { CompanyPosition } from "../../Company/CompanyPosition"; 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 { checkEnum } from "../../utils/helpers/checkEnum";
import { CrimeType } from "../../utils/WorkType";
import { CityName } from "../../Locations/data/CityNames";
import { Factions } from "../../Faction/Factions"; import { Factions } from "../../Faction/Factions";
import { CityName } from "../../Locations/data/CityNames";
import { LocationName } from "../../Locations/data/LocationNames"; 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";
@ -97,13 +94,9 @@ export class Sleeve extends Person {
} }
/** Commit crimes */ /** Commit crimes */
commitCrime(crimeKey: string): boolean { commitCrime(type: string): boolean {
const crime: Crime | null = Crimes[crimeKey] || Object.values(Crimes).find((crime) => crime.name === crimeKey); if (!checkEnum(CrimeType, type)) return false;
if (!crime) { this.startWork(new SleeveCrimeWork(type));
return false;
}
this.startWork(new SleeveCrimeWork(crime.type));
return true; return true;
} }

@ -8,6 +8,7 @@ import { Crime } from "../../../Crime/Crime";
import { newWorkStats, scaleWorkStats, WorkStats } from "../../../Work/WorkStats"; import { newWorkStats, scaleWorkStats, WorkStats } from "../../../Work/WorkStats";
import { CONSTANTS } from "../../../Constants"; import { CONSTANTS } from "../../../Constants";
import { BitNodeMultipliers } from "../../../BitNode/BitNodeMultipliers"; import { BitNodeMultipliers } from "../../../BitNode/BitNodeMultipliers";
import { checkEnum } from "../../../utils/helpers/checkEnum";
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;
@ -20,9 +21,8 @@ export class SleeveCrimeWork extends Work {
} }
getCrime(): Crime { getCrime(): Crime {
const crime = Object.values(Crimes).find((crime) => crime.type === this.crimeType); if (!checkEnum(CrimeType, this.crimeType)) throw new Error("crime should not be undefined");
if (!crime) throw new Error("crime should not be undefined"); return Crimes[this.crimeType];
return crime;
} }
getExp(sleeve: Sleeve): WorkStats { getExp(sleeve: Sleeve): WorkStats {

@ -74,7 +74,7 @@ export function SleeveElem(props: IProps): React.ReactElement {
const crime = w.getCrime(); const crime = w.getCrime();
desc = ( desc = (
<> <>
This sleeve is currently attempting to {crime.type} (Success Rate:{" "} This sleeve is currently attempting {crime.workName} (Success Rate:{" "}
{numeralWrapper.formatPercentage(crime.successRate(props.sleeve))}). {numeralWrapper.formatPercentage(crime.successRate(props.sleeve))}).
</> </>
); );

@ -19,6 +19,8 @@ import { isSleeveSupportWork } from "../Work/SleeveSupportWork";
import { ClassType } from "../../../Work/ClassWork"; import { ClassType } from "../../../Work/ClassWork";
import { isSleeveCrimeWork } from "../Work/SleeveCrimeWork"; import { isSleeveCrimeWork } from "../Work/SleeveCrimeWork";
import { FactionWorkType } from "../../../Work/data/FactionWorkType"; import { FactionWorkType } from "../../../Work/data/FactionWorkType";
import { checkEnum } from "../../../utils/helpers/checkEnum";
import { CrimeType } from "../../../utils/WorkType";
const universitySelectorOptions: string[] = [ const universitySelectorOptions: string[] = [
"Study Computer Science", "Study Computer Science",
@ -314,11 +316,7 @@ function getABC(sleeve: Sleeve): [string, string, string] {
} }
} }
if (isSleeveCrimeWork(w)) { if (isSleeveCrimeWork(w)) {
return [ return ["Commit Crime", checkEnum(CrimeType, w.crimeType) ? Crimes[w.crimeType].name : "Shoplift", "------"];
"Commit Crime",
Object.values(Crimes).find((crime) => crime.type === w.crimeType)?.name ?? "Shoplift",
"------",
];
} }
if (isSleeveSupportWork(w)) { if (isSleeveSupportWork(w)) {
return ["Perform Bladeburner Actions", "Support main sleeve", "------"]; return ["Perform Bladeburner Actions", "Support main sleeve", "------"];

@ -1,6 +1,3 @@
/** @public */
export type ValuesFrom<T> = T[keyof T];
/** @public */ /** @public */
export interface HP { export interface HP {
current: number; current: number;
@ -1979,19 +1976,13 @@ export interface Singularity {
* *
* This function returns the number of milliseconds it takes to attempt the * This function returns the number of milliseconds it takes to attempt the
* specified crime (e.g It takes 60 seconds to attempt the Rob Store crime, * specified crime (e.g It takes 60 seconds to attempt the Rob Store crime,
* so running `commitCrime('rob store')` will return 60,000). * so running `commitCrime('ROBSTORE')` will return 60,000).
*
* Warning: I do not recommend using the time returned from this function to try
* and schedule your crime attempts. Instead, I would use the isBusy Singularity
* function to check whether you have finished attempting a crime. This is because
* although the game sets a certain crime to be X amount of seconds, there is no
* guarantee that your browser will follow that time limit.
* *
* @param crime - Name of crime to attempt. * @param crime - Name of crime to attempt.
* @param focus - Acquire player focus on this crime. Optional. Defaults to true. * @param focus - Acquire player focus on this crime. Optional. Defaults to true.
* @returns The number of milliseconds it takes to attempt the specified crime. * @returns The number of milliseconds it takes to attempt the specified crime.
*/ */
commitCrime(crime: string, focus?: boolean): number; commitCrime(crime: CrimeType | CrimeNames, focus?: boolean): number;
/** /**
* Get chance to successfully commit a crime. * Get chance to successfully commit a crime.
@ -2004,7 +1995,7 @@ export interface Singularity {
* @param crime - Name of crime. * @param crime - Name of crime.
* @returns Chance of success at committing the specified crime. * @returns Chance of success at committing the specified crime.
*/ */
getCrimeChance(crime: string): number; getCrimeChance(crime: CrimeType | CrimeNames): number;
/** /**
* Get stats related to a crime. * Get stats related to a crime.
@ -2014,10 +2005,10 @@ export interface Singularity {
* *
* Returns the stats of the crime. * Returns the stats of the crime.
* *
* @param crime - Name of crime. Not case-sensitive * @param crime - Name of crime.
* @returns The stats of the crime. * @returns The stats of the crime.
*/ */
getCrimeStats(crime: string): CrimeStats; getCrimeStats(crime: CrimeType | CrimeNames): CrimeStats;
/** /**
* Get a list of owned augmentation. * Get a list of owned augmentation.
@ -2037,6 +2028,7 @@ export interface Singularity {
* @remarks * @remarks
* RAM cost: 5 GB * RAM cost: 5 GB
* *
*
* Returns an array of source files * Returns an array of source files
* *
* @returns Array containing an object with number and level of the source file. * @returns Array containing an object with number and level of the source file.
@ -3651,32 +3643,13 @@ export interface Sleeve {
* @remarks * @remarks
* RAM cost: 4 GB * RAM cost: 4 GB
* *
* Return a boolean indicating whether or not this action was set successfully. * Return a boolean indicating whether or not this action was set successfully (false if an invalid action is specified).
*
* Returns false if an invalid action is specified.
*
* You can set a sleeve to commit one of the following crimes. The crime names are not
* case sensitive. For example, you can pass in the crime name as `"Shoplift"`,
* `"shoplift"`, `"shopLift"`, or even `"SHOPLIFT"`.
*
* - Assassination
* - Bond forgery
* - Deal drugs
* - Grand theft auto
* - Heist
* - Homicide
* - Kidnap
* - Larceny
* - Mug
* - Rob store
* - Shoplift
* - Traffick arms
* *
* @example * @example
* ```ts * ```ts
* // NS1 * // NS1
* // Assign the first 3 sleeves to commit various crimes. * // Assign the first 3 sleeves to commit various crimes.
* var crime = ["mug", "rob store", "shoplift"]; * var crime = ["MUG", "ROBSTORE", "SHOPLIFT"];
* for (var i = 0; i < crime.length; i++) { * for (var i = 0; i < crime.length; i++) {
* tprintf("Sleeve %d commits crime: %s", i, crime[i]); * tprintf("Sleeve %d commits crime: %s", i, crime[i]);
* sleeve.setToCommitCrime(i, crime[i]); * sleeve.setToCommitCrime(i, crime[i]);
@ -3686,7 +3659,7 @@ export interface Sleeve {
* ```ts * ```ts
* // NS2 * // NS2
* // Assign the first 3 sleeves to commit various crimes. * // Assign the first 3 sleeves to commit various crimes.
* const crime = ["mug", "rob store", "shoplift"]; * const crime = ["MUG", "ROBSTORE", "SHOPLIFT"];
* for (let i = 0; i < crime.length; i++) { * for (let i = 0; i < crime.length; i++) {
* ns.tprintf("Sleeve %d commits crime: %s", i, crime[i]); * ns.tprintf("Sleeve %d commits crime: %s", i, crime[i]);
* ns.sleeve.setToCommitCrime(i, crime[i]); * ns.sleeve.setToCommitCrime(i, crime[i]);
@ -3694,10 +3667,10 @@ export interface Sleeve {
* ``` * ```
* *
* @param sleeveNumber - Index of the sleeve to start committing crime. Sleeves are numbered starting from 0. * @param sleeveNumber - Index of the sleeve to start committing crime. Sleeves are numbered starting from 0.
* @param name - Name of the crime. Must be an exact match. Refer to the list of crimes. * @param name - Name of the crime.
* @returns True if this action was set successfully, false otherwise. * @returns True if this action was set successfully, false otherwise.
*/ */
setToCommitCrime(sleeveNumber: number, name: string): boolean; setToCommitCrime(sleeveNumber: number, crimeType: CrimeType | CrimeNames): boolean;
/** /**
* Set a sleeve to work for a faction. * Set a sleeve to work for a faction.
@ -3935,7 +3908,7 @@ export interface WorkStats {
* @public * @public
*/ */
interface WorkFormulas { interface WorkFormulas {
crimeGains(crimeType: string): WorkStats; crimeGains(crimeType: CrimeType | CrimeNames): WorkStats;
classGains(player: Player, classType: string, locationName: string): WorkStats; classGains(player: Player, classType: string, locationName: string): WorkStats;
factionGains(player: Player, workType: string, favor: number): WorkStats; factionGains(player: Player, workType: string, favor: number): WorkStats;
} }
@ -6700,7 +6673,7 @@ export interface NS {
* @param variant - Type of toast, must be one of success, info, warning, error. Defaults to success. * @param variant - Type of toast, must be one of success, info, warning, error. Defaults to success.
* @param duration - Duration of toast in ms. Can also be `null` to create a persistent toast. Defaults to 2000 * @param duration - Duration of toast in ms. Can also be `null` to create a persistent toast. Defaults to 2000
*/ */
toast(msg: string, variant?: ToastVariant, duration?: number | null): void; toast(msg: string, variant?: ToastTypes | ToastVariant, duration?: number | null): void;
/** /**
* Download a file from the internet. * Download a file from the internet.
@ -6899,21 +6872,38 @@ export interface NS {
enums: NSEnums; enums: NSEnums;
} }
declare enum ToastVariant {
SUCCESS = "success",
WARNING = "warning",
ERROR = "error",
INFO = "info",
}
/** @public */ /** @public */
declare const enums = { export type ToastTypes = `${ToastVariant}`;
toast: {
SUCCESS: "success", declare enum CrimeType {
WARNING: "warning", SHOPLIFT = "SHOPLIFT",
ERROR: "error", ROB_STORE = "ROBSTORE",
INFO: "info", MUG = "MUG",
}, LARCENY = "LARCENY",
DRUGS = "DRUGS",
BOND_FORGERY = "BONDFORGERY",
TRAFFIC_ARMS = "TRAFFICKARMS",
HOMICIDE = "HOMICIDE",
GRAND_THEFT_AUTO = "GRANDTHEFTAUTO",
KIDNAP = "KIDNAP",
ASSASSINATION = "ASSASSINATION",
HEIST = "HEIST",
}
/** @public */
type CrimeNames = `${CrimeType}`;
/** @public */
export type NSEnums = {
toast: typeof ToastVariant;
crimes: typeof CrimeType;
}; };
/** @public */
type ToastVariant = ValuesFrom<typeof enums.toast>;
/** @public */
export type NSEnums = typeof enums;
/** /**
* Corporation Office API * Corporation Office API
* @remarks * @remarks

@ -9,51 +9,7 @@ import { CrimeType } from "../utils/WorkType";
import { Work, WorkType } from "./Work"; import { Work, WorkType } from "./Work";
import { scaleWorkStats, WorkStats } from "./WorkStats"; import { scaleWorkStats, WorkStats } from "./WorkStats";
import { calculateCrimeWorkStats } from "./formulas/Crime"; import { calculateCrimeWorkStats } from "./formulas/Crime";
import { checkEnum } from "../utils/helpers/checkEnum";
enum newCrimeType {
SHOPLIFT = "SHOPLIFT",
ROBSTORE = "ROBSTORE",
MUG = "MUG",
LARCENY = "LARCENY",
DRUGS = "DRUGS",
BONDFORGERY = "BONDFORGERY",
TRAFFICKARMS = "TRAFFICKARMS",
HOMICIDE = "HOMICIDE",
GRANDTHEFTAUTO = "GRANDTHEFTAUTO",
KIDNAP = "KIDNAP",
ASSASSINATION = "ASSASSINATION",
HEIST = "HEIST",
}
const convertCrimeType = (crimeType: CrimeType): newCrimeType => {
switch (crimeType) {
case CrimeType.SHOPLIFT:
return newCrimeType.SHOPLIFT;
case CrimeType.ROB_STORE:
return newCrimeType.ROBSTORE;
case CrimeType.MUG:
return newCrimeType.MUG;
case CrimeType.LARCENY:
return newCrimeType.LARCENY;
case CrimeType.DRUGS:
return newCrimeType.DRUGS;
case CrimeType.BOND_FORGERY:
return newCrimeType.BONDFORGERY;
case CrimeType.TRAFFIC_ARMS:
return newCrimeType.TRAFFICKARMS;
case CrimeType.HOMICIDE:
return newCrimeType.HOMICIDE;
case CrimeType.GRAND_THEFT_AUTO:
return newCrimeType.GRANDTHEFTAUTO;
case CrimeType.KIDNAP:
return newCrimeType.KIDNAP;
case CrimeType.ASSASSINATION:
return newCrimeType.ASSASSINATION;
case CrimeType.HEIST:
return newCrimeType.HEIST;
}
return newCrimeType.SHOPLIFT;
};
interface CrimeWorkParams { interface CrimeWorkParams {
crimeType: CrimeType; crimeType: CrimeType;
@ -73,9 +29,10 @@ export class CrimeWork extends Work {
} }
getCrime(): Crime { getCrime(): Crime {
const crime = Object.values(Crimes).find((c) => c.type === this.crimeType); if (!checkEnum(CrimeType, this.crimeType)) {
if (!crime) throw new Error("CrimeWork object constructed with invalid crime type"); throw new Error("CrimeWork object constructed with invalid crime type");
return crime; }
return Crimes[this.crimeType];
} }
process(cycles = 1): boolean { process(cycles = 1): boolean {
@ -132,7 +89,7 @@ export class CrimeWork extends Work {
return { return {
type: this.type, type: this.type,
cyclesWorked: this.cyclesWorked, cyclesWorked: this.cyclesWorked,
crimeType: convertCrimeType(this.crimeType), crimeType: checkEnum(CrimeType, this.crimeType) ? this.crimeType : CrimeType.SHOPLIFT,
}; };
} }

@ -1,5 +1,4 @@
export enum CrimeType { export enum CrimeType {
None = "",
SHOPLIFT = "SHOPLIFT", //"shoplift", SHOPLIFT = "SHOPLIFT", //"shoplift",
ROB_STORE = "ROBSTORE", //"rob a store", ROB_STORE = "ROBSTORE", //"rob a store",
MUG = "MUG", //"mug someone", MUG = "MUG", //"mug someone",