diff --git a/src/Company/CompanyPosition.ts b/src/Company/CompanyPosition.ts index 0206e9639..b4905f950 100644 --- a/src/Company/CompanyPosition.ts +++ b/src/Company/CompanyPosition.ts @@ -1,3 +1,4 @@ +import { Person } from "../PersonObjects/Person"; import { CONSTANTS } from "../Constants"; import * as names from "./data/companypositionnames"; @@ -117,13 +118,13 @@ export class CompanyPosition { this.charismaExpGain = p.charismaExpGain != null ? p.charismaExpGain : 0; } - calculateJobPerformance(hack: number, str: number, def: number, dex: number, agi: number, cha: number): number { - const hackRatio: number = (this.hackingEffectiveness * hack) / CONSTANTS.MaxSkillLevel; - const strRatio: number = (this.strengthEffectiveness * str) / CONSTANTS.MaxSkillLevel; - const defRatio: number = (this.defenseEffectiveness * def) / CONSTANTS.MaxSkillLevel; - const dexRatio: number = (this.dexterityEffectiveness * dex) / CONSTANTS.MaxSkillLevel; - const agiRatio: number = (this.agilityEffectiveness * agi) / CONSTANTS.MaxSkillLevel; - const chaRatio: number = (this.charismaEffectiveness * cha) / CONSTANTS.MaxSkillLevel; + calculateJobPerformance(worker: Person): number { + const hackRatio: number = (this.hackingEffectiveness * worker.skills.hacking) / CONSTANTS.MaxSkillLevel; + const strRatio: number = (this.strengthEffectiveness * worker.skills.strength) / CONSTANTS.MaxSkillLevel; + const defRatio: number = (this.defenseEffectiveness * worker.skills.defense) / CONSTANTS.MaxSkillLevel; + const dexRatio: number = (this.dexterityEffectiveness * worker.skills.dexterity) / CONSTANTS.MaxSkillLevel; + const agiRatio: number = (this.agilityEffectiveness * worker.skills.agility) / CONSTANTS.MaxSkillLevel; + const chaRatio: number = (this.charismaEffectiveness * worker.skills.charisma) / CONSTANTS.MaxSkillLevel; let reputationGain: number = (this.repMultiplier * (hackRatio + strRatio + defRatio + dexRatio + agiRatio + chaRatio)) / 100; @@ -131,7 +132,7 @@ export class CompanyPosition { console.error("Company reputation gain calculated to be NaN"); reputationGain = 0; } - + reputationGain += worker.skills.intelligence / CONSTANTS.MaxSkillLevel; return reputationGain; } diff --git a/src/Locations/ui/GymLocation.tsx b/src/Locations/ui/GymLocation.tsx index 007e3c900..9e931df7d 100644 --- a/src/Locations/ui/GymLocation.tsx +++ b/src/Locations/ui/GymLocation.tsx @@ -14,7 +14,7 @@ import { Money } from "../../ui/React/Money"; import { Router } from "../../ui/GameRoot"; import { Box } from "@mui/material"; import { ClassWork, ClassType, Classes } from "../../Work/ClassWork"; -import { calculateCost } from "../../Work/formulas/Class"; +import { calculateCost } from "../../Work/Formulas"; type IProps = { loc: Location; diff --git a/src/Locations/ui/UniversityLocation.tsx b/src/Locations/ui/UniversityLocation.tsx index 606b35186..7b8528ca9 100644 --- a/src/Locations/ui/UniversityLocation.tsx +++ b/src/Locations/ui/UniversityLocation.tsx @@ -15,7 +15,7 @@ import { Player } from "@player"; import { Box } from "@mui/material"; import { ClassWork, ClassType, Classes } from "../../Work/ClassWork"; -import { calculateCost } from "../../Work/formulas/Class"; +import { calculateCost } from "../../Work/Formulas"; type IProps = { loc: Location; diff --git a/src/Netscript/RamCostGenerator.ts b/src/Netscript/RamCostGenerator.ts index 566d27608..01010b150 100644 --- a/src/Netscript/RamCostGenerator.ts +++ b/src/Netscript/RamCostGenerator.ts @@ -600,6 +600,7 @@ export const RamCosts: RamCostTree> = { crimeGains: 0, classGains: 0, factionGains: 0, + companyGains: 0, }, }, } as const; diff --git a/src/NetscriptFunctions/Formulas.ts b/src/NetscriptFunctions/Formulas.ts index 0ebfd14a9..f8062af81 100644 --- a/src/NetscriptFunctions/Formulas.ts +++ b/src/NetscriptFunctions/Formulas.ts @@ -39,17 +39,20 @@ import { favorToRep as calculateFavorToRep, repToFavor as calculateRepToFavor } import { repFromDonation } from "../Faction/formulas/donation"; import { InternalAPI, NetscriptContext } from "../Netscript/APIWrapper"; import { helpers } from "../Netscript/NetscriptHelpers"; -import { calculateCrimeWorkStats } from "../Work/formulas/Crime"; +import { calculateCrimeWorkStats } from "../Work/Formulas"; import { Crimes } from "../Crime/Crimes"; -import { calculateClassEarnings } from "../Work/formulas/Class"; +import { calculateCompanyWorkStats } from "../Work/Formulas"; +import { Companies } from "../Company/Companies"; +import { calculateClassEarnings } from "../Work/Formulas"; import { ClassType } from "../Work/ClassWork"; import { LocationName } from "../Locations/data/LocationNames"; -import { calculateFactionExp, calculateFactionRep } from "../Work/formulas/Faction"; +import { calculateFactionExp, calculateFactionRep } from "../Work/Formulas"; import { FactionWorkType } from "../Work/data/FactionWorkType"; import { defaultMultipliers } from "../PersonObjects/Multipliers"; import { checkEnum } from "../utils/helpers/checkEnum"; import { CrimeType } from "../utils/WorkType"; +import { CompanyPositions } from "../Company/CompanyPositions"; export function NetscriptFormulas(): InternalAPI { const checkFormulasAccess = function (ctx: NetscriptContext): void { @@ -362,10 +365,11 @@ export function NetscriptFormulas(): InternalAPI { }, }, work: { - crimeGains: (ctx) => (_crimeType) => { + crimeGains: (ctx) => (_person, _crimeType) => { + const person = helpers.player(ctx, _person); const crimeType = helpers.string(ctx, "crimeType", _crimeType); if (!checkEnum(CrimeType, crimeType)) throw new Error(`Invalid crime type: ${crimeType}`); - return calculateCrimeWorkStats(Crimes[crimeType]); + return calculateCrimeWorkStats(person, Crimes[crimeType]); }, classGains: (ctx) => (_person, _classType, _locationName) => { const person = helpers.player(ctx, _person); @@ -382,10 +386,22 @@ export function NetscriptFormulas(): InternalAPI { exp.reputation = rep; return exp; }, - // companyGains: (ctx) => (_player) { - // const player = helpers.player(ctx, _player); - // }, + companyGains: (ctx) => (_player, _companyName, _positionName, _favor) => { + const player = helpers.player(ctx, _player); + CompanyPositions; + const positionName = helpers.string(ctx, "_positionName", _positionName); + const position = Object.values(CompanyPositions).find((c) => c.name === positionName); + if (!position) throw new Error(`Invalid position name: ${positionName}`); + + const companyName = helpers.string(ctx, "_companyName", _companyName); + const company = Object.values(Companies).find((c) => c.name === companyName); + if (!company) throw new Error(`Invalid company name: ${companyName}`); + + const favor = helpers.number(ctx, "favor", _favor); + + return calculateCompanyWorkStats(player, company, position, favor); + }, }, }; } diff --git a/src/NetscriptFunctions/Singularity.ts b/src/NetscriptFunctions/Singularity.ts index c707e192b..56b80df95 100644 --- a/src/NetscriptFunctions/Singularity.ts +++ b/src/NetscriptFunctions/Singularity.ts @@ -49,7 +49,7 @@ import { FactionWorkType } from "../Work/data/FactionWorkType"; import { CompanyWork } from "../Work/CompanyWork"; import { canGetBonus, onExport } from "../ExportBonus"; import { saveObject } from "../SaveObject"; -import { calculateCrimeWorkStats } from "../Work/formulas/Crime"; +import { calculateCrimeWorkStats } from "../Work/Formulas"; import { checkEnum } from "../utils/helpers/checkEnum"; import { Crimes } from "../Crime/Crimes"; import { CrimeType } from "../utils/WorkType"; @@ -1160,7 +1160,7 @@ export function NetscriptSingularity(): InternalAPI { const crime = checkEnum(CrimeType, crimeType) ? Crimes[crimeType] : findCrime(crimeType); if (crime == null) throw helpers.makeRuntimeErrorMsg(ctx, `Invalid crime: '${crimeType}'`); - const crimeStatsWithMultipliers = calculateCrimeWorkStats(crime); + const crimeStatsWithMultipliers = calculateCrimeWorkStats(Player, crime); return Object.assign({}, crime, { money: crimeStatsWithMultipliers.money, diff --git a/src/NetscriptFunctions/Sleeve.ts b/src/NetscriptFunctions/Sleeve.ts index a22dd711c..43586bbd5 100644 --- a/src/NetscriptFunctions/Sleeve.ts +++ b/src/NetscriptFunctions/Sleeve.ts @@ -13,6 +13,7 @@ import { isSleeveCompanyWork } from "../PersonObjects/Sleeve/Work/SleeveCompanyW import { helpers } from "../Netscript/NetscriptHelpers"; import { Crimes } from "../Crime/Crimes"; import { CrimeType } from "../utils/WorkType"; +import { cloneDeep } from "lodash"; export function NetscriptSleeve(): InternalAPI { const checkSleeveAPIAccess = function (ctx: NetscriptContext) { @@ -200,6 +201,7 @@ export function NetscriptSleeve(): InternalAPI { strengthExp: sl.mults.strength_exp, workMoney: sl.mults.work_money, }, + skills: cloneDeep(sl.skills), }; }, getSleeveAugmentations: (ctx) => (_sleeveNumber) => { diff --git a/src/PersonObjects/Sleeve/Work/SleeveClassWork.ts b/src/PersonObjects/Sleeve/Work/SleeveClassWork.ts index cbd7c9760..65c766def 100644 --- a/src/PersonObjects/Sleeve/Work/SleeveClassWork.ts +++ b/src/PersonObjects/Sleeve/Work/SleeveClassWork.ts @@ -2,7 +2,7 @@ import { Generic_fromJSON, Generic_toJSON, IReviverValue, Reviver } from "../../ import { applySleeveGains, Work, WorkType } from "./Work"; import { ClassType } from "../../../Work/ClassWork"; import { LocationName } from "../../../Locations/data/LocationNames"; -import { calculateClassEarnings } from "../../../Work/formulas/Class"; +import { calculateClassEarnings } from "../../../Work/Formulas"; import { Sleeve } from "../Sleeve"; import { scaleWorkStats, WorkStats } from "../../../Work/WorkStats"; diff --git a/src/PersonObjects/Sleeve/Work/SleeveCompanyWork.ts b/src/PersonObjects/Sleeve/Work/SleeveCompanyWork.ts index 9c3dcd061..d027b476b 100644 --- a/src/PersonObjects/Sleeve/Work/SleeveCompanyWork.ts +++ b/src/PersonObjects/Sleeve/Work/SleeveCompanyWork.ts @@ -4,9 +4,11 @@ import { applySleeveGains, Work, WorkType } from "./Work"; import { LocationName } from "../../../Locations/data/LocationNames"; import { Companies } from "../../../Company/Companies"; import { Company } from "../../../Company/Company"; -import { calculateCompanyWorkStats } from "../../../Work/formulas/Company"; +import { calculateCompanyWorkStats } from "../../../Work/Formulas"; import { WorkStats } from "../../../Work/WorkStats"; import { influenceStockThroughCompanyWork } from "../../../StockMarket/PlayerInfluencing"; +import { Player } from "@player"; +import { CompanyPositions } from "../../../Company/CompanyPositions"; interface SleeveCompanyWorkParams { companyName: string; @@ -30,7 +32,8 @@ export class SleeveCompanyWork extends Work { } getGainRates(sleeve: Sleeve): WorkStats { - return calculateCompanyWorkStats(sleeve, this.getCompany()); + const company = this.getCompany(); + return calculateCompanyWorkStats(sleeve, company, CompanyPositions[Player.jobs[company.name]], company.favor); } process(sleeve: Sleeve, cycles: number): number { diff --git a/src/PersonObjects/Sleeve/Work/SleeveCrimeWork.ts b/src/PersonObjects/Sleeve/Work/SleeveCrimeWork.ts index 6f254399c..a5f170869 100644 --- a/src/PersonObjects/Sleeve/Work/SleeveCrimeWork.ts +++ b/src/PersonObjects/Sleeve/Work/SleeveCrimeWork.ts @@ -5,10 +5,10 @@ import { applySleeveGains, Work, WorkType } from "./Work"; import { CrimeType } from "../../../utils/WorkType"; import { Crimes } from "../../../Crime/Crimes"; import { Crime } from "../../../Crime/Crime"; -import { newWorkStats, scaleWorkStats, WorkStats } from "../../../Work/WorkStats"; +import { scaleWorkStats, WorkStats } from "../../../Work/WorkStats"; import { CONSTANTS } from "../../../Constants"; -import { BitNodeMultipliers } from "../../../BitNode/BitNodeMultipliers"; import { checkEnum } from "../../../utils/helpers/checkEnum"; +import { calculateCrimeWorkStats } from "../../../Work/Formulas"; export const isSleeveCrimeWork = (w: Work | null): w is SleeveCrimeWork => w !== null && w.type === WorkType.CRIME; @@ -26,17 +26,7 @@ export class SleeveCrimeWork extends Work { } getExp(sleeve: Sleeve): WorkStats { - const crime = this.getCrime(); - return newWorkStats({ - money: crime.money * BitNodeMultipliers.CrimeMoney * sleeve.mults.crime_money, - hackExp: crime.hacking_exp * BitNodeMultipliers.CrimeExpGain * sleeve.mults.hacking_exp, - strExp: crime.strength_exp * BitNodeMultipliers.CrimeExpGain * sleeve.mults.strength_exp, - defExp: crime.defense_exp * BitNodeMultipliers.CrimeExpGain * sleeve.mults.defense_exp, - dexExp: crime.dexterity_exp * BitNodeMultipliers.CrimeExpGain * sleeve.mults.dexterity_exp, - agiExp: crime.agility_exp * BitNodeMultipliers.CrimeExpGain * sleeve.mults.agility_exp, - chaExp: crime.charisma_exp * BitNodeMultipliers.CrimeExpGain * sleeve.mults.charisma_exp, - intExp: crime.intelligence_exp * BitNodeMultipliers.CrimeExpGain, - }); + return calculateCrimeWorkStats(sleeve, this.getCrime()); } cyclesNeeded(): number { diff --git a/src/PersonObjects/Sleeve/Work/SleeveFactionWork.ts b/src/PersonObjects/Sleeve/Work/SleeveFactionWork.ts index ec8ca8abe..252b04ea4 100644 --- a/src/PersonObjects/Sleeve/Work/SleeveFactionWork.ts +++ b/src/PersonObjects/Sleeve/Work/SleeveFactionWork.ts @@ -5,15 +5,9 @@ import { applySleeveGains, Work, WorkType } from "./Work"; import { FactionWorkType } from "../../../Work/data/FactionWorkType"; import { FactionNames } from "../../../Faction/data/FactionNames"; import { Factions } from "../../../Faction/Factions"; -import { calculateFactionExp } from "../../../Work/formulas/Faction"; +import { calculateFactionExp, calculateFactionRep } from "../../../Work/Formulas"; import { Faction } from "../../../Faction/Faction"; -import { - getFactionFieldWorkRepGain, - getFactionSecurityWorkRepGain, - getHackingWorkRepGain, -} from "../../../PersonObjects/formulas/reputation"; import { scaleWorkStats, WorkStats } from "../../../Work/WorkStats"; -import { BitNodeMultipliers } from "../../../BitNode/BitNodeMultipliers"; interface SleeveFactionWorkParams { factionWorkType: FactionWorkType; @@ -38,17 +32,7 @@ export class SleeveFactionWork extends Work { } getReputationRate(sleeve: Sleeve): number { - const faction = this.getFaction(); - const repFormulas = { - [FactionWorkType.HACKING]: getHackingWorkRepGain, - [FactionWorkType.FIELD]: getFactionFieldWorkRepGain, - [FactionWorkType.SECURITY]: getFactionSecurityWorkRepGain, - }; - return ( - repFormulas[this.factionWorkType](sleeve, faction.favor) * - sleeve.shockBonus() * - BitNodeMultipliers.FactionWorkRepGain - ); + return calculateFactionRep(sleeve, this.factionWorkType, this.getFaction().favor) * sleeve.shockBonus(); } getFaction(): Faction { diff --git a/src/ScriptEditor/NetscriptDefinitions.d.ts b/src/ScriptEditor/NetscriptDefinitions.d.ts index 8233f21b1..00a370ca4 100644 --- a/src/ScriptEditor/NetscriptDefinitions.d.ts +++ b/src/ScriptEditor/NetscriptDefinitions.d.ts @@ -37,7 +37,7 @@ type ScriptArg = string | number | boolean; type FilenameOrPID = number | string; /** @public */ -interface Player { +interface Person { hp: HP; skills: Skills; exp: Skills; @@ -641,62 +641,6 @@ export interface NodeStats { totalProduction: number; } -/** @public */ -export interface CharacterMult { - /** Agility stat */ - agility: number; - /** Agility exp */ - agilityExp: number; - /** Charisma stat */ - charisma: number; - /** Charisma exp */ - charismaExp: number; - /** Company reputation */ - companyRep: number; - /** Money earned from crimes */ - crimeMoney: number; - /** Crime success chance */ - crimeSuccess: number; - /** Defense stat */ - defense: number; - /** Defense exp */ - defenseExp: number; - /** Dexterity stat */ - dexterity: number; - /** Dexterity exp */ - dexterityExp: number; - /** Faction reputation */ - factionRep: number; - /** Hacking stat */ - hacking: number; - /** Hacking exp */ - hackingExp: number; - /** Strength stat */ - strength: number; - /** Strength exp */ - strengthExp: number; - /** Money earned from jobs */ - workMoney: number; -} - -/** @public */ -export interface SleeveWorkGains { - /** Hacking exp gained from work */ - workHackExpGain: number; - /** Strength exp gained from work */ - workStrExpGain: number; - /** Defense exp gained from work, */ - workDefExpGain: number; - /** Dexterity exp gained from work */ - workDexExpGain: number; - /** Agility exp gained from work */ - workAgiExpGain: number; - /** Charisma exp gained from work */ - workChaExpGain: number; - /** Money gained from work */ - workMoneyGain: number; -} - /** @public */ export interface SourceFileLvl { /** The number of the source file */ @@ -966,7 +910,9 @@ export interface SleeveInformation { /** Does this sleeve have access to the tor router */ tor: boolean; /** Sleeve multipliers */ - mult: CharacterMult; + mult: Multipliers; + /** Sleeve skills */ + skills: Skills; } /** @@ -3907,9 +3853,10 @@ export interface WorkStats { * @public */ interface WorkFormulas { - crimeGains(crimeType: CrimeType | CrimeNames): WorkStats; - classGains(player: Player, classType: string, locationName: string): WorkStats; - factionGains(player: Player, workType: string, favor: number): WorkStats; + crimeGains(person: Person, crimeType: CrimeType | CrimeNames): WorkStats; + classGains(person: Person, classType: string, locationName: string): WorkStats; + factionGains(person: Person, workType: string, favor: number): WorkStats; + companyGains(person: Person, companyName: string, workType: string, favor: number): WorkStats; } /** @@ -3936,7 +3883,7 @@ interface ReputationFormulas { * @param amount - Amount of money donated * @param player - Player info from {@link NS.getPlayer | getPlayer} */ - repFromDonation(amount: number, player: Player): number; + repFromDonation(amount: number, player: Person): number; } /** @@ -3951,7 +3898,7 @@ interface HackingFormulas { * @param player - Player info from {@link NS.getPlayer | getPlayer} * @returns The calculated hack chance. */ - hackChance(server: Server, player: Player): number; + hackChance(server: Server, player: Person): number; /** * Calculate hack exp for one thread. * @remarks @@ -3960,7 +3907,7 @@ interface HackingFormulas { * @param player - Player info from {@link NS.getPlayer | getPlayer} * @returns The calculated hack exp. */ - hackExp(server: Server, player: Player): number; + hackExp(server: Server, player: Person): number; /** * Calculate hack percent for one thread. * (Ex: 0.25 would steal 25% of the server's current value.) @@ -3970,7 +3917,7 @@ interface HackingFormulas { * @param player - Player info from {@link NS.getPlayer | getPlayer} * @returns The calculated hack percent. */ - hackPercent(server: Server, player: Player): number; + hackPercent(server: Server, player: Person): number; /** * Calculate the percent a server would grow to. * (Ex: 3.0 would would grow the server to 300% of its current value.) @@ -3980,28 +3927,28 @@ interface HackingFormulas { * @param cores - Number of cores on the computer that will execute grow. * @returns The calculated grow percent. */ - growPercent(server: Server, threads: number, player: Player, cores?: number): number; + growPercent(server: Server, threads: number, player: Person, cores?: number): number; /** * Calculate hack time. * @param server - Server info from {@link NS.getServer | getServer} * @param player - Player info from {@link NS.getPlayer | getPlayer} * @returns The calculated hack time. */ - hackTime(server: Server, player: Player): number; + hackTime(server: Server, player: Person): number; /** * Calculate grow time. * @param server - Server info from {@link NS.getServer | getServer} * @param player - Player info from {@link NS.getPlayer | getPlayer} * @returns The calculated grow time. */ - growTime(server: Server, player: Player): number; + growTime(server: Server, player: Person): number; /** * Calculate weaken time. * @param server - Server info from {@link NS.getServer | getServer} * @param player - Player info from {@link NS.getPlayer | getPlayer} * @returns The calculated weaken time. */ - weakenTime(server: Server, player: Player): number; + weakenTime(server: Server, player: Person): number; } /** @@ -4182,7 +4129,7 @@ interface GangFormulas { */ export interface Formulas { mockServer(): Server; - mockPlayer(): Player; + mockPlayer(): Person; /** Reputation formulas */ reputation: ReputationFormulas; /** Skills formulas */ @@ -6758,7 +6705,7 @@ export interface NS { * * @returns Player info */ - getPlayer(): Player; + getPlayer(): Person; /** * Get information about the sources of income for this run. diff --git a/src/Work/ClassWork.tsx b/src/Work/ClassWork.tsx index f1b11d3f3..c3daa6ed3 100644 --- a/src/Work/ClassWork.tsx +++ b/src/Work/ClassWork.tsx @@ -7,7 +7,7 @@ import { dialogBoxCreate } from "../ui/React/DialogBox"; import { Money } from "../ui/React/Money"; import { convertTimeMsToTimeElapsedString } from "../utils/StringHelperFunctions"; import { Player } from "@player"; -import { calculateClassEarnings as calculateClassEarningsRate } from "./formulas/Class"; +import { calculateClassEarnings as calculateClassEarningsRate } from "./Formulas"; import { Work, WorkType } from "./Work"; import { applyWorkStats, newWorkStats, sumWorkStats, WorkStats } from "./WorkStats"; diff --git a/src/Work/CompanyWork.tsx b/src/Work/CompanyWork.tsx index f08931c7f..dce14ac61 100644 --- a/src/Work/CompanyWork.tsx +++ b/src/Work/CompanyWork.tsx @@ -4,7 +4,7 @@ import { Player } from "@player"; import { Work, WorkType } from "./Work"; import { influenceStockThroughCompanyWork } from "../StockMarket/PlayerInfluencing"; import { LocationName } from "../Locations/data/LocationNames"; -import { calculateCompanyWorkStats } from "./formulas/Company"; +import { calculateCompanyWorkStats } from "./Formulas"; import { Companies } from "../Company/Companies"; import { applyWorkStats, scaleWorkStats, WorkStats } from "./WorkStats"; import { Company } from "../Company/Company"; @@ -12,6 +12,7 @@ import { dialogBoxCreate } from "../ui/React/DialogBox"; import { Reputation } from "../ui/React/Reputation"; import { AugmentationNames } from "../Augmentation/data/AugmentationNames"; import { CONSTANTS } from "../Constants"; +import { CompanyPositions } from "../Company/CompanyPositions"; interface CompanyWorkParams { companyName: string; @@ -38,7 +39,11 @@ export class CompanyWork extends Work { if (!Player.hasAugmentation(AugmentationNames.NeuroreceptorManager, true)) { focusBonus = Player.focus ? 1 : CONSTANTS.BaseFocusBonus; } - return scaleWorkStats(calculateCompanyWorkStats(Player, this.getCompany()), focusBonus); + const company = this.getCompany(); + return scaleWorkStats( + calculateCompanyWorkStats(Player, company, CompanyPositions[Player.jobs[company.name]], company.favor), + focusBonus, + ); } process(cycles: number): boolean { diff --git a/src/Work/CrimeWork.ts b/src/Work/CrimeWork.ts index ea1eae137..52d387886 100644 --- a/src/Work/CrimeWork.ts +++ b/src/Work/CrimeWork.ts @@ -8,7 +8,7 @@ import { dialogBoxCreate } from "../ui/React/DialogBox"; import { CrimeType } from "../utils/WorkType"; import { Work, WorkType } from "./Work"; import { scaleWorkStats, WorkStats } from "./WorkStats"; -import { calculateCrimeWorkStats } from "./formulas/Crime"; +import { calculateCrimeWorkStats } from "./Formulas"; import { checkEnum } from "../utils/helpers/checkEnum"; interface CrimeWorkParams { @@ -47,7 +47,7 @@ export class CrimeWork extends Work { } earnings(): WorkStats { - return calculateCrimeWorkStats(this.getCrime()); + return calculateCrimeWorkStats(Player, this.getCrime()); } commit(): void { diff --git a/src/Work/FactionWork.tsx b/src/Work/FactionWork.tsx index 3cd5aac81..0c6fb8267 100644 --- a/src/Work/FactionWork.tsx +++ b/src/Work/FactionWork.tsx @@ -10,7 +10,7 @@ import { dialogBoxCreate } from "../ui/React/DialogBox"; import { Reputation } from "../ui/React/Reputation"; import { CONSTANTS } from "../Constants"; import { AugmentationNames } from "../Augmentation/data/AugmentationNames"; -import { calculateFactionExp, calculateFactionRep } from "./formulas/Faction"; +import { calculateFactionExp, calculateFactionRep } from "./Formulas"; import { FactionWorkType } from "./data/FactionWorkType"; interface FactionWorkParams { diff --git a/src/Work/Formulas.ts b/src/Work/Formulas.ts new file mode 100644 index 000000000..579e5379e --- /dev/null +++ b/src/Work/Formulas.ts @@ -0,0 +1,142 @@ +import { BitNodeMultipliers } from "../BitNode/BitNodeMultipliers"; +import { Crime } from "../Crime/Crime"; +import { newWorkStats, scaleWorkStats, WorkStats, multWorkStats } from "./WorkStats"; +import { Person } from "../PersonObjects/Person"; +import { CONSTANTS } from "../Constants"; +import { FactionWorkType } from "./data/FactionWorkType"; +import { + getFactionFieldWorkRepGain, + getFactionSecurityWorkRepGain, + getHackingWorkRepGain, +} from "../PersonObjects/formulas/reputation"; +import { Locations } from "../Locations/Locations"; +import { Location } from "../Locations/Location"; +import { Player } from "@player"; +import { Class, Classes, ClassType } from "./ClassWork"; +import { Server } from "../Server/Server"; +import { GetServer } from "../Server/AllServers"; +import { serverMetadata } from "../Server/data/servers"; +import { LocationName } from "../Locations/data/LocationNames"; +import { Company } from "../Company/Company"; +import { CompanyPosition } from "../Company/CompanyPosition"; + +const gameCPS = 1000 / CONSTANTS._idleSpeed; // 5 cycles per second +export const FactionWorkStats: Record = { + [FactionWorkType.HACKING]: newWorkStats({ hackExp: 15 }), + [FactionWorkType.FIELD]: newWorkStats({ + hackExp: 10, + strExp: 10, + defExp: 10, + dexExp: 10, + agiExp: 10, + chaExp: 10, + }), + [FactionWorkType.SECURITY]: newWorkStats({ + hackExp: 5, + strExp: 15, + defExp: 15, + dexExp: 15, + agiExp: 15, + }), +}; + +export function calculateCrimeWorkStats(person: Person, crime: Crime): WorkStats { + const gains = scaleWorkStats( + multWorkStats( + //Todo: rework crime and workstats interfaces to use the same naming convention for exp values, then we can just make a workStats directly from a crime. + newWorkStats({ + money: crime.money, + hackExp: crime.hacking_exp, + strExp: crime.strength_exp, + defExp: crime.defense_exp, + dexExp: crime.dexterity_exp, + agiExp: crime.agility_exp, + chaExp: crime.charisma_exp, + intExp: crime.intelligence_exp, + }), + person.mults, + person.mults.crime_money * BitNodeMultipliers.CrimeMoney, + ), + BitNodeMultipliers.CrimeExpGain, + false, + ); + return gains; +} + +export const calculateFactionRep = (person: Person, type: FactionWorkType, favor: number): number => { + const repFormulas = { + [FactionWorkType.HACKING]: getHackingWorkRepGain, + [FactionWorkType.FIELD]: getFactionFieldWorkRepGain, + [FactionWorkType.SECURITY]: getFactionSecurityWorkRepGain, + }; + return repFormulas[type](person, favor); +}; + +export function calculateFactionExp(person: Person, type: FactionWorkType): WorkStats { + return scaleWorkStats( + multWorkStats(FactionWorkStats[type], person.mults), + BitNodeMultipliers.FactionWorkExpGain / gameCPS, + ); +} + +/** Calculate cost for a class */ +export function calculateCost(classs: Class, location: Location): number { + const serverMeta = serverMetadata.find((s) => s.specialName === location.name); + const server = GetServer(serverMeta ? serverMeta.hostname : ""); + const discount = (server as Server).backdoorInstalled ? 0.9 : 1; + return classs.earnings.money * location.costMult * discount; +} + +export function calculateClassEarnings(person: Person, type: ClassType, locationName: LocationName): WorkStats { + const hashManager = Player.hashManager; + const classs = Classes[type]; + const location = Locations[locationName]; + + const hashMult = [ClassType.GymAgility, ClassType.GymDefense, ClassType.GymStrength, ClassType.GymDexterity].includes( + type, + ) + ? hashManager.getTrainingMult() + : hashManager.getStudyMult(); + + const earnings = multWorkStats( + scaleWorkStats(classs.earnings, (location.expMult / gameCPS) * hashMult, false), + person.mults, + ); + earnings.money = calculateCost(classs, location) / gameCPS; + return earnings; +} + +export const calculateCompanyWorkStats = ( + worker: Person, + company: Company, + companyPosition: CompanyPosition, + favor: number, +): WorkStats => { + // If player has SF-11, calculate salary multiplier from favor + const favorMult = isNaN(favor) ? 1 : 1 + favor / 100; + const bn11Mult = Player.sourceFileLvl(11) > 0 ? favorMult : 1; + + const gains = scaleWorkStats( + multWorkStats( + { + money: companyPosition.baseSalary * company.salaryMultiplier * bn11Mult * BitNodeMultipliers.CompanyWorkMoney, + hackExp: companyPosition.hackingExpGain, + strExp: companyPosition.strengthExpGain, + defExp: companyPosition.defenseExpGain, + dexExp: companyPosition.dexterityExpGain, + agiExp: companyPosition.agilityExpGain, + chaExp: companyPosition.charismaExpGain, + }, + worker.mults, + worker.mults.work_money, + ), + company.expMultiplier * BitNodeMultipliers.CompanyWorkExpGain, + false, + ); + + const jobPerformance = companyPosition.calculateJobPerformance(worker); + + gains.reputation = jobPerformance * worker.mults.company_rep * favorMult; + + return gains; +}; diff --git a/src/Work/WorkStats.ts b/src/Work/WorkStats.ts index 4acf59c65..9c8090d4c 100644 --- a/src/Work/WorkStats.ts +++ b/src/Work/WorkStats.ts @@ -1,5 +1,6 @@ import { Person } from "src/PersonObjects/Person"; import { Player } from "@player"; +import { Multipliers } from "../PersonObjects/Multipliers"; export interface WorkStats { money: number; @@ -13,19 +14,7 @@ export interface WorkStats { intExp: number; } -interface newWorkStatsParams { - money?: number; - reputation?: number; - hackExp?: number; - strExp?: number; - defExp?: number; - dexExp?: number; - agiExp?: number; - chaExp?: number; - intExp?: number; -} - -export const newWorkStats = (params?: newWorkStatsParams): WorkStats => { +export const newWorkStats = (params?: Partial): WorkStats => { return { money: params?.money ?? 0, reputation: params?.reputation ?? 0, @@ -39,6 +28,7 @@ export const newWorkStats = (params?: newWorkStatsParams): WorkStats => { }; }; +/** Add two workStats objects */ export const sumWorkStats = (w0: WorkStats, w1: WorkStats): WorkStats => { return { money: w0.money + w1.money, @@ -53,6 +43,7 @@ export const sumWorkStats = (w0: WorkStats, w1: WorkStats): WorkStats => { }; }; +/** Scale all stats on a WorkStats object by a number. Money scaling optional but defaults to true. */ export const scaleWorkStats = (w: WorkStats, n: number, scaleMoney = true): WorkStats => { const m = scaleMoney ? n : 1; return { @@ -107,3 +98,18 @@ export const applyWorkStatsExp = (target: Person, workStats: WorkStats, cycles: target.gainIntelligenceExp(gains.intExp); return gains; }; + +/** Calculate the application of a person's multipliers to a WorkStats object */ +export function multWorkStats(workStats: Partial, mults: Multipliers, moneyMult = 1, repMult = 1) { + return { + money: (workStats.money ?? 0) * moneyMult, + reputation: (workStats.reputation ?? 0) * repMult, + hackExp: (workStats.hackExp ?? 0) * mults.hacking_exp, + strExp: (workStats.strExp ?? 0) * mults.strength_exp, + defExp: (workStats.defExp ?? 0) * mults.defense_exp, + dexExp: (workStats.dexExp ?? 0) * mults.dexterity_exp, + agiExp: (workStats.agiExp ?? 0) * mults.agility_exp, + chaExp: (workStats.chaExp ?? 0) * mults.charisma_exp, + intExp: workStats.intExp ?? 0, + }; +} diff --git a/src/Work/formulas/Class.ts b/src/Work/formulas/Class.ts deleted file mode 100644 index 2af9d557c..000000000 --- a/src/Work/formulas/Class.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Locations } from "../../Locations/Locations"; -import { Location } from "../../Locations/Location"; -import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers"; -import { CONSTANTS } from "../../Constants"; -import { Player } from "@player"; -import { Class, Classes, ClassType } from "../ClassWork"; -import { WorkStats } from "../WorkStats"; -import { Server } from "../../Server/Server"; -import { GetServer } from "../../Server/AllServers"; -import { serverMetadata } from "../../Server/data/servers"; -import { Person } from "../../PersonObjects/Person"; -import { LocationName } from "../../Locations/data/LocationNames"; - -const gameCPS = 1000 / CONSTANTS._idleSpeed; // 5 cycles per second - -export function calculateCost(classs: Class, location: Location): number { - const serverMeta = serverMetadata.find((s) => s.specialName === location.name); - const server = GetServer(serverMeta ? serverMeta.hostname : ""); - const discount = (server as Server).backdoorInstalled ? 0.9 : 1; - return classs.earnings.money * location.costMult * discount; -} - -export function calculateClassEarnings(person: Person, type: ClassType, locationName: LocationName): WorkStats { - //Find cost and exp gain per game cycle - const hashManager = Player.hashManager; - const classs = Classes[type]; - const location = Locations[locationName]; - - const hashMult = [ClassType.GymAgility, ClassType.GymDefense, ClassType.GymStrength, ClassType.GymDexterity].includes( - type, - ) - ? hashManager.getTrainingMult() - : hashManager.getStudyMult(); - - const cost = calculateCost(classs, location) / gameCPS; - const hackExp = ((classs.earnings.hackExp * location.expMult) / gameCPS) * hashMult; - const strExp = ((classs.earnings.strExp * location.expMult) / gameCPS) * hashMult; - const defExp = ((classs.earnings.defExp * location.expMult) / gameCPS) * hashMult; - const dexExp = ((classs.earnings.dexExp * location.expMult) / gameCPS) * hashMult; - const agiExp = ((classs.earnings.agiExp * location.expMult) / gameCPS) * hashMult; - const chaExp = ((classs.earnings.chaExp * location.expMult) / gameCPS) * hashMult; - return { - money: cost, - reputation: 0, - hackExp: hackExp * person.mults.hacking_exp * BitNodeMultipliers.ClassGymExpGain, - strExp: strExp * person.mults.strength_exp * BitNodeMultipliers.ClassGymExpGain, - defExp: defExp * person.mults.defense_exp * BitNodeMultipliers.ClassGymExpGain, - dexExp: dexExp * person.mults.dexterity_exp * BitNodeMultipliers.ClassGymExpGain, - agiExp: agiExp * person.mults.agility_exp * BitNodeMultipliers.ClassGymExpGain, - chaExp: chaExp * person.mults.charisma_exp * BitNodeMultipliers.ClassGymExpGain, - intExp: 0, - }; -} diff --git a/src/Work/formulas/Company.ts b/src/Work/formulas/Company.ts deleted file mode 100644 index f3e110b88..000000000 --- a/src/Work/formulas/Company.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { CompanyPositions } from "../../Company/CompanyPositions"; -import { Company } from "../../Company/Company"; -import { Player } from "@player"; -import { WorkStats } from "../WorkStats"; -import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers"; -import { CONSTANTS } from "../../Constants"; -import { Person } from "../../PersonObjects/Person"; - -export const calculateCompanyWorkStats = (worker: Person, company: Company): WorkStats => { - const companyPositionName = Player.jobs[company.name]; - const companyPosition = CompanyPositions[companyPositionName]; - - // If player has SF-11, calculate salary multiplier from favor - let favorMult = 1 + company.favor / 100; - if (isNaN(favorMult)) { - favorMult = 1; - } - - let bn11Mult = 1; - if (Player.sourceFileLvl(11) > 0) { - bn11Mult = favorMult; - } - - let jobPerformance = companyPosition.calculateJobPerformance( - worker.skills.hacking, - worker.skills.strength, - worker.skills.defense, - worker.skills.dexterity, - worker.skills.agility, - worker.skills.charisma, - ); - - jobPerformance += worker.skills.intelligence / CONSTANTS.MaxSkillLevel; - - return { - money: - companyPosition.baseSalary * - company.salaryMultiplier * - worker.mults.work_money * - BitNodeMultipliers.CompanyWorkMoney * - bn11Mult, - reputation: jobPerformance * worker.mults.company_rep * favorMult, - hackExp: - companyPosition.hackingExpGain * - company.expMultiplier * - worker.mults.hacking_exp * - BitNodeMultipliers.CompanyWorkExpGain, - strExp: - companyPosition.strengthExpGain * - company.expMultiplier * - worker.mults.strength_exp * - BitNodeMultipliers.CompanyWorkExpGain, - defExp: - companyPosition.defenseExpGain * - company.expMultiplier * - worker.mults.defense_exp * - BitNodeMultipliers.CompanyWorkExpGain, - dexExp: - companyPosition.dexterityExpGain * - company.expMultiplier * - worker.mults.dexterity_exp * - BitNodeMultipliers.CompanyWorkExpGain, - agiExp: - companyPosition.agilityExpGain * - company.expMultiplier * - worker.mults.agility_exp * - BitNodeMultipliers.CompanyWorkExpGain, - chaExp: - companyPosition.charismaExpGain * - company.expMultiplier * - worker.mults.charisma_exp * - BitNodeMultipliers.CompanyWorkExpGain, - intExp: 0, - }; -}; diff --git a/src/Work/formulas/Crime.ts b/src/Work/formulas/Crime.ts deleted file mode 100644 index 3d8da618f..000000000 --- a/src/Work/formulas/Crime.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers"; -import { Crime } from "src/Crime/Crime"; -import { newWorkStats, scaleWorkStats, WorkStats } from "../WorkStats"; -import { Player } from "@player"; - -export const calculateCrimeWorkStats = (crime: Crime): WorkStats => { - const gains = scaleWorkStats( - newWorkStats({ - money: crime.money * Player.mults.crime_money, - hackExp: crime.hacking_exp * 2 * Player.mults.hacking_exp, - strExp: crime.strength_exp * 2 * Player.mults.strength_exp, - defExp: crime.defense_exp * 2 * Player.mults.defense_exp, - dexExp: crime.dexterity_exp * 2 * Player.mults.dexterity_exp, - agiExp: crime.agility_exp * 2 * Player.mults.agility_exp, - chaExp: crime.charisma_exp * 2 * Player.mults.charisma_exp, - intExp: crime.intelligence_exp * 2, - }), - BitNodeMultipliers.CrimeExpGain, - false, - ); - gains.money *= BitNodeMultipliers.CrimeMoney; - return gains; -}; diff --git a/src/Work/formulas/Faction.ts b/src/Work/formulas/Faction.ts deleted file mode 100644 index 1dd704c3a..000000000 --- a/src/Work/formulas/Faction.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Person } from "../../PersonObjects/Person"; -import { BitNodeMultipliers } from "../../BitNode/BitNodeMultipliers"; -import { CONSTANTS } from "../../Constants"; -import { FactionWorkType } from "../data/FactionWorkType"; -import { newWorkStats, WorkStats } from "../WorkStats"; -import { - getFactionFieldWorkRepGain, - getFactionSecurityWorkRepGain, - getHackingWorkRepGain, -} from "../../PersonObjects/formulas/reputation"; - -const gameCPS = 1000 / CONSTANTS._idleSpeed; // 5 cycles per second - -export const FactionWorkStats: Record = { - [FactionWorkType.HACKING]: newWorkStats({ hackExp: 15 }), - [FactionWorkType.FIELD]: newWorkStats({ - hackExp: 10, - strExp: 10, - defExp: 10, - dexExp: 10, - agiExp: 10, - chaExp: 10, - }), - [FactionWorkType.SECURITY]: newWorkStats({ - hackExp: 5, - strExp: 15, - defExp: 15, - dexExp: 15, - agiExp: 15, - }), -}; - -export const calculateFactionRep = (person: Person, tpe: FactionWorkType, favor: number): number => { - const repFormulas = { - [FactionWorkType.HACKING]: getHackingWorkRepGain, - [FactionWorkType.FIELD]: getFactionFieldWorkRepGain, - [FactionWorkType.SECURITY]: getFactionSecurityWorkRepGain, - }; - return repFormulas[tpe](person, favor); -}; - -export function calculateFactionExp(person: Person, tpe: FactionWorkType): WorkStats { - const baseStats = FactionWorkStats[tpe]; - return { - money: 0, - reputation: 0, - hackExp: (baseStats.hackExp * person.mults.hacking_exp * BitNodeMultipliers.FactionWorkExpGain) / gameCPS, - strExp: (baseStats.strExp * person.mults.strength_exp * BitNodeMultipliers.FactionWorkExpGain) / gameCPS, - defExp: (baseStats.defExp * person.mults.defense_exp * BitNodeMultipliers.FactionWorkExpGain) / gameCPS, - dexExp: (baseStats.dexExp * person.mults.dexterity_exp * BitNodeMultipliers.FactionWorkExpGain) / gameCPS, - agiExp: (baseStats.agiExp * person.mults.agility_exp * BitNodeMultipliers.FactionWorkExpGain) / gameCPS, - chaExp: (baseStats.chaExp * person.mults.charisma_exp * BitNodeMultipliers.FactionWorkExpGain) / gameCPS, - intExp: 0, - }; -}