bitburner-src/src/Work/Formulas.ts

157 lines
5.6 KiB
TypeScript
Raw Normal View History

import { currentNodeMults } from "../BitNode/BitNodeMultipliers";
import { Crime } from "../Crime/Crime";
import { newWorkStats, scaleWorkStats, WorkStats, multWorkStats } from "./WorkStats";
import { Person as IPerson } from "@nsdefs";
import { CONSTANTS } from "../Constants";
import { ClassType, FactionWorkType, LocationName } from "@enums";
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 } from "./ClassWork";
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";
import { isMember } from "../utils/EnumHelper";
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
export const FactionWorkStats: Record<FactionWorkType, WorkStats> = {
2023-01-03 08:40:06 +01:00
[FactionWorkType.hacking]: newWorkStats({ hackExp: 2 }),
[FactionWorkType.field]: newWorkStats({
2023-01-03 08:40:06 +01:00
hackExp: 1,
strExp: 1,
defExp: 1,
dexExp: 1,
agiExp: 1,
chaExp: 1,
}),
[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,
}),
};
NETSCRIPT: ns.sleeve.getSleeve added. getPlayer and getSleeve can both be used for formulas. (#200) * BREAKING CHANGE: Removed getSleeveStats and getSleeveInformation because this info is provided by getSleeve in a more usable form. * BREAKING CHANGE: Removed tor, inBladeburner, and hasCorporation fields from ns.getPlayer. Functionality still exists via added functions ns.hasTorRouter, ns.corporation.hasCorporation, and ns.bladeburner.inBladeburner. * Separated ns definitions for Person, Sleeve, and Player interfaces with both Player and Sleeve just extending Person. Added getSleeve, which provides a Sleeve object similar to getPlayer. * Renamed the sleeve ns layer's interface as sleeve lowercase because of name conflict. todo: May move all the ns layers interface names to lowercase for consistency * Added ns.formulas.work.crimeSuccessChance and reworked to allow both sleeve and player calculations. * Removed internal Person.getIntelligenceBonus function which was just a wrapper for calculateIntelligenceBonus. Any use of the former in formulas creates a conflict where ns-provided Person objects throw an error. * Renamed helpers.player to helpers.person for netscript person validation. Reduced number of fields validated due to Person being a smaller interface. * Fixed bug in bladeburner where Player multipliers and int were being used no matter which person was performing the task * Fixed leak of Player.jobs at ns.getPlayer * Person / Player / Sleeve classes now implement the netscript equivalent interfaces. Netscript helper for person no longer asserts that it's a real Person class member, only that it's a Person interface. Functions that use netscript persons have been changed to expect just a person interface to prevent needing this incorrect type assertion.
2022-11-09 13:26:26 +01:00
export function calculateCrimeWorkStats(person: IPerson, 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 * currentNodeMults.CrimeMoney,
),
currentNodeMults.CrimeExpGain,
false,
);
2024-07-14 23:30:30 +02:00
return processWorkStats(person, gains);
}
/** @returns faction rep rate per cycle */
NETSCRIPT: ns.sleeve.getSleeve added. getPlayer and getSleeve can both be used for formulas. (#200) * BREAKING CHANGE: Removed getSleeveStats and getSleeveInformation because this info is provided by getSleeve in a more usable form. * BREAKING CHANGE: Removed tor, inBladeburner, and hasCorporation fields from ns.getPlayer. Functionality still exists via added functions ns.hasTorRouter, ns.corporation.hasCorporation, and ns.bladeburner.inBladeburner. * Separated ns definitions for Person, Sleeve, and Player interfaces with both Player and Sleeve just extending Person. Added getSleeve, which provides a Sleeve object similar to getPlayer. * Renamed the sleeve ns layer's interface as sleeve lowercase because of name conflict. todo: May move all the ns layers interface names to lowercase for consistency * Added ns.formulas.work.crimeSuccessChance and reworked to allow both sleeve and player calculations. * Removed internal Person.getIntelligenceBonus function which was just a wrapper for calculateIntelligenceBonus. Any use of the former in formulas creates a conflict where ns-provided Person objects throw an error. * Renamed helpers.player to helpers.person for netscript person validation. Reduced number of fields validated due to Person being a smaller interface. * Fixed bug in bladeburner where Player multipliers and int were being used no matter which person was performing the task * Fixed leak of Player.jobs at ns.getPlayer * Person / Player / Sleeve classes now implement the netscript equivalent interfaces. Netscript helper for person no longer asserts that it's a real Person class member, only that it's a Person interface. Functions that use netscript persons have been changed to expect just a person interface to prevent needing this incorrect type assertion.
2022-11-09 13:26:26 +01:00
export const calculateFactionRep = (person: IPerson, type: FactionWorkType, favor: number): number => {
const repFormulas = {
[FactionWorkType.hacking]: getHackingWorkRepGain,
[FactionWorkType.field]: getFactionFieldWorkRepGain,
[FactionWorkType.security]: getFactionSecurityWorkRepGain,
};
return repFormulas[type](person, favor);
};
/** @returns per-cycle WorkStats */
NETSCRIPT: ns.sleeve.getSleeve added. getPlayer and getSleeve can both be used for formulas. (#200) * BREAKING CHANGE: Removed getSleeveStats and getSleeveInformation because this info is provided by getSleeve in a more usable form. * BREAKING CHANGE: Removed tor, inBladeburner, and hasCorporation fields from ns.getPlayer. Functionality still exists via added functions ns.hasTorRouter, ns.corporation.hasCorporation, and ns.bladeburner.inBladeburner. * Separated ns definitions for Person, Sleeve, and Player interfaces with both Player and Sleeve just extending Person. Added getSleeve, which provides a Sleeve object similar to getPlayer. * Renamed the sleeve ns layer's interface as sleeve lowercase because of name conflict. todo: May move all the ns layers interface names to lowercase for consistency * Added ns.formulas.work.crimeSuccessChance and reworked to allow both sleeve and player calculations. * Removed internal Person.getIntelligenceBonus function which was just a wrapper for calculateIntelligenceBonus. Any use of the former in formulas creates a conflict where ns-provided Person objects throw an error. * Renamed helpers.player to helpers.person for netscript person validation. Reduced number of fields validated due to Person being a smaller interface. * Fixed bug in bladeburner where Player multipliers and int were being used no matter which person was performing the task * Fixed leak of Player.jobs at ns.getPlayer * Person / Player / Sleeve classes now implement the netscript equivalent interfaces. Netscript helper for person no longer asserts that it's a real Person class member, only that it's a Person interface. Functions that use netscript persons have been changed to expect just a person interface to prevent needing this incorrect type assertion.
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),
);
}
/** 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;
}
/** @returns per-cycle WorkStats */
NETSCRIPT: ns.sleeve.getSleeve added. getPlayer and getSleeve can both be used for formulas. (#200) * BREAKING CHANGE: Removed getSleeveStats and getSleeveInformation because this info is provided by getSleeve in a more usable form. * BREAKING CHANGE: Removed tor, inBladeburner, and hasCorporation fields from ns.getPlayer. Functionality still exists via added functions ns.hasTorRouter, ns.corporation.hasCorporation, and ns.bladeburner.inBladeburner. * Separated ns definitions for Person, Sleeve, and Player interfaces with both Player and Sleeve just extending Person. Added getSleeve, which provides a Sleeve object similar to getPlayer. * Renamed the sleeve ns layer's interface as sleeve lowercase because of name conflict. todo: May move all the ns layers interface names to lowercase for consistency * Added ns.formulas.work.crimeSuccessChance and reworked to allow both sleeve and player calculations. * Removed internal Person.getIntelligenceBonus function which was just a wrapper for calculateIntelligenceBonus. Any use of the former in formulas creates a conflict where ns-provided Person objects throw an error. * Renamed helpers.player to helpers.person for netscript person validation. Reduced number of fields validated due to Person being a smaller interface. * Fixed bug in bladeburner where Player multipliers and int were being used no matter which person was performing the task * Fixed leak of Player.jobs at ns.getPlayer * Person / Player / Sleeve classes now implement the netscript equivalent interfaces. Netscript helper for person no longer asserts that it's a real Person class member, only that it's a Person interface. Functions that use netscript persons have been changed to expect just a person interface to prevent needing this incorrect type assertion.
2022-11-09 13:26:26 +01:00
export function calculateClassEarnings(person: IPerson, type: ClassType, locationName: LocationName): WorkStats {
const hashManager = Player.hashManager;
const classs = Classes[type];
const location = Locations[locationName];
const hashMult = isMember("GymType", type) ? hashManager.getTrainingMult() : hashManager.getStudyMult();
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);
}
/** @returns per-cycle WorkStats */
export const calculateCompanyWorkStats = (
NETSCRIPT: ns.sleeve.getSleeve added. getPlayer and getSleeve can both be used for formulas. (#200) * BREAKING CHANGE: Removed getSleeveStats and getSleeveInformation because this info is provided by getSleeve in a more usable form. * BREAKING CHANGE: Removed tor, inBladeburner, and hasCorporation fields from ns.getPlayer. Functionality still exists via added functions ns.hasTorRouter, ns.corporation.hasCorporation, and ns.bladeburner.inBladeburner. * Separated ns definitions for Person, Sleeve, and Player interfaces with both Player and Sleeve just extending Person. Added getSleeve, which provides a Sleeve object similar to getPlayer. * Renamed the sleeve ns layer's interface as sleeve lowercase because of name conflict. todo: May move all the ns layers interface names to lowercase for consistency * Added ns.formulas.work.crimeSuccessChance and reworked to allow both sleeve and player calculations. * Removed internal Person.getIntelligenceBonus function which was just a wrapper for calculateIntelligenceBonus. Any use of the former in formulas creates a conflict where ns-provided Person objects throw an error. * Renamed helpers.player to helpers.person for netscript person validation. Reduced number of fields validated due to Person being a smaller interface. * Fixed bug in bladeburner where Player multipliers and int were being used no matter which person was performing the task * Fixed leak of Player.jobs at ns.getPlayer * Person / Player / Sleeve classes now implement the netscript equivalent interfaces. Netscript helper for person no longer asserts that it's a real Person class member, only that it's a Person interface. Functions that use netscript persons have been changed to expect just a person interface to prevent needing this incorrect type assertion.
2022-11-09 13:26:26 +01:00
worker: IPerson,
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;
const gains = scaleWorkStats(
multWorkStats(
{
money: companyPosition.baseSalary * company.salaryMultiplier * bn11Mult * currentNodeMults.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 * currentNodeMults.CompanyWorkExpGain,
false,
);
const jobPerformance = companyPosition.calculateJobPerformance(worker);
gains.reputation = jobPerformance * worker.mults.company_rep * favorMult * currentNodeMults.CompanyWorkRepGain;
2024-07-14 23:30:30 +02:00
return processWorkStats(worker, gains);
};