From de6b20234104fe911e7a1a9a05fb7bdf0af11f92 Mon Sep 17 00:00:00 2001 From: catloversg <152669316+catloversg@users.noreply.github.com> Date: Mon, 3 Feb 2025 00:29:18 +0700 Subject: [PATCH] CODEBASE: Refactor Player.applyForJob (#1947) --- src/Company/ui/ApplyToJobButton.tsx | 6 +- src/NetscriptFunctions/Singularity.ts | 16 ++-- .../Player/PlayerObjectGeneralMethods.ts | 56 +++++------ test/jest/Netscript/Singularity.test.ts | 92 ++++++++++++++++++- 4 files changed, 133 insertions(+), 37 deletions(-) diff --git a/src/Company/ui/ApplyToJobButton.tsx b/src/Company/ui/ApplyToJobButton.tsx index b36ed3a71..be98ec261 100644 --- a/src/Company/ui/ApplyToJobButton.tsx +++ b/src/Company/ui/ApplyToJobButton.tsx @@ -9,6 +9,7 @@ import { ButtonWithTooltip } from "../../ui/Components/ButtonWithTooltip"; import { JobSummary } from "./JobSummary"; import { Requirement } from "../../ui/Components/Requirement"; import { getJobRequirements } from "../GetJobRequirements"; +import { dialogBoxCreate } from "../../ui/React/DialogBox"; interface ApplyToJobProps { company: Company; @@ -47,7 +48,10 @@ export function ApplyToJobButton({ company, position, qualified }: ApplyToJobPro ); function applyForJob(): void { - Player.applyForJob(company, position); + const result = Player.applyForJob(company, position); + if (result.message) { + dialogBoxCreate(result.message); + } } return ( diff --git a/src/NetscriptFunctions/Singularity.ts b/src/NetscriptFunctions/Singularity.ts index 953b29005..c4764488f 100644 --- a/src/NetscriptFunctions/Singularity.ts +++ b/src/NetscriptFunctions/Singularity.ts @@ -714,13 +714,17 @@ export function NetscriptSingularity(): InternalAPI { const company = Companies[companyName]; const entryPos = CompanyPositions[JobTracks[field][0]]; - const jobName = Player.applyForJob(company, entryPos, true); - if (jobName) { - helpers.log(ctx, () => `You were offered a new job at '${companyName}' with position '${jobName}'`); - } else { - helpers.log(ctx, () => `You failed to get a new job/promotion at '${companyName}' in the '${field}' field.`); + const result = Player.applyForJob(company, entryPos); + if (!result.success) { + helpers.log( + ctx, + () => + `You failed to get a new job/promotion at '${companyName}' in the '${field}' field. Reason: ${result.message}`, + ); + return null; } - return jobName; + helpers.log(ctx, () => `You were offered a new job at '${companyName}' with position '${result.jobName}'.`); + return result.jobName; }, quitJob: (ctx) => (_companyName) => { helpers.checkSingularityAccess(ctx); diff --git a/src/PersonObjects/Player/PlayerObjectGeneralMethods.ts b/src/PersonObjects/Player/PlayerObjectGeneralMethods.ts index 3294efeae..bbf801d02 100644 --- a/src/PersonObjects/Player/PlayerObjectGeneralMethods.ts +++ b/src/PersonObjects/Player/PlayerObjectGeneralMethods.ts @@ -53,6 +53,7 @@ import { canAccessBitNodeFeature } from "../../BitNode/BitNodeUtils"; import { AlertEvents } from "../../ui/React/AlertManager"; import { Augmentations } from "../../Augmentation/Augmentations"; import { PlayerEventType, PlayerEvents } from "./PlayerEvents"; +import { Result } from "../../types"; export function init(this: PlayerObject): void { /* Initialize Player's home computer */ @@ -288,22 +289,25 @@ export function applyForJob( this: PlayerObject, company: Company, position: CompanyPosition, - sing = false, -): JobName | null { - if (!company) return null; +): Result<{ jobName: JobName }> { + if (!company) { + return { success: false, message: `Invalid company: ${company}.` }; + } // Start searching the job track from the provided point (which may not be the entry position) let pos = position; if (!this.isQualified(company, pos)) { - if (!sing) { - dialogBoxCreate(`Unfortunately, you do not qualify for this position.\n${getJobRequirementText(company, pos)}`); - } - return null; + return { + success: false, + message: `Unfortunately, you do not qualify for this position.\n${getJobRequirementText(company, pos)}`, + }; } if (!company.hasPosition(pos)) { - console.error(`Company ${company.name} does not have position ${pos.name}. Player.applyToCompany() failed.`); - return null; + return { + success: false, + message: `Company ${company.name} does not have position ${pos.name}.`, + }; } let nextPos = getNextCompanyPositionHelper(pos); @@ -312,31 +316,27 @@ export function applyForJob( nextPos = getNextCompanyPositionHelper(pos); } - //Check if player already has the assigned job + // Check if player already has the assigned job if (this.jobs[company.name] === pos.name) { - if (!sing) { - const nextPos = getNextCompanyPositionHelper(pos); - if (nextPos == null) { - dialogBoxCreate(`You are already ${pos.name}! No promotion available`); - } else if (!company.hasPosition(nextPos)) { - dialogBoxCreate( - `You already have the highest ${pos.field} position available at ${company.name}! No promotion available`, - ); - } else { - dialogBoxCreate( - `Unfortunately, you do not qualify for a promotion.\n${getJobRequirementText(company, nextPos)}`, - ); - } + let errorMessage; + const nextPos = getNextCompanyPositionHelper(pos); + if (nextPos === null) { + errorMessage = `You are already ${pos.name}! No promotion available.`; + } else if (!company.hasPosition(nextPos)) { + errorMessage = `You already have the highest ${pos.field} position available at ${company.name}! No promotion available.`; + } else { + errorMessage = `Unfortunately, you do not qualify for a promotion.\n${getJobRequirementText(company, nextPos)}`; } - return null; + return { success: false, message: errorMessage }; } this.jobs[company.name] = pos.name; - if (!sing) { - dialogBoxCreate(`${pos.hiredText} at ${company.name}!`); - } - return pos.name; + return { + success: true, + message: `${pos.hiredText} at ${company.name}!`, + jobName: pos.name, + }; } /** diff --git a/test/jest/Netscript/Singularity.test.ts b/test/jest/Netscript/Singularity.test.ts index cafed4f0d..8d73257f6 100644 --- a/test/jest/Netscript/Singularity.test.ts +++ b/test/jest/Netscript/Singularity.test.ts @@ -1,6 +1,6 @@ import { installAugmentations } from "../../../src/Augmentation/AugmentationHelpers"; import { blackOpsArray } from "../../../src/Bladeburner/data/BlackOperations"; -import { AugmentationName, FactionName } from "@enums"; +import { AugmentationName, CompanyName, FactionName, JobField, JobName } from "@enums"; import { Player } from "@player"; import { prestigeSourceFile } from "../../../src/Prestige"; import { GetServerOrThrow } from "../../../src/Server/AllServers"; @@ -10,6 +10,10 @@ import { PlayerOwnedAugmentation } from "../../../src/Augmentation/PlayerOwnedAu import { getNS, initGameEnvironment, setupBasicTestingEnvironment } from "./Utilities"; import { Terminal } from "../../../src/Terminal"; import type { NSFull } from "../../../src/NetscriptFunctions"; +import { Companies } from "../../../src/Company/Companies"; +import { CompanyPositions } from "../../../src/Company/CompanyPositions"; + +const nextBN = 3; function setNumBlackOpsComplete(value: number): void { if (!Player.bladeburner) { @@ -18,7 +22,25 @@ function setNumBlackOpsComplete(value: number): void { Player.bladeburner.numBlackOpsComplete = value; } -const nextBN = 3; +function gainTonsOfExp() { + Player.exp.hacking = 1e100; + Player.exp.strength = 1e100; + Player.exp.defense = 1e100; + Player.exp.dexterity = 1e100; + Player.exp.agility = 1e100; + Player.exp.charisma = 1e100; + Player.updateSkillLevels(); +} + +function resetExp() { + Player.exp.hacking = 0; + Player.exp.strength = 0; + Player.exp.defense = 0; + Player.exp.dexterity = 0; + Player.exp.agility = 0; + Player.exp.charisma = 0; + Player.updateSkillLevels(); +} beforeAll(() => { initGameEnvironment(); @@ -358,3 +380,69 @@ describe("connect", () => { }); }); }); + +describe("applyToCompany", () => { + beforeEach(() => { + setupBasicTestingEnvironment(); + prestigeSourceFile(true); + gainTonsOfExp(); + }); + + describe("Success", () => { + test("Apply to entry position", () => { + const ns = getNS(); + Companies[CompanyName.MegaCorp].playerReputation = 0; + expect(ns.singularity.applyToCompany(CompanyName.MegaCorp, JobField.software)).toStrictEqual(JobName.software0); + }); + test("Apply and be promoted to next position", () => { + const ns = getNS(); + const nextPosition = CompanyPositions["Junior Software Engineer"]; + Companies[CompanyName.MegaCorp].playerReputation = nextPosition.requiredReputation; + expect(ns.singularity.applyToCompany(CompanyName.MegaCorp, JobField.software)).toStrictEqual(JobName.software1); + }); + test("Apply and be promoted to highest position", () => { + const ns = getNS(); + Companies[CompanyName.MegaCorp].playerReputation = 1e10; + expect(ns.singularity.applyToCompany(CompanyName.MegaCorp, JobField.software)).toStrictEqual(JobName.software7); + }); + test("Apply then apply again to be promoted to highest position", () => { + const ns = getNS(); + Companies[CompanyName.MegaCorp].playerReputation = 0; + expect(ns.singularity.applyToCompany(CompanyName.MegaCorp, JobField.software)).toStrictEqual(JobName.software0); + Companies[CompanyName.MegaCorp].playerReputation = 1e10; + expect(ns.singularity.applyToCompany(CompanyName.MegaCorp, JobField.software)).toStrictEqual(JobName.software7); + }); + }); + + describe("Failure", () => { + test("Not qualified", () => { + resetExp(); + const ns = getNS(); + expect(ns.singularity.applyToCompany(CompanyName.MegaCorp, JobField.software)).toStrictEqual(null); + }); + test("Invalid field", () => { + const ns = getNS(); + expect(ns.singularity.applyToCompany(CompanyName.MegaCorp, JobField.agent)).toStrictEqual(null); + }); + test("Already at highest position", () => { + const ns = getNS(); + Companies[CompanyName.MegaCorp].playerReputation = 1e10; + expect(ns.singularity.applyToCompany(CompanyName.MegaCorp, JobField.software)).toStrictEqual(JobName.software7); + expect(ns.singularity.applyToCompany(CompanyName.MegaCorp, JobField.software)).toStrictEqual(null); + }); + test("Already at highest available position", () => { + const ns = getNS(); + Companies[CompanyName.WatchdogSecurity].playerReputation = 1e10; + // Watchdog Security only offers up to software5 (Head of Engineering). + expect(ns.singularity.applyToCompany(CompanyName.WatchdogSecurity, JobField.software)).toStrictEqual( + JobName.software5, + ); + expect(ns.singularity.applyToCompany(CompanyName.WatchdogSecurity, JobField.software)).toStrictEqual(null); + }); + test("Not qualified for promotion", () => { + const ns = getNS(); + expect(ns.singularity.applyToCompany(CompanyName.MegaCorp, JobField.software)).toStrictEqual(JobName.software0); + expect(ns.singularity.applyToCompany(CompanyName.MegaCorp, JobField.software)).toStrictEqual(null); + }); + }); +});