diff --git a/markdown/bitburner.md b/markdown/bitburner.md index db870ab0a..aeeaacf1d 100644 --- a/markdown/bitburner.md +++ b/markdown/bitburner.md @@ -122,8 +122,7 @@ | [SpawnOptions](./bitburner.spawnoptions.md) | | | [Stanek](./bitburner.stanek.md) | Stanek's Gift API. | | [StockMarketConstants](./bitburner.stockmarketconstants.md) | Constants used for the stock market game mechanic. | -| [StockOrder](./bitburner.stockorder.md) |

Return value of [getOrders](./bitburner.tix.getorders.md)

Keys are stock symbols, properties are arrays of [StockOrderObject](./bitburner.stockorderobject.md)

| -| [StockOrderObject](./bitburner.stockorderobject.md) | Value in map of [StockOrder](./bitburner.stockorder.md) | +| [StockOrder](./bitburner.stockorder.md) | | | [StudyTask](./bitburner.studytask.md) | Study | | [TailProperties](./bitburner.tailproperties.md) | | | [TIX](./bitburner.tix.md) | Stock market API | diff --git a/markdown/bitburner.stockorder.md b/markdown/bitburner.stockorder.md index 56a458021..0491a5839 100644 --- a/markdown/bitburner.stockorder.md +++ b/markdown/bitburner.stockorder.md @@ -4,12 +4,19 @@ ## StockOrder interface -Return value of [getOrders](./bitburner.tix.getorders.md) - -Keys are stock symbols, properties are arrays of [StockOrderObject](./bitburner.stockorderobject.md) **Signature:** ```typescript interface StockOrder ``` + +## Properties + +| Property | Modifiers | Type | Description | +| --- | --- | --- | --- | +| [position](./bitburner.stockorder.position.md) | | [PositionType](./bitburner.positiontype.md) | Order position | +| [price](./bitburner.stockorder.price.md) | | number | Price per share | +| [shares](./bitburner.stockorder.shares.md) | | number | Number of shares | +| [type](./bitburner.stockorder.type.md) | | [OrderType](./bitburner.ordertype.md) | Order type | + diff --git a/markdown/bitburner.stockorderobject.position.md b/markdown/bitburner.stockorder.position.md similarity index 61% rename from markdown/bitburner.stockorderobject.position.md rename to markdown/bitburner.stockorder.position.md index b53bdcf74..a700eadce 100644 --- a/markdown/bitburner.stockorderobject.position.md +++ b/markdown/bitburner.stockorder.position.md @@ -1,8 +1,8 @@ -[Home](./index.md) > [bitburner](./bitburner.md) > [StockOrderObject](./bitburner.stockorderobject.md) > [position](./bitburner.stockorderobject.position.md) +[Home](./index.md) > [bitburner](./bitburner.md) > [StockOrder](./bitburner.stockorder.md) > [position](./bitburner.stockorder.position.md) -## StockOrderObject.position property +## StockOrder.position property Order position diff --git a/markdown/bitburner.stockorderobject.price.md b/markdown/bitburner.stockorder.price.md similarity index 61% rename from markdown/bitburner.stockorderobject.price.md rename to markdown/bitburner.stockorder.price.md index 3fd027f2c..1d5966983 100644 --- a/markdown/bitburner.stockorderobject.price.md +++ b/markdown/bitburner.stockorder.price.md @@ -1,8 +1,8 @@ -[Home](./index.md) > [bitburner](./bitburner.md) > [StockOrderObject](./bitburner.stockorderobject.md) > [price](./bitburner.stockorderobject.price.md) +[Home](./index.md) > [bitburner](./bitburner.md) > [StockOrder](./bitburner.stockorder.md) > [price](./bitburner.stockorder.price.md) -## StockOrderObject.price property +## StockOrder.price property Price per share diff --git a/markdown/bitburner.stockorderobject.shares.md b/markdown/bitburner.stockorder.shares.md similarity index 61% rename from markdown/bitburner.stockorderobject.shares.md rename to markdown/bitburner.stockorder.shares.md index 0816130d2..a379c59b1 100644 --- a/markdown/bitburner.stockorderobject.shares.md +++ b/markdown/bitburner.stockorder.shares.md @@ -1,8 +1,8 @@ -[Home](./index.md) > [bitburner](./bitburner.md) > [StockOrderObject](./bitburner.stockorderobject.md) > [shares](./bitburner.stockorderobject.shares.md) +[Home](./index.md) > [bitburner](./bitburner.md) > [StockOrder](./bitburner.stockorder.md) > [shares](./bitburner.stockorder.shares.md) -## StockOrderObject.shares property +## StockOrder.shares property Number of shares diff --git a/markdown/bitburner.stockorderobject.type.md b/markdown/bitburner.stockorder.type.md similarity index 62% rename from markdown/bitburner.stockorderobject.type.md rename to markdown/bitburner.stockorder.type.md index 10d30d24f..1c1ce2789 100644 --- a/markdown/bitburner.stockorderobject.type.md +++ b/markdown/bitburner.stockorder.type.md @@ -1,8 +1,8 @@ -[Home](./index.md) > [bitburner](./bitburner.md) > [StockOrderObject](./bitburner.stockorderobject.md) > [type](./bitburner.stockorderobject.type.md) +[Home](./index.md) > [bitburner](./bitburner.md) > [StockOrder](./bitburner.stockorder.md) > [type](./bitburner.stockorder.type.md) -## StockOrderObject.type property +## StockOrder.type property Order type diff --git a/markdown/bitburner.stockorderobject.md b/markdown/bitburner.stockorderobject.md deleted file mode 100644 index 00e45833d..000000000 --- a/markdown/bitburner.stockorderobject.md +++ /dev/null @@ -1,23 +0,0 @@ - - -[Home](./index.md) > [bitburner](./bitburner.md) > [StockOrderObject](./bitburner.stockorderobject.md) - -## StockOrderObject interface - -Value in map of [StockOrder](./bitburner.stockorder.md) - -**Signature:** - -```typescript -interface StockOrderObject -``` - -## Properties - -| Property | Modifiers | Type | Description | -| --- | --- | --- | --- | -| [position](./bitburner.stockorderobject.position.md) | | [PositionType](./bitburner.positiontype.md) | Order position | -| [price](./bitburner.stockorderobject.price.md) | | number | Price per share | -| [shares](./bitburner.stockorderobject.shares.md) | | number | Number of shares | -| [type](./bitburner.stockorderobject.type.md) | | [OrderType](./bitburner.ordertype.md) | Order type | - diff --git a/markdown/bitburner.tix.cancelorder.md b/markdown/bitburner.tix.cancelorder.md index bda678423..d6ab09734 100644 --- a/markdown/bitburner.tix.cancelorder.md +++ b/markdown/bitburner.tix.cancelorder.md @@ -9,7 +9,7 @@ Cancel order for stocks. **Signature:** ```typescript -cancelOrder(sym: string, shares: number, price: number, type: string, pos: string): void; +cancelOrder(sym: string, shares: number, price: number, orderType: OrderType, positionType: PositionType): void; ``` ## Parameters @@ -19,8 +19,8 @@ cancelOrder(sym: string, shares: number, price: number, type: string, pos: strin | sym | string | Stock symbol. | | shares | number | Number of shares for order. Must be positive. Will be rounded to the nearest integer. | | price | number | Execution price for the order. | -| type | string | Type of order. | -| pos | string | Specifies whether the order is a “Long” or “Short” position. | +| orderType | [OrderType](./bitburner.ordertype.md) | Type of order. | +| positionType | [PositionType](./bitburner.positiontype.md) | Specifies whether the order is a Long ("L") or Short ("S") position. | **Returns:** diff --git a/markdown/bitburner.tix.getorders.md b/markdown/bitburner.tix.getorders.md index c4ff82daa..d8b463847 100644 --- a/markdown/bitburner.tix.getorders.md +++ b/markdown/bitburner.tix.getorders.md @@ -9,17 +9,17 @@ Returns your order book for the stock market. **Signature:** ```typescript -getOrders(): StockOrder; +getOrders(): Record; ``` **Returns:** -[StockOrder](./bitburner.stockorder.md) +Record<string, [StockOrder](./bitburner.stockorder.md)\[\]> -Object containing information for all the Limit and Stop Orders you have in the stock market. +Object containing information for all the Limit and Stop Orders you have in the stock market. Keys are stock symbols, and properties are arrays of [StockOrder](./bitburner.stockorder.md) ## Remarks -RAM cost: 2.5 GB This is an object containing information for all the Limit and Stop Orders you have in the stock market. For each symbol you have a position in, the returned object will have a key with that symbol's name. The object's properties are each an array of [StockOrderObject](./bitburner.stockorderobject.md) The object has the following structure: +RAM cost: 2.5 GB This is an object containing information for all the Limit and Stop Orders you have in the stock market. For each symbol you have a position in, the returned object will have a key with that symbol's name. The object's properties are each an array of [StockOrder](./bitburner.stockorder.md) The object has the following structure: ```js { diff --git a/markdown/bitburner.tix.getpurchasecost.md b/markdown/bitburner.tix.getpurchasecost.md index 029342b7b..04b22cfb0 100644 --- a/markdown/bitburner.tix.getpurchasecost.md +++ b/markdown/bitburner.tix.getpurchasecost.md @@ -9,7 +9,7 @@ Calculates cost of buying stocks. **Signature:** ```typescript -getPurchaseCost(sym: string, shares: number, posType: string): number; +getPurchaseCost(sym: string, shares: number, positionType: PositionType): number; ``` ## Parameters @@ -18,7 +18,7 @@ getPurchaseCost(sym: string, shares: number, posType: string): number; | --- | --- | --- | | sym | string | Stock symbol. | | shares | number | Number of shares to purchase. | -| posType | string | Specifies whether the order is a “Long” or “Short” position. | +| positionType | [PositionType](./bitburner.positiontype.md) | Specifies whether the order is a Long ("L") or Short ("S") position. | **Returns:** diff --git a/markdown/bitburner.tix.getsalegain.md b/markdown/bitburner.tix.getsalegain.md index ddd969301..21b2f6302 100644 --- a/markdown/bitburner.tix.getsalegain.md +++ b/markdown/bitburner.tix.getsalegain.md @@ -9,7 +9,7 @@ Calculate profit of selling stocks. **Signature:** ```typescript -getSaleGain(sym: string, shares: number, posType: string): number; +getSaleGain(sym: string, shares: number, positionType: PositionType): number; ``` ## Parameters @@ -18,7 +18,7 @@ getSaleGain(sym: string, shares: number, posType: string): number; | --- | --- | --- | | sym | string | Stock symbol. | | shares | number | Number of shares to sell. | -| posType | string | Specifies whether the order is a “Long” or “Short” position. | +| positionType | [PositionType](./bitburner.positiontype.md) | Specifies whether the order is a Long ("L") or Short ("S") position. | **Returns:** diff --git a/markdown/bitburner.tix.md b/markdown/bitburner.tix.md index 69211d109..af250e752 100644 --- a/markdown/bitburner.tix.md +++ b/markdown/bitburner.tix.md @@ -18,7 +18,7 @@ export interface TIX | --- | --- | | [buyShort(sym, shares)](./bitburner.tix.buyshort.md) | Short stocks. | | [buyStock(sym, shares)](./bitburner.tix.buystock.md) | Buy stocks. | -| [cancelOrder(sym, shares, price, type, pos)](./bitburner.tix.cancelorder.md) | Cancel order for stocks. | +| [cancelOrder(sym, shares, price, orderType, positionType)](./bitburner.tix.cancelorder.md) | Cancel order for stocks. | | [getAskPrice(sym)](./bitburner.tix.getaskprice.md) | Returns the ask price of that stock. | | [getBidPrice(sym)](./bitburner.tix.getbidprice.md) | Returns the bid price of that stock. | | [getBonusTime()](./bitburner.tix.getbonustime.md) | Get Stock Market bonus time. | @@ -29,8 +29,8 @@ export interface TIX | [getOrganization(sym)](./bitburner.tix.getorganization.md) | Returns the organization associated with a stock symbol. | | [getPosition(sym)](./bitburner.tix.getposition.md) | Returns the player’s position in a stock. | | [getPrice(sym)](./bitburner.tix.getprice.md) | Returns the price of a stock. | -| [getPurchaseCost(sym, shares, posType)](./bitburner.tix.getpurchasecost.md) | Calculates cost of buying stocks. | -| [getSaleGain(sym, shares, posType)](./bitburner.tix.getsalegain.md) | Calculate profit of selling stocks. | +| [getPurchaseCost(sym, shares, positionType)](./bitburner.tix.getpurchasecost.md) | Calculates cost of buying stocks. | +| [getSaleGain(sym, shares, positionType)](./bitburner.tix.getsalegain.md) | Calculate profit of selling stocks. | | [getSymbols()](./bitburner.tix.getsymbols.md) | Returns an array of the symbols of the tradable stocks | | [getVolatility(sym)](./bitburner.tix.getvolatility.md) | Returns the volatility of the specified stock. | | [has4SData()](./bitburner.tix.has4sdata.md) | Returns true if the player has access to the 4S Data | @@ -38,7 +38,7 @@ export interface TIX | [hasTIXAPIAccess()](./bitburner.tix.hastixapiaccess.md) | Returns true if the player has access to the TIX API | | [hasWSEAccount()](./bitburner.tix.haswseaccount.md) | Returns true if the player has access to a WSE Account | | [nextUpdate()](./bitburner.tix.nextupdate.md) | Sleep until the next Stock Market price update has happened. | -| [placeOrder(sym, shares, price, type, pos)](./bitburner.tix.placeorder.md) | Place order for stocks. | +| [placeOrder(sym, shares, price, orderType, positionType)](./bitburner.tix.placeorder.md) | Place order for stocks. | | [purchase4SMarketData()](./bitburner.tix.purchase4smarketdata.md) | Purchase 4S Market Data Access. | | [purchase4SMarketDataTixApi()](./bitburner.tix.purchase4smarketdatatixapi.md) | Purchase 4S Market Data TIX API Access. | | [purchaseTixApi()](./bitburner.tix.purchasetixapi.md) | Purchase TIX API Access | diff --git a/markdown/bitburner.tix.placeorder.md b/markdown/bitburner.tix.placeorder.md index fd139cb1e..1c7cd5b24 100644 --- a/markdown/bitburner.tix.placeorder.md +++ b/markdown/bitburner.tix.placeorder.md @@ -9,7 +9,7 @@ Place order for stocks. **Signature:** ```typescript -placeOrder(sym: string, shares: number, price: number, type: string, pos: string): boolean; +placeOrder(sym: string, shares: number, price: number, orderType: OrderType, positionType: PositionType): boolean; ``` ## Parameters @@ -19,8 +19,8 @@ placeOrder(sym: string, shares: number, price: number, type: string, pos: string | sym | string | Stock symbol. | | shares | number | Number of shares for order. Must be positive. Will be rounded to the nearest integer. | | price | number | Execution price for the order. | -| type | string | Type of order. | -| pos | string | Specifies whether the order is a “Long” or “Short” position. | +| orderType | [OrderType](./bitburner.ordertype.md) | Type of order. | +| positionType | [PositionType](./bitburner.positiontype.md) | Specifies whether the order is a Long ("L") or Short ("S") position. | **Returns:** diff --git a/src/Bladeburner/Bladeburner.ts b/src/Bladeburner/Bladeburner.ts index ab79a0f12..e6433dd21 100644 --- a/src/Bladeburner/Bladeburner.ts +++ b/src/Bladeburner/Bladeburner.ts @@ -7,6 +7,7 @@ import type { Skills as PersonSkills } from "../PersonObjects/Skills"; import { AugmentationName, BladeburnerActionType, + type BladeburnerBlackOpName, BladeburnerContractName, BladeburnerGeneralActionName, BladeburnerMultName, @@ -246,7 +247,7 @@ export class Bladeburner implements OperationTeam { } const type = args[1]; const name = args[2]; - const action = this.getActionFromTypeAndName(type, name); + const action = this.guessActionFromTypeAndName(type, name); if (!action) { this.postToConsole(`Invalid action type / name specified: type: ${type}, name: ${name}`); return; @@ -1406,8 +1407,25 @@ export class Bladeburner implements OperationTeam { } } - /** Fuzzy matching for action identifiers. Should be removed in 3.0 */ - getActionFromTypeAndName(type: string, name: string): Action | null { + getActionFromTypeAndName(type: BladeburnerActionType, name: string): Action | undefined { + /** + * Typecasting "name" instead of checking it with getEnumHelper().isMember() is intentional. The callers will handle + * the undefined value if "name" is invalid. + */ + switch (type) { + case BladeburnerActionType.General: + return GeneralActions[name as BladeburnerGeneralActionName]; + case BladeburnerActionType.Contract: + return this.contracts[name as BladeburnerContractName]; + case BladeburnerActionType.Operation: + return this.operations[name as BladeburnerOperationName]; + case BladeburnerActionType.BlackOp: + return BlackOperations[name as BladeburnerBlackOpName]; + } + } + + /** Fuzzy matching for action identifiers. Do not use this function for anything except BB console. */ + guessActionFromTypeAndName(type: string, name: string): Action | null { if (!type || !name) return null; const id = autoCompleteTypeShorthand(type, name); return id ? this.getActionObject(id) : null; diff --git a/src/Bladeburner/Enums.ts b/src/Bladeburner/Enums.ts index 2b778cd49..18e49a575 100644 --- a/src/Bladeburner/Enums.ts +++ b/src/Bladeburner/Enums.ts @@ -14,6 +14,12 @@ export enum BladeburnerGeneralActionName { InciteViolence = "Incite Violence", } +export enum SpecialBladeburnerActionTypeForSleeve { + InfiltrateSynthoids = "Infiltrate Synthoids", + SupportMainSleeve = "Support main sleeve", + TakeOnContracts = "Take on contracts", +} + export enum BladeburnerContractName { Tracking = "Tracking", BountyHunter = "Bounty Hunter", diff --git a/src/Crime/CrimeHelpers.ts b/src/Crime/CrimeHelpers.ts index 2860c56c9..c3e3b23f4 100644 --- a/src/Crime/CrimeHelpers.ts +++ b/src/Crime/CrimeHelpers.ts @@ -1,8 +1,6 @@ import { Crimes } from "./Crimes"; -import { Crime } from "./Crime"; import { Player } from "@player"; -import { getEnumHelper } from "../utils/EnumHelper"; import { CrimeType } from "@enums"; //This is only used for the player @@ -11,25 +9,3 @@ export function determineCrimeSuccess(type: CrimeType): boolean { const chance = crime.successRate(Player); return Math.random() <= chance; } - -export function findCrime(roughName: string): Crime | null { - const matchedName = getEnumHelper("CrimeType").getMember(roughName, { fuzzy: true }); - if (matchedName) return Crimes[matchedName]; - // This can probably all be removed - roughName = roughName.toLowerCase(); - if (roughName.includes("shoplift")) return Crimes[CrimeType.shoplift]; - else if (roughName.includes("rob") && roughName.includes("store")) return Crimes[CrimeType.robStore]; - else if (roughName.includes("mug")) return Crimes[CrimeType.mug]; - else if (roughName.includes("larceny")) return Crimes[CrimeType.larceny]; - else if (roughName.includes("drugs")) return Crimes[CrimeType.dealDrugs]; - else if (roughName.includes("bond") && roughName.includes("forge")) return Crimes[CrimeType.bondForgery]; - else if ((roughName.includes("traffic") || roughName.includes("illegal")) && roughName.includes("arms")) { - return Crimes[CrimeType.traffickArms]; - } else if (roughName.includes("homicide")) return Crimes[CrimeType.homicide]; - else if (roughName.includes("grand") && roughName.includes("auto")) return Crimes[CrimeType.grandTheftAuto]; - 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; -} diff --git a/src/NetscriptFunctions/Bladeburner.ts b/src/NetscriptFunctions/Bladeburner.ts index 1a83f7938..0cdf440dc 100644 --- a/src/NetscriptFunctions/Bladeburner.ts +++ b/src/NetscriptFunctions/Bladeburner.ts @@ -35,13 +35,17 @@ export function NetscriptBladeburner(): InternalAPI { throw helpers.errorMessage(ctx, "You must be a member of the Bladeburner division to use this API."); return bladeburner; }; - function getAction(ctx: NetscriptContext, type: unknown, name: unknown): Action { + function getAction(ctx: NetscriptContext, _type: unknown, name: unknown): Action { const bladeburner = Player.bladeburner; - assertStringWithNSContext(ctx, "type", type); + const type = getEnumHelper("BladeburnerActionType").nsGetMember(ctx, _type); assertStringWithNSContext(ctx, "name", name); - if (bladeburner === null) throw new Error("Must have joined bladeburner"); + if (bladeburner === null) { + throw new Error("Must have joined bladeburner"); + } const action = bladeburner.getActionFromTypeAndName(type, name); - if (!action) throw helpers.errorMessage(ctx, `Invalid action type='${type}', name='${name}'`); + if (!action) { + throw helpers.errorMessage(ctx, `Invalid action type='${_type}', name='${name}'`); + } return action; } diff --git a/src/NetscriptFunctions/Formulas.ts b/src/NetscriptFunctions/Formulas.ts index 2c894e650..7354fd6ec 100644 --- a/src/NetscriptFunctions/Formulas.ts +++ b/src/NetscriptFunctions/Formulas.ts @@ -26,7 +26,7 @@ import { calculateGrowTime, calculateWeakenTime, } from "../Hacking"; -import { CityName, CompletedProgramName, FactionWorkType, GymType, LocationName, UniversityClassType } from "@enums"; +import { CityName, CompletedProgramName, LocationName } from "@enums"; import { Formulas as IFormulas, Player as IPlayer, Person as IPerson } from "@nsdefs"; import { calculateRespectGain, @@ -47,12 +47,11 @@ import { calculateClassEarnings } from "../Work/Formulas"; import { calculateFactionExp, calculateFactionRep } from "../Work/Formulas"; import { defaultMultipliers } from "../PersonObjects/Multipliers"; -import { findEnumMember } from "../utils/helpers/enum"; import { getEnumHelper } from "../utils/EnumHelper"; import { CompanyPositions } from "../Company/CompanyPositions"; -import { findCrime } from "../Crime/CrimeHelpers"; import { Skills } from "../Bladeburner/data/Skills"; import type { PositiveNumber } from "../types"; +import { Crimes } from "../Crime/Crimes"; import { calculateEffectiveSharedThreads, calculateShareBonus } from "../NetworkShare/Share"; export function NetscriptFormulas(): InternalAPI { @@ -395,38 +394,39 @@ export function NetscriptFormulas(): InternalAPI { crimeSuccessChance: (ctx) => (_person, _crimeType) => { checkFormulasAccess(ctx); const person = helpers.person(ctx, _person); - const crime = findCrime(helpers.string(ctx, "crimeType", _crimeType)); - if (!crime) throw new Error(`Invalid crime type: ${_crimeType}`); + const crime = Crimes[getEnumHelper("CrimeType").nsGetMember(ctx, _crimeType)]; + if (!crime) { + throw new Error(`Invalid crime type: ${_crimeType}`); + } return crime.successRate(person); }, crimeGains: (ctx) => (_person, _crimeType) => { checkFormulasAccess(ctx); const person = helpers.person(ctx, _person); - const crime = findCrime(helpers.string(ctx, "crimeType", _crimeType)); - if (!crime) throw new Error(`Invalid crime type: ${_crimeType}`); + const crime = Crimes[getEnumHelper("CrimeType").nsGetMember(ctx, _crimeType)]; + if (!crime) { + throw new Error(`Invalid crime type: ${_crimeType}`); + } return calculateCrimeWorkStats(person, crime); }, gymGains: (ctx) => (_person, _classType, _locationName) => { checkFormulasAccess(ctx); const person = helpers.person(ctx, _person); - const classType = findEnumMember(GymType, helpers.string(ctx, "classType", _classType)); - if (!classType) throw new Error(`Invalid gym training type: ${_classType}`); + const classType = getEnumHelper("GymType").nsGetMember(ctx, _classType); const locationName = getEnumHelper("LocationName").nsGetMember(ctx, _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 classType = getEnumHelper("UniversityClassType").nsGetMember(ctx, _classType); const locationName = getEnumHelper("LocationName").nsGetMember(ctx, _locationName); return calculateClassEarnings(person, classType, locationName); }, factionGains: (ctx) => (_player, _workType, _favor) => { checkFormulasAccess(ctx); const player = helpers.person(ctx, _player); - const workType = findEnumMember(FactionWorkType, helpers.string(ctx, "_workType", _workType)); - if (!workType) throw new Error(`Invalid faction work type: ${_workType}`); + const workType = getEnumHelper("FactionWorkType").nsGetMember(ctx, _workType); const favor = helpers.number(ctx, "favor", _favor); const exp = calculateFactionExp(player, workType); const rep = calculateFactionRep(player, workType, favor); diff --git a/src/NetscriptFunctions/Singularity.ts b/src/NetscriptFunctions/Singularity.ts index e2700c6d0..59a3235e9 100644 --- a/src/NetscriptFunctions/Singularity.ts +++ b/src/NetscriptFunctions/Singularity.ts @@ -1,7 +1,7 @@ import type { Singularity as ISingularity } from "@nsdefs"; import { Player } from "@player"; -import { CityName, FactionWorkType, GymType, LocationName, UniversityClassType } from "@enums"; +import { CityName, FactionWorkType, LocationName } from "@enums"; import { purchaseAugmentation, joinFaction, getFactionAugmentationsFiltered } from "../Faction/FactionHelpers"; import { startWorkerScript } from "../NetscriptWorker"; import { Augmentations } from "../Augmentation/Augmentations"; @@ -9,7 +9,6 @@ import { getAugCost, installAugmentations } from "../Augmentation/AugmentationHe import { CONSTANTS } from "../Constants"; import { RunningScript } from "../Script/RunningScript"; import { calculateAchievements } from "../Achievements/Achievements"; -import { findCrime } from "../Crime/CrimeHelpers"; import { CompanyPositions } from "../Company/CompanyPositions"; import { DarkWebItems } from "../DarkWeb/DarkWebItems"; import { Router } from "../ui/GameRoot"; @@ -40,7 +39,6 @@ import { CompanyWork } from "../Work/CompanyWork"; import { canGetBonus, onExport } from "../ExportBonus"; import { saveObject } from "../SaveObject"; import { calculateCrimeWorkStats } from "../Work/Formulas"; -import { findEnumMember } from "../utils/helpers/enum"; import { Engine } from "../engine"; import { getEnumHelper } from "../utils/EnumHelper"; import { ScriptFilePath, resolveScriptFilePath } from "../Paths/ScriptFilePath"; @@ -53,6 +51,7 @@ import { addRepToFavor } from "../Faction/formulas/favor"; import { validBitNodes } from "../BitNode/BitNodeUtils"; import { exceptionAlert } from "../utils/helpers/exceptionAlert"; import { cat } from "../Terminal/commands/cat"; +import { Crimes } from "../Crime/Crimes"; export function NetscriptSingularity(): InternalAPI { const runAfterReset = function (cbScript: ScriptFilePath) { @@ -231,17 +230,13 @@ export function NetscriptSingularity(): InternalAPI { (_universityName, _className, _focus = true) => { helpers.checkSingularityAccess(ctx); const universityName = helpers.string(ctx, "universityName", _universityName); - const classType = findEnumMember(UniversityClassType, helpers.string(ctx, "className", _className)); - if (!classType) { - helpers.log(ctx, () => `Invalid class name: ${_className}.`); - return false; - } + const classType = getEnumHelper("UniversityClassType").nsGetMember(ctx, _className); const focus = !!_focus; const wasFocusing = Player.focus; - switch (universityName.toLowerCase()) { - case LocationName.AevumSummitUniversity.toLowerCase(): - if (Player.city != CityName.Aevum) { + switch (universityName) { + case LocationName.AevumSummitUniversity: + if (Player.city !== CityName.Aevum) { helpers.log( ctx, () => `You cannot study at 'Summit University' because you are not in '${CityName.Aevum}'.`, @@ -250,8 +245,8 @@ export function NetscriptSingularity(): InternalAPI { } Player.gotoLocation(LocationName.AevumSummitUniversity); break; - case LocationName.Sector12RothmanUniversity.toLowerCase(): - if (Player.city != CityName.Sector12) { + case LocationName.Sector12RothmanUniversity: + if (Player.city !== CityName.Sector12) { helpers.log( ctx, () => `You cannot study at 'Rothman University' because you are not in '${CityName.Sector12}'.`, @@ -260,8 +255,8 @@ export function NetscriptSingularity(): InternalAPI { } Player.gotoLocation(LocationName.Sector12RothmanUniversity); break; - case LocationName.VolhavenZBInstituteOfTechnology.toLowerCase(): - if (Player.city != CityName.Volhaven) { + case LocationName.VolhavenZBInstituteOfTechnology: + if (Player.city !== CityName.Volhaven) { helpers.log( ctx, () => `You cannot study at 'ZB Institute of Technology' because you are not in '${CityName.Volhaven}'.`, @@ -298,17 +293,13 @@ export function NetscriptSingularity(): InternalAPI { (_gymName, _stat, _focus = true) => { helpers.checkSingularityAccess(ctx); const gymName = helpers.string(ctx, "gymName", _gymName); - const classType = findEnumMember(GymType, helpers.string(ctx, "stat", _stat)); - if (!classType) { - helpers.log(ctx, () => `Invalid stat: ${_stat}.`); - return false; - } + const classType = getEnumHelper("GymType").nsGetMember(ctx, _stat); const focus = !!_focus; const wasFocusing = Player.focus; - switch (gymName.toLowerCase()) { - case LocationName.AevumCrushFitnessGym.toLowerCase(): - if (Player.city != CityName.Aevum) { + switch (gymName) { + case LocationName.AevumCrushFitnessGym: + if (Player.city !== CityName.Aevum) { helpers.log( ctx, () => @@ -318,8 +309,8 @@ export function NetscriptSingularity(): InternalAPI { } Player.gotoLocation(LocationName.AevumCrushFitnessGym); break; - case LocationName.AevumSnapFitnessGym.toLowerCase(): - if (Player.city != CityName.Aevum) { + case LocationName.AevumSnapFitnessGym: + if (Player.city !== CityName.Aevum) { helpers.log( ctx, () => @@ -329,8 +320,8 @@ export function NetscriptSingularity(): InternalAPI { } Player.gotoLocation(LocationName.AevumSnapFitnessGym); break; - case LocationName.Sector12IronGym.toLowerCase(): - if (Player.city != CityName.Sector12) { + case LocationName.Sector12IronGym: + if (Player.city !== CityName.Sector12) { helpers.log( ctx, () => @@ -340,8 +331,8 @@ export function NetscriptSingularity(): InternalAPI { } Player.gotoLocation(LocationName.Sector12IronGym); break; - case LocationName.Sector12PowerhouseGym.toLowerCase(): - if (Player.city != CityName.Sector12) { + case LocationName.Sector12PowerhouseGym: + if (Player.city !== CityName.Sector12) { helpers.log( ctx, () => @@ -351,8 +342,8 @@ export function NetscriptSingularity(): InternalAPI { } Player.gotoLocation(LocationName.Sector12PowerhouseGym); break; - case LocationName.VolhavenMilleniumFitnessGym.toLowerCase(): - if (Player.city != CityName.Volhaven) { + case LocationName.VolhavenMilleniumFitnessGym: + if (Player.city !== CityName.Volhaven) { helpers.log( ctx, () => @@ -719,7 +710,7 @@ export function NetscriptSingularity(): InternalAPI { applyToCompany: (ctx) => (_companyName, _field) => { helpers.checkSingularityAccess(ctx); const companyName = getEnumHelper("CompanyName").nsGetMember(ctx, _companyName); - const field = getEnumHelper("JobField").nsGetMember(ctx, _field, "field", { fuzzy: true }); + const field = getEnumHelper("JobField").nsGetMember(ctx, _field, "field"); const company = Companies[companyName]; const entryPos = CompanyPositions[JobTracks[field][0]]; @@ -796,7 +787,7 @@ export function NetscriptSingularity(): InternalAPI { (_facName, _type, _focus = true) => { helpers.checkSingularityAccess(ctx); const facName = getEnumHelper("FactionName").nsGetMember(ctx, _facName); - const type = helpers.string(ctx, "type", _type); + const type = getEnumHelper("FactionWorkType").nsGetMember(ctx, _type); const focus = !!_focus; const faction = Factions[facName]; @@ -813,10 +804,8 @@ export function NetscriptSingularity(): InternalAPI { const wasFocusing = Player.focus; - switch (type.toLowerCase()) { - case "hacking": - case "hacking contracts": - case "hackingcontracts": + switch (type) { + case FactionWorkType.hacking: if (!FactionInfos[faction.name].offerHackingWork) { helpers.log(ctx, () => `Faction '${faction.name}' do not need help with hacking contracts.`); return false; @@ -837,9 +826,7 @@ export function NetscriptSingularity(): InternalAPI { } helpers.log(ctx, () => `Started carrying out hacking contracts for '${faction.name}'`); return true; - case "field": - case "fieldwork": - case "field work": + case FactionWorkType.field: if (!FactionInfos[faction.name].offerFieldWork) { helpers.log(ctx, () => `Faction '${faction.name}' do not need help with field missions.`); return false; @@ -860,9 +847,7 @@ export function NetscriptSingularity(): InternalAPI { } helpers.log(ctx, () => `Started carrying out field missions for '${faction.name}'`); return true; - case "security": - case "securitywork": - case "security work": + case FactionWorkType.security: if (!FactionInfos[faction.name].offerSecurityWork) { helpers.log(ctx, () => `Faction '${faction.name}' do not need help with security work.`); return false; @@ -1019,16 +1004,19 @@ export function NetscriptSingularity(): InternalAPI { }, commitCrime: (ctx) => (_crimeType, _focus) => { helpers.checkSingularityAccess(ctx); - const crimeType = helpers.string(ctx, "crimeType", _crimeType); + const crimeType = getEnumHelper("CrimeType").nsGetMember(ctx, _crimeType); const focus = _focus === undefined ? true : !!_focus; const wasFocusing = Player.focus; - if (Player.currentWork !== null) Player.finishWork(true); + if (Player.currentWork !== null) { + Player.finishWork(true); + } Player.gotoLocation(LocationName.Slums); - // If input isn't a crimeType, use search using roughname. - const crime = findCrime(crimeType); - if (crime == null) throw helpers.errorMessage(ctx, `Invalid crime: '${crimeType}'`); + const crime = Crimes[crimeType]; + if (crime == null) { + throw helpers.errorMessage(ctx, `Invalid crime: '${crimeType}'`); + } helpers.log(ctx, () => `Attempting to commit ${crime.type}...`); const crimeTime = crime.commit(1, ctx.workerScript); @@ -1043,21 +1031,23 @@ export function NetscriptSingularity(): InternalAPI { }, getCrimeChance: (ctx) => (_crimeType) => { helpers.checkSingularityAccess(ctx); - const crimeType = helpers.string(ctx, "crimeType", _crimeType); + const crimeType = getEnumHelper("CrimeType").nsGetMember(ctx, _crimeType); - // If input isn't a crimeType, use search using roughname. - const crime = findCrime(crimeType); - if (crime == null) throw helpers.errorMessage(ctx, `Invalid crime: '${crimeType}'`); + const crime = Crimes[crimeType]; + if (crime == null) { + throw helpers.errorMessage(ctx, `Invalid crime: '${crimeType}'`); + } return crime.successRate(Player); }, getCrimeStats: (ctx) => (_crimeType) => { helpers.checkSingularityAccess(ctx); - const crimeType = helpers.string(ctx, "crimeType", _crimeType); + const crimeType = getEnumHelper("CrimeType").nsGetMember(ctx, _crimeType); - // If input isn't a crimeType, use search using roughname. - const crime = findCrime(crimeType); - if (crime == null) throw helpers.errorMessage(ctx, `Invalid crime: '${crimeType}'`); + const crime = Crimes[crimeType]; + if (crime == null) { + throw helpers.errorMessage(ctx, `Invalid crime: '${crimeType}'`); + } const crimeStatsWithMultipliers = calculateCrimeWorkStats(Player, crime); diff --git a/src/NetscriptFunctions/Sleeve.ts b/src/NetscriptFunctions/Sleeve.ts index 312dec69d..4280d15e4 100644 --- a/src/NetscriptFunctions/Sleeve.ts +++ b/src/NetscriptFunctions/Sleeve.ts @@ -3,9 +3,8 @@ import type { Sleeve as NetscriptSleeve } from "@nsdefs"; import type { ActionIdentifier } from "../Bladeburner/Types"; import { Player } from "@player"; -import { BladeburnerActionType, type BladeburnerContractName } from "@enums"; +import { BladeburnerActionType, SpecialBladeburnerActionTypeForSleeve, type BladeburnerContractName } from "@enums"; import { Augmentations } from "../Augmentation/Augmentations"; -import { findCrime } from "../Crime/CrimeHelpers"; import { getEnumHelper } from "../utils/EnumHelper"; import { InternalAPI, NetscriptContext, setRemovedFunctions } from "../Netscript/APIWrapper"; import { isSleeveFactionWork } from "../PersonObjects/Sleeve/Work/SleeveFactionWork"; @@ -15,6 +14,7 @@ import { getAugCost } from "../Augmentation/AugmentationHelpers"; import { Factions } from "../Faction/Factions"; import { SleeveWorkType } from "../PersonObjects/Sleeve/Work/Work"; import { canAccessBitNodeFeature } from "../BitNode/BitNodeUtils"; +import { Crimes } from "../Crime/Crimes"; export const checkSleeveAPIAccess = function (ctx: NetscriptContext) { /** @@ -79,17 +79,17 @@ export function NetscriptSleeve(): InternalAPI { }, setToCommitCrime: (ctx) => (_sleeveNumber, _crimeType) => { const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber); - const crimeType = helpers.string(ctx, "crimeType", _crimeType); + const crimeType = getEnumHelper("CrimeType").nsGetMember(ctx, _crimeType); checkSleeveAPIAccess(ctx); checkSleeveNumber(ctx, sleeveNumber); - const crime = findCrime(crimeType); + const crime = Crimes[crimeType]; if (crime == null) return false; return Player.sleeves[sleeveNumber].commitCrime(crime.type); }, setToUniversityCourse: (ctx) => (_sleeveNumber, _universityName, _className) => { const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber); const universityName = helpers.string(ctx, "universityName", _universityName); - const className = helpers.string(ctx, "className", _className); + const className = getEnumHelper("UniversityClassType").nsGetMember(ctx, _className); checkSleeveAPIAccess(ctx); checkSleeveNumber(ctx, sleeveNumber); return Player.sleeves[sleeveNumber].takeUniversityCourse(universityName, className); @@ -130,7 +130,7 @@ export function NetscriptSleeve(): InternalAPI { setToFactionWork: (ctx) => (_sleeveNumber, _factionName, _workType) => { const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber); const factionName = getEnumHelper("FactionName").nsGetMember(ctx, _factionName); - const workType = helpers.string(ctx, "workType", _workType); + const workType = getEnumHelper("FactionWorkType").nsGetMember(ctx, _workType); checkSleeveAPIAccess(ctx); checkSleeveNumber(ctx, sleeveNumber); @@ -164,7 +164,7 @@ export function NetscriptSleeve(): InternalAPI { setToGymWorkout: (ctx) => (_sleeveNumber, _gymName, _stat) => { const sleeveNumber = helpers.number(ctx, "sleeveNumber", _sleeveNumber); const gymName = helpers.string(ctx, "gymName", _gymName); - const stat = helpers.string(ctx, "stat", _stat); + const stat = getEnumHelper("GymType").nsGetMember(ctx, _stat); checkSleeveAPIAccess(ctx); checkSleeveNumber(ctx, sleeveNumber); @@ -267,7 +267,7 @@ export function NetscriptSleeve(): InternalAPI { return false; } let contract: BladeburnerContractName | undefined = undefined; - if (action === "Take on contracts") { + if (action === SpecialBladeburnerActionTypeForSleeve.TakeOnContracts) { contract = getEnumHelper("BladeburnerContractName").nsGetMember(ctx, _contract); for (let i = 0; i < Player.sleeves.length; ++i) { if (i === sleeveNumber) { diff --git a/src/NetscriptFunctions/StockMarket.ts b/src/NetscriptFunctions/StockMarket.ts index 21a5e7cb3..99b6e03d1 100644 --- a/src/NetscriptFunctions/StockMarket.ts +++ b/src/NetscriptFunctions/StockMarket.ts @@ -9,7 +9,7 @@ import { StockMarketPromise, } from "../StockMarket/StockMarket"; import { getBuyTransactionCost, getSellTransactionGain } from "../StockMarket/StockMarketHelpers"; -import { PositionType, OrderType, StockSymbol } from "@enums"; +import { StockSymbol } from "@enums"; import { getStockMarket4SDataCost, getStockMarket4STixApiCost, @@ -21,6 +21,7 @@ import { StockOrder, TIX } from "@nsdefs"; import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper"; import { helpers } from "../Netscript/NetscriptHelpers"; import { StockMarketConstants } from "../StockMarket/data/Constants"; +import { getEnumHelper } from "../utils/EnumHelper"; export function NetscriptStockMarket(): InternalAPI { /** Checks if the player has TIX API access. Throws an error if the player does not */ @@ -99,22 +100,12 @@ export function NetscriptStockMarket(): InternalAPI { getPurchaseCost: (ctx) => (_symbol, _shares, _posType) => { const symbol = helpers.string(ctx, "symbol", _symbol); let shares = helpers.number(ctx, "shares", _shares); - const posType = helpers.string(ctx, "posType", _posType); + const posType = getEnumHelper("PositionType").nsGetMember(ctx, _posType); checkTixApiAccess(ctx); const stock = getStockFromSymbol(ctx, symbol); shares = Math.round(shares); - let pos; - const sanitizedPosType = posType.toLowerCase(); - if (sanitizedPosType.includes("l")) { - pos = PositionType.Long; - } else if (sanitizedPosType.includes("s")) { - pos = PositionType.Short; - } else { - return Infinity; - } - - const res = getBuyTransactionCost(stock, shares, pos); + const res = getBuyTransactionCost(stock, shares, posType); if (res == null) { return Infinity; } @@ -124,22 +115,12 @@ export function NetscriptStockMarket(): InternalAPI { getSaleGain: (ctx) => (_symbol, _shares, _posType) => { const symbol = helpers.string(ctx, "symbol", _symbol); let shares = helpers.number(ctx, "shares", _shares); - const posType = helpers.string(ctx, "posType", _posType); + const posType = getEnumHelper("PositionType").nsGetMember(ctx, _posType); checkTixApiAccess(ctx); const stock = getStockFromSymbol(ctx, symbol); shares = Math.round(shares); - let pos; - const sanitizedPosType = posType.toLowerCase(); - if (sanitizedPosType.includes("l")) { - pos = PositionType.Long; - } else if (sanitizedPosType.includes("s")) { - pos = PositionType.Short; - } else { - return 0; - } - - const res = getSellTransactionGain(stock, shares, pos); + const res = getSellTransactionGain(stock, shares, posType); if (res == null) { return 0; } @@ -191,46 +172,22 @@ export function NetscriptStockMarket(): InternalAPI { const symbol = helpers.string(ctx, "symbol", _symbol); const shares = helpers.number(ctx, "shares", _shares); const price = helpers.number(ctx, "price", _price); - const type = helpers.string(ctx, "type", _type); - const pos = helpers.string(ctx, "pos", _pos); + const type = getEnumHelper("OrderType").nsGetMember(ctx, _type); + const pos = getEnumHelper("PositionType").nsGetMember(ctx, _pos); checkTixApiAccess(ctx); if (Player.bitNodeN !== 8 && Player.activeSourceFileLvl(8) <= 2) { throw helpers.errorMessage(ctx, "You must either be in BitNode-8 or you must have Source-File 8 Level 3."); } const stock = getStockFromSymbol(ctx, symbol); - let orderType; - let orderPos; - const ltype = type.toLowerCase(); - if (ltype.includes("limit") && ltype.includes("buy")) { - orderType = OrderType.LimitBuy; - } else if (ltype.includes("limit") && ltype.includes("sell")) { - orderType = OrderType.LimitSell; - } else if (ltype.includes("stop") && ltype.includes("buy")) { - orderType = OrderType.StopBuy; - } else if (ltype.includes("stop") && ltype.includes("sell")) { - orderType = OrderType.StopSell; - } else { - throw helpers.errorMessage(ctx, `Invalid order type: ${type}`); - } - - const lpos = pos.toLowerCase(); - if (lpos.includes("l")) { - orderPos = PositionType.Long; - } else if (lpos.includes("s")) { - orderPos = PositionType.Short; - } else { - throw helpers.errorMessage(ctx, `Invalid position type: ${pos}`); - } - - return placeOrder(stock, shares, price, orderType, orderPos, ctx); + return placeOrder(stock, shares, price, type, pos, ctx); }, cancelOrder: (ctx) => (_symbol, _shares, _price, _type, _pos) => { const symbol = helpers.string(ctx, "symbol", _symbol); const shares = helpers.number(ctx, "shares", _shares); const price = helpers.number(ctx, "price", _price); - const type = helpers.string(ctx, "type", _type); - const pos = helpers.string(ctx, "pos", _pos); + const type = getEnumHelper("OrderType").nsGetMember(ctx, _type); + const pos = getEnumHelper("PositionType").nsGetMember(ctx, _pos); checkTixApiAccess(ctx); if (Player.bitNodeN !== 8 && Player.activeSourceFileLvl(8) <= 2) { throw helpers.errorMessage(ctx, "You must either be in BitNode-8 or you must have Source-File 8 Level 3."); @@ -239,37 +196,8 @@ export function NetscriptStockMarket(): InternalAPI { if (isNaN(shares) || isNaN(price)) { throw helpers.errorMessage(ctx, `Invalid shares or price. Must be numeric. shares=${shares}, price=${price}`); } - let orderType; - let orderPos; - const ltype = type.toLowerCase(); - if (ltype.includes("limit") && ltype.includes("buy")) { - orderType = OrderType.LimitBuy; - } else if (ltype.includes("limit") && ltype.includes("sell")) { - orderType = OrderType.LimitSell; - } else if (ltype.includes("stop") && ltype.includes("buy")) { - orderType = OrderType.StopBuy; - } else if (ltype.includes("stop") && ltype.includes("sell")) { - orderType = OrderType.StopSell; - } else { - throw helpers.errorMessage(ctx, `Invalid order type: ${type}`); - } - const lpos = pos.toLowerCase(); - if (lpos.includes("l")) { - orderPos = PositionType.Long; - } else if (lpos.includes("s")) { - orderPos = PositionType.Short; - } else { - throw helpers.errorMessage(ctx, `Invalid position type: ${pos}`); - } - const params = { - stock: stock, - shares: shares, - price: price, - type: orderType, - pos: orderPos, - }; - return cancelOrder(params, ctx); + return cancelOrder({ stock, shares, price, type, pos }, ctx); }, getOrders: (ctx) => () => { checkTixApiAccess(ctx); @@ -277,7 +205,7 @@ export function NetscriptStockMarket(): InternalAPI { throw helpers.errorMessage(ctx, "You must either be in BitNode-8 or have Source-File 8 Level 3."); } - const orders: StockOrder = {}; + const orders: Record = {}; const stockMarketOrders = StockMarket.Orders; for (const symbol of Object.keys(stockMarketOrders)) { diff --git a/src/PersonObjects/Sleeve/Sleeve.ts b/src/PersonObjects/Sleeve/Sleeve.ts index 39b781bee..05e3a8fb7 100644 --- a/src/PersonObjects/Sleeve/Sleeve.ts +++ b/src/PersonObjects/Sleeve/Sleeve.ts @@ -28,6 +28,7 @@ import { BladeburnerActionType, BladeburnerGeneralActionName, AugmentationName, + SpecialBladeburnerActionTypeForSleeve, } from "@enums"; import { Factions } from "../../Faction/Factions"; @@ -286,22 +287,22 @@ export class Sleeve extends Person implements SleevePerson { } /** Take a course at a university */ - takeUniversityCourse(universityName: string, className: string): boolean { + takeUniversityCourse(universityName: string, className: UniversityClassType): boolean { // Set exp/money multipliers based on which university. // Also check that the sleeve is in the right city let loc: LocationName | undefined; - switch (universityName.toLowerCase()) { - case LocationName.AevumSummitUniversity.toLowerCase(): { + switch (universityName) { + case LocationName.AevumSummitUniversity: { if (this.city !== CityName.Aevum) return false; loc = LocationName.AevumSummitUniversity; break; } - case LocationName.Sector12RothmanUniversity.toLowerCase(): { + case LocationName.Sector12RothmanUniversity: { if (this.city !== CityName.Sector12) return false; loc = LocationName.Sector12RothmanUniversity; break; } - case LocationName.VolhavenZBInstituteOfTechnology.toLowerCase(): { + case LocationName.VolhavenZBInstituteOfTechnology: { if (this.city !== CityName.Volhaven) return false; loc = LocationName.VolhavenZBInstituteOfTechnology; break; @@ -311,25 +312,23 @@ export class Sleeve extends Person implements SleevePerson { // Set experience/money gains based on class let classType: ClassType | undefined; - // TODO: why lower case??? It's not effecient, not typesafe and in general a bad idea - switch (className.toLowerCase()) { - case "study computer science": // deprecated, leave it here for backwards compatibility - case ClassType.computerScience.toLowerCase(): + switch (className) { + case ClassType.computerScience: classType = UniversityClassType.computerScience; break; - case ClassType.dataStructures.toLowerCase(): + case ClassType.dataStructures: classType = UniversityClassType.dataStructures; break; - case ClassType.networks.toLowerCase(): + case ClassType.networks: classType = UniversityClassType.networks; break; - case ClassType.algorithms.toLowerCase(): + case ClassType.algorithms: classType = UniversityClassType.algorithms; break; - case ClassType.management.toLowerCase(): + case ClassType.management: classType = UniversityClassType.management; break; - case ClassType.leadership.toLowerCase(): + case ClassType.leadership: classType = UniversityClassType.leadership; break; } @@ -376,17 +375,8 @@ export class Sleeve extends Person implements SleevePerson { return true; } - /** TODO 2.4: Make this take in type correct data */ - workForFaction(factionName: FactionName, _workType: string): boolean { - const workTypeConversion: Record = { - "Hacking Contracts": "hacking", - "Field Work": "field", - "Security Work": "security", - }; - if (workTypeConversion[_workType]) _workType = workTypeConversion[_workType]; + workForFaction(factionName: FactionName, workType: FactionWorkType): boolean { const faction = Factions[factionName]; - const workType = getEnumHelper("FactionWorkType").getMember(_workType, { fuzzy: true }); - if (!workType) return false; const factionInfo = faction.getInfo(); switch (workType) { @@ -412,62 +402,41 @@ export class Sleeve extends Person implements SleevePerson { } /** Begin a gym workout task */ - workoutAtGym(gymName: string, stat: string): boolean { - // Set exp/money multipliers based on which university. - // Also check that the sleeve is in the right city + workoutAtGym(gymName: string, stat: GymType): boolean { + // Check that the sleeve is in the right city let loc: LocationName | undefined; - switch (gymName.toLowerCase()) { - case LocationName.AevumCrushFitnessGym.toLowerCase(): { - if (this.city != CityName.Aevum) return false; + switch (gymName) { + case LocationName.AevumCrushFitnessGym: { + if (this.city !== CityName.Aevum) return false; loc = LocationName.AevumCrushFitnessGym; break; } - case LocationName.AevumSnapFitnessGym.toLowerCase(): { - if (this.city != CityName.Aevum) return false; + case LocationName.AevumSnapFitnessGym: { + if (this.city !== CityName.Aevum) return false; loc = LocationName.AevumSnapFitnessGym; break; } - case LocationName.Sector12IronGym.toLowerCase(): { - if (this.city != CityName.Sector12) return false; + case LocationName.Sector12IronGym: { + if (this.city !== CityName.Sector12) return false; loc = LocationName.Sector12IronGym; break; } - case LocationName.Sector12PowerhouseGym.toLowerCase(): { - if (this.city != CityName.Sector12) return false; + case LocationName.Sector12PowerhouseGym: { + if (this.city !== CityName.Sector12) return false; loc = LocationName.Sector12PowerhouseGym; break; } - case LocationName.VolhavenMilleniumFitnessGym.toLowerCase(): { - if (this.city != CityName.Volhaven) return false; + case LocationName.VolhavenMilleniumFitnessGym: { + if (this.city !== CityName.Volhaven) return false; loc = LocationName.VolhavenMilleniumFitnessGym; break; } } if (!loc) return false; - // Set experience/money gains based on class - const sanitizedStat: string = stat.toLowerCase(); - - // set stat to a default value. - let classType: ClassType | undefined; - if (sanitizedStat.includes("str")) { - classType = GymType.strength; - } - if (sanitizedStat.includes("def")) { - classType = GymType.defense; - } - if (sanitizedStat.includes("dex")) { - classType = GymType.dexterity; - } - if (sanitizedStat.includes("agi")) { - classType = GymType.agility; - } - // if stat is still equals its default value, then validation has failed. - if (!classType) return false; - this.startWork( new SleeveClassWork({ - classType: classType, + classType: stat, location: loc, }), ); @@ -479,50 +448,48 @@ export class Sleeve extends Person implements SleevePerson { bladeburner(action: string, contract?: string): boolean { if (!Player.bladeburner) return false; switch (action) { - case "Training": + case BladeburnerGeneralActionName.Training: this.startWork( new SleeveBladeburnerWork({ actionId: { type: BladeburnerActionType.General, name: BladeburnerGeneralActionName.Training }, }), ); return true; - case "Field analysis": - case "Field Analysis": + case BladeburnerGeneralActionName.FieldAnalysis: this.startWork( new SleeveBladeburnerWork({ actionId: { type: BladeburnerActionType.General, name: BladeburnerGeneralActionName.FieldAnalysis }, }), ); return true; - case "Recruitment": + case BladeburnerGeneralActionName.Recruitment: this.startWork( new SleeveBladeburnerWork({ actionId: { type: BladeburnerActionType.General, name: BladeburnerGeneralActionName.Recruitment }, }), ); return true; - case "Diplomacy": + case BladeburnerGeneralActionName.Diplomacy: this.startWork( new SleeveBladeburnerWork({ actionId: { type: BladeburnerActionType.General, name: BladeburnerGeneralActionName.Diplomacy }, }), ); return true; - case "Hyperbolic Regeneration Chamber": + case BladeburnerGeneralActionName.HyperbolicRegen: this.startWork( new SleeveBladeburnerWork({ actionId: { type: BladeburnerActionType.General, name: BladeburnerGeneralActionName.HyperbolicRegen }, }), ); return true; - case "Infiltrate synthoids": - case "Infiltrate Synthoids": + case SpecialBladeburnerActionTypeForSleeve.InfiltrateSynthoids: this.startWork(new SleeveInfiltrateWork()); return true; - case "Support main sleeve": + case SpecialBladeburnerActionTypeForSleeve.SupportMainSleeve: this.startWork(new SleeveSupportWork()); return true; - case "Take on contracts": + case SpecialBladeburnerActionTypeForSleeve.TakeOnContracts: if (!getEnumHelper("BladeburnerContractName").isMember(contract)) return false; this.startWork( new SleeveBladeburnerWork({ actionId: { type: BladeburnerActionType.Contract, name: contract } }), diff --git a/src/PersonObjects/Sleeve/Work/SleeveCrimeWork.ts b/src/PersonObjects/Sleeve/Work/SleeveCrimeWork.ts index 4d0a086d8..ce17b3927 100644 --- a/src/PersonObjects/Sleeve/Work/SleeveCrimeWork.ts +++ b/src/PersonObjects/Sleeve/Work/SleeveCrimeWork.ts @@ -8,7 +8,6 @@ import { Crime } from "../../../Crime/Crime"; import { scaleWorkStats, WorkStats } from "../../../Work/WorkStats"; import { CONSTANTS } from "../../../Constants"; import { calculateCrimeWorkStats } from "../../../Work/Formulas"; -import { findCrime } from "../../../Crime/CrimeHelpers"; export const isSleeveCrimeWork = (w: SleeveWorkClass | null): w is SleeveCrimeWork => w !== null && w.type === SleeveWorkType.CRIME; @@ -68,10 +67,12 @@ export class SleeveCrimeWork extends SleeveWorkClass { return Generic_toJSON("SleeveCrimeWork", this); } - /** Initializes a RecoveryWork object from a JSON save state. */ + /** Initializes an object from a JSON save state. */ static fromJSON(value: IReviverValue): SleeveCrimeWork { const crimeWork = Generic_fromJSON(SleeveCrimeWork, value.data); - crimeWork.crimeType = findCrime(crimeWork.crimeType)?.type ?? CrimeType.shoplift; + if (!(crimeWork.crimeType in Crimes)) { + crimeWork.crimeType = CrimeType.shoplift; + } return crimeWork; } } diff --git a/src/PersonObjects/Sleeve/ui/SleeveElem.tsx b/src/PersonObjects/Sleeve/ui/SleeveElem.tsx index 0220b773d..bf63e87cb 100644 --- a/src/PersonObjects/Sleeve/ui/SleeveElem.tsx +++ b/src/PersonObjects/Sleeve/ui/SleeveElem.tsx @@ -1,6 +1,6 @@ import { Box, Button, Paper, Tooltip, Typography } from "@mui/material"; import React, { useEffect, useState } from "react"; -import { BladeburnerActionType, CrimeType, FactionWorkType, GymType } from "@enums"; +import { BladeburnerActionType, FactionWorkType, GymType, SpecialBladeburnerActionTypeForSleeve } from "@enums"; import { CONSTANTS } from "../../../Constants"; import { Player } from "@player"; import { formatPercent, formatInt } from "../../../ui/formatNumber"; @@ -11,9 +11,22 @@ import { SleeveAugmentationsModal } from "./SleeveAugmentationsModal"; import { EarningsElement, StatsElement } from "./StatsElement"; import { TaskSelector } from "./TaskSelector"; import { TravelModal } from "./TravelModal"; -import { findCrime } from "../../../Crime/CrimeHelpers"; import { type SleeveWork, SleeveWorkType } from "../Work/Work"; import { getEnumHelper } from "../../../utils/EnumHelper"; +import { getRecordEntries } from "../../../Types/Record"; + +const factionWorkTypeDescriptions = { + [FactionWorkType.field]: "Field Work", + [FactionWorkType.hacking]: "Hacking Contracts", + [FactionWorkType.security]: "Security Work", +}; + +const gymTypeDescriptions: Record = { + [GymType.strength]: "Train Strength", + [GymType.defense]: "Train Defense", + [GymType.dexterity]: "Train Dexterity", + [GymType.agility]: "Train Agility", +}; function getWorkDescription(sleeve: Sleeve, progress: number): string { const work = sleeve.currentWork; @@ -57,14 +70,9 @@ function getWorkDescription(sleeve: Sleeve, progress: number): string { ); } case SleeveWorkType.FACTION: { - // This isn't the way this should be handled... - const workNames = { - [FactionWorkType.field]: "Field Work", - [FactionWorkType.hacking]: "Hacking Contracts", - [FactionWorkType.security]: "Security Work", - }; - const doing = workNames[work.factionWorkType] ?? "nothing"; - return `This sleeve is currently doing ${doing} for ${work.factionName}.`; + return `This sleeve is currently doing ${factionWorkTypeDescriptions[work.factionWorkType]} for ${ + work.factionName + }.`; } case SleeveWorkType.INFILTRATE: return ( @@ -82,36 +90,29 @@ function calculateABC(work: SleeveWork | null): [string, string, string] { case SleeveWorkType.COMPANY: return ["Work for Company", work.companyName, "------"]; case SleeveWorkType.FACTION: { - const workNames = { - [FactionWorkType.field]: "Field Work", - [FactionWorkType.hacking]: "Hacking Contracts", - [FactionWorkType.security]: "Security Work", - }; - return ["Work for Faction", work.factionName, workNames[work.factionWorkType] ?? ""]; + return ["Work for Faction", work.factionName, factionWorkTypeDescriptions[work.factionWorkType]]; } case SleeveWorkType.BLADEBURNER: if (work.actionId.type === BladeburnerActionType.Contract) { - return ["Perform Bladeburner Actions", "Take on contracts", work.actionId.name]; + return [ + "Perform Bladeburner Actions", + SpecialBladeburnerActionTypeForSleeve.TakeOnContracts, + work.actionId.name, + ]; } return ["Perform Bladeburner Actions", work.actionId.name, "------"]; case SleeveWorkType.CLASS: { if (!work.isGym()) { return ["Take University Course", work.classType, work.location]; } - const gymNames: Record = { - [GymType.strength]: "Train Strength", - [GymType.defense]: "Train Defense", - [GymType.dexterity]: "Train Dexterity", - [GymType.agility]: "Train Agility", - }; - return ["Workout at Gym", gymNames[work.classType as GymType], work.location]; + return ["Workout at Gym", gymTypeDescriptions[work.classType as GymType], work.location]; } case SleeveWorkType.CRIME: return ["Commit Crime", getEnumHelper("CrimeType").getMember(work.crimeType, { alwaysMatch: true }), "------"]; case SleeveWorkType.SUPPORT: - return ["Perform Bladeburner Actions", "Support main sleeve", "------"]; + return ["Perform Bladeburner Actions", SpecialBladeburnerActionTypeForSleeve.SupportMainSleeve, "------"]; case SleeveWorkType.INFILTRATE: - return ["Perform Bladeburner Actions", "Infiltrate Synthoids", "------"]; + return ["Perform Bladeburner Actions", SpecialBladeburnerActionTypeForSleeve.InfiltrateSynthoids, "------"]; case SleeveWorkType.RECOVERY: return ["Shock Recovery", "------", "------"]; case SleeveWorkType.SYNCHRO: @@ -148,21 +149,41 @@ export function SleeveElem(props: SleeveElemProps): React.ReactElement { props.sleeve.stopWork(); break; case "Work for Company": - if (getEnumHelper("CompanyName").isMember(abc[1])) props.sleeve.workForCompany(abc[1]); - else console.error(`Invalid company name in setSleeveTask: ${abc[1]}`); + if (getEnumHelper("CompanyName").isMember(abc[1])) { + props.sleeve.workForCompany(abc[1]); + } else { + console.error(`Invalid company name in setSleeveTask: ${abc[1]}`); + } break; case "Work for Faction": - if (getEnumHelper("FactionName").isMember(abc[1])) props.sleeve.workForFaction(abc[1], abc[2]); - else console.error(`Invalid faction name in setSleeveTask: ${abc[1]}`); + if (getEnumHelper("FactionName").isMember(abc[1])) { + for (const [factionWorkType, description] of getRecordEntries(factionWorkTypeDescriptions)) { + if (description === abc[2]) { + props.sleeve.workForFaction(abc[1], factionWorkType); + break; + } + } + } else { + console.error(`Invalid faction name in setSleeveTask: ${abc[1]}`); + } break; case "Commit Crime": - props.sleeve.commitCrime(findCrime(abc[1])?.type ?? CrimeType.shoplift); + if (getEnumHelper("CrimeType").isMember(abc[1])) { + props.sleeve.commitCrime(abc[1]); + } break; case "Take University Course": - props.sleeve.takeUniversityCourse(abc[2], abc[1]); + if (getEnumHelper("UniversityClassType").isMember(abc[1])) { + props.sleeve.takeUniversityCourse(abc[2], abc[1]); + } break; case "Workout at Gym": - props.sleeve.workoutAtGym(abc[2], abc[1]); + for (const [gymType, description] of getRecordEntries(gymTypeDescriptions)) { + if (description === abc[1]) { + props.sleeve.workoutAtGym(abc[2], gymType); + break; + } + } break; case "Perform Bladeburner Actions": props.sleeve.bladeburner(abc[1], abc[2]); diff --git a/src/PersonObjects/Sleeve/ui/TaskSelector.tsx b/src/PersonObjects/Sleeve/ui/TaskSelector.tsx index c0f5926ba..c6b39704f 100644 --- a/src/PersonObjects/Sleeve/ui/TaskSelector.tsx +++ b/src/PersonObjects/Sleeve/ui/TaskSelector.tsx @@ -4,33 +4,35 @@ import React from "react"; import { MenuItem, Select, SelectChangeEvent } from "@mui/material"; import { Player } from "@player"; -import { BladeburnerActionType, BladeburnerContractName, CityName, FactionName, LocationName } from "@enums"; +import { + BladeburnerActionType, + BladeburnerContractName, + BladeburnerGeneralActionName, + CityName, + FactionName, + LocationName, + SpecialBladeburnerActionTypeForSleeve, + UniversityClassType, +} from "@enums"; import { Crimes } from "../../../Crime/Crimes"; import { Factions } from "../../../Faction/Factions"; import { getEnumHelper } from "../../../utils/EnumHelper"; import { SleeveWorkType } from "../Work/Work"; import { getRecordKeys } from "../../../Types/Record"; -const universitySelectorOptions: string[] = [ - "Computer Science", - "Data Structures", - "Networks", - "Algorithms", - "Management", - "Leadership", -]; +const universitySelectorOptions = Object.values(UniversityClassType); const gymSelectorOptions: string[] = ["Train Strength", "Train Defense", "Train Dexterity", "Train Agility"]; const bladeburnerSelectorOptions: string[] = [ - "Training", - "Field Analysis", - "Recruitment", - "Diplomacy", - "Hyperbolic Regeneration Chamber", - "Infiltrate Synthoids", - "Support main sleeve", - "Take on contracts", + BladeburnerGeneralActionName.Training, + BladeburnerGeneralActionName.FieldAnalysis, + BladeburnerGeneralActionName.Recruitment, + BladeburnerGeneralActionName.Diplomacy, + BladeburnerGeneralActionName.HyperbolicRegen, + SpecialBladeburnerActionTypeForSleeve.InfiltrateSynthoids, + SpecialBladeburnerActionTypeForSleeve.SupportMainSleeve, + SpecialBladeburnerActionTypeForSleeve.TakeOnContracts, ]; interface IProps { @@ -201,7 +203,7 @@ const tasks: { return { first: bladeburnerSelectorOptions, second: (s1: string) => { - if (s1 === "Take on contracts") { + if (s1 === SpecialBladeburnerActionTypeForSleeve.TakeOnContracts) { return possibleContracts(sleeve); } else { return ["------"]; diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index f2ba6e867..5b7290649 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -430,10 +430,9 @@ type OrderEnumType = { type OrderType = _ValueOf; /** - * Value in map of {@link StockOrder} * @public */ -interface StockOrderObject { +interface StockOrder { /** Number of shares */ shares: number; /** Price per share */ @@ -444,16 +443,6 @@ interface StockOrderObject { position: PositionType; } -/** - * Return value of {@link TIX.getOrders | getOrders} - * - * Keys are stock symbols, properties are arrays of {@link StockOrderObject} - * @public - */ -interface StockOrder { - [key: string]: StockOrderObject[]; -} - /** Constants used for the stock market game mechanic. * @public */ interface StockMarketConstants { @@ -1381,10 +1370,10 @@ export interface TIX { * * @param sym - Stock symbol. * @param shares - Number of shares to purchase. - * @param posType - Specifies whether the order is a “Long” or “Short” position. + * @param positionType - Specifies whether the order is a Long ("L") or Short ("S") position. * @returns Cost to buy a given number of shares of a stock. */ - getPurchaseCost(sym: string, shares: number, posType: string): number; + getPurchaseCost(sym: string, shares: number, positionType: PositionType): number; /** * Calculate profit of selling stocks. @@ -1395,10 +1384,10 @@ export interface TIX { * * @param sym - Stock symbol. * @param shares - Number of shares to sell. - * @param posType - Specifies whether the order is a “Long” or “Short” position. + * @param positionType - Specifies whether the order is a Long ("L") or Short ("S") position. * @returns Gain from selling a given number of shares of a stock. */ - getSaleGain(sym: string, shares: number, posType: string): number; + getSaleGain(sym: string, shares: number, positionType: PositionType): number; /** * Buy stocks. @@ -1501,11 +1490,11 @@ export interface TIX { * @param sym - Stock symbol. * @param shares - Number of shares for order. Must be positive. Will be rounded to the nearest integer. * @param price - Execution price for the order. - * @param type - Type of order. - * @param pos - Specifies whether the order is a “Long” or “Short” position. + * @param orderType - Type of order. + * @param positionType - Specifies whether the order is a Long ("L") or Short ("S") position. * @returns True if the order is successfully placed, and false otherwise. */ - placeOrder(sym: string, shares: number, price: number, type: string, pos: string): boolean; + placeOrder(sym: string, shares: number, price: number, orderType: OrderType, positionType: PositionType): boolean; /** * Cancel order for stocks. @@ -1519,10 +1508,10 @@ export interface TIX { * @param sym - Stock symbol. * @param shares - Number of shares for order. Must be positive. Will be rounded to the nearest integer. * @param price - Execution price for the order. - * @param type - Type of order. - * @param pos - Specifies whether the order is a “Long” or “Short” position. + * @param orderType - Type of order. + * @param positionType - Specifies whether the order is a Long ("L") or Short ("S") position. */ - cancelOrder(sym: string, shares: number, price: number, type: string, pos: string): void; + cancelOrder(sym: string, shares: number, price: number, orderType: OrderType, positionType: PositionType): void; /** * Returns your order book for the stock market. @@ -1530,7 +1519,7 @@ export interface TIX { * RAM cost: 2.5 GB * This is an object containing information for all the Limit and Stop Orders you have in the stock market. * For each symbol you have a position in, the returned object will have a key with that symbol's name. - * The object's properties are each an array of {@link StockOrderObject} + * The object's properties are each an array of {@link StockOrder} * The object has the following structure: * * ```js @@ -1585,9 +1574,10 @@ export interface TIX { * ], * } * ``` - * @returns Object containing information for all the Limit and Stop Orders you have in the stock market. + * @returns Object containing information for all the Limit and Stop Orders you have in the stock market. Keys are + * stock symbols, and properties are arrays of {@link StockOrder} */ - getOrders(): StockOrder; + getOrders(): Record; /** * Returns the volatility of the specified stock.