diff --git a/markdown/bitburner.companypositioninfo.field.md b/markdown/bitburner.companypositioninfo.field.md
new file mode 100644
index 000000000..cbd11546a
--- /dev/null
+++ b/markdown/bitburner.companypositioninfo.field.md
@@ -0,0 +1,11 @@
+
+
+[Home](./index.md) > [bitburner](./bitburner.md) > [CompanyPositionInfo](./bitburner.companypositioninfo.md) > [field](./bitburner.companypositioninfo.field.md)
+
+## CompanyPositionInfo.field property
+
+**Signature:**
+
+```typescript
+field: JobField;
+```
diff --git a/markdown/bitburner.companypositioninfo.md b/markdown/bitburner.companypositioninfo.md
index f76fd5828..538e84634 100644
--- a/markdown/bitburner.companypositioninfo.md
+++ b/markdown/bitburner.companypositioninfo.md
@@ -16,6 +16,7 @@ export interface CompanyPositionInfo
| Property | Modifiers | Type | Description |
| --- | --- | --- | --- |
+| [field](./bitburner.companypositioninfo.field.md) | | [JobField](./bitburner.jobfield.md) | |
| [name](./bitburner.companypositioninfo.name.md) | | [JobName](./bitburner.jobname.md) | |
| [nextPosition](./bitburner.companypositioninfo.nextposition.md) | | [JobName](./bitburner.jobname.md) \| null | |
| [requiredReputation](./bitburner.companypositioninfo.requiredreputation.md) | | number | |
diff --git a/markdown/bitburner.jobfield.md b/markdown/bitburner.jobfield.md
new file mode 100644
index 000000000..9c37371f9
--- /dev/null
+++ b/markdown/bitburner.jobfield.md
@@ -0,0 +1,31 @@
+
+
+[Home](./index.md) > [bitburner](./bitburner.md) > [JobField](./bitburner.jobfield.md)
+
+## JobField enum
+
+
+**Signature:**
+
+```typescript
+declare enum JobField
+```
+
+## Enumeration Members
+
+| Member | Value | Description |
+| --- | --- | --- |
+| agent | "Agent"
| |
+| business | "Business"
| |
+| businessConsultant | "Business Consultant"
| |
+| employee | "Employee"
| |
+| it | "IT"
| |
+| networkEngineer | "Network Engineer"
| |
+| partTimeEmployee | "part-time Employee"
| |
+| partTimeWaiter | "part-time Waiter"
| |
+| security | "Security"
| |
+| securityEngineer | "Security Engineer"
| |
+| software | "Software"
| |
+| softwareConsultant | "Software Consultant"
| |
+| waiter | "Waiter"
| |
+
diff --git a/markdown/bitburner.md b/markdown/bitburner.md
index 8cb319a2c..6ae71ba46 100644
--- a/markdown/bitburner.md
+++ b/markdown/bitburner.md
@@ -13,6 +13,7 @@
| [CrimeType](./bitburner.crimetype.md) | |
| [FactionWorkType](./bitburner.factionworktype.md) | |
| [GymType](./bitburner.gymtype.md) | |
+| [JobField](./bitburner.jobfield.md) | |
| [JobName](./bitburner.jobname.md) | |
| [LocationName](./bitburner.locationname.md) | Names of all locations |
| [OrderType](./bitburner.ordertype.md) | |
diff --git a/markdown/bitburner.nsenums.md b/markdown/bitburner.nsenums.md
index f1b1fe8fc..a6d9b58da 100644
--- a/markdown/bitburner.nsenums.md
+++ b/markdown/bitburner.nsenums.md
@@ -14,11 +14,12 @@ export type NSEnums = {
FactionWorkType: typeof FactionWorkType;
GymType: typeof GymType;
JobName: typeof JobName;
+ JobField: typeof JobField;
LocationName: typeof LocationName;
ToastVariant: typeof ToastVariant;
UniversityClassType: typeof UniversityClassType;
CompanyName: typeof CompanyName;
};
```
-**References:** [CityName](./bitburner.cityname.md), [CrimeType](./bitburner.crimetype.md), [FactionWorkType](./bitburner.factionworktype.md), [GymType](./bitburner.gymtype.md), [JobName](./bitburner.jobname.md), [LocationName](./bitburner.locationname.md), [ToastVariant](./bitburner.toastvariant.md), [UniversityClassType](./bitburner.universityclasstype.md), [CompanyName](./bitburner.companyname.md)
+**References:** [CityName](./bitburner.cityname.md), [CrimeType](./bitburner.crimetype.md), [FactionWorkType](./bitburner.factionworktype.md), [GymType](./bitburner.gymtype.md), [JobName](./bitburner.jobname.md), [JobField](./bitburner.jobfield.md), [LocationName](./bitburner.locationname.md), [ToastVariant](./bitburner.toastvariant.md), [UniversityClassType](./bitburner.universityclasstype.md), [CompanyName](./bitburner.companyname.md)
diff --git a/markdown/bitburner.singularity.applytocompany.md b/markdown/bitburner.singularity.applytocompany.md
index 63eb45fdf..6d22ea046 100644
--- a/markdown/bitburner.singularity.applytocompany.md
+++ b/markdown/bitburner.singularity.applytocompany.md
@@ -9,7 +9,7 @@ Apply for a job at a company.
**Signature:**
```typescript
-applyToCompany(companyName: CompanyName | `${CompanyName}`, field: string): boolean;
+applyToCompany(companyName: CompanyName | `${CompanyName}`, field: JobField | `${JobField}`): boolean;
```
## Parameters
@@ -17,7 +17,7 @@ applyToCompany(companyName: CompanyName | `${CompanyName}`, field: string): bool
| Parameter | Type | Description |
| --- | --- | --- |
| companyName | [CompanyName](./bitburner.companyname.md) \| \`${[CompanyName](./bitburner.companyname.md)}\` | Name of company to apply to. |
-| field | string | Field to which you want to apply. |
+| field | [JobField](./bitburner.jobfield.md) \| \`${[JobField](./bitburner.jobfield.md)}\` | Field to which you want to apply. |
**Returns:**
diff --git a/src/Company/CompanyPosition.ts b/src/Company/CompanyPosition.ts
index a752512ec..36ea3438d 100644
--- a/src/Company/CompanyPosition.ts
+++ b/src/Company/CompanyPosition.ts
@@ -1,6 +1,6 @@
import { Person as IPerson } from "@nsdefs";
import { CONSTANTS } from "../Constants";
-import { JobName } from "@enums";
+import { JobName, JobField } from "@enums";
import {
agentJobs,
businessConsultJobs,
@@ -14,6 +14,7 @@ import {
export interface CompanyPositionCtorParams {
nextPosition: JobName | null;
+ field: JobField;
baseSalary: number;
repMultiplier: number;
@@ -44,6 +45,9 @@ export class CompanyPosition {
/** Position title */
name: JobName;
+ /** Field type of the position (software, it, business, etc) */
+ field: JobField;
+
/** Title of next position to be promoted to */
nextPosition: JobName | null;
@@ -85,6 +89,7 @@ export class CompanyPosition {
constructor(name: JobName, p: CompanyPositionCtorParams) {
this.name = name;
+ this.field = p.field;
this.nextPosition = p.nextPosition;
this.baseSalary = p.baseSalary;
this.repMultiplier = p.repMultiplier;
diff --git a/src/Company/data/CompanyPositionsMetadata.ts b/src/Company/data/CompanyPositionsMetadata.ts
index 629ac9a9a..e45812cb0 100644
--- a/src/Company/data/CompanyPositionsMetadata.ts
+++ b/src/Company/data/CompanyPositionsMetadata.ts
@@ -1,11 +1,12 @@
// Metadata used for constructing Company Positions
-import { JobName } from "@enums";
+import { JobName, JobField } from "@enums";
import { CompanyPositionCtorParams } from "../CompanyPosition";
export function getCompanyPositionMetadata(): Record {
return {
[JobName.software0]: {
nextPosition: JobName.software1, // Junior Software Engineer
+ field: JobField.software,
baseSalary: 33,
charismaEffectiveness: 15,
charismaExpGain: 0.02,
@@ -16,6 +17,7 @@ export function getCompanyPositionMetadata(): Record
)}
{company.hasBusinessConsultantPositions() && (
@@ -246,7 +246,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
company={company}
entryPosType={CompanyPositions[JobName.businessConsult0]}
onClick={applyForBusinessConsultantJob}
- text={"Apply for Business Consultant Job"}
+ text={"Apply for " + JobField.businessConsultant + " Job"}
/>
)}
{company.hasBusinessPositions() && (
@@ -254,7 +254,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
company={company}
entryPosType={CompanyPositions[JobName.business0]}
onClick={applyForBusinessJob}
- text={"Apply for Business Job"}
+ text={"Apply for " + JobField.business + " Job"}
/>
)}
{company.hasEmployeePositions() && (
@@ -262,7 +262,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
company={company}
entryPosType={CompanyPositions[JobName.employee]}
onClick={applyForEmployeeJob}
- text={"Apply to be an Employee"}
+ text={"Apply to be an " + JobField.employee}
/>
)}
{company.hasEmployeePositions() && (
@@ -270,7 +270,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
company={company}
entryPosType={CompanyPositions[JobName.employeePT]}
onClick={applyForPartTimeEmployeeJob}
- text={"Apply to be a part-time Employee"}
+ text={"Apply to be a " + JobField.partTimeEmployee}
/>
)}
{company.hasITPositions() && (
@@ -278,7 +278,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
company={company}
entryPosType={CompanyPositions[JobName.IT0]}
onClick={applyForItJob}
- text={"Apply for IT Job"}
+ text={"Apply for " + JobField.it + " Job"}
/>
)}
{company.hasSecurityPositions() && (
@@ -286,7 +286,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
company={company}
entryPosType={CompanyPositions[JobName.security0]}
onClick={applyForSecurityJob}
- text={"Apply for Security Job"}
+ text={"Apply for " + JobField.security + " Job"}
/>
)}
{company.hasSoftwareConsultantPositions() && (
@@ -294,7 +294,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
company={company}
entryPosType={CompanyPositions[JobName.softwareConsult0]}
onClick={applyForSoftwareConsultantJob}
- text={"Apply for Software Consultant Job"}
+ text={"Apply for " + JobField.softwareConsultant + " Job"}
/>
)}
{company.hasSoftwarePositions() && (
@@ -302,7 +302,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
company={company}
entryPosType={CompanyPositions[JobName.software0]}
onClick={applyForSoftwareJob}
- text={"Apply for Software Job"}
+ text={"Apply for " + JobField.software + " Job"}
/>
)}
{company.hasWaiterPositions() && (
@@ -310,7 +310,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
company={company}
entryPosType={CompanyPositions[JobName.waiter]}
onClick={applyForWaiterJob}
- text={"Apply to be a Waiter"}
+ text={"Apply to be a " + JobField.waiter}
/>
)}
{company.hasWaiterPositions() && (
@@ -318,7 +318,7 @@ export function CompanyLocation(props: IProps): React.ReactElement {
company={company}
entryPosType={CompanyPositions[JobName.waiterPT]}
onClick={applyForPartTimeWaiterJob}
- text={"Apply to be a part-time Waiter"}
+ text={"Apply to be a " + JobField.partTimeWaiter}
/>
)}
{location.infiltrationData != null && }
diff --git a/src/NetscriptFunctions.ts b/src/NetscriptFunctions.ts
index 7cefda6ca..641b6ddfe 100644
--- a/src/NetscriptFunctions.ts
+++ b/src/NetscriptFunctions.ts
@@ -20,6 +20,7 @@ import {
FactionWorkType,
GymType,
JobName,
+ JobField,
LiteratureName,
LocationName,
ToastVariant,
@@ -109,6 +110,7 @@ export const enums: NSEnums = {
FactionWorkType,
GymType,
JobName,
+ JobField,
LocationName,
ToastVariant,
UniversityClassType,
diff --git a/src/NetscriptFunctions/Singularity.ts b/src/NetscriptFunctions/Singularity.ts
index 1335017f8..dab4d7f77 100644
--- a/src/NetscriptFunctions/Singularity.ts
+++ b/src/NetscriptFunctions/Singularity.ts
@@ -8,6 +8,7 @@ import {
FactionName,
FactionWorkType,
GymType,
+ JobField,
LocationName,
UniversityClassType,
} from "@enums";
@@ -31,7 +32,7 @@ import { formatMoney, formatRam, formatReputation } from "../ui/formatNumber";
import { currentNodeMults } from "../BitNode/BitNodeMultipliers";
import { Companies } from "../Company/Companies";
import { Factions } from "../Faction/Factions";
-import { helpers } from "../Netscript/NetscriptHelpers";
+import { helpers, assertString } from "../Netscript/NetscriptHelpers";
import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions";
import { getServerOnNetwork } from "../Server/ServerHelpers";
import { Terminal } from "../Terminal";
@@ -687,6 +688,7 @@ export function NetscriptSingularity(): InternalAPI {
const job = CompanyPositions[positionName];
const res = {
name: CompanyPositions[positionName].name,
+ field: CompanyPositions[positionName].field,
nextPosition: CompanyPositions[positionName].nextPosition,
salary: CompanyPositions[positionName].baseSalary * company.salaryMultiplier,
requiredReputation: CompanyPositions[positionName].requiredReputation,
@@ -736,48 +738,63 @@ export function NetscriptSingularity(): InternalAPI {
applyToCompany: (ctx) => (_companyName, _field) => {
helpers.checkSingularityAccess(ctx);
const companyName = getEnumHelper("CompanyName").nsGetMember(ctx, _companyName);
- const field = helpers.string(ctx, "field", _field);
+ assertString(ctx, "field", _field);
+
+ // capitalize each word, except for "part-time"
+ function capitalizeJobField(field: string) {
+ return field
+ .toLowerCase()
+ .split(" ")
+ .map((s) => {
+ if (s.length == 0 || s == "part-time") return s;
+ if (s.length == 2) return s.toUpperCase(); // Probably an acronym
+ return s[0].toUpperCase() + s.slice(1);
+ })
+ .join(" ");
+ }
+
+ const field = getEnumHelper("JobField").nsGetMember(ctx, capitalizeJobField(_field as string), "field");
Player.location = companyNameAsLocationName(companyName);
let res;
- switch (field.toLowerCase()) {
- case "software":
+ switch (field) {
+ case JobField.software:
res = Player.applyForSoftwareJob(true);
break;
- case "software consultant":
+ case JobField.softwareConsultant:
res = Player.applyForSoftwareConsultantJob(true);
break;
- case "it":
+ case JobField.it:
res = Player.applyForItJob(true);
break;
- case "security engineer":
+ case JobField.securityEngineer:
res = Player.applyForSecurityEngineerJob(true);
break;
- case "network engineer":
+ case JobField.networkEngineer:
res = Player.applyForNetworkEngineerJob(true);
break;
- case "business":
+ case JobField.business:
res = Player.applyForBusinessJob(true);
break;
- case "business consultant":
+ case JobField.businessConsultant:
res = Player.applyForBusinessConsultantJob(true);
break;
- case "security":
+ case JobField.security:
res = Player.applyForSecurityJob(true);
break;
- case "agent":
+ case JobField.agent:
res = Player.applyForAgentJob(true);
break;
- case "employee":
+ case JobField.employee:
res = Player.applyForEmployeeJob(true);
break;
- case "part-time employee":
+ case JobField.partTimeEmployee:
res = Player.applyForPartTimeEmployeeJob(true);
break;
- case "waiter":
+ case JobField.waiter:
res = Player.applyForWaiterJob(true);
break;
- case "part-time waiter":
+ case JobField.partTimeWaiter:
res = Player.applyForPartTimeWaiterJob(true);
break;
default:
diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts
index de481fbf3..9401221cf 100644
--- a/src/ScriptEditor/NetscriptDefinitions.d.ts
+++ b/src/ScriptEditor/NetscriptDefinitions.d.ts
@@ -1856,7 +1856,7 @@ export interface Singularity {
* @param field - Field to which you want to apply.
* @returns True if the player successfully get a job/promotion, and false otherwise.
*/
- applyToCompany(companyName: CompanyName | `${CompanyName}`, field: string): boolean;
+ applyToCompany(companyName: CompanyName | `${CompanyName}`, field: JobField | `${JobField}`): boolean;
/**
* Get company reputation.
@@ -2423,6 +2423,7 @@ export interface Singularity {
*/
export interface CompanyPositionInfo {
name: JobName;
+ field: JobField;
nextPosition: JobName | null;
salary: number;
requiredReputation: number;
@@ -6860,6 +6861,23 @@ declare enum JobName {
employeePT = "Part-time Employee",
}
+/** @public */
+declare enum JobField {
+ software = "Software",
+ softwareConsultant = "Software Consultant",
+ it = "IT",
+ securityEngineer = "Security Engineer",
+ networkEngineer = "Network Engineer",
+ business = "Business",
+ businessConsultant = "Business Consultant",
+ security = "Security",
+ agent = "Agent",
+ employee = "Employee",
+ partTimeEmployee = "part-time Employee",
+ waiter = "Waiter",
+ partTimeWaiter = "part-time Waiter",
+}
+
// CORP ENUMS - Changed to types
/** @public */
type CorpEmployeePosition =
@@ -7021,6 +7039,7 @@ export type NSEnums = {
FactionWorkType: typeof FactionWorkType;
GymType: typeof GymType;
JobName: typeof JobName;
+ JobField: typeof JobField;
LocationName: typeof LocationName;
ToastVariant: typeof ToastVariant;
UniversityClassType: typeof UniversityClassType;
diff --git a/src/Work/Enums.ts b/src/Work/Enums.ts
index 1c31d3f6b..4cceec84a 100644
--- a/src/Work/Enums.ts
+++ b/src/Work/Enums.ts
@@ -63,3 +63,19 @@ export enum JobName {
businessConsult0 = "Business Consultant",
businessConsult1 = "Senior Business Consultant",
}
+
+export enum JobField {
+ software = "Software",
+ softwareConsultant = "Software Consultant",
+ it = "IT",
+ securityEngineer = "Security Engineer",
+ networkEngineer = "Network Engineer",
+ business = "Business",
+ businessConsultant = "Business Consultant",
+ security = "Security",
+ agent = "Agent",
+ employee = "Employee",
+ partTimeEmployee = "part-time Employee",
+ waiter = "Waiter",
+ partTimeWaiter = "part-time Waiter",
+}
diff --git a/test/jest/NetscriptFunctions/Singularity.test.ts b/test/jest/NetscriptFunctions/Singularity.test.ts
new file mode 100644
index 000000000..cd65e5402
--- /dev/null
+++ b/test/jest/NetscriptFunctions/Singularity.test.ts
@@ -0,0 +1,101 @@
+import { Player, setPlayer } from "../../../src/Player";
+import { getCompaniesMetadata } from "../../../src/Company/data/CompaniesMetadata";
+import { getCompanyPositionMetadata } from "../../../src/Company/data/CompanyPositionsMetadata";
+import { PlayerObject } from "../../../src/PersonObjects/Player/PlayerObject";
+import { NetscriptSingularity } from "../../../src/NetscriptFunctions/Singularity";
+import { CompanyName, JobField, JobName } from "@enums";
+
+import { WorkerScript } from "../../../src/Netscript/WorkerScript";
+import { Script } from "../../../src/Script/Script";
+import { RunningScript } from "../../../src/Script/RunningScript";
+import { ScriptFilePath } from "../../../src/Paths/ScriptFilePath";
+import { GetServer } from "../../../src/Server/AllServers";
+
+describe("Singularity", () => {
+ let ctx;
+ let singularity;
+ let positionMetadata;
+ let companyMetadata;
+
+ beforeAll(() => {
+ singularity = NetscriptSingularity();
+ positionMetadata = getCompanyPositionMetadata();
+ companyMetadata = getCompaniesMetadata();
+ });
+
+ beforeEach(() => {
+ setPlayer(new PlayerObject());
+ Player.init();
+ Player.sourceFiles.set(4, 3);
+
+ GetServer("home").writeToScriptFile("function.js", "");
+ let script = new Script("function.js", "", "home");
+ let runningScript = new RunningScript(script, 1, []);
+ let workerScript = new WorkerScript(runningScript, 1);
+ ctx = { workerScript: workerScript, function: "singularityTest", functionPath: "test.singularityTest" };
+ });
+
+ afterEach(() => {
+ Object.values(CompanyName).forEach((k) => {
+ companyMetadata[k].playerReputation = 0;
+ });
+ });
+
+ describe("getCompanyPositionInfo", () => {
+ it("returns an enum for field", () => {
+ let companyWithPositions = Object.values(CompanyName).find(
+ (cn) => companyMetadata[cn].companyPositions.length > 0,
+ );
+ let company = companyMetadata[companyWithPositions];
+ let positionName = company.companyPositions[0];
+ let position = positionMetadata[positionName];
+
+ let companyPosition = singularity.getCompanyPositionInfo(ctx)(company.name, positionName);
+ expect(companyPosition.field).toEqual(position.field);
+ });
+ });
+
+ describe("applyToCompany", () => {
+ it("throws an error if input doesn't match an enum", () => {
+ let anyValidCompany = Object.values(CompanyName)[0];
+ expect(() => singularity.applyToCompany(ctx)(anyValidCompany, "sockware")).toThrow("should be a JobField");
+ expect(() => singularity.applyToCompany(ctx)(anyValidCompany, "invalid-job-field")).toThrow(
+ "should be a JobField",
+ );
+ });
+
+ it("accepts the JobField specified by getCompanyPositionInfo", () => {
+ Object.values(CompanyName).forEach((cn) => {
+ companyMetadata[cn].companyPositions.forEach((pn) => {
+ let pos = positionMetadata[pn];
+ expect(() => singularity.applyToCompany(ctx)(cn, pos.field)).not.toThrow();
+ Player.quitJob(cn);
+ });
+ });
+ });
+
+ it("is case-insensitive to string inputs to the field parameter", () => {
+ Object.values(CompanyName).forEach((cn) => {
+ companyMetadata[cn].companyPositions.forEach((pn) => {
+ let pos = positionMetadata[pn];
+ let field = pos.field;
+
+ let upperCase = field.toUpperCase();
+ expect(() => singularity.applyToCompany(ctx)(cn, upperCase)).not.toThrow();
+ Player.quitJob(cn);
+
+ let lowerCase = field.toLowerCase();
+ expect(() => singularity.applyToCompany(ctx)(cn, lowerCase)).not.toThrow();
+ Player.quitJob(cn);
+
+ let brokenCasing = field
+ .split("")
+ .map((c, i) => (i % 2 == 0 ? c.toUpperCase() : c.toLowerCase()))
+ .join("");
+ expect(() => singularity.applyToCompany(ctx)(cn, brokenCasing)).not.toThrow();
+ Player.quitJob(cn);
+ });
+ });
+ });
+ });
+});