diff --git a/src/Company/Company.ts b/src/Company/Company.ts index b1bc34c32..fdbf4e9a5 100644 --- a/src/Company/Company.ts +++ b/src/Company/Company.ts @@ -56,42 +56,6 @@ export class Company { return this.companyPositions.has(typeof pos === "string" ? pos : pos.name); } - hasAgentPositions(): boolean { - return this.companyPositions.has(JobName.agent0); - } - - hasBusinessConsultantPositions(): boolean { - return this.companyPositions.has(JobName.businessConsult0); - } - - hasBusinessPositions(): boolean { - return this.companyPositions.has(JobName.business0); - } - - hasEmployeePositions(): boolean { - return this.companyPositions.has(JobName.employee); - } - - hasITPositions(): boolean { - return this.companyPositions.has(JobName.IT0); - } - - hasSecurityPositions(): boolean { - return this.companyPositions.has(JobName.security0); - } - - hasSoftwareConsultantPositions(): boolean { - return this.companyPositions.has(JobName.softwareConsult0); - } - - hasSoftwarePositions(): boolean { - return this.companyPositions.has(JobName.software0); - } - - hasWaiterPositions(): boolean { - return this.companyPositions.has(JobName.waiter); - } - prestigeAugmentation(): void { if (this.favor == null) this.favor = 0; this.favor += this.getFavorGain(); @@ -121,7 +85,7 @@ export class Company { return Generic_fromJSON(Company, value.data, Company.includedKeys); } - // Only these 3 keys are relevant to the save file + // Only these 2 keys are relevant to the save file static includedKeys = ["favor", "playerReputation"] as const; } diff --git a/src/Company/CompanyPosition.ts b/src/Company/CompanyPosition.ts index 36ea3438d..cc9aaa852 100644 --- a/src/Company/CompanyPosition.ts +++ b/src/Company/CompanyPosition.ts @@ -1,22 +1,16 @@ import { Person as IPerson } from "@nsdefs"; import { CONSTANTS } from "../Constants"; import { JobName, JobField } from "@enums"; -import { - agentJobs, - businessConsultJobs, - businessJobs, - itJobs, - netEngJobs, - securityJobs, - softwareConsultJobs, - softwareJobs, -} from "./data/JobTracks"; +import type { Skills } from "../PersonObjects/Skills"; export interface CompanyPositionCtorParams { nextPosition: JobName | null; field: JobField; baseSalary: number; repMultiplier: number; + applyText?: string; + hiredText?: string; + isPartTime?: boolean; reqdHacking?: number; reqdStrength?: number; @@ -60,6 +54,15 @@ export class CompanyPosition { /** Reputation multiplier */ repMultiplier: number; + /** Text to display when applying for this job */ + applyText: string; + + /** Text to display when receiving this job */ + hiredText: string; + + /** Whether this position is part-time */ + isPartTime: boolean; + /** Required stats to earn this position */ requiredAgility: number; requiredCharisma: number; @@ -93,6 +96,9 @@ export class CompanyPosition { this.nextPosition = p.nextPosition; this.baseSalary = p.baseSalary; this.repMultiplier = p.repMultiplier; + this.isPartTime = p.isPartTime ?? false; + this.applyText = p.applyText ?? `Apply for ${this.name} Job`; + this.hiredText = p.hiredText ?? `Congratulations, you are now employed as a ${this.name}`; this.requiredHacking = p.reqdHacking != null ? p.reqdHacking : 0; this.requiredStrength = p.reqdStrength != null ? p.reqdStrength : 0; @@ -130,6 +136,18 @@ export class CompanyPosition { this.charismaExpGain = p.charismaExpGain != null ? p.charismaExpGain : 0; } + requiredSkills(jobStatReqOffset: number): Skills { + return { + hacking: this.requiredHacking > 0 ? this.requiredHacking + jobStatReqOffset : 0, + strength: this.requiredStrength > 0 ? this.requiredStrength + jobStatReqOffset : 0, + defense: this.requiredDefense > 0 ? this.requiredDefense + jobStatReqOffset : 0, + dexterity: this.requiredDexterity > 0 ? this.requiredDexterity + jobStatReqOffset : 0, + agility: this.requiredAgility > 0 ? this.requiredAgility + jobStatReqOffset : 0, + charisma: this.requiredCharisma > 0 ? this.requiredCharisma + jobStatReqOffset : 0, + intelligence: 0, + }; + } + calculateJobPerformance(worker: IPerson): number { const hackRatio: number = (this.hackingEffectiveness * worker.skills.hacking) / CONSTANTS.MaxSkillLevel; const strRatio: number = (this.strengthEffectiveness * worker.skills.strength) / CONSTANTS.MaxSkillLevel; @@ -147,44 +165,4 @@ export class CompanyPosition { reputationGain += worker.skills.intelligence / CONSTANTS.MaxSkillLevel; return reputationGain; } - - isSoftwareJob(): boolean { - return softwareJobs.includes(this.name); - } - - isITJob(): boolean { - return itJobs.includes(this.name); - } - - isSecurityEngineerJob(): boolean { - return this.name === JobName.securityEng; - } - - isNetworkEngineerJob(): boolean { - return netEngJobs.includes(this.name); - } - - isBusinessJob(): boolean { - return businessJobs.includes(this.name); - } - - isSecurityJob(): boolean { - return securityJobs.includes(this.name); - } - - isAgentJob(): boolean { - return agentJobs.includes(this.name); - } - - isSoftwareConsultantJob(): boolean { - return softwareConsultJobs.includes(this.name); - } - - isBusinessConsultantJob(): boolean { - return businessConsultJobs.includes(this.name); - } - - isPartTimeJob(): boolean { - return [JobName.employeePT, JobName.waiterPT].includes(this.name); - } } diff --git a/src/Company/GetJobRequirementText.ts b/src/Company/GetJobRequirementText.ts deleted file mode 100644 index 9fba7b87b..000000000 --- a/src/Company/GetJobRequirementText.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Company } from "./Company"; -import { CompanyPosition } from "./CompanyPosition"; - -/** Returns a string with the given CompanyPosition's stat requirements */ -export function getJobRequirementText(company: Company, pos: CompanyPosition, tooltiptext = false): string { - let reqText = ""; - const offset: number = company.jobStatReqOffset; - const reqHacking: number = pos.requiredHacking > 0 ? pos.requiredHacking + offset : 0; - const reqStrength: number = pos.requiredStrength > 0 ? pos.requiredStrength + offset : 0; - const reqDefense: number = pos.requiredDefense > 0 ? pos.requiredDefense + offset : 0; - const reqDexterity: number = pos.requiredDexterity > 0 ? pos.requiredDexterity + offset : 0; - const reqAgility: number = pos.requiredDexterity > 0 ? pos.requiredDexterity + offset : 0; - const reqCharisma: number = pos.requiredCharisma > 0 ? pos.requiredCharisma + offset : 0; - const reqRep: number = pos.requiredReputation; - if (tooltiptext) { - reqText = "Requires:
"; - reqText += reqHacking.toString() + " hacking
"; - reqText += reqStrength.toString() + " strength
"; - reqText += reqDefense.toString() + " defense
"; - reqText += reqDexterity.toString() + " dexterity
"; - reqText += reqAgility.toString() + " agility
"; - reqText += reqCharisma.toString() + " charisma
"; - reqText += reqRep.toString() + " reputation"; - } else { - reqText = "(Requires "; - if (reqHacking > 0) { - reqText += reqHacking + " hacking, "; - } - if (reqStrength > 0) { - reqText += reqStrength + " strength, "; - } - if (reqDefense > 0) { - reqText += reqDefense + " defense, "; - } - if (reqDexterity > 0) { - reqText += reqDexterity + " dexterity, "; - } - if (reqAgility > 0) { - reqText += reqAgility + " agility, "; - } - if (reqCharisma > 0) { - reqText += reqCharisma + " charisma, "; - } - if (reqRep > 1) { - reqText += reqRep + " reputation, "; - } - reqText = reqText.substring(0, reqText.length - 2); - reqText += ")"; - } - return reqText; -} diff --git a/src/Company/GetJobRequirements.ts b/src/Company/GetJobRequirements.ts new file mode 100644 index 000000000..3c9ed2e91 --- /dev/null +++ b/src/Company/GetJobRequirements.ts @@ -0,0 +1,23 @@ +import { Company } from "./Company"; +import { CompanyPosition } from "./CompanyPosition"; + +import { PlayerCondition, haveSkill, haveCompanyRep } from "../Faction/FactionJoinCondition"; +import type { Skills } from "../PersonObjects/Skills"; + +export function getJobRequirements(company: Company, pos: CompanyPosition): PlayerCondition[] { + const reqSkills = pos.requiredSkills(company.jobStatReqOffset); + const reqs = []; + for (const [skillName, value] of Object.entries(reqSkills)) { + if (value > 0) reqs.push(haveSkill(skillName as keyof Skills, value)); + } + if (pos.requiredReputation > 0) { + reqs.push(haveCompanyRep(company.name, pos.requiredReputation)); + } + return reqs; +} + +/** Returns a string with the given CompanyPosition's stat requirements */ +export function getJobRequirementText(company: Company, pos: CompanyPosition): string { + const reqs = getJobRequirements(company, pos); + return `(${pos.name} requires: ${reqs.map((s) => s.toString()).join(", ")})`; +} diff --git a/src/Company/data/CompaniesMetadata.ts b/src/Company/data/CompaniesMetadata.ts index ec86cd53a..98bc40da2 100644 --- a/src/Company/data/CompaniesMetadata.ts +++ b/src/Company/data/CompaniesMetadata.ts @@ -1,14 +1,15 @@ import { CompanyCtorParams } from "../Company"; -import { CompanyName, JobName, FactionName } from "@enums"; +import { CompanyName, FactionName, JobName } from "@enums"; import { - agentJobs, + softwareJobs, businessJobs, - itJobs, - netEngJobs, securityJobs, softwareConsultJobs, - softwareJobs, + netEngJobs, + itJobs, + agentJobs, + businessConsultJobs, } from "./JobTracks"; export function getCompaniesMetadata(): Record { @@ -107,14 +108,14 @@ export function getCompaniesMetadata(): Record { }, [CompanyName.DefComm]: { name: CompanyName.DefComm, - companyPositions: [JobName.business5, ...allTechJobs, ...softwareConsultJobs], + companyPositions: [JobName.business5, ...allTechJobs, ...softwareConsultJobs, ...businessConsultJobs], expMultiplier: 1.75, salaryMultiplier: 1.75, jobStatReqOffset: 199, }, [CompanyName.HeliosLabs]: { name: CompanyName.HeliosLabs, - companyPositions: [JobName.business5, ...allTechJobs, ...softwareConsultJobs], + companyPositions: [JobName.business5, ...allTechJobs, ...softwareConsultJobs, ...businessConsultJobs], expMultiplier: 1.8, salaryMultiplier: 1.8, jobStatReqOffset: 199, @@ -149,28 +150,28 @@ export function getCompaniesMetadata(): Record { }, [CompanyName.AeroCorp]: { name: CompanyName.AeroCorp, - companyPositions: [JobName.business3, JobName.business5, ...allTechJobs, ...securityJobs], + companyPositions: [JobName.business3, JobName.business5, ...allTechJobs, ...securityJobs, ...businessConsultJobs], expMultiplier: 1.7, salaryMultiplier: 1.7, jobStatReqOffset: 199, }, [CompanyName.OmniaCybersystems]: { name: CompanyName.OmniaCybersystems, - companyPositions: [JobName.business3, JobName.business5, ...allTechJobs, ...securityJobs], + companyPositions: [JobName.business3, JobName.business5, ...allTechJobs, ...securityJobs, ...businessConsultJobs], expMultiplier: 1.7, salaryMultiplier: 1.7, jobStatReqOffset: 199, }, [CompanyName.SolarisSpaceSystems]: { name: CompanyName.SolarisSpaceSystems, - companyPositions: [JobName.business3, JobName.business5, ...allTechJobs, ...securityJobs], + companyPositions: [JobName.business3, JobName.business5, ...allTechJobs, ...securityJobs, ...businessConsultJobs], expMultiplier: 1.7, salaryMultiplier: 1.7, jobStatReqOffset: 199, }, [CompanyName.DeltaOne]: { name: CompanyName.DeltaOne, - companyPositions: [JobName.business3, JobName.business5, ...allTechJobs, ...securityJobs], + companyPositions: [JobName.business3, JobName.business5, ...allTechJobs, ...securityJobs, ...businessConsultJobs], expMultiplier: 1.6, salaryMultiplier: 1.6, jobStatReqOffset: 199, diff --git a/src/Company/data/CompanyPositionsMetadata.ts b/src/Company/data/CompanyPositionsMetadata.ts index e45812cb0..50e665d78 100644 --- a/src/Company/data/CompanyPositionsMetadata.ts +++ b/src/Company/data/CompanyPositionsMetadata.ts @@ -65,6 +65,7 @@ export function getCompanyPositionMetadata(): Record = { + [JobField.software]: [ + JobName.software0, + JobName.software1, + JobName.software2, + JobName.software3, + JobName.software4, + JobName.software5, + JobName.software6, + JobName.software7, + ], + [JobField.softwareConsultant]: [JobName.softwareConsult0, JobName.softwareConsult1], + [JobField.it]: [JobName.IT0, JobName.IT1, JobName.IT2, JobName.IT3], + [JobField.securityEngineer]: [JobName.securityEng], + [JobField.networkEngineer]: [JobName.networkEng0, JobName.networkEng1], + [JobField.business]: [ + JobName.business0, + JobName.business1, + JobName.business2, + JobName.business3, + JobName.business4, + JobName.business5, + ], + [JobField.businessConsultant]: [JobName.businessConsult0, JobName.businessConsult1], + [JobField.security]: [JobName.security0, JobName.security1, JobName.security2, JobName.security3], + [JobField.agent]: [JobName.agent0, JobName.agent1, JobName.agent2], + [JobField.employee]: [JobName.employee], + [JobField.partTimeEmployee]: [JobName.employeePT], + [JobField.waiter]: [JobName.waiter], + [JobField.partTimeWaiter]: [JobName.waiterPT], +} as const; + +export const softwareJobs = JobTracks[JobField.software]; +export const itJobs = JobTracks[JobField.it]; +export const netEngJobs = JobTracks[JobField.networkEngineer]; +export const businessJobs = JobTracks[JobField.business]; +export const securityJobs = JobTracks[JobField.security]; +export const agentJobs = JobTracks[JobField.agent]; +export const softwareConsultJobs = JobTracks[JobField.softwareConsultant]; +export const businessConsultJobs = JobTracks[JobField.businessConsultant]; diff --git a/src/Company/ui/ApplyToJobButton.tsx b/src/Company/ui/ApplyToJobButton.tsx new file mode 100644 index 000000000..876a7b7db --- /dev/null +++ b/src/Company/ui/ApplyToJobButton.tsx @@ -0,0 +1,74 @@ +import * as React from "react"; + +import { Company } from "../Company"; +import { CompanyPosition } from "../CompanyPosition"; + +import { Player } from "@player"; +import { Typography } from "@mui/material"; +import { ButtonWithTooltip } from "../../ui/Components/ButtonWithTooltip"; +import { CompanyPositions } from "../CompanyPositions"; +import { JobSummary } from "./JobSummary"; +import { Requirement } from "../../ui/Components/Requirement"; +import { getJobRequirements } from "../GetJobRequirements"; + +interface IProps { + company: Company; + position: CompanyPosition; + currentPosition: CompanyPosition | null; +} + +/** React Component for a button that's used to apply for a job */ +export function ApplyToJobButton(props: IProps): React.ReactElement { + const underqualified = !Player.isQualified(props.company, props.position); + const nextPos = props.position.nextPosition && CompanyPositions[props.position.nextPosition]; + const overqualified = nextPos != null && Player.isQualified(props.company, nextPos); + + const reqs = getJobRequirements(props.company, props.position); + const positionRequirements = + reqs.length == 0 ? ( + Accepting all applicants + ) : ( + <> + Requirements: + {reqs.map((req, i) => ( + + ))} + + ); + + const positionDetails = ( + <> + + {props.position.isPartTime && ( + +
+ Part-time jobs have no penalty for +
doing something else simultaneously. +
+ )} +
+ {positionRequirements} + {overqualified && ( + +
+ You are overqualified for this position. +
+ )} + + ); + + function applyForJob(): void { + Player.applyForJob(props.company, props.position); + } + + return ( + + {props.position.applyText} + + ); +} diff --git a/src/Company/ui/JobListings.tsx b/src/Company/ui/JobListings.tsx new file mode 100644 index 000000000..4c3481182 --- /dev/null +++ b/src/Company/ui/JobListings.tsx @@ -0,0 +1,40 @@ +import type { Company } from "../Company"; +import type { CompanyPosition } from "../CompanyPosition"; + +import React from "react"; + +import { CompanyPositions } from "../CompanyPositions"; +import { ApplyToJobButton } from "./ApplyToJobButton"; +import { Player } from "@player"; + +interface IJobListingsProps { + company: Company; + currentPosition: CompanyPosition | null; +} + +export function JobListings(props: IJobListingsProps): React.ReactElement { + const { company, currentPosition } = props; + + const jobsToShow = []; + for (const jobName of company.companyPositions) { + const offeredPos = CompanyPositions[jobName]; + const underqualified = !Player.isQualified(props.company, offeredPos); + const isCurrentPosition = jobName == props.currentPosition?.name; + const nextPos = offeredPos.nextPosition && CompanyPositions[offeredPos.nextPosition]; + const overqualified = nextPos != null && Player.isQualified(props.company, nextPos); + const shouldShowApplyButton = + !isCurrentPosition && !overqualified && (!underqualified || offeredPos.requiredReputation == 0); + + if (shouldShowApplyButton) { + jobsToShow.push(offeredPos); + } + } + + return ( + <> + {jobsToShow.map((position) => ( + + ))} + + ); +} diff --git a/src/Company/ui/JobSummary.tsx b/src/Company/ui/JobSummary.tsx new file mode 100644 index 000000000..67e91fa5d --- /dev/null +++ b/src/Company/ui/JobSummary.tsx @@ -0,0 +1,35 @@ +import { Typography } from "@mui/material"; +import { Player } from "@player"; +import * as React from "react"; +import { CONSTANTS } from "../../Constants"; +import { calculateCompanyWorkStats } from "../../Work/Formulas"; +import { MoneyRate } from "../../ui/React/MoneyRate"; +import { ReputationRate } from "../../ui/React/ReputationRate"; +import { StatsTable } from "../../ui/React/StatsTable"; +import type { Company } from "../Company"; +import type { CompanyPosition } from "../CompanyPosition"; + +const CYCLES_PER_SEC = 1000 / CONSTANTS.MilliPerCycle; +interface IJobSummaryProps { + company: Company; + position: CompanyPosition; + overqualified?: boolean; +} + +export function JobSummary(props: IJobSummaryProps): React.ReactElement { + const workStats = calculateCompanyWorkStats(Player, props.company, props.position, props.company.favor); + return ( + <> + + {props.position.name} + + ], + ["Reputation:", ], + ]} + /> + + ); +} diff --git a/src/DevMenu/ui/ServersDev.tsx b/src/DevMenu/ui/ServersDev.tsx index 2a59b5713..bc32b4e63 100644 --- a/src/DevMenu/ui/ServersDev.tsx +++ b/src/DevMenu/ui/ServersDev.tsx @@ -43,6 +43,20 @@ export function ServersDev(): React.ReactElement { } } + function backdoorServer(): void { + const s = GetServer(server); + if (s === null) return; + if (!(s instanceof Server)) return; + s.backdoorInstalled = true; + } + + function backdoorAllServers(): void { + for (const s of GetAllServers()) { + if (!(s instanceof Server)) return; + s.backdoorInstalled = true; + } + } + function minSecurity(): void { const s = GetServer(server); if (s === null) return; @@ -118,6 +132,17 @@ export function ServersDev(): React.ReactElement { + + + Backdoor: + + + + + + + + Security: diff --git a/src/Locations/ui/ApplyToJobButton.tsx b/src/Locations/ui/ApplyToJobButton.tsx deleted file mode 100644 index 5b5c80255..000000000 --- a/src/Locations/ui/ApplyToJobButton.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import * as React from "react"; - -import { Company } from "../../Company/Company"; -import { CompanyPosition } from "../../Company/CompanyPosition"; -import { getJobRequirementText } from "../../Company/GetJobRequirementText"; - -import { Player } from "@player"; -import Button from "@mui/material/Button"; -import Tooltip from "@mui/material/Tooltip"; - -interface IProps { - company: Company; - entryPosType: CompanyPosition; - onClick: (e: React.MouseEvent) => void; - text: string; -} - -/** React Component for a button that's used to apply for a job */ -export function ApplyToJobButton(props: IProps): React.ReactElement { - function getJobRequirementTooltip(): string { - const pos = Player.getNextCompanyPosition(props.company, props.entryPosType); - if (pos == null) { - return ""; - } - - if (!props.company.hasPosition(pos)) { - return ""; - } - - return getJobRequirementText(props.company, pos, true); - } - - return ( - <> - }> - - - - ); -} diff --git a/src/Locations/ui/CompanyLocation.tsx b/src/Locations/ui/CompanyLocation.tsx index 9c30afc33..bcfe303b9 100644 --- a/src/Locations/ui/CompanyLocation.tsx +++ b/src/Locations/ui/CompanyLocation.tsx @@ -4,15 +4,10 @@ * This subcomponent renders all of the buttons for applying to jobs at a company */ import React, { useState } from "react"; -import Typography from "@mui/material/Typography"; -import Button from "@mui/material/Button"; -import Tooltip from "@mui/material/Tooltip"; -import Box from "@mui/material/Box"; - -import { ApplyToJobButton } from "./ApplyToJobButton"; +import { Paper, Box, Tooltip, Button, Typography } from "@mui/material"; import { Locations } from "../Locations"; -import { CompanyName, JobName, JobField } from "@enums"; +import { CompanyName } from "@enums"; import { Companies } from "../../Company/Companies"; import { CompanyPositions } from "../../Company/CompanyPositions"; @@ -26,6 +21,9 @@ import { QuitJobModal } from "../../Company/ui/QuitJobModal"; import { CompanyWork } from "../../Work/CompanyWork"; import { useRerender } from "../../ui/React/hooks"; import { companyNameAsLocationName } from "../../Company/utils"; +import { JobSummary } from "../../Company/ui/JobSummary"; +import { StatsTable } from "../../ui/React/StatsTable"; +import { JobListings } from "../../Company/ui/JobListings"; interface IProps { companyName: CompanyName; @@ -54,101 +52,12 @@ export function CompanyLocation(props: IProps): React.ReactElement { const hasMoreJobs = Object.keys(Player.jobs).length > 1; /** - * CompanyPosition object for the job that the player holds at this company - * (if he has one) + * CompanyPosition object for the job that the player holds at this company, if applicable */ - const companyPosition = jobTitle ? CompanyPositions[jobTitle] : null; + const currentPosition = jobTitle ? CompanyPositions[jobTitle] : null; Player.location = companyNameAsLocationName(props.companyName); - function applyForAgentJob(e: React.MouseEvent): void { - if (!e.isTrusted) { - return; - } - Player.applyForAgentJob(); - rerender(); - } - - function applyForBusinessConsultantJob(e: React.MouseEvent): void { - if (!e.isTrusted) { - return; - } - Player.applyForBusinessConsultantJob(); - rerender(); - } - - function applyForBusinessJob(e: React.MouseEvent): void { - if (!e.isTrusted) { - return; - } - Player.applyForBusinessJob(); - rerender(); - } - - function applyForEmployeeJob(e: React.MouseEvent): void { - if (!e.isTrusted) { - return; - } - Player.applyForEmployeeJob(); - rerender(); - } - - function applyForItJob(e: React.MouseEvent): void { - if (!e.isTrusted) { - return; - } - Player.applyForItJob(); - rerender(); - } - - function applyForPartTimeEmployeeJob(e: React.MouseEvent): void { - if (!e.isTrusted) { - return; - } - Player.applyForPartTimeEmployeeJob(); - rerender(); - } - - function applyForPartTimeWaiterJob(e: React.MouseEvent): void { - if (!e.isTrusted) { - return; - } - Player.applyForPartTimeWaiterJob(); - rerender(); - } - - function applyForSecurityJob(e: React.MouseEvent): void { - if (!e.isTrusted) { - return; - } - Player.applyForSecurityJob(); - rerender(); - } - - function applyForSoftwareConsultantJob(e: React.MouseEvent): void { - if (!e.isTrusted) { - return; - } - Player.applyForSoftwareConsultantJob(); - rerender(); - } - - function applyForSoftwareJob(e: React.MouseEvent): void { - if (!e.isTrusted) { - return; - } - Player.applyForSoftwareJob(); - rerender(); - } - - function applyForWaiterJob(e: React.MouseEvent): void { - if (!e.isTrusted) { - return; - } - Player.applyForWaiterJob(); - rerender(); - } - function startInfiltration(e: React.MouseEvent): void { if (!e.isTrusted) { return; @@ -164,8 +73,7 @@ export function CompanyLocation(props: IProps): React.ReactElement { return; } - const pos = companyPosition; - if (pos) { + if (currentPosition) { Player.startWork( new CompanyWork({ singularity: false, @@ -189,59 +97,58 @@ export function CompanyLocation(props: IProps): React.ReactElement { Router.toPage(Page.Job, { location: Locations[Object.keys(Player.jobs)[targetNum]] }); } - const isEmployedHere = jobTitle != null; + const isEmployedHere = currentPosition != null; const favorGain = company.getFavorGain(); return ( <> - {isEmployedHere && hasMoreJobs && ( - <> - - - + + {isEmployedHere && hasMoreJobs && ( + + + -
- - )} - {isEmployedHere && ( - <> - Job Title: {jobTitle} - ------------------------- - - - You will have company favor upon resetting after - installing Augmentations - - } - > - - Company reputation: - - - - ------------------------- - - - Company favor increases the rate at which you earn reputation for this company by 1% per favor. - Company favor is gained whenever you reset after installing Augmentations. The amount of favor you - gain depends on how much reputation you have with the company. - - } - > - - Company Favor: - - - - ------------------------- -
- - )} - + )} + {isEmployedHere && ( + + + + You will have company favor upon resetting after + installing Augmentations + + } + > + Total reputation: + , + , + ], + [ + + Company favor increases the rate at which you earn reputation for this company by 1% per favor. + Company favor is gained whenever you reset after installing Augmentations. The amount of favor + you gain depends on how much reputation you have with the company. + + } + > + Company favor: + , + , + ], + ]} + /> + + )} + {isEmployedHere && ( @@ -255,94 +162,9 @@ export function CompanyLocation(props: IProps): React.ReactElement { /> )} - {company.hasAgentPositions() && ( - - )} - {company.hasBusinessConsultantPositions() && ( - - )} - {company.hasBusinessPositions() && ( - - )} - {company.hasEmployeePositions() && ( - - )} - {company.hasEmployeePositions() && ( - - )} - {company.hasITPositions() && ( - - )} - {company.hasSecurityPositions() && ( - - )} - {company.hasSoftwareConsultantPositions() && ( - - )} - {company.hasSoftwarePositions() && ( - - )} - {company.hasWaiterPositions() && ( - - )} - {company.hasWaiterPositions() && ( - - )} + + {company.companyPositions.size > 0 && } + {location.infiltrationData != null && } diff --git a/src/NetscriptFunctions/Singularity.ts b/src/NetscriptFunctions/Singularity.ts index faedfb2fe..c0a89863d 100644 --- a/src/NetscriptFunctions/Singularity.ts +++ b/src/NetscriptFunctions/Singularity.ts @@ -8,7 +8,6 @@ import { FactionName, FactionWorkType, GymType, - JobField, LocationName, UniversityClassType, } from "@enums"; @@ -55,8 +54,8 @@ import { Engine } from "../engine"; import { getEnumHelper } from "../utils/EnumHelper"; import { ScriptFilePath, resolveScriptFilePath } from "../Paths/ScriptFilePath"; import { root } from "../Paths/Directory"; -import { companyNameAsLocationName } from "../Company/utils"; import { getRecordEntries } from "../Types/Record"; +import { JobTracks } from "../Company/data/JobTracks"; export function NetscriptSingularity(): InternalAPI { const runAfterReset = function (cbScript: ScriptFilePath) { @@ -687,20 +686,12 @@ 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, - requiredSkills: { - hacking: job.requiredHacking > 0 ? job.requiredHacking + company.jobStatReqOffset : 0, - strength: job.requiredStrength > 0 ? job.requiredStrength + company.jobStatReqOffset : 0, - defense: job.requiredDefense > 0 ? job.requiredDefense + company.jobStatReqOffset : 0, - dexterity: job.requiredDexterity > 0 ? job.requiredDexterity + company.jobStatReqOffset : 0, - agility: job.requiredAgility > 0 ? job.requiredAgility + company.jobStatReqOffset : 0, - charisma: job.requiredCharisma > 0 ? job.requiredCharisma + company.jobStatReqOffset : 0, - intelligence: 0, - }, + name: job.name, + field: job.field, + nextPosition: job.nextPosition, + salary: job.baseSalary * company.salaryMultiplier, + requiredReputation: job.requiredReputation, + requiredSkills: job.requiredSkills(company.jobStatReqOffset), }; return res; }, @@ -739,62 +730,16 @@ export function NetscriptSingularity(): InternalAPI { helpers.checkSingularityAccess(ctx); const companyName = getEnumHelper("CompanyName").nsGetMember(ctx, _companyName); const field = getEnumHelper("JobField").nsGetMember(ctx, _field, "field", { fuzzy: true }); + const company = Companies[companyName]; + const entryPos = CompanyPositions[JobTracks[field][0]]; - Player.location = companyNameAsLocationName(companyName); - let res; - switch (field) { - case JobField.software: - res = Player.applyForSoftwareJob(true); - break; - case JobField.softwareConsultant: - res = Player.applyForSoftwareConsultantJob(true); - break; - case JobField.it: - res = Player.applyForItJob(true); - break; - case JobField.securityEngineer: - res = Player.applyForSecurityEngineerJob(true); - break; - case JobField.networkEngineer: - res = Player.applyForNetworkEngineerJob(true); - break; - case JobField.business: - res = Player.applyForBusinessJob(true); - break; - case JobField.businessConsultant: - res = Player.applyForBusinessConsultantJob(true); - break; - case JobField.security: - res = Player.applyForSecurityJob(true); - break; - case JobField.agent: - res = Player.applyForAgentJob(true); - break; - case JobField.employee: - res = Player.applyForEmployeeJob(true); - break; - case JobField.partTimeEmployee: - res = Player.applyForPartTimeEmployeeJob(true); - break; - case JobField.waiter: - res = Player.applyForWaiterJob(true); - break; - case JobField.partTimeWaiter: - res = Player.applyForPartTimeWaiterJob(true); - break; - default: - helpers.log(ctx, () => `Invalid job: '${field}'.`); - return false; - } - if (res) { - helpers.log( - ctx, - () => `You were offered a new job at '${companyName}' with position '${Player.jobs[companyName]}'`, - ); + 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.`); } - return res; + return jobName; }, quitJob: (ctx) => (_companyName) => { helpers.checkSingularityAccess(ctx); diff --git a/src/PersonObjects/Player/PlayerObject.ts b/src/PersonObjects/Player/PlayerObject.ts index 526e92c9f..1d6ca7ff8 100644 --- a/src/PersonObjects/Player/PlayerObject.ts +++ b/src/PersonObjects/Player/PlayerObject.ts @@ -79,19 +79,6 @@ export class PlayerObject extends Person implements IPlayer { startWork = workMethods.startWork; processWork = workMethods.processWork; finishWork = workMethods.finishWork; - applyForSoftwareJob = generalMethods.applyForSoftwareJob; - applyForSoftwareConsultantJob = generalMethods.applyForSoftwareConsultantJob; - applyForItJob = generalMethods.applyForItJob; - applyForSecurityEngineerJob = generalMethods.applyForSecurityEngineerJob; - applyForNetworkEngineerJob = generalMethods.applyForNetworkEngineerJob; - applyForBusinessJob = generalMethods.applyForBusinessJob; - applyForBusinessConsultantJob = generalMethods.applyForBusinessConsultantJob; - applyForSecurityJob = generalMethods.applyForSecurityJob; - applyForAgentJob = generalMethods.applyForAgentJob; - applyForEmployeeJob = generalMethods.applyForEmployeeJob; - applyForPartTimeEmployeeJob = generalMethods.applyForPartTimeEmployeeJob; - applyForWaiterJob = generalMethods.applyForWaiterJob; - applyForPartTimeWaiterJob = generalMethods.applyForPartTimeWaiterJob; applyForJob = generalMethods.applyForJob; canAccessBladeburner = bladeburnerMethods.canAccessBladeburner; canAccessCorporation = corporationMethods.canAccessCorporation; diff --git a/src/PersonObjects/Player/PlayerObjectGeneralMethods.ts b/src/PersonObjects/Player/PlayerObjectGeneralMethods.ts index 44288622a..90cc159bd 100644 --- a/src/PersonObjects/Player/PlayerObjectGeneralMethods.ts +++ b/src/PersonObjects/Player/PlayerObjectGeneralMethods.ts @@ -20,8 +20,7 @@ import { CodingContractRewardType, ICodingContractReward } from "../../CodingCon import { Company } from "../../Company/Company"; import { Companies } from "../../Company/Companies"; import { getNextCompanyPositionHelper } from "../../Company/GetNextCompanyPosition"; -import { getJobRequirementText } from "../../Company/GetJobRequirementText"; -import { CompanyPositions } from "../../Company/CompanyPositions"; +import { getJobRequirements, getJobRequirementText } from "../../Company/GetJobRequirements"; import { CompanyPosition } from "../../Company/CompanyPosition"; import { CONSTANTS } from "../../Constants"; import { Exploit } from "../../Exploits/Exploit"; @@ -51,7 +50,7 @@ import { SnackbarEvents } from "../../ui/React/Snackbar"; import { achievements } from "../../Achievements/Achievements"; import { isCompanyWork } from "../../Work/CompanyWork"; -import { getEnumHelper, isMember } from "../../utils/EnumHelper"; +import { isMember } from "../../utils/EnumHelper"; export function init(this: PlayerObject): void { /* Initialize Player's home computer */ @@ -273,26 +272,34 @@ export function hospitalize(this: PlayerObject): number { return cost; } -/********* Company job application **********/ -//Determines the job that the Player should get (if any) at the current company -//The 'sing' argument designates whether or not this is being called from -//the applyToCompany() Netscript Singularity function -export function applyForJob(this: PlayerObject, entryPosType: CompanyPosition, sing = false): boolean { - const companyName = getEnumHelper("CompanyName").getMember(this.location); - if (!companyName) return false; - const company = Companies[companyName]; //Company being applied to - let pos = entryPosType; +/** + * Company job application. Determines the job that the Player should get (if any) at the given company. + * @param this The player instance + * @param company The company being applied to + * @param position A specific position + * @param sing Whether this is being called from the applyToCompany() Netscript Singularity function + * @returns The name of the Job received (if any). May be higher or lower than the job applied to. + */ +export function applyForJob( + this: PlayerObject, + company: Company, + position: CompanyPosition, + sing = false, +): JobName | null { + if (!company) return null; + // 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)); + dialogBoxCreate(`Unfortunately, you do not qualify for this position.\n${getJobRequirementText(company, pos)}`); } - return false; + return null; } if (!company.hasPosition(pos)) { - console.error(`Company ${company.name} does not have position ${pos}. Player.applyToCompany() failed`); - return false; + console.error(`Company ${company.name} does not have position ${pos}. Player.applyToCompany() failed.`); + return null; } let nextPos = getNextCompanyPositionHelper(pos); @@ -305,59 +312,53 @@ export function applyForJob(this: PlayerObject, entryPosType: CompanyPosition, s if (this.jobs[company.name] === pos.name) { if (!sing) { const nextPos = getNextCompanyPositionHelper(pos); - if (nextPos == null || !company.hasPosition(nextPos)) { - dialogBoxCreate("You are already at the highest position for your field! No promotion available"); + 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 { - const reqText = getJobRequirementText(company, nextPos); - dialogBoxCreate("Unfortunately, you do not qualify for a promotion\n" + reqText); + dialogBoxCreate( + `Unfortunately, you do not qualify for a promotion.\n${getJobRequirementText(company, nextPos)}`, + ); } } - return false; + return null; } this.jobs[company.name] = pos.name; if (!sing) { - dialogBoxCreate(`Congratulations! You were offered a new job at ${company.name} for position ${pos.name}!`); + dialogBoxCreate(`${pos.hiredText} at ${company.name}!`); } - return true; + return pos.name; } -//Returns your next position at a company given the field (software, business, etc.) +/** + * Get a job position that the player can apply for. + * @param this The player instance + * @param company The Company being applied to + * @param entryPosType Job field (Software, Business, etc) + * @returns The highest job the player can apply for at this company, if any + */ export function getNextCompanyPosition( this: PlayerObject, company: Company, entryPosType: CompanyPosition, ): CompanyPosition | null { - const currCompany = Companies[company.name]; - - //Not employed at this company, so return the entry position - if (currCompany == null || currCompany.name != company.name) { - return entryPosType; + let pos: CompanyPosition | null = entryPosType; + let nextPos = getNextCompanyPositionHelper(pos); + // Find the highest-level job in this category that the player is currently able to apply for. + while (nextPos && company.hasPosition(nextPos) && this.isQualified(company, nextPos)) { + pos = nextPos; + nextPos = getNextCompanyPositionHelper(pos); } - - //If the entry pos type and the player's current position have the same type, - //return the player's "nextCompanyPosition". Otherwise return the entryposType - //Employed at this company, so just return the next position if it exists. - const currentPositionName = this.jobs[company.name]; - if (!currentPositionName) return entryPosType; - const currentPosition = CompanyPositions[currentPositionName]; - if ( - (currentPosition.isSoftwareJob() && entryPosType.isSoftwareJob()) || - (currentPosition.isITJob() && entryPosType.isITJob()) || - (currentPosition.isBusinessJob() && entryPosType.isBusinessJob()) || - (currentPosition.isSecurityEngineerJob() && entryPosType.isSecurityEngineerJob()) || - (currentPosition.isNetworkEngineerJob() && entryPosType.isNetworkEngineerJob()) || - (currentPosition.isSecurityJob() && entryPosType.isSecurityJob()) || - (currentPosition.isAgentJob() && entryPosType.isAgentJob()) || - (currentPosition.isSoftwareConsultantJob() && entryPosType.isSoftwareConsultantJob()) || - (currentPosition.isBusinessConsultantJob() && entryPosType.isBusinessConsultantJob()) || - (currentPosition.isPartTimeJob() && entryPosType.isPartTimeJob()) - ) { - return getNextCompanyPositionHelper(currentPosition); + // If the player already has this position, return the one after that (if any). + if (this.jobs[company.name] == pos.name) { + pos = nextPos; } - - return entryPosType; + return pos; } export function quitJob(this: PlayerObject, company: CompanyName): void { @@ -382,192 +383,10 @@ export function hasJob(this: PlayerObject): boolean { return Boolean(Object.keys(this.jobs).length); } -export function applyForSoftwareJob(this: PlayerObject, sing = false): boolean { - return this.applyForJob(CompanyPositions[JobName.software0], sing); -} - -export function applyForSoftwareConsultantJob(this: PlayerObject, sing = false): boolean { - return this.applyForJob(CompanyPositions[JobName.softwareConsult0], sing); -} - -export function applyForItJob(this: PlayerObject, sing = false): boolean { - return this.applyForJob(CompanyPositions[JobName.IT0], sing); -} - -export function applyForSecurityEngineerJob(this: PlayerObject, sing = false): boolean { - const companyName = getEnumHelper("CompanyName").getMember(this.location); - if (!companyName) return false; - const company = Companies[companyName]; - if (this.isQualified(company, CompanyPositions[JobName.securityEng])) { - return this.applyForJob(CompanyPositions[JobName.securityEng], sing); - } else { - if (!sing) { - dialogBoxCreate("Unfortunately, you do not qualify for this position"); - } - return false; - } -} - -export function applyForNetworkEngineerJob(this: PlayerObject, sing = false): boolean { - const companyName = getEnumHelper("CompanyName").getMember(this.location); - if (!companyName) return false; - const company = Companies[companyName]; - if (this.isQualified(company, CompanyPositions[JobName.networkEng0])) { - const pos = CompanyPositions[JobName.networkEng0]; - return this.applyForJob(pos, sing); - } else { - if (!sing) { - dialogBoxCreate("Unfortunately, you do not qualify for this position"); - } - return false; - } -} - -export function applyForBusinessJob(this: PlayerObject, sing = false): boolean { - return this.applyForJob(CompanyPositions[JobName.business0], sing); -} - -export function applyForBusinessConsultantJob(this: PlayerObject, sing = false): boolean { - return this.applyForJob(CompanyPositions[JobName.businessConsult0], sing); -} - -export function applyForSecurityJob(this: PlayerObject, sing = false): boolean { - // TODO Police Jobs - // Indexing starts at 2 because 0 is for police officer - return this.applyForJob(CompanyPositions[JobName.security0], sing); -} - -export function applyForAgentJob(this: PlayerObject, sing = false): boolean { - const companyName = getEnumHelper("CompanyName").getMember(this.location); - if (!companyName) return false; - const company = Companies[companyName]; - if (this.isQualified(company, CompanyPositions[JobName.agent0])) { - const pos = CompanyPositions[JobName.agent0]; - return this.applyForJob(pos, sing); - } else { - if (!sing) { - dialogBoxCreate("Unfortunately, you do not qualify for this position"); - } - return false; - } -} - -export function applyForEmployeeJob(this: PlayerObject, sing = false): boolean { - const companyName = getEnumHelper("CompanyName").getMember(this.location); - if (!companyName) return false; - const company = Companies[companyName]; - const position = JobName.employee; - // Check if this company has the position - if (!company.hasPosition(position)) { - return false; - } - if (this.isQualified(company, CompanyPositions[position])) { - this.jobs[company.name] = position; - - if (!sing) { - dialogBoxCreate("Congratulations, you are now employed at " + this.location); - } - - return true; - } else { - if (!sing) { - dialogBoxCreate("Unfortunately, you do not qualify for this position"); - } - - return false; - } -} - -export function applyForPartTimeEmployeeJob(this: PlayerObject, sing = false): boolean { - const companyName = getEnumHelper("CompanyName").getMember(this.location); - if (!companyName) return false; - const company = Companies[companyName]; - const position = JobName.employeePT; - // Check if this company has the position - if (!company.hasPosition(position)) { - return false; - } - if (this.isQualified(company, CompanyPositions[position])) { - this.jobs[company.name] = position; - if (!sing) { - dialogBoxCreate("Congratulations, you are now employed part-time at " + this.location); - } - - return true; - } else { - if (!sing) { - dialogBoxCreate("Unfortunately, you do not qualify for this position"); - } - - return false; - } -} - -export function applyForWaiterJob(this: PlayerObject, sing = false): boolean { - const companyName = getEnumHelper("CompanyName").getMember(this.location); - if (!companyName) return false; - const company = Companies[companyName]; - const position = JobName.waiter; - // Check if this company has the position - if (!company.hasPosition(position)) { - return false; - } - if (this.isQualified(company, CompanyPositions[position])) { - this.jobs[company.name] = position; - if (!sing) { - dialogBoxCreate("Congratulations, you are now employed as a waiter at " + this.location); - } - return true; - } else { - if (!sing) { - dialogBoxCreate("Unfortunately, you do not qualify for this position"); - } - return false; - } -} - -export function applyForPartTimeWaiterJob(this: PlayerObject, sing = false): boolean { - const companyName = getEnumHelper("CompanyName").getMember(this.location); - if (!companyName) return false; - const company = Companies[companyName]; - const position = JobName.waiterPT; - // Check if this company has the position - if (!company.hasPosition(position)) { - return false; - } - if (this.isQualified(company, CompanyPositions[position])) { - this.jobs[company.name] = position; - if (!sing) { - dialogBoxCreate("Congratulations, you are now employed as a part-time waiter at " + this.location); - } - return true; - } else { - if (!sing) { - dialogBoxCreate("Unfortunately, you do not qualify for this position"); - } - return false; - } -} - //Checks if the Player is qualified for a certain position export function isQualified(this: PlayerObject, company: Company, position: CompanyPosition): boolean { - const offset = company.jobStatReqOffset; - const reqHacking = position.requiredHacking > 0 ? position.requiredHacking + offset : 0; - const reqStrength = position.requiredStrength > 0 ? position.requiredStrength + offset : 0; - const reqDefense = position.requiredDefense > 0 ? position.requiredDefense + offset : 0; - const reqDexterity = position.requiredDexterity > 0 ? position.requiredDexterity + offset : 0; - const reqAgility = position.requiredDexterity > 0 ? position.requiredDexterity + offset : 0; - const reqCharisma = position.requiredCharisma > 0 ? position.requiredCharisma + offset : 0; - - return ( - this.skills.hacking >= reqHacking && - this.skills.strength >= reqStrength && - this.skills.defense >= reqDefense && - this.skills.dexterity >= reqDexterity && - this.skills.agility >= reqAgility && - this.skills.charisma >= reqCharisma && - company.playerReputation >= position.requiredReputation - ); + const reqs = getJobRequirements(company, position); + return reqs.every((req) => req.isSatisfied(this)); } /********** Reapplying Augmentations and Source File ***********/ diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index c83a6d913..930235af1 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -1893,7 +1893,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: JobField | `${JobField}`): boolean; + applyToCompany(companyName: CompanyName | `${CompanyName}`, field: JobField | `${JobField}`): JobName | null; /** * Get company reputation. diff --git a/src/Work/CompanyWork.tsx b/src/Work/CompanyWork.tsx index 1dde82400..3e8679e38 100644 --- a/src/Work/CompanyWork.tsx +++ b/src/Work/CompanyWork.tsx @@ -3,14 +3,13 @@ import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue import { Player } from "@player"; import { Work, WorkType } from "./Work"; import { influenceStockThroughCompanyWork } from "../StockMarket/PlayerInfluencing"; -import { AugmentationName, CompanyName, JobName } from "@enums"; +import { CompanyName, JobName } from "@enums"; import { calculateCompanyWorkStats } from "./Formulas"; import { Companies } from "../Company/Companies"; import { applyWorkStats, scaleWorkStats, WorkStats } from "./WorkStats"; import { Company } from "../Company/Company"; import { dialogBoxCreate } from "../ui/React/DialogBox"; import { Reputation } from "../ui/React/Reputation"; -import { CONSTANTS } from "../Constants"; import { CompanyPositions } from "../Company/CompanyPositions"; import { isMember } from "../utils/EnumHelper"; import { invalidWork } from "./InvalidWork"; @@ -34,10 +33,7 @@ export class CompanyWork extends Work { } getGainRates(job: JobName): WorkStats { - let focusBonus = 1; - if (!Player.hasAugmentation(AugmentationName.NeuroreceptorManager, true)) { - focusBonus = Player.focus ? 1 : CONSTANTS.BaseFocusBonus; - } + const focusBonus = CompanyPositions[job].isPartTime ? 1 : Player.focusPenalty(); const company = this.getCompany(); return scaleWorkStats(calculateCompanyWorkStats(Player, company, CompanyPositions[job], company.favor), focusBonus); } diff --git a/src/Work/CreateProgramWork.ts b/src/Work/CreateProgramWork.ts index 8039306fd..cf8c6d18e 100644 --- a/src/Work/CreateProgramWork.ts +++ b/src/Work/CreateProgramWork.ts @@ -1,6 +1,6 @@ import { dialogBoxCreate } from "../ui/React/DialogBox"; import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver"; -import { AugmentationName, CompletedProgramName } from "@enums"; +import { CompletedProgramName } from "@enums"; import { CONSTANTS } from "../Constants"; import { Player } from "@player"; import { Programs } from "../Programs/Programs"; @@ -55,10 +55,7 @@ export class CreateProgramWork extends Work { } process(cycles: number): boolean { - let focusBonus = 1; - if (!Player.hasAugmentation(AugmentationName.NeuroreceptorManager, true)) { - focusBonus = Player.focus ? 1 : CONSTANTS.BaseFocusBonus; - } + const focusBonus = Player.focusPenalty(); //Higher hacking skill will allow you to create programs faster const reqLvl = this.getProgram().create?.level ?? 0; let skillMult = (Player.skills.hacking / reqLvl) * calculateIntelligenceBonus(Player.skills.intelligence, 3); //This should always be greater than 1; diff --git a/src/Work/CrimeWork.ts b/src/Work/CrimeWork.ts index a64fae7cc..1c6cbcf8f 100644 --- a/src/Work/CrimeWork.ts +++ b/src/Work/CrimeWork.ts @@ -55,10 +55,10 @@ export class CrimeWork extends Work { ); return; } - const focusPenalty = Player.focusPenalty(); + const focusBonus = Player.focusPenalty(); // exp times 2 because were trying to maintain the same numbers as before the conversion // Technically the definition of Crimes should have the success numbers and failure should divide by 4 - let gains = scaleWorkStats(this.earnings(), focusPenalty, false); + let gains = scaleWorkStats(this.earnings(), focusBonus, false); let karma = crime.karma; const success = determineCrimeSuccess(crime.type); if (success) { @@ -75,7 +75,7 @@ export class CrimeWork extends Work { Player.gainDexterityExp(gains.dexExp); Player.gainAgilityExp(gains.agiExp); Player.gainCharismaExp(gains.chaExp); - Player.karma -= karma * focusPenalty; + Player.karma -= karma * focusBonus; } finish(): void { diff --git a/src/Work/FactionWork.tsx b/src/Work/FactionWork.tsx index 26c17530c..1e1bdafc6 100644 --- a/src/Work/FactionWork.tsx +++ b/src/Work/FactionWork.tsx @@ -4,12 +4,11 @@ import React from "react"; import { Work, WorkType } from "./Work"; import { constructorsForReviver, Generic_toJSON, Generic_fromJSON, IReviverValue } from "../utils/JSONReviver"; import { Player } from "@player"; -import { AugmentationName, FactionName, FactionWorkType } from "@enums"; +import { FactionName, FactionWorkType } from "@enums"; import { Factions } from "../Faction/Factions"; import { applyWorkStats, scaleWorkStats, WorkStats } from "./WorkStats"; import { dialogBoxCreate } from "../ui/React/DialogBox"; import { Reputation } from "../ui/React/Reputation"; -import { CONSTANTS } from "../Constants"; import { calculateFactionExp, calculateFactionRep } from "./Formulas"; import { getEnumHelper } from "../utils/EnumHelper"; @@ -36,18 +35,12 @@ export class FactionWork extends Work { } getReputationRate(): number { - let focusBonus = 1; - if (!Player.hasAugmentation(AugmentationName.NeuroreceptorManager, true)) { - focusBonus = Player.focus ? 1 : CONSTANTS.BaseFocusBonus; - } + const focusBonus = Player.focusPenalty(); return calculateFactionRep(Player, this.factionWorkType, this.getFaction().favor) * focusBonus; } getExpRates(): WorkStats { - let focusBonus = 1; - if (!Player.hasAugmentation(AugmentationName.NeuroreceptorManager, true)) { - focusBonus = Player.focus ? 1 : CONSTANTS.BaseFocusBonus; - } + const focusBonus = Player.focusPenalty(); const rate = calculateFactionExp(Player, this.factionWorkType); return scaleWorkStats(rate, focusBonus, false); } diff --git a/src/Work/GraftingWork.tsx b/src/Work/GraftingWork.tsx index 2bf8145bd..87fa8a902 100644 --- a/src/Work/GraftingWork.tsx +++ b/src/Work/GraftingWork.tsx @@ -35,11 +35,7 @@ export class GraftingWork extends Work { } process(cycles: number): boolean { - let focusBonus = 1; - if (!Player.hasAugmentation(AugmentationName.NeuroreceptorManager, true)) { - focusBonus = Player.focus ? 1 : CONSTANTS.BaseFocusBonus; - } - + const focusBonus = Player.focusPenalty(); this.cyclesWorked += cycles; this.unitCompleted += CONSTANTS.MilliPerCycle * cycles * graftingIntBonus() * focusBonus;