2023-06-16 23:52:42 +02:00
import { currentNodeMults } from "../BitNode/BitNodeMultipliers" ;
2022-11-06 23:27:04 +01:00
import { Crime } from "../Crime/Crime" ;
import { newWorkStats , scaleWorkStats , WorkStats , multWorkStats } from "./WorkStats" ;
2022-12-30 02:28:53 +01:00
import { Person as IPerson } from "@nsdefs" ;
2022-11-06 23:27:04 +01:00
import { CONSTANTS } from "../Constants" ;
2023-06-12 06:34:20 +02:00
import { ClassType , FactionWorkType , LocationName } from "@enums" ;
2022-11-06 23:27:04 +01:00
import {
getFactionFieldWorkRepGain ,
getFactionSecurityWorkRepGain ,
getHackingWorkRepGain ,
} from "../PersonObjects/formulas/reputation" ;
import { Locations } from "../Locations/Locations" ;
import { Location } from "../Locations/Location" ;
import { Player } from "@player" ;
2023-06-12 06:34:20 +02:00
import { Class , Classes } from "./ClassWork" ;
2022-11-06 23:27:04 +01:00
import { Server } from "../Server/Server" ;
import { GetServer } from "../Server/AllServers" ;
import { serverMetadata } from "../Server/data/servers" ;
import { Company } from "../Company/Company" ;
import { CompanyPosition } from "../Company/CompanyPosition" ;
2023-06-12 06:34:20 +02:00
import { isMember } from "../utils/EnumHelper" ;
2022-11-06 23:27:04 +01:00
2024-07-14 23:30:30 +02:00
function processWorkStats ( person : IPerson , workStats : WorkStats ) : WorkStats {
// "person" can be a normal object that the player passes to NS APIs, so we cannot use `person instanceof Sleeve`.
if ( Player . bitNodeOptions . disableSleeveExpAndAugmentation && "shock" in person ) {
workStats . hackExp = 0 ;
workStats . strExp = 0 ;
workStats . defExp = 0 ;
workStats . dexExp = 0 ;
workStats . agiExp = 0 ;
workStats . chaExp = 0 ;
workStats . intExp = 0 ;
}
return workStats ;
}
2023-02-21 15:44:18 +01:00
const gameCPS = 1000 / CONSTANTS . MilliPerCycle ; // 5 cycles per second
2022-11-06 23:27:04 +01:00
export const FactionWorkStats : Record < FactionWorkType , WorkStats > = {
2023-01-03 08:40:06 +01:00
[ FactionWorkType . hacking ] : newWorkStats ( { hackExp : 2 } ) ,
2022-11-20 14:37:11 +01:00
[ FactionWorkType . field ] : newWorkStats ( {
2023-01-03 08:40:06 +01:00
hackExp : 1 ,
strExp : 1 ,
defExp : 1 ,
dexExp : 1 ,
agiExp : 1 ,
chaExp : 1 ,
2022-11-06 23:27:04 +01:00
} ) ,
2022-11-20 14:37:11 +01:00
[ FactionWorkType . security ] : newWorkStats ( {
2023-01-03 08:40:06 +01:00
hackExp : 0.5 ,
strExp : 1.5 ,
defExp : 1.5 ,
dexExp : 1.5 ,
agiExp : 1.5 ,
2022-11-06 23:27:04 +01:00
} ) ,
} ;
2022-11-09 13:26:26 +01:00
export function calculateCrimeWorkStats ( person : IPerson , crime : Crime ) : WorkStats {
2022-11-06 23:27:04 +01:00
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 ,
2023-06-16 23:52:42 +02:00
person . mults . crime_money * currentNodeMults . CrimeMoney ,
2022-11-06 23:27:04 +01:00
) ,
2023-06-16 23:52:42 +02:00
currentNodeMults . CrimeExpGain ,
2022-11-06 23:27:04 +01:00
false ,
) ;
2024-07-14 23:30:30 +02:00
return processWorkStats ( person , gains ) ;
2022-11-06 23:27:04 +01:00
}
2022-11-11 03:56:46 +01:00
/** @returns faction rep rate per cycle */
2022-11-09 13:26:26 +01:00
export const calculateFactionRep = ( person : IPerson , type : FactionWorkType , favor : number ) : number = > {
2022-11-06 23:27:04 +01:00
const repFormulas = {
2022-11-20 14:37:11 +01:00
[ FactionWorkType . hacking ] : getHackingWorkRepGain ,
[ FactionWorkType . field ] : getFactionFieldWorkRepGain ,
[ FactionWorkType . security ] : getFactionSecurityWorkRepGain ,
2022-11-06 23:27:04 +01:00
} ;
return repFormulas [ type ] ( person , favor ) ;
} ;
2022-11-11 03:56:46 +01:00
/** @returns per-cycle WorkStats */
2022-11-09 13:26:26 +01:00
export function calculateFactionExp ( person : IPerson , type : FactionWorkType ) : WorkStats {
2024-07-14 23:30:30 +02:00
return processWorkStats (
person ,
scaleWorkStats ( multWorkStats ( FactionWorkStats [ type ] , person . mults ) , currentNodeMults . FactionWorkExpGain / gameCPS ) ,
2022-11-06 23:27:04 +01:00
) ;
}
/** 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 : "" ) ;
2023-11-02 01:22:17 +01:00
const discount = ( server as Server ) ? . backdoorInstalled ? 0.9 : 1 ;
2022-11-06 23:27:04 +01:00
return classs . earnings . money * location . costMult * discount ;
}
2022-11-11 03:56:46 +01:00
/** @returns per-cycle WorkStats */
2022-11-09 13:26:26 +01:00
export function calculateClassEarnings ( person : IPerson , type : ClassType , locationName : LocationName ) : WorkStats {
2022-11-06 23:27:04 +01:00
const hashManager = Player . hashManager ;
const classs = Classes [ type ] ;
const location = Locations [ locationName ] ;
2023-06-12 06:34:20 +02:00
const hashMult = isMember ( "GymType" , type ) ? hashManager . getTrainingMult ( ) : hashManager . getStudyMult ( ) ;
2022-11-06 23:27:04 +01:00
const earnings = multWorkStats (
scaleWorkStats ( classs . earnings , ( location . expMult / gameCPS ) * hashMult , false ) ,
person . mults ,
) ;
earnings . money = calculateCost ( classs , location ) / gameCPS ;
2024-07-14 23:30:30 +02:00
return processWorkStats ( person , earnings ) ;
2022-11-06 23:27:04 +01:00
}
2022-11-11 03:56:46 +01:00
/** @returns per-cycle WorkStats */
2022-11-06 23:27:04 +01:00
export const calculateCompanyWorkStats = (
2022-11-09 13:26:26 +01:00
worker : IPerson ,
2022-11-06 23:27:04 +01:00
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 ;
2024-07-14 23:30:30 +02:00
const bn11Mult = Player . activeSourceFileLvl ( 11 ) > 0 ? favorMult : 1 ;
2022-11-06 23:27:04 +01:00
const gains = scaleWorkStats (
multWorkStats (
{
2023-06-16 23:52:42 +02:00
money : companyPosition.baseSalary * company . salaryMultiplier * bn11Mult * currentNodeMults . CompanyWorkMoney ,
2022-11-06 23:27:04 +01:00
hackExp : companyPosition.hackingExpGain ,
strExp : companyPosition.strengthExpGain ,
defExp : companyPosition.defenseExpGain ,
dexExp : companyPosition.dexterityExpGain ,
agiExp : companyPosition.agilityExpGain ,
chaExp : companyPosition.charismaExpGain ,
} ,
worker . mults ,
worker . mults . work_money ,
) ,
2023-06-16 23:52:42 +02:00
company . expMultiplier * currentNodeMults . CompanyWorkExpGain ,
2022-11-06 23:27:04 +01:00
false ,
) ;
const jobPerformance = companyPosition . calculateJobPerformance ( worker ) ;
2023-12-26 17:45:27 +01:00
gains . reputation = jobPerformance * worker . mults . company_rep * favorMult * currentNodeMults . CompanyWorkRepGain ;
2022-11-06 23:27:04 +01:00
2024-07-14 23:30:30 +02:00
return processWorkStats ( worker , gains ) ;
2022-11-06 23:27:04 +01:00
} ;